return 0;
}
-static int flags_fds(const int fds[], size_t n_socket_fds, size_t n_storage_fds, bool nonblock) {
- size_t n_fds;
+static int flags_fds(
+ const int fds[],
+ size_t n_socket_fds,
+ size_t n_fds,
+ bool nonblock) {
+
int r;
- n_fds = n_socket_fds + n_storage_fds;
if (n_fds <= 0)
return 0;
}
static void rename_process_from_path(const char *path) {
- char process_name[11];
+ _cleanup_free_ char *buf = NULL;
const char *p;
- size_t l;
- /* This resulting string must fit in 10 chars (i.e. the length
- * of "/sbin/init") to look pretty in /bin/ps */
+ assert(path);
+
+ /* This resulting string must fit in 10 chars (i.e. the length of "/sbin/init") to look pretty in
+ * /bin/ps */
- p = basename(path);
- if (isempty(p)) {
+ if (path_extract_filename(path, &buf) < 0) {
rename_process("(...)");
return;
}
- l = strlen(p);
+ size_t l = strlen(buf);
if (l > 8) {
- /* The end of the process name is usually more
- * interesting, since the first bit might just be
+ /* The end of the process name is usually more interesting, since the first bit might just be
* "systemd-" */
- p = p + l - 8;
+ p = buf + l - 8;
l = 8;
- }
+ } else
+ p = buf;
+ char process_name[11];
process_name[0] = '(';
memcpy(process_name+1, p, l);
process_name[1+l] = ')';
const ExecContext *c,
const ExecParameters *p,
size_t n_fds,
+ char **fdnames,
const char *home,
const char *username,
const char *shell,
return -ENOMEM;
our_env[n_env++] = x;
- joined = strv_join(p->fd_names, ":");
+ joined = strv_join(fdnames, ":");
if (!joined)
return -ENOMEM;
return 1;
}
+static int connect_unix_harder(Unit *u, const OpenFile *of, int ofd) {
+ union sockaddr_union addr = {
+ .un.sun_family = AF_UNIX,
+ };
+ socklen_t sa_len;
+ static const int socket_types[] = { SOCK_DGRAM, SOCK_STREAM, SOCK_SEQPACKET };
+ int r;
+
+ assert(u);
+ assert(of);
+ assert(ofd >= 0);
+
+ r = sockaddr_un_set_path(&addr.un, FORMAT_PROC_FD_PATH(ofd));
+ if (r < 0)
+ return log_unit_error_errno(u, r, "Failed to set sockaddr for %s: %m", of->path);
+
+ sa_len = r;
+
+ for (size_t i = 0; i < ELEMENTSOF(socket_types); i++) {
+ _cleanup_close_ int fd = -EBADF;
+
+ fd = socket(AF_UNIX, socket_types[i] | SOCK_CLOEXEC, 0);
+ if (fd < 0)
+ return log_unit_error_errno(u, errno, "Failed to create socket for %s: %m", of->path);
+
+ r = RET_NERRNO(connect(fd, &addr.sa, sa_len));
+ if (r == -EPROTOTYPE)
+ continue;
+ if (r < 0)
+ return log_unit_error_errno(u, r, "Failed to connect socket for %s: %m", of->path);
+
+ return TAKE_FD(fd);
+ }
+
+ return log_unit_error_errno(u, SYNTHETIC_ERRNO(EPROTOTYPE), "Failed to connect socket for \"%s\".", of->path);
+}
+
+static int get_open_file_fd(Unit *u, const OpenFile *of) {
+ struct stat st;
+ _cleanup_close_ int fd = -EBADF, ofd = -EBADF;
+
+ assert(u);
+ assert(of);
+
+ ofd = open(of->path, O_PATH | O_CLOEXEC);
+ if (ofd < 0)
+ return log_error_errno(errno, "Could not open \"%s\": %m", of->path);
+ if (fstat(ofd, &st) < 0)
+ return log_error_errno(errno, "Failed to stat %s: %m", of->path);
+
+ if (S_ISSOCK(st.st_mode)) {
+ fd = connect_unix_harder(u, of, ofd);
+ if (fd < 0)
+ return fd;
+
+ if (FLAGS_SET(of->flags, OPENFILE_READ_ONLY) && shutdown(fd, SHUT_WR) < 0)
+ return log_error_errno(errno, "Failed to shutdown send for socket %s: %m", of->path);
+
+ log_unit_debug(u, "socket %s opened (fd=%d)", of->path, fd);
+ } else {
+ int flags = FLAGS_SET(of->flags, OPENFILE_READ_ONLY) ? O_RDONLY : O_RDWR;
+ if (FLAGS_SET(of->flags, OPENFILE_APPEND))
+ flags |= O_APPEND;
+ else if (FLAGS_SET(of->flags, OPENFILE_TRUNCATE))
+ flags |= O_TRUNC;
+
+ fd = fd_reopen(ofd, flags | O_CLOEXEC);
+ if (fd < 0)
+ return log_unit_error_errno(u, fd, "Failed to open file %s: %m", of->path);
+
+ log_unit_debug(u, "file %s opened (fd=%d)", of->path, fd);
+ }
+
+ return TAKE_FD(fd);
+}
+
+static int collect_open_file_fds(
+ Unit *u,
+ OpenFile* open_files,
+ int **fds,
+ char ***fdnames,
+ size_t *n_fds) {
+ int r;
+
+ assert(u);
+ assert(fds);
+ assert(fdnames);
+ assert(n_fds);
+
+ LIST_FOREACH(open_files, of, open_files) {
+ _cleanup_close_ int fd = -EBADF;
+
+ fd = get_open_file_fd(u, of);
+ if (fd < 0) {
+ if (FLAGS_SET(of->flags, OPENFILE_GRACEFUL)) {
+ log_unit_debug_errno(u, fd, "Failed to get OpenFile= file descriptor for %s, ignoring: %m", of->path);
+ continue;
+ }
+
+ return fd;
+ }
+
+ if (!GREEDY_REALLOC(*fds, *n_fds + 1))
+ return -ENOMEM;
+
+ r = strv_extend(fdnames, of->fdname);
+ if (r < 0)
+ return r;
+
+ (*fds)[*n_fds] = TAKE_FD(fd);
+
+ (*n_fds)++;
+ }
+
+ return 0;
+}
+
static int exec_child(
Unit *unit,
const ExecCommand *command,
DynamicCreds *dcreds,
int socket_fd,
const int named_iofds[static 3],
- int *fds,
+ int *params_fds,
size_t n_socket_fds,
size_t n_storage_fds,
char **files_env,
int secure_bits;
_cleanup_free_ gid_t *gids_after_pam = NULL;
int ngids_after_pam = 0;
+ _cleanup_free_ int *fds = NULL;
+ _cleanup_strv_free_ char **fdnames = NULL;
assert(unit);
assert(command);
/* In case anything used libc syslog(), close this here, too */
closelog();
+ fds = newdup(int, params_fds, n_fds);
+ if (!fds) {
+ *exit_status = EXIT_MEMORY;
+ return log_oom();
+ }
+
+ fdnames = strv_copy((char**) params->fd_names);
+ if (!fdnames) {
+ *exit_status = EXIT_MEMORY;
+ return log_oom();
+ }
+
+ r = collect_open_file_fds(unit, params->open_files, &fds, &fdnames, &n_fds);
+ if (r < 0) {
+ *exit_status = EXIT_FDS;
+ return log_unit_error_errno(unit, r, "Failed to get OpenFile= file descriptors: %m");
+ }
+
int keep_fds[n_fds + 3];
memcpy_safe(keep_fds, fds, n_fds * sizeof(int));
n_keep_fds = n_fds;
context,
params,
n_fds,
+ fdnames,
home,
username,
shell,
/* If the user namespace was not set up above, try to do it now.
* It's preferred to set up the user namespace later (after all other namespaces) so as not to be
- * restricted by rules pertaining to combining user namspaces with other namespaces (e.g. in the
+ * restricted by rules pertaining to combining user namespaces with other namespaces (e.g. in the
* case of mount namespaces being less privileged when the mount point list is copied from a
* different user namespace). */
if (r >= 0)
r = shift_fds(fds, n_fds);
if (r >= 0)
- r = flags_fds(fds, n_socket_fds, n_storage_fds, context->non_blocking);
+ r = flags_fds(fds, n_socket_fds, n_fds, context->non_blocking);
if (r < 0) {
*exit_status = EXIT_FDS;
return log_unit_error_errno(unit, r, "Failed to adjust passed file descriptors: %m");
return 0;
}
+int exec_context_destroy_mount_ns_dir(Unit *u) {
+ _cleanup_free_ char *p = NULL;
+
+ if (!u || !MANAGER_IS_SYSTEM(u->manager))
+ return 0;
+
+ p = path_join("/run/systemd/propagate/", u->id);
+ if (!p)
+ return -ENOMEM;
+
+ /* This is only filled transiently (see mount_in_namespace()), should be empty or even non-existent*/
+ if (rmdir(p) < 0 && errno != ENOENT)
+ log_unit_debug_errno(u, errno, "Unable to remove propagation dir '%s', ignoring: %m", p);
+
+ return 0;
+}
+
static void exec_command_done(ExecCommand *c) {
assert(c);
if (*l) {
/* It's kind of important, that we keep the order here */
- LIST_FIND_TAIL(command, *l, end);
+ end = LIST_FIND_TAIL(command, *l);
LIST_INSERT_AFTER(command, *l, end, e);
} else
*l = e;