}
/* ------------------ */
-static void sigterm_handler(int sig)
+static void sig_handler(int sig)
{
switch( sig ) {
- case SIGTERM :
- LOG(log_info, logtype_afpd, "shutting down on signal %d", sig );
+ case SIGTERM:
+ case SIGQUIT:
+ LOG(log_note, logtype_afpd, "shutting down on %s",
+ sig == SIGTERM ? "SIGTERM" : "SIGQUIT");
break;
default :
LOG(log_error, logtype_afpd, "unexpected signal: %d", sig);
daemon_exit(EXITERR_SYS);
}
- /* Catch SIGTERM */
- sv.sa_handler = sigterm_handler;
+ /* Catch SIGTERM and SIGQUIT */
+ sv.sa_handler = sig_handler;
sigfillset(&sv.sa_mask );
if (sigaction(SIGTERM, &sv, NULL ) < 0 ) {
LOG(log_error, logtype_afpd, "sigaction: %s", strerror(errno) );
daemon_exit(EXITERR_SYS);
}
+ if (sigaction(SIGQUIT, &sv, NULL ) < 0 ) {
+ LOG(log_error, logtype_afpd, "sigaction: %s", strerror(errno) );
+ daemon_exit(EXITERR_SYS);
+ }
/* Ignore the rest */
sv.sa_handler = SIG_IGN;
/* forward declaration */
static pid_t run_process(const char *path, ...);
-static void kill_childs(int count, int sig, ...);
+static void kill_childs(int sig, ...);
/* static variables */
static AFPObj obj;
static void sigquit_cb(evutil_socket_t fd, short what, void *arg)
{
LOG(log_note, logtype_afpd, "Exiting on SIGQUIT");
- in_shutdown = 1;
- event_base_loopbreak(base);
+ kill_childs(SIGQUIT, &afpd_pid, &cnid_metad_pid, NULL);
}
/* SIGCHLD callback */
* helper functions
******************************************************************/
-/* kill "count" processes passed as varargs of type "pid_t *" */
-static void kill_childs(int count, int sig, ...)
+/* kill processes passed as varargs of type "pid_t *", terminate list with NULL */
+static void kill_childs(int sig, ...)
{
va_list args;
pid_t *pid;
va_start(args, sig);
- while (count--) {
- pid = va_arg(args, pid_t *);
+ while ((pid = va_arg(args, pid_t *)) != NULL) {
if (*pid == -1)
continue;
kill(*pid, sig);
}
sigterm_ev = event_new(base, SIGTERM, EV_SIGNAL, sigterm_cb, NULL);
- sigquit_ev = event_new(base, SIGQUIT, EV_SIGNAL, sigquit_cb, NULL);
+ sigquit_ev = event_new(base, SIGQUIT, EV_SIGNAL | EV_PERSIST, sigquit_cb, NULL);
sigchld_ev = event_new(base, SIGCHLD, EV_SIGNAL | EV_PERSIST, sigchld_cb, NULL);
event_add(sigterm_ev, NULL);
/* run the event loop */
ret = event_base_dispatch(base);
- /* got SIGTERM or similar, so we're going to shutdown */
+ /* got SIGTERM so we're going to shutdown */
/* block any signal but SIGCHLD */
sigfillset(&blocksigs);
event_del(sigquit_ev);
/* run the event loop again, waiting for child to exit on SIGTERM for KILL_GRACETIME seconds */
- kill_childs(2, SIGTERM, &afpd_pid, &cnid_metad_pid);
+ kill_childs(SIGTERM, &afpd_pid, &cnid_metad_pid, NULL);
ret = event_base_dispatch(base);
if (afpd_pid != -1 || cnid_metad_pid != -1) {
LOG(log_error, logtype_afpd, "AFP service did not shutdown, killing it");
if (cnid_metad_pid != -1)
LOG(log_error, logtype_afpd, "CNID database service did not shutdown, killing it");
- kill_childs(2, SIGKILL, &afpd_pid, &cnid_metad_pid);
+ kill_childs(SIGKILL, &afpd_pid, &cnid_metad_pid, NULL);
}
netatalk_exit(ret);
}
.sp
.RE
.PP
-ldap uuuid attr = \fIdn\fR \fB(G)\fR
+ldap uuid attr = \fIdn\fR \fB(G)\fR
.RS 4
Name of the LDAP attribute with the UUIDs\&.
.sp
.PP
keep sessions = \fIBOOLEAN\fR (default: \fIno\fR) \fB(G)\fR
.RS 4
-Enable "Continuous AFP Service"\&. This means the ability to stop the master afpd process with a SIGQUIT signal, possibly install an afpd update and start the afpd process\&. Existing AFP sessions afpd processes will remain unaffected\&. Technically they will be notified of the master afpd shutdown, sleep 15\-20 seconds and then try to reconnect their IPC channel to the master afpd process\&. If this reconnect fails, the sessions are in an undefined state\&. Therefor it\'s absolutely critical to restart the master process in time!
+Enable "Continuous AFP Service"\&. This means restarting AFP and CNID service daemons master processes, but keeping the AFP session processes\&. This can be used to install (most) updates to Netatalk without interruping active AFP sessions\&. Existing AFP sessions will still run the version from before updating, but new AFP sessions will run the updated code\&. After enabling this option when sending SIGQUIT to the
+\fInetatalk\fR
+service controller process, the AFP and CNID daemons will exit and then the service controller will restart them\&. AFP session processes are notified of the master afpd shutdown, they will then sleep 15\-20 seconds and then try to reconnect their IPC channel to the master afpd process\&. The IPC channel between the AFP master service daemon and the AFP session child is used for keeping session state of AFP sessions in the AFP master process\&. The session state is needed when AFP clients experience eg network outages and try to reconnect to the AFP server\&.
.RE
.PP
map acls = \fIBOOLEAN\fR (default: \fIyes\fR) \fB(G)\fR