sd_daemon

package
v0.5.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 15, 2019 License: Apache-2.0 Imports: 12 Imported by: 5

Documentation

Overview

Package sd_daemon implements utilities for writing "new-style" daemons.

The daemon(7) manual page has historically documented the very long list of things that a daemon must do at start-up to be a well-behaved SysV daemon. Modern service managers allow daemons to be much simpler; modern versions of the daemon(7) page on GNU/Linux systems also describe "new-style" daemons. Though many of the mechanisms described there and implemented here originated with systemd, they are all very simple mechanisms which can easily be implemented with a variety of service managers.

daemon(7): https://www.freedesktop.org/software/systemd/man/daemon.html

BUG(lukeshu): Logically, sd_id128.GetInvocationID might belong in this package, but we defer to the C-language libsystemd's placement of sd_id128_get_invocation() in sd-id128.h.

Index

Examples

Constants

View Source
const (
	//   0-  8 are currently defined by LSB.
	EXIT_SUCCESS         uint8 = 0
	EXIT_FAILURE         uint8 = 1
	EXIT_INVALIDARGUMENT uint8 = 2
	EXIT_NOTIMPLEMENTED  uint8 = 3
	EXIT_NOPERMISSION    uint8 = 4
	EXIT_NOTINSTALLED    uint8 = 5
	EXIT_NOTCONFIGURED   uint8 = 6
	EXIT_NOTRUNNING      uint8 = 7
	//
	//   8- 99 are reserved for future LSB use.
	//         However, let's provide the EX_ codes from
	//         sysexits.h anyway.
	EX_OK          uint8 = EXIT_SUCCESS
	EX_USAGE       uint8 = 64 // command line usage error
	EX_DATAERR     uint8 = 65 // data format error
	EX_NOINPUT     uint8 = 66 // cannot open input
	EX_NOUSER      uint8 = 67 // addressee unknown
	EX_NOHOST      uint8 = 68 // host name unknown
	EX_UNAVAILABLE uint8 = 69 // service unavailable
	EX_SOFTWARE    uint8 = 70 // internal software error
	EX_OSERR       uint8 = 71 // system error (e.g., can't fork)
	EX_OSFILE      uint8 = 72 // critical OS file missing
	EX_CANTCREAT   uint8 = 73 // can't create (user) output file
	EX_IOERR       uint8 = 74 // input/output error
	EX_TEMPFAIL    uint8 = 75 // temp failure; user is invited to retry
	EX_PROTOCOL    uint8 = 76 // remote error in protocol
	EX_NOPERM      uint8 = 77 // permission denied
	EX_CONFIG      uint8 = 78 // configuration error
	//
	// 100-149 are reserved for distribution use.
	//
	// 150-199 are reserved for application use.
	//
	// 200-254 are reserved (for init system use).
	//         So, take codes 200+ from systemd's
	//         `src/basic/exit-status.h`
	//         (last updated for SD v242)
	EXIT_CHDIR                   uint8 = 200 // SD v8+
	EXIT_NICE                    uint8 = 201 // SD v8+
	EXIT_FDS                     uint8 = 202 // SD v8+
	EXIT_EXEC                    uint8 = 203 // SD v8+
	EXIT_MEMORY                  uint8 = 204 // SD v8+
	EXIT_LIMITS                  uint8 = 205 // SD v8+
	EXIT_OOM_ADJUST              uint8 = 206 // SD v8+
	EXIT_SIGNAL_MASK             uint8 = 207 // SD v8+
	EXIT_STDIN                   uint8 = 208 // SD v8+
	EXIT_STDOUT                  uint8 = 209 // SD v8+
	EXIT_CHROOT                  uint8 = 210 // SD v8+
	EXIT_IOPRIO                  uint8 = 211 // SD v8+
	EXIT_TIMERSLACK              uint8 = 212 // SD v8+
	EXIT_SECUREBITS              uint8 = 213 // SD v8+
	EXIT_SETSCHEDULER            uint8 = 214 // SD v8+
	EXIT_CPUAFFINITY             uint8 = 215 // SD v8+
	EXIT_GROUP                   uint8 = 216 // SD v8+
	EXIT_USER                    uint8 = 217 // SD v8+
	EXIT_CAPABILITIES            uint8 = 218 // SD v8+
	EXIT_CGROUP                  uint8 = 219 // SD v8+
	EXIT_SETSID                  uint8 = 220 // SD v8+
	EXIT_CONFIRM                 uint8 = 221 // SD v8+
	EXIT_STDERR                  uint8 = 222 // SD v8+
	EXIT_TCPWRAP                 uint8 = 223 // SD v8-v211
	EXIT_PAM                     uint8 = 224 // SD v8+
	EXIT_NETWORK                 uint8 = 225 // SD v33+
	EXIT_NAMESPACE               uint8 = 226 // SD v38+
	EXIT_NO_NEW_PRIVILEGES       uint8 = 227 // SD v187+
	EXIT_SECCOMP                 uint8 = 228 // SD v187+
	EXIT_SELINUX_CONTEXT         uint8 = 229 // SD v209+
	EXIT_PERSONALITY             uint8 = 230 // SD v209+
	EXIT_APPARMOR_PROFILE        uint8 = 231 // SD v210+
	EXIT_ADDRESS_FAMILIES        uint8 = 232 // SD v211+
	EXIT_RUNTIME_DIRECTORY       uint8 = 233 // SD v211+
	EXIT_MAKE_STARTER            uint8 = 234 // SD v214-v234
	EXIT_CHOWN                   uint8 = 235 // SD v214+
	EXIT_SMACK_PROCESS_LABEL     uint8 = 236 // SD v230+; was BUS_ENDPOINT in SD v217-v229
	EXIT_KEYRING                 uint8 = 237 // SD v233+; was SMACK_PROCESS_LABEL in SD v218-v229
	EXIT_STATE_DIRECTORY         uint8 = 238 // SD v235+
	EXIT_CACHE_DIRECTORY         uint8 = 239 // SD v235+
	EXIT_LOGS_DIRECTORY          uint8 = 240 // SD v235+
	EXIT_CONFIGURATION_DIRECTORY uint8 = 241 // SD v235+
)

daemon(7) recommends using the exit codes defined in the "LSB recommendations for SysV init scripts"1.

BSD sysexits.h (which is also in GNU libc) defines several exit codes in the range 64-78. These are typically used in the context of mail delivery; originating with BSD delivermail (the NCP predecessor to the TCP/IP sendmail), and are still used by modern mail systems such as Postfix to interpret the local(8) delivery agent's exit status. Using these for service exit codes isn't recommended by LSB (which says they are in the range reserved for future LSB use) or by daemon(7). However, they are used in practice, and are recognized by systemd.

sysexits(3): https://www.freebsd.org/cgi/man.cgi?query=sysexits

local(8): http://www.postfix.org/local.8.html

Variables

View Source
var ErrDisabled = errors.New("Mechanism Disabled")

ErrDisabled is the error returned when the service manager does not want/support a mechanism; or when that mechanism has been disabled for this process by setting unsetEnv=true when calling one of these functions.

View Source
var Log = NewLogger(os.Stderr)

Log is a Logger whose interface is very similar to syslog.Writer, but writes to os.Stderr under the assumption that stderr is forwarded to syslogd (or journald).

Functions

func ListenFds

func ListenFds(unsetEnv bool) []*os.File

ListenFds returns a list of file descriptors passed in by the service manager as part of the socket-based activation logic.

If unsetEnv is true, then (regardless of whether the function call itself succeeds or not) it will unset the environmental variables LISTEN_FDS and LISTEN_PID, which will cause further calls to this function to fail.

In the case of an error, this function returns nil.

func Recover

func Recover()

Recover is a utility function to defer at the beginning of a goroutine in order to have the correct exit code in the case of a panic.

func SdBooted

func SdBooted() bool

Returns whether the operating system booted using the systemd init system.

Please do not use this function. All of the other functionality in this package uses interfaces that are not systemd-specific.

func WatchdogEnabled

func WatchdogEnabled(unsetEnv bool) (time.Duration, error)

WatchdogEnabled returns how often the process is expected to send a keep-alive notification to the service manager.

Notification{State: "WATCHDOG=1"}.Send(false) // send keep-alive notification

If unsetEnv is true, then (regardless of whether the function call itself succeeds or not) it will unset the environmental variables WATCHDOG_USEC and WATCHDOG_PID, which will cause further calls to this function to fail.

If an error is not returned, then the duration returned is greater than 0; if an error is returned, then the duration is 0. If the service manager is not expecting a keep-alive notification from this process (or if this has already been called with unsetEnv=true), then the error is ErrDisabled.

Types

type Logger

type Logger struct {
	// contains filtered or unexported fields
}

A Logger writes "<N>"-prefixed lines to an io.Writer, where N is a syslog priority number. It implements mostly the same interface as syslog.Writer.

You probably don't need any instance of this other than the constant "Log", which uses os.Stderr as the writer. It is implemented as a struct rather than a set of functions so that it can be passed around as an implementation of an interface.

Each logging operation makes a single call to the underlying Writer's Write method. A single logging operation may be multiple lines; each line will have the prefix, and they will all be written in the same Write. A Logger can be used simultaneously from multiple goroutines; it guarantees to serialize access to the Writer.

func NewLogger

func NewLogger(w io.Writer) *Logger

NewLogger creates a new Logger.

func (*Logger) Alert

func (l *Logger) Alert(msg string) error

Alert writes a message with priority syslog.LOG_ALERT to the log.

func (*Logger) Crit

func (l *Logger) Crit(msg string) error

Crit writes a message with priority syslog.LOG_CRIT to the log.

func (*Logger) Debug

func (l *Logger) Debug(msg string) error

Debug writes a message with priority syslog.LOG_DEBUG to the log.

func (*Logger) Emerg

func (l *Logger) Emerg(msg string) error

Emerg writes a message with priority syslog.LOG_EMERG to the log.

func (*Logger) Err

func (l *Logger) Err(msg string) error

Err writes a message with priority syslog.LOG_ERR to the log.

func (*Logger) Info

func (l *Logger) Info(msg string) error

Info writes a message with priority syslog.LOG_INFO to the log.

func (*Logger) LogBytes

func (l *Logger) LogBytes(pri syslog.Priority, msg []byte) (n int, err error)

LogBytes writes a message with the specified priority to the log.

func (*Logger) LogString

func (l *Logger) LogString(pri syslog.Priority, msg string) (n int, err error)

LogString writes a message with the specified priority to the log.

func (*Logger) Notice

func (l *Logger) Notice(msg string) error

Notice writes a message with priority syslog.LOG_NOTICE to the log.

func (*Logger) Warning

func (l *Logger) Warning(msg string) error

Warning writes a message with priority syslog.LOG_WARNING to the log.

func (*Logger) Write

func (l *Logger) Write(msg []byte) (n int, err error)

Write writes a message with priority syslog.LOG_INFO to the log; implementing io.Writer.

func (*Logger) WriteString

func (l *Logger) WriteString(msg string) (n int, err error)

WriteString writes a message with priority syslog.LOG_INFO to the log; implementing io.WriteString's interface.

func (*Logger) Writer

func (l *Logger) Writer(pri syslog.Priority) io.Writer

Writer returns an io.Writer that writes messages with the specified priority to the log.

type Notification

type Notification struct {
	// PID specifies which process to send a notification about.
	// If PID <= 0, or if the current process does not have
	// privileges to send messages on behalf of other processes,
	// then the message is simply sent from the current process.
	//
	// BUG(lukeshu): Spoofing the PID is not implemented on
	// non-Linux kernels.  If you are knowledgable about how to do
	// this on other kernels, please let me know at
	// <lukeshu@lukeshu.com>!
	PID int

	// State should contain a newline-separated list of variable
	// assignments.  See the documentation for sd_notify(3) for
	// well-known variable assignments.
	//
	// https://www.freedesktop.org/software/systemd/man/sd_notify.html
	State string

	// Files is a list of file descriptors to send to the service
	// manager with the message.  This is useful for keeping files
	// open across restarts, as it enables the service manager to
	// pass those files to the new process when it is restarted
	// (see ListenFds).
	//
	// Note: The service manager will only actually store the file
	// descriptors if you include "FDSTORE=1" in the state (again,
	// see sd_notify(3) for well-known variable assignments).
	Files []*os.File
}

Notification is a message to be sent to the service manager about state changes.

Example
package main

import (
	"git.lukeshu.com/go/libsystemd/sd_daemon"
)

func main() {
	sd_daemon.Notification{State: "READY=1\nSTATUS=Daemon is running"}.Send(false)
}
Output:

func (Notification) Send

func (msg Notification) Send(unsetEnv bool) error

Send sends the Notification to the service manager.

If unsetEnv is true, then (regardless of whether the function call itself succeeds or not) it will unset the environmental variable NOTIFY_SOCKET, which will cause further notify operations to fail.

If the service manager is not listening for notifications from this process tree (or a Notification has has already been send with unsetEnv=true), then ErrDisabled is returned. If the service manager appears to be listening, but there is an error sending the message, then that error is returned.

It is generally recommended that you ignore the return value: if there is an error, then this is function no-op; meaning that by calling the function but ignoring the return value, you can easily support both service managers that support these notifications and those that do not.

Notes

Bugs

  • SdBooted is systemd-specific, and isn't of particular value to daemons. It doesn't really belong in a library of generic daemon utilities. But, we defer to its inclusion in the C-language libsystemd.

  • Logically, sd_id128.GetInvocationID might belong in this package, but we defer to the C-language libsystemd's placement of sd_id128_get_invocation() in sd-id128.h.

  • Spoofing the PID is not implemented on non-Linux kernels. If you are knowledgable about how to do this on other kernels, please let me know at <lukeshu@lukeshu.com>!

  • On Linux, Notification.Send() depends on SOCK_CLOEXEC in Linux 2.6.27 (2008-10-09), which is slightly newer than Go itself depends on, 2.6.23 (2007-10-09).

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL