]> mj.ucw.cz Git - libucw.git/blob - ucw/daemon-ctrl.c
Config: daemon-helper is not compiled by default any longer
[libucw.git] / ucw / daemon-ctrl.c
1 /*
2  *      UCW Library -- Daemon Control
3  *
4  *      (c) 2012 Martin Mares <mj@ucw.cz>
5  *
6  *      This software may be freely distributed and used according to the terms
7  *      of the GNU Lesser General Public License.
8  */
9
10 #include <ucw/lib.h>
11 #include <ucw/daemon.h>
12 #include <ucw/process.h>
13
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <stdarg.h>
17 #include <fcntl.h>
18 #include <unistd.h>
19 #include <errno.h>
20 #include <signal.h>
21 #include <sys/file.h>
22 #include <sys/wait.h>
23
24 static enum daemon_control_status
25 daemon_control_err(struct daemon_control_params *dc, char *msg, ...)
26 {
27   va_list args;
28   va_start(args, msg);
29   vsnprintf(dc->error_msg, DAEMON_ERR_LEN, msg, args);
30   va_end(args);
31   return DAEMON_STATUS_ERROR;
32 }
33
34 static int
35 daemon_read_pid(struct daemon_control_params *dc, int will_wait)
36 {
37   int pid_fd = open(dc->pid_file, O_RDONLY);
38   if (pid_fd < 0)
39     {
40       if (errno == ENOENT)
41         return 0;
42       daemon_control_err(dc, "Cannot open PID file `%s': %m", dc->pid_file);
43       return -1;
44     }
45
46   if (flock(pid_fd, LOCK_EX | (will_wait ? 0 : LOCK_NB)) >= 0)
47     {
48       // The lock file is stale
49       close(pid_fd);
50       return 0;
51     }
52
53   if (errno != EINTR && errno != EWOULDBLOCK)
54     {
55       daemon_control_err(dc, "Cannot lock PID file `%s': %m", dc->pid_file);
56       goto fail;
57     }
58
59   char buf[16];
60   int n = read(pid_fd, buf, sizeof(buf));
61   if (n < 0)
62     {
63       daemon_control_err(dc, "Error reading `%s': %m", dc->pid_file);
64       goto fail;
65     }
66   if (n == (int) sizeof(buf))
67     {
68       daemon_control_err(dc, "PID file `%s' is too long", dc->pid_file);
69       goto fail;
70     }
71   buf[n] = 0;
72   int pid = atoi(buf);
73   if (!pid)
74     {
75       daemon_control_err(dc, "PID file `%s' does not contain a valid PID", dc->pid_file);
76       goto fail;
77     }
78   close(pid_fd);
79   return pid;
80
81 fail:
82   close(pid_fd);
83   return -1;
84 }
85
86 enum daemon_control_status
87 daemon_control(struct daemon_control_params *dc)
88 {
89   enum daemon_control_status st = DAEMON_STATUS_ERROR;
90   int sig;
91
92   int guard_fd = open(dc->guard_file, O_RDWR | O_CREAT, 0666);
93   if (guard_fd < 0)
94     return daemon_control_err(dc, "Cannot open guard file `%s': %m", dc->guard_file);
95   if (flock(guard_fd, LOCK_EX) < 0)
96     return daemon_control_err(dc, "Cannot lock guard file `%s': %m", dc->guard_file);
97
98   // Read the PID file
99   int pid = daemon_read_pid(dc, 0);
100   if (pid < 0)
101     goto done;
102
103   switch (dc->action)
104     {
105     case DAEMON_CONTROL_CHECK:
106       if (pid)
107         st = DAEMON_STATUS_OK;
108       else
109         st = DAEMON_STATUS_NOT_RUNNING;
110       break;
111     case DAEMON_CONTROL_START:
112       if (pid)
113         st = DAEMON_STATUS_ALREADY_DONE;
114       else
115         {
116           pid_t pp = fork();
117           if (pp < 0)
118             {
119               daemon_control_err(dc, "Cannot fork: %m");
120               goto done;
121             }
122           if (!pp)
123             {
124               close(guard_fd);
125               execvp(dc->argv[0], dc->argv);
126               fprintf(stderr, "Cannot execute `%s': %m\n", dc->argv[0]);
127               exit(DAEMON_STATUS_ERROR);
128             }
129           int stat;
130           int ec = waitpid(pp, &stat, 0);
131           if (ec < 0)
132             {
133               daemon_control_err(dc, "Cannot wait: %m");
134               goto done;
135             }
136           if (WIFEXITED(stat) && WEXITSTATUS(stat) == DAEMON_STATUS_ERROR)
137             {
138               daemon_control_err(dc, "Cannot execute the daemon");
139               goto done;
140             }
141           char ecmsg[EXIT_STATUS_MSG_SIZE];
142           if (format_exit_status(ecmsg, stat))
143             {
144               daemon_control_err(dc, "Daemon %s %s", dc->argv[0], ecmsg);
145               goto done;
146             }
147           pid = daemon_read_pid(dc, 0);
148           if (!pid)
149             daemon_control_err(dc, "Daemon %s failed to write the PID file `%s'", dc->argv[0], dc->pid_file);
150           else
151             st = DAEMON_STATUS_OK;
152         }
153       break;
154     case DAEMON_CONTROL_STOP:
155       if (!pid)
156         return DAEMON_STATUS_ALREADY_DONE;
157       sig = dc->signal ? : SIGTERM;
158       if (kill(pid, sig) < 0)
159         {
160           daemon_control_err(dc, "Cannot send signal %d: %m", sig);
161           goto done;
162         }
163       pid = daemon_read_pid(dc, 1);
164       ASSERT(pid <= 0);
165       if (!pid)
166         st = DAEMON_STATUS_OK;
167       break;
168     case DAEMON_CONTROL_SIGNAL:
169       if (!pid)
170         return DAEMON_STATUS_NOT_RUNNING;
171       sig = dc->signal ? : SIGHUP;
172       if (kill(pid, sig) < 0)
173         daemon_control_err(dc, "Cannot send signal %d: %m", sig);
174       else
175         st = DAEMON_STATUS_OK;
176       break;
177     default:
178       ASSERT(0);
179     }
180
181 done:
182   close(guard_fd);
183   return st;
184 }