diff options
Diffstat (limited to 'src/core')
46 files changed, 1389 insertions, 1384 deletions
diff --git a/src/core/automount.c b/src/core/automount.c index c88e3311bc..e0535ec201 100644 --- a/src/core/automount.c +++ b/src/core/automount.c @@ -774,8 +774,9 @@ static int automount_stop(Unit *u) { static int automount_serialize(Unit *u, FILE *f, FDSet *fds) { Automount *a = AUTOMOUNT(u); - void *p; Iterator i; + void *p; + int r; assert(a); assert(f); @@ -790,15 +791,9 @@ static int automount_serialize(Unit *u, FILE *f, FDSet *fds) { SET_FOREACH(p, a->expire_tokens, i) unit_serialize_item_format(u, f, "expire-token", "%u", PTR_TO_UINT(p)); - if (a->pipe_fd >= 0) { - int copy; - - copy = fdset_put_dup(fds, a->pipe_fd); - if (copy < 0) - return copy; - - unit_serialize_item_format(u, f, "pipe-fd", "%i", copy); - } + r = unit_serialize_item_fd(u, f, fds, "pipe-fd", a->pipe_fd); + if (r < 0) + return r; return 0; } @@ -1024,15 +1019,6 @@ static bool automount_supported(void) { return supported; } -static const char* const automount_state_table[_AUTOMOUNT_STATE_MAX] = { - [AUTOMOUNT_DEAD] = "dead", - [AUTOMOUNT_WAITING] = "waiting", - [AUTOMOUNT_RUNNING] = "running", - [AUTOMOUNT_FAILED] = "failed" -}; - -DEFINE_STRING_TABLE_LOOKUP(automount_state, AutomountState); - static const char* const automount_result_table[_AUTOMOUNT_RESULT_MAX] = { [AUTOMOUNT_SUCCESS] = "success", [AUTOMOUNT_FAILURE_RESOURCES] = "resources" diff --git a/src/core/automount.h b/src/core/automount.h index 2a50fef68d..43ea9f772d 100644 --- a/src/core/automount.h +++ b/src/core/automount.h @@ -25,15 +25,6 @@ typedef struct Automount Automount; #include "unit.h" -typedef enum AutomountState { - AUTOMOUNT_DEAD, - AUTOMOUNT_WAITING, - AUTOMOUNT_RUNNING, - AUTOMOUNT_FAILED, - _AUTOMOUNT_STATE_MAX, - _AUTOMOUNT_STATE_INVALID = -1 -} AutomountState; - typedef enum AutomountResult { AUTOMOUNT_SUCCESS, AUTOMOUNT_FAILURE_RESOURCES, @@ -66,8 +57,5 @@ extern const UnitVTable automount_vtable; int automount_update_mount(Automount *a, MountState old_state, MountState state); -const char* automount_state_to_string(AutomountState i) _const_; -AutomountState automount_state_from_string(const char *s) _pure_; - const char* automount_result_to_string(AutomountResult i) _const_; AutomountResult automount_result_from_string(const char *s) _pure_; diff --git a/src/core/busname.c b/src/core/busname.c index 4020e9dd3c..38becfc119 100644 --- a/src/core/busname.c +++ b/src/core/busname.c @@ -656,6 +656,7 @@ static int busname_stop(Unit *u) { static int busname_serialize(Unit *u, FILE *f, FDSet *fds) { BusName *n = BUSNAME(u); + int r; assert(n); assert(f); @@ -667,15 +668,9 @@ static int busname_serialize(Unit *u, FILE *f, FDSet *fds) { if (n->control_pid > 0) unit_serialize_item_format(u, f, "control-pid", PID_FMT, n->control_pid); - if (n->starter_fd >= 0) { - int copy; - - copy = fdset_put_dup(fds, n->starter_fd); - if (copy < 0) - return copy; - - unit_serialize_item_format(u, f, "starter-fd", "%i", copy); - } + r = unit_serialize_item_fd(u, f, fds, "starter-fd", n->starter_fd); + if (r < 0) + return r; return 0; } @@ -991,19 +986,6 @@ static bool busname_supported(void) { return supported; } -static const char* const busname_state_table[_BUSNAME_STATE_MAX] = { - [BUSNAME_DEAD] = "dead", - [BUSNAME_MAKING] = "making", - [BUSNAME_REGISTERED] = "registered", - [BUSNAME_LISTENING] = "listening", - [BUSNAME_RUNNING] = "running", - [BUSNAME_SIGTERM] = "sigterm", - [BUSNAME_SIGKILL] = "sigkill", - [BUSNAME_FAILED] = "failed", -}; - -DEFINE_STRING_TABLE_LOOKUP(busname_state, BusNameState); - static const char* const busname_result_table[_BUSNAME_RESULT_MAX] = { [BUSNAME_SUCCESS] = "success", [BUSNAME_FAILURE_RESOURCES] = "resources", diff --git a/src/core/busname.h b/src/core/busname.h index 69528a2aef..1bc3290596 100644 --- a/src/core/busname.h +++ b/src/core/busname.h @@ -24,20 +24,6 @@ typedef struct BusName BusName; typedef struct BusNamePolicy BusNamePolicy; - -typedef enum BusNameState { - BUSNAME_DEAD, - BUSNAME_MAKING, - BUSNAME_REGISTERED, - BUSNAME_LISTENING, - BUSNAME_RUNNING, - BUSNAME_SIGTERM, - BUSNAME_SIGKILL, - BUSNAME_FAILED, - _BUSNAME_STATE_MAX, - _BUSNAME_STATE_INVALID = -1 -} BusNameState; - typedef enum BusNameResult { BUSNAME_SUCCESS, BUSNAME_FAILURE_RESOURCES, @@ -77,8 +63,5 @@ struct BusName { extern const UnitVTable busname_vtable; -const char* busname_state_to_string(BusNameState i) _const_; -BusNameState busname_state_from_string(const char *s) _pure_; - const char* busname_result_to_string(BusNameResult i) _const_; BusNameResult busname_result_from_string(const char *s) _pure_; diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c index 868c8cc05a..adf613d328 100644 --- a/src/core/dbus-execute.c +++ b/src/core/dbus-execute.c @@ -595,6 +595,33 @@ static int property_get_address_families( return sd_bus_message_close_container(reply); } +static int property_get_working_directory( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + ExecContext *c = userdata; + const char *wd; + + assert(bus); + assert(reply); + assert(c); + + if (c->working_directory_home) + wd = "~"; + else + wd = c->working_directory; + + if (c->working_directory_missing_ok) + wd = strjoina("!", wd); + + return sd_bus_message_append(reply, "s", wd); +} + const sd_bus_vtable bus_exec_vtable[] = { SD_BUS_VTABLE_START(0), SD_BUS_PROPERTY("Environment", "as", NULL, offsetof(ExecContext, environment), SD_BUS_VTABLE_PROPERTY_CONST), @@ -616,7 +643,7 @@ const sd_bus_vtable bus_exec_vtable[] = { SD_BUS_PROPERTY("LimitNICE", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_NICE]), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("LimitRTPRIO", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_RTPRIO]), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("LimitRTTIME", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_RTTIME]), SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("WorkingDirectory", "s", NULL, offsetof(ExecContext, working_directory), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("WorkingDirectory", "s", property_get_working_directory, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("RootDirectory", "s", NULL, offsetof(ExecContext, root_directory), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("OOMScoreAdjust", "i", property_get_oom_score_adjust, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("Nice", "i", property_get_nice, 0, SD_BUS_VTABLE_PROPERTY_CONST), @@ -847,8 +874,7 @@ int bus_exec_context_set_transient_property( return 1; - } else if (STR_IN_SET(name, - "TTYPath", "WorkingDirectory", "RootDirectory")) { + } else if (STR_IN_SET(name, "TTYPath", "RootDirectory")) { const char *s; r = sd_bus_message_read(message, "s", &s); @@ -859,24 +885,51 @@ int bus_exec_context_set_transient_property( return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "%s takes an absolute path", name); if (mode != UNIT_CHECK) { - char *t; + if (streq(name, "TTYPath")) + r = free_and_strdup(&c->tty_path, s); + else { + assert(streq(name, "RootDirectory")); + r = free_and_strdup(&c->root_directory, s); + } + if (r < 0) + return r; - t = strdup(s); - if (!t) - return -ENOMEM; + unit_write_drop_in_private_format(u, mode, name, "%s=%s\n", name, s); + } - if (streq(name, "TTYPath")) { - free(c->tty_path); - c->tty_path = t; - } else if (streq(name, "WorkingDirectory")) { - free(c->working_directory); - c->working_directory = t; - } else if (streq(name, "RootDirectory")) { - free(c->root_directory); - c->root_directory = t; + return 1; + + } else if (streq(name, "WorkingDirectory")) { + const char *s; + bool missing_ok; + + r = sd_bus_message_read(message, "s", &s); + if (r < 0) + return r; + + if (s[0] == '-') { + missing_ok = true; + s++; + } else + missing_ok = false; + + if (!streq(s, "~") && !path_is_absolute(s)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "WorkingDirectory= expects an absolute path or '~'"); + + if (mode != UNIT_CHECK) { + if (streq(s, "~")) { + c->working_directory = mfree(c->working_directory); + c->working_directory_home = true; + } else { + r = free_and_strdup(&c->working_directory, s); + if (r < 0) + return r; + + c->working_directory_home = false; } - unit_write_drop_in_private_format(u, mode, name, "%s=%s\n", name, s); + c->working_directory_missing_ok = missing_ok; + unit_write_drop_in_private_format(u, mode, name, "WorkingDirectory=%s%s", missing_ok ? "-" : "", s); } return 1; diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c index 561b6f8bfa..9e21b0787d 100644 --- a/src/core/dbus-manager.c +++ b/src/core/dbus-manager.c @@ -81,10 +81,21 @@ static int property_get_virtualization( void *userdata, sd_bus_error *error) { + int v; + assert(bus); assert(reply); - return sd_bus_message_append(reply, "s", virtualization_to_string(detect_virtualization())); + v = detect_virtualization(); + + /* Make sure to return the empty string when we detect no virtualization, as that is the API. + * + * https://github.com/systemd/systemd/issues/1423 + */ + + return sd_bus_message_append( + reply, "s", + v == VIRTUALIZATION_NONE ? "" : virtualization_to_string(v)); } static int property_get_architecture( @@ -1960,6 +1971,16 @@ const sd_bus_vtable bus_manager_vtable[] = { SD_BUS_PROPERTY("ControlGroup", "s", NULL, offsetof(Manager, cgroup_root), 0), SD_BUS_PROPERTY("SystemState", "s", property_get_system_state, 0, 0), SD_BUS_PROPERTY("ExitCode", "y", bus_property_get_unsigned, offsetof(Manager, return_value), 0), + SD_BUS_PROPERTY("DefaultTimerAccuracyUSec", "t", bus_property_get_usec, offsetof(Manager, default_timer_accuracy_usec), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("DefaultTimeoutStartUSec", "t", bus_property_get_usec, offsetof(Manager, default_timeout_start_usec), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("DefaultTimeoutStopUSec", "t", bus_property_get_usec, offsetof(Manager, default_timeout_stop_usec), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("DefaultRestartUSec", "t", bus_property_get_usec, offsetof(Manager, default_restart_usec), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("DefaultStartLimitInterval", "t", bus_property_get_usec, offsetof(Manager, default_start_limit_interval), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("DefaultStartLimitBurst", "u", bus_property_get_unsigned, offsetof(Manager, default_start_limit_burst), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("DefaultCPUAccounting", "b", bus_property_get_bool, offsetof(Manager, default_cpu_accounting), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("DefaultBlockIOAccounting", "b", bus_property_get_bool, offsetof(Manager, default_blockio_accounting), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("DefaultMemoryAccounting", "b", bus_property_get_bool, offsetof(Manager, default_memory_accounting), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("DefaultTasksAccounting", "b", bus_property_get_bool, offsetof(Manager, default_tasks_accounting), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_METHOD("GetUnit", "s", "o", method_get_unit, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("GetUnitByPID", "u", "o", method_get_unit_by_pid, SD_BUS_VTABLE_UNPRIVILEGED), diff --git a/src/core/dbus-service.c b/src/core/dbus-service.c index 3436342bef..b636f8ba6a 100644 --- a/src/core/dbus-service.c +++ b/src/core/dbus-service.c @@ -19,6 +19,7 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include "async.h" #include "strv.h" #include "path-util.h" #include "unit.h" @@ -120,6 +121,37 @@ static int bus_service_set_transient_property( return 1; + } else if (STR_IN_SET(name, + "StandardInputFileDescriptor", + "StandardOutputFileDescriptor", + "StandardErrorFileDescriptor")) { + int fd; + + r = sd_bus_message_read(message, "h", &fd); + if (r < 0) + return r; + + if (mode != UNIT_CHECK) { + int copy; + + copy = fcntl(fd, F_DUPFD_CLOEXEC, 3); + if (copy < 0) + return -errno; + + if (streq(name, "StandardInputFileDescriptor")) { + asynchronous_close(s->stdin_fd); + s->stdin_fd = copy; + } else if (streq(name, "StandardOutputFileDescriptor")) { + asynchronous_close(s->stdout_fd); + s->stdout_fd = copy; + } else { + asynchronous_close(s->stderr_fd); + s->stderr_fd = copy; + } + } + + return 1; + } else if (streq(name, "ExecStart")) { unsigned n = 0; diff --git a/src/core/dbus-socket.c b/src/core/dbus-socket.c index 86732e2a45..7444649f8b 100644 --- a/src/core/dbus-socket.c +++ b/src/core/dbus-socket.c @@ -84,6 +84,25 @@ static int property_get_listen( return sd_bus_message_close_container(reply); } + +static int property_get_fdname( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + Socket *s = SOCKET(userdata); + + assert(bus); + assert(reply); + assert(s); + + return sd_bus_message_append(reply, "s", socket_fdname(s)); +} + const sd_bus_vtable bus_socket_vtable[] = { SD_BUS_VTABLE_START(0), SD_BUS_PROPERTY("BindIPv6Only", "s", property_get_bind_ipv6_only, offsetof(Socket, bind_ipv6_only), SD_BUS_VTABLE_PROPERTY_CONST), @@ -95,6 +114,7 @@ const sd_bus_vtable bus_socket_vtable[] = { SD_BUS_PROPERTY("SocketMode", "u", bus_property_get_mode, offsetof(Socket, socket_mode), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("DirectoryMode", "u", bus_property_get_mode, offsetof(Socket, directory_mode), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("Accept", "b", bus_property_get_bool, offsetof(Socket, accept), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("Writable", "b", bus_property_get_bool, offsetof(Socket, writable), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("KeepAlive", "b", bus_property_get_bool, offsetof(Socket, keep_alive), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("KeepAliveTimeUSec", "t", bus_property_get_usec, offsetof(Socket, keep_alive_time), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("KeepAliveIntervalUSec", "t", bus_property_get_usec, offsetof(Socket, keep_alive_interval), SD_BUS_VTABLE_PROPERTY_CONST), @@ -127,6 +147,7 @@ const sd_bus_vtable bus_socket_vtable[] = { SD_BUS_PROPERTY("Result", "s", property_get_result, offsetof(Socket, result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), SD_BUS_PROPERTY("NConnections", "u", bus_property_get_unsigned, offsetof(Socket, n_connections), 0), SD_BUS_PROPERTY("NAccepted", "u", bus_property_get_unsigned, offsetof(Socket, n_accepted), 0), + SD_BUS_PROPERTY("FileDescriptorName", "s", property_get_fdname, 0, 0), BUS_EXEC_COMMAND_LIST_VTABLE("ExecStartPre", offsetof(Socket, exec_command[SOCKET_EXEC_START_PRE]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION), BUS_EXEC_COMMAND_LIST_VTABLE("ExecStartPost", offsetof(Socket, exec_command[SOCKET_EXEC_START_POST]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION), BUS_EXEC_COMMAND_LIST_VTABLE("ExecStopPre", offsetof(Socket, exec_command[SOCKET_EXEC_STOP_PRE]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION), diff --git a/src/core/device.c b/src/core/device.c index 0b54518691..a819ab8d4e 100644 --- a/src/core/device.c +++ b/src/core/device.c @@ -816,14 +816,6 @@ int device_found_node(Manager *m, const char *node, bool add, DeviceFound found, return device_update_found_by_name(m, node, add, found, now); } -static const char* const device_state_table[_DEVICE_STATE_MAX] = { - [DEVICE_DEAD] = "dead", - [DEVICE_TENTATIVE] = "tentative", - [DEVICE_PLUGGED] = "plugged", -}; - -DEFINE_STRING_TABLE_LOOKUP(device_state, DeviceState); - const UnitVTable device_vtable = { .object_size = sizeof(Device), .sections = diff --git a/src/core/device.h b/src/core/device.h index 10ab113176..da8737870b 100644 --- a/src/core/device.h +++ b/src/core/device.h @@ -23,16 +23,6 @@ typedef struct Device Device; -/* We simply watch devices, we cannot plug/unplug them. That - * simplifies the state engine greatly */ -typedef enum DeviceState { - DEVICE_DEAD, - DEVICE_TENTATIVE, /* mounted or swapped, but not (yet) announced by udev */ - DEVICE_PLUGGED, /* announced by udev */ - _DEVICE_STATE_MAX, - _DEVICE_STATE_INVALID = -1 -} DeviceState; - typedef enum DeviceFound { DEVICE_NOT_FOUND = 0, DEVICE_FOUND_UDEV = 1, @@ -56,7 +46,4 @@ struct Device { extern const UnitVTable device_vtable; -const char* device_state_to_string(DeviceState i) _const_; -DeviceState device_state_from_string(const char *s) _pure_; - int device_found_node(Manager *m, const char *node, bool add, DeviceFound found, bool now); diff --git a/src/core/execute.c b/src/core/execute.c index 7796c07fcf..d6217840c0 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -21,18 +21,18 @@ #include <errno.h> #include <fcntl.h> -#include <unistd.h> -#include <string.h> +#include <glob.h> +#include <grp.h> +#include <poll.h> #include <signal.h> -#include <sys/socket.h> -#include <sys/un.h> +#include <string.h> +#include <sys/personality.h> #include <sys/prctl.h> +#include <sys/socket.h> #include <sys/stat.h> -#include <grp.h> -#include <poll.h> -#include <glob.h> +#include <sys/un.h> +#include <unistd.h> #include <utmpx.h> -#include <sys/personality.h> #ifdef HAVE_PAM #include <security/pam_appl.h> @@ -50,37 +50,38 @@ #include <sys/apparmor.h> #endif -#include "barrier.h" #include "sd-messages.h" -#include "rm-rf.h" -#include "strv.h" -#include "macro.h" + +#include "af-list.h" +#include "async.h" +#include "barrier.h" +#include "bus-endpoint.h" +#include "cap-list.h" #include "capability.h" -#include "util.h" -#include "log.h" -#include "ioprio.h" -#include "securebits.h" -#include "namespace.h" -#include "exit-status.h" -#include "missing.h" -#include "utmp-wtmp.h" #include "def.h" -#include "path-util.h" #include "env-util.h" -#include "fileio.h" -#include "unit.h" -#include "async.h" -#include "selinux-util.h" #include "errno-list.h" -#include "af-list.h" -#include "mkdir.h" -#include "smack-util.h" -#include "bus-endpoint.h" -#include "cap-list.h" +#include "exit-status.h" +#include "fileio.h" #include "formats-util.h" +#include "ioprio.h" +#include "log.h" +#include "macro.h" +#include "missing.h" +#include "mkdir.h" +#include "namespace.h" +#include "path-util.h" #include "process-util.h" -#include "terminal-util.h" +#include "rm-rf.h" +#include "securebits.h" +#include "selinux-util.h" #include "signal-util.h" +#include "smack-util.h" +#include "strv.h" +#include "terminal-util.h" +#include "unit.h" +#include "util.h" +#include "utmp-wtmp.h" #ifdef HAVE_APPARMOR #include "apparmor-util.h" @@ -358,12 +359,28 @@ static int fixup_output(ExecOutput std_output, int socket_fd) { return std_output; } -static int setup_input(const ExecContext *context, int socket_fd, bool apply_tty_stdin) { +static int setup_input( + const ExecContext *context, + const ExecParameters *params, + int socket_fd) { + ExecInput i; assert(context); + assert(params); - i = fixup_input(context->std_input, socket_fd, apply_tty_stdin); + if (params->stdin_fd >= 0) { + if (dup2(params->stdin_fd, STDIN_FILENO) < 0) + return -errno; + + /* Try to make this the controlling tty, if it is a tty, and reset it */ + (void) ioctl(STDIN_FILENO, TIOCSCTTY, context->std_input == EXEC_INPUT_TTY_FORCE); + (void) reset_terminal_fd(STDIN_FILENO, true); + + return STDIN_FILENO; + } + + i = fixup_input(context->std_input, socket_fd, params->apply_tty_stdin); switch (i) { @@ -400,16 +417,40 @@ static int setup_input(const ExecContext *context, int socket_fd, bool apply_tty } } -static int setup_output(Unit *unit, const ExecContext *context, int fileno, int socket_fd, const char *ident, bool apply_tty_stdin, uid_t uid, gid_t gid) { +static int setup_output( + Unit *unit, + const ExecContext *context, + const ExecParameters *params, + int fileno, + int socket_fd, + const char *ident, + uid_t uid, gid_t gid) { + ExecOutput o; ExecInput i; int r; assert(unit); assert(context); + assert(params); assert(ident); - i = fixup_input(context->std_input, socket_fd, apply_tty_stdin); + if (fileno == STDOUT_FILENO && params->stdout_fd >= 0) { + + if (dup2(params->stdout_fd, STDOUT_FILENO) < 0) + return -errno; + + return STDOUT_FILENO; + } + + if (fileno == STDERR_FILENO && params->stderr_fd >= 0) { + if (dup2(params->stderr_fd, STDERR_FILENO) < 0) + return -errno; + + return STDERR_FILENO; + } + + i = fixup_input(context->std_input, socket_fd, params->apply_tty_stdin); o = fixup_output(context->std_output, socket_fd); if (fileno == STDERR_FILENO) { @@ -502,9 +543,9 @@ static int chown_terminal(int fd, uid_t uid) { return 0; } -static int setup_confirm_stdio(int *_saved_stdin, - int *_saved_stdout) { - int fd = -1, saved_stdin, saved_stdout = -1, r; +static int setup_confirm_stdio(int *_saved_stdin, int *_saved_stdout) { + _cleanup_close_ int fd = -1, saved_stdin = -1, saved_stdout = -1; + int r; assert(_saved_stdin); assert(_saved_stdout); @@ -514,10 +555,8 @@ static int setup_confirm_stdio(int *_saved_stdin, return -errno; saved_stdout = fcntl(STDOUT_FILENO, F_DUPFD, 3); - if (saved_stdout < 0) { - r = errno; - goto fail; - } + if (saved_stdout < 0) + return -errno; fd = acquire_terminal( "/dev/console", @@ -525,39 +564,33 @@ static int setup_confirm_stdio(int *_saved_stdin, false, false, DEFAULT_CONFIRM_USEC); - if (fd < 0) { - r = fd; - goto fail; - } + if (fd < 0) + return fd; r = chown_terminal(fd, getuid()); if (r < 0) - goto fail; + return r; - if (dup2(fd, STDIN_FILENO) < 0) { - r = -errno; - goto fail; - } + r = reset_terminal_fd(fd, true); + if (r < 0) + return r; - if (dup2(fd, STDOUT_FILENO) < 0) { - r = -errno; - goto fail; - } + if (dup2(fd, STDIN_FILENO) < 0) + return -errno; + + if (dup2(fd, STDOUT_FILENO) < 0) + return -errno; if (fd >= 2) safe_close(fd); + fd = -1; *_saved_stdin = saved_stdin; *_saved_stdout = saved_stdout; - return 0; - -fail: - safe_close(saved_stdout); - safe_close(saved_stdin); - safe_close(fd); + saved_stdin = saved_stdout = -1; - return r; + return 0; } _printf_(1, 2) static int write_confirm_message(const char *format, ...) { @@ -577,9 +610,7 @@ _printf_(1, 2) static int write_confirm_message(const char *format, ...) { return 0; } -static int restore_confirm_stdio(int *saved_stdin, - int *saved_stdout) { - +static int restore_confirm_stdio(int *saved_stdin, int *saved_stdout) { int r = 0; assert(saved_stdin); @@ -595,8 +626,8 @@ static int restore_confirm_stdio(int *saved_stdin, if (dup2(*saved_stdout, STDOUT_FILENO) < 0) r = -errno; - safe_close(*saved_stdin); - safe_close(*saved_stdout); + *saved_stdin = safe_close(*saved_stdin); + *saved_stdout = safe_close(*saved_stdout); return r; } @@ -1198,6 +1229,7 @@ static void do_idle_pipe_dance(int idle_pipe[4]) { static int build_environment( const ExecContext *c, unsigned n_fds, + char ** fd_names, usec_t watchdog_usec, const char *home, const char *username, @@ -1211,11 +1243,13 @@ static int build_environment( assert(c); assert(ret); - our_env = new0(char*, 10); + our_env = new0(char*, 11); if (!our_env) return -ENOMEM; if (n_fds > 0) { + _cleanup_free_ char *joined = NULL; + if (asprintf(&x, "LISTEN_PID="PID_FMT, getpid()) < 0) return -ENOMEM; our_env[n_env++] = x; @@ -1223,6 +1257,15 @@ static int build_environment( if (asprintf(&x, "LISTEN_FDS=%u", n_fds) < 0) return -ENOMEM; our_env[n_env++] = x; + + joined = strv_join(fd_names, ":"); + if (!joined) + return -ENOMEM; + + x = strjoin("LISTEN_FDNAMES=", joined, NULL); + if (!x) + return -ENOMEM; + our_env[n_env++] = x; } if (watchdog_usec > 0) { @@ -1273,7 +1316,7 @@ static int build_environment( } our_env[n_env++] = NULL; - assert(n_env <= 10); + assert(n_env <= 11); *ret = our_env; our_env = NULL; @@ -1311,6 +1354,44 @@ static bool exec_needs_mount_namespace( return false; } +static int close_remaining_fds( + const ExecParameters *params, + ExecRuntime *runtime, + int socket_fd, + int *fds, unsigned n_fds) { + + unsigned n_dont_close = 0; + int dont_close[n_fds + 7]; + + assert(params); + + if (params->stdin_fd >= 0) + dont_close[n_dont_close++] = params->stdin_fd; + if (params->stdout_fd >= 0) + dont_close[n_dont_close++] = params->stdout_fd; + if (params->stderr_fd >= 0) + dont_close[n_dont_close++] = params->stderr_fd; + + if (socket_fd >= 0) + dont_close[n_dont_close++] = socket_fd; + if (n_fds > 0) { + memcpy(dont_close + n_dont_close, fds, sizeof(int) * n_fds); + n_dont_close += n_fds; + } + + if (params->bus_endpoint_fd >= 0) + dont_close[n_dont_close++] = params->bus_endpoint_fd; + + if (runtime) { + if (runtime->netns_storage_socket[0] >= 0) + dont_close[n_dont_close++] = runtime->netns_storage_socket[0]; + if (runtime->netns_storage_socket[1] >= 0) + dont_close[n_dont_close++] = runtime->netns_storage_socket[1]; + } + + return close_all_fds(dont_close, n_dont_close); +} + static int exec_child( Unit *unit, ExecCommand *command, @@ -1325,9 +1406,7 @@ static int exec_child( _cleanup_strv_free_ char **our_env = NULL, **pam_env = NULL, **final_env = NULL, **final_argv = NULL; _cleanup_free_ char *mac_selinux_context_net = NULL; - const char *username = NULL, *home = NULL, *shell = NULL; - unsigned n_dont_close = 0; - int dont_close[n_fds + 4]; + const char *username = NULL, *home = NULL, *shell = NULL, *wd; uid_t uid = UID_INVALID; gid_t gid = GID_INVALID; int i, r; @@ -1367,22 +1446,7 @@ static int exec_child( log_forget_fds(); - if (socket_fd >= 0) - dont_close[n_dont_close++] = socket_fd; - if (n_fds > 0) { - memcpy(dont_close + n_dont_close, fds, sizeof(int) * n_fds); - n_dont_close += n_fds; - } - if (params->bus_endpoint_fd >= 0) - dont_close[n_dont_close++] = params->bus_endpoint_fd; - if (runtime) { - if (runtime->netns_storage_socket[0] >= 0) - dont_close[n_dont_close++] = runtime->netns_storage_socket[0]; - if (runtime->netns_storage_socket[1] >= 0) - dont_close[n_dont_close++] = runtime->netns_storage_socket[1]; - } - - r = close_all_fds(dont_close, n_dont_close); + r = close_remaining_fds(params, runtime, socket_fd, fds, n_fds); if (r < 0) { *exit_status = EXIT_FDS; return r; @@ -1438,21 +1502,21 @@ static int exec_child( /* If a socket is connected to STDIN/STDOUT/STDERR, we * must sure to drop O_NONBLOCK */ if (socket_fd >= 0) - fd_nonblock(socket_fd, false); + (void) fd_nonblock(socket_fd, false); - r = setup_input(context, socket_fd, params->apply_tty_stdin); + r = setup_input(context, params, socket_fd); if (r < 0) { *exit_status = EXIT_STDIN; return r; } - r = setup_output(unit, context, STDOUT_FILENO, socket_fd, basename(command->path), params->apply_tty_stdin, uid, gid); + r = setup_output(unit, context, params, STDOUT_FILENO, socket_fd, basename(command->path), uid, gid); if (r < 0) { *exit_status = EXIT_STDOUT; return r; } - r = setup_output(unit, context, STDERR_FILENO, socket_fd, basename(command->path), params->apply_tty_stdin, uid, gid); + r = setup_output(unit, context, params, STDERR_FILENO, socket_fd, basename(command->path), uid, gid); if (r < 0) { *exit_status = EXIT_STDERR; return r; @@ -1698,6 +1762,13 @@ static int exec_child( } } + if (context->working_directory_home) + wd = home; + else if (context->working_directory) + wd = context->working_directory; + else + wd = "/"; + if (params->apply_chroot) { if (!needs_mount_namespace && context->root_directory) if (chroot(context->root_directory) < 0) { @@ -1705,21 +1776,15 @@ static int exec_child( return -errno; } - if (chdir(context->working_directory ?: "/") < 0 && + if (chdir(wd) < 0 && !context->working_directory_missing_ok) { *exit_status = EXIT_CHDIR; return -errno; } } else { - _cleanup_free_ char *d = NULL; - - if (asprintf(&d, "%s/%s", - context->root_directory ?: "", - context->working_directory ?: "") < 0) { - *exit_status = EXIT_MEMORY; - return -ENOMEM; - } + const char *d; + d = strjoina(strempty(context->root_directory), "/", strempty(wd)); if (chdir(d) < 0 && !context->working_directory_missing_ok) { *exit_status = EXIT_CHDIR; @@ -1849,7 +1914,7 @@ static int exec_child( #endif } - r = build_environment(context, n_fds, params->watchdog_usec, home, username, shell, &our_env); + r = build_environment(context, n_fds, params->fd_names, params->watchdog_usec, home, username, shell, &our_env); if (r < 0) { *exit_status = EXIT_MEMORY; return r; @@ -2711,7 +2776,7 @@ int exec_command_append(ExecCommand *c, const char *path, ...) { if (!l) return -ENOMEM; - r = strv_extend_strv(&c->argv, l); + r = strv_extend_strv(&c->argv, l, false); if (r < 0) return r; diff --git a/src/core/execute.h b/src/core/execute.h index a750246a89..f8995a4203 100644 --- a/src/core/execute.h +++ b/src/core/execute.h @@ -103,6 +103,7 @@ struct ExecContext { struct rlimit *rlimit[_RLIMIT_MAX]; char *working_directory, *root_directory; bool working_directory_missing_ok; + bool working_directory_home; mode_t umask; int oom_score_adjust; @@ -207,21 +208,35 @@ struct ExecContext { struct ExecParameters { char **argv; - int *fds; unsigned n_fds; char **environment; - bool apply_permissions; - bool apply_chroot; - bool apply_tty_stdin; - bool confirm_spawn; - bool selinux_context_net; + + int *fds; + char **fd_names; + unsigned n_fds; + + bool apply_permissions:1; + bool apply_chroot:1; + bool apply_tty_stdin:1; + + bool confirm_spawn:1; + bool selinux_context_net:1; + + bool cgroup_delegate:1; CGroupMask cgroup_supported; const char *cgroup_path; - bool cgroup_delegate; + const char *runtime_prefix; + usec_t watchdog_usec; + int *idle_pipe; + char *bus_endpoint_path; int bus_endpoint_fd; + + int stdin_fd; + int stdout_fd; + int stderr_fd; }; int exec_spawn(Unit *unit, diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4 index fd293d8287..89e624b557 100644 --- a/src/core/load-fragment-gperf.gperf.m4 +++ b/src/core/load-fragment-gperf.gperf.m4 @@ -17,7 +17,7 @@ struct ConfigPerfItem; %% m4_dnl Define the context options only once m4_define(`EXEC_CONTEXT_CONFIG_ITEMS', -`$1.WorkingDirectory, config_parse_unit_path_printf, 0, offsetof($1, exec_context.working_directory) +`$1.WorkingDirectory, config_parse_working_directory, 0, offsetof($1, exec_context) $1.RootDirectory, config_parse_unit_path_printf, 0, offsetof($1, exec_context.root_directory) $1.User, config_parse_unit_string_printf, 0, offsetof($1, exec_context.user) $1.Group, config_parse_unit_string_printf, 0, offsetof($1, exec_context.group) @@ -261,6 +261,7 @@ Socket.SocketGroup, config_parse_unit_string_printf, 0, Socket.SocketMode, config_parse_mode, 0, offsetof(Socket, socket_mode) Socket.DirectoryMode, config_parse_mode, 0, offsetof(Socket, directory_mode) Socket.Accept, config_parse_bool, 0, offsetof(Socket, accept) +Socket.Writable, config_parse_bool, 0, offsetof(Socket, writable) Socket.MaxConnections, config_parse_unsigned, 0, offsetof(Socket, max_connections) Socket.KeepAlive, config_parse_bool, 0, offsetof(Socket, keep_alive) Socket.KeepAliveTimeSec, config_parse_sec, 0, offsetof(Socket, keep_alive_time) @@ -286,6 +287,7 @@ Socket.MessageQueueMaxMessages, config_parse_long, 0, Socket.MessageQueueMessageSize, config_parse_long, 0, offsetof(Socket, mq_msgsize) Socket.RemoveOnStop, config_parse_bool, 0, offsetof(Socket, remove_on_stop) Socket.Symlinks, config_parse_unit_path_strv_printf, 0, offsetof(Socket, symlinks) +Socket.FileDescriptorName, config_parse_fdname, 0, 0 Socket.Service, config_parse_socket_service, 0, 0 m4_ifdef(`HAVE_SMACK', `Socket.SmackLabel, config_parse_string, 0, offsetof(Socket, smack) diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index a13f42b5e0..b1d4c6b57d 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -20,44 +20,43 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <linux/oom.h> #include <errno.h> -#include <string.h> #include <fcntl.h> -#include <sched.h> #include <linux/fs.h> -#include <sys/stat.h> -#include <sys/resource.h> - +#include <linux/oom.h> #ifdef HAVE_SECCOMP #include <seccomp.h> #endif +#include <sched.h> +#include <string.h> +#include <sys/resource.h> +#include <sys/stat.h> -#include "unit.h" -#include "strv.h" +#include "af-list.h" +#include "bus-error.h" +#include "bus-internal.h" +#include "bus-util.h" +#include "cap-list.h" +#include "cgroup.h" #include "conf-parser.h" -#include "load-fragment.h" -#include "log.h" +#include "cpu-set-util.h" +#include "env-util.h" +#include "errno-list.h" #include "ioprio.h" -#include "securebits.h" +#include "log.h" #include "missing.h" -#include "unit-name.h" -#include "unit-printf.h" -#include "utf8.h" #include "path-util.h" -#include "env-util.h" -#include "cgroup.h" -#include "bus-util.h" -#include "bus-error.h" -#include "errno-list.h" -#include "af-list.h" -#include "cap-list.h" -#include "signal-util.h" -#include "bus-internal.h" - #ifdef HAVE_SECCOMP #include "seccomp-util.h" #endif +#include "securebits.h" +#include "signal-util.h" +#include "strv.h" +#include "unit-name.h" +#include "unit-printf.h" +#include "unit.h" +#include "utf8.h" +#include "load-fragment.h" int config_parse_warn_compat( const char *unit, @@ -74,15 +73,15 @@ int config_parse_warn_compat( switch(reason) { case DISABLED_CONFIGURATION: - log_syntax(unit, LOG_DEBUG, filename, line, EINVAL, + log_syntax(unit, LOG_DEBUG, filename, line, 0, "Support for option %s= has been disabled at compile time and it is ignored", lvalue); break; case DISABLED_LEGACY: - log_syntax(unit, LOG_INFO, filename, line, EINVAL, + log_syntax(unit, LOG_INFO, filename, line, 0, "Support for option %s= has been removed and it is ignored", lvalue); break; case DISABLED_EXPERIMENTAL: - log_syntax(unit, LOG_INFO, filename, line, EINVAL, + log_syntax(unit, LOG_INFO, filename, line, 0, "Support for option %s= has not yet been enabled and it is ignored", lvalue); break; }; @@ -120,18 +119,16 @@ int config_parse_unit_deps(const char *unit, r = unit_name_printf(u, t, &k); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, -r, - "Failed to resolve specifiers, ignoring: %s", strerror(-r)); + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %m"); continue; } r = unit_add_dependency_by_name(u, d, k, NULL, true); if (r < 0) - log_syntax(unit, LOG_ERR, filename, line, -r, - "Failed to add dependency on %s, ignoring: %s", k, strerror(-r)); + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add dependency on %s, ignoring: %m", k); } if (!isempty(state)) - log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid syntax, ignoring."); + log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid syntax, ignoring."); return 0; } @@ -166,16 +163,17 @@ int config_parse_unit_string_printf( return config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, k, data, userdata); } -int config_parse_unit_strv_printf(const char *unit, - const char *filename, - unsigned line, - const char *section, - unsigned section_line, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { +int config_parse_unit_strv_printf( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { Unit *u = userdata; _cleanup_free_ char *k = NULL; @@ -187,24 +185,25 @@ int config_parse_unit_strv_printf(const char *unit, assert(u); r = unit_full_printf(u, rvalue, &k); - if (r < 0) - log_syntax(unit, LOG_ERR, filename, line, -r, - "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r)); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue); + return 0; + } - return config_parse_strv(unit, filename, line, section, section_line, lvalue, ltype, - k ? k : rvalue, data, userdata); + return config_parse_strv(unit, filename, line, section, section_line, lvalue, ltype, k, data, userdata); } -int config_parse_unit_path_printf(const char *unit, - const char *filename, - unsigned line, - const char *section, - unsigned section_line, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { +int config_parse_unit_path_printf( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { _cleanup_free_ char *k = NULL; Unit *u = userdata; @@ -217,7 +216,7 @@ int config_parse_unit_path_printf(const char *unit, r = unit_full_printf(u, rvalue, &k); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r)); + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue); return 0; } @@ -256,17 +255,17 @@ int config_parse_unit_path_strv_printf( r = unit_full_printf(u, t, &k); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve unit specifiers on %s, ignoring: %s", t, strerror(-r)); + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s, ignoring: %m", t); return 0; } if (!utf8_is_valid(k)) { - log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue); + log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, rvalue); return 0; } if (!path_is_absolute(k)) { - log_syntax(unit, LOG_ERR, filename, line, -r, "Symlink path %s is not absolute, ignoring: %s", k, strerror(-r)); + log_syntax(unit, LOG_ERR, filename, line, 0, "Symlink path %s is not absolute, ignoring: %m", k); return 0; } @@ -279,7 +278,7 @@ int config_parse_unit_path_strv_printf( k = NULL; } if (!isempty(state)) - log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid syntax, ignoring."); + log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid syntax, ignoring."); return 0; } @@ -322,12 +321,8 @@ int config_parse_socket_listen(const char *unit, p->type = ltype; r = unit_full_printf(UNIT(s), rvalue, &p->path); if (r < 0) { - p->path = strdup(rvalue); - if (!p->path) - return log_oom(); - else - log_syntax(unit, LOG_ERR, filename, line, -r, - "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r)); + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue); + return 0; } path_kill_slashes(p->path); @@ -337,14 +332,14 @@ int config_parse_socket_listen(const char *unit, p->type = SOCKET_SOCKET; r = unit_full_printf(UNIT(s), rvalue, &k); - if (r < 0) - log_syntax(unit, LOG_ERR, filename, line, -r, - "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r)); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue); + return 0; + } - r = socket_address_parse_netlink(&p->address, k ?: rvalue); + r = socket_address_parse_netlink(&p->address, k); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, -r, - "Failed to parse address value, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse address value, ignoring: %s", rvalue); return 0; } @@ -353,14 +348,14 @@ int config_parse_socket_listen(const char *unit, p->type = SOCKET_SOCKET; r = unit_full_printf(UNIT(s), rvalue, &k); - if (r < 0) - log_syntax(unit, LOG_ERR, filename, line, -r, - "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r)); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r,"Failed to resolve unit specifiers on %s, ignoring: %m", rvalue); + return 0; + } - r = socket_address_parse_and_warn(&p->address, k ? k : rvalue); + r = socket_address_parse_and_warn(&p->address, k); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, -r, - "Failed to parse address value, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse address value, ignoring: %s", rvalue); return 0; } @@ -374,8 +369,7 @@ int config_parse_socket_listen(const char *unit, } if (socket_address_family(&p->address) != AF_LOCAL && p->address.type == SOCK_SEQPACKET) { - log_syntax(unit, LOG_ERR, filename, line, EOPNOTSUPP, - "Address family not supported, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, 0, "Address family not supported, ignoring: %s", rvalue); return 0; } } @@ -422,8 +416,7 @@ int config_parse_socket_bind(const char *unit, r = parse_boolean(rvalue); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Failed to parse bind IPv6 only value, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse bind IPv6 only value, ignoring: %s", rvalue); return 0; } @@ -455,14 +448,12 @@ int config_parse_exec_nice(const char *unit, r = safe_atoi(rvalue, &priority); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, -r, - "Failed to parse nice priority, ignoring: %s. ", rvalue); + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse nice priority, ignoring: %s", rvalue); return 0; } if (priority < PRIO_MIN || priority >= PRIO_MAX) { - log_syntax(unit, LOG_ERR, filename, line, ERANGE, - "Nice priority out of range, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, 0, "Nice priority out of range, ignoring: %s", rvalue); return 0; } @@ -493,14 +484,12 @@ int config_parse_exec_oom_score_adjust(const char* unit, r = safe_atoi(rvalue, &oa); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, -r, - "Failed to parse the OOM score adjust value, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse the OOM score adjust value, ignoring: %s", rvalue); return 0; } if (oa < OOM_SCORE_ADJ_MIN || oa > OOM_SCORE_ADJ_MAX) { - log_syntax(unit, LOG_ERR, filename, line, ERANGE, - "OOM score adjust value out of range, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, 0, "OOM score adjust value out of range, ignoring: %s", rvalue); return 0; } @@ -574,24 +563,19 @@ int config_parse_exec( if (isempty(f)) { /* First word is either "-" or "@" with no command. */ - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Empty path in command line, ignoring: \"%s\"", rvalue); + log_syntax(unit, LOG_ERR, filename, line, 0, "Empty path in command line, ignoring: \"%s\"", rvalue); return 0; } - if (!string_is_safe(f)) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Executable path contains special characters, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, 0, "Executable path contains special characters, ignoring: %s", rvalue); return 0; } if (!path_is_absolute(f)) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Executable path is not absolute, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, 0, "Executable path is not absolute, ignoring: %s", rvalue); return 0; } if (endswith(f, "/")) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Executable path specifies a directory, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, 0, "Executable path specifies a directory, ignoring: %s", rvalue); return 0; } @@ -658,8 +642,7 @@ int config_parse_exec( } if (!n || !n[0]) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Empty executable name or zeroeth argument, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, 0, "Empty executable name or zeroeth argument, ignoring: %s", rvalue); return 0; } @@ -743,8 +726,7 @@ int config_parse_exec_io_class(const char *unit, x = ioprio_class_from_string(rvalue); if (x < 0) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Failed to parse IO scheduling class, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse IO scheduling class, ignoring: %s", rvalue); return 0; } @@ -775,8 +757,7 @@ int config_parse_exec_io_priority(const char *unit, r = safe_atoi(rvalue, &i); if (r < 0 || i < 0 || i >= IOPRIO_BE_NR) { - log_syntax(unit, LOG_ERR, filename, line, -r, - "Failed to parse IO priority, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse IO priority, ignoring: %s", rvalue); return 0; } @@ -808,8 +789,7 @@ int config_parse_exec_cpu_sched_policy(const char *unit, x = sched_policy_from_string(rvalue); if (x < 0) { - log_syntax(unit, LOG_ERR, filename, line, -x, - "Failed to parse CPU scheduling policy, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse CPU scheduling policy, ignoring: %s", rvalue); return 0; } @@ -842,8 +822,7 @@ int config_parse_exec_cpu_sched_prio(const char *unit, r = safe_atoi(rvalue, &i); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, -r, - "Failed to parse CPU scheduling policy, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse CPU scheduling policy, ignoring: %s", rvalue); return 0; } @@ -852,8 +831,7 @@ int config_parse_exec_cpu_sched_prio(const char *unit, max = sched_get_priority_max(c->cpu_sched_policy); if (i < min || i > max) { - log_syntax(unit, LOG_ERR, filename, line, ERANGE, - "CPU scheduling priority is out of range, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, 0, "CPU scheduling priority is out of range, ignoring: %s", rvalue); return 0; } @@ -883,8 +861,7 @@ int config_parse_exec_cpu_affinity(const char *unit, assert(rvalue); assert(data); - ncpus = parse_cpu_set(rvalue, &cpuset, unit, filename, line, lvalue); - + ncpus = parse_cpu_set_and_warn(rvalue, &cpuset, unit, filename, line, lvalue); if (ncpus < 0) return ncpus; @@ -924,8 +901,7 @@ int config_parse_exec_capabilities(const char *unit, cap = cap_from_text(rvalue); if (!cap) { - log_syntax(unit, LOG_ERR, filename, line, errno, - "Failed to parse capabilities, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, errno, "Failed to parse capabilities, ignoring: %s", rvalue); return 0; } @@ -976,14 +952,12 @@ int config_parse_exec_secure_bits(const char *unit, else if (first_word(word, "noroot-locked")) c->secure_bits |= 1<<SECURE_NOROOT_LOCKED; else { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Failed to parse secure bits, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse secure bits, ignoring: %s", rvalue); return 0; } } if (!isempty(state)) - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Invalid syntax, garbage at the end, ignoring."); + log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid syntax, garbage at the end, ignoring."); return 0; } @@ -1030,15 +1004,14 @@ int config_parse_bounding_set(const char *unit, cap = capability_from_name(t); if (cap < 0) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse capability in bounding set, ignoring: %s", t); + log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse capability in bounding set, ignoring: %s", t); continue; } sum |= ((uint64_t) 1ULL) << (uint64_t) cap; } if (!isempty(state)) - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Trailing garbage, ignoring."); + log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring."); if (invert) *capability_bounding_set_drop |= sum; @@ -1076,8 +1049,7 @@ int config_parse_limit(const char *unit, r = safe_atollu(rvalue, &u); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, -r, - "Failed to parse resource value, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse resource value, ignoring: %s", rvalue); return 0; } } @@ -1114,8 +1086,7 @@ int config_parse_sysv_priority(const char *unit, r = safe_atoi(rvalue, &i); if (r < 0 || i < 0) { - log_syntax(unit, LOG_ERR, filename, line, -r, - "Failed to parse SysV start priority, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse SysV start priority, ignoring: %s", rvalue); return 0; } @@ -1162,12 +1133,12 @@ int config_parse_exec_mount_flags(const char *unit, else if (streq(t, "private")) flags = MS_PRIVATE; else { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse mount flag %s, ignoring: %s", t, rvalue); + log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse mount flag %s, ignoring: %s", t, rvalue); return 0; } } if (!isempty(state)) - log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Trailing garbage, ignoring."); + log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring."); c->mount_flags = flags; return 0; @@ -1210,8 +1181,7 @@ int config_parse_exec_selinux_context( r = unit_name_printf(u, rvalue, &k); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, -r, - "Failed to resolve specifiers, ignoring: %s", strerror(-r)); + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %m"); return 0; } @@ -1259,8 +1229,7 @@ int config_parse_exec_apparmor_profile( r = unit_name_printf(u, rvalue, &k); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, -r, - "Failed to resolve specifiers, ignoring: %s", strerror(-r)); + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %m"); return 0; } @@ -1308,8 +1277,7 @@ int config_parse_exec_smack_process_label( r = unit_name_printf(u, rvalue, &k); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, -r, - "Failed to resolve specifiers, ignoring: %s", strerror(-r)); + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %m"); return 0; } @@ -1350,23 +1318,18 @@ int config_parse_timer(const char *unit, b = timer_base_from_string(lvalue); if (b < 0) { - log_syntax(unit, LOG_ERR, filename, line, -b, - "Failed to parse timer base, ignoring: %s", lvalue); + log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse timer base, ignoring: %s", lvalue); return 0; } if (b == TIMER_CALENDAR) { if (calendar_spec_from_string(rvalue, &c) < 0) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Failed to parse calendar specification, ignoring: %s", - rvalue); + log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse calendar specification, ignoring: %s", rvalue); return 0; } } else { if (parse_sec(rvalue, &u) < 0) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Failed to parse timer value, ignoring: %s", - rvalue); + log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse timer value, ignoring: %s", rvalue); return 0; } } @@ -1409,33 +1372,30 @@ int config_parse_trigger_unit( assert(data); if (!set_isempty(u->dependencies[UNIT_TRIGGERS])) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Multiple units to trigger specified, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, 0, "Multiple units to trigger specified, ignoring: %s", rvalue); return 0; } r = unit_name_printf(u, rvalue, &p); - if (r < 0) - log_syntax(unit, LOG_ERR, filename, line, -r, - "Failed to resolve specifiers, ignoring: %s", strerror(-r)); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %m"); + return 0; + } - type = unit_name_to_type(p ?: rvalue); + type = unit_name_to_type(p); if (type < 0) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Unit type not valid, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, 0, "Unit type not valid, ignoring: %s", rvalue); return 0; } if (type == u->type) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Trigger cannot be of same type, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, 0, "Trigger cannot be of same type, ignoring: %s", rvalue); return 0; } - r = unit_add_two_dependencies_by_name(u, UNIT_BEFORE, UNIT_TRIGGERS, p ?: rvalue, NULL, true); + r = unit_add_two_dependencies_by_name(u, UNIT_BEFORE, UNIT_TRIGGERS, p, NULL, true); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, -r, - "Failed to add trigger on %s, ignoring: %s", p ?: rvalue, strerror(-r)); + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add trigger on %s, ignoring: %m", p); return 0; } @@ -1472,25 +1432,18 @@ int config_parse_path_spec(const char *unit, b = path_type_from_string(lvalue); if (b < 0) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Failed to parse path type, ignoring: %s", lvalue); + log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse path type, ignoring: %s", lvalue); return 0; } r = unit_full_printf(UNIT(p), rvalue, &k); if (r < 0) { - k = strdup(rvalue); - if (!k) - return log_oom(); - else - log_syntax(unit, LOG_ERR, filename, line, -r, - "Failed to resolve unit specifiers on %s. Ignoring.", - rvalue); + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s. Ignoring.", rvalue); + return 0; } if (!path_is_absolute(k)) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Path is not absolute, ignoring: %s", k); + log_syntax(unit, LOG_ERR, filename, line, 0, "Path is not absolute, ignoring: %s", k); return 0; } @@ -1522,10 +1475,10 @@ int config_parse_socket_service( void *userdata) { _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_free_ char *p = NULL; Socket *s = data; - int r; Unit *x; - _cleanup_free_ char *p = NULL; + int r; assert(filename); assert(lvalue); @@ -1539,13 +1492,13 @@ int config_parse_socket_service( } if (!endswith(p, ".service")) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Unit must be of type service, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, 0, "Unit must be of type service, ignoring: %s", rvalue); return 0; } r = manager_load_unit(UNIT(s)->manager, p, NULL, &error, &x); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r)); + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r)); return 0; } @@ -1554,6 +1507,50 @@ int config_parse_socket_service( return 0; } +int config_parse_fdname( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + _cleanup_free_ char *p = NULL; + Socket *s = data; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + if (isempty(rvalue)) { + s->fdname = mfree(s->fdname); + return 0; + } + + r = unit_name_printf(UNIT(s), rvalue, &p); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %s", rvalue); + return 0; + } + + if (!fdname_is_valid(p)) { + log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid file descriptor name, ignoring: %s", p); + return 0; + } + + free(s->fdname); + s->fdname = p; + p = NULL; + + return 0; +} + int config_parse_service_sockets( const char *unit, const char *filename, @@ -1590,7 +1587,7 @@ int config_parse_service_sockets( } if (!endswith(k, ".socket")) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Unit must be of type socket, ignoring: %s", k); + log_syntax(unit, LOG_ERR, filename, line, 0, "Unit must be of type socket, ignoring: %s", k); continue; } @@ -1603,7 +1600,7 @@ int config_parse_service_sockets( log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add dependency on %s, ignoring: %m", k); } if (!isempty(state)) - log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Trailing garbage, ignoring."); + log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring."); return 0; } @@ -1636,7 +1633,7 @@ int config_parse_bus_name( } if (!service_name_is_valid(k)) { - log_syntax(unit, LOG_ERR, filename, line, r, "Invalid bus name %s, ignoring.", k); + log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid bus name %s, ignoring.", k); return 0; } @@ -1701,21 +1698,18 @@ int config_parse_busname_service( r = unit_name_printf(UNIT(n), rvalue, &p); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, -r, - "Failed to resolve specifiers, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %s", rvalue); return 0; } if (!endswith(p, ".service")) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Unit must be of type service, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, 0, "Unit must be of type service, ignoring: %s", rvalue); return 0; } r = manager_load_unit(UNIT(n)->manager, p, NULL, &error, &x); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, -r, - "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r)); + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r)); return 0; } @@ -1765,8 +1759,7 @@ int config_parse_bus_policy( access_str = strpbrk(id_str, WHITESPACE); if (!access_str) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Invalid busname policy value '%s'", rvalue); + log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid busname policy value '%s'", rvalue); return 0; } @@ -1776,8 +1769,7 @@ int config_parse_bus_policy( p->access = bus_policy_access_from_string(access_str); if (p->access < 0) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Invalid busname policy access type '%s'", access_str); + log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid busname policy access type '%s'", access_str); return 0; } @@ -1819,8 +1811,7 @@ int config_parse_bus_endpoint_policy( access_str = strpbrk(name, WHITESPACE); if (!access_str) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Invalid endpoint policy value '%s'", rvalue); + log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid endpoint policy value '%s'", rvalue); return 0; } @@ -1831,21 +1822,83 @@ int config_parse_bus_endpoint_policy( access = bus_policy_access_from_string(access_str); if (access <= _BUS_POLICY_ACCESS_INVALID || access >= _BUS_POLICY_ACCESS_MAX) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Invalid endpoint policy access type '%s'", access_str); + log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid endpoint policy access type '%s'", access_str); return 0; } if (!c->bus_endpoint) { r = bus_endpoint_new(&c->bus_endpoint); - if (r < 0) - return r; + return log_error_errno(r, "Failed to create bus endpoint object: %m"); } return bus_endpoint_add_policy(c->bus_endpoint, name, access); } +int config_parse_working_directory( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + ExecContext *c = data; + Unit *u = userdata; + bool missing_ok; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(c); + assert(u); + + if (rvalue[0] == '-') { + missing_ok = true; + rvalue++; + } else + missing_ok = false; + + if (streq(rvalue, "~")) { + c->working_directory_home = true; + c->working_directory = mfree(c->working_directory); + } else { + _cleanup_free_ char *k = NULL; + + r = unit_full_printf(u, rvalue, &k); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in working directory path '%s', ignoring: %m", rvalue); + return 0; + } + + path_kill_slashes(k); + + if (!utf8_is_valid(k)) { + log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, rvalue); + return 0; + } + + if (!path_is_absolute(k)) { + log_syntax(unit, LOG_ERR, filename, line, 0, "Working directory path '%s' is not absolute, ignoring.", rvalue); + return 0; + } + + free(c->working_directory); + c->working_directory = k; + k = NULL; + + c->working_directory_home = false; + } + + c->working_directory_missing_ok = missing_ok; + return 0; +} + int config_parse_unit_env_file(const char *unit, const char *filename, unsigned line, @@ -1860,7 +1913,6 @@ int config_parse_unit_env_file(const char *unit, char ***env = data; Unit *u = userdata; _cleanup_free_ char *n = NULL; - const char *s; int r; assert(filename); @@ -1875,18 +1927,17 @@ int config_parse_unit_env_file(const char *unit, } r = unit_full_printf(u, rvalue, &n); - if (r < 0) - log_syntax(unit, LOG_ERR, filename, line, -r, - "Failed to resolve specifiers, ignoring: %s", rvalue); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %s", rvalue); + return 0; + } - s = n ?: rvalue; - if (!path_is_absolute(s[0] == '-' ? s + 1 : s)) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Path '%s' is not absolute, ignoring.", s); + if (!path_is_absolute(n[0] == '-' ? n + 1 : n)) { + log_syntax(unit, LOG_ERR, filename, line, 0, "Path '%s' is not absolute, ignoring.", n); return 0; } - r = strv_extend(env, s); + r = strv_extend(env, n); if (r < 0) return log_oom(); @@ -1924,14 +1975,17 @@ int config_parse_environ(const char *unit, if (u) { r = unit_full_printf(u, rvalue, &k); - if (r < 0) - log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", rvalue); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %s", rvalue); + return 0; + } } - if (!k) + if (!k) { k = strdup(rvalue); - if (!k) - return log_oom(); + if (!k) + return log_oom(); + } FOREACH_WORD_QUOTED(word, l, k, state) { _cleanup_free_ char *n = NULL; @@ -1944,7 +1998,7 @@ int config_parse_environ(const char *unit, } if (!env_assignment_is_valid(n)) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid environment assignment, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid environment assignment, ignoring: %s", rvalue); continue; } @@ -1956,8 +2010,7 @@ int config_parse_environ(const char *unit, *env = x; } if (!isempty(state)) - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Trailing garbage, ignoring."); + log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring."); return 0; } @@ -1982,8 +2035,7 @@ int config_parse_ip_tos(const char *unit, x = ip_tos_from_string(rvalue); if (x < 0) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Failed to parse IP TOS value, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse IP TOS value, ignoring: %s", rvalue); return 0; } @@ -2031,12 +2083,12 @@ int config_parse_unit_condition_path( r = unit_full_printf(u, rvalue, &p); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %s", rvalue); return 0; } if (!path_is_absolute(p)) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Path in condition not absolute, ignoring: %s", p); + log_syntax(unit, LOG_ERR, filename, line, 0, "Path in condition not absolute, ignoring: %s", p); return 0; } @@ -2088,7 +2140,7 @@ int config_parse_unit_condition_string( r = unit_full_printf(u, rvalue, &s); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %s", rvalue); return 0; } @@ -2137,7 +2189,7 @@ int config_parse_unit_condition_null( b = parse_boolean(rvalue); if (b < 0) { - log_syntax(unit, LOG_ERR, filename, line, -b, "Failed to parse boolean value in condition, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, b, "Failed to parse boolean value in condition, ignoring: %s", rvalue); return 0; } @@ -2185,20 +2237,18 @@ int config_parse_unit_requires_mounts_for( return log_oom(); if (!utf8_is_valid(n)) { - log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue); + log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, rvalue); continue; } r = unit_require_mounts_for(u, n); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, -r, - "Failed to add required mount for, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add required mount for, ignoring: %s", rvalue); continue; } } if (!isempty(state)) - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Trailing garbage, ignoring."); + log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring."); return 0; } @@ -2239,8 +2289,7 @@ int config_parse_documentation(const char *unit, if (documentation_url_is_valid(*a)) *(b++) = *a; else { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Invalid URL, ignoring: %s", *a); + log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid URL, ignoring: %s", *a); free(*a); } } @@ -2335,8 +2384,7 @@ int config_parse_syscall_filter( id = seccomp_syscall_resolve_name(t); if (id < 0) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Failed to parse system call, ignoring: %s", t); + log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse system call, ignoring: %s", t); continue; } @@ -2353,8 +2401,7 @@ int config_parse_syscall_filter( set_remove(c->syscall_filter, INT_TO_PTR(id + 1)); } if (!isempty(state)) - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Trailing garbage, ignoring."); + log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring."); /* Turn on NNP, but only if it wasn't configured explicitly * before, and only if we are in user mode. */ @@ -2400,8 +2447,7 @@ int config_parse_syscall_archs( r = seccomp_arch_from_string(t, &a); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Failed to parse system call architecture, ignoring: %s", t); + log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse system call architecture, ignoring: %s", t); continue; } @@ -2412,8 +2458,7 @@ int config_parse_syscall_archs( return log_oom(); } if (!isempty(state)) - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Trailing garbage, ignoring."); + log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring."); return 0; } @@ -2445,8 +2490,7 @@ int config_parse_syscall_errno( e = errno_from_name(rvalue); if (e < 0) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Failed to parse error number, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse error number, ignoring: %s", rvalue); return 0; } @@ -2506,8 +2550,7 @@ int config_parse_address_families( af = af_from_name(t); if (af <= 0) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Failed to parse address family, ignoring: %s", t); + log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse address family, ignoring: %s", t); continue; } @@ -2524,8 +2567,7 @@ int config_parse_address_families( set_remove(c->address_families, INT_TO_PTR(af)); } if (!isempty(state)) - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Trailing garbage, ignoring."); + log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring."); return 0; } @@ -2628,15 +2670,12 @@ int config_parse_cpu_quota( } if (!endswith(rvalue, "%")) { - - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "CPU quota '%s' not ending in '%%'. Ignoring.", rvalue); + log_syntax(unit, LOG_ERR, filename, line, 0, "CPU quota '%s' not ending in '%%'. Ignoring.", rvalue); return 0; } if (sscanf(rvalue, "%lf%%", &percent) != 1 || percent <= 0) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "CPU quota '%s' invalid. Ignoring.", rvalue); + log_syntax(unit, LOG_ERR, filename, line, 0, "CPU quota '%s' invalid. Ignoring.", rvalue); return 0; } @@ -2668,7 +2707,7 @@ int config_parse_memory_limit( r = parse_size(rvalue, 1024, &bytes); if (r < 0 || bytes < 1) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Memory limit '%s' invalid. Ignoring.", rvalue); + log_syntax(unit, LOG_ERR, filename, line, r, "Memory limit '%s' invalid. Ignoring.", rvalue); return 0; } @@ -2699,7 +2738,7 @@ int config_parse_tasks_max( r = safe_atou64(rvalue, &u); if (r < 0 || u < 1) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Maximum tasks value '%s' invalid. Ignoring.", rvalue); + log_syntax(unit, LOG_ERR, filename, line, r, "Maximum tasks value '%s' invalid. Ignoring.", rvalue); return 0; } @@ -2739,8 +2778,7 @@ int config_parse_device_allow( if (!startswith(path, "/dev/") && !startswith(path, "block-") && !startswith(path, "char-")) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Invalid device node path '%s'. Ignoring.", path); + log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device node path '%s'. Ignoring.", path); return 0; } @@ -2749,8 +2787,7 @@ int config_parse_device_allow( m = "rwm"; if (!in_charset(m, "rwm")) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Invalid device rights '%s'. Ignoring.", m); + log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device rights '%s'. Ignoring.", m); return 0; } @@ -2832,7 +2869,7 @@ int config_parse_blockio_device_weight( weight += strspn(weight, WHITESPACE); if (isempty(weight)) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Expected block device and device weight. Ignoring."); + log_syntax(unit, LOG_ERR, filename, line, 0, "Expected block device and device weight. Ignoring."); return 0; } @@ -2841,7 +2878,7 @@ int config_parse_blockio_device_weight( return log_oom(); if (!path_startswith(path, "/dev")) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid device node path '%s'. Ignoring.", path); + log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device node path '%s'. Ignoring.", path); return 0; } @@ -2908,8 +2945,7 @@ int config_parse_blockio_bandwidth( bandwidth += strspn(bandwidth, WHITESPACE); if (!*bandwidth) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Expected space separated pair of device node and bandwidth. Ignoring."); + log_syntax(unit, LOG_ERR, filename, line, 0, "Expected space separated pair of device node and bandwidth. Ignoring."); return 0; } @@ -2918,15 +2954,13 @@ int config_parse_blockio_bandwidth( return log_oom(); if (!path_startswith(path, "/dev")) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Invalid device node path '%s'. Ignoring.", path); + log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device node path '%s'. Ignoring.", path); return 0; } r = parse_size(bandwidth, 1000, &bytes); if (r < 0 || bytes <= 0) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Block IO Bandwidth '%s' invalid. Ignoring.", rvalue); + log_syntax(unit, LOG_ERR, filename, line, r, "Block IO Bandwidth '%s' invalid. Ignoring.", rvalue); return 0; } @@ -2971,13 +3005,12 @@ int config_parse_netclass( r = safe_atou32(rvalue, &v); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Netclass '%s' invalid. Ignoring.", rvalue); + log_syntax(unit, LOG_ERR, filename, line, r, "Netclass '%s' invalid. Ignoring.", rvalue); return 0; } if (v > CGROUP_NETCLASS_FIXED_MAX) - log_syntax(unit, LOG_ERR, filename, line, EINVAL, + log_syntax(unit, LOG_ERR, filename, line, 0, "Fixed netclass %" PRIu32 " out of allowed range (0-%d). Applying anyway.", v, (uint32_t) CGROUP_NETCLASS_FIXED_MAX); c->netclass_id = v; @@ -3009,8 +3042,7 @@ int config_parse_job_mode_isolate( r = parse_boolean(rvalue); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Failed to parse boolean, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse boolean, ignoring: %s", rvalue); return 0; } @@ -3056,14 +3088,12 @@ int config_parse_runtime_directory( r = unit_name_printf(u, t, &n); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, -r, - "Failed to resolve specifiers, ignoring: %s", strerror(-r)); + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %m"); continue; } if (!filename_is_valid(n)) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Runtime directory is not valid, ignoring assignment: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, 0, "Runtime directory is not valid, ignoring assignment: %s", rvalue); continue; } @@ -3074,8 +3104,7 @@ int config_parse_runtime_directory( n = NULL; } if (!isempty(state)) - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Trailing garbage, ignoring."); + log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring."); return 0; } @@ -3122,15 +3151,13 @@ int config_parse_set_status( val = signal_from_string_try_harder(temp); if (val <= 0) { - log_syntax(unit, LOG_ERR, filename, line, -val, - "Failed to parse value, ignoring: %s", word); + log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse value, ignoring: %s", word); continue; } set = &status_set->signal; } else { if (val < 0 || val > 255) { - log_syntax(unit, LOG_ERR, filename, line, ERANGE, - "Value %d is outside range 0-255, ignoring", val); + log_syntax(unit, LOG_ERR, filename, line, 0, "Value %d is outside range 0-255, ignoring", val); continue; } set = &status_set->status; @@ -3142,14 +3169,12 @@ int config_parse_set_status( r = set_put(*set, INT_TO_PTR(val)); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, -r, - "Unable to store: %s", word); + log_syntax(unit, LOG_ERR, filename, line, r, "Unable to store: %s", word); return r; } } if (!isempty(state)) - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Trailing garbage, ignoring."); + log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring."); return 0; } @@ -3191,14 +3216,13 @@ int config_parse_namespace_path_strv( return log_oom(); if (!utf8_is_valid(n)) { - log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue); + log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, rvalue); continue; } offset = n[0] == '-'; if (!path_is_absolute(n + offset)) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Not an absolute path, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, 0, "Not an absolute path, ignoring: %s", rvalue); continue; } @@ -3211,8 +3235,7 @@ int config_parse_namespace_path_strv( n = NULL; } if (!isempty(state)) - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Trailing garbage, ignoring."); + log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring."); return 0; } @@ -3239,8 +3262,7 @@ int config_parse_no_new_privileges( k = parse_boolean(rvalue); if (k < 0) { - log_syntax(unit, LOG_ERR, filename, line, -k, - "Failed to parse boolean value, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, k, "Failed to parse boolean value, ignoring: %s", rvalue); return 0; } @@ -3283,8 +3305,7 @@ int config_parse_protect_home( h = protect_home_from_string(rvalue); if (h < 0){ - log_syntax(unit, LOG_ERR, filename, line, -h, - "Failed to parse protect home value, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse protect home value, ignoring: %s", rvalue); return 0; } @@ -3327,8 +3348,7 @@ int config_parse_protect_system( s = protect_system_from_string(rvalue); if (s < 0){ - log_syntax(unit, LOG_ERR, filename, line, -s, - "Failed to parse protect system value, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse protect system value, ignoring: %s", rvalue); return 0; } diff --git a/src/core/load-fragment.h b/src/core/load-fragment.h index 5d0a09249f..8661cbfedc 100644 --- a/src/core/load-fragment.h +++ b/src/core/load-fragment.h @@ -106,6 +106,8 @@ int config_parse_protect_home(const char* unit, const char *filename, unsigned l int config_parse_protect_system(const char* unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_bus_name(const char* unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_exec_utmp_mode(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_working_directory(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_fdname(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); /* gperf prototypes */ const struct ConfigPerfItem* load_fragment_gperf_lookup(const char *key, unsigned length); diff --git a/src/core/machine-id-setup.c b/src/core/machine-id-setup.c index 8f682c6d10..363ffaaf05 100644 --- a/src/core/machine-id-setup.c +++ b/src/core/machine-id-setup.c @@ -19,24 +19,25 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <unistd.h> -#include <stdio.h> #include <errno.h> -#include <string.h> #include <fcntl.h> +#include <sched.h> +#include <stdio.h> +#include <string.h> #include <sys/mount.h> +#include <unistd.h> -#include "systemd/sd-id128.h" +#include "sd-id128.h" -#include "machine-id-setup.h" +#include "fileio.h" +#include "log.h" #include "macro.h" -#include "util.h" #include "mkdir.h" -#include "log.h" -#include "virt.h" -#include "fileio.h" #include "path-util.h" #include "process-util.h" +#include "util.h" +#include "virt.h" +#include "machine-id-setup.h" static int shorten_uuid(char destination[34], const char source[36]) { unsigned i, j; diff --git a/src/core/main.c b/src/core/main.c index bc72a2b00b..87b3af92bc 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -19,63 +19,64 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdio.h> #include <errno.h> -#include <string.h> -#include <unistd.h> -#include <sys/stat.h> +#include <fcntl.h> #include <getopt.h> #include <signal.h> -#include <fcntl.h> -#include <sys/prctl.h> +#include <stdio.h> +#include <string.h> #include <sys/mount.h> - -#ifdef HAVE_VALGRIND_VALGRIND_H -#include <valgrind/valgrind.h> -#endif +#include <sys/prctl.h> +#include <sys/reboot.h> +#include <sys/stat.h> +#include <unistd.h> #ifdef HAVE_SECCOMP #include <seccomp.h> #endif +#ifdef HAVE_VALGRIND_VALGRIND_H +#include <valgrind/valgrind.h> +#endif #include "sd-daemon.h" #include "sd-bus.h" -#include "log.h" -#include "fdset.h" -#include "special.h" -#include "conf-parser.h" -#include "missing.h" -#include "pager.h" -#include "build.h" -#include "strv.h" -#include "def.h" -#include "virt.h" + #include "architecture.h" -#include "watchdog.h" -#include "switch-root.h" +#include "build.h" +#include "bus-error.h" +#include "bus-util.h" #include "capability.h" -#include "killall.h" -#include "env-util.h" #include "clock-util.h" +#include "conf-parser.h" +#include "cpu-set-util.h" +#include "dbus-manager.h" +#include "def.h" +#include "env-util.h" +#include "fdset.h" #include "fileio.h" -#include "bus-error.h" -#include "bus-util.h" -#include "selinux-util.h" #include "formats-util.h" -#include "process-util.h" -#include "terminal-util.h" -#include "signal-util.h" -#include "manager.h" -#include "dbus-manager.h" +#include "hostname-setup.h" +#include "ima-setup.h" +#include "killall.h" +#include "kmod-setup.h" #include "load-fragment.h" - -#include "mount-setup.h" +#include "log.h" #include "loopback-setup.h" -#include "hostname-setup.h" #include "machine-id-setup.h" +#include "manager.h" +#include "missing.h" +#include "mount-setup.h" +#include "pager.h" +#include "process-util.h" #include "selinux-setup.h" -#include "ima-setup.h" +#include "selinux-util.h" +#include "signal-util.h" #include "smack-setup.h" -#include "kmod-setup.h" +#include "special.h" +#include "strv.h" +#include "switch-root.h" +#include "terminal-util.h" +#include "virt.h" +#include "watchdog.h" static enum { ACTION_RUN, @@ -88,8 +89,9 @@ static enum { static char *arg_default_unit = NULL; static ManagerRunningAs arg_running_as = _MANAGER_RUNNING_AS_INVALID; static bool arg_dump_core = true; -static bool arg_crash_shell = false; static int arg_crash_chvt = -1; +static bool arg_crash_shell = false; +static bool arg_crash_reboot = false; static bool arg_confirm_spawn = false; static ShowStatus arg_show_status = _SHOW_STATUS_UNSET; static bool arg_switched_root = false; @@ -116,8 +118,6 @@ static bool arg_default_blockio_accounting = false; static bool arg_default_memory_accounting = false; static bool arg_default_tasks_accounting = false; -static void nop_handler(int sig) {} - static void pager_open_if_enabled(void) { if (arg_no_pager <= 0) @@ -126,49 +126,66 @@ static void pager_open_if_enabled(void) { pager_open(false); } +noreturn static void freeze_or_reboot(void) { + + if (arg_crash_reboot) { + log_notice("Rebooting in 10s..."); + (void) sleep(10); + + log_notice("Rebooting now..."); + (void) reboot(RB_AUTOBOOT); + log_emergency_errno(errno, "Failed to reboot: %m"); + } + + log_emergency("Freezing execution."); + freeze(); +} + noreturn static void crash(int sig) { + struct sigaction sa; + pid_t pid; if (getpid() != 1) /* Pass this on immediately, if this is not PID 1 */ - raise(sig); + (void) raise(sig); else if (!arg_dump_core) log_emergency("Caught <%s>, not dumping core.", signal_to_string(sig)); else { - struct sigaction sa = { - .sa_handler = nop_handler, + sa = (struct sigaction) { + .sa_handler = nop_signal_handler, .sa_flags = SA_NOCLDSTOP|SA_RESTART, }; - pid_t pid; /* We want to wait for the core process, hence let's enable SIGCHLD */ - sigaction(SIGCHLD, &sa, NULL); + (void) sigaction(SIGCHLD, &sa, NULL); pid = raw_clone(SIGCHLD, NULL); if (pid < 0) log_emergency_errno(errno, "Caught <%s>, cannot fork for core dump: %m", signal_to_string(sig)); - else if (pid == 0) { - struct rlimit rl = {}; + struct rlimit rl = { + .rlim_cur = RLIM_INFINITY, + .rlim_max = RLIM_INFINITY, + }; /* Enable default signal handler for core dump */ - zero(sa); - sa.sa_handler = SIG_DFL; - sigaction(sig, &sa, NULL); + sa = (struct sigaction) { + .sa_handler = SIG_DFL, + }; + (void) sigaction(sig, &sa, NULL); /* Don't limit the core dump size */ - rl.rlim_cur = RLIM_INFINITY; - rl.rlim_max = RLIM_INFINITY; - setrlimit(RLIMIT_CORE, &rl); + (void) setrlimit(RLIMIT_CORE, &rl); /* Just to be sure... */ (void) chdir("/"); /* Raise the signal again */ pid = raw_getpid(); - kill(pid, sig); /* raise() would kill the parent */ + (void) kill(pid, sig); /* raise() would kill the parent */ assert_not_reached("We shouldn't be here..."); - _exit(1); + _exit(EXIT_FAILURE); } else { siginfo_t status; int r; @@ -190,37 +207,38 @@ noreturn static void crash(int sig) { } } - if (arg_crash_chvt) - chvt(arg_crash_chvt); + if (arg_crash_chvt >= 0) + (void) chvt(arg_crash_chvt); - if (arg_crash_shell) { - struct sigaction sa = { - .sa_handler = SIG_IGN, - .sa_flags = SA_NOCLDSTOP|SA_NOCLDWAIT|SA_RESTART, - }; - pid_t pid; + sa = (struct sigaction) { + .sa_handler = SIG_IGN, + .sa_flags = SA_NOCLDSTOP|SA_NOCLDWAIT|SA_RESTART, + }; - log_info("Executing crash shell in 10s..."); - sleep(10); + /* Let the kernel reap children for us */ + (void) sigaction(SIGCHLD, &sa, NULL); - /* Let the kernel reap children for us */ - assert_se(sigaction(SIGCHLD, &sa, NULL) == 0); + if (arg_crash_shell) { + log_notice("Executing crash shell in 10s..."); + (void) sleep(10); pid = raw_clone(SIGCHLD, NULL); if (pid < 0) log_emergency_errno(errno, "Failed to fork off crash shell: %m"); else if (pid == 0) { - make_console_stdio(); - execle("/bin/sh", "/bin/sh", NULL, environ); + (void) setsid(); + (void) make_console_stdio(); + (void) execle("/bin/sh", "/bin/sh", NULL, environ); log_emergency_errno(errno, "execle() failed: %m"); - _exit(1); - } else - log_info("Successfully spawned crash shell as PID "PID_FMT".", pid); + _exit(EXIT_FAILURE); + } else { + log_info("Spawned crash shell as PID "PID_FMT".", pid); + (void) wait_for_terminate(pid, NULL); + } } - log_emergency("Freezing execution."); - freeze(); + freeze_or_reboot(); } static void install_crash_handler(void) { @@ -254,17 +272,20 @@ static int console_setup(void) { return 0; } -static int set_default_unit(const char *u) { - char *c; +static int parse_crash_chvt(const char *value) { + int b; - assert(u); + if (safe_atoi(value, &arg_crash_chvt) >= 0) + return 0; - c = strdup(u); - if (!c) - return -ENOMEM; + b = parse_boolean(value); + if (b < 0) + return b; - free(arg_default_unit); - arg_default_unit = c; + if (b > 0) + arg_crash_chvt = 0; /* switch to where kmsg goes */ + else + arg_crash_chvt = -1; /* turn off switching */ return 0; } @@ -292,12 +313,12 @@ static int parse_proc_cmdline_item(const char *key, const char *value) { if (streq(key, "systemd.unit") && value) { if (!in_initrd()) - return set_default_unit(value); + return free_and_strdup(&arg_default_unit, value); } else if (streq(key, "rd.systemd.unit") && value) { if (in_initrd()) - return set_default_unit(value); + return free_and_strdup(&arg_default_unit, value); } else if (streq(key, "systemd.dump_core") && value) { @@ -307,6 +328,11 @@ static int parse_proc_cmdline_item(const char *key, const char *value) { else arg_dump_core = r; + } else if (streq(key, "systemd.crash_chvt") && value) { + + if (parse_crash_chvt(value) < 0) + log_warning("Failed to parse crash chvt switch %s. Ignoring.", value); + } else if (streq(key, "systemd.crash_shell") && value) { r = parse_boolean(value); @@ -315,12 +341,13 @@ static int parse_proc_cmdline_item(const char *key, const char *value) { else arg_crash_shell = r; - } else if (streq(key, "systemd.crash_chvt") && value) { + } else if (streq(key, "systemd.crash_reboot") && value) { - if (safe_atoi(value, &r) < 0) - log_warning("Failed to parse crash chvt switch %s. Ignoring.", value); + r = parse_boolean(value); + if (r < 0) + log_warning("Failed to parse crash reboot switch %s. Ignoring.", value); else - arg_crash_chvt = r; + arg_crash_reboot = r; } else if (streq(key, "systemd.confirm_spawn") && value) { @@ -384,7 +411,7 @@ static int parse_proc_cmdline_item(const char *key, const char *value) { /* SysV compatibility */ for (i = 0; i < ELEMENTSOF(rlmap); i += 2) if (streq(key, rlmap[i])) - return set_default_unit(rlmap[i+1]); + return free_and_strdup(&arg_default_unit, rlmap[i+1]); } return 0; @@ -410,9 +437,9 @@ static int parse_proc_cmdline_item(const char *key, const char *value) { \ r = func(rvalue); \ if (r < 0) \ - log_syntax(unit, LOG_ERR, filename, line, -r, \ - "Invalid " descr "'%s': %s", \ - rvalue, strerror(-r)); \ + log_syntax(unit, LOG_ERR, filename, line, r, \ + "Invalid " descr "'%s': %m", \ + rvalue); \ \ return 0; \ } @@ -437,8 +464,7 @@ static int config_parse_cpu_affinity2( _cleanup_cpu_free_ cpu_set_t *c = NULL; int ncpus; - ncpus = parse_cpu_set(rvalue, &c, unit, filename, line, lvalue); - + ncpus = parse_cpu_set_and_warn(rvalue, &c, unit, filename, line, lvalue); if (ncpus < 0) return ncpus; @@ -470,29 +496,38 @@ static int config_parse_show_status( k = parse_show_status(rvalue, b); if (k < 0) { - log_syntax(unit, LOG_ERR, filename, line, -k, - "Failed to parse show status setting, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, k, "Failed to parse show status setting, ignoring: %s", rvalue); return 0; } return 0; } -static void strv_free_free(char ***l) { - char ***i; +static int config_parse_crash_chvt( + const char* unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { - if (!l) - return; + int r; - for (i = l; *i; i++) - strv_free(*i); + assert(filename); + assert(lvalue); + assert(rvalue); - free(l); -} + r = parse_crash_chvt(rvalue); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse CrashChangeVT= setting, ignoring: %s", rvalue); + return 0; + } -static void free_join_controllers(void) { - strv_free_free(arg_join_controllers); - arg_join_controllers = NULL; + return 0; } static int config_parse_join_controllers(const char *unit, @@ -513,7 +548,7 @@ static int config_parse_join_controllers(const char *unit, assert(lvalue); assert(rvalue); - free_join_controllers(); + arg_join_controllers = strv_free_free(arg_join_controllers); for (;;) { _cleanup_free_ char *word = NULL; @@ -530,7 +565,7 @@ static int config_parse_join_controllers(const char *unit, l = strv_split(word, ","); if (!l) - log_oom(); + return log_oom(); strv_uniq(l); if (strv_length(l) <= 1) { @@ -564,7 +599,7 @@ static int config_parse_join_controllers(const char *unit, for (a = arg_join_controllers; *a; a++) { if (strv_overlap(*a, l)) { - if (strv_extend_strv(&l, *a) < 0) { + if (strv_extend_strv(&l, *a, false) < 0) { strv_free(l); strv_free_free(t); return log_oom(); @@ -591,8 +626,7 @@ static int config_parse_join_controllers(const char *unit, } } if (!isempty(rvalue)) - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Trailing garbage, ignoring."); + log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring."); return 0; } @@ -605,9 +639,11 @@ static int parse_config_file(void) { { "Manager", "LogColor", config_parse_color, 0, NULL }, { "Manager", "LogLocation", config_parse_location, 0, NULL }, { "Manager", "DumpCore", config_parse_bool, 0, &arg_dump_core }, + { "Manager", "CrashChVT", /* legacy */ config_parse_crash_chvt, 0, NULL }, + { "Manager", "CrashChangeVT", config_parse_crash_chvt, 0, NULL }, { "Manager", "CrashShell", config_parse_bool, 0, &arg_crash_shell }, + { "Manager", "CrashReboot", config_parse_bool, 0, &arg_crash_reboot }, { "Manager", "ShowStatus", config_parse_show_status, 0, &arg_show_status }, - { "Manager", "CrashChVT", config_parse_int, 0, &arg_crash_chvt }, { "Manager", "CPUAffinity", config_parse_cpu_affinity2, 0, NULL }, { "Manager", "JoinControllers", config_parse_join_controllers, 0, &arg_join_controllers }, { "Manager", "RuntimeWatchdogSec", config_parse_sec, 0, &arg_runtime_watchdog }, @@ -695,7 +731,9 @@ static int parse_argv(int argc, char *argv[]) { ARG_VERSION, ARG_DUMP_CONFIGURATION_ITEMS, ARG_DUMP_CORE, + ARG_CRASH_CHVT, ARG_CRASH_SHELL, + ARG_CRASH_REBOOT, ARG_CONFIRM_SPAWN, ARG_SHOW_STATUS, ARG_DESERIALIZE, @@ -718,7 +756,9 @@ static int parse_argv(int argc, char *argv[]) { { "version", no_argument, NULL, ARG_VERSION }, { "dump-configuration-items", no_argument, NULL, ARG_DUMP_CONFIGURATION_ITEMS }, { "dump-core", optional_argument, NULL, ARG_DUMP_CORE }, + { "crash-chvt", required_argument, NULL, ARG_CRASH_CHVT }, { "crash-shell", optional_argument, NULL, ARG_CRASH_SHELL }, + { "crash-reboot", optional_argument, NULL, ARG_CRASH_REBOOT }, { "confirm-spawn", optional_argument, NULL, ARG_CONFIRM_SPAWN }, { "show-status", optional_argument, NULL, ARG_SHOW_STATUS }, { "deserialize", required_argument, NULL, ARG_DESERIALIZE }, @@ -803,7 +843,7 @@ static int parse_argv(int argc, char *argv[]) { case ARG_UNIT: - r = set_default_unit(optarg); + r = free_and_strdup(&arg_default_unit, optarg); if (r < 0) return log_error_errno(r, "Failed to set default unit %s: %m", optarg); @@ -836,21 +876,42 @@ static int parse_argv(int argc, char *argv[]) { break; case ARG_DUMP_CORE: - r = optarg ? parse_boolean(optarg) : 1; - if (r < 0) { - log_error("Failed to parse dump core boolean %s.", optarg); - return r; + if (!optarg) + arg_dump_core = true; + else { + r = parse_boolean(optarg); + if (r < 0) + return log_error_errno(r, "Failed to parse dump core boolean: %s", optarg); + arg_dump_core = r; } - arg_dump_core = r; + break; + + case ARG_CRASH_CHVT: + r = parse_crash_chvt(optarg); + if (r < 0) + return log_error_errno(r, "Failed to parse crash virtual terminal index: %s", optarg); break; case ARG_CRASH_SHELL: - r = optarg ? parse_boolean(optarg) : 1; - if (r < 0) { - log_error("Failed to parse crash shell boolean %s.", optarg); - return r; + if (!optarg) + arg_crash_shell = true; + else { + r = parse_boolean(optarg); + if (r < 0) + return log_error_errno(r, "Failed to parse crash shell boolean: %s", optarg); + arg_crash_shell = r; + } + break; + + case ARG_CRASH_REBOOT: + if (!optarg) + arg_crash_reboot = true; + else { + r = parse_boolean(optarg); + if (r < 0) + return log_error_errno(r, "Failed to parse crash shell boolean: %s", optarg); + arg_crash_reboot = r; } - arg_crash_shell = r; break; case ARG_CONFIRM_SPAWN: @@ -880,17 +941,16 @@ static int parse_argv(int argc, char *argv[]) { r = safe_atoi(optarg, &fd); if (r < 0 || fd < 0) { log_error("Failed to parse deserialize option %s.", optarg); - return r < 0 ? r : -EINVAL; + return -EINVAL; } - fd_cloexec(fd, true); + (void) fd_cloexec(fd, true); f = fdopen(fd, "r"); if (!f) return log_error_errno(errno, "Failed to open serialization fd: %m"); safe_fclose(arg_serialization); - arg_serialization = f; break; @@ -950,14 +1010,16 @@ static int help(void) { " --unit=UNIT Set default unit\n" " --system Run a system instance, even if PID != 1\n" " --user Run a user instance\n" - " --dump-core[=0|1] Dump core on crash\n" - " --crash-shell[=0|1] Run shell on crash\n" - " --confirm-spawn[=0|1] Ask for confirmation when spawning processes\n" - " --show-status[=0|1] Show status updates on the console during bootup\n" + " --dump-core[=BOOL] Dump core on crash\n" + " --crash-vt=NR Change to specified VT on crash\n" + " --crash-reboot[=BOOL] Reboot on crash\n" + " --crash-shell[=BOOL] Run shell on crash\n" + " --confirm-spawn[=BOOL] Ask for confirmation when spawning processes\n" + " --show-status[=BOOL] Show status updates on the console during bootup\n" " --log-target=TARGET Set log target (console, journal, kmsg, journal-or-kmsg, null)\n" " --log-level=LEVEL Set log level (debug, info, notice, warning, err, crit, alert, emerg)\n" - " --log-color[=0|1] Highlight important log messages\n" - " --log-location[=0|1] Include code location in log messages\n" + " --log-color[=BOOL] Highlight important log messages\n" + " --log-location[=BOOL] Include code location in log messages\n" " --default-standard-output= Set default standard output for services\n" " --default-standard-error= Set default standard error output for services\n", program_invocation_short_name); @@ -965,16 +1027,9 @@ static int help(void) { return 0; } -static int version(void) { - puts(PACKAGE_STRING); - puts(SYSTEMD_FEATURES); - - return 0; -} - static int prepare_reexecute(Manager *m, FILE **_f, FDSet **_fds, bool switching_root) { - FILE *f = NULL; - FDSet *fds = NULL; + _cleanup_fdset_free_ FDSet *fds = NULL; + _cleanup_fclose_ FILE *f = NULL; int r; assert(m); @@ -982,56 +1037,39 @@ static int prepare_reexecute(Manager *m, FILE **_f, FDSet **_fds, bool switching assert(_fds); r = manager_open_serialization(m, &f); - if (r < 0) { - log_error_errno(r, "Failed to create serialization file: %m"); - goto fail; - } + if (r < 0) + return log_error_errno(r, "Failed to create serialization file: %m"); /* Make sure nothing is really destructed when we shut down */ m->n_reloading ++; bus_manager_send_reloading(m, true); fds = fdset_new(); - if (!fds) { - r = -ENOMEM; - log_error_errno(r, "Failed to allocate fd set: %m"); - goto fail; - } + if (!fds) + return log_oom(); r = manager_serialize(m, f, fds, switching_root); - if (r < 0) { - log_error_errno(r, "Failed to serialize state: %m"); - goto fail; - } + if (r < 0) + return log_error_errno(r, "Failed to serialize state: %m"); - if (fseeko(f, 0, SEEK_SET) < 0) { - log_error_errno(errno, "Failed to rewind serialization fd: %m"); - goto fail; - } + if (fseeko(f, 0, SEEK_SET) == (off_t) -1) + return log_error_errno(errno, "Failed to rewind serialization fd: %m"); r = fd_cloexec(fileno(f), false); - if (r < 0) { - log_error_errno(r, "Failed to disable O_CLOEXEC for serialization: %m"); - goto fail; - } + if (r < 0) + return log_error_errno(r, "Failed to disable O_CLOEXEC for serialization: %m"); r = fdset_cloexec(fds, false); - if (r < 0) { - log_error_errno(r, "Failed to disable O_CLOEXEC for serialization fds: %m"); - goto fail; - } + if (r < 0) + return log_error_errno(r, "Failed to disable O_CLOEXEC for serialization fds: %m"); *_f = f; *_fds = fds; - return 0; - -fail: - fdset_free(fds); - - safe_fclose(f); + f = NULL; + fds = NULL; - return r; + return 0; } static int bump_rlimit_nofile(struct rlimit *saved_rlimit) { @@ -1089,8 +1127,8 @@ static void test_mtab(void) { log_error("/etc/mtab is not a symlink or not pointing to /proc/self/mounts. " "This is not supported anymore. " - "Please make sure to replace this file by a symlink to avoid incorrect or misleading mount(8) output."); - freeze(); + "Please replace /etc/mtab with a symlink to /proc/self/mounts."); + freeze_or_reboot(); } static void test_usr(void) { @@ -1116,15 +1154,19 @@ static int initialize_join_controllers(void) { return -ENOMEM; arg_join_controllers[0] = strv_new("cpu", "cpuacct", NULL); - arg_join_controllers[1] = strv_new("net_cls", "net_prio", NULL); - arg_join_controllers[2] = NULL; + if (!arg_join_controllers[0]) + goto oom; - if (!arg_join_controllers[0] || !arg_join_controllers[1]) { - free_join_controllers(); - return -ENOMEM; - } + arg_join_controllers[1] = strv_new("net_cls", "net_prio", NULL); + if (!arg_join_controllers[1]) + goto oom; + arg_join_controllers[2] = NULL; return 0; + +oom: + arg_join_controllers = strv_free_free(arg_join_controllers); + return -ENOMEM; } static int enforce_syscall_archs(Set *archs) { @@ -1222,7 +1264,6 @@ int main(int argc, char *argv[]) { char *switch_root_dir = NULL, *switch_root_init = NULL; struct rlimit saved_rlimit_nofile = RLIMIT_MAKE_CONST(0); const char *error_message = NULL; - uint8_t shutdown_exit_code = 0; #ifdef HAVE_SYSV_COMPAT if (getpid() != 1 && strstr(program_invocation_short_name, "init")) { @@ -1369,7 +1410,7 @@ int main(int argc, char *argv[]) { } /* Initialize default unit */ - r = set_default_unit(SPECIAL_DEFAULT_TARGET); + r = free_and_strdup(&arg_default_unit, SPECIAL_DEFAULT_TARGET); if (r < 0) { log_emergency_errno(r, "Failed to set default unit %s: %m", SPECIAL_DEFAULT_TARGET); error_message = "Failed to set default unit"; @@ -1646,8 +1687,7 @@ int main(int argc, char *argv[]) { /* This will close all file descriptors that were opened, but * not claimed by any unit. */ - fdset_free(fds); - fds = NULL; + fds = fdset_free(fds); arg_serialization = safe_fclose(arg_serialization); @@ -1775,8 +1815,9 @@ int main(int argc, char *argv[]) { goto finish; case MANAGER_EXIT: + retval = m->return_value; + if (m->running_as == MANAGER_USER) { - retval = EXIT_SUCCESS; log_debug("Exit."); goto finish; } @@ -1809,21 +1850,17 @@ int main(int argc, char *argv[]) { finish: pager_close(); - if (m) { + if (m) arg_shutdown_watchdog = m->shutdown_watchdog; - shutdown_exit_code = m->return_value; - } + m = manager_free(m); for (j = 0; j < ELEMENTSOF(arg_default_rlimit); j++) arg_default_rlimit[j] = mfree(arg_default_rlimit[j]); arg_default_unit = mfree(arg_default_unit); - - free_join_controllers(); - + arg_join_controllers = strv_free_free(arg_join_controllers); arg_default_environment = strv_free(arg_default_environment); - arg_syscall_archs = set_free(arg_syscall_archs); mac_selinux_finish(); @@ -1841,7 +1878,7 @@ finish: * that the new systemd can pass the kernel default to * its child processes */ if (saved_rlimit_nofile.rlim_cur > 0) - setrlimit(RLIMIT_NOFILE, &saved_rlimit_nofile); + (void) setrlimit(RLIMIT_NOFILE, &saved_rlimit_nofile); if (switch_root_dir) { /* Kill all remaining processes from the @@ -1883,10 +1920,10 @@ finish: /* do not pass along the environment we inherit from the kernel or initrd */ if (switch_root_dir) - clearenv(); + (void) clearenv(); assert(i <= args_size); - execv(args[0], (char* const*) args); + (void) execv(args[0], (char* const*) args); } /* Try the fallback, if there is any, without any @@ -1896,14 +1933,10 @@ finish: * but let's hope that doesn't matter.) */ arg_serialization = safe_fclose(arg_serialization); - - if (fds) { - fdset_free(fds); - fds = NULL; - } + fds = fdset_free(fds); /* Reopen the console */ - make_console_stdio(); + (void) make_console_stdio(); for (j = 1, i = 1; j < (unsigned) argc; j++) args[i++] = argv[j]; @@ -1917,30 +1950,26 @@ finish: if (switch_root_init) { args[0] = switch_root_init; - execv(args[0], (char* const*) args); + (void) execv(args[0], (char* const*) args); log_warning_errno(errno, "Failed to execute configured init, trying fallback: %m"); } args[0] = "/sbin/init"; - execv(args[0], (char* const*) args); + (void) execv(args[0], (char* const*) args); if (errno == ENOENT) { log_warning("No /sbin/init, trying fallback"); args[0] = "/bin/sh"; args[1] = NULL; - execv(args[0], (char* const*) args); + (void) execv(args[0], (char* const*) args); log_error_errno(errno, "Failed to execute /bin/sh, giving up: %m"); } else log_warning_errno(errno, "Failed to execute /sbin/init, giving up: %m"); } arg_serialization = safe_fclose(arg_serialization); - - if (fds) { - fdset_free(fds); - fds = NULL; - } + fds = fdset_free(fds); #ifdef HAVE_VALGRIND_VALGRIND_H /* If we are PID 1 and running under valgrind, then let's exit @@ -1969,6 +1998,7 @@ finish: xsprintf(log_level, "%d", log_get_max_level()); switch (log_get_target()) { + case LOG_TARGET_KMSG: case LOG_TARGET_JOURNAL_OR_KMSG: case LOG_TARGET_SYSLOG_OR_KMSG: @@ -1994,7 +2024,7 @@ finish: if (streq(shutdown_verb, "exit")) { command_line[pos++] = "--exit-code"; command_line[pos++] = exit_code; - xsprintf(exit_code, "%d", shutdown_exit_code); + xsprintf(exit_code, "%d", retval); } assert(pos < ELEMENTSOF(command_line)); @@ -2010,7 +2040,7 @@ finish: /* Tell the binary how often to ping, ignore failure */ if (asprintf(&e, "WATCHDOG_USEC="USEC_FMT, arg_shutdown_watchdog) > 0) - strv_push(&env_block, e); + (void) strv_push(&env_block, e); } else watchdog_close(true); @@ -2030,7 +2060,7 @@ finish: manager_status_printf(NULL, STATUS_TYPE_EMERGENCY, ANSI_HIGHLIGHT_RED "!!!!!!" ANSI_NORMAL, "%s, freezing.", error_message); - freeze(); + freeze_or_reboot(); } return retval; diff --git a/src/core/manager.c b/src/core/manager.c index 9bfe867ea0..526d4d1cef 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -19,19 +19,19 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include <dirent.h> #include <errno.h> -#include <string.h> +#include <fcntl.h> +#include <linux/kd.h> #include <signal.h> -#include <sys/wait.h> -#include <unistd.h> -#include <sys/inotify.h> +#include <string.h> #include <sys/epoll.h> -#include <sys/reboot.h> +#include <sys/inotify.h> #include <sys/ioctl.h> -#include <linux/kd.h> -#include <fcntl.h> -#include <dirent.h> +#include <sys/reboot.h> #include <sys/timerfd.h> +#include <sys/wait.h> +#include <unistd.h> #ifdef HAVE_AUDIT #include <libaudit.h> @@ -40,40 +40,40 @@ #include "sd-daemon.h" #include "sd-messages.h" +#include "audit-fd.h" +#include "boot-timestamps.h" +#include "bus-common-errors.h" +#include "bus-error.h" +#include "bus-kernel.h" +#include "bus-util.h" +#include "dbus-job.h" +#include "dbus-manager.h" +#include "dbus-unit.h" +#include "dbus.h" +#include "env-util.h" +#include "exit-status.h" #include "hashmap.h" -#include "macro.h" -#include "strv.h" +#include "locale-setup.h" #include "log.h" -#include "util.h" +#include "macro.h" +#include "missing.h" #include "mkdir.h" +#include "path-lookup.h" +#include "path-util.h" +#include "process-util.h" #include "ratelimit.h" -#include "locale-setup.h" -#include "unit-name.h" -#include "missing.h" #include "rm-rf.h" -#include "path-lookup.h" +#include "signal-util.h" #include "special.h" -#include "exit-status.h" +#include "strv.h" +#include "terminal-util.h" +#include "time-util.h" +#include "transaction.h" +#include "unit-name.h" +#include "util.h" #include "virt.h" #include "watchdog.h" -#include "path-util.h" -#include "audit-fd.h" -#include "boot-timestamps.h" -#include "env-util.h" -#include "bus-common-errors.h" -#include "bus-error.h" -#include "bus-util.h" -#include "bus-kernel.h" -#include "time-util.h" -#include "process-util.h" -#include "terminal-util.h" -#include "signal-util.h" -#include "dbus.h" -#include "dbus-unit.h" -#include "dbus-job.h" -#include "dbus-manager.h" #include "manager.h" -#include "transaction.h" /* Initial delay and the interval for printing status messages about running jobs */ #define JOBS_IN_PROGRESS_WAIT_USEC (5*USEC_PER_SEC) @@ -495,6 +495,7 @@ static void manager_clean_environment(Manager *m) { "MANAGERPID", "LISTEN_PID", "LISTEN_FDS", + "LISTEN_FDNAMES", "WATCHDOG_PID", "WATCHDOG_USEC", NULL); diff --git a/src/core/manager.h b/src/core/manager.h index cc0e5e3361..fad10aaacf 100644 --- a/src/core/manager.h +++ b/src/core/manager.h @@ -27,8 +27,8 @@ #include "sd-bus.h" #include "sd-event.h" -#include "fdset.h" #include "cgroup-util.h" +#include "fdset.h" #include "hashmap.h" #include "list.h" #include "ratelimit.h" @@ -69,11 +69,11 @@ typedef enum StatusType { STATUS_TYPE_EMERGENCY, } StatusType; +#include "execute.h" #include "job.h" #include "path-lookup.h" -#include "execute.h" -#include "unit-name.h" #include "show-status.h" +#include "unit-name.h" struct Manager { /* Note that the set of units we know of is allowed to be diff --git a/src/core/mount.c b/src/core/mount.c index e7aae6e19a..8611129453 100644 --- a/src/core/mount.c +++ b/src/core/mount.c @@ -694,6 +694,9 @@ static int mount_spawn(Mount *m, 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(m); @@ -1756,24 +1759,6 @@ static int mount_kill(Unit *u, KillWho who, int signo, sd_bus_error *error) { return unit_kill_common(u, who, signo, -1, MOUNT(u)->control_pid, error); } -static const char* const mount_state_table[_MOUNT_STATE_MAX] = { - [MOUNT_DEAD] = "dead", - [MOUNT_MOUNTING] = "mounting", - [MOUNT_MOUNTING_DONE] = "mounting-done", - [MOUNT_MOUNTED] = "mounted", - [MOUNT_REMOUNTING] = "remounting", - [MOUNT_UNMOUNTING] = "unmounting", - [MOUNT_MOUNTING_SIGTERM] = "mounting-sigterm", - [MOUNT_MOUNTING_SIGKILL] = "mounting-sigkill", - [MOUNT_REMOUNTING_SIGTERM] = "remounting-sigterm", - [MOUNT_REMOUNTING_SIGKILL] = "remounting-sigkill", - [MOUNT_UNMOUNTING_SIGTERM] = "unmounting-sigterm", - [MOUNT_UNMOUNTING_SIGKILL] = "unmounting-sigkill", - [MOUNT_FAILED] = "failed" -}; - -DEFINE_STRING_TABLE_LOOKUP(mount_state, MountState); - static const char* const mount_exec_command_table[_MOUNT_EXEC_COMMAND_MAX] = { [MOUNT_EXEC_MOUNT] = "ExecMount", [MOUNT_EXEC_UNMOUNT] = "ExecUnmount", diff --git a/src/core/mount.h b/src/core/mount.h index 280ea0d638..83d14ae713 100644 --- a/src/core/mount.h +++ b/src/core/mount.h @@ -26,24 +26,6 @@ typedef struct Mount Mount; #include "kill.h" #include "execute.h" -typedef enum MountState { - MOUNT_DEAD, - MOUNT_MOUNTING, /* /usr/bin/mount is running, but the mount is not done yet. */ - MOUNT_MOUNTING_DONE, /* /usr/bin/mount is running, and the mount is done. */ - MOUNT_MOUNTED, - MOUNT_REMOUNTING, - MOUNT_UNMOUNTING, - MOUNT_MOUNTING_SIGTERM, - MOUNT_MOUNTING_SIGKILL, - MOUNT_REMOUNTING_SIGTERM, - MOUNT_REMOUNTING_SIGKILL, - MOUNT_UNMOUNTING_SIGTERM, - MOUNT_UNMOUNTING_SIGKILL, - MOUNT_FAILED, - _MOUNT_STATE_MAX, - _MOUNT_STATE_INVALID = -1 -} MountState; - typedef enum MountExecCommand { MOUNT_EXEC_MOUNT, MOUNT_EXEC_UNMOUNT, @@ -120,9 +102,6 @@ extern const UnitVTable mount_vtable; void mount_fd_event(Manager *m, int events); -const char* mount_state_to_string(MountState i) _const_; -MountState mount_state_from_string(const char *s) _pure_; - const char* mount_exec_command_to_string(MountExecCommand i) _const_; MountExecCommand mount_exec_command_from_string(const char *s) _pure_; diff --git a/src/core/namespace.c b/src/core/namespace.c index eb88574f8f..2b8b707df5 100644 --- a/src/core/namespace.c +++ b/src/core/namespace.c @@ -643,16 +643,7 @@ int setup_tmp_dirs(const char *id, char **tmp_dir, char **var_tmp_dir) { int setup_netns(int netns_storage_socket[2]) { _cleanup_close_ int netns = -1; - union { - struct cmsghdr cmsghdr; - uint8_t buf[CMSG_SPACE(sizeof(int))]; - } control = {}; - struct msghdr mh = { - .msg_control = &control, - .msg_controllen = sizeof(control), - }; - struct cmsghdr *cmsg; - int r; + int r, q; assert(netns_storage_socket); assert(netns_storage_socket[0] >= 0); @@ -669,12 +660,8 @@ int setup_netns(int netns_storage_socket[2]) { if (lockf(netns_storage_socket[0], F_LOCK, 0) < 0) return -errno; - if (recvmsg(netns_storage_socket[0], &mh, MSG_DONTWAIT|MSG_CMSG_CLOEXEC) < 0) { - if (errno != EAGAIN) { - r = -errno; - goto fail; - } - + netns = receive_one_fd(netns_storage_socket[0], MSG_DONTWAIT); + if (netns == -EAGAIN) { /* Nothing stored yet, so let's create a new namespace */ if (unshare(CLONE_NEWNET) < 0) { @@ -691,15 +678,13 @@ int setup_netns(int netns_storage_socket[2]) { } r = 1; - } else { - /* Yay, found something, so let's join the namespace */ - CMSG_FOREACH(cmsg, &mh) - if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) { - assert(cmsg->cmsg_len == CMSG_LEN(sizeof(int))); - netns = *(int*) CMSG_DATA(cmsg); - } + } else if (netns < 0) { + r = netns; + goto fail; + } else { + /* Yay, found something, so let's join the namespace */ if (setns(netns, CLONE_NEWNET) < 0) { r = -errno; goto fail; @@ -708,21 +693,14 @@ int setup_netns(int netns_storage_socket[2]) { r = 0; } - cmsg = CMSG_FIRSTHDR(&mh); - cmsg->cmsg_level = SOL_SOCKET; - cmsg->cmsg_type = SCM_RIGHTS; - cmsg->cmsg_len = CMSG_LEN(sizeof(int)); - memcpy(CMSG_DATA(cmsg), &netns, sizeof(int)); - mh.msg_controllen = cmsg->cmsg_len; - - if (sendmsg(netns_storage_socket[1], &mh, MSG_DONTWAIT|MSG_NOSIGNAL) < 0) { - r = -errno; + q = send_one_fd(netns_storage_socket[1], netns, MSG_DONTWAIT); + if (q < 0) { + r = q; goto fail; } fail: lockf(netns_storage_socket[0], F_ULOCK, 0); - return r; } diff --git a/src/core/path.c b/src/core/path.c index e9111d0612..081ac2040d 100644 --- a/src/core/path.c +++ b/src/core/path.c @@ -715,15 +715,6 @@ static void path_reset_failed(Unit *u) { p->result = PATH_SUCCESS; } -static const char* const path_state_table[_PATH_STATE_MAX] = { - [PATH_DEAD] = "dead", - [PATH_WAITING] = "waiting", - [PATH_RUNNING] = "running", - [PATH_FAILED] = "failed" -}; - -DEFINE_STRING_TABLE_LOOKUP(path_state, PathState); - static const char* const path_type_table[_PATH_TYPE_MAX] = { [PATH_EXISTS] = "PathExists", [PATH_EXISTS_GLOB] = "PathExistsGlob", diff --git a/src/core/path.h b/src/core/path.h index dec39333e4..deb9bab1e5 100644 --- a/src/core/path.h +++ b/src/core/path.h @@ -26,15 +26,6 @@ typedef struct PathSpec PathSpec; #include "unit.h" -typedef enum PathState { - PATH_DEAD, - PATH_WAITING, - PATH_RUNNING, - PATH_FAILED, - _PATH_STATE_MAX, - _PATH_STATE_INVALID = -1 -} PathState; - typedef enum PathType { PATH_EXISTS, PATH_EXISTS_GLOB, @@ -96,9 +87,6 @@ void path_free_specs(Path *p); extern const UnitVTable path_vtable; -const char* path_state_to_string(PathState i) _const_; -PathState path_state_from_string(const char *s) _pure_; - const char* path_type_to_string(PathType i) _const_; PathType path_type_from_string(const char *s) _pure_; diff --git a/src/core/scope.c b/src/core/scope.c index 98395becfd..7325e3601b 100644 --- a/src/core/scope.c +++ b/src/core/scope.c @@ -549,17 +549,6 @@ static int scope_enumerate(Manager *m) { return 0; } -static const char* const scope_state_table[_SCOPE_STATE_MAX] = { - [SCOPE_DEAD] = "dead", - [SCOPE_RUNNING] = "running", - [SCOPE_ABANDONED] = "abandoned", - [SCOPE_STOP_SIGTERM] = "stop-sigterm", - [SCOPE_STOP_SIGKILL] = "stop-sigkill", - [SCOPE_FAILED] = "failed", -}; - -DEFINE_STRING_TABLE_LOOKUP(scope_state, ScopeState); - static const char* const scope_result_table[_SCOPE_RESULT_MAX] = { [SCOPE_SUCCESS] = "success", [SCOPE_FAILURE_RESOURCES] = "resources", diff --git a/src/core/scope.h b/src/core/scope.h index 4452fe2c94..f838ee5357 100644 --- a/src/core/scope.h +++ b/src/core/scope.h @@ -25,17 +25,6 @@ typedef struct Scope Scope; #include "kill.h" -typedef enum ScopeState { - SCOPE_DEAD, - SCOPE_RUNNING, - SCOPE_ABANDONED, - SCOPE_STOP_SIGTERM, - SCOPE_STOP_SIGKILL, - SCOPE_FAILED, - _SCOPE_STATE_MAX, - _SCOPE_STATE_INVALID = -1 -} ScopeState; - typedef enum ScopeResult { SCOPE_SUCCESS, SCOPE_FAILURE_RESOURCES, @@ -64,8 +53,5 @@ extern const UnitVTable scope_vtable; int scope_abandon(Scope *s); -const char* scope_state_to_string(ScopeState i) _const_; -ScopeState scope_state_from_string(const char *s) _pure_; - const char* scope_result_to_string(ScopeResult i) _const_; ScopeResult scope_result_from_string(const char *s) _pure_; diff --git a/src/core/selinux-setup.c b/src/core/selinux-setup.c index e5b457643b..ff1ea23528 100644 --- a/src/core/selinux-setup.c +++ b/src/core/selinux-setup.c @@ -78,14 +78,14 @@ int mac_selinux_setup(bool *loaded_policy) { before_load = now(CLOCK_MONOTONIC); r = selinux_init_load_policy(&enforce); if (r == 0) { + _cleanup_(mac_selinux_freep) char *label = NULL; char timespan[FORMAT_TIMESPAN_MAX]; - char *label; mac_selinux_retest(); /* Transition to the new context */ r = mac_selinux_get_create_label_from_exe(SYSTEMD_BINARY_PATH, &label); - if (r < 0 || label == NULL) { + if (r < 0 || !label) { log_open(); log_error("Failed to compute init label, ignoring."); } else { @@ -94,8 +94,6 @@ int mac_selinux_setup(bool *loaded_policy) { log_open(); if (r < 0) log_error("Failed to transition into init label '%s', ignoring.", label); - - mac_selinux_free(label); } after_load = now(CLOCK_MONOTONIC); diff --git a/src/core/service.c b/src/core/service.c index f7de5e89ff..1e4f707bf4 100644 --- a/src/core/service.c +++ b/src/core/service.c @@ -108,6 +108,7 @@ static void service_init(Unit *u) { s->type = _SERVICE_TYPE_INVALID; s->socket_fd = -1; s->bus_endpoint_fd = -1; + s->stdin_fd = s->stdout_fd = s->stderr_fd = -1; s->guess_main_pid = true; RATELIMIT_INIT(s->start_limit, u->manager->default_start_limit_interval, u->manager->default_start_limit_burst); @@ -261,6 +262,7 @@ static void service_fd_store_unlink(ServiceFDStore *fs) { sd_event_source_unref(fs->event_source); } + free(fs->fdname); safe_close(fs->fd); free(fs); } @@ -270,11 +272,15 @@ static void service_release_resources(Unit *u) { assert(s); - if (!s->fd_store) + if (!s->fd_store && s->stdin_fd < 0 && s->stdout_fd < 0 && s->stderr_fd < 0) return; log_unit_debug(u, "Releasing all resources."); + s->stdin_fd = safe_close(s->stdin_fd); + s->stdout_fd = safe_close(s->stdout_fd); + s->stderr_fd = safe_close(s->stderr_fd); + while (s->fd_store) service_fd_store_unlink(s->fd_store); @@ -334,7 +340,7 @@ static int on_fd_store_io(sd_event_source *e, int fd, uint32_t revents, void *us return 0; } -static int service_add_fd_store(Service *s, int fd) { +static int service_add_fd_store(Service *s, int fd, const char *name) { ServiceFDStore *fs; int r; @@ -361,9 +367,15 @@ static int service_add_fd_store(Service *s, int fd) { fs->fd = fd; fs->service = s; + fs->fdname = strdup(name ?: "stored"); + if (!fs->fdname) { + free(fs); + return -ENOMEM; + } r = sd_event_add_io(UNIT(s)->manager->event, &fs->event_source, fd, 0, on_fd_store_io, fs); if (r < 0) { + free(fs->fdname); free(fs); return r; } @@ -376,7 +388,7 @@ static int service_add_fd_store(Service *s, int fd) { return 1; } -static int service_add_fd_store_set(Service *s, FDSet *fds) { +static int service_add_fd_store_set(Service *s, FDSet *fds, const char *name) { int r; assert(s); @@ -391,7 +403,7 @@ static int service_add_fd_store_set(Service *s, FDSet *fds) { if (fd < 0) break; - r = service_add_fd_store(s, fd); + r = service_add_fd_store(s, fd, name); if (r < 0) return log_unit_error_errno(UNIT(s), r, "Couldn't add fd to fd store: %m"); if (r > 0) { @@ -884,7 +896,6 @@ static void service_set_state(Service *s, ServiceState state) { log_unit_debug(UNIT(s), "Changed %s -> %s", service_state_to_string(old_state), service_state_to_string(state)); unit_notify(UNIT(s), table[old_state], table[state], s->reload_result == SERVICE_SUCCESS); - s->reload_result = SERVICE_SUCCESS; } static int service_coldplug(Unit *u) { @@ -957,62 +968,79 @@ static int service_coldplug(Unit *u) { return 0; } -static int service_collect_fds(Service *s, int **fds, unsigned *n_fds) { +static int service_collect_fds(Service *s, int **fds, char ***fd_names) { + _cleanup_strv_free_ char **rfd_names = NULL; _cleanup_free_ int *rfds = NULL; - unsigned rn_fds = 0; - Iterator i; - int r; - Unit *u; + int rn_fds = 0, r; assert(s); assert(fds); - assert(n_fds); + assert(fd_names); - if (s->socket_fd >= 0) - return 0; + if (s->socket_fd >= 0) { - SET_FOREACH(u, UNIT(s)->dependencies[UNIT_TRIGGERED_BY], i) { - int *cfds; - unsigned cn_fds; - Socket *sock; + /* Pass the per-connection socket */ - if (u->type != UNIT_SOCKET) - continue; + rfds = new(int, 1); + if (!rfds) + return -ENOMEM; + rfds[0] = s->socket_fd; - sock = SOCKET(u); + rfd_names = strv_new("connection", NULL); + if (!rfd_names) + return -ENOMEM; - r = socket_collect_fds(sock, &cfds, &cn_fds); - if (r < 0) - return r; + rn_fds = 1; + } else { + Iterator i; + Unit *u; - if (cn_fds <= 0) { - free(cfds); - continue; - } + /* Pass all our configured sockets for singleton services */ - if (!rfds) { - rfds = cfds; - rn_fds = cn_fds; - } else { - int *t; + SET_FOREACH(u, UNIT(s)->dependencies[UNIT_TRIGGERED_BY], i) { + _cleanup_free_ int *cfds = NULL; + Socket *sock; + int cn_fds; - t = realloc(rfds, (rn_fds + cn_fds) * sizeof(int)); - if (!t) { - free(cfds); - return -ENOMEM; - } + if (u->type != UNIT_SOCKET) + continue; + + sock = SOCKET(u); - memcpy(t + rn_fds, cfds, cn_fds * sizeof(int)); - rfds = t; - rn_fds += cn_fds; + cn_fds = socket_collect_fds(sock, &cfds); + if (cn_fds < 0) + return cn_fds; - free(cfds); + if (cn_fds <= 0) + continue; + + if (!rfds) { + rfds = cfds; + rn_fds = cn_fds; + + cfds = NULL; + } else { + int *t; + + t = realloc(rfds, (rn_fds + cn_fds) * sizeof(int)); + if (!t) + return -ENOMEM; + + memcpy(t + rn_fds, cfds, cn_fds * sizeof(int)); + + rfds = t; + rn_fds += cn_fds; + } + r = strv_extend_n(&rfd_names, socket_fdname(sock), cn_fds); + if (r < 0) + return r; } } if (s->n_fd_store > 0) { ServiceFDStore *fs; + char **nl; int *t; t = realloc(rfds, (rn_fds + s->n_fd_store) * sizeof(int)); @@ -1020,15 +1048,32 @@ static int service_collect_fds(Service *s, int **fds, unsigned *n_fds) { return -ENOMEM; rfds = t; - LIST_FOREACH(fd_store, fs, s->fd_store) - rfds[rn_fds++] = fs->fd; + + nl = realloc(rfd_names, (rn_fds + s->n_fd_store + 1) * sizeof(char*)); + if (!nl) + return -ENOMEM; + + rfd_names = nl; + + LIST_FOREACH(fd_store, fs, s->fd_store) { + rfds[rn_fds] = fs->fd; + rfd_names[rn_fds] = strdup(strempty(fs->fdname)); + if (!rfd_names[rn_fds]) + return -ENOMEM; + + rn_fds++; + } + + rfd_names[rn_fds] = NULL; } *fds = rfds; - *n_fds = rn_fds; + *fd_names = rfd_names; rfds = NULL; - return 0; + rfd_names = NULL; + + return rn_fds; } static int service_spawn( @@ -1042,23 +1087,25 @@ static int service_spawn( bool is_control, pid_t *_pid) { - pid_t pid; - int r; - int *fds = NULL; - _cleanup_free_ int *fdsbuf = NULL; - unsigned n_fds = 0, n_env = 0; + _cleanup_strv_free_ char **argv = NULL, **final_env = NULL, **our_env = NULL, **fd_names = NULL; _cleanup_free_ char *bus_endpoint_path = NULL; - _cleanup_strv_free_ char - **argv = NULL, **final_env = NULL, **our_env = NULL; + _cleanup_free_ int *fds = NULL; + unsigned n_fds = 0, n_env = 0; const char *path; + pid_t pid; + ExecParameters exec_params = { - .apply_permissions = apply_permissions, - .apply_chroot = apply_chroot, - .apply_tty_stdin = apply_tty_stdin, - .bus_endpoint_fd = -1, - .selinux_context_net = s->socket_fd_selinux_context_net + .apply_permissions = apply_permissions, + .apply_chroot = apply_chroot, + .apply_tty_stdin = apply_tty_stdin, + .bus_endpoint_fd = -1, + .stdin_fd = -1, + .stdout_fd = -1, + .stderr_fd = -1, }; + int r; + assert(s); assert(c); assert(_pid); @@ -1078,16 +1125,11 @@ static int service_spawn( s->exec_context.std_output == EXEC_OUTPUT_SOCKET || s->exec_context.std_error == EXEC_OUTPUT_SOCKET) { - if (s->socket_fd >= 0) { - fds = &s->socket_fd; - n_fds = 1; - } else { - r = service_collect_fds(s, &fdsbuf, &n_fds); - if (r < 0) - goto fail; + r = service_collect_fds(s, &fds, &fd_names); + if (r < 0) + goto fail; - fds = fdsbuf; - } + n_fds = r; } if (timeout > 0) { @@ -1125,7 +1167,7 @@ static int service_spawn( goto fail; } - if (UNIT_DEREF(s->accept_socket)) { + if (s->socket_fd >= 0) { union sockaddr_union sa; socklen_t salen = sizeof(sa); @@ -1191,6 +1233,7 @@ static int service_spawn( exec_params.argv = argv; exec_params.fds = fds; + exec_params.fd_names = fd_names; exec_params.n_fds = n_fds; exec_params.environment = final_env; exec_params.confirm_spawn = UNIT(s)->manager->confirm_spawn; @@ -1200,8 +1243,12 @@ static int service_spawn( exec_params.runtime_prefix = manager_get_runtime_prefix(UNIT(s)->manager); exec_params.watchdog_usec = s->watchdog_usec; exec_params.bus_endpoint_path = bus_endpoint_path; + exec_params.selinux_context_net = s->socket_fd_selinux_context_net; if (s->type == SERVICE_IDLE) exec_params.idle_pipe = UNIT(s)->manager->idle_pipe; + exec_params.stdin_fd = s->stdin_fd; + exec_params.stdout_fd = s->stdout_fd; + exec_params.stderr_fd = s->stderr_fd; r = exec_spawn(UNIT(s), c, @@ -1778,6 +1825,7 @@ static void service_enter_reload(Service *s) { assert(s); service_unwatch_control_pid(s); + s->reload_result = SERVICE_SUCCESS; s->control_command = s->exec_command[SERVICE_EXEC_RELOAD]; if (s->control_command) { @@ -2001,6 +2049,7 @@ _pure_ static bool service_can_reload(Unit *u) { static int service_serialize(Unit *u, FILE *f, FDSet *fds) { Service *s = SERVICE(u); ServiceFDStore *fs; + int r; assert(u); assert(f); @@ -2019,12 +2068,9 @@ static int service_serialize(Unit *u, FILE *f, FDSet *fds) { unit_serialize_item(u, f, "main-pid-known", yes_no(s->main_pid_known)); unit_serialize_item(u, f, "bus-name-good", yes_no(s->bus_name_good)); - if (s->status_text) { - _cleanup_free_ char *c = NULL; - - c = cescape(s->status_text); - unit_serialize_item(u, f, "status-text", strempty(c)); - } + r = unit_serialize_item_escaped(u, f, "status-text", s->status_text); + if (r < 0) + return r; /* FIXME: There's a minor uncleanliness here: if there are * multiple commands attached here, we will start from the @@ -2032,34 +2078,34 @@ static int service_serialize(Unit *u, FILE *f, FDSet *fds) { if (s->control_command_id >= 0) unit_serialize_item(u, f, "control-command", service_exec_command_to_string(s->control_command_id)); - if (s->socket_fd >= 0) { - int copy; - - copy = fdset_put_dup(fds, s->socket_fd); - if (copy < 0) - return copy; - - unit_serialize_item_format(u, f, "socket-fd", "%i", copy); - } - - if (s->bus_endpoint_fd >= 0) { - int copy; - - copy = fdset_put_dup(fds, s->bus_endpoint_fd); - if (copy < 0) - return copy; + r = unit_serialize_item_fd(u, f, fds, "stdin-fd", s->stdin_fd); + if (r < 0) + return r; + r = unit_serialize_item_fd(u, f, fds, "stdout-fd", s->stdout_fd); + if (r < 0) + return r; + r = unit_serialize_item_fd(u, f, fds, "stderr-fd", s->stderr_fd); + if (r < 0) + return r; - unit_serialize_item_format(u, f, "endpoint-fd", "%i", copy); - } + r = unit_serialize_item_fd(u, f, fds, "socket-fd", s->socket_fd); + if (r < 0) + return r; + r = unit_serialize_item_fd(u, f, fds, "endpoint-fd", s->bus_endpoint_fd); + if (r < 0) + return r; LIST_FOREACH(fd_store, fs, s->fd_store) { + _cleanup_free_ char *c = NULL; int copy; copy = fdset_put_dup(fds, fs->fd); if (copy < 0) return copy; - unit_serialize_item_format(u, f, "fd-store-fd", "%i", copy); + c = cescape(fs->fdname); + + unit_serialize_item_format(u, f, "fd-store-fd", "%i %s", copy, strempty(c)); } if (s->main_exec_status.pid > 0) { @@ -2076,8 +2122,7 @@ static int service_serialize(Unit *u, FILE *f, FDSet *fds) { if (dual_timestamp_is_set(&s->watchdog_timestamp)) dual_timestamp_serialize(f, "watchdog-timestamp", &s->watchdog_timestamp); - if (s->forbid_restart) - unit_serialize_item(u, f, "forbid-restart", yes_no(s->forbid_restart)); + unit_serialize_item(u, f, "forbid-restart", yes_no(s->forbid_restart)); return 0; } @@ -2189,12 +2234,24 @@ static int service_deserialize_item(Unit *u, const char *key, const char *value, s->bus_endpoint_fd = fdset_remove(fds, fd); } } else if (streq(key, "fd-store-fd")) { + const char *fdv; + size_t pf; int fd; - if (safe_atoi(value, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd)) + pf = strcspn(value, WHITESPACE); + fdv = strndupa(value, pf); + + if (safe_atoi(fdv, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd)) log_unit_debug(u, "Failed to parse fd-store-fd value: %s", value); else { - r = service_add_fd_store(s, fd); + _cleanup_free_ char *t = NULL; + const char *fdn; + + fdn = value + pf; + fdn += strspn(fdn, WHITESPACE); + (void) cunescape(fdn, 0, &t); + + r = service_add_fd_store(s, fd, t); if (r < 0) log_unit_error_errno(u, r, "Failed to add fd to store: %m"); else if (r > 0) @@ -2236,6 +2293,33 @@ static int service_deserialize_item(Unit *u, const char *key, const char *value, log_unit_debug(u, "Failed to parse forbid-restart value: %s", value); else s->forbid_restart = b; + } else if (streq(key, "stdin-fd")) { + int fd; + + if (safe_atoi(value, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd)) + log_unit_debug(u, "Failed to parse stdin-fd value: %s", value); + else { + asynchronous_close(s->stdin_fd); + s->stdin_fd = fdset_remove(fds, fd); + } + } else if (streq(key, "stdout-fd")) { + int fd; + + if (safe_atoi(value, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd)) + log_unit_debug(u, "Failed to parse stdout-fd value: %s", value); + else { + asynchronous_close(s->stdout_fd); + s->stdout_fd = fdset_remove(fds, fd); + } + } else if (streq(key, "stderr-fd")) { + int fd; + + if (safe_atoi(value, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd)) + log_unit_debug(u, "Failed to parse stderr-fd value: %s", value); + else { + asynchronous_close(s->stderr_fd); + s->stderr_fd = fdset_remove(fds, fd); + } } else log_unit_debug(u, "Unknown serialization key: %s", key); @@ -2948,8 +3032,17 @@ static void service_notify_message(Unit *u, pid_t pid, char **tags, FDSet *fds) if (strv_find(tags, "WATCHDOG=1")) service_reset_watchdog(s); - if (strv_find(tags, "FDSTORE=1")) - service_add_fd_store_set(s, fds); + if (strv_find(tags, "FDSTORE=1")) { + const char *name; + + name = strv_find_startswith(tags, "FDNAME="); + if (name && !fdname_is_valid(name)) { + log_unit_warning(u, "Passed FDNAME= name is invalid, ignoring."); + name = NULL; + } + + service_add_fd_store_set(s, fds, name); + } /* Notify clients about changed status or main pid */ if (notify_dbus) @@ -3092,27 +3185,6 @@ static int service_kill(Unit *u, KillWho who, int signo, sd_bus_error *error) { return unit_kill_common(u, who, signo, s->main_pid, s->control_pid, error); } -static const char* const service_state_table[_SERVICE_STATE_MAX] = { - [SERVICE_DEAD] = "dead", - [SERVICE_START_PRE] = "start-pre", - [SERVICE_START] = "start", - [SERVICE_START_POST] = "start-post", - [SERVICE_RUNNING] = "running", - [SERVICE_EXITED] = "exited", - [SERVICE_RELOAD] = "reload", - [SERVICE_STOP] = "stop", - [SERVICE_STOP_SIGABRT] = "stop-sigabrt", - [SERVICE_STOP_SIGTERM] = "stop-sigterm", - [SERVICE_STOP_SIGKILL] = "stop-sigkill", - [SERVICE_STOP_POST] = "stop-post", - [SERVICE_FINAL_SIGTERM] = "final-sigterm", - [SERVICE_FINAL_SIGKILL] = "final-sigkill", - [SERVICE_FAILED] = "failed", - [SERVICE_AUTO_RESTART] = "auto-restart", -}; - -DEFINE_STRING_TABLE_LOOKUP(service_state, ServiceState); - static const char* const service_restart_table[_SERVICE_RESTART_MAX] = { [SERVICE_RESTART_NO] = "no", [SERVICE_RESTART_ON_SUCCESS] = "on-success", diff --git a/src/core/service.h b/src/core/service.h index 789dff23a9..e765668247 100644 --- a/src/core/service.h +++ b/src/core/service.h @@ -29,27 +29,6 @@ typedef struct ServiceFDStore ServiceFDStore; #include "kill.h" #include "exit-status.h" -typedef enum ServiceState { - SERVICE_DEAD, - SERVICE_START_PRE, - SERVICE_START, - SERVICE_START_POST, - SERVICE_RUNNING, - SERVICE_EXITED, /* Nothing is running anymore, but RemainAfterExit is true hence this is OK */ - SERVICE_RELOAD, - SERVICE_STOP, /* No STOP_PRE state, instead just register multiple STOP executables */ - SERVICE_STOP_SIGABRT, /* Watchdog timeout */ - SERVICE_STOP_SIGTERM, - SERVICE_STOP_SIGKILL, - SERVICE_STOP_POST, - SERVICE_FINAL_SIGTERM, /* In case the STOP_POST executable hangs, we shoot that down, too */ - SERVICE_FINAL_SIGKILL, - SERVICE_FAILED, - SERVICE_AUTO_RESTART, - _SERVICE_STATE_MAX, - _SERVICE_STATE_INVALID = -1 -} ServiceState; - typedef enum ServiceRestart { SERVICE_RESTART_NO, SERVICE_RESTART_ON_SUCCESS, @@ -118,6 +97,7 @@ struct ServiceFDStore { Service *service; int fd; + char *fdname; sd_event_source *event_source; LIST_FIELDS(ServiceFDStore, fd_store); @@ -215,15 +195,16 @@ struct Service { char *usb_function_descriptors; char *usb_function_strings; + + int stdin_fd; + int stdout_fd; + int stderr_fd; }; extern const UnitVTable service_vtable; int service_set_socket_fd(Service *s, int fd, struct Socket *socket, bool selinux_context_net); -const char* service_state_to_string(ServiceState i) _const_; -ServiceState service_state_from_string(const char *s) _pure_; - const char* service_restart_to_string(ServiceRestart i) _const_; ServiceRestart service_restart_from_string(const char *s) _pure_; diff --git a/src/core/shutdown.c b/src/core/shutdown.c index 5296efce1d..27c581d9c1 100644 --- a/src/core/shutdown.c +++ b/src/core/shutdown.c @@ -430,6 +430,5 @@ int main(int argc, char *argv[]) { error: log_emergency_errno(r, "Critical error while doing system shutdown: %m"); - freeze(); } diff --git a/src/core/slice.c b/src/core/slice.c index b414462066..063024134a 100644 --- a/src/core/slice.c +++ b/src/core/slice.c @@ -287,13 +287,6 @@ static int slice_enumerate(Manager *m) { return 0; } -static const char* const slice_state_table[_SLICE_STATE_MAX] = { - [SLICE_DEAD] = "dead", - [SLICE_ACTIVE] = "active" -}; - -DEFINE_STRING_TABLE_LOOKUP(slice_state, SliceState); - const UnitVTable slice_vtable = { .object_size = sizeof(Slice), .cgroup_context_offset = offsetof(Slice, cgroup_context), diff --git a/src/core/slice.h b/src/core/slice.h index ac648e56f8..0c356651e3 100644 --- a/src/core/slice.h +++ b/src/core/slice.h @@ -23,14 +23,6 @@ typedef struct Slice Slice; - -typedef enum SliceState { - SLICE_DEAD, - SLICE_ACTIVE, - _SLICE_STATE_MAX, - _SLICE_STATE_INVALID = -1 -} SliceState; - struct Slice { Unit meta; @@ -40,6 +32,3 @@ struct Slice { }; extern const UnitVTable slice_vtable; - -const char* slice_state_to_string(SliceState i) _const_; -SliceState slice_state_from_string(const char *s) _pure_; diff --git a/src/core/smack-setup.c b/src/core/smack-setup.c index cbe7d0b4a9..761582c7a2 100644 --- a/src/core/smack-setup.c +++ b/src/core/smack-setup.c @@ -215,16 +215,14 @@ int mac_smack_setup(bool *loaded_policy) { log_info("Successfully loaded Smack policies."); break; default: - log_warning("Failed to load Smack access rules: %s, ignoring.", - strerror(abs(r))); + log_warning_errno(r, "Failed to load Smack access rules, ignoring: %m"); return 0; } #ifdef SMACK_RUN_LABEL r = write_string_file("/proc/self/attr/current", SMACK_RUN_LABEL, 0); if (r) - log_warning("Failed to set SMACK label \"%s\" on self: %s", - SMACK_RUN_LABEL, strerror(-r)); + log_warning_errno(r, "Failed to set SMACK label \"%s\" on self: %m", SMACK_RUN_LABEL); #endif r = write_cipso2_rules("/etc/smack/cipso.d/"); @@ -239,8 +237,7 @@ int mac_smack_setup(bool *loaded_policy) { log_info("Successfully loaded Smack/CIPSO policies."); break; default: - log_warning("Failed to load Smack/CIPSO access rules: %s, ignoring.", - strerror(abs(r))); + log_warning_errno(r, "Failed to load Smack/CIPSO access rules, ignoring: %m"); return 0; } diff --git a/src/core/snapshot.c b/src/core/snapshot.c index 336ff20f84..867f3765e7 100644 --- a/src/core/snapshot.c +++ b/src/core/snapshot.c @@ -272,13 +272,6 @@ void snapshot_remove(Snapshot *s) { unit_add_to_cleanup_queue(UNIT(s)); } -static const char* const snapshot_state_table[_SNAPSHOT_STATE_MAX] = { - [SNAPSHOT_DEAD] = "dead", - [SNAPSHOT_ACTIVE] = "active" -}; - -DEFINE_STRING_TABLE_LOOKUP(snapshot_state, SnapshotState); - const UnitVTable snapshot_vtable = { .object_size = sizeof(Snapshot), diff --git a/src/core/snapshot.h b/src/core/snapshot.h index f2451b1193..97747e18bd 100644 --- a/src/core/snapshot.h +++ b/src/core/snapshot.h @@ -23,14 +23,6 @@ typedef struct Snapshot Snapshot; - -typedef enum SnapshotState { - SNAPSHOT_DEAD, - SNAPSHOT_ACTIVE, - _SNAPSHOT_STATE_MAX, - _SNAPSHOT_STATE_INVALID = -1 -} SnapshotState; - struct Snapshot { Unit meta; @@ -43,6 +35,3 @@ extern const UnitVTable snapshot_vtable; int snapshot_create(Manager *m, const char *name, bool cleanup, sd_bus_error *e, Snapshot **s); void snapshot_remove(Snapshot *s); - -const char* snapshot_state_to_string(SnapshotState i) _const_; -SnapshotState snapshot_state_from_string(const char *s) _pure_; diff --git a/src/core/socket.c b/src/core/socket.c index 54e94c4f74..e42ed62ef1 100644 --- a/src/core/socket.c +++ b/src/core/socket.c @@ -19,38 +19,39 @@ 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 "bus-error.h" +#include "bus-util.h" +#include "copy.h" +#include "dbus-socket.h" +#include "def.h" +#include "exit-status.h" +#include "formats-util.h" +#include "label.h" #include "log.h" -#include "strv.h" +#include "missing.h" #include "mkdir.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 "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 "strv.h" +#include "unit-name.h" +#include "unit-printf.h" +#include "unit.h" static const UnitActiveState state_translation_table[_SOCKET_STATE_MAX] = { [SOCKET_DEAD] = UNIT_INACTIVE, @@ -506,6 +507,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 +525,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 +647,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 +961,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 +1019,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 +1075,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 +1108,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 +1145,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 +1153,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; - r = scandir(path, &ent, select_ep, alphasort); + r = scandir(path, &ent, usbffs_select_ep, alphasort); if (r < 0) return -errno; @@ -1216,10 +1192,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 +1205,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 +1213,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 +1225,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 +1278,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; } @@ -1519,6 +1505,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 +2633,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 +2765,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", diff --git a/src/core/socket.h b/src/core/socket.h index 286397b41c..94cda8a90d 100644 --- a/src/core/socket.h +++ b/src/core/socket.h @@ -27,24 +27,6 @@ typedef struct Socket Socket; #include "mount.h" #include "service.h" -typedef enum SocketState { - SOCKET_DEAD, - SOCKET_START_PRE, - SOCKET_START_CHOWN, - SOCKET_START_POST, - SOCKET_LISTENING, - SOCKET_RUNNING, - SOCKET_STOP_PRE, - SOCKET_STOP_PRE_SIGTERM, - SOCKET_STOP_PRE_SIGKILL, - SOCKET_STOP_POST, - SOCKET_FINAL_SIGTERM, - SOCKET_FINAL_SIGKILL, - SOCKET_FAILED, - _SOCKET_STATE_MAX, - _SOCKET_STATE_INVALID = -1 -} SocketState; - typedef enum SocketExecCommand { SOCKET_EXEC_START_PRE, SOCKET_EXEC_START_CHOWN, @@ -136,6 +118,7 @@ struct Socket { bool accept; bool remove_on_stop; + bool writable; /* Socket options */ bool keep_alive; @@ -171,20 +154,23 @@ struct Socket { char *user, *group; bool reset_cpu_usage:1; + + char *fdname; }; /* Called from the service code when collecting fds */ -int socket_collect_fds(Socket *s, int **fds, unsigned *n_fds); +int socket_collect_fds(Socket *s, int **fds); /* Called from the service code when a per-connection service ended */ void socket_connection_unref(Socket *s); void socket_free_ports(Socket *s); -extern const UnitVTable socket_vtable; +int socket_instantiate_service(Socket *s); -const char* socket_state_to_string(SocketState i) _const_; -SocketState socket_state_from_string(const char *s) _pure_; +char *socket_fdname(Socket *s); + +extern const UnitVTable socket_vtable; const char* socket_exec_command_to_string(SocketExecCommand i) _const_; SocketExecCommand socket_exec_command_from_string(const char *s) _pure_; @@ -193,5 +179,3 @@ const char* socket_result_to_string(SocketResult i) _const_; SocketResult socket_result_from_string(const char *s) _pure_; const char* socket_port_type_to_string(SocketPort *p) _pure_; - -int socket_instantiate_service(Socket *s); diff --git a/src/core/swap.c b/src/core/swap.c index bef457069f..f42d151075 100644 --- a/src/core/swap.c +++ b/src/core/swap.c @@ -597,6 +597,9 @@ static int swap_spawn(Swap *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); @@ -1398,21 +1401,6 @@ static bool swap_supported(void) { return supported; } -static const char* const swap_state_table[_SWAP_STATE_MAX] = { - [SWAP_DEAD] = "dead", - [SWAP_ACTIVATING] = "activating", - [SWAP_ACTIVATING_DONE] = "activating-done", - [SWAP_ACTIVE] = "active", - [SWAP_DEACTIVATING] = "deactivating", - [SWAP_ACTIVATING_SIGTERM] = "activating-sigterm", - [SWAP_ACTIVATING_SIGKILL] = "activating-sigkill", - [SWAP_DEACTIVATING_SIGTERM] = "deactivating-sigterm", - [SWAP_DEACTIVATING_SIGKILL] = "deactivating-sigkill", - [SWAP_FAILED] = "failed" -}; - -DEFINE_STRING_TABLE_LOOKUP(swap_state, SwapState); - static const char* const swap_exec_command_table[_SWAP_EXEC_COMMAND_MAX] = { [SWAP_EXEC_ACTIVATE] = "ExecActivate", [SWAP_EXEC_DEACTIVATE] = "ExecDeactivate", diff --git a/src/core/swap.h b/src/core/swap.h index 9136b9abab..7f29603c32 100644 --- a/src/core/swap.h +++ b/src/core/swap.h @@ -26,22 +26,6 @@ typedef struct Swap Swap; - -typedef enum SwapState { - SWAP_DEAD, - SWAP_ACTIVATING, /* /sbin/swapon is running, but the swap not yet enabled. */ - SWAP_ACTIVATING_DONE, /* /sbin/swapon is running, and the swap is done. */ - SWAP_ACTIVE, - SWAP_DEACTIVATING, - SWAP_ACTIVATING_SIGTERM, - SWAP_ACTIVATING_SIGKILL, - SWAP_DEACTIVATING_SIGTERM, - SWAP_DEACTIVATING_SIGKILL, - SWAP_FAILED, - _SWAP_STATE_MAX, - _SWAP_STATE_INVALID = -1 -} SwapState; - typedef enum SwapExecCommand { SWAP_EXEC_ACTIVATE, SWAP_EXEC_DEACTIVATE, @@ -120,9 +104,6 @@ extern const UnitVTable swap_vtable; int swap_process_device_new(Manager *m, struct udev_device *dev); int swap_process_device_remove(Manager *m, struct udev_device *dev); -const char* swap_state_to_string(SwapState i) _const_; -SwapState swap_state_from_string(const char *s) _pure_; - const char* swap_exec_command_to_string(SwapExecCommand i) _const_; SwapExecCommand swap_exec_command_from_string(const char *s) _pure_; diff --git a/src/core/system.conf b/src/core/system.conf index 231609033b..50668e12c4 100644 --- a/src/core/system.conf +++ b/src/core/system.conf @@ -17,9 +17,10 @@ #LogColor=yes #LogLocation=no #DumpCore=yes -#CrashShell=no #ShowStatus=yes -#CrashChVT=1 +#CrashChangeVT=no +#CrashShell=no +#CrashReboot=no #CPUAffinity=1 2 #JoinControllers=cpu,cpuacct net_cls,net_prio #RuntimeWatchdogSec=0 @@ -39,6 +40,7 @@ #DefaultCPUAccounting=no #DefaultBlockIOAccounting=no #DefaultMemoryAccounting=no +#DefaultTasksAccounting=no #DefaultLimitCPU= #DefaultLimitFSIZE= #DefaultLimitDATA= diff --git a/src/core/target.c b/src/core/target.c index f714cb31c2..a905a1adf6 100644 --- a/src/core/target.c +++ b/src/core/target.c @@ -192,13 +192,6 @@ _pure_ static const char *target_sub_state_to_string(Unit *u) { return target_state_to_string(TARGET(u)->state); } -static const char* const target_state_table[_TARGET_STATE_MAX] = { - [TARGET_DEAD] = "dead", - [TARGET_ACTIVE] = "active" -}; - -DEFINE_STRING_TABLE_LOOKUP(target_state, TargetState); - const UnitVTable target_vtable = { .object_size = sizeof(Target), diff --git a/src/core/target.h b/src/core/target.h index 0a25ef469a..3cc6c07bfa 100644 --- a/src/core/target.h +++ b/src/core/target.h @@ -23,14 +23,6 @@ typedef struct Target Target; - -typedef enum TargetState { - TARGET_DEAD, - TARGET_ACTIVE, - _TARGET_STATE_MAX, - _TARGET_STATE_INVALID = -1 -} TargetState; - struct Target { Unit meta; @@ -38,6 +30,3 @@ struct Target { }; extern const UnitVTable target_vtable; - -const char* target_state_to_string(TargetState i) _const_; -TargetState target_state_from_string(const char *s) _pure_; diff --git a/src/core/timer.c b/src/core/timer.c index eb6567bbfa..800e58261c 100644 --- a/src/core/timer.c +++ b/src/core/timer.c @@ -713,16 +713,6 @@ static void timer_time_change(Unit *u) { timer_enter_waiting(t, false); } -static const char* const timer_state_table[_TIMER_STATE_MAX] = { - [TIMER_DEAD] = "dead", - [TIMER_WAITING] = "waiting", - [TIMER_RUNNING] = "running", - [TIMER_ELAPSED] = "elapsed", - [TIMER_FAILED] = "failed" -}; - -DEFINE_STRING_TABLE_LOOKUP(timer_state, TimerState); - static const char* const timer_base_table[_TIMER_BASE_MAX] = { [TIMER_ACTIVE] = "OnActiveSec", [TIMER_BOOT] = "OnBootSec", diff --git a/src/core/timer.h b/src/core/timer.h index 9d919e4d3e..ac5af6a93c 100644 --- a/src/core/timer.h +++ b/src/core/timer.h @@ -25,16 +25,6 @@ typedef struct Timer Timer; #include "calendarspec.h" -typedef enum TimerState { - TIMER_DEAD, - TIMER_WAITING, - TIMER_RUNNING, - TIMER_ELAPSED, - TIMER_FAILED, - _TIMER_STATE_MAX, - _TIMER_STATE_INVALID = -1 -} TimerState; - typedef enum TimerBase { TIMER_ACTIVE, TIMER_BOOT, @@ -91,9 +81,6 @@ void timer_free_values(Timer *t); extern const UnitVTable timer_vtable; -const char *timer_state_to_string(TimerState i) _const_; -TimerState timer_state_from_string(const char *s) _pure_; - const char *timer_base_to_string(TimerBase i) _const_; TimerBase timer_base_from_string(const char *s) _pure_; diff --git a/src/core/unit.c b/src/core/unit.c index 1227399e16..39cd89f1e3 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -1129,12 +1129,12 @@ static int unit_add_slice_dependencies(Unit *u) { return 0; if (UNIT_ISSET(u->slice)) - return unit_add_two_dependencies(u, UNIT_AFTER, UNIT_WANTS, UNIT_DEREF(u->slice), true); + return unit_add_two_dependencies(u, UNIT_AFTER, UNIT_REQUIRES, UNIT_DEREF(u->slice), true); - if (streq(u->id, SPECIAL_ROOT_SLICE)) + if (unit_has_name(u, SPECIAL_ROOT_SLICE)) return 0; - return unit_add_two_dependencies_by_name(u, UNIT_AFTER, UNIT_WANTS, SPECIAL_ROOT_SLICE, NULL, true); + return unit_add_two_dependencies_by_name(u, UNIT_AFTER, UNIT_REQUIRES, SPECIAL_ROOT_SLICE, NULL, true); } static int unit_add_mount_dependencies(Unit *u) { @@ -2634,6 +2634,62 @@ int unit_serialize(Unit *u, FILE *f, FDSet *fds, bool serialize_jobs) { return 0; } +int unit_serialize_item(Unit *u, FILE *f, const char *key, const char *value) { + assert(u); + assert(f); + assert(key); + + if (!value) + return 0; + + fputs(key, f); + fputc('=', f); + fputs(value, f); + fputc('\n', f); + + return 1; +} + +int unit_serialize_item_escaped(Unit *u, FILE *f, const char *key, const char *value) { + _cleanup_free_ char *c = NULL; + + assert(u); + assert(f); + assert(key); + + if (!value) + return 0; + + c = cescape(value); + if (!c) + return -ENOMEM; + + fputs(key, f); + fputc('=', f); + fputs(c, f); + fputc('\n', f); + + return 1; +} + +int unit_serialize_item_fd(Unit *u, FILE *f, FDSet *fds, const char *key, int fd) { + int copy; + + assert(u); + assert(f); + assert(key); + + if (fd < 0) + return 0; + + copy = fdset_put_dup(fds, fd); + if (copy < 0) + return copy; + + fprintf(f, "%s=%i\n", key, copy); + return 1; +} + void unit_serialize_item_format(Unit *u, FILE *f, const char *key, const char *format, ...) { va_list ap; @@ -2652,15 +2708,6 @@ void unit_serialize_item_format(Unit *u, FILE *f, const char *key, const char *f fputc('\n', f); } -void unit_serialize_item(Unit *u, FILE *f, const char *key, const char *value) { - assert(u); - assert(f); - assert(key); - assert(value); - - fprintf(f, "%s=%s\n", key, value); -} - int unit_deserialize(Unit *u, FILE *f, FDSet *fds) { ExecRuntime **rt = NULL; size_t offset; @@ -3739,14 +3786,3 @@ int unit_fail_if_symlink(Unit *u, const char* where) { return -ELOOP; } - -static const char* const unit_active_state_table[_UNIT_ACTIVE_STATE_MAX] = { - [UNIT_ACTIVE] = "active", - [UNIT_RELOADING] = "reloading", - [UNIT_INACTIVE] = "inactive", - [UNIT_FAILED] = "failed", - [UNIT_ACTIVATING] = "activating", - [UNIT_DEACTIVATING] = "deactivating" -}; - -DEFINE_STRING_TABLE_LOOKUP(unit_active_state, UnitActiveState); diff --git a/src/core/unit.h b/src/core/unit.h index c868d75c79..a4a1b011fc 100644 --- a/src/core/unit.h +++ b/src/core/unit.h @@ -27,7 +27,6 @@ typedef struct Unit Unit; typedef struct UnitVTable UnitVTable; -typedef enum UnitActiveState UnitActiveState; typedef struct UnitRef UnitRef; typedef struct UnitStatusMessageFormats UnitStatusMessageFormats; @@ -37,17 +36,6 @@ typedef struct UnitStatusMessageFormats UnitStatusMessageFormats; #include "unit-name.h" #include "failure-action.h" -enum UnitActiveState { - UNIT_ACTIVE, - UNIT_RELOADING, - UNIT_INACTIVE, - UNIT_FAILED, - UNIT_ACTIVATING, - UNIT_DEACTIVATING, - _UNIT_ACTIVE_STATE_MAX, - _UNIT_ACTIVE_STATE_INVALID = -1 -}; - typedef enum KillOperation { KILL_TERMINATE, KILL_KILL, @@ -545,11 +533,15 @@ char *unit_dbus_path(Unit *u); int unit_load_related_unit(Unit *u, const char *type, Unit **_found); bool unit_can_serialize(Unit *u) _pure_; + int unit_serialize(Unit *u, FILE *f, FDSet *fds, bool serialize_jobs); -void unit_serialize_item_format(Unit *u, FILE *f, const char *key, const char *value, ...) _printf_(4,5); -void unit_serialize_item(Unit *u, FILE *f, const char *key, const char *value); int unit_deserialize(Unit *u, FILE *f, FDSet *fds); +int unit_serialize_item(Unit *u, FILE *f, const char *key, const char *value); +int unit_serialize_item_escaped(Unit *u, FILE *f, const char *key, const char *value); +int unit_serialize_item_fd(Unit *u, FILE *f, FDSet *fds, const char *key, int fd); +void unit_serialize_item_format(Unit *u, FILE *f, const char *key, const char *value, ...) _printf_(4,5); + int unit_add_node_link(Unit *u, const char *what, bool wants); int unit_coldplug(Unit *u); @@ -617,9 +609,6 @@ static inline bool unit_supported(Unit *u) { void unit_warn_if_dir_nonempty(Unit *u, const char* where); int unit_fail_if_symlink(Unit *u, const char* where); -const char *unit_active_state_to_string(UnitActiveState i) _const_; -UnitActiveState unit_active_state_from_string(const char *s) _pure_; - /* Macros which append UNIT= or USER_UNIT= to the message */ #define log_unit_full(unit, level, error, ...) \ |