| In case upstart-socket-bridge gets restarted, we want to remove any domain |
| sockets we created, and cleanup any existing sockets (e.g., from crashes), |
| since bind() will fail instead of clobbering them. |
| |
| We can't guarantee sun_path[] is zero terminated if it contains a full 108 |
| chars, so copy into a temporary buffer before unlink(). |
| |
| diff --git a/extra/upstart-socket-bridge.c b/extra/upstart-socket-bridge.c |
| index dabb9fa35cda..4b204a0ccf1a 100644 |
| --- a/extra/upstart-socket-bridge.c |
| +++ b/extra/upstart-socket-bridge.c |
| @@ -85,6 +85,7 @@ static void upstart_job_added (void *data, NihDBusMessage *message, |
| static void upstart_job_removed (void *data, NihDBusMessage *message, |
| const char *job); |
| static void job_add_socket (Job *job, char **socket_info); |
| +static void cleanup (void); |
| static void socket_destroy (Socket *socket); |
| static void upstart_disconnected (DBusConnection *connection); |
| static void emit_event_reply (Socket *sock, NihDBusMessage *message); |
| @@ -270,10 +271,28 @@ main (int argc, |
| |
| ret = nih_main_loop (); |
| |
| + cleanup (); |
| + |
| return ret; |
| } |
| |
| |
| +/* We can't guarantee sun_path was 0-terminated */ |
| +static int unlink_sun_path (const struct sockaddr_un *sun_addr) |
| +{ |
| + size_t max_len = sizeof (sun_addr->sun_path); |
| + char sun_path[max_len + 1]; |
| + |
| + if (!sun_addr->sun_path[0]) |
| + return 0; |
| + |
| + memcpy (sun_path, sun_addr->sun_path, max_len); |
| + sun_path[max_len] = '\0'; |
| + |
| + return unlink (sun_path); |
| +} |
| + |
| + |
| static void |
| epoll_watcher (void * data, |
| NihIoWatch *watch, |
| @@ -567,6 +586,12 @@ job_add_socket (Job * job, |
| goto error; |
| } |
| |
| + /* Unlink before binding, just in case. Ignore failures (e.g., |
| + * -ENOENT). |
| + */ |
| + if (sock->addr.sa_family == AF_UNIX) |
| + unlink_sun_path (&sock->sun_addr); |
| + |
| if (bind (sock->sock, &sock->addr, sock->addrlen) < 0) { |
| nih_warn ("Failed to bind socket in %s: %s", |
| job->path, strerror (errno)); |
| @@ -608,11 +633,33 @@ error: |
| } |
| |
| static void |
| +cleanup (void) |
| +{ |
| + Job *job; |
| + |
| + nih_debug ("Performing cleanup"); |
| + |
| + /* |
| + * Free each job, so it gets to clean up its resources (e.g., unlinking |
| + * local domain sockets). |
| + */ |
| + NIH_HASH_FOREACH_SAFE (jobs, job) { |
| + nih_free (job); |
| + } |
| +} |
| + |
| +static void |
| socket_destroy (Socket *sock) |
| { |
| epoll_ctl (epoll_fd, EPOLL_CTL_DEL, sock->sock, NULL); |
| close (sock->sock); |
| |
| + if (sock->addr.sa_family == AF_UNIX) { |
| + nih_debug ("Removing socket at path: %s", |
| + sock->sun_addr.sun_path); |
| + unlink_sun_path (&sock->sun_addr); |
| + } |
| + |
| nih_list_destroy (&sock->entry); |
| } |
| |