]> arthur.barton.de Git - netatalk.git/blob - etc/netatalk/netatalk.c
Merge branch 'release-3-0-alpha2'
[netatalk.git] / etc / netatalk / netatalk.c
1 /*
2  * Copyright (c) 1990,1993 Regents of The University of Michigan.
3  * All Rights Reserved.  See COPYRIGHT.
4  */
5
6 #ifdef HAVE_CONFIG_H
7 #include "config.h"
8 #endif /* HAVE_CONFIG_H */
9
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <signal.h>
14 #include <sys/param.h>
15 #include <sys/uio.h>
16 #include <sys/time.h>
17 #include <sys/socket.h>
18 #include <sys/poll.h>
19 #include <errno.h>
20 #include <sys/wait.h>
21 #include <sys/resource.h>
22
23 #include <atalk/logger.h>
24 #include <atalk/adouble.h>
25 #include <atalk/compat.h>
26 #include <atalk/dsi.h>
27 #include <atalk/afp.h>
28 #include <atalk/paths.h>
29 #include <atalk/util.h>
30 #include <atalk/server_child.h>
31 #include <atalk/server_ipc.h>
32 #include <atalk/errchk.h>
33 #include <atalk/globals.h>
34 #include <atalk/netatalk_conf.h>
35
36 #include <event2/event.h>
37
38 /* how many seconds we wait to shutdown from SIGTERM before we send SIGKILL */
39 #define KILL_GRACETIME 5
40
41 /* forward declaration */
42 static pid_t run_process(const char *path, ...);
43 static void kill_childs(int sig, ...);
44
45 /* static variables */
46 static AFPObj obj;
47 static sig_atomic_t got_chldsig;
48 static pid_t afpd_pid = -1,  cnid_metad_pid = -1;
49 static uint afpd_restarts, cnid_metad_restarts;
50 static struct event_base *base;
51 struct event *sigterm_ev, *sigquit_ev, *sigchld_ev, *timer_ev;
52 static int in_shutdown;
53
54 /******************************************************************
55  * libevent helper functions
56  ******************************************************************/
57
58 /* libevent logging callback */
59 static void libevent_logmsg_cb(int severity, const char *msg)
60 {
61     switch (severity) {
62     case _EVENT_LOG_DEBUG:
63         LOG(log_debug, logtype_default, "libevent: %s", msg);
64         break;
65     case _EVENT_LOG_MSG:
66         LOG(log_info, logtype_default, "libevent: %s", msg);
67         break;
68     case _EVENT_LOG_WARN:
69         LOG(log_warning, logtype_default, "libevent: %s", msg);
70         break;
71     case _EVENT_LOG_ERR:
72         LOG(log_error, logtype_default, "libevent: %s", msg);
73         break;
74     default:
75         LOG(log_error, logtype_default, "libevent: %s", msg);
76         break; /* never reached */
77     }
78 }
79
80 /******************************************************************
81  * libevent event callbacks
82  ******************************************************************/
83
84 /* SIGTERM callback */
85 static void sigterm_cb(evutil_socket_t fd, short what, void *arg)
86 {
87     sigset_t sigs;
88     struct timeval tv;
89
90     LOG(log_info, logtype_afpd, "Exiting on SIGTERM");
91
92     if (in_shutdown)
93         return;
94     in_shutdown = 1;
95
96     /* block any signal but SIGCHLD */
97     sigfillset(&sigs);
98     sigdelset(&sigs, SIGCHLD);
99     sigprocmask(SIG_SETMASK, &sigs, NULL);
100
101     /* add 10 sec timeout timer, remove all events but SIGCHLD */
102     tv.tv_sec = KILL_GRACETIME;
103     tv.tv_usec = 0;
104     event_base_loopexit(base, &tv);
105     event_del(sigterm_ev);
106     event_del(sigquit_ev);
107     event_del(timer_ev);
108
109     kill_childs(SIGTERM, &afpd_pid, &cnid_metad_pid, NULL);
110 }
111
112 /* SIGQUIT callback */
113 static void sigquit_cb(evutil_socket_t fd, short what, void *arg)
114 {
115     LOG(log_note, logtype_afpd, "Exiting on SIGQUIT");
116     kill_childs(SIGQUIT, &afpd_pid, &cnid_metad_pid, NULL);
117 }
118
119 /* SIGCHLD callback */
120 static void sigchld_cb(evutil_socket_t fd, short what, void *arg)
121 {
122     int status, i;
123     pid_t pid;
124
125     LOG(log_debug, logtype_afpd, "Got SIGCHLD event");
126   
127     while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
128         if (WIFEXITED(status)) {
129             if (WEXITSTATUS(status))
130                 LOG(log_info, logtype_afpd, "child[%d]: exited %d", pid, WEXITSTATUS(status));
131             else
132                 LOG(log_info, logtype_afpd, "child[%d]: done", pid);
133         } else {
134             if (WIFSIGNALED(status))
135                 LOG(log_info, logtype_afpd, "child[%d]: killed by signal %d", pid, WTERMSIG(status));
136             else
137                 LOG(log_info, logtype_afpd, "child[%d]: died", pid);
138         }
139
140         if (pid == afpd_pid)
141             afpd_pid = -1;
142         else if (pid = cnid_metad_pid)
143             cnid_metad_pid = -1;
144         else
145             LOG(log_error, logtype_afpd, "Bad pid: %d", pid);
146     }
147
148     if (in_shutdown && afpd_pid == -1 && cnid_metad_pid == -1)
149         event_base_loopbreak(base);
150 }
151
152 /* timer callback */
153 static void timer_cb(evutil_socket_t fd, short what, void *arg)
154 {
155     static int i = 0;
156     LOG(log_debug, logtype_afpd, "looping: %i", i++);
157
158     if (in_shutdown)
159         return;
160
161     if (afpd_pid == -1) {
162         afpd_restarts++;
163         LOG(log_note, logtype_afpd, "Restarting 'afpd' (restarts: %u)", afpd_restarts);
164         if ((afpd_pid = run_process(_PATH_AFPD, "-d", "-F", obj.options.configfile, NULL)) == -1) {
165             LOG(log_error, logtype_afpd, "Error starting 'afpd'");
166         }
167     }
168
169     if (cnid_metad_pid == -1) {
170         cnid_metad_restarts++;
171         LOG(log_note, logtype_afpd, "Restarting 'cnid_metad' (restarts: %u)", cnid_metad_restarts);
172         if ((cnid_metad_pid = run_process(_PATH_CNID_METAD, "-d", "-F", obj.options.configfile, NULL)) == -1) {
173             LOG(log_error, logtype_afpd, "Error starting 'cnid_metad'");
174         }
175     }
176 }
177
178 /******************************************************************
179  * helper functions
180  ******************************************************************/
181
182 /* kill processes passed as varargs of type "pid_t *", terminate list with NULL */
183 static void kill_childs(int sig, ...)
184 {
185     va_list args;
186     pid_t *pid;
187
188     va_start(args, sig);
189
190     while ((pid = va_arg(args, pid_t *)) != NULL) {
191         if (*pid == -1)
192             continue;
193         kill(*pid, sig);
194     }
195     va_end(args);
196 }
197
198 /* this get called when error conditions are met that require us to exit gracefully */
199 static void netatalk_exit(int ret)
200 {
201     server_unlock(_PATH_NETATALK_LOCK);
202     exit(ret);
203 }
204
205 /* this forks() and exec() "path" with varags as argc[] */
206 static pid_t run_process(const char *path, ...)
207 {
208     int ret, i = 0;
209     char *myargv[10];
210     va_list args;
211     pid_t pid;
212
213     if ((pid = fork()) < 0) {
214         LOG(log_error, logtype_cnid, "error in fork: %s", strerror(errno));
215         return -1;
216     }
217
218     if (pid == 0) {
219         myargv[i++] = (char *)path;
220         va_start(args, path);
221         while ((myargv[i++] = va_arg(args, char *)) != NULL)
222             ;
223         va_end(args);
224
225         ret = execv(path, myargv);
226
227         /* Yikes! We're still here, so exec failed... */
228         LOG(log_error, logtype_cnid, "Fatal error in exec: %s", strerror(errno));
229         exit(1);
230     }
231     return pid;
232 }
233
234 static void usage(void)
235 {
236     printf("usage: netatalk [-F configfile] \n");
237 }
238
239 int main(int argc, char **argv)
240 {
241     const char *configfile = NULL;
242     int c, ret, debug = 0;
243     sigset_t blocksigs;
244     struct timeval tv;
245
246     /* Log SIGBUS/SIGSEGV SBT */
247     fault_setup(NULL);
248
249     while ((c = getopt(argc, argv, ":dF:")) != -1) {
250         switch(c) {
251         case 'd':
252             debug = 1;
253             break;
254         case 'F':
255             obj.cmdlineconfigfile = strdup(optarg);
256             break;
257         default:
258             usage();
259             exit(EXIT_FAILURE);
260         }
261     }
262
263     if (check_lockfile("netatalk", _PATH_NETATALK_LOCK) != 0)
264         exit(EXITERR_SYS);
265
266     if (!debug && daemonize(0, 0) != 0)
267         exit(EXITERR_SYS);
268
269     if (create_lockfile("netatalk", _PATH_NETATALK_LOCK) != 0)
270         exit(EXITERR_SYS);
271
272     sigfillset(&blocksigs);
273     sigprocmask(SIG_SETMASK, &blocksigs, NULL);
274     
275     if (afp_config_parse(&obj) != 0)
276         netatalk_exit(EXITERR_CONF);
277
278     set_processname("netatalk");
279     setuplog(obj.options.logconfig, obj.options.logfile);
280     event_set_log_callback(libevent_logmsg_cb);
281     event_set_fatal_callback(netatalk_exit);
282
283     LOG(log_note, logtype_default, "Netatalk AFP server starting");
284
285     if ((afpd_pid = run_process(_PATH_AFPD, "-d", "-F", obj.options.configfile, NULL)) == -1) {
286         LOG(log_error, logtype_afpd, "Error starting 'cnid_metad'");
287         netatalk_exit(EXITERR_CONF);
288     }
289
290     if ((cnid_metad_pid = run_process(_PATH_CNID_METAD, "-d", "-F", obj.options.configfile, NULL)) == -1) {
291         LOG(log_error, logtype_afpd, "Error starting 'cnid_metad'");
292         netatalk_exit(EXITERR_CONF);
293     }
294
295     if ((base = event_base_new()) == NULL) {
296         LOG(log_error, logtype_afpd, "Error starting event loop");
297         netatalk_exit(EXITERR_CONF);
298     }
299
300     sigterm_ev = event_new(base, SIGTERM, EV_SIGNAL, sigterm_cb, NULL);
301     sigquit_ev = event_new(base, SIGQUIT, EV_SIGNAL | EV_PERSIST, sigquit_cb, NULL);
302     sigchld_ev = event_new(base, SIGCHLD, EV_SIGNAL | EV_PERSIST, sigchld_cb, NULL);
303     timer_ev = event_new(base, -1, EV_PERSIST, timer_cb, NULL);
304
305     tv.tv_sec = 1;
306     tv.tv_usec = 0;
307
308     event_add(sigterm_ev, NULL);
309     event_add(sigquit_ev, NULL);
310     event_add(sigchld_ev, NULL);
311     event_add(timer_ev, &tv);
312
313     sigfillset(&blocksigs);
314     sigdelset(&blocksigs, SIGTERM);
315     sigdelset(&blocksigs, SIGQUIT);
316     sigdelset(&blocksigs, SIGCHLD);
317     sigprocmask(SIG_SETMASK, &blocksigs, NULL);
318
319     /* run the event loop */
320     ret = event_base_dispatch(base);
321
322     if (afpd_pid != -1 || cnid_metad_pid != -1) {
323         if (afpd_pid != -1)
324             LOG(log_error, logtype_afpd, "AFP service did not shutdown, killing it");
325         if (cnid_metad_pid != -1)
326             LOG(log_error, logtype_afpd, "CNID database service did not shutdown, killing it");
327         kill_childs(SIGKILL, &afpd_pid, &cnid_metad_pid, NULL);
328     }
329
330     LOG(log_note, logtype_afpd, "Netatalk AFP server exiting");
331
332     netatalk_exit(ret);
333 }