veyron/services/mgmt: integrate device manager with sysinit
This change adds support to the deviced binary to install/uninstall/start/stop
itself via the sysinit package (which in turn interfaces with upstart/sysinit).
In 'init mode', the install command creates a service description and registers
it with the system daemon manager. Uninstall, Start, and Stop will then also
use sysinit to perform their respective duties.
Since sysinit operations need to be run as root, we introduce a new helper
(inithelper) analogous to suidhelper, which deviced calls when it needs to do
sysinit operations.
This change also makes some necessary changes to the sysinit package:
- setting the uid to 0 when euid is 0
- adding a New() api to create the appropriate InstallSystemInit object
- removing the setup function
- adding serialization/deserialization routines for ServiceDescription
Other changes lumped up with this CL, which could have been separated out into
their own CLs if we had less time pressure:
- managing stdout/stderr output from device manager and security agent, and
ensuring we persist that in appropriate log dirs
- changing the exit code behavior of device manager to return 0 when a restart
is not desired, and to non-zero if restart is desired; in particular, Stop now
return 0 but Revert/Update/Suspend do not (nor do crashes obviously). This
makes it easier to decide if device manager is meant to be restarted or not.
- adding a 'hack' to lib/signals to treat duplicate signals received by the
process as one; this gets around the problem of deviced receiving a signal
from its parent (the security agent) in addition to the signal it gets from
e.g. a ^C or from upstart by virtue of being part of the process group lead by
the agent.
Change-Id: I9f75577abb2258600b9b58bd141002bd2e05fac7
diff --git a/lib/signals/signals.go b/lib/signals/signals.go
index e2d64a6..564c6c6 100644
--- a/lib/signals/signals.go
+++ b/lib/signals/signals.go
@@ -4,6 +4,7 @@
"os"
"os/signal"
"syscall"
+ "time"
"v.io/core/veyron2"
"v.io/core/veyron2/context"
@@ -19,6 +20,25 @@
DoubleStopExitCode = 1
)
+// TODO(caprita): Needless to say, this is a hack. The motivator was getting
+// the device manager (run by the security agent) to shut down cleanly when the
+// process group containing both the agent and device manager receives a signal
+// (and the agent propagates that signal to the child). We should be able to
+// finesse this by demonizing the device manager and/or being smarter about how
+// and when the agent sends the signal to the child.
+
+// SameSignalTimeWindow specifies the time window during which multiple
+// deliveries of the same signal are counted as one signal. If set to zero, no
+// such de-duping occurs. This is useful in situations where a process receives
+// a signal explicitly sent by its parent when the parent receives the signal,
+// but also receives it independently by virtue of being part of the same
+// process group.
+//
+// This is a variable, so that I can be set appropriately. Note, there is no
+// locking around it, the assumption being that it's set during initialization
+// and never reset afterwards.
+var SameSignalTimeWindow time.Duration
+
// defaultSignals returns a set of platform-specific signals that an application
// is encouraged to listen on.
func defaultSignals() []os.Signal {
@@ -68,11 +88,19 @@
go func() {
// First signal received.
sig := <-ch
+ sigTime := time.Now()
ret <- sig
// Wait for a second signal, and force an exit if the process is
// still executing cleanup code.
- <-ch
- os.Exit(DoubleStopExitCode)
+ for {
+ secondSig := <-ch
+ // If signal de-duping is enabled, ignore the signal if
+ // it's the same signal and has occured within the
+ // specified time window.
+ if SameSignalTimeWindow <= 0 || secondSig.String() != sig.String() || sigTime.Add(SameSignalTimeWindow).Before(time.Now()) {
+ os.Exit(DoubleStopExitCode)
+ }
+ }
}()
return ret
}