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 ¶
- Constants
- Variables
- func ListenFds(unsetEnv bool) []*os.File
- func Recover()
- func SdBooted() bool
- func WatchdogEnabled(unsetEnv bool) (time.Duration, error)
- type Logger
- func (l *Logger) Alert(msg string) error
- func (l *Logger) Crit(msg string) error
- func (l *Logger) Debug(msg string) error
- func (l *Logger) Emerg(msg string) error
- func (l *Logger) Err(msg string) error
- func (l *Logger) Info(msg string) error
- func (l *Logger) LogBytes(pri syslog.Priority, msg []byte) (n int, err error)
- func (l *Logger) LogString(pri syslog.Priority, msg string) (n int, err error)
- func (l *Logger) Notice(msg string) error
- func (l *Logger) Warning(msg string) error
- func (l *Logger) Write(msg []byte) (n int, err error)
- func (l *Logger) WriteString(msg string) (n int, err error)
- func (l *Logger) Writer(pri syslog.Priority) io.Writer
- type Notification
- Bugs
Examples ¶
Constants ¶
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 ¶
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.
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 ¶
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 ¶
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 (*Logger) Alert ¶
Alert writes a message with priority syslog.LOG_ALERT to the log.
func (*Logger) Crit ¶
Crit writes a message with priority syslog.LOG_CRIT to the log.
func (*Logger) Debug ¶
Debug writes a message with priority syslog.LOG_DEBUG to the log.
func (*Logger) Emerg ¶
Emerg writes a message with priority syslog.LOG_EMERG to the log.
func (*Logger) Err ¶
Err writes a message with priority syslog.LOG_ERR to the log.
func (*Logger) Info ¶
Info writes a message with priority syslog.LOG_INFO to the log.
func (*Logger) LogBytes ¶
LogBytes writes a message with the specified priority to the log.
func (*Logger) LogString ¶
LogString writes a message with the specified priority to the log.
func (*Logger) Notice ¶
Notice writes a message with priority syslog.LOG_NOTICE to the log.
func (*Logger) Warning ¶
Warning writes a message with priority syslog.LOG_WARNING to the log.
func (*Logger) Write ¶
Write writes a message with priority syslog.LOG_INFO to the log; implementing io.Writer.
func (*Logger) WriteString ¶
WriteString writes a message with priority syslog.LOG_INFO to the log; implementing io.WriteString's interface.
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).