From da323d62044ca98455763300596645dc082bd007 Mon Sep 17 00:00:00 2001 From: Luke Shumaker Date: Wed, 18 Jan 2017 16:49:40 -0500 Subject: Change the notify signature (again). BREAKING CHANGE. I think this should reduce the cognitive load of using the function. --- sd_daemon/notify.go | 98 +++++++++++++++++++++++++++++++---------------------- 1 file changed, 57 insertions(+), 41 deletions(-) (limited to 'sd_daemon/notify.go') diff --git a/sd_daemon/notify.go b/sd_daemon/notify.go index f2b9076..fcd8060 100644 --- a/sd_daemon/notify.go +++ b/sd_daemon/notify.go @@ -1,6 +1,6 @@ // Copyright 2013-2015 Docker, Inc. // Copyright 2014 CoreOS, Inc. -// Copyright 2015-2016 Luke Shumaker +// Copyright 2015-2017 Luke Shumaker // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -24,39 +24,52 @@ import ( "golang.org/x/sys/unix" ) -// Notify sends a message from process pid to the service manager -// about state changes. If pid <= 0, or if the current process does -// not have priveleges to send messages on behalf of other processes, -// then the message is simply sent from the current process. +// Notification is a message to be sent to the service manager about +// state changes. +type Notification struct { + // PID specifies which process to send a notification about. + // If PID <= 0, or if the current process does not have + // priveleges to send messages on behalf of other processes, + // then the message is simply sent from the current process. + PID int + + // State should countain 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 +} + +// 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 calls to this function to -// fail. -// -// The state parameter should countain 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 -// -// It is possible to include a set of file descriptors 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). +// NOTIFY_SOCKET, which will cause further notify operations to fail. // // If the service manager is not listening for notifications from this -// process tree (or this has already been called 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, 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. -func Notify(pid int, unsetEnv bool, state string, files []*os.File) error { +// 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. +func (msg Notification) Send(unsetEnv bool) error { if unsetEnv { defer func() { _ = os.Unsetenv("NOTIFY_SOCKET") }() } @@ -78,37 +91,40 @@ func Notify(pid int, unsetEnv bool, state string, files []*os.File) error { var cmsgs [][]byte - if len(files) > 0 { - fds := make([]int, len(files)) - for i := range files { - fds[i] = int(files[i].Fd()) + if len(msg.Files) > 0 { + fds := make([]int, len(msg.Files)) + for i := range msg.Files { + fds[i] = int(msg.Files[i].Fd()) } cmsg := unix.UnixRights(fds...) cmsgs = append(cmsgs, cmsg) } - havePid := pid > 0 && pid != os.Getpid() + havePid := msg.PID > 0 && msg.PID != os.Getpid() if havePid { cmsg := unix.UnixCredentials(&unix.Ucred{ - Pid: int32(pid), + Pid: int32(msg.PID), Uid: uint32(os.Getuid()), Gid: uint32(os.Getgid()), }) cmsgs = append(cmsgs, cmsg) } - // If the 2nd argument is empty, this is equivalent to .Write([]byte(state)) - _, _, err = conn.WriteMsgUnix([]byte(state), bytes.Join(cmsgs, nil), socketAddr) + // If the 2nd argument is empty, this is equivalent to + // + // conn, _ := net.DialUnix(socketAddr.Net, nil, socketAddr) + // conn.Write([]byte(msg.State)) + _, _, err = conn.WriteMsgUnix([]byte(msg.State), bytes.Join(cmsgs, nil), socketAddr) if err != nil && havePid { // Maybe it failed because we don't have privileges to - // spoof our pid, retry without spoofing the pid. + // spoof our pid; retry without spoofing the pid. // - // I'm not too happy that does this silently without - // notifying the user, but that's what + // I'm not too happy that we do this silently without + // notifying the caller, but that's what // sd_pid_notify_with_fds does. cmsgs = cmsgs[:len(cmsgs)-1] - _, _, err = conn.WriteMsgUnix([]byte(state), bytes.Join(cmsgs, nil), socketAddr) + _, _, err = conn.WriteMsgUnix([]byte(msg.State), bytes.Join(cmsgs, nil), socketAddr) } return err -- cgit v1.2.3