summaryrefslogtreecommitdiff
path: root/src/core/socket.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/socket.c')
-rw-r--r--src/core/socket.c348
1 files changed, 165 insertions, 183 deletions
diff --git a/src/core/socket.c b/src/core/socket.c
index 54e94c4f74..3c7f972fbc 100644
--- a/src/core/socket.c
+++ b/src/core/socket.c
@@ -19,38 +19,46 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <sys/stat.h>
-#include <unistd.h>
+#include <arpa/inet.h>
#include <errno.h>
#include <fcntl.h>
-#include <sys/epoll.h>
-#include <signal.h>
-#include <arpa/inet.h>
-#include <netinet/tcp.h>
#include <mqueue.h>
+#include <netinet/tcp.h>
+#include <signal.h>
+#include <sys/epoll.h>
+#include <sys/stat.h>
+#include <unistd.h>
#include "sd-event.h"
+
+#include "alloc-util.h"
+#include "bus-error.h"
+#include "bus-util.h"
+#include "copy.h"
+#include "dbus-socket.h"
+#include "def.h"
+#include "exit-status.h"
+#include "fd-util.h"
+#include "formats-util.h"
+#include "label.h"
#include "log.h"
-#include "strv.h"
+#include "missing.h"
#include "mkdir.h"
+#include "parse-util.h"
#include "path-util.h"
-#include "unit-name.h"
-#include "unit-printf.h"
-#include "missing.h"
-#include "special.h"
-#include "label.h"
-#include "exit-status.h"
-#include "def.h"
-#include "smack-util.h"
-#include "bus-util.h"
-#include "bus-error.h"
+#include "process-util.h"
#include "selinux-util.h"
-#include "dbus-socket.h"
-#include "unit.h"
-#include "formats-util.h"
#include "signal-util.h"
+#include "smack-util.h"
#include "socket.h"
-#include "copy.h"
+#include "special.h"
+#include "string-table.h"
+#include "string-util.h"
+#include "strv.h"
+#include "unit-name.h"
+#include "unit-printf.h"
+#include "unit.h"
+#include "user-util.h"
static const UnitActiveState state_translation_table[_SOCKET_STATE_MAX] = {
[SOCKET_DEAD] = UNIT_INACTIVE,
@@ -106,11 +114,9 @@ static void socket_unwatch_control_pid(Socket *s) {
}
static void socket_cleanup_fd_list(SocketPort *p) {
- int k = p->n_auxiliary_fds;
-
- while (k--)
- safe_close(p->auxiliary_fds[k]);
+ assert(p);
+ close_many(p->auxiliary_fds, p->n_auxiliary_fds);
p->auxiliary_fds = mfree(p->auxiliary_fds);
p->n_auxiliary_fds = 0;
}
@@ -506,6 +512,8 @@ static void socket_dump(Unit *u, FILE *f, const char *prefix) {
"%sPassSecurity: %s\n"
"%sTCPCongestion: %s\n"
"%sRemoveOnStop: %s\n"
+ "%sWritable: %s\n"
+ "%sFDName: %s\n"
"%sSELinuxContextFromNet: %s\n",
prefix, socket_state_to_string(s->state),
prefix, socket_result_to_string(s->result),
@@ -522,6 +530,8 @@ static void socket_dump(Unit *u, FILE *f, const char *prefix) {
prefix, yes_no(s->pass_sec),
prefix, strna(s->tcp_congestion),
prefix, yes_no(s->remove_on_stop),
+ prefix, yes_no(s->writable),
+ prefix, socket_fdname(s),
prefix, yes_no(s->selinux_context_from_net));
if (s->control_pid > 0)
@@ -642,7 +652,8 @@ static void socket_dump(Unit *u, FILE *f, const char *prefix) {
int r;
char *k = NULL;
- if ((r = socket_address_print(&p->address, &k)) < 0)
+ r = socket_address_print(&p->address, &k);
+ if (r < 0)
t = strerror(-r);
else
t = k;
@@ -955,50 +966,48 @@ static void socket_apply_fifo_options(Socket *s, int fd) {
if (s->pipe_size > 0)
if (fcntl(fd, F_SETPIPE_SZ, s->pipe_size) < 0)
- log_unit_warning_errno(UNIT(s), errno, "F_SETPIPE_SZ: %m");
+ log_unit_warning_errno(UNIT(s), errno, "Setting pipe size failed, ignoring: %m");
if (s->smack) {
r = mac_smack_apply_fd(fd, SMACK_ATTR_ACCESS, s->smack);
if (r < 0)
- log_unit_error_errno(UNIT(s), r, "mac_smack_apply_fd: %m");
+ log_unit_error_errno(UNIT(s), r, "SMACK relabelling failed, ignoring: %m");
}
}
static int fifo_address_create(
const char *path,
mode_t directory_mode,
- mode_t socket_mode,
- int *_fd) {
+ mode_t socket_mode) {
- int fd = -1, r = 0;
- struct stat st;
+ _cleanup_close_ int fd = -1;
mode_t old_mask;
+ struct stat st;
+ int r;
assert(path);
- assert(_fd);
mkdir_parents_label(path, directory_mode);
r = mac_selinux_create_file_prepare(path, S_IFIFO);
if (r < 0)
- goto fail;
+ return r;
/* Enforce the right access mode for the fifo */
old_mask = umask(~ socket_mode);
/* Include the original umask in our mask */
- umask(~socket_mode | old_mask);
+ (void) umask(~socket_mode | old_mask);
r = mkfifo(path, socket_mode);
- umask(old_mask);
+ (void) umask(old_mask);
if (r < 0 && errno != EEXIST) {
r = -errno;
goto fail;
}
- fd = open(path,
- O_RDWR | O_CLOEXEC | O_NOCTTY | O_NONBLOCK | O_NOFOLLOW);
+ fd = open(path, O_RDWR | O_CLOEXEC | O_NOCTTY | O_NONBLOCK | O_NOFOLLOW);
if (fd < 0) {
r = -errno;
goto fail;
@@ -1015,66 +1024,50 @@ static int fifo_address_create(
(st.st_mode & 0777) != (socket_mode & ~old_mask) ||
st.st_uid != getuid() ||
st.st_gid != getgid()) {
-
r = -EEXIST;
goto fail;
}
- *_fd = fd;
- return 0;
+ r = fd;
+ fd = -1;
+
+ return r;
fail:
mac_selinux_create_file_clear();
- safe_close(fd);
-
return r;
}
-static int special_address_create(
- const char *path,
- int *_fd) {
-
- int fd = -1, r = 0;
+static int special_address_create(const char *path, bool writable) {
+ _cleanup_close_ int fd = -1;
struct stat st;
+ int r;
assert(path);
- assert(_fd);
- fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NONBLOCK|O_NOFOLLOW);
- if (fd < 0) {
- r = -errno;
- goto fail;
- }
+ fd = open(path, (writable ? O_RDWR : O_RDONLY)|O_CLOEXEC|O_NOCTTY|O_NONBLOCK|O_NOFOLLOW);
+ if (fd < 0)
+ return -errno;
- if (fstat(fd, &st) < 0) {
- r = -errno;
- goto fail;
- }
+ if (fstat(fd, &st) < 0)
+ return -errno;
/* Check whether this is a /proc, /sys or /dev file or char device */
- if (!S_ISREG(st.st_mode) && !S_ISCHR(st.st_mode)) {
- r = -EEXIST;
- goto fail;
- }
-
- *_fd = fd;
- return 0;
+ if (!S_ISREG(st.st_mode) && !S_ISCHR(st.st_mode))
+ return -EEXIST;
-fail:
- safe_close(fd);
+ r = fd;
+ fd = -1;
return r;
}
-static int ffs_address_create(
- const char *path,
- int *_fd) {
-
+static int usbffs_address_create(const char *path) {
_cleanup_close_ int fd = -1;
struct stat st;
+ int r;
assert(path);
- assert(_fd);
fd = open(path, O_RDWR|O_CLOEXEC|O_NOCTTY|O_NONBLOCK|O_NOFOLLOW);
if (fd < 0)
@@ -1087,32 +1080,32 @@ static int ffs_address_create(
if (!S_ISREG(st.st_mode))
return -EEXIST;
- *_fd = fd;
+ r = fd;
fd = -1;
- return 0;
+ return r;
}
static int mq_address_create(
const char *path,
mode_t mq_mode,
long maxmsg,
- long msgsize,
- int *_fd) {
+ long msgsize) {
- int fd = -1, r = 0;
+ _cleanup_close_ int fd = -1;
struct stat st;
mode_t old_mask;
struct mq_attr _attr, *attr = NULL;
+ int r;
assert(path);
- assert(_fd);
if (maxmsg > 0 && msgsize > 0) {
- zero(_attr);
- _attr.mq_flags = O_NONBLOCK;
- _attr.mq_maxmsg = maxmsg;
- _attr.mq_msgsize = msgsize;
+ _attr = (struct mq_attr) {
+ .mq_flags = O_NONBLOCK,
+ .mq_maxmsg = maxmsg,
+ .mq_msgsize = msgsize,
+ };
attr = &_attr;
}
@@ -1120,33 +1113,24 @@ static int mq_address_create(
old_mask = umask(~ mq_mode);
/* Include the original umask in our mask */
- umask(~mq_mode | old_mask);
+ (void) umask(~mq_mode | old_mask);
fd = mq_open(path, O_RDONLY|O_CLOEXEC|O_NONBLOCK|O_CREAT, mq_mode, attr);
- umask(old_mask);
+ (void) umask(old_mask);
- if (fd < 0) {
- r = -errno;
- goto fail;
- }
+ if (fd < 0)
+ return -errno;
- if (fstat(fd, &st) < 0) {
- r = -errno;
- goto fail;
- }
+ if (fstat(fd, &st) < 0)
+ return -errno;
if ((st.st_mode & 0777) != (mq_mode & ~old_mask) ||
st.st_uid != getuid() ||
- st.st_gid != getgid()) {
-
- r = -EEXIST;
- goto fail;
- }
+ st.st_gid != getgid())
+ return -EEXIST;
- *_fd = fd;
- return 0;
+ r = fd;
+ fd = -1;
-fail:
- safe_close(fd);
return r;
}
@@ -1166,8 +1150,7 @@ static int socket_symlink(Socket *s) {
return 0;
}
-static int ffs_write_descs(int fd, Unit *u) {
- Service *s = SERVICE(u);
+static int usbffs_write_descs(int fd, Service *s) {
int r;
if (!s->usb_function_descriptors || !s->usb_function_strings)
@@ -1175,27 +1158,25 @@ static int ffs_write_descs(int fd, Unit *u) {
r = copy_file_fd(s->usb_function_descriptors, fd, false);
if (r < 0)
- return 0;
-
- r = copy_file_fd(s->usb_function_strings, fd, false);
+ return r;
- return r;
+ return copy_file_fd(s->usb_function_strings, fd, false);
}
-static int select_ep(const struct dirent *d) {
+static int usbffs_select_ep(const struct dirent *d) {
return d->d_name[0] != '.' && !streq(d->d_name, "ep0");
}
-static int ffs_dispatch_eps(SocketPort *p) {
+static int usbffs_dispatch_eps(SocketPort *p) {
_cleanup_free_ struct dirent **ent = NULL;
- int r, i, n, k;
_cleanup_free_ char *path = NULL;
+ int r, i, n, k;
- r = path_get_parent(p->path, &path);
- if (r < 0)
- return r;
+ path = dirname_malloc(p->path);
+ if (!path)
+ return -ENOMEM;
- r = scandir(path, &ent, select_ep, alphasort);
+ r = scandir(path, &ent, usbffs_select_ep, alphasort);
if (r < 0)
return -errno;
@@ -1216,10 +1197,12 @@ static int ffs_dispatch_eps(SocketPort *p) {
path_kill_slashes(ep);
- r = ffs_address_create(ep, &p->auxiliary_fds[k]);
+ r = usbffs_address_create(ep);
if (r < 0)
goto fail;
+ p->auxiliary_fds[k] = r;
+
++k;
free(ent[i]);
}
@@ -1227,9 +1210,7 @@ static int ffs_dispatch_eps(SocketPort *p) {
return r;
fail:
- while (k)
- safe_close(p->auxiliary_fds[--k]);
-
+ close_many(p->auxiliary_fds, k);
p->auxiliary_fds = mfree(p->auxiliary_fds);
p->n_auxiliary_fds = 0;
@@ -1237,10 +1218,10 @@ fail:
}
static int socket_open_fds(Socket *s) {
+ _cleanup_(mac_selinux_freep) char *label = NULL;
+ bool know_label = false;
SocketPort *p;
int r;
- char *label = NULL;
- bool know_label = false;
assert(s);
@@ -1249,7 +1230,9 @@ static int socket_open_fds(Socket *s) {
if (p->fd >= 0)
continue;
- if (p->type == SOCKET_SOCKET) {
+ switch (p->type) {
+
+ case SOCKET_SOCKET:
if (!know_label) {
/* Figure out label, if we don't it know
@@ -1300,64 +1283,72 @@ static int socket_open_fds(Socket *s) {
p->fd = r;
socket_apply_socket_options(s, p->fd);
socket_symlink(s);
+ break;
- } else if (p->type == SOCKET_SPECIAL) {
+ case SOCKET_SPECIAL:
- r = special_address_create(
- p->path,
- &p->fd);
- if (r < 0)
+ p->fd = special_address_create(p->path, s->writable);
+ if (p->fd < 0) {
+ r = p->fd;
goto rollback;
+ }
+ break;
- } else if (p->type == SOCKET_FIFO) {
+ case SOCKET_FIFO:
- r = fifo_address_create(
+ p->fd = fifo_address_create(
p->path,
s->directory_mode,
- s->socket_mode,
- &p->fd);
- if (r < 0)
+ s->socket_mode);
+ if (p->fd < 0) {
+ r = p->fd;
goto rollback;
+ }
socket_apply_fifo_options(s, p->fd);
socket_symlink(s);
+ break;
- } else if (p->type == SOCKET_MQUEUE) {
+ case SOCKET_MQUEUE:
- r = mq_address_create(
+ p->fd = mq_address_create(
p->path,
s->socket_mode,
s->mq_maxmsg,
- s->mq_msgsize,
- &p->fd);
- if (r < 0)
+ s->mq_msgsize);
+ if (p->fd < 0) {
+ r = p->fd;
goto rollback;
- } else if (p->type == SOCKET_USB_FUNCTION) {
+ }
+ break;
- r = ffs_address_create(
- p->path,
- &p->fd);
- if (r < 0)
+ case SOCKET_USB_FUNCTION:
+
+ p->fd = usbffs_address_create(p->path);
+ if (p->fd < 0) {
+ r = p->fd;
goto rollback;
+ }
- r = ffs_write_descs(p->fd, s->service.unit);
+ r = usbffs_write_descs(p->fd, SERVICE(UNIT_DEREF(s->service)));
if (r < 0)
goto rollback;
- r = ffs_dispatch_eps(p);
+ r = usbffs_dispatch_eps(p);
if (r < 0)
goto rollback;
- } else
+
+ break;
+
+ default:
assert_not_reached("Unknown port type");
+ }
}
- mac_selinux_free(label);
return 0;
rollback:
socket_close_fds(s);
- mac_selinux_free(label);
-
return r;
}
@@ -1464,7 +1455,9 @@ static int socket_coldplug(Unit *u) {
if (s->deserialized_state == s->state)
return 0;
- if (IN_SET(s->deserialized_state,
+ if (s->control_pid > 0 &&
+ pid_is_unwaited(s->control_pid) &&
+ IN_SET(s->deserialized_state,
SOCKET_START_PRE,
SOCKET_START_CHOWN,
SOCKET_START_POST,
@@ -1475,9 +1468,6 @@ static int socket_coldplug(Unit *u) {
SOCKET_FINAL_SIGTERM,
SOCKET_FINAL_SIGKILL)) {
- if (s->control_pid <= 0)
- return -EBADMSG;
-
r = unit_watch_pid(UNIT(s), s->control_pid);
if (r < 0)
return r;
@@ -1519,6 +1509,9 @@ static int socket_spawn(Socket *s, ExecCommand *c, pid_t *_pid) {
.apply_chroot = true,
.apply_tty_stdin = true,
.bus_endpoint_fd = -1,
+ .stdin_fd = -1,
+ .stdout_fd = -1,
+ .stderr_fd = -1,
};
assert(s);
@@ -2644,49 +2637,43 @@ static int socket_dispatch_timer(sd_event_source *source, usec_t usec, void *use
return 0;
}
-int socket_collect_fds(Socket *s, int **fds, unsigned *n_fds) {
- int *rfds;
- unsigned rn_fds, k;
- int i;
+int socket_collect_fds(Socket *s, int **fds) {
+ int *rfds, k = 0, n = 0;
SocketPort *p;
assert(s);
assert(fds);
- assert(n_fds);
/* Called from the service code for requesting our fds */
- rn_fds = 0;
LIST_FOREACH(port, p, s->ports) {
if (p->fd >= 0)
- rn_fds++;
- rn_fds += p->n_auxiliary_fds;
+ n++;
+ n += p->n_auxiliary_fds;
}
- if (rn_fds <= 0) {
+ if (n <= 0) {
*fds = NULL;
- *n_fds = 0;
return 0;
}
- rfds = new(int, rn_fds);
+ rfds = new(int, n);
if (!rfds)
return -ENOMEM;
- k = 0;
LIST_FOREACH(port, p, s->ports) {
+ int i;
+
if (p->fd >= 0)
rfds[k++] = p->fd;
for (i = 0; i < p->n_auxiliary_fds; ++i)
rfds[k++] = p->auxiliary_fds[i];
}
- assert(k == rn_fds);
+ assert(k == n);
*fds = rfds;
- *n_fds = rn_fds;
-
- return 0;
+ return n;
}
static void socket_reset_failed(Unit *u) {
@@ -2782,23 +2769,18 @@ static int socket_get_timeout(Unit *u, uint64_t *timeout) {
return 1;
}
-static const char* const socket_state_table[_SOCKET_STATE_MAX] = {
- [SOCKET_DEAD] = "dead",
- [SOCKET_START_PRE] = "start-pre",
- [SOCKET_START_CHOWN] = "start-chown",
- [SOCKET_START_POST] = "start-post",
- [SOCKET_LISTENING] = "listening",
- [SOCKET_RUNNING] = "running",
- [SOCKET_STOP_PRE] = "stop-pre",
- [SOCKET_STOP_PRE_SIGTERM] = "stop-pre-sigterm",
- [SOCKET_STOP_PRE_SIGKILL] = "stop-pre-sigkill",
- [SOCKET_STOP_POST] = "stop-post",
- [SOCKET_FINAL_SIGTERM] = "final-sigterm",
- [SOCKET_FINAL_SIGKILL] = "final-sigkill",
- [SOCKET_FAILED] = "failed"
-};
+char *socket_fdname(Socket *s) {
+ assert(s);
+
+ /* Returns the name to use for $LISTEN_NAMES. If the user
+ * didn't specify anything specifically, use the socket unit's
+ * name as fallback. */
-DEFINE_STRING_TABLE_LOOKUP(socket_state, SocketState);
+ if (s->fdname)
+ return s->fdname;
+
+ return UNIT(s)->id;
+}
static const char* const socket_exec_command_table[_SOCKET_EXEC_COMMAND_MAX] = {
[SOCKET_EXEC_START_PRE] = "StartPre",