From: Lennart Poettering Date: Fri, 29 Jan 2010 19:46:22 +0000 (+0100) Subject: support chrooting/setting of ioprio when spawning X-Git-Tag: 0.git+20100605+dfd8ee-1~349 X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=9eba9da4bce4778b4d5dd43e2c41756976a1582b;p=systemd support chrooting/setting of ioprio when spawning --- diff --git a/execute.c b/execute.c index cbefadfc..f2f2be74 100644 --- a/execute.c +++ b/execute.c @@ -15,6 +15,7 @@ #include "macro.h" #include "util.h" #include "log.h" +#include "ioprio.h" static int close_fds(int except[], unsigned n_except) { DIR *d; @@ -273,13 +274,13 @@ int exec_spawn(const ExecCommand *command, const ExecContext *context, int *fds, goto fail; } - umask(context->umask); - - if (chdir(context->directory ? context->directory : "/") < 0) { - r = EXIT_CHDIR; + if (setpgid(0, 0) < 0) { + r = EXIT_PGID; goto fail; } + umask(context->umask); + if (setup_output(context, file_name_from_path(command->path)) < 0) { r = EXIT_OUTPUT; goto fail; @@ -297,12 +298,29 @@ int exec_spawn(const ExecCommand *command, const ExecContext *context, int *fds, } } + if (context->root_directory) + if (chroot(context->root_directory) < 0) { + r = EXIT_CHROOT; + goto fail; + } + + if (chdir(context->working_directory ? context->working_directory : "/") < 0) { + r = EXIT_CHDIR; + goto fail; + } + if (context->nice_set) if (setpriority(PRIO_PROCESS, 0, context->nice) < 0) { r = EXIT_NICE; goto fail; } + if (context->ioprio_set) + if (ioprio_set(IOPRIO_WHO_PROCESS, 0, context->ioprio) < 0) { + r = EXIT_IOPRIO; + goto fail; + } + if (close_fds(fds, n_fds) < 0 || shift_fds(fds, n_fds) < 0 || flags_fds(fds, n_fds) < 0) { @@ -366,8 +384,13 @@ void exec_context_init(ExecContext *c) { c->umask = 0002; cap_clear(c->capabilities); + c->capabilities_set = false; c->oom_adjust = 0; + c->oom_adjust_set = false; c->nice = 0; + c->nice_set = false; + c->ioprio = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, 0); + c->ioprio_set = false; c->output = 0; c->syslog_priority = LOG_DAEMON|LOG_INFO; @@ -386,8 +409,10 @@ void exec_context_done(ExecContext *c) { c->rlimit[l] = NULL; } - free(c->directory); - c->directory = NULL; + free(c->working_directory); + c->working_directory = NULL; + free(c->root_directory); + c->root_directory = NULL; free(c->syslog_identifier); c->syslog_identifier = NULL; @@ -424,6 +449,14 @@ void exec_command_free_array(ExecCommand **c, unsigned n) { } void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) { + + static const char * const table[] = { + [IOPRIO_CLASS_NONE] = "none", + [IOPRIO_CLASS_RT] = "realtime", + [IOPRIO_CLASS_BE] = "best-effort", + [IOPRIO_CLASS_IDLE] = "idle" + }; + assert(c); assert(f); @@ -432,9 +465,11 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) { fprintf(f, "%sUmask: %04o\n" - "%sDirectory: %s\n", + "%sWorking Directory: %s\n" + "%sRoot Directory: %s\n", prefix, c->umask, - prefix, c->directory ? c->directory : "/"); + prefix, c->working_directory ? c->working_directory : "/", + prefix, c->root_directory ? c->root_directory : "/"); if (c->nice_set) fprintf(f, @@ -445,6 +480,13 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) { fprintf(f, "%sOOMAdjust: %i\n", prefix, c->oom_adjust); + + if (c->ioprio_set) + fprintf(f, + "%sIOSchedulingClass: %s\n" + "%sIOPriority: %i\n", + prefix, table[IOPRIO_PRIO_CLASS(c->ioprio)], + prefix, (int) IOPRIO_PRIO_DATA(c->ioprio)); } void exec_status_fill(ExecStatus *s, pid_t pid, int code, int status) { diff --git a/execute.h b/execute.h index 04b9f6ef..581736d0 100644 --- a/execute.h +++ b/execute.h @@ -44,12 +44,14 @@ struct ExecContext { char **environment; mode_t umask; struct rlimit *rlimit[RLIMIT_NLIMITS]; /* FIXME: load-fragment parser missing */ - char *directory; + char *working_directory, *root_directory; int oom_adjust; int nice; + int ioprio; bool oom_adjust_set:1; bool nice_set:1; + bool ioprio_set:1; ExecOutput output; int syslog_priority; @@ -91,7 +93,10 @@ typedef enum ExitStatus { EXIT_LIMITS, EXIT_OOM_ADJUST, EXIT_SIGNAL_MASK, - EXIT_OUTPUT + EXIT_OUTPUT, + EXIT_CHROOT, + EXIT_PGID, + EXIT_IOPRIO } ExitStatus; int exec_spawn(const ExecCommand *command, const ExecContext *context, int *fds, unsigned n_fds, pid_t *ret); diff --git a/fixme b/fixme index 29a6c260..2668bbbc 100644 --- a/fixme +++ b/fixme @@ -27,9 +27,9 @@ - implement mount/automount -- more process attributes: chroot, cpu affinity, scheduling +- more process attributes: cpu affinity, cpu scheduling -- create session/pgroup for child processes +- create session/pgroup for child processes? handle input on console properly? interactive fsck? interactive luks password? - fs namespaces @@ -45,3 +45,10 @@ presumably uses the logging socket in blocking mode which might trigger a deadlock if syslog does not process the socket anymore (maybe because it is restarted) and the socket buffer is full. + +- in udev/mount if properties change we need to delete the old + settings and install the new settings. Deleting the old settings is + currently missing. + +- ability to kill services? i.e. in contrast to stopping them, go directly + into killing mode? diff --git a/load-fragment.c b/load-fragment.c index 0cdaaa20..68646225 100644 --- a/load-fragment.c +++ b/load-fragment.c @@ -12,6 +12,7 @@ #include "conf-parser.h" #include "load-fragment.h" #include "log.h" +#include "ioprio.h" static int config_parse_deps( const char *filename, @@ -625,6 +626,90 @@ int config_parse_level( return 0; } +int config_parse_io_class( + const char *filename, + unsigned line, + const char *section, + const char *lvalue, + const char *rvalue, + void *data, + void *userdata) { + + static const char * const table[] = { + [IOPRIO_CLASS_NONE] = NULL, + [IOPRIO_CLASS_RT] = "realtime", + [IOPRIO_CLASS_BE] = "best-effort", + [IOPRIO_CLASS_IDLE] = "idle", + }; + + ExecContext *c = data; + int i; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + for (i = 0; i < (int) ELEMENTSOF(table); i++) { + if (!table[i]) + continue; + + if (streq(rvalue, table[i])) { + c->ioprio = IOPRIO_PRIO_VALUE(i, IOPRIO_PRIO_DATA(c->ioprio)); + break; + } + } + + if (i >= (int) ELEMENTSOF(table)) { + + /* Second try, let's see if this is a number. */ + if (safe_atoi(rvalue, &i) >= 0 && + i >= 0 && + i < (int) ELEMENTSOF(table) && + table[i]) + c->ioprio = IOPRIO_PRIO_VALUE(i, IOPRIO_PRIO_DATA(c->ioprio)); + else { + log_error("[%s:%u] Failed to parse io priority: %s", filename, line, rvalue); + return -EBADMSG; + } + } + + c->ioprio_set = true; + + return 0; +} + +int config_parse_io_priority( + const char *filename, + unsigned line, + const char *section, + const char *lvalue, + const char *rvalue, + void *data, + void *userdata) { + + ExecContext *c = data; + int i; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + if (safe_atoi(rvalue, &i) >= 0 && + i >= 0 && + i < IOPRIO_BE_NR) + c->ioprio = IOPRIO_PRIO_VALUE(IOPRIO_PRIO_CLASS(c->ioprio), i); + else { + log_error("[%s:%u] Failed to parse io priority: %s", filename, line, rvalue); + return -EBADMSG; + } + + c->ioprio_set = true; + + return 0; +} + #define FOLLOW_MAX 8 static int open_follow(char **filename, FILE **_f, Set *names, char **_id) { @@ -709,12 +794,15 @@ static int load_from_path(Unit *u, const char *path) { }; #define EXEC_CONTEXT_CONFIG_ITEMS(context, section) \ - { "Directory", config_parse_path, &(context).directory, section }, \ + { "WorkingDirectory", config_parse_path, &(context).working_directory, section }, \ + { "RootDirectory", config_parse_path, &(context).root_directory, section }, \ { "User", config_parse_string, &(context).user, section }, \ { "Group", config_parse_string, &(context).group, section }, \ { "SupplementaryGroups", config_parse_strv, &(context).supplementary_groups, section }, \ { "Nice", config_parse_nice, &(context), section }, \ { "OOMAdjust", config_parse_oom_adjust, &(context), section }, \ + { "IOPriority", config_parse_io_priority, &(context), section }, \ + { "IOSchedulingClass", config_parse_io_class, &(context), section }, \ { "UMask", config_parse_umask, &(context).umask, section }, \ { "Environment", config_parse_strv, &(context).environment, section }, \ { "Output", config_parse_output, &(context).output, section }, \