X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fcore%2Fsocket.c;h=c158aaf1de4204f9d59f1ae056e0fb7933e11597;hp=536904f3091f71312acc79455efb1bcf312e7a91;hb=811ba7a0e292eda0f2f470613cc28a97bda7ee66;hpb=d38f6e34a618e2d100b06888e0810f776eb83510 diff --git a/src/core/socket.c b/src/core/socket.c index 536904f30..c158aaf1d 100644 --- a/src/core/socket.c +++ b/src/core/socket.c @@ -29,9 +29,7 @@ #include #include #include -#ifdef HAVE_XATTR -#include -#endif +#include #include "sd-event.h" #include "log.h" @@ -147,6 +145,8 @@ static void socket_done(Unit *u) { free(s->smack_ip_in); free(s->smack_ip_out); + strv_free(s->symlinks); + s->timer_event_source = sd_event_source_unref(s->timer_event_source); } @@ -357,6 +357,39 @@ static int socket_add_extras(Socket *s) { return 0; } +static const char *socket_find_symlink_target(Socket *s) { + const char *found = NULL; + SocketPort *p; + + LIST_FOREACH(port, p, s->ports) { + const char *f = NULL; + + switch (p->type) { + + case SOCKET_FIFO: + f = p->path; + break; + + case SOCKET_SOCKET: + if (p->address.sockaddr.un.sun_path[0] != 0) + f = p->address.sockaddr.un.sun_path; + break; + + default: + break; + } + + if (f) { + if (found) + return NULL; + + found = f; + } + } + + return found; +} + static int socket_verify(Socket *s) { assert(s); @@ -389,6 +422,11 @@ static int socket_verify(Socket *s) { return -EINVAL; } + if (!strv_isempty(s->symlinks) && !socket_find_symlink_target(s)) { + log_error_unit(UNIT(s)->id, "%s has symlinks set but none or more than one node in the file system. Refusing.", UNIT(s)->id); + return -EINVAL; + } + return 0; } @@ -453,7 +491,8 @@ static void socket_dump(Unit *u, FILE *f, const char *prefix) { "%sBroadcast: %s\n" "%sPassCredentials: %s\n" "%sPassSecurity: %s\n" - "%sTCPCongestion: %s\n", + "%sTCPCongestion: %s\n" + "%sRemoveOnStop: %s\n", prefix, socket_state_to_string(s->state), prefix, socket_result_to_string(s->result), prefix, socket_address_bind_ipv6_only_to_string(s->bind_ipv6_only), @@ -466,12 +505,13 @@ static void socket_dump(Unit *u, FILE *f, const char *prefix) { prefix, yes_no(s->broadcast), prefix, yes_no(s->pass_cred), prefix, yes_no(s->pass_sec), - prefix, strna(s->tcp_congestion)); + prefix, strna(s->tcp_congestion), + prefix, yes_no(s->remove_on_stop)); if (s->control_pid > 0) fprintf(f, - "%sControl PID: %lu\n", - prefix, (unsigned long) s->control_pid); + "%sControl PID: "PID_FMT"\n", + prefix, s->control_pid); if (s->bind_to_device) fprintf(f, @@ -692,6 +732,7 @@ static int instance_from_socket(int fd, unsigned nr, char **instance) { static void socket_close_fds(Socket *s) { SocketPort *p; + char **i; assert(s); @@ -704,14 +745,38 @@ static void socket_close_fds(Socket *s) { p->fd = safe_close(p->fd); - /* One little note: we should never delete any sockets - * in the file system here! After all some other - * process we spawned might still have a reference of - * this fd and wants to continue to use it. Therefore - * we delete sockets in the file system before we - * create a new one, not after we stopped using - * one! */ + /* One little note: we should normally not delete any + * sockets in the file system here! After all some + * other process we spawned might still have a + * reference of this fd and wants to continue to use + * it. Therefore we delete sockets in the file system + * before we create a new one, not after we stopped + * using one! */ + + if (s->remove_on_stop) { + switch (p->type) { + + case SOCKET_FIFO: + unlink(p->path); + break; + + case SOCKET_MQUEUE: + mq_unlink(p->path); + break; + + case SOCKET_SOCKET: + socket_address_unlink(&p->address); + break; + + default: + break; + } + } } + + if (s->remove_on_stop) + STRV_FOREACH(i, s->symlinks) + unlink(*i); } static void socket_apply_socket_options(Socket *s, int fd) { @@ -895,7 +960,8 @@ static int special_address_create( assert(path); assert(_fd); - if ((fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NONBLOCK|O_NOFOLLOW)) < 0) { + fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NONBLOCK|O_NOFOLLOW); + if (fd < 0) { r = -errno; goto fail; } @@ -948,7 +1014,6 @@ static int mq_address_create( /* Include the original umask in our mask */ umask(~mq_mode | old_mask); - fd = mq_open(path, O_RDONLY|O_CLOEXEC|O_NONBLOCK|O_CREAT, mq_mode, attr); umask(old_mask); @@ -978,6 +1043,22 @@ fail: return r; } +static int socket_symlink(Socket *s) { + const char *p; + char **i; + + assert(s); + + p = socket_find_symlink_target(s); + if (!p) + return 0; + + STRV_FOREACH(i, s->symlinks) + symlink(p, *i); + + return 0; +} + static int socket_open_fds(Socket *s) { SocketPort *p; int r; @@ -995,17 +1076,15 @@ static int socket_open_fds(Socket *s) { if (!know_label) { - if ((r = socket_instantiate_service(s)) < 0) + r = socket_instantiate_service(s); + if (r < 0) return r; if (UNIT_ISSET(s->service) && SERVICE(UNIT_DEREF(s->service))->exec_command[SERVICE_EXEC_START]) { r = label_get_create_label_from_exe(SERVICE(UNIT_DEREF(s->service))->exec_command[SERVICE_EXEC_START]->path, &label); - - if (r < 0) { - if (r != -EPERM) - return r; - } + if (r < 0 && r != -EPERM) + return r; } know_label = true; @@ -1027,6 +1106,7 @@ static int socket_open_fds(Socket *s) { p->fd = r; socket_apply_socket_options(s, p->fd); + socket_symlink(s); } else if (p->type == SOCKET_SPECIAL) { @@ -1047,6 +1127,8 @@ static int socket_open_fds(Socket *s) { goto rollback; socket_apply_fifo_options(s, p->fd); + socket_symlink(s); + } else if (p->type == SOCKET_MQUEUE) { r = mq_address_create( @@ -1123,14 +1205,15 @@ static void socket_set_state(Socket *s, SocketState state) { old_state = s->state; s->state = state; - if (state != SOCKET_START_PRE && - state != SOCKET_START_POST && - state != SOCKET_STOP_PRE && - state != SOCKET_STOP_PRE_SIGTERM && - state != SOCKET_STOP_PRE_SIGKILL && - state != SOCKET_STOP_POST && - state != SOCKET_FINAL_SIGTERM && - state != SOCKET_FINAL_SIGKILL) { + if (!IN_SET(state, + SOCKET_START_PRE, + SOCKET_START_POST, + SOCKET_STOP_PRE, + SOCKET_STOP_PRE_SIGTERM, + SOCKET_STOP_PRE_SIGKILL, + SOCKET_STOP_POST, + SOCKET_FINAL_SIGTERM, + SOCKET_FINAL_SIGKILL)) { s->timer_event_source = sd_event_source_unref(s->timer_event_source); socket_unwatch_control_pid(s); @@ -1141,12 +1224,13 @@ static void socket_set_state(Socket *s, SocketState state) { if (state != SOCKET_LISTENING) socket_unwatch_fds(s); - if (state != SOCKET_START_POST && - state != SOCKET_LISTENING && - state != SOCKET_RUNNING && - state != SOCKET_STOP_PRE && - state != SOCKET_STOP_PRE_SIGTERM && - state != SOCKET_STOP_PRE_SIGKILL) + if (!IN_SET(state, + SOCKET_START_POST, + SOCKET_LISTENING, + SOCKET_RUNNING, + SOCKET_STOP_PRE, + SOCKET_STOP_PRE_SIGTERM, + SOCKET_STOP_PRE_SIGKILL)) socket_close_fds(s); if (state != old_state) @@ -1503,6 +1587,12 @@ static void socket_enter_running(Socket *s, int cfd) { } if (!pending) { + if (!UNIT_ISSET(s->service)) { + log_error_unit(UNIT(s)->id, "%s: service to activate vanished, refusing activation.", UNIT(s)->id); + r = -ENOENT; + goto fail; + } + r = manager_add_job(UNIT(s)->manager, JOB_START, UNIT_DEREF(s->service), JOB_REPLACE, true, &error, NULL); if (r < 0) goto fail; @@ -1710,7 +1800,7 @@ static int socket_serialize(Unit *u, FILE *f, FDSet *fds) { unit_serialize_item_format(u, f, "n-accepted", "%u", s->n_accepted); if (s->control_pid > 0) - unit_serialize_item_format(u, f, "control-pid", "%lu", (unsigned long) s->control_pid); + unit_serialize_item_format(u, f, "control-pid", PID_FMT, s->control_pid); if (s->control_command_id >= 0) unit_serialize_item(u, f, "control-command", socket_exec_command_to_string(s->control_command_id));