#include "log.h"
#include "ioprio.h"
#include "securebits.h"
-
-static int close_fds(int except[], unsigned n_except) {
- DIR *d;
- struct dirent *de;
- int r = 0;
-
- /* Modifies the fds array! (sorts it) */
-
- if (!(d = opendir("/proc/self/fd")))
- return -errno;
-
- while ((de = readdir(d))) {
- int fd;
-
- if (de->d_name[0] == '.')
- continue;
-
- if ((r = safe_atoi(de->d_name, &fd)) < 0)
- goto finish;
-
- if (fd < 3)
- continue;
-
- if (fd == dirfd(d))
- continue;
-
- if (except) {
- bool found;
- unsigned i;
-
- found = false;
- for (i = 0; i < n_except; i++)
- if (except[i] == fd) {
- found = true;
- break;
- }
-
- if (found)
- continue;
- }
-
- if ((r = close_nointr(fd)) < 0)
- goto finish;
- }
-
-finish:
- closedir(d);
- return r;
-}
+#include "cgroup.h"
static int shift_fds(int fds[], unsigned n_fds) {
int start, restart_from;
if (n_fds <= 0)
return 0;
+ /* Modifies the fds array! (sorts it) */
+
assert(fds);
start = 0;
static int flags_fds(int fds[], unsigned n_fds, bool nonblock) {
unsigned i;
+ int r;
if (n_fds <= 0)
return 0;
/* Drops/Sets O_NONBLOCK and FD_CLOEXEC from the file flags */
for (i = 0; i < n_fds; i++) {
- int flags;
-
- if ((flags = fcntl(fds[i], F_GETFL, 0)) < 0)
- return -errno;
-
- if (nonblock)
- flags |= O_NONBLOCK;
- else
- flags &= ~O_NONBLOCK;
- if (fcntl(fds[i], F_SETFL, flags) < 0)
- return -errno;
+ if ((r = fd_nonblock(fds[i], nonblock)) < 0)
+ return r;
/* We unconditionally drop FD_CLOEXEC from the fds,
* since after all we want to pass these fds to our
* children */
- if ((flags = fcntl(fds[i], F_GETFD, 0)) < 0)
- return -errno;
- if (fcntl(fds[i], F_SETFD, flags &~FD_CLOEXEC) < 0)
- return -errno;
+ if ((r = fd_cloexec(fds[i], false)) < 0)
+ return r;
}
return 0;
/* First step: If we need to keep capabilities but
* drop privileges we need to make sure we keep our
* caps, whiel we drop priviliges. */
- if (uid != 0)
- if (prctl(PR_SET_SECUREBITS, context->secure_bits|SECURE_KEEP_CAPS) < 0)
- return -errno;
+ if (uid != 0) {
+ int sb = context->secure_bits|SECURE_KEEP_CAPS;
+
+ if (prctl(PR_GET_SECUREBITS) != sb)
+ if (prctl(PR_SET_SECUREBITS, sb) < 0)
+ return -errno;
+ }
/* Second step: set the capabilites. This will reduce
* the capabilities to the minimum we need. */
return 0;
}
-int exec_spawn(const ExecCommand *command,
+int exec_spawn(ExecCommand *command,
const ExecContext *context,
int *fds, unsigned n_fds,
bool apply_permissions,
bool apply_chroot,
+ CGroupBonding *cgroup_bondings,
pid_t *ret) {
pid_t pid;
+ int r;
assert(command);
assert(context);
log_debug("About to execute %s", command->path);
+ if (cgroup_bondings)
+ if ((r = cgroup_bonding_realize_list(cgroup_bondings)))
+ return r;
+
if ((pid = fork()) < 0)
return -errno;
if (pid == 0) {
- int i, r;
+ int i;
sigset_t ss;
const char *username = NULL, *home = NULL;
uid_t uid = (uid_t) -1;
goto fail;
}
- if (setpgid(0, 0) < 0) {
- r = EXIT_PGID;
- goto fail;
+ if (context->new_session) {
+ if (setsid() < 0) {
+ r = EXIT_SETSID;
+ goto fail;
+ }
+ } else {
+ if (setpgid(0, 0) < 0) {
+ r = EXIT_PGID;
+ goto fail;
+ }
}
umask(context->umask);
goto fail;
}
+ if (cgroup_bondings)
+ if ((r = cgroup_bonding_install_list(cgroup_bondings, 0)) < 0) {
+ r = EXIT_CGROUP;
+ goto fail;
+ }
+
if (context->oom_adjust_set) {
char t[16];
free(d);
}
- if (close_fds(fds, n_fds) < 0 ||
+ if (close_all_fds(fds, n_fds) < 0 ||
shift_fds(fds, n_fds) < 0 ||
flags_fds(fds, n_fds, context->non_blocking) < 0) {
r = EXIT_FDS;
goto fail;
}
- if (prctl(PR_SET_SECUREBITS, context->secure_bits) < 0) {
- r = EXIT_SECUREBITS;
- goto fail;
- }
+ /* PR_GET_SECUREBITS is not priviliged, while
+ * PR_SET_SECUREBITS is. So to suppress
+ * potential EPERMs we'll try not to call
+ * PR_SET_SECUREBITS unless necessary. */
+ if (prctl(PR_GET_SECUREBITS) != context->secure_bits)
+ if (prctl(PR_SET_SECUREBITS, context->secure_bits) < 0) {
+ r = EXIT_SECUREBITS;
+ goto fail;
+ }
if (context->capabilities)
if (cap_set_proc(context->capabilities) < 0) {
log_debug("Forked %s as %llu", command->path, (unsigned long long) pid);
+ command->exec_status.pid = pid;
+ command->exec_status.start_timestamp = now(CLOCK_REALTIME);
+
*ret = pid;
return 0;
}
c->cpu_sched_set = false;
CPU_ZERO(&c->cpu_affinity);
c->cpu_affinity_set = false;
+ c->timer_slack_ns = 0;
+ c->timer_slack_ns_set = false;
+
+ c->cpu_sched_reset_on_fork = false;
+ c->non_blocking = false;
+ c->new_session = false;
c->input = 0;
c->output = 0;
"%sUMask: %04o\n"
"%sWorkingDirectory: %s\n"
"%sRootDirectory: %s\n"
- "%sNonBlocking: %s\n",
+ "%sNonBlocking: %s\n"
+ "%sNewSession: %s\n",
prefix, c->umask,
prefix, c->working_directory ? c->working_directory : "/",
prefix, c->root_directory ? c->root_directory : "/",
- prefix, yes_no(c->non_blocking));
+ prefix, yes_no(c->non_blocking),
+ prefix, yes_no(c->new_session));
if (c->environment)
for (e = c->environment; *e; e++)
assert(s);
s->pid = pid;
+ s->exit_timestamp = now(CLOCK_REALTIME);
+
s->code = code;
s->status = status;
- s->timestamp = now(CLOCK_REALTIME);
+}
+
+void exec_status_dump(ExecStatus *s, FILE *f, const char *prefix) {
+ char buf[FORMAT_TIMESTAMP_MAX];
+
+ assert(s);
+ assert(f);
+
+ if (!prefix)
+ prefix = "";
+
+ if (s->pid <= 0)
+ return;
+
+ fprintf(f,
+ "%sPID: %llu\n",
+ prefix, (unsigned long long) s->pid);
+
+ if (s->start_timestamp > 0)
+ fprintf(f,
+ "%sStart Timestamp: %s\n",
+ prefix, format_timestamp(buf, sizeof(buf), s->start_timestamp));
+
+ if (s->exit_timestamp > 0)
+ fprintf(f,
+ "%sExit Timestamp: %s\n"
+ "%sExit Code: %s\n"
+ "%sExit Status: %i\n",
+ prefix, format_timestamp(buf, sizeof(buf), s->exit_timestamp),
+ prefix, sigchld_code_to_string(s->code),
+ prefix, s->status);
}
char *exec_command_line(ExecCommand *c) {
}
void exec_command_dump(ExecCommand *c, FILE *f, const char *prefix) {
+ char *p2;
+ const char *prefix2;
+
char *cmd;
assert(c);
if (!prefix)
prefix = "";
+ p2 = strappend(prefix, "\t");
+ prefix2 = p2 ? p2 : prefix;
cmd = exec_command_line(c);
prefix, cmd ? cmd : strerror(ENOMEM));
free(cmd);
+
+ exec_status_dump(&c->exec_status, f, prefix2);
+
+ free(p2);
}
void exec_command_dump_list(ExecCommand *c, FILE *f, const char *prefix) {