#include <arpa/inet.h>
#include <netinet/tcp.h>
#include <mqueue.h>
-#ifdef HAVE_XATTR
-#include <attr/xattr.h>
-#endif
+#include <sys/xattr.h>
#include "sd-event.h"
#include "log.h"
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);
}
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);
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;
}
"%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),
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,
static void socket_close_fds(Socket *s) {
SocketPort *p;
+ char **i;
assert(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) {
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;
}
/* 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);
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;
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;
p->fd = r;
socket_apply_socket_options(s, p->fd);
+ socket_symlink(s);
} else if (p->type == SOCKET_SPECIAL) {
goto rollback;
socket_apply_fifo_options(s, p->fd);
+ socket_symlink(s);
+
} else if (p->type == SOCKET_MQUEUE) {
r = mq_address_create(
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);
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)
}
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;
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));