0 | module System.Systemd.Daemon
  1 |
  2 | import public System.Systemd.Daemon.Fd
  3 | import public System.Systemd.Internal
  4 |
  5 | import System
  6 | import System.Posix.Errno
  7 | import System.Posix.File
  8 | import System.Posix.Socket
  9 |
 10 | ||| Notify systemd about an event
 11 | ||| After notifying systemd the Bool parameter specify if the environment
 12 | ||| shall be unset (Further call to notify will fail).
 13 | ||| The String is the event to pass.
 14 | ||| Returns Nothing if the program was not started with systemd
 15 | ||| or the environment was previously unset.
 16 | export
 17 | notify :  Bool
 18 |        -> String
 19 |        -> IO (Maybe ())
 20 | notify unset_env state =
 21 |   notifyWithFd_ unset_env
 22 |                 state
 23 |                 Nothing
 24 |
 25 | ||| Same as `notify` but send along a socket to be stored.
 26 | ||| It is up to the caller to properly set the message
 27 | ||| (i.e: do not forget to set FDSTORE=1).
 28 | export
 29 | notifyWithFD :  Bool
 30 |              -> String
 31 |              -> Socket AF_UNIX
 32 |              -> IO (Maybe ())
 33 | notifyWithFD unset_env state sock =
 34 |   notifyWithFd unset_env
 35 |                state
 36 |                (cast {to=Fd} sock)
 37 |
 38 | ||| Notify the watchdog that the program is still alive.
 39 | export
 40 | notifyWatchdog : IO (Maybe ())
 41 | notifyWatchdog =
 42 |   notify False
 43 |          "WATCHDOG=1"
 44 |
 45 | ||| Notify the systemd that the program is ready.
 46 | export
 47 | notifyReady : IO (Maybe ())
 48 | notifyReady =
 49 |   notify False
 50 |          "READY=1"
 51 |
 52 | ||| Notify systemd of the PID of the program (for after a fork).
 53 | export
 54 | notifyPID : Int -> IO (Maybe ())
 55 | notifyPID pid =
 56 |   notify False
 57 |          ("MAINPID=" ++ show pid)
 58 |
 59 | ||| Notify systemd that the service is reloading its configuration.
 60 | export
 61 | notifyReloading : IO (Maybe ())
 62 | notifyReloading =
 63 |   notify False
 64 |          "RELOADING=1"
 65 |
 66 | ||| Notify systemd that the service is beginning its shutdown.
 67 | export
 68 | notifyStopping : IO (Maybe())
 69 | notifyStopping =
 70 |   notify False
 71 |          "STOPPING=1"
 72 |
 73 | ||| Notify systemd of an 'Errno' error.
 74 | export
 75 | notifyErrno :  Errno
 76 |             -> IO (Maybe())
 77 | notifyErrno (EN errorNb) =
 78 |   notify False
 79 |          ("ERRNO=" ++ show errorNb)
 80 |
 81 | ||| Notify systemd of the status of the program.
 82 | ||| An arbitrary String can be passed.
 83 | export
 84 | notifyStatus :  String
 85 |              -> IO (Maybe())
 86 | notifyStatus msg =
 87 |   notify False
 88 |          ("STATUS=" ++ msg)
 89 |
 90 | ||| Notify systemd of a DBUS error like.
 91 | ||| Correct formatting of the String is left to the caller.
 92 | export
 93 | notifyBusError :  String
 94 |                -> IO (Maybe())
 95 | notifyBusError msg =
 96 |   notify False
 97 |          ("BUSERROR=" ++ msg)
 98 |
 99 | ||| Notify systemd to store a socket for us.
100 | ||| To be used along `getActivatedSockets` during a restart.
101 | ||| Useful for zero downtime restart.
102 | export
103 | storeFd :  Socket AF_UNIX
104 |         -> IO (Maybe ())
105 | storeFd sock =
106 |   storeFd (cast {to=Fd} sock)
107 |
108 | ||| Notify systemd to store a socket for us and specify a name.
109 | ||| To be used along `getActivatedSocketsWithNames` during a restart.
110 | ||| Useful for zero downtime restart.
111 | export
112 | storeFdWithName :  Socket AF_UNIX
113 |                 -> String
114 |                 -> IO (Maybe ())
115 | storeFdWithName sock name = 
116 |   storeFdWithName (cast {to=Fd} sock)
117 |                   name
118 |
119 | ||| Return a list of activated sockets, if the program was started with
120 | ||| socket activation.
121 | ||| The sockets are in the same order as in the associated .socket file.
122 | ||| The sockets will have their family, type, and status set appropriately.
123 | ||| Returns Nothing in systems without socket activation (or
124 | ||| when the program was not socket activated).
125 | export
126 | getActivatedSockets : IO (Maybe (List (Socket AF_UNIX)))
127 | getActivatedSockets = do
128 |   Just fds <- System.Systemd.Daemon.Fd.getActivatedSockets
129 |     | Nothing =>
130 |         pure Nothing
131 |   let fds' = map (\(MkFd fd) =>
132 |                     cast {to=Socket AF_UNIX} $
133 |                       cast {to=Int32} fd
134 |                  ) fds
135 |   pure $
136 |     Just fds'
137 |
138 | ||| Same as `getActivatedSockets` but return also the names associated
139 | ||| with those sockets if `storeFdWithName` was used or specified in the .socket file.
140 | ||| If `storeFd` was used to transmit the socket to systemd, the name will be a generic one
141 | ||| (i.e: usally "stored").
142 | export
143 | getActivatedSocketsWithNames : IO (Maybe (List (Socket AF_UNIX, String)))
144 | getActivatedSocketsWithNames = do
145 |   Just fdsandnames <- System.Systemd.Daemon.Fd.getActivatedSocketsWithNames
146 |     | Nothing =>
147 |         pure Nothing
148 |   let fdsandnames' = map (\(MkFd fd, name) =>
149 |                             let sock = cast {to=Socket AF_UNIX} $
150 |                                          cast {to=Int32} fd
151 |                               in (sock, name)
152 |                          ) fdsandnames
153 |   pure $
154 |     Just fdsandnames'
155 |