]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
master: Several fixes to handling SIGHUPs.
authorTimo Sirainen <tss@iki.fi>
Fri, 4 Sep 2009 21:06:58 +0000 (17:06 -0400)
committerTimo Sirainen <tss@iki.fi>
Fri, 4 Sep 2009 21:06:58 +0000 (17:06 -0400)
--HG--
branch : HEAD

src/master/common.h
src/master/main.c
src/master/service-auth-server.c
src/master/service-listen.c
src/master/service-monitor.c
src/master/service.c
src/master/service.h

index 027993e33365f057d8032b4d9d1e124d0a3966aa..89e46b06bc3c740e6a2550c40443350f7d466037 100644 (file)
@@ -12,6 +12,7 @@ extern gid_t master_gid;
 extern bool auth_success_written;
 extern bool core_dumps_disabled;
 extern int null_fd;
+extern struct service_list *services;
 
 void process_exec(const char *cmd, const char *extra_args[]) ATTR_NORETURN;
 
index 25a9135dbc13b043529c65870897a298c966b246..2463dd8e763d9c4b93aa40df85789cf12029e9de 100644 (file)
@@ -38,9 +38,9 @@ gid_t master_gid;
 bool auth_success_written;
 bool core_dumps_disabled;
 int null_fd;
+struct service_list *services;
 
 static char *pidfile_path;
-static struct service_list *services;
 static fatal_failure_callback_t *orig_fatal_callback;
 static const char *child_process_env[3]; /* @UNSAFE */
 
index 89eb7a98ae5e9a92a2cdad36d1a700024d51c3c2..cdbff6d2cec97837f5946ad675f8e1a7a1636ecf 100644 (file)
@@ -83,6 +83,22 @@ auth_process_lookup_request(struct service_process_auth_server *process,
        return request;
 }
 
+static struct service *
+auth_process_get_dest_service(struct service_process_auth_source *process)
+{
+       struct service *service = process->process.service;
+
+       if (!service->list->destroyed)
+               return service->auth_dest_service;
+
+       service = service_lookup(services, service->set->auth_dest_service);
+       if (service == NULL) {
+               i_warning("service(%s): Lost destination service %s",
+                         service->set->name, service->set->auth_dest_service);
+       }
+       return service;
+}
+
 static int
 auth_process_input_user(struct service_process_auth_server *process, const char *args)
 {
@@ -103,12 +119,12 @@ auth_process_input_user(struct service_process_auth_server *process, const char
 
         request = auth_process_lookup_request(process, id);
        if (request != NULL) {
-               struct service *dest_service =
-                       request->process->process.service->auth_dest_service;
+               struct service *dest_service;
                struct service_process *dest_process;
 
-               dest_process = service_process_create(dest_service, list + 1,
-                                                     request);
+               dest_service = auth_process_get_dest_service(request->process);
+               dest_process = dest_service == NULL ? NULL :
+                       service_process_create(dest_service, list + 1, request);
                status = dest_process != NULL ?
                        MASTER_AUTH_STATUS_OK :
                        MASTER_AUTH_STATUS_INTERNAL_ERROR;
index 4345134f154a27a1444897f793c7f33377d216c0..699bee8cf1f1dd0cec34ba7501f9d3fc610d8902 100644 (file)
@@ -190,16 +190,11 @@ static int listener_equals(const struct service_listener *l1,
        switch (l1->type) {
        case SERVICE_LISTENER_UNIX:
        case SERVICE_LISTENER_FIFO:
-               if (strcmp(l1->set.fileset.set->path,
-                          l2->set.fileset.set->path) != 0)
-                       return FALSE;
-               if (l1->set.fileset.set->mode != l2->set.fileset.set->mode)
-                       return FALSE;
-               if (l1->set.fileset.uid != l2->set.fileset.uid)
-                       return FALSE;
-               if (l1->set.fileset.gid != l2->set.fileset.gid)
-                       return FALSE;
-               return TRUE;
+               /* We could just keep using the same listener, but it's more
+                  likely to cause problems if old process accepts a connection
+                  before it knows that it should die. So just always unlink
+                  and recreate unix/fifo listeners. */
+               return FALSE;
        case SERVICE_LISTENER_INET:
                if (memcmp(&l1->set.inetset.ip, &l2->set.inetset.ip,
                           sizeof(l1->set.inetset.ip)) != 0)
@@ -253,6 +248,18 @@ int services_listen_using(struct service_list *new_service_list,
                        if (close(old_listeners[j]->fd) < 0)
                                i_error("close(listener) failed: %m");
                }
+               switch (old_listeners[j]->type) {
+               case SERVICE_LISTENER_UNIX:
+               case SERVICE_LISTENER_FIFO: {
+                       const char *path =
+                               old_listeners[j]->set.fileset.set->path;
+                       if (unlink(path) < 0)
+                               i_error("unlink(%s) failed: %m", path);
+                       break;
+               }
+               case SERVICE_LISTENER_INET:
+                       break;
+               }
        }
 
        /* and let services_listen() deal with the remaining fds */
index 4a174829429333d82b74171a2663838566bcee18..a8765d73bf34f5293ca5a105df6c39d66ed99b26 100644 (file)
@@ -277,6 +277,7 @@ void services_monitor_reap_children(void)
        struct service *service;
        pid_t pid;
        int status;
+       bool service_destroyed;
 
        while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
                process = hash_table_lookup(service_pids, &pid);
@@ -294,10 +295,13 @@ void services_monitor_reap_children(void)
                } else {
                        service_process_failure(process, status);
                }
+               service_destroyed = service->list->destroyed;
                service_process_destroy(process);
-               service_monitor_start_extra_avail(service);
 
-                if (service->to_throttle == NULL)
-                       service_monitor_listen_start(service);
+               if (!service_destroyed) {
+                       service_monitor_start_extra_avail(service);
+                       if (service->to_throttle == NULL)
+                               service_monitor_listen_start(service);
+               }
        }
 }
index e8ac70e836df1636fa8a800ac1b8e48a8e431a81..9bf35353a9a7a846ba809a3f44f04a71a4386411 100644 (file)
@@ -313,7 +313,7 @@ static int pid_hash_cmp(const void *p1, const void *p2)
                *pid1 > *pid2 ? 1 : 0;
 }
 
-static struct service *
+struct service *
 service_lookup(struct service_list *service_list, const char *name)
 {
        struct service *const *services;
@@ -455,22 +455,35 @@ void service_signal(struct service *service, int signo)
 
 static void services_kill_timeout(struct service_list *service_list)
 {
-       struct service *const *services;
+       struct service *const *services, *log_service;
        unsigned int i, count;
+       bool sigterm_log;
        int sig;
 
-       if (!service_list->sigterm_sent)
+       if (!service_list->sigterm_sent || !service_list->sigterm_sent_to_log)
                sig = SIGTERM;
        else
                sig = SIGKILL;
+       sigterm_log = service_list->sigterm_sent;
        service_list->sigterm_sent = TRUE;
 
        i_warning("Processes aren't dying after reload, sending %s.",
                  sig == SIGTERM ? "SIGTERM" : "SIGKILL");
 
+       log_service = NULL;
        services = array_get(&service_list->services, &count);
-       for (i = 0; i < count; i++)
-               service_signal(services[i], sig);
+       for (i = 0; i < count; i++) {
+               if (services[i]->type == SERVICE_TYPE_LOG)
+                       log_service = services[i];
+               else
+                       service_signal(services[i], sig);
+       }
+       /* kill log service later so it could still have a chance of logging
+          something */
+       if (log_service != NULL && sigterm_log) {
+               service_signal(log_service, sig);
+               service_list->sigterm_sent_to_log = TRUE;
+       }
 }
 
 void services_destroy(struct service_list *service_list)
@@ -487,6 +500,7 @@ void services_destroy(struct service_list *service_list)
                                    services_kill_timeout, service_list);
        }
 
+       service_list->destroyed = TRUE;
        service_list_unref(service_list);
 }
 
index 10b6c9286a0454689ffe979d4f78677677287af5..a28eeae7444465742a6af76e1223ae4f2c2a3e2c 100644 (file)
@@ -119,7 +119,9 @@ struct service_list {
 
        ARRAY_DEFINE(services, struct service *);
 
+       unsigned int destroyed:1;
        unsigned int sigterm_sent:1;
+       unsigned int sigterm_sent_to_log:1;
 };
 
 extern struct hash_table *service_pids;
@@ -147,6 +149,10 @@ void service_throttle(struct service *service, unsigned int secs);
 void services_throttle_time_sensitives(struct service_list *list,
                                       unsigned int secs);
 
+/* Find a service by name. */
+struct service *
+service_lookup(struct service_list *service_list, const char *name);
+
 void service_error(struct service *service, const char *format, ...)
        ATTR_FORMAT(2, 3);