]> mj.ucw.cz Git - libucw.git/blob - ucw/daemon-ctrl.c
Mainloop: Avoid polling for an empty set of events
[libucw.git] / ucw / daemon-ctrl.c
1 /*
2  *      UCW Library -- Daemon Control
3  *
4  *      (c) 2012 Martin Mares <mj@ucw.cz>
5  *      (c) 2014 Pavel Charvat <pchar@ucw.cz>
6  *
7  *      This software may be freely distributed and used according to the terms
8  *      of the GNU Lesser General Public License.
9  */
10
11 #include <ucw/lib.h>
12 #include <ucw/daemon.h>
13 #include <ucw/process.h>
14 #include <ucw/strtonum.h>
15
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <stdarg.h>
19 #include <fcntl.h>
20 #include <unistd.h>
21 #include <errno.h>
22 #include <signal.h>
23 #include <string.h>
24 #include <sys/file.h>
25 #include <sys/wait.h>
26
27 static enum daemon_control_status
28 daemon_control_err(struct daemon_control_params *dc, char *msg, ...)
29 {
30   va_list args;
31   va_start(args, msg);
32   vsnprintf(dc->error_msg, DAEMON_ERR_LEN, msg, args);
33   va_end(args);
34   return DAEMON_STATUS_ERROR;
35 }
36
37 static enum daemon_control_status
38 daemon_read_pid(struct daemon_control_params *dc, int will_wait, int *pidp)
39 {
40   // We expect successfully locked guard file, so no foreign process
41   // can be inside daemon_control() and therefore also in daemon_init()
42   // or daemon_run(). Only these results are then possible:
43   //
44   // -- DAEMON_STATUS_ERROR -- some local failure
45   // -- DAEMON_STATUS_NOT_RUNNING -- no daemon is running
46   // -- DAEMON_STATUS_STALE -- crashed daemon
47   // -- DAEMON_STATUS_OK, pid > 0 -- running daemon with known PID
48   // -- DAEMON_STATUS_OK, pid == 0 -- just exiting daemon, after ftruncate()
49
50   enum daemon_control_status st = DAEMON_STATUS_NOT_RUNNING;
51   *pidp = 0;
52
53   int pid_fd = open(dc->pid_file, O_RDONLY);
54   if (pid_fd < 0)
55     {
56       if (errno == ENOENT)
57         return st;
58       return daemon_control_err(dc, "Cannot open PID file `%s': %m", dc->pid_file);
59     }
60
61   while (flock(pid_fd, LOCK_SH | (will_wait ? 0 : LOCK_NB)) < 0)
62     {
63       if (errno == EWOULDBLOCK)
64         {
65           st = DAEMON_STATUS_OK;
66           break;
67         }
68       else if (errno != EINTR)
69         {
70           daemon_control_err(dc, "Cannot lock PID file `%s': %m", dc->pid_file);
71           goto fail;
72         }
73     }
74
75   char buf[16];
76   int n = read(pid_fd, buf, sizeof(buf));
77   if (n < 0)
78     {
79       daemon_control_err(dc, "Error reading `%s': %m", dc->pid_file);
80       goto fail;
81     }
82   if (n == (int) sizeof(buf))
83     {
84       daemon_control_err(dc, "PID file `%s' is too long", dc->pid_file);
85       goto fail;
86     }
87   buf[n] = 0;
88
89   if (!n)
90     {
91       close(pid_fd);
92       return st;
93     }
94
95   if (st != DAEMON_STATUS_OK)
96     {
97       close(pid_fd);
98       return DAEMON_STATUS_STALE;
99     }
100
101   int pid;
102   const char *next;
103   if (str_to_int(&pid, buf, &next, 10) || strcmp(next, "\n"))
104     {
105       daemon_control_err(dc, "PID file `%s' does not contain a valid PID", dc->pid_file);
106       goto fail;
107     }
108
109   close(pid_fd);
110   *pidp = pid;
111   return DAEMON_STATUS_OK;
112
113 fail:
114   close(pid_fd);
115   return DAEMON_STATUS_ERROR;
116 }
117
118 enum daemon_control_status
119 daemon_control(struct daemon_control_params *dc)
120 {
121   int guard_fd = open(dc->guard_file, O_RDWR | O_CREAT, 0666);
122   if (guard_fd < 0)
123     return daemon_control_err(dc, "Cannot open guard file `%s': %m", dc->guard_file);
124   if (flock(guard_fd, LOCK_EX) < 0)
125     return daemon_control_err(dc, "Cannot lock guard file `%s': %m", dc->guard_file);
126
127   // Read the PID file
128   int pid, sig;
129   enum daemon_control_status st = daemon_read_pid(dc, 0, &pid);
130   if (st == DAEMON_STATUS_ERROR)
131     goto done;
132
133   switch (dc->action)
134     {
135     case DAEMON_CONTROL_CHECK:
136       break;
137     case DAEMON_CONTROL_START:
138       if (st == DAEMON_STATUS_OK)
139         st = DAEMON_STATUS_ALREADY_DONE;
140       else
141         {
142           pid_t pp = fork();
143           if (pp < 0)
144             {
145               st = daemon_control_err(dc, "Cannot fork: %m");
146               goto done;
147             }
148           if (!pp)
149             {
150               close(guard_fd);
151               execvp(dc->argv[0], dc->argv);
152               fprintf(stderr, "Cannot execute `%s': %m\n", dc->argv[0]);
153               exit(DAEMON_STATUS_ERROR);
154             }
155           int stat;
156           int ec = waitpid(pp, &stat, 0);
157           if (ec < 0)
158             {
159               st = daemon_control_err(dc, "Cannot wait: %m");
160               goto done;
161             }
162           if (WIFEXITED(stat) && WEXITSTATUS(stat) == DAEMON_STATUS_ERROR)
163             {
164               st = daemon_control_err(dc, "Cannot execute the daemon");
165               goto done;
166             }
167           char ecmsg[EXIT_STATUS_MSG_SIZE];
168           if (format_exit_status(ecmsg, stat))
169             {
170               st = daemon_control_err(dc, "Daemon %s %s", dc->argv[0], ecmsg);
171               goto done;
172             }
173           enum daemon_control_status st2 = daemon_read_pid(dc, 0, &pid);
174           if (st2 != DAEMON_STATUS_OK && st2 != DAEMON_STATUS_NOT_RUNNING)
175             st = daemon_control_err(dc, "Daemon %s failed to write the PID file `%s'", dc->argv[0], dc->pid_file);
176           else if (st != DAEMON_STATUS_STALE)
177             st = DAEMON_STATUS_OK;
178         }
179       break;
180     case DAEMON_CONTROL_STOP:
181       if (st != DAEMON_STATUS_OK)
182         {
183           if (st == DAEMON_STATUS_NOT_RUNNING)
184             st = DAEMON_STATUS_ALREADY_DONE;
185           goto done;
186         }
187       if (pid)
188         {
189           sig = dc->signal ? : SIGTERM;
190           if (kill(pid, sig) < 0 && errno != ESRCH)
191             {
192               st = daemon_control_err(dc, "Cannot send signal %d: %m", sig);
193               goto done;
194             }
195         }
196       else
197         {
198           // Just exiting daemon => we can safely wait without sending any signal
199         }
200       st = daemon_read_pid(dc, 1, &pid);
201       if (st != DAEMON_STATUS_ERROR)
202         st = DAEMON_STATUS_OK;
203       break;
204     case DAEMON_CONTROL_SIGNAL:
205       if (!pid)
206         return DAEMON_STATUS_NOT_RUNNING;
207       sig = dc->signal ? : SIGHUP;
208       if (kill(pid, sig) >= 0)
209         st = DAEMON_STATUS_OK;
210       else if (errno == ESRCH)
211         st = DAEMON_STATUS_NOT_RUNNING;
212       else
213         st = daemon_control_err(dc, "Cannot send signal %d: %m", sig);
214       break;
215     default:
216       ASSERT(0);
217     }
218
219 done:
220   close(guard_fd);
221   return st;
222 }