From dfac97b21e00cd3617ba817227db7b621841b5cc Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 16 May 2010 19:09:22 +0200 Subject: build-sys: generate intermediate files in subdirs --- src/.gitignore | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 src/.gitignore (limited to 'src/.gitignore') diff --git a/src/.gitignore b/src/.gitignore new file mode 100644 index 0000000000..954d7fe0fc --- /dev/null +++ b/src/.gitignore @@ -0,0 +1,3 @@ +systemctl.c +systemd-interfaces.c +systemadm.c -- cgit v1.2.3-54-g00ecf From 7e4249b94e7f6edb9ffa842c3e790acee298594d Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 15 Jun 2010 02:51:55 +0200 Subject: systemctl: reimplement systemctl in pure C without Vala/GObject --- Makefile.am | 15 +- fixme | 6 +- src/.gitignore | 1 - src/systemctl.c | 1485 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/systemctl.vala | 357 ------------- 5 files changed, 1496 insertions(+), 368 deletions(-) create mode 100644 src/systemctl.c delete mode 100644 src/systemctl.vala (limited to 'src/.gitignore') diff --git a/Makefile.am b/Makefile.am index 7c0f793db6..03591bed15 100644 --- a/Makefile.am +++ b/Makefile.am @@ -343,6 +343,13 @@ systemd_cgroups_agent_CPPFLAGS = \ systemd_cgroups_agent_LDADD = \ $(DBUS_LIBS) +systemctl_SOURCES = \ + src/systemctl.c \ + $(BASIC_SOURCES) + +systemctl_CPPFLAGS = $(AM_CPPFLAGS) $(DBUS_CFLAGS) +systemctl_LDADD = $(DBUS_LIBS) + VALAFLAGS = \ -g \ --save-temps \ @@ -358,13 +365,6 @@ VALA_CFLAGS = \ -Wno-unused-variable \ -Wno-unused-function -systemctl_SOURCES = \ - src/systemctl.vala \ - src/systemd-interfaces.vala - -systemctl_CPPFLAGS = $(AM_CPPFLAGS) $(DBUSGLIB_CFLAGS) $(VALA_CFLAGS) -systemctl_LDADD = $(DBUSGLIB_LIBS) - systemadm_SOURCES = \ src/systemadm.vala \ src/systemd-interfaces.vala @@ -417,7 +417,6 @@ CLEANFILES = \ if HAVE_VALAC CLEANFILES += \ src/systemd-interfaces.c \ - src/systemctl.c \ src/systemadm.c endif diff --git a/fixme b/fixme index 514e3731fd..57682f0ea8 100644 --- a/fixme +++ b/fixme @@ -54,8 +54,6 @@ - bluetoothd (/var/run/sdp! @/org/bluez/audio!) - distccd -* teach dbus to talk to systemd when autospawning services - * regnerate unit/sysv search paths on daemon reload * write utmp record a la upstart for processes @@ -66,6 +64,10 @@ * use setproctitle() when forking, before exec() (waiting for (PR_SET_PROCTITLE_AREA to enter the kernel) +* s/maintainance/maintenance/ + +* follow property change dbus spec + Regularly: * look for close() vs. close_nointr() vs. close_nointr_nofail() diff --git a/src/.gitignore b/src/.gitignore index 954d7fe0fc..1841bf597d 100644 --- a/src/.gitignore +++ b/src/.gitignore @@ -1,3 +1,2 @@ -systemctl.c systemd-interfaces.c systemadm.c diff --git a/src/systemctl.c b/src/systemctl.c new file mode 100644 index 0000000000..8a7a2de403 --- /dev/null +++ b/src/systemctl.c @@ -0,0 +1,1485 @@ +/*-*- Mode: C; c-basic-offset: 8 -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "log.h" +#include "util.h" +#include "macro.h" +#include "set.h" + +static const char *arg_type = NULL; +static bool arg_all = false; +static bool arg_replace = false; +static bool arg_session = false; +static bool arg_block = false; + +static int bus_iter_get_basic_and_next(DBusMessageIter *iter, int type, void *data, bool next) { + + if (dbus_message_iter_get_arg_type(iter) != type) + return -EIO; + + dbus_message_iter_get_basic(iter, data); + + if (!dbus_message_iter_next(iter) != !next) + return -EIO; + + return 0; +} + +static int columns(void) { + static int parsed_columns = 0; + const char *e; + + if (parsed_columns > 0) + return parsed_columns; + + if ((e = getenv("COLUMNS"))) + parsed_columns = atoi(e); + + if (parsed_columns <= 0) { + struct winsize ws; + zero(ws); + + if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) >= 0) + parsed_columns = ws.ws_col; + } + + if (parsed_columns <= 0) + parsed_columns = 80; + + return parsed_columns; +} + +static int list_units(DBusConnection *bus, char **args, unsigned n) { + DBusMessage *m = NULL, *reply = NULL; + DBusError error; + int r; + DBusMessageIter iter, sub, sub2; + unsigned k = 0; + + dbus_error_init(&error); + + if (!(m = dbus_message_new_method_call( + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "ListUnits"))) { + log_error("Could not allocate message."); + return -ENOMEM; + } + + if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) { + log_error("Failed to issue method call: %s", error.message); + r = -EIO; + goto finish; + } + + if (!dbus_message_iter_init(reply, &iter) || + dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY || + dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT) { + log_error("Failed to parse reply."); + r = -EIO; + goto finish; + } + + dbus_message_iter_recurse(&iter, &sub); + + printf("%-45s %-6s %-12s %-12s %-15s %s\n", "UNIT", "LOAD", "ACTIVE", "SUB", "JOB", "DESCRIPTION"); + + while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) { + const char *id, *description, *load_state, *active_state, *sub_state, *unit_state, *job_type, *job_path, *dot; + uint32_t job_id; + + if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) { + log_error("Failed to parse reply."); + r = -EIO; + goto finish; + } + + dbus_message_iter_recurse(&sub, &sub2); + + if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &id, true) < 0 || + bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &description, true) < 0 || + bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &load_state, true) < 0 || + bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &active_state, true) < 0 || + bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &sub_state, true) < 0 || + bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &unit_state, true) < 0 || + bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &job_id, true) < 0 || + bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &job_type, true) < 0 || + bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &job_path, false) < 0) { + log_error("Failed to parse reply."); + r = -EIO; + goto finish; + } + + if ((!arg_type || ((dot = strrchr(id, '.')) && + streq(dot+1, arg_type))) && + (arg_all || !streq(active_state, "inactive"))) { + + int a = 0, b = 0; + + printf("%-45s %-6s %-12s %-12s%n", id, load_state, active_state, sub_state, &a); + + if (job_id != 0) + printf(" %-15s%n", job_type, &b); + else + b = 1 + 15; + + if (a + b + 2 < columns()) { + if (job_id == 0) + printf(" "); + + printf("%.*s", columns() - a - b - 2, description); + } + + fputs("\n", stdout); + k++; + } + + dbus_message_iter_next(&sub); + } + + if (arg_all) + printf("\n%u units listed.\n", k); + else + printf("\n%u live units listed. Pass --all to see dead units, too.\n", k); + + r = 0; + +finish: + if (m) + dbus_message_unref(m); + + if (reply) + dbus_message_unref(reply); + + dbus_error_free(&error); + + return r; +} + +static int list_jobs(DBusConnection *bus, char **args, unsigned n) { + DBusMessage *m = NULL, *reply = NULL; + DBusError error; + int r; + DBusMessageIter iter, sub, sub2; + unsigned k = 0; + + dbus_error_init(&error); + + if (!(m = dbus_message_new_method_call( + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "ListJobs"))) { + log_error("Could not allocate message."); + return -ENOMEM; + } + + if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) { + log_error("Failed to issue method call: %s", error.message); + r = -EIO; + goto finish; + } + + if (!dbus_message_iter_init(reply, &iter) || + dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY || + dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT) { + log_error("Failed to parse reply."); + r = -EIO; + goto finish; + } + + dbus_message_iter_recurse(&iter, &sub); + + printf("%4s %-45s %-17s %-7s\n", "JOB", "UNIT", "TYPE", "STATE"); + + while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) { + const char *name, *type, *state, *job_path, *unit_path; + uint32_t id; + + if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) { + log_error("Failed to parse reply."); + r = -EIO; + goto finish; + } + + dbus_message_iter_recurse(&sub, &sub2); + + if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &id, true) < 0 || + bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &name, true) < 0 || + bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) < 0 || + bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &state, true) < 0 || + bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &job_path, true) < 0 || + bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &unit_path, false) < 0) { + log_error("Failed to parse reply."); + r = -EIO; + goto finish; + } + + printf("%4u %-45s %-17s %-7s\n", id, name, type, state); + k++; + + dbus_message_iter_next(&sub); + } + + printf("\n%u jobs listed.\n", k); + r = 0; + +finish: + if (m) + dbus_message_unref(m); + + if (reply) + dbus_message_unref(reply); + + dbus_error_free(&error); + + return r; +} + +static int load_unit(DBusConnection *bus, char **args, unsigned n) { + DBusMessage *m = NULL, *reply = NULL; + DBusError error; + int r; + unsigned i; + + dbus_error_init(&error); + + for (i = 1; i < n; i++) { + + if (!(m = dbus_message_new_method_call( + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "LoadUnit"))) { + log_error("Could not allocate message."); + r = -ENOMEM; + goto finish; + } + + if (!dbus_message_append_args(m, + DBUS_TYPE_STRING, &args[i], + DBUS_TYPE_INVALID)) { + log_error("Could not append arguments to message."); + r = -ENOMEM; + goto finish; + } + + if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) { + log_error("Failed to issue method call: %s", error.message); + r = -EIO; + goto finish; + } + + dbus_message_unref(m); + dbus_message_unref(reply); + + m = reply = NULL; + } + + r = 0; + +finish: + if (m) + dbus_message_unref(m); + + if (reply) + dbus_message_unref(reply); + + dbus_error_free(&error); + + return r; +} + +static int cancel_job(DBusConnection *bus, char **args, unsigned n) { + DBusMessage *m = NULL, *reply = NULL; + DBusError error; + int r; + unsigned i; + + dbus_error_init(&error); + + for (i = 1; i < n; i++) { + unsigned id; + const char *path; + + if (!(m = dbus_message_new_method_call( + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "GetJob"))) { + log_error("Could not allocate message."); + r = -ENOMEM; + goto finish; + } + + if ((r = safe_atou(args[i], &id)) < 0) { + log_error("Failed to parse job id: %s", strerror(-r)); + goto finish; + } + + assert_cc(sizeof(uint32_t) == sizeof(id)); + if (!dbus_message_append_args(m, + DBUS_TYPE_UINT32, &id, + DBUS_TYPE_INVALID)) { + log_error("Could not append arguments to message."); + r = -ENOMEM; + goto finish; + } + + if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) { + log_error("Failed to issue method call: %s", error.message); + r = -EIO; + goto finish; + } + + if (!dbus_message_get_args(reply, &error, + DBUS_TYPE_OBJECT_PATH, &path, + DBUS_TYPE_INVALID)) { + log_error("Failed to parse reply: %s", error.message); + r = -EIO; + goto finish; + } + + dbus_message_unref(m); + if (!(m = dbus_message_new_method_call( + "org.freedesktop.systemd1", + path, + "org.freedesktop.systemd1.Job", + "Cancel"))) { + log_error("Could not allocate message."); + r = -ENOMEM; + goto finish; + } + + dbus_message_unref(reply); + if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) { + log_error("Failed to issue method call: %s", error.message); + r = -EIO; + goto finish; + } + + dbus_message_unref(m); + dbus_message_unref(reply); + m = reply = NULL; + } + + r = 0; + +finish: + if (m) + dbus_message_unref(m); + + if (reply) + dbus_message_unref(reply); + + dbus_error_free(&error); + + return r; +} + +static DBusHandlerResult wait_filter(DBusConnection *connection, DBusMessage *message, void *data) { + DBusError error; + Set *s = data; + + assert(connection); + assert(message); + assert(s); + + dbus_error_init(&error); + + /* log_debug("Got D-Bus request: %s.%s() on %s", */ + /* dbus_message_get_interface(message), */ + /* dbus_message_get_member(message), */ + /* dbus_message_get_path(message)); */ + + if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL, "Disconnected")) { + log_error("Warning! D-Bus connection terminated."); + dbus_connection_close(connection); + + } else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "JobRemoved")) { + uint32_t id; + const char *path; + + if (!dbus_message_get_args(message, &error, + DBUS_TYPE_UINT32, &id, + DBUS_TYPE_OBJECT_PATH, &path, + DBUS_TYPE_INVALID)) + log_error("Failed to parse message: %s", error.message); + else { + char *p; + + if ((p = set_remove(s, (char*) path))) + free(p); + } + } + + dbus_error_free(&error); + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +} + +static int wait_for_jobs(DBusConnection *bus, Set *s) { + DBusError error; + DBusMessage *m = NULL, *reply = NULL; + int r; + + assert(bus); + assert(s); + + dbus_error_init(&error); + + dbus_bus_add_match(bus, + "type='signal'," + "sender='org.freedesktop.systemd1'," + "interface='org.freedesktop.systemd1.Manager'," + "member='JobRemoved'," + "path='/org/freedesktop/systemd1'", + &error); + + if (dbus_error_is_set(&error)) { + log_error("Failed to add match: %s", error.message); + r = -EIO; + goto finish; + } + + if (!dbus_connection_add_filter(bus, wait_filter, s, NULL)) { + log_error("Failed to add filter."); + r = -ENOMEM; + goto finish; + } + + if (!(m = dbus_message_new_method_call( + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "Subscribe"))) { + log_error("Could not allocate message."); + r = -ENOMEM; + goto finish; + } + + if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) { + log_error("Failed to issue method call: %s", error.message); + r = -EIO; + goto finish; + } + + while (!set_isempty(s) && + dbus_connection_read_write_dispatch(bus, -1)) + ; + + r = 0; + +finish: + /* This is slightly dirty, since we don't undo the filter or the matches. */ + + if (m) + dbus_message_unref(m); + + if (reply) + dbus_message_unref(reply); + + dbus_error_free(&error); + + return r; +} + +static int start_unit(DBusConnection *bus, char **args, unsigned n) { + DBusMessage *m = NULL, *reply = NULL; + DBusError error; + int r; + unsigned i; + const char *method, *mode; + char *p = NULL; + Set *s = NULL; + + dbus_error_init(&error); + + method = + streq(args[0], "start") ? "StartUnit" : + streq(args[0], "stop") ? "StopUnit" : + streq(args[0], "reload") ? "ReloadUnit" : + "RestartUnit"; + + mode = arg_replace ? "replace" : "fail"; + + for (i = 1; i < n; i++) { + + if (!(m = dbus_message_new_method_call( + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + method))) { + log_error("Could not allocate message."); + r = -ENOMEM; + goto finish; + } + + if (!dbus_message_append_args(m, + DBUS_TYPE_STRING, &args[i], + DBUS_TYPE_STRING, &mode, + DBUS_TYPE_INVALID)) { + log_error("Could not append arguments to message."); + r = -ENOMEM; + goto finish; + } + + if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) { + log_error("Failed to issue method call: %s", error.message); + r = -EIO; + goto finish; + } + + if (arg_block) { + const char *path; + + if (!dbus_message_get_args(reply, &error, + DBUS_TYPE_OBJECT_PATH, &path, + DBUS_TYPE_INVALID)) { + log_error("Failed to parse reply: %s", error.message); + r = -EIO; + goto finish; + } + + if (!s) + if (!(s = set_new(string_hash_func, string_compare_func))) { + log_error("Failed to allocate set."); + r = -ENOMEM; + goto finish; + } + + if (!(p = strdup(path))) { + log_error("Failed to duplicate path."); + r = -ENOMEM; + goto finish; + } + + if ((r = set_put(s, p)) < 0) { + log_error("Failed to add path to set."); + goto finish; + } + p = NULL; + } + + dbus_message_unref(m); + dbus_message_unref(reply); + + m = reply = NULL; + } + + if (arg_block) + r = wait_for_jobs(bus, s); + else + r = 0; + +finish: + free(p); + + if (s) + set_free_free(s); + + if (m) + dbus_message_unref(m); + + if (reply) + dbus_message_unref(reply); + + dbus_error_free(&error); + + return r; +} + +static int isolate_unit(DBusConnection *bus, char **args, unsigned n) { + DBusMessage *m = NULL, *reply = NULL; + DBusError error; + int r; + const char *mode = "isolate"; + char *p = NULL; + Set *s = NULL; + + dbus_error_init(&error); + + if (!(m = dbus_message_new_method_call( + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "StartUnit"))) { + log_error("Could not allocate message."); + r = -ENOMEM; + goto finish; + } + + if (!dbus_message_append_args(m, + DBUS_TYPE_STRING, &args[1], + DBUS_TYPE_STRING, &mode, + DBUS_TYPE_INVALID)) { + log_error("Could not append arguments to message."); + r = -ENOMEM; + goto finish; + } + + if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) { + log_error("Failed to issue method call: %s", error.message); + r = -EIO; + goto finish; + } + + if (arg_block) { + const char *path; + + if (!dbus_message_get_args(reply, &error, + DBUS_TYPE_OBJECT_PATH, &path, + DBUS_TYPE_INVALID)) { + log_error("Failed to parse reply: %s", error.message); + r = -EIO; + goto finish; + } + + if (!(s = set_new(string_hash_func, string_compare_func))) { + log_error("Failed to allocate set."); + r = -ENOMEM; + goto finish; + } + + if (!(p = strdup(path))) { + log_error("Failed to duplicate path."); + r = -ENOMEM; + goto finish; + } + + if ((r = set_put(s, p)) < 0) { + log_error("Failed to add path to set."); + goto finish; + } + p = NULL; + + r = wait_for_jobs(bus, s); + + } else + r = 0; + +finish: + free(p); + + if (s) + set_free_free(s); + + if (m) + dbus_message_unref(m); + + if (reply) + dbus_message_unref(reply); + + dbus_error_free(&error); + + return r; +} + +static DBusHandlerResult monitor_filter(DBusConnection *connection, DBusMessage *message, void *data) { + DBusError error; + DBusMessage *m = NULL, *reply = NULL; + + assert(connection); + assert(message); + + dbus_error_init(&error); + + /* log_debug("Got D-Bus request: %s.%s() on %s", */ + /* dbus_message_get_interface(message), */ + /* dbus_message_get_member(message), */ + /* dbus_message_get_path(message)); */ + + if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL, "Disconnected")) { + log_error("Warning! D-Bus connection terminated."); + dbus_connection_close(connection); + + } else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "UnitNew") || + dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "UnitRemoved")) { + const char *id, *path; + + if (!dbus_message_get_args(message, &error, + DBUS_TYPE_STRING, &id, + DBUS_TYPE_OBJECT_PATH, &path, + DBUS_TYPE_INVALID)) + log_error("Failed to parse message: %s", error.message); + else if (streq(dbus_message_get_member(message), "UnitNew")) + printf("Unit %s added.\n", id); + else + printf("Unit %s removed.\n", id); + + } else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "JobNew") || + dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "JobRemoved")) { + uint32_t id; + const char *path; + + if (!dbus_message_get_args(message, &error, + DBUS_TYPE_UINT32, &id, + DBUS_TYPE_OBJECT_PATH, &path, + DBUS_TYPE_INVALID)) + log_error("Failed to parse message: %s", error.message); + else if (streq(dbus_message_get_member(message), "JobNew")) + printf("Job %u added.\n", id); + else + printf("Job %u removed.\n", id); + + + } else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Unit", "Changed") || + dbus_message_is_signal(message, "org.freedesktop.systemd1.Job", "Changed")) { + + const char *path, *interface, *property = "Id"; + DBusMessageIter iter, sub; + + path = dbus_message_get_path(message); + interface = dbus_message_get_interface(message); + + if (!(m = dbus_message_new_method_call( + "org.freedesktop.systemd1", + path, + "org.freedesktop.DBus.Properties", + "Get"))) { + log_error("Could not allocate message."); + goto oom; + } + + if (!dbus_message_append_args(m, + DBUS_TYPE_STRING, &interface, + DBUS_TYPE_STRING, &property, + DBUS_TYPE_INVALID)) { + log_error("Could not append arguments to message."); + goto finish; + } + + if (!(reply = dbus_connection_send_with_reply_and_block(connection, m, -1, &error))) { + log_error("Failed to issue method call: %s", error.message); + goto finish; + } + + if (!dbus_message_iter_init(reply, &iter) || + dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) { + log_error("Failed to parse reply."); + goto finish; + } + + dbus_message_iter_recurse(&iter, &sub); + + if (streq(interface, "org.freedesktop.systemd1.Unit")) { + const char *id; + + if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING) { + log_error("Failed to parse reply."); + goto finish; + } + + dbus_message_iter_get_basic(&sub, &id); + printf("Unit %s changed.\n", id); + } else { + uint32_t id; + + if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_UINT32) { + log_error("Failed to parse reply."); + goto finish; + } + + dbus_message_iter_get_basic(&sub, &id); + printf("Job %u changed.\n", id); + } + } + +finish: + if (m) + dbus_message_unref(m); + + if (reply) + dbus_message_unref(reply); + + dbus_error_free(&error); + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + +oom: + if (m) + dbus_message_unref(m); + + if (reply) + dbus_message_unref(reply); + + dbus_error_free(&error); + return DBUS_HANDLER_RESULT_NEED_MEMORY; +} + +static int monitor(DBusConnection *bus, char **args, unsigned n) { + DBusMessage *m = NULL, *reply = NULL; + DBusError error; + int r; + + dbus_error_init(&error); + + dbus_bus_add_match(bus, + "type='signal'," + "sender='org.freedesktop.systemd1'," + "interface='org.freedesktop.systemd1.Manager'," + "path='/org/freedesktop/systemd1'", + &error); + + if (dbus_error_is_set(&error)) { + log_error("Failed to add match: %s", error.message); + r = -EIO; + goto finish; + } + + dbus_bus_add_match(bus, + "type='signal'," + "sender='org.freedesktop.systemd1'," + "interface='org.freedesktop.systemd1.Unit'," + "member='Changed'", + &error); + + if (dbus_error_is_set(&error)) { + log_error("Failed to add match: %s", error.message); + r = -EIO; + goto finish; + } + + dbus_bus_add_match(bus, + "type='signal'," + "sender='org.freedesktop.systemd1'," + "interface='org.freedesktop.systemd1.Job'," + "member='Changed'", + &error); + + if (dbus_error_is_set(&error)) { + log_error("Failed to add match: %s", error.message); + r = -EIO; + goto finish; + } + + if (!dbus_connection_add_filter(bus, monitor_filter, NULL, NULL)) { + log_error("Failed to add filter."); + r = -ENOMEM; + goto finish; + } + + if (!(m = dbus_message_new_method_call( + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "Subscribe"))) { + log_error("Could not allocate message."); + r = -ENOMEM; + goto finish; + } + + if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) { + log_error("Failed to issue method call: %s", error.message); + r = -EIO; + goto finish; + } + + while (dbus_connection_read_write_dispatch(bus, -1)) + ; + + r = 0; + +finish: + + /* This is slightly dirty, since we don't undo the filter or the matches. */ + + if (m) + dbus_message_unref(m); + + if (reply) + dbus_message_unref(reply); + + dbus_error_free(&error); + + return r; +} + +static int dump(DBusConnection *bus, char **args, unsigned n) { + DBusMessage *m = NULL, *reply = NULL; + DBusError error; + int r; + const char *text; + + dbus_error_init(&error); + + if (!(m = dbus_message_new_method_call( + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "Dump"))) { + log_error("Could not allocate message."); + return -ENOMEM; + } + + if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) { + log_error("Failed to issue method call: %s", error.message); + r = -EIO; + goto finish; + } + + if (!dbus_message_get_args(reply, &error, + DBUS_TYPE_STRING, &text, + DBUS_TYPE_INVALID)) { + log_error("Failed to parse reply: %s", error.message); + r = -EIO; + goto finish; + } + + fputs(text, stdout); + + r = 0; + +finish: + if (m) + dbus_message_unref(m); + + if (reply) + dbus_message_unref(reply); + + dbus_error_free(&error); + + return r; +} + +static int snapshot(DBusConnection *bus, char **args, unsigned n) { + DBusMessage *m = NULL, *reply = NULL; + DBusError error; + int r; + const char *name = "", *path, *id; + dbus_bool_t cleanup = FALSE; + DBusMessageIter iter, sub; + const char + *interface = "org.freedesktop.systemd1.Unit", + *property = "Id"; + + dbus_error_init(&error); + + if (!(m = dbus_message_new_method_call( + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "CreateSnapshot"))) { + log_error("Could not allocate message."); + return -ENOMEM; + } + + if (n > 1) + name = args[1]; + + if (!dbus_message_append_args(m, + DBUS_TYPE_STRING, &name, + DBUS_TYPE_BOOLEAN, &cleanup, + DBUS_TYPE_INVALID)) { + log_error("Could not append arguments to message."); + r = -ENOMEM; + goto finish; + } + + if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) { + log_error("Failed to issue method call: %s", error.message); + r = -EIO; + goto finish; + } + + if (!dbus_message_get_args(reply, &error, + DBUS_TYPE_OBJECT_PATH, &path, + DBUS_TYPE_INVALID)) { + log_error("Failed to parse reply: %s", error.message); + r = -EIO; + goto finish; + } + + dbus_message_unref(m); + if (!(m = dbus_message_new_method_call( + "org.freedesktop.systemd1", + path, + "org.freedesktop.DBus.Properties", + "Get"))) { + log_error("Could not allocate message."); + return -ENOMEM; + } + + if (!dbus_message_append_args(m, + DBUS_TYPE_STRING, &interface, + DBUS_TYPE_STRING, &property, + DBUS_TYPE_INVALID)) { + log_error("Could not append arguments to message."); + r = -ENOMEM; + goto finish; + } + + dbus_message_unref(reply); + if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) { + log_error("Failed to issue method call: %s", error.message); + r = -EIO; + goto finish; + } + + if (!dbus_message_iter_init(reply, &iter) || + dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) { + log_error("Failed to parse reply."); + r = -EIO; + goto finish; + } + + dbus_message_iter_recurse(&iter, &sub); + + if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING) { + log_error("Failed to parse reply."); + r = -EIO; + goto finish; + } + + dbus_message_iter_get_basic(&sub, &id); + puts(id); + r = 0; + +finish: + if (m) + dbus_message_unref(m); + + if (reply) + dbus_message_unref(reply); + + dbus_error_free(&error); + + return r; +} + +static int clear_jobs(DBusConnection *bus, char **args, unsigned n) { + DBusMessage *m = NULL, *reply = NULL; + DBusError error; + int r; + const char *method; + + dbus_error_init(&error); + + method = + streq(args[0], "clear-jobs") ? "ClearJobs" : + streq(args[0], "daemon-reload") ? "Reload" : + streq(args[0], "daemon-reexec") ? "Reexecute" : + "Exit"; + + if (!(m = dbus_message_new_method_call( + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + method))) { + log_error("Could not allocate message."); + return -ENOMEM; + } + + if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) { + log_error("Failed to issue method call: %s", error.message); + r = -EIO; + goto finish; + } + + r = 0; + +finish: + if (m) + dbus_message_unref(m); + + if (reply) + dbus_message_unref(reply); + + dbus_error_free(&error); + + return r; +} + +static int show_enviroment(DBusConnection *bus, char **args, unsigned n) { + DBusMessage *m = NULL, *reply = NULL; + DBusError error; + DBusMessageIter iter, sub, sub2; + int r; + const char + *interface = "org.freedesktop.systemd1.Manager", + *property = "Environment"; + + dbus_error_init(&error); + + if (!(m = dbus_message_new_method_call( + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.DBus.Properties", + "Get"))) { + log_error("Could not allocate message."); + return -ENOMEM; + } + + if (!dbus_message_append_args(m, + DBUS_TYPE_STRING, &interface, + DBUS_TYPE_STRING, &property, + DBUS_TYPE_INVALID)) { + log_error("Could not append arguments to message."); + r = -ENOMEM; + goto finish; + } + + if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) { + log_error("Failed to issue method call: %s", error.message); + r = -EIO; + goto finish; + } + + if (!dbus_message_iter_init(reply, &iter) || + dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) { + log_error("Failed to parse reply."); + r = -EIO; + goto finish; + } + + dbus_message_iter_recurse(&iter, &sub); + + if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_ARRAY || + dbus_message_iter_get_element_type(&sub) != DBUS_TYPE_STRING) { + log_error("Failed to parse reply."); + r = -EIO; + goto finish; + } + + dbus_message_iter_recurse(&sub, &sub2); + + while (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_INVALID) { + const char *text; + + if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_STRING) { + log_error("Failed to parse reply."); + r = -EIO; + goto finish; + } + + dbus_message_iter_get_basic(&sub2, &text); + printf("%s\n", text); + + dbus_message_iter_next(&sub2); + } + + r = 0; + +finish: + if (m) + dbus_message_unref(m); + + if (reply) + dbus_message_unref(reply); + + dbus_error_free(&error); + + return r; +} + +static int set_environment(DBusConnection *bus, char **args, unsigned n) { + DBusMessage *m = NULL, *reply = NULL; + DBusError error; + int r; + const char *method; + DBusMessageIter iter, sub; + unsigned i; + + dbus_error_init(&error); + + method = streq(args[0], "set-environment") + ? "SetEnvironment" + : "UnsetEnvironment"; + + if (!(m = dbus_message_new_method_call( + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + method))) { + + log_error("Could not allocate message."); + return -ENOMEM; + } + + dbus_message_iter_init_append(m, &iter); + + if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &sub)) { + log_error("Could not append arguments to message."); + r = -ENOMEM; + goto finish; + } + + for (i = 1; i < n; i++) + if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &args[i])) { + log_error("Could not append arguments to message."); + r = -ENOMEM; + goto finish; + } + + if (!dbus_message_iter_close_container(&iter, &sub)) { + log_error("Could not append arguments to message."); + r = -ENOMEM; + goto finish; + } + + if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) { + log_error("Failed to issue method call: %s", error.message); + r = -EIO; + goto finish; + } + + r = 0; + +finish: + if (m) + dbus_message_unref(m); + + if (reply) + dbus_message_unref(reply); + + dbus_error_free(&error); + + return r; +} + +static int help(void) { + + printf("%s [options]\n\n" + " -h --help Show this help\n" + " -t --type=TYPE List only units of a particular type\n" + " -a --all Show all units, including dead ones\n" + " --replace When installing a new job, replace existing conflicting ones\n" + " --system Connect to system bus\n" + " --session Connect to session bus\n" + " --block Wait until operation finished\n\n" + "Commands:\n" + " list-units List units\n" + " list-jobs List jobs\n" + " clear-jobs Cancel all jobs\n" + " load [NAME...] Load one or more units\n" + " cancel [JOB...] Cancel one or more jobs\n" + " start [NAME...] Start one or more units\n" + " stop [NAME...] Stop one or more units\n" + " restart [NAME...] Restart one or more units\n" + " reload [NAME...] Reload one or more units\n" + " isolate [NAME] Start one unit and stop all others\n" + " monitor Monitor unit/job changes\n" + " dump Dump server status\n" + " snapshot [NAME] Create a snapshot\n" + " daemon-reload Reload daemon configuration\n" + " daemon-reexecute Reexecute daemon\n" + " daemon-exit Ask the daemon to quit\n" + " show-environment Dump environment\n" + " set-environment [NAME=VALUE...] Set one or more environment variables\n" + " unset-environment [NAME...] Unset one or more environment variables\n", + __progname); + + return 0; +} + +static int parse_argv(int argc, char *argv[]) { + + enum { + ARG_REPLACE = 0x100, + ARG_SESSION, + ARG_SYSTEM, + ARG_BLOCK, + }; + + static const struct option options[] = { + { "help", no_argument, NULL, 'h' }, + { "type", required_argument, NULL, 't' }, + { "all", no_argument, NULL, 'a' }, + { "replace", no_argument, NULL, ARG_REPLACE }, + { "session", no_argument, NULL, ARG_SESSION }, + { "system", no_argument, NULL, ARG_SYSTEM }, + { "block", no_argument, NULL, ARG_BLOCK } + }; + + int c; + + assert(argc >= 1); + assert(argv); + + while ((c = getopt_long(argc, argv, "hta", options, NULL)) >= 0) { + + switch (c) { + + case 'h': + help(); + return 0; + + case 't': + arg_type = optarg; + break; + + case 'a': + arg_all = true; + break; + + case ARG_REPLACE: + arg_replace = true; + break; + + case ARG_SESSION: + arg_session = true; + break; + + case ARG_SYSTEM: + arg_session = false; + break; + + case ARG_BLOCK: + arg_block = true; + break; + + case '?': + return -EINVAL; + + default: + log_error("Unknown option code %c", c); + return -EINVAL; + } + } + + return 1; +} + +int main(int argc, char*argv[]) { + + + static const struct { + const char* verb; + const enum { + MORE, + LESS, + EQUAL + } argc_cmp; + const int argc; + int (* const dispatch)(DBusConnection *bus, char **args, unsigned n); + } verbs[] = { + { "list-units", LESS, 1, list_units }, + { "list-jobs", EQUAL, 1, list_jobs }, + { "clear-jobs", EQUAL, 1, clear_jobs }, + { "load", MORE, 2, load_unit }, + { "cancel", MORE, 2, cancel_job }, + { "start", MORE, 2, start_unit }, + { "stop", MORE, 2, start_unit }, + { "reload", MORE, 2, start_unit }, + { "restart", MORE, 2, start_unit }, + { "isolate", EQUAL, 2, isolate_unit }, + { "monitor", EQUAL, 1, monitor }, + { "dump", EQUAL, 1, dump }, + { "snapshot", LESS, 2, snapshot }, + { "daemon-reload", EQUAL, 1, clear_jobs }, + { "daemon-reexec", EQUAL, 1, clear_jobs }, + { "daemon-exit", EQUAL, 1, clear_jobs }, + { "show-environment", EQUAL, 1, show_enviroment }, + { "set-environment", MORE, 2, set_environment }, + { "unset-environment", MORE, 2, set_environment }, + }; + + int r, retval = 1, left; + unsigned i; + DBusConnection *bus = NULL; + DBusError error; + + dbus_error_init(&error); + + log_set_target(LOG_TARGET_CONSOLE); + log_parse_environment(); + + if ((r = parse_argv(argc, argv)) < 0) + goto finish; + else if (r == 0) { + retval = 0; + goto finish; + } + + left = argc - optind; + + if (left <= 0) + /* Special rule: no arguments means "list-units" */ + i = 0; + else { + for (i = 0; i < ELEMENTSOF(verbs); i++) + if (streq(argv[optind], verbs[i].verb)) + break; + + if (i >= ELEMENTSOF(verbs)) { + log_error("Unknown operation %s", argv[optind]); + goto finish; + } + } + + switch (verbs[i].argc_cmp) { + + case EQUAL: + if (left != verbs[i].argc) { + log_error("Invalid number of arguments."); + goto finish; + } + + break; + + case MORE: + if (left < verbs[i].argc) { + log_error("Too few arguments."); + goto finish; + } + + break; + + case LESS: + if (left > verbs[i].argc) { + log_error("Too many arguments."); + goto finish; + } + + break; + + default: + assert_not_reached("Unknown comparison operator."); + } + + if (!(bus = dbus_bus_get(arg_session ? DBUS_BUS_SESSION : DBUS_BUS_SYSTEM, &error))) { + log_error("Failed to get D-Bus connection: %s", error.message); + goto finish; + } + + dbus_connection_set_exit_on_disconnect(bus, FALSE); + + retval = verbs[i].dispatch(bus, argv + optind, left) < 0; + +finish: + + if (bus) + dbus_connection_unref(bus); + + dbus_shutdown(); + + return retval; +} diff --git a/src/systemctl.vala b/src/systemctl.vala deleted file mode 100644 index 6cce93bec6..0000000000 --- a/src/systemctl.vala +++ /dev/null @@ -1,357 +0,0 @@ -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with systemd; If not, see . -***/ - -using DBus; -using GLib; - -static string type = null; -static bool all = false; -static bool replace = false; -static bool session = false; -static bool block = false; -static Connection? bus = null; -static List jobs = null; -static MainLoop main_loop = null; -static int exit_code = 0; - -public static int job_info_compare(void* key1, void* key2) { - Manager.JobInfo *j1 = (Manager.JobInfo*) key1; - Manager.JobInfo *j2 = (Manager.JobInfo*) key2; - - return j1->id < j2->id ? -1 : (j1->id > j2->id ? 1 : 0); -} - -public static int unit_info_compare(void* key1, void* key2) { - Manager.UnitInfo *u1 = (Manager.UnitInfo*) key1; - Manager.UnitInfo *u2 = (Manager.UnitInfo*) key2; - - int r = Posix.strcmp(Posix.strrchr(u1->id, '.'), Posix.strrchr(u2->id, '.')); - if (r != 0) - return r; - - return Posix.strcmp(u1->id, u2->id); -} - -public void monitor_on_unit_changed(Unit u) { - stdout.printf("Unit %s changed.\n", u.id); -} - -public void monitor_on_unit_new(string id, ObjectPath path) { - stdout.printf("Unit %s added.\n", id); - - Unit u = bus.get_object( - "org.freedesktop.systemd1", - path, - "org.freedesktop.systemd1.Unit") as Unit; - - u.changed += monitor_on_unit_changed; - - /* FIXME: We leak memory here */ - u.ref(); -} - -public void monitor_on_job_changed(Job j) { - stdout.printf("Job %u changed.\n", j.id); -} - -public void monitor_on_job_new(uint32 id, ObjectPath path) { - stdout.printf("Job %u added.\n", id); - - Job j = bus.get_object( - "org.freedesktop.systemd1", - path, - "org.freedesktop.systemd1.Job") as Job; - - j.changed += monitor_on_job_changed; - - /* FIXME: We leak memory here */ - j.ref(); -} - -public void monitor_on_unit_removed(string id, ObjectPath path) { - stdout.printf("Unit %s removed.\n", id); -} - -public void monitor_on_job_removed(uint32 id, ObjectPath path, bool success) { - stdout.printf("Job %u removed (success=%i).\n", id, (int) success); -} - -public void block_on_job_removed(uint32 id, ObjectPath path, bool success) { - - for (unowned List i = jobs; i != null; i = i.next) - if (i.data == path) { - jobs.remove_link(i); - break; - } - - if (jobs == null) { - if (!success) - exit_code = 1; - - main_loop.quit(); - } -} - -static const OptionEntry entries[] = { - { "type", 't', 0, OptionArg.STRING, out type, "List only particular type of units", "TYPE" }, - { "all", 'a', 0, OptionArg.NONE, out all, "Show all units, including dead ones", null }, - { "replace", 0, 0, OptionArg.NONE, out replace, "When installing a new job, replace existing conflicting ones", null }, - { "session", 0, 0, OptionArg.NONE, out session, "Connect to session bus", null }, - { "system", 0, OptionFlags.REVERSE, OptionArg.NONE, out session, "Connect to system bus", null }, - { "block", 0, 0, OptionArg.NONE, out block, "Wait until the operation finished", null }, - { null } -}; - -int main (string[] args) { - OptionContext context = new OptionContext("[COMMAND [ARGUMENT...]]"); - context.add_main_entries(entries, null); - context.set_description( - "Commands:\n" + - " list-units List units\n" + - " list-jobs List jobs\n" + - " clear-jobs Cancel all jobs\n" + - " load [NAME...] Load one or more units\n" + - " cancel [JOB...] Cancel one or more jobs\n" + - " start [NAME...] Start one or more units\n" + - " stop [NAME...] Stop one or more units\n" + - " restart [NAME...] Restart one or more units\n" + - " reload [NAME...] Reload one or more units\n" + - " isolate [NAME] Start one unit and stop all others\n" + - " monitor Monitor unit/job changes\n" + - " dump Dump server status\n" + - " snapshot [NAME] Create a snapshot\n" + - " daemon-reload Reload daemon configuration\n" + - " daemon-reexecute Reexecute daemon\n" + - " daemon-exit Ask the daemon to quit\n" + - " show-environment Dump environment\n" + - " set-environment [NAME=VALUE...] Set one or more environment variables\n" + - " unset-environment [NAME...] Unset one or more environment variables\n"); - - try { - context.parse(ref args); - } catch (GLib.OptionError e) { - message("Failed to parse command line: %s".printf(e.message)); - } - - try { - bus = Bus.get(session ? BusType.SESSION : BusType.SYSTEM); - - Manager manager = bus.get_object ( - "org.freedesktop.systemd1", - "/org/freedesktop/systemd1", - "org.freedesktop.systemd1.Manager") as Manager; - - if (args[1] == "list-units" || args.length <= 1) { - var list = manager.list_units(); - uint n = 0; - Posix.qsort(list, list.length, sizeof(Manager.UnitInfo), unit_info_compare); - - stdout.printf("%-45s %-6s %-12s %-12s %-17s\n", "UNIT", "LOAD", "ACTIVE", "SUB", "JOB"); - - foreach (var i in list) { - - if (type != null && !i.id.has_suffix(".%s".printf(type))) - continue; - - if (!all && i.active_state == "inactive") - continue; - - stdout.printf("%-45s %-6s %-12s %-12s", i.id, i.load_state, i.active_state, i.sub_state); - - if (i.job_id != 0) - stdout.printf(" -> %-15s", i.job_type); - - stdout.puts("\n"); - n++; - } - - if (all) - stdout.printf("\n%u units listed.\n", n); - else - stdout.printf("\n%u live units listed. Pass --all to see dead units, too.\n", n); - - - } else if (args[1] == "list-jobs") { - var list = manager.list_jobs(); - Posix.qsort(list, list.length, sizeof(Manager.JobInfo), job_info_compare); - - stdout.printf("%4s %-45s %-17s %-7s\n", "JOB", "UNIT", "TYPE", "STATE"); - - foreach (var i in list) - stdout.printf("%4u %-45s → %-15s %-7s\n", i.id, i.name, i.type, i.state); - - stdout.printf("\n%u jobs listed.\n", list.length); - - } else if (args[1] == "clear-jobs") { - - manager.clear_jobs(); - - } else if (args[1] == "load") { - - if (args.length < 3) { - stderr.printf("Missing argument.\n"); - return 1; - } - - for (int i = 2; i < args.length; i++) - manager.load_unit(args[i]); - - } else if (args[1] == "cancel") { - - if (args.length < 3) { - stderr.printf("Missing argument.\n"); - return 1; - } - - for (int i = 2; i < args.length; i++) { - uint32 id; - - if (args[i].scanf("%u", out id) != 1) { - stderr.printf("Failed to parse argument.\n"); - return 1; - } - - ObjectPath p = manager.get_job(id); - - Job j = bus.get_object ( - "org.freedesktop.systemd1", - p, - "org.freedesktop.systemd1.Job") as Job; - - j.cancel(); - } - - } else if (args[1] == "start" || - args[1] == "stop" || - args[1] == "reload" || - args[1] == "restart") { - - if (args.length < 3) { - stderr.printf("Missing argument.\n"); - return 1; - } - - if (block) - manager.subscribe(); - - for (int i = 2; i < args.length; i++) { - - string mode = replace ? "replace" : "fail"; - ObjectPath j = null; - - if (args[1] == "start") - j = manager.start_unit(args[i], mode); - else if (args[1] == "stop") - j = manager.stop_unit(args[i], mode); - else if (args[1] == "restart") - j = manager.restart_unit(args[i], mode); - else if (args[1] == "reload") - j = manager.reload_unit(args[i], mode); - - if (block) - jobs.append(j); - } - - } else if (args[1] == "isolate") { - - if (args.length != 3) { - stderr.printf("Missing argument.\n"); - return 1; - } - - ObjectPath j = manager.start_unit(args[2], "isolate"); - - if (block) { - manager.subscribe(); - jobs.append(j); - } - - } else if (args[1] == "monitor") { - - manager.subscribe(); - - var unit_list = manager.list_units(); - - foreach (var i in unit_list) { - monitor_on_unit_new(i.id, i.unit_path); - - if (i.job_id != 0) - monitor_on_job_new(i.job_id, i.job_path); - } - - manager.unit_new += monitor_on_unit_new; - manager.unit_removed += monitor_on_unit_removed; - manager.job_new += monitor_on_job_new; - manager.job_removed += monitor_on_job_removed; - - main_loop = new MainLoop(); - main_loop.run(); - - } else if (args[1] == "dump") - stdout.puts(manager.dump()); - - else if (args[1] == "snapshot") { - - ObjectPath p = manager.create_snapshot(args.length > 2 ? args[2] : ""); - - Unit u = bus.get_object( - "org.freedesktop.systemd1", - p, - "org.freedesktop.systemd1.Unit") as Unit; - - stdout.printf("%s\n", u.id); - - } else if (args[1] == "daemon-reload") - manager.reload(); - - else if (args[1] == "daemon-reexecute" || args[1] == "daemon-reexec") - manager.reexecute(); - - else if (args[1] == "daemon-exit") - manager.exit(); - - else if (args[1] == "show-environment") { - foreach(var x in manager.environment) - stderr.printf("%s\n", x); - - } else if (args[1] == "set-environment") - manager.set_environment(args[2:args.length]); - - else if (args[1] == "unset-environment") - manager.unset_environment(args[2:args.length]); - - else { - stderr.printf("Unknown command %s.\n", args[1]); - return 1; - } - - if (jobs != null && block) { - manager.job_removed += block_on_job_removed; - - main_loop = new MainLoop(); - main_loop.run(); - } - - } catch (DBus.Error e) { - stderr.printf("%s\n".printf(e.message)); - return 1; - } - - return exit_code; -} -- cgit v1.2.3-54-g00ecf From 490aed584944b684026a3fd01f8d81f2881e38d6 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 17 Sep 2010 01:26:29 +0200 Subject: ask-password: add minimal framework to allow services query SSL/harddisk passphrases from the user --- .gitignore | 3 + Makefile.am | 49 ++++- configure.ac | 2 +- src/.gitignore | 1 + src/ask-password-agent.vala | 250 +++++++++++++++++++++++++ src/ask-password.c | 352 ++++++++++++++++++++++++++++++++++++ src/main.c | 2 + src/org.freedesktop.systemd1.policy | 30 +++ src/reply-password.c | 108 +++++++++++ src/systemadm.vala | 2 +- 10 files changed, 794 insertions(+), 5 deletions(-) create mode 100644 src/ask-password-agent.vala create mode 100644 src/ask-password.c create mode 100644 src/org.freedesktop.systemd1.policy create mode 100644 src/reply-password.c (limited to 'src/.gitignore') diff --git a/.gitignore b/.gitignore index 9e2fb86b57..7cecf1c31b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ +systemd-reply-password +systemd-ask-password-agent +systemd-ask-password systemd-kmsg-syslogd systemd-remount-api-vfs test-hostname diff --git a/Makefile.am b/Makefile.am index 7632e553d8..5f11e4fb7a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -25,6 +25,7 @@ dbusinterfacedir=@dbusinterfacedir@ udevrulesdir=@udevrulesdir@ pamlibdir=@pamlibdir@ pkgconfigdatadir=$(datadir)/pkgconfig +polkitpolicydir=$(datadir)/polkit-1/actions # Our own, non-special dirs pkgsysconfdir=$(sysconfdir)/systemd @@ -56,14 +57,16 @@ AM_CPPFLAGS = \ rootbin_PROGRAMS = \ systemd \ systemctl \ - systemd-notify + systemd-notify \ + systemd-ask-password bin_PROGRAMS = \ systemd-cgls if HAVE_GTK bin_PROGRAMS += \ - systemadm + systemadm \ + systemd-ask-password-agent endif rootlibexec_PROGRAMS = \ @@ -76,7 +79,8 @@ rootlibexec_PROGRAMS = \ systemd-modules-load \ systemd-remount-api-vfs \ systemd-kmsg-syslogd \ - systemd-vconsole-setup + systemd-vconsole-setup \ + systemd-reply-password noinst_PROGRAMS = \ test-engine \ @@ -282,6 +286,9 @@ dist_doc_DATA = \ pkgconfigdata_DATA = \ systemd.pc +dist_polkitpolicy_DATA = \ + src/org.freedesktop.systemd1.policy + noinst_LTLIBRARIES = \ libsystemd-basic.la \ libsystemd-core.la @@ -665,6 +672,18 @@ systemd_notify_SOURCES = \ systemd_notify_LDADD = \ libsystemd-basic.la +systemd_ask_password_SOURCES = \ + src/ask-password.c + +systemd_ask_password_LDADD = \ + libsystemd-basic.la + +systemd_reply_password_SOURCES = \ + src/reply-password.c + +systemd_reply_password_LDADD = \ + libsystemd-basic.la + systemd_cgls_SOURCES = \ src/cgls.c \ src/cgroup-show.c \ @@ -699,6 +718,30 @@ systemadm_LDADD = \ $(DBUSGLIB_LIBS) \ $(GTK_LIBS) +systemd_ask_password_agent_SOURCES = \ + src/ask-password-agent.vala + +systemd_ask_password_agent_CFLAGS = \ + $(AM_CFLAGS) \ + $(DBUSGLIB_CFLAGS) \ + $(GTK_CFLAGS) \ + -Wno-unused-variable \ + -Wno-unused-function \ + -Wno-shadow \ + -Wno-format-nonliteral + +systemd_ask_password_agent_VALAFLAGS = \ + --pkg=dbus-glib-1 \ + --pkg=posix \ + --pkg=gtk+-2.0 \ + --pkg=linux \ + --pkg=gio-unix-2.0 \ + -g + +systemd_ask_password_agent_LDADD = \ + $(DBUSGLIB_LIBS) \ + $(GTK_LIBS) + pam_systemd_la_SOURCES = \ src/pam-module.c \ src/cgroup-util.c \ diff --git a/configure.ac b/configure.ac index 2ff0c1ffc8..334b1e263c 100644 --- a/configure.ac +++ b/configure.ac @@ -226,7 +226,7 @@ AC_SUBST(AUDIT_LIBS) have_gtk=no AC_ARG_ENABLE(gtk, AS_HELP_STRING([--disable-gtk], [disable GTK tools])) if test "x$enable_gtk" != "xno"; then - PKG_CHECK_MODULES(GTK, [ gtk+-2.0 ], + PKG_CHECK_MODULES(GTK, [ gtk+-2.0 gio-unix-2.0 ], [AC_DEFINE(HAVE_GTK, 1, [Define if GTK is available]) have_gtk=yes], have_gtk=no) AC_SUBST(GTK_CFLAGS) AC_SUBST(GTK_LIBS) diff --git a/src/.gitignore b/src/.gitignore index 1841bf597d..389f26daa2 100644 --- a/src/.gitignore +++ b/src/.gitignore @@ -1,2 +1,3 @@ +ask-password-agent.c systemd-interfaces.c systemadm.c diff --git a/src/ask-password-agent.vala b/src/ask-password-agent.vala new file mode 100644 index 0000000000..5355bb4694 --- /dev/null +++ b/src/ask-password-agent.vala @@ -0,0 +1,250 @@ +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with systemd; If not, see . +***/ + +using Gtk; +using GLib; +using DBus; +using Linux; +using Posix; + +[CCode (cheader_filename = "time.h")] +extern int clock_gettime(int id, out timespec ts); + +public class PasswordDialog : Dialog { + + public Entry entry; + + public PasswordDialog(string message, string icon) { + set_title("System Password"); + set_has_separator(false); + set_border_width(8); + set_default_response(ResponseType.OK); + set_icon_name(icon); + + add_button(STOCK_CANCEL, ResponseType.CANCEL); + add_button(STOCK_OK, ResponseType.OK); + + Container content = (Container) get_content_area(); + + Box hbox = new HBox(false, 16); + hbox.set_border_width(8); + content.add(hbox); + + Image image = new Image.from_icon_name(icon, IconSize.DIALOG); + hbox.pack_start(image, false, false); + + Box vbox = new VBox(false, 8); + hbox.pack_start(vbox, true, true); + + Label label = new Label(message); + vbox.pack_start(label, false, false); + + entry = new Entry(); + entry.set_visibility(false); + entry.set_activates_default(true); + vbox.pack_start(entry, false, false); + + entry.activate.connect(on_entry_activated); + + show_all(); + } + + public void on_entry_activated() { + response(ResponseType.OK); + } +} + +public class MyStatusIcon : StatusIcon { + + File directory; + File current; + FileMonitor file_monitor; + + string message; + string icon; + string socket; + + PasswordDialog password_dialog; + + public MyStatusIcon() throws GLib.Error { + GLib.Object(icon_name : "dialog-password"); + set_title("System Password Agent"); + + directory = File.new_for_path("/dev/.systemd/ask-password/"); + file_monitor = directory.monitor_directory(0); + file_monitor.changed.connect(file_monitor_changed); + + current = null; + look_for_password(); + + activate.connect(status_icon_activate); + } + + void file_monitor_changed(GLib.File file, GLib.File? other_file, GLib.FileMonitorEvent event_type) throws GLib.Error { + + if (!file.get_basename().has_prefix("ask.")) + return; + + if (event_type == FileMonitorEvent.CREATED || + event_type == FileMonitorEvent.DELETED) + look_for_password(); + } + + void look_for_password() throws GLib.Error { + + if (current != null) { + if (!current.query_exists()) { + current = null; + if (password_dialog != null) + password_dialog.response(ResponseType.REJECT); + } + } + + if (current == null) { + FileEnumerator enumerator = directory.enumerate_children("standard::name", FileQueryInfoFlags.NOFOLLOW_SYMLINKS); + + FileInfo i; + while ((i = enumerator.next_file()) != null) { + if (!i.get_name().has_prefix("ask.")) + continue; + + current = directory.get_child(i.get_name()); + + if (load_password()) + break; + + current = null; + } + } + + if (current == null) + set_visible(false); + + } + + bool load_password() { + + KeyFile key_file = new KeyFile(); + + try { + timespec ts; + + key_file.load_from_file(current.get_path(), KeyFileFlags.NONE); + + string not_after_as_string = key_file.get_string("Ask", "NotAfter"); + + clock_gettime(1, out ts); + uint64 now = (ts.tv_sec * 1000000) + (ts.tv_nsec / 1000); + + uint64 not_after; + if (not_after_as_string.scanf("%llu", out not_after) != 1) + return false; + + if (not_after < now) + return false; + + socket = key_file.get_string("Ask", "Socket"); + } catch (GLib.Error e) { + return false; + } + + try { + message = key_file.get_string("Ask", "Message").compress(); + } catch (GLib.Error e) { + message = "Please Enter System Password!"; + } + set_tooltip_text(message); + + try { + icon = key_file.get_string("Ask", "Icon"); + } catch (GLib.Error e) { + icon = "dialog-password"; + } + set_from_icon_name(icon); + + set_visible(true); + return true; + } + + void status_icon_activate() throws GLib.Error { + + if (current == null) + return; + + if (password_dialog != null) { + password_dialog.present(); + return; + } + + password_dialog = new PasswordDialog(message, icon); + + int result = password_dialog.run(); + string password = password_dialog.entry.get_text(); + + password_dialog.destroy(); + password_dialog = null; + + if (result == ResponseType.REJECT || + result == ResponseType.DELETE_EVENT) + return; + + int to_process; + + Process.spawn_async_with_pipes( + null, + { "/usr/bin/pkexec", "/lib/systemd/systemd-reply-password", result == ResponseType.OK ? "1" : "0", socket }, + null, + 0, + null, + null, + out to_process, + null, + null); + + OutputStream stream = new UnixOutputStream(to_process, true); + + stream.write(password, password.length, null); + } +} + +static const OptionEntry entries[] = { + { null } +}; + +void show_error(string e) { + var m = new MessageDialog(null, 0, MessageType.ERROR, ButtonsType.CLOSE, "%s", e); + m.run(); + m.destroy(); +} + +int main(string[] args) { + try { + Gtk.init_with_args(ref args, "[OPTION...]", entries, "systemd-ask-password-agent"); + + MyStatusIcon i = new MyStatusIcon(); + Gtk.main(); + + } catch (DBus.Error e) { + show_error(e.message); + } catch (GLib.Error e) { + show_error(e.message); + } + + return 0; +} diff --git a/src/ask-password.c b/src/ask-password.c new file mode 100644 index 0000000000..2c9b027d00 --- /dev/null +++ b/src/ask-password.c @@ -0,0 +1,352 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "log.h" +#include "macro.h" +#include "util.h" + +static const char *arg_icon = NULL; +static const char *arg_message = NULL; +static usec_t arg_timeout = 60 * USEC_PER_SEC; + +static int create_socket(char **name) { + int fd; + union { + struct sockaddr sa; + struct sockaddr_un un; + } sa; + int one = 1, r; + char *c; + + assert(name); + + if ((fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0)) < 0) { + log_error("socket() failed: %m"); + return -errno; + } + + zero(sa); + sa.un.sun_family = AF_UNIX; + snprintf(sa.un.sun_path+1, sizeof(sa.un.sun_path)-1, "/org/freedesktop/systemd1/ask-password/%llu", random_ull()); + + if (bind(fd, &sa.sa, sizeof(sa_family_t) + 1 + strlen(sa.un.sun_path+1)) < 0) { + r = -errno; + log_error("bind() failed: %m"); + goto fail; + } + + if (setsockopt(fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one)) < 0) { + r = -errno; + log_error("SO_PASSCRED failed: %m"); + goto fail; + } + + if (!(c = strdup(sa.un.sun_path+1))) { + r = -ENOMEM; + log_error("Out of memory"); + goto fail; + } + + *name = c; + return fd; + +fail: + close_nointr_nofail(fd); + + return r; +} + +static int help(void) { + + printf("%s [OPTIONS...] MESSAGE\n\n" + "Query the user for a passphrase.\n\n" + " -h --help Show this help\n" + " --icon=NAME Icon name\n" + " --timeout=USEC Timeout in usec\n", + program_invocation_short_name); + + return 0; +} + +static int parse_argv(int argc, char *argv[]) { + + enum { + ARG_ICON = 0x100, + ARG_TIMEOUT + }; + + static const struct option options[] = { + { "help", no_argument, NULL, 'h' }, + { "icon", required_argument, NULL, ARG_ICON }, + { "timeout", required_argument, NULL, ARG_TIMEOUT }, + { NULL, 0, NULL, 0 } + }; + + int c; + + assert(argc >= 0); + assert(argv); + + while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) { + + switch (c) { + + case 'h': + help(); + return 0; + + case ARG_ICON: + arg_icon = optarg; + break; + + case ARG_TIMEOUT: + if (parse_usec(optarg, &arg_timeout) < 0 || arg_timeout <= 0) { + log_error("Failed to parse --timeout parameter %s", optarg); + return -EINVAL; + } + break; + + case '?': + return -EINVAL; + + default: + log_error("Unknown option code %c", c); + return -EINVAL; + } + } + + if (optind != argc-1) { + help(); + return -EINVAL; + } + + arg_message = argv[optind]; + return 0; +} + +int main(int argc, char *argv[]) { + char temp[] = "/dev/.systemd/ask-password/tmp.XXXXXX"; + char final[sizeof(temp)] = ""; + int fd = -1, r = EXIT_FAILURE, k; + FILE *f = NULL; + char *socket_name = NULL; + int socket_fd, signal_fd; + sigset_t mask; + usec_t not_after; + + log_parse_environment(); + log_open(); + + if ((k = parse_argv(argc, argv)) < 0) { + r = k < 0 ? EXIT_FAILURE : EXIT_SUCCESS; + goto finish; + } + + if ((fd = mkostemp(temp, O_CLOEXEC|O_CREAT|O_WRONLY)) < 0) { + log_error("Failed to create password file: %m"); + goto finish; + } + + fchmod(fd, 0644); + + if (!(f = fdopen(fd, "w"))) { + log_error("Failed to allocate FILE: %m"); + goto finish; + } + + fd = -1; + + assert_se(sigemptyset(&mask) == 0); + sigset_add_many(&mask, SIGINT, SIGTERM, -1); + assert_se(sigprocmask(SIG_SETMASK, &mask, NULL) == 0); + + if ((signal_fd = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC)) < 0) { + log_error("signalfd(): %m"); + goto finish; + } + + if ((socket_fd = create_socket(&socket_name)) < 0) + goto finish; + + not_after = now(CLOCK_MONOTONIC) + arg_timeout; + + fprintf(f, + "[Ask]\n" + "Socket=%s\n" + "NotAfter=%llu\n", + socket_name, + (unsigned long long) not_after); + + if (arg_message) + fprintf(f, "Message=%s\n", arg_message); + + if (arg_icon) + fprintf(f, "Icon=%s\n", arg_icon); + + fflush(f); + + if (ferror(f)) { + log_error("Failed to write query file: %m"); + goto finish; + } + + memcpy(final, temp, sizeof(temp)); + + final[sizeof(final)-11] = 'a'; + final[sizeof(final)-10] = 's'; + final[sizeof(final)-9] = 'k'; + + if (rename(temp, final) < 0) { + log_error("Failed to rename query file: %m"); + goto finish; + } + + for (;;) { + enum { + FD_SOCKET, + FD_SIGNAL, + _FD_MAX + }; + + char passphrase[LINE_MAX+1]; + struct msghdr msghdr; + struct iovec iovec; + struct ucred *ucred; + union { + struct cmsghdr cmsghdr; + uint8_t buf[CMSG_SPACE(sizeof(struct ucred))]; + } control; + ssize_t n; + struct pollfd pollfd[_FD_MAX]; + + zero(pollfd); + pollfd[FD_SOCKET].fd = socket_fd; + pollfd[FD_SOCKET].events = POLLIN; + pollfd[FD_SIGNAL].fd = signal_fd; + pollfd[FD_SIGNAL].events = POLLIN; + + if ((k = poll(pollfd, 2, arg_timeout/USEC_PER_MSEC)) < 0) { + + if (errno == EINTR) + continue; + + log_error("poll() failed: %s", strerror(-r)); + goto finish; + } + + if (k <= 0) { + log_notice("Timed out"); + goto finish; + } + + if (pollfd[FD_SIGNAL].revents & POLLIN) + break; + + if (pollfd[FD_SOCKET].revents != POLLIN) { + log_error("Unexpected poll() event."); + goto finish; + } + + zero(iovec); + iovec.iov_base = passphrase; + iovec.iov_len = sizeof(passphrase)-1; + + zero(control); + zero(msghdr); + msghdr.msg_iov = &iovec; + msghdr.msg_iovlen = 1; + msghdr.msg_control = &control; + msghdr.msg_controllen = sizeof(control); + + if ((n = recvmsg(socket_fd, &msghdr, 0)) < 0) { + + if (errno == EAGAIN || + errno == EINTR) + continue; + + log_error("recvmsg() failed: %m"); + goto finish; + } + + if (n <= 0) { + log_error("Message too short"); + continue; + } + + if (msghdr.msg_controllen < CMSG_LEN(sizeof(struct ucred)) || + control.cmsghdr.cmsg_level != SOL_SOCKET || + control.cmsghdr.cmsg_type != SCM_CREDENTIALS || + control.cmsghdr.cmsg_len != CMSG_LEN(sizeof(struct ucred))) { + log_warning("Received message without credentials. Ignoring."); + continue; + } + + ucred = (struct ucred*) CMSG_DATA(&control.cmsghdr); + if (ucred->uid != 0) { + log_warning("Got request from unprivileged user. Ignoring."); + continue; + } + + if (passphrase[0] == '+') { + passphrase[n] = 0; + fputs(passphrase+1, stdout); + } else if (passphrase[0] == '-') + goto finish; + else { + log_error("Invalid packet"); + continue; + } + + break; + } + + r = EXIT_SUCCESS; + +finish: + if (fd >= 0) + close_nointr_nofail(fd); + + if (socket_fd >= 0) + close_nointr_nofail(socket_fd); + + if (f) + fclose(f); + + unlink(temp); + + if (final[0]) + unlink(final); + + return r; +} diff --git a/src/main.c b/src/main.c index 671f2bbf1d..fcb6e8f9db 100644 --- a/src/main.c +++ b/src/main.c @@ -1006,6 +1006,8 @@ int main(int argc, char *argv[]) { kmod_setup(); hostname_setup(); loopback_setup(); + + mkdir_p("/dev/.systemd/ask-password/", 0755); } if ((r = manager_new(arg_running_as, &m)) < 0) { diff --git a/src/org.freedesktop.systemd1.policy b/src/org.freedesktop.systemd1.policy new file mode 100644 index 0000000000..bb07b827fc --- /dev/null +++ b/src/org.freedesktop.systemd1.policy @@ -0,0 +1,30 @@ + + + + + + + + The systemd Project + http://www.freedesktop.org/wiki/Software/systemd + + + Send passphrase back to system + Authentication is required to send the entered passphrase back to the system. + + no + no + auth_admin_keep + + /lib/systemd/systemd-reply-password + + + diff --git a/src/reply-password.c b/src/reply-password.c new file mode 100644 index 0000000000..236fdcc94c --- /dev/null +++ b/src/reply-password.c @@ -0,0 +1,108 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "log.h" +#include "macro.h" +#include "util.h" + +static int send_on_socket(int fd, const char *socket_name, const void *packet, size_t size) { + union { + struct sockaddr sa; + struct sockaddr_un un; + } sa; + + assert(fd >= 0); + assert(socket_name); + assert(packet); + + zero(sa); + sa.un.sun_family = AF_UNIX; + strncpy(sa.un.sun_path+1, socket_name, sizeof(sa.un.sun_path)-1); + + if (sendto(fd, packet, size, MSG_NOSIGNAL, &sa.sa, sizeof(sa_family_t) + 1 + strlen(socket_name)) < 0) { + log_error("Failed to send: %m"); + return -1; + } + + return 0; +} + +int main(int argc, char *argv[]) { + int fd = -1, r = EXIT_FAILURE; + char packet[LINE_MAX]; + size_t length; + + log_set_target(LOG_TARGET_SYSLOG_OR_KMSG); + log_parse_environment(); + log_open(); + + if (argc != 3) { + log_error("Wrong number of arguments."); + goto finish; + } + + if (streq(argv[1], "1")) { + + packet[0] = '+'; + if (!fgets(packet+1, sizeof(packet)-1, stdin)) { + log_error("Failed to read password: %m"); + goto finish; + } + + truncate_nl(packet+1); + length = strlen(packet+1) + 1; + } else if (streq(argv[1], "0")) { + packet[0] = '-'; + length = 1; + } else { + log_error("Invalid first argument %s", argv[1]); + goto finish; + } + + if ((fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0)) < 0) { + log_error("socket() failed: %m"); + goto finish; + } + + if (send_on_socket(fd, argv[2], packet, length) < 0) + goto finish; + + r = EXIT_SUCCESS; + +finish: + if (fd >= 0) + close_nointr_nofail(fd); + + return r; +} diff --git a/src/systemadm.vala b/src/systemadm.vala index 4aee1d35e6..2f3aed205a 100644 --- a/src/systemadm.vala +++ b/src/systemadm.vala @@ -978,7 +978,7 @@ void show_error(string e) { m.destroy(); } -int main (string[] args) { +int main(string[] args) { try { Gtk.init_with_args(ref args, "[OPTION...]", entries, "systemadm"); -- cgit v1.2.3-54-g00ecf From ec863ba65a41e58680a3ab15841243088284e808 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 25 Oct 2010 20:35:17 +0200 Subject: ask-password: add basic tty agent --- .gitignore | 3 +- Makefile.am | 10 +- src/.gitignore | 2 +- src/ask-password.c | 113 +++----------- src/conf-parser.c | 25 +++ src/conf-parser.h | 1 + src/reply-password.c | 4 +- src/tty-ask-password-agent.c | 356 +++++++++++++++++++++++++++++++++++++++++++ src/util.c | 164 ++++++++++++++++++++ src/util.h | 2 + 10 files changed, 585 insertions(+), 95 deletions(-) create mode 100644 src/tty-ask-password-agent.c (limited to 'src/.gitignore') diff --git a/.gitignore b/.gitignore index ad0f5f4e72..2a30fab7d8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +systemd-tty-ask-password-agent systemd-fsck systemd-quotacheck systemd-user-sessions @@ -6,7 +7,7 @@ systemd-tmpfiles systemd-readahead-collect systemd-readahead-replay systemd-reply-password -systemd-ask-password-agent +systemd-gnome-ask-password-agent systemd-ask-password systemd-kmsg-syslogd systemd-remount-api-vfs diff --git a/Makefile.am b/Makefile.am index dcaf382fb4..62dcf78e6f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -81,7 +81,8 @@ rootbin_PROGRAMS = \ systemd \ systemctl \ systemd-notify \ - systemd-ask-password + systemd-ask-password \ + systemd-tty-ask-password-agent bin_PROGRAMS = \ systemd-cgls @@ -880,6 +881,13 @@ systemd_gnome_ask_password_agent_LDADD = \ $(DBUSGLIB_LIBS) \ $(GTK_LIBS) +systemd_tty_ask_password_agent_SOURCES = \ + src/tty-ask-password-agent.c \ + src/utmp-wtmp.c + +systemd_tty_ask_password_agent_LDADD = \ + libsystemd-basic.la + pam_systemd_la_SOURCES = \ src/pam-module.c \ src/cgroup-util.c \ diff --git a/src/.gitignore b/src/.gitignore index 389f26daa2..9c01ae1fda 100644 --- a/src/.gitignore +++ b/src/.gitignore @@ -1,3 +1,3 @@ -ask-password-agent.c +gnome-ask-password-agent.c systemd-interfaces.c systemadm.c diff --git a/src/ask-password.c b/src/ask-password.c index 9e4d9e7e68..493bbfef14 100644 --- a/src/ask-password.c +++ b/src/ask-password.c @@ -62,9 +62,9 @@ static int create_socket(char **name) { zero(sa); sa.un.sun_family = AF_UNIX; - snprintf(sa.un.sun_path+1, sizeof(sa.un.sun_path)-1, "/org/freedesktop/systemd1/ask-password/%llu", random_ull()); + snprintf(sa.un.sun_path, sizeof(sa.un.sun_path)-1, "/dev/.systemd/ask-password/sck.%llu", random_ull()); - if (bind(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + 1 + strlen(sa.un.sun_path+1)) < 0) { + if (bind(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)) < 0) { r = -errno; log_error("bind() failed: %m"); goto fail; @@ -76,7 +76,7 @@ static int create_socket(char **name) { goto fail; } - if (!(c = strdup(sa.un.sun_path+1))) { + if (!(c = strdup(sa.un.sun_path))) { r = -ENOMEM; log_error("Out of memory"); goto fail; @@ -97,7 +97,7 @@ static int help(void) { "Query the user for a system passphrase, via the TTY or an UI agent.\n\n" " -h --help Show this help\n" " --icon=NAME Icon name\n" - " --timeout=USEC Timeout in usec\n" + " --timeout=SEC Timeout in sec\n" " --no-tty Ask question via agent even on TTY\n", program_invocation_short_name); @@ -176,6 +176,8 @@ static int ask_agent(void) { sigset_t mask; usec_t not_after; + mkdir_p("/dev/.systemd/ask-password", 0755); + if ((fd = mkostemp(temp, O_CLOEXEC|O_CREAT|O_WRONLY)) < 0) { log_error("Failed to create password file: %m"); r = -errno; @@ -211,8 +213,10 @@ static int ask_agent(void) { fprintf(f, "[Ask]\n" + "PID=%lu\n" "Socket=%s\n" "NotAfter=%llu\n", + (unsigned long) getpid(), socket_name, (unsigned long long) not_after); @@ -354,6 +358,11 @@ finish: if (fd >= 0) close_nointr_nofail(fd); + if (socket_name) { + unlink(socket_name); + free(socket_name); + } + if (socket_fd >= 0) close_nointr_nofail(socket_fd); @@ -368,89 +377,6 @@ finish: return r; } -static int ask_tty(void) { - struct termios old_termios, new_termios; - char passphrase[LINE_MAX]; - FILE *ttyf; - - if (!(ttyf = fopen("/dev/tty", "w"))) { - log_error("Failed to open /dev/tty: %m"); - return -errno; - } - - fputs("\x1B[1m", ttyf); - fprintf(ttyf, "%s: ", arg_message); - fputs("\x1B[0m", ttyf); - fflush(ttyf); - - if (tcgetattr(STDIN_FILENO, &old_termios) >= 0) { - - new_termios = old_termios; - - new_termios.c_lflag &= ~(ICANON|ECHO); - new_termios.c_cc[VMIN] = 1; - new_termios.c_cc[VTIME] = 0; - - if (tcsetattr(STDIN_FILENO, TCSADRAIN, &new_termios) >= 0) { - size_t p = 0; - int r = 0; - - for (;;) { - size_t k; - char c; - - k = fread(&c, 1, 1, stdin); - - if (k <= 0) { - r = -EIO; - break; - } - - if (c == '\n') - break; - else if (c == '\b' || c == 127) { - if (p > 0) { - p--; - fputs("\b \b", ttyf); - } - } else { - passphrase[p++] = c; - fputc('*', ttyf); - } - - fflush(ttyf); - } - - fputc('\n', ttyf); - fclose(ttyf); - tcsetattr(STDIN_FILENO, TCSADRAIN, &old_termios); - - if (r < 0) - return -EIO; - - passphrase[p] = 0; - - fputs(passphrase, stdout); - fflush(stdout); - return 0; - } - - } - - fclose(ttyf); - - if (!fgets(passphrase, sizeof(passphrase), stdin)) { - log_error("Failed to read password."); - return -EIO; - } - - truncate_nl(passphrase); - fputs(passphrase, stdout); - fflush(stdout); - - return 0; -} - int main(int argc, char *argv[]) { int r; @@ -460,9 +386,16 @@ int main(int argc, char *argv[]) { if ((r = parse_argv(argc, argv)) <= 0) goto finish; - if (arg_use_tty && isatty(STDIN_FILENO)) - r = ask_tty(); - else + if (arg_use_tty && isatty(STDIN_FILENO)) { + char *password = NULL; + + if ((r = ask_password_tty(arg_message, now(CLOCK_MONOTONIC) + arg_timeout, NULL, &password)) >= 0) { + fputs(password, stdout); + fflush(stdout); + free(password); + } + + } else r = ask_agent(); finish: diff --git a/src/conf-parser.c b/src/conf-parser.c index d18b2a150d..aac64b29a3 100644 --- a/src/conf-parser.c +++ b/src/conf-parser.c @@ -246,6 +246,31 @@ int config_parse_int( return 0; } +int config_parse_uint64( + const char *filename, + unsigned line, + const char *section, + const char *lvalue, + const char *rvalue, + void *data, + void *userdata) { + + uint64_t *u = data; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + if ((r = safe_atou64(rvalue, u)) < 0) { + log_error("[%s:%u] Failed to parse numeric value: %s", filename, line, rvalue); + return r; + } + + return 0; +} + int config_parse_unsigned( const char *filename, unsigned line, diff --git a/src/conf-parser.h b/src/conf-parser.h index 9ff65a9bfe..019b7afd13 100644 --- a/src/conf-parser.h +++ b/src/conf-parser.h @@ -46,6 +46,7 @@ int config_parse(const char *filename, FILE *f, const char* const *sections, con /* Generic parsers */ int config_parse_int(const char *filename, unsigned line, const char *section, const char *lvalue, const char *rvalue, void *data, void *userdata); int config_parse_unsigned(const char *filename, unsigned line, const char *section, const char *lvalue, const char *rvalue, void *data, void *userdata); +int config_parse_uint64(const char *filename, unsigned line, const char *section, const char *lvalue, const char *rvalue, void *data, void *userdata); int config_parse_size(const char *filename, unsigned line, const char *section, const char *lvalue, const char *rvalue, void *data, void *userdata); int config_parse_bool(const char *filename, unsigned line, const char *section, const char *lvalue, const char *rvalue, void *data, void *userdata); int config_parse_string(const char *filename, unsigned line, const char *section, const char *lvalue, const char *rvalue, void *data, void *userdata); diff --git a/src/reply-password.c b/src/reply-password.c index 24d73a798e..575a437645 100644 --- a/src/reply-password.c +++ b/src/reply-password.c @@ -49,9 +49,9 @@ static int send_on_socket(int fd, const char *socket_name, const void *packet, s zero(sa); sa.un.sun_family = AF_UNIX; - strncpy(sa.un.sun_path+1, socket_name, sizeof(sa.un.sun_path)-1); + strncpy(sa.un.sun_path, socket_name, sizeof(sa.un.sun_path)); - if (sendto(fd, packet, size, MSG_NOSIGNAL, &sa.sa, offsetof(struct sockaddr_un, sun_path) + 1 + strlen(socket_name)) < 0) { + if (sendto(fd, packet, size, MSG_NOSIGNAL, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(socket_name)) < 0) { log_error("Failed to send: %m"); return -1; } diff --git a/src/tty-ask-password-agent.c b/src/tty-ask-password-agent.c new file mode 100644 index 0000000000..9c4d076b31 --- /dev/null +++ b/src/tty-ask-password-agent.c @@ -0,0 +1,356 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "util.h" +#include "conf-parser.h" +#include "utmp-wtmp.h" + +static enum { + ACTION_LIST, + ACTION_QUERY, + ACTION_WATCH, + ACTION_WALL +} arg_action = ACTION_QUERY; + +static int parse_password(const char *filename) { + char *socket_name = NULL, *message = NULL, *packet = NULL; + uint64_t not_after = 0; + unsigned pid = 0; + int socket_fd = -1; + + const ConfigItem items[] = { + { "Socket", config_parse_string, &socket_name, "Ask" }, + { "NotAfter", config_parse_uint64, ¬_after, "Ask" }, + { "Message", config_parse_string, &message, "Ask" }, + { "PID", config_parse_unsigned, &pid, "Ask" }, + }; + + FILE *f; + int r; + usec_t n; + + assert(filename); + + if (!(f = fopen(filename, "re"))) { + + if (errno == ENOENT) + return 0; + + log_error("open(%s): %m", filename); + return -errno; + } + + if ((r = config_parse(filename, f, NULL, items, false, NULL)) < 0) { + log_error("Failed to parse password file %s: %s", filename, strerror(-r)); + goto finish; + } + + if (!socket_name || not_after <= 0) { + log_error("Invalid password file %s", filename); + r = -EBADMSG; + goto finish; + } + + n = now(CLOCK_MONOTONIC); + if (n > not_after) { + r = 0; + goto finish; + } + + if (arg_action == ACTION_LIST) + printf("'%s' (PID %u)\n", message, pid); + else if (arg_action == ACTION_WALL) { + char *wall; + + if (asprintf(&wall, + "Password entry required for \'%s\' (PID %u).\r\n" + "Please enter password with the systemd-tty-password-agent tool!", + message, + pid) < 0) { + log_error("Out of memory"); + r = -ENOMEM; + goto finish; + } + + r = utmp_wall(wall); + free(wall); + } else { + union { + struct sockaddr sa; + struct sockaddr_un un; + } sa; + char *password; + + assert(arg_action == ACTION_QUERY || + arg_action == ACTION_WATCH); + + if (access(socket_name, W_OK) < 0) { + + if (arg_action == ACTION_QUERY) + log_info("Not querying '%s' (PID %u), lacking privileges.", message, pid); + + r = 0; + goto finish; + } + + if ((r = ask_password_tty(message, not_after, filename, &password)) < 0) { + log_error("Failed to query passwords: %s", strerror(-r)); + goto finish; + } + + asprintf(&packet, "+%s", password); + free(password); + + if (!packet) { + log_error("Out of memory"); + r = -ENOMEM; + goto finish; + } + + if ((socket_fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0)) < 0) { + log_error("socket(): %m"); + r = -errno; + goto finish; + } + + zero(sa); + sa.un.sun_family = AF_UNIX; + strncpy(sa.un.sun_path, socket_name, sizeof(sa.un.sun_path)); + + if (sendto(socket_fd, packet, strlen(packet), MSG_NOSIGNAL, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(socket_name)) < 0) { + log_error("Failed to send: %m"); + r = -errno; + goto finish; + } + } + +finish: + fclose(f); + + if (socket_fd >= 0) + close_nointr_nofail(socket_fd); + + free(packet); + free(socket_name); + free(message); + + return r; +} + +static int show_passwords(void) { + DIR *d; + struct dirent *de; + int r = 0; + + if (!(d = opendir("/dev/.systemd/ask-password"))) { + if (errno == ENOENT) + return 0; + + log_error("opendir(): %m"); + return -errno; + } + + while ((de = readdir(d))) { + char *p; + int q; + + if (de->d_type != DT_REG) + continue; + + if (ignore_file(de->d_name)) + continue; + + if (!startswith(de->d_name, "ask.")) + continue; + + if (!(p = strappend("/dev/.systemd/ask-password/", de->d_name))) { + log_error("Out of memory"); + r = -ENOMEM; + goto finish; + } + + if ((q = parse_password(p)) < 0) + r = q; + + free(p); + } + +finish: + if (d) + closedir(d); + + return r; +} + +static int watch_passwords(void) { + int notify; + struct pollfd pollfd; + int r; + + mkdir_p("/dev/.systemd/ask-password", 0755); + + if ((notify = inotify_init1(IN_CLOEXEC)) < 0) { + r = -errno; + goto finish; + } + + if (inotify_add_watch(notify, "/dev/.systemd/ask-password", IN_CLOSE_WRITE|IN_MOVED_TO) < 0) { + r = -errno; + goto finish; + } + + zero(pollfd); + pollfd.fd = notify; + pollfd.events = POLLIN; + + for (;;) { + if ((r = show_passwords()) < 0) + break; + + if (poll(&pollfd, 1, -1) < 0) { + + if (errno == EINTR) + continue; + + r = -errno; + goto finish; + } + + if (pollfd.revents != 0) + flush_fd(notify); + } + + r = 0; + +finish: + if (notify >= 0) + close_nointr_nofail(notify); + + return r; +} + +static int help(void) { + + printf("%s [OPTIONS...]\n\n" + "Process system password requests.\n\n" + " -h --help Show this help\n" + " --list Show pending password requests\n" + " --query Process pending password requests\n" + " --watch Continously process password requests\n" + " --wall Continously forward password requests to wall\n", + program_invocation_short_name); + + return 0; +} + +static int parse_argv(int argc, char *argv[]) { + + enum { + ARG_LIST = 0x100, + ARG_QUERY, + ARG_WATCH, + ARG_WALL, + }; + + static const struct option options[] = { + { "help", no_argument, NULL, 'h' }, + { "list", no_argument, NULL, ARG_LIST }, + { "query", no_argument, NULL, ARG_QUERY }, + { "watch", no_argument, NULL, ARG_WATCH }, + { "wall", no_argument, NULL, ARG_WALL }, + { NULL, 0, NULL, 0 } + }; + + int c; + + assert(argc >= 0); + assert(argv); + + while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) { + + switch (c) { + + case 'h': + help(); + return 0; + + case ARG_LIST: + arg_action = ACTION_LIST; + break; + + case ARG_QUERY: + arg_action = ACTION_QUERY; + break; + + case ARG_WATCH: + arg_action = ACTION_WATCH; + break; + + case ARG_WALL: + arg_action = ACTION_WALL; + break; + + case '?': + return -EINVAL; + + default: + log_error("Unknown option code %c", c); + return -EINVAL; + } + } + + if (optind != argc) { + help(); + return -EINVAL; + } + + return 1; +} + +int main(int argc, char *argv[]) { + int r; + + log_parse_environment(); + log_open(); + + if ((r = parse_argv(argc, argv)) <= 0) + goto finish; + + if (arg_action == ACTION_WATCH || + arg_action == ACTION_WALL) + r = watch_passwords(); + else + r = show_passwords(); + +finish: + return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; +} diff --git a/src/util.c b/src/util.c index cf3cf292a0..98422b236d 100644 --- a/src/util.c +++ b/src/util.c @@ -3350,6 +3350,170 @@ int signal_from_string_try_harder(const char *s) { return signo; } +int ask_password_tty(const char *message, usec_t until, const char *flag_file, char **_passphrase) { + struct termios old_termios, new_termios; + char passphrase[LINE_MAX]; + size_t p = 0; + int r, ttyfd = -1, notify = -1; + struct pollfd pollfd[2]; + bool reset_tty = false; + enum { + POLL_TTY, + POLL_INOTIFY + }; + + assert(message); + assert(_passphrase); + + if (flag_file) { + if ((notify = inotify_init1(IN_CLOEXEC)) < 0) { + r = -errno; + goto finish; + } + + if (inotify_add_watch(notify, flag_file, IN_ATTRIB /* for the link count */) < 0) { + r = -errno; + goto finish; + } + } + + if ((ttyfd = open("/dev/tty", O_RDWR|O_NOCTTY|O_CLOEXEC)) >= 0) { + + if (tcgetattr(ttyfd, &old_termios) < 0) { + r = -errno; + goto finish; + } + + loop_write(ttyfd, "\x1B[1m", 4, false); + loop_write(ttyfd, message, strlen(message), false); + loop_write(ttyfd, ": ", 2, false); + loop_write(ttyfd, "\x1B[0m", 4, false); + + new_termios = old_termios; + new_termios.c_lflag &= ~(ICANON|ECHO); + new_termios.c_cc[VMIN] = 1; + new_termios.c_cc[VTIME] = 0; + + if (tcsetattr(ttyfd, TCSADRAIN, &new_termios) < 0) { + r = -errno; + goto finish; + } + + reset_tty = true; + } + + zero(pollfd); + + pollfd[POLL_TTY].fd = ttyfd >= 0 ? ttyfd : STDIN_FILENO; + pollfd[POLL_TTY].events = POLLIN; + pollfd[POLL_INOTIFY].fd = notify; + pollfd[POLL_INOTIFY].events = POLLIN; + + for (;;) { + char c; + int sleep_for = -1, k; + ssize_t n; + + if (until > 0) { + usec_t y; + + y = now(CLOCK_MONOTONIC); + + if (y > until) { + r = -ETIMEDOUT; + goto finish; + } + + sleep_for = (int) ((until - y) / USEC_PER_MSEC); + } + + if (flag_file) + if (access(flag_file, F_OK) < 0) { + r = -errno; + goto finish; + } + + if ((k = poll(pollfd, notify > 0 ? 2 : 1, sleep_for)) < 0) { + + if (errno == EINTR) + continue; + + r = -errno; + goto finish; + } else if (k == 0) { + r = -ETIMEDOUT; + goto finish; + } + + if (notify > 0 && pollfd[POLL_INOTIFY].revents != 0) + flush_fd(notify); + + if (pollfd[POLL_TTY].revents == 0) + continue; + + if ((n = read(ttyfd >= 0 ? ttyfd : STDIN_FILENO, &c, 1)) < 0) { + + if (errno == EINTR || errno == EAGAIN) + continue; + + r = -errno; + goto finish; + + } else if (n == 0) + break; + + if (c == '\n') + break; + else if (c == 21) { + + while (p > 0) { + p--; + + if (ttyfd >= 0) + loop_write(ttyfd, "\b \b", 3, false); + } + + } else if (c == '\b' || c == 127) { + if (p > 0) { + p--; + + if (ttyfd >= 0) + loop_write(ttyfd, "\b \b", 3, false); + } + } else { + passphrase[p++] = c; + + if (ttyfd >= 0) + loop_write(ttyfd, "*", 1, false); + } + } + + if (ttyfd >= 0) + loop_write(ttyfd, "\n", 1, false); + + passphrase[p] = 0; + + if (!(*_passphrase = strdup(passphrase))) { + r = -ENOMEM; + goto finish; + } + + r = 0; + +finish: + if (notify >= 0) + close_nointr_nofail(notify); + + if (ttyfd >= 0) { + if (reset_tty) + tcsetattr(ttyfd, TCSADRAIN, &old_termios); + + close_nointr_nofail(ttyfd); + } + + return r; +} + static const char *const ioprio_class_table[] = { [IOPRIO_CLASS_NONE] = "none", [IOPRIO_CLASS_RT] = "realtime", diff --git a/src/util.h b/src/util.h index b257ee5603..6a252abbb1 100644 --- a/src/util.h +++ b/src/util.h @@ -364,6 +364,8 @@ bool null_or_empty(struct stat *st); DIR *xopendirat(int dirfd, const char *name); +int ask_password_tty(const char *message, usec_t until, const char *flag_file, char **_passphrase); + #define NULSTR_FOREACH(i, l) \ for ((i) = (l); (i) && *(i); (i) = strchr((i), 0)+1) -- cgit v1.2.3-54-g00ecf From 224170db0a2215284964fd9cc218681651713271 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 14 Mar 2011 02:34:18 +0100 Subject: git: ignore generated policy file --- src/.gitignore | 1 + 1 file changed, 1 insertion(+) (limited to 'src/.gitignore') diff --git a/src/.gitignore b/src/.gitignore index 9c01ae1fda..4c7d3c8822 100644 --- a/src/.gitignore +++ b/src/.gitignore @@ -1,3 +1,4 @@ +org.freedesktop.systemd1.policy gnome-ask-password-agent.c systemd-interfaces.c systemadm.c -- cgit v1.2.3-54-g00ecf From 0b191e603cc31ef0aff435fe20d49c7df39dfb8c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 29 Jun 2011 04:14:43 +0200 Subject: logind: hook uaccess into udev by default --- Makefile.am | 10 ++++++++-- src/.gitignore | 1 + src/73-seat-late.rules | 15 --------------- src/73-seat-late.rules.in | 17 +++++++++++++++++ src/logind.h | 1 - src/uaccess.c | 6 +++--- 6 files changed, 29 insertions(+), 21 deletions(-) delete mode 100644 src/73-seat-late.rules create mode 100644 src/73-seat-late.rules.in (limited to 'src/.gitignore') diff --git a/Makefile.am b/Makefile.am index 940892c5a9..8da2e1bbee 100644 --- a/Makefile.am +++ b/Makefile.am @@ -218,9 +218,11 @@ dist_dbussystemservice_DATA = \ dist_udevrules_DATA = \ src/70-uaccess.rules \ src/71-seat.rules \ - src/73-seat-late.rules \ src/99-systemd.rules +nodist_udevrules_DATA = \ + src/73-seat-late.rules + dbusinterface_DATA = \ org.freedesktop.systemd1.Manager.xml \ org.freedesktop.systemd1.Job.xml \ @@ -404,7 +406,8 @@ EXTRA_DIST = \ units/quotacheck.service.in \ systemd.pc.in \ introspect.awk \ - src/org.freedesktop.systemd1.policy.in + src/org.freedesktop.systemd1.policy.in \ + src/73-seat-late.rules.in if ENABLE_BINFMT EXTRA_DIST += \ @@ -1306,6 +1309,9 @@ man/%: man/%.in Makefile src/%.policy: src/%.policy.in Makefile $(SED_PROCESS) +src/%.rules: src/%.rules.in Makefile + $(SED_PROCESS) + M4_PROCESS_SYSTEM = \ $(AM_V_GEN)$(MKDIR_P) $(dir $@) && \ $(M4) -P $(M4_DISTRO_FLAG) -DFOR_SYSTEM=1 < $< > $@ || rm $@ diff --git a/src/.gitignore b/src/.gitignore index 4c7d3c8822..de3bb5f100 100644 --- a/src/.gitignore +++ b/src/.gitignore @@ -2,3 +2,4 @@ org.freedesktop.systemd1.policy gnome-ask-password-agent.c systemd-interfaces.c systemadm.c +73-seat-late.rules diff --git a/src/73-seat-late.rules b/src/73-seat-late.rules deleted file mode 100644 index 5a17c814ae..0000000000 --- a/src/73-seat-late.rules +++ /dev/null @@ -1,15 +0,0 @@ -# This file is part of systemd. -# -# systemd is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. - -ACTION=="remove", GOTO="seat_late_end" - -ENV{ID_SEAT}=="", ENV{ID_AUTOSEAT}=="1", ENV{ID_FOR_SEAT}!="", ENV{ID_SEAT}="seat-$env{ID_FOR_SEAT}" -ENV{ID_SEAT}=="", IMPORT{parent}="ID_SEAT" - -ENV{ID_SEAT}!="", TAG+="$env{ID_SEAT}" - -LABEL="seat_late_end" diff --git a/src/73-seat-late.rules.in b/src/73-seat-late.rules.in new file mode 100644 index 0000000000..e93a0e6da9 --- /dev/null +++ b/src/73-seat-late.rules.in @@ -0,0 +1,17 @@ +# This file is part of systemd. +# +# systemd is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. + +ACTION=="remove", GOTO="seat_late_end" + +ENV{ID_SEAT}=="", ENV{ID_AUTOSEAT}=="1", ENV{ID_FOR_SEAT}!="", ENV{ID_SEAT}="seat-$env{ID_FOR_SEAT}" +ENV{ID_SEAT}=="", IMPORT{parent}="ID_SEAT" + +ENV{ID_SEAT}!="", TAG+="$env{ID_SEAT}" + +TAG=="uaccess", RUN+="@rootlibexecdir@/systemd-uaccess $env{DEVNAME} $env{ID_SEAT}" + +LABEL="seat_late_end" diff --git a/src/logind.h b/src/logind.h index 8726502c1c..aaa21cddda 100644 --- a/src/logind.h +++ b/src/logind.h @@ -37,7 +37,6 @@ * spawn user systemd * direct client API * verify access to SetIdleHint - * hook up ACL tool for udev * * udev: * drop redundant udev_device_get_is_initialized() use as soon as libudev is fixed diff --git a/src/uaccess.c b/src/uaccess.c index 524e4f0032..392b51604f 100644 --- a/src/uaccess.c +++ b/src/uaccess.c @@ -36,14 +36,14 @@ int main(int argc, char *argv[]) { log_parse_environment(); log_open(); - if (argc != 2) { - log_error("This program expects two argument."); + if (argc < 2 || argc > 3) { + log_error("This program expects one or two arguments."); r = -EINVAL; goto finish; } path = argv[1]; - seat = argv[2]; + seat = argc >= 3 ? argv[2] : "seat0"; p = strappend("/run/systemd/seats/", seat); if (!p) { -- cgit v1.2.3-54-g00ecf From 9356a6c656357fe67b310cbbb270c6ccd1048e82 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 12 Jul 2011 01:11:27 +0200 Subject: build-sys: fix make distcheck --- Makefile.am | 26 +++++++++++++------- po/POTFILES.skip | 19 ++++++++++++++ src/.gitignore | 4 +++ src/org.freedesktop.systemd1.policy.in | 41 ------------------------------- src/org.freedesktop.systemd1.policy.in.in | 41 +++++++++++++++++++++++++++++++ 5 files changed, 81 insertions(+), 50 deletions(-) create mode 100644 po/POTFILES.skip delete mode 100644 src/org.freedesktop.systemd1.policy.in create mode 100644 src/org.freedesktop.systemd1.policy.in.in (limited to 'src/.gitignore') diff --git a/Makefile.am b/Makefile.am index 96e8838669..e5eeda393f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -411,7 +411,6 @@ EXTRA_DIST = \ units/user@.service.in \ systemd.pc.in \ introspect.awk \ - src/org.freedesktop.systemd1.policy.in \ src/73-seat-late.rules.in if ENABLE_BINFMT @@ -475,17 +474,26 @@ dist_doc_DATA = \ pkgconfigdata_DATA = \ systemd.pc -nodist_polkitpolicy_DATA = \ - src/org.freedesktop.systemd1.policy - -dist_polkitpolicy_in_files = \ +# Passed through intltool only +polkitpolicy_in_files = \ src/org.freedesktop.hostname1.policy.in \ src/org.freedesktop.locale1.policy.in \ src/org.freedesktop.timedate1.policy.in \ src/org.freedesktop.login1.policy.in +# First passed through sed, followed by intltool +polkitpolicy_in_in_files = \ + src/org.freedesktop.systemd1.policy.in.in + +nodist_polkitpolicy_DATA = \ + $(polkitpolicy_in_files:.policy.in=.policy) \ + $(polkitpolicy_in_files:.policy.in.in=.policy) + +EXTRA_DIST += \ + $(polkitpolicy_in_files) \ + $(polkitpolicy_in_in_files) + @INTLTOOL_POLICY_RULE@ -polkitpolicy_DATA = $(dist_polkitpolicy_in_files:.policy.in=.policy) noinst_LTLIBRARIES = \ libsystemd-basic.la \ @@ -1357,7 +1365,7 @@ man/%: man/%.in Makefile %.pc: %.pc.in Makefile $(SED_PROCESS) -src/%.policy: src/%.policy.in Makefile +src/%.policy.in: src/%.policy.in.in Makefile $(SED_PROCESS) src/%.rules: src/%.rules.in Makefile @@ -1383,8 +1391,8 @@ CLEANFILES = \ $(nodist_man_MANS) \ ${XML_IN_FILES:.xml.in=.html} \ $(pkgconfigdata_DATA) \ - $(polkitpolicy_DATA) \ - src/org.freedesktop.systemd1.policy + $(nodist_polkitpolicy_DATA) \ + src/73-seat-late.rules if HAVE_VALAC CLEANFILES += \ diff --git a/po/POTFILES.skip b/po/POTFILES.skip new file mode 100644 index 0000000000..192f3b6cc6 --- /dev/null +++ b/po/POTFILES.skip @@ -0,0 +1,19 @@ +src/dbus-automount.c +src/dbus-device.c +src/dbus-job.c +src/dbus-manager.c +src/dbus-mount.c +src/dbus-path.c +src/dbus-service.c +src/dbus-snapshot.c +src/dbus-socket.c +src/dbus-swap.c +src/dbus-target.c +src/dbus-timer.c +src/dbus-unit.c +src/hostnamed.c +src/localed.c +src/org.freedesktop.systemd1.policy.in.in +src/timedated.c +units/systemd-readahead-done.service.in +units/user@.service.in diff --git a/src/.gitignore b/src/.gitignore index de3bb5f100..8832dd6d3f 100644 --- a/src/.gitignore +++ b/src/.gitignore @@ -1,3 +1,7 @@ +org.freedesktop.hostname1.policy +org.freedesktop.locale1.policy +org.freedesktop.login1.policy +org.freedesktop.timedate1.policy org.freedesktop.systemd1.policy gnome-ask-password-agent.c systemd-interfaces.c diff --git a/src/org.freedesktop.systemd1.policy.in b/src/org.freedesktop.systemd1.policy.in deleted file mode 100644 index 52a28d40ea..0000000000 --- a/src/org.freedesktop.systemd1.policy.in +++ /dev/null @@ -1,41 +0,0 @@ - - - - - - - - The systemd Project - http://www.freedesktop.org/wiki/Software/systemd - - - Send passphrase back to system - Authentication is required to send the entered passphrase back to the system. - - no - no - auth_admin_keep - - @rootlibexecdir@/systemd-reply-password - - - - Privileged system and service manager access - Authentication is required to access the system and service manager. - - no - no - auth_admin_keep - - @bindir@/systemd-stdio-bridge - - - diff --git a/src/org.freedesktop.systemd1.policy.in.in b/src/org.freedesktop.systemd1.policy.in.in new file mode 100644 index 0000000000..1771314e09 --- /dev/null +++ b/src/org.freedesktop.systemd1.policy.in.in @@ -0,0 +1,41 @@ + + + + + + + + The systemd Project + http://www.freedesktop.org/wiki/Software/systemd + + + <_description>Send passphrase back to system + <_message>Authentication is required to send the entered passphrase back to the system. + + no + no + auth_admin_keep + + @rootlibexecdir@/systemd-reply-password + + + + <_description>Privileged system and service manager access + <_message>Authentication is required to access the system and service manager. + + no + no + auth_admin_keep + + @bindir@/systemd-stdio-bridge + + + -- cgit v1.2.3-54-g00ecf From 41e4d6e9ace4f3b717af3c0419b69a2ac7935116 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 25 Jul 2011 20:24:58 +0200 Subject: sysctl: apply network specific sysctls to each network card as they appear --- Makefile.am | 12 +++++++----- TODO | 2 -- src/.gitignore | 1 + src/99-systemd.rules | 44 -------------------------------------------- src/99-systemd.rules.in | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 54 insertions(+), 51 deletions(-) delete mode 100644 src/99-systemd.rules create mode 100644 src/99-systemd.rules.in (limited to 'src/.gitignore') diff --git a/Makefile.am b/Makefile.am index 2ebf53ce86..d99a2485fa 100644 --- a/Makefile.am +++ b/Makefile.am @@ -239,11 +239,11 @@ dist_dbussystemservice_DATA = \ dist_udevrules_DATA = \ src/70-uaccess.rules \ - src/71-seat.rules \ - src/99-systemd.rules + src/71-seat.rules nodist_udevrules_DATA = \ - src/73-seat-late.rules + src/73-seat-late.rules \ + src/99-systemd.rules dbusinterface_DATA = \ org.freedesktop.systemd1.Manager.xml \ @@ -434,7 +434,8 @@ EXTRA_DIST = \ src/libsystemd-daemon.sym \ src/libsystemd-login.sym \ introspect.awk \ - src/73-seat-late.rules.in + src/73-seat-late.rules.in \ + src/99-systemd.rules.in if ENABLE_BINFMT EXTRA_DIST += \ @@ -1487,7 +1488,8 @@ CLEANFILES = \ ${XML_IN_FILES:.xml.in=.html} \ $(pkgconfigdata_DATA) \ $(nodist_polkitpolicy_DATA) \ - src/73-seat-late.rules + src/73-seat-late.rules \ + src/99-systemd.rules if HAVE_VALAC CLEANFILES += \ diff --git a/TODO b/TODO index feac225cb5..0a1f98d552 100644 --- a/TODO +++ b/TODO @@ -38,8 +38,6 @@ Features: * logind: use sysfs path in device hash table instead of sysname, as soon as fb driver is fixed -* possibly apply systemd-sysctl per network device subtrees on hotplug - * implement Register= switch in .socket units to enable registration in Avahi, RPC and other socket registration services. diff --git a/src/.gitignore b/src/.gitignore index 8832dd6d3f..6c4ccaa2dd 100644 --- a/src/.gitignore +++ b/src/.gitignore @@ -1,3 +1,4 @@ +99-systemd.rules org.freedesktop.hostname1.policy org.freedesktop.locale1.policy org.freedesktop.login1.policy diff --git a/src/99-systemd.rules b/src/99-systemd.rules deleted file mode 100644 index f015d5e67b..0000000000 --- a/src/99-systemd.rules +++ /dev/null @@ -1,44 +0,0 @@ -# This file is part of systemd. -# -# systemd is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. - -ACTION=="remove", GOTO="systemd_end" - -SUBSYSTEM=="tty", KERNEL=="tty[0-9]|tty1[0-2]", TAG+="systemd" -SUBSYSTEM=="tty", KERNEL=="tty[a-zA-Z]*|hvc*", TAG+="systemd" - -KERNEL=="vport*", TAG+="systemd" - -SUBSYSTEM=="block", KERNEL!="ram*|loop*", TAG+="systemd" -SUBSYSTEM=="block", KERNEL!="ram*|loop*", ENV{DM_UDEV_DISABLE_OTHER_RULES_FLAG}=="1", ENV{SYSTEMD_READY}="0" - -# Ignore encrypted devices with no identified superblock on it, since -# we are probably still calling mke2fs or mkswap on it. -SUBSYSTEM=="block", KERNEL!="ram*|loop*", ENV{DM_UUID}=="CRYPT-*", ENV{ID_PART_TABLE_TYPE}=="", ENV{ID_FS_USAGE}=="", ENV{SYSTEMD_READY}="0" - -# We need a hardware independent way to identify network devices. We -# use the /sys/subsystem path for this. Current vanilla kernels don't -# actually support that hierarchy right now, however upcoming kernels -# will. HAL and udev internally support /sys/subsystem already, hence -# it should be safe to use this here, too. This is mostly just an -# identification string for systemd, so whether the path actually is -# accessible or not does not matter as long as it is unique and in the -# filesystem namespace. -# -# http://git.kernel.org/?p=linux/hotplug/udev.git;a=blob;f=libudev/libudev-enumerate.c;h=da831449dcaf5e936a14409e8e68ab12d30a98e2;hb=HEAD#l742 - -SUBSYSTEM=="net", KERNEL!="lo", TAG+="systemd", ENV{SYSTEMD_ALIAS}="/sys/subsystem/net/devices/%k" -SUBSYSTEM=="bluetooth", TAG+="systemd", ENV{SYSTEMD_ALIAS}="/sys/subsystem/bluetooth/devices/%k" - -SUBSYSTEM=="bluetooth", TAG+="systemd", ENV{SYSTEMD_WANTS}="bluetooth.target" -ENV{ID_SMARTCARD_READER}=="*?", TAG+="systemd", ENV{SYSTEMD_WANTS}="smartcard.target" -SUBSYSTEM=="sound", KERNEL=="card*", TAG+="systemd", ENV{SYSTEMD_WANTS}="sound.target" - -SUBSYSTEM=="printer", TAG+="systemd", ENV{SYSTEMD_WANTS}="printer.target" -SUBSYSTEM=="usb", KERNEL=="lp*", TAG+="systemd", ENV{SYSTEMD_WANTS}="printer.target" -SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ENV{ID_USB_INTERFACES}=="*:0701??:*", TAG+="systemd", ENV{SYSTEMD_WANTS}="printer.target" - -LABEL="systemd_end" diff --git a/src/99-systemd.rules.in b/src/99-systemd.rules.in new file mode 100644 index 0000000000..f3829ad049 --- /dev/null +++ b/src/99-systemd.rules.in @@ -0,0 +1,46 @@ +# This file is part of systemd. +# +# systemd is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. + +ACTION=="remove", GOTO="systemd_end" + +SUBSYSTEM=="tty", KERNEL=="tty[0-9]|tty1[0-2]", TAG+="systemd" +SUBSYSTEM=="tty", KERNEL=="tty[a-zA-Z]*|hvc*", TAG+="systemd" + +KERNEL=="vport*", TAG+="systemd" + +SUBSYSTEM=="block", KERNEL!="ram*|loop*", TAG+="systemd" +SUBSYSTEM=="block", KERNEL!="ram*|loop*", ENV{DM_UDEV_DISABLE_OTHER_RULES_FLAG}=="1", ENV{SYSTEMD_READY}="0" + +# Ignore encrypted devices with no identified superblock on it, since +# we are probably still calling mke2fs or mkswap on it. +SUBSYSTEM=="block", KERNEL!="ram*|loop*", ENV{DM_UUID}=="CRYPT-*", ENV{ID_PART_TABLE_TYPE}=="", ENV{ID_FS_USAGE}=="", ENV{SYSTEMD_READY}="0" + +# We need a hardware independent way to identify network devices. We +# use the /sys/subsystem path for this. Current vanilla kernels don't +# actually support that hierarchy right now, however upcoming kernels +# will. HAL and udev internally support /sys/subsystem already, hence +# it should be safe to use this here, too. This is mostly just an +# identification string for systemd, so whether the path actually is +# accessible or not does not matter as long as it is unique and in the +# filesystem namespace. +# +# http://git.kernel.org/?p=linux/hotplug/udev.git;a=blob;f=libudev/libudev-enumerate.c;h=da831449dcaf5e936a14409e8e68ab12d30a98e2;hb=HEAD#l742 + +SUBSYSTEM=="net", KERNEL!="lo", TAG+="systemd", ENV{SYSTEMD_ALIAS}="/sys/subsystem/net/devices/%k" +SUBSYSTEM=="bluetooth", TAG+="systemd", ENV{SYSTEMD_ALIAS}="/sys/subsystem/bluetooth/devices/%k" + +SUBSYSTEM=="bluetooth", TAG+="systemd", ENV{SYSTEMD_WANTS}="bluetooth.target" +ENV{ID_SMARTCARD_READER}=="*?", TAG+="systemd", ENV{SYSTEMD_WANTS}="smartcard.target" +SUBSYSTEM=="sound", KERNEL=="card*", TAG+="systemd", ENV{SYSTEMD_WANTS}="sound.target" + +SUBSYSTEM=="printer", TAG+="systemd", ENV{SYSTEMD_WANTS}="printer.target" +SUBSYSTEM=="usb", KERNEL=="lp*", TAG+="systemd", ENV{SYSTEMD_WANTS}="printer.target" +SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ENV{ID_USB_INTERFACES}=="*:0701??:*", TAG+="systemd", ENV{SYSTEMD_WANTS}="printer.target" + +SUBSYSTEM=="net", RUN+="@rootlibexecdir@/systemd-sysctl --prefix=/proc/sys/net/ipv4/conf/%k --prefix=/proc/sys/net/ipv4/neigh/%k --prefix=/proc/sys/net/ipv6/conf/%k --prefix=/proc/sys/net/ipv4/conf/%k" + +LABEL="systemd_end" -- cgit v1.2.3-54-g00ecf From 2030694fecef41b9c0bfa917df79b92afd5cb380 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 29 Jul 2011 03:26:10 +0200 Subject: git: hide org.freedesktop.systemd1.policy.in --- src/.gitignore | 1 + 1 file changed, 1 insertion(+) (limited to 'src/.gitignore') diff --git a/src/.gitignore b/src/.gitignore index 6c4ccaa2dd..778ae5302c 100644 --- a/src/.gitignore +++ b/src/.gitignore @@ -1,3 +1,4 @@ +org.freedesktop.systemd1.policy.in 99-systemd.rules org.freedesktop.hostname1.policy org.freedesktop.locale1.policy -- cgit v1.2.3-54-g00ecf From f975e971accc4d50c73ae53167db3df7a7099cf2 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 1 Aug 2011 00:43:05 +0200 Subject: load-fragment: speed up parsing by using a perfect hash table with configuration settings built by gperf --- Makefile.am | 23 +- configure.ac | 31 ++- src/.gitignore | 4 + src/automount.c | 4 + src/conf-parser.c | 290 ++++++++++++++++---- src/conf-parser.h | 76 ++++- src/device.c | 4 + src/install.c | 12 +- src/load-fragment-gperf.gperf.m4 | 206 ++++++++++++++ src/load-fragment.c | 578 ++++++++++----------------------------- src/load-fragment.h | 51 ++++ src/logind-gperf.gperf | 22 ++ src/logind.c | 18 +- src/logind.h | 3 + src/main.c | 52 ++-- src/mount.c | 4 + src/path.c | 4 + src/service.c | 4 + src/socket.c | 4 + src/swap.c | 4 + src/target.c | 4 + src/timer.c | 4 + src/tty-ask-password-agent.c | 21 +- src/unit.h | 4 + 24 files changed, 853 insertions(+), 574 deletions(-) create mode 100644 src/load-fragment-gperf.gperf.m4 create mode 100644 src/logind-gperf.gperf (limited to 'src/.gitignore') diff --git a/Makefile.am b/Makefile.am index b526183300..32877233a6 100644 --- a/Makefile.am +++ b/Makefile.am @@ -601,6 +601,10 @@ libsystemd_core_la_SOURCES = \ src/sd-daemon.c \ src/install.c +nodist_libsystemd_core_la_SOURCES = \ + src/load-fragment-gperf.c \ + src/load-fragment-gperf-nulstr.c + libsystemd_core_la_CFLAGS = \ $(AM_CFLAGS) \ $(DBUS_CFLAGS) \ @@ -967,6 +971,9 @@ systemd_logind_SOURCES = \ src/cgroup-util.c \ src/polkit.c +nodist_systemd_logind_SOURCES = \ + src/logind-gperf.c + systemd_logind_CFLAGS = \ $(AM_CFLAGS) \ $(DBUS_CFLAGS) \ @@ -1486,13 +1493,25 @@ src/%.policy.in: src/%.policy.in.in Makefile src/%.rules: src/%.rules.in Makefile $(SED_PROCESS) +src/%.c: src/%.gperf + $(AM_V_GEN)$(MKDIR_P) $(dir $@) && \ + $(GPERF) < $< > $@ + +src/%: src/%.m4 + $(AM_V_GEN)$(MKDIR_P) $(dir $@) && \ + $(M4) -P $(M4_DEFINES) < $< > $@ || rm $@ + +src/load-fragment-gperf-nulstr.c: src/load-fragment-gperf.gperf + $(AM_V_GEN)$(MKDIR_P) $(dir $@) && \ + $(AWK) 'BEGIN{ keywords=0 ; FS="," ; print "extern const char load_fragment_gperf_nulstr[];" ; print "const char load_fragment_gperf_nulstr[] ="} ; keyword==1 { print "\"" $$1 "\\0\"" } ; /%%/ { keyword=1} ; END { print ";" }' < $< > $@ || rm $@ + M4_PROCESS_SYSTEM = \ $(AM_V_GEN)$(MKDIR_P) $(dir $@) && \ - $(M4) -P $(M4_DISTRO_FLAG) -DFOR_SYSTEM=1 < $< > $@ || rm $@ + $(M4) -P $(M4_DEFINES) -DFOR_SYSTEM=1 < $< > $@ || rm $@ M4_PROCESS_USER = \ $(AM_V_GEN)$(MKDIR_P) $(dir $@) && \ - $(M4) -P $(M4_DISTRO_FLAG) -DFOR_USER=1 < $< > $@ || rm $@ + $(M4) -P $(M4_DEFINES) -DFOR_USER=1 < $< > $@ || rm $@ units/%: units/%.m4 Makefile $(M4_PROCESS_SYSTEM) diff --git a/configure.ac b/configure.ac index 2641de6f41..74fb061f35 100644 --- a/configure.ac +++ b/configure.ac @@ -52,6 +52,7 @@ AC_SUBST(GETTEXT_PACKAGE) AC_PROG_MKDIR_P AC_PROG_LN_S AC_PROG_SED +AC_PROG_AWK AC_PROG_CC AC_PROG_CC_C99 @@ -60,6 +61,7 @@ AC_PROG_GCC_TRADITIONAL AC_CHECK_TOOL(OBJCOPY, objcopy) AC_CHECK_TOOL(STRINGS, strings) +AC_CHECK_TOOL(GPERF, gperf) CC_CHECK_CFLAGS_APPEND([ \ -pipe \ @@ -360,77 +362,77 @@ AC_DEFINE_UNQUOTED(DISTRIBUTION, ["${with_distro}"], [Target Distribution]) SYSTEM_SYSVINIT_PATH=/etc/init.d SYSTEM_SYSVRCND_PATH=/etc/rc.d -M4_DISTRO_FLAG= +M4_DEFINES= have_plymouth=no case $with_distro in fedora) SYSTEM_SYSVINIT_PATH=/etc/rc.d/init.d AC_DEFINE(TARGET_FEDORA, [], [Target is Fedora/RHEL]) - M4_DISTRO_FLAG=-DTARGET_FEDORA=1 + M4_DEFINES=-DTARGET_FEDORA=1 have_plymouth=yes ;; suse) SYSTEM_SYSVRCND_PATH=/etc/init.d AC_DEFINE(TARGET_SUSE, [], [Target is openSUSE/SLE]) - M4_DISTRO_FLAG=-DTARGET_SUSE=1 + M4_DEFINES=-DTARGET_SUSE=1 have_plymouth=yes ;; debian) SYSTEM_SYSVRCND_PATH=/etc AC_DEFINE(TARGET_DEBIAN, [], [Target is Debian]) - M4_DISTRO_FLAG=-DTARGET_DEBIAN=1 + M4_DEFINES=-DTARGET_DEBIAN=1 ;; ubuntu) SYSTEM_SYSVRCND_PATH=/etc AC_DEFINE(TARGET_UBUNTU, [], [Target is Ubuntu]) - M4_DISTRO_FLAG=-DTARGET_UBUNTU=1 + M4_DEFINES=-DTARGET_UBUNTU=1 ;; arch) SYSTEM_SYSVINIT_PATH=/etc/rc.d SYSTEM_SYSVRCND_PATH=/etc AC_DEFINE(TARGET_ARCH, [], [Target is ArchLinux]) - M4_DISTRO_FLAG=-DTARGET_ARCH=1 + M4_DEFINES=-DTARGET_ARCH=1 ;; gentoo) SYSTEM_SYSVINIT_PATH= SYSTEM_SYSVRCND_PATH= AC_DEFINE(TARGET_GENTOO, [], [Target is Gentoo]) - M4_DISTRO_FLAG=-DTARGET_GENTOO=1 + M4_DEFINES=-DTARGET_GENTOO=1 ;; slackware) SYSTEM_SYSVINIT_PATH=/etc/rc.d/init.d AC_DEFINE(TARGET_SLACKWARE, [], [Target is Slackware]) - M4_DISTRO_FLAG=-DTARGET_SLACKWARE=1 + M4_DEFINES=-DTARGET_SLACKWARE=1 ;; frugalware) SYSTEM_SYSVINIT_PATH=/etc/rc.d AC_DEFINE(TARGET_FRUGALWARE, [], [Target is Frugalware]) - M4_DISTRO_FLAG=-DTARGET_FRUGALWARE=1 + M4_DEFINES=-DTARGET_FRUGALWARE=1 have_plymouth=yes ;; altlinux) SYSTEM_SYSVINIT_PATH=/etc/rc.d/init.d AC_DEFINE(TARGET_ALTLINUX, [], [Target is ALTLinux]) - M4_DISTRO_FLAG=-DTARGET_ALTLINUX=1 + M4_DEFINES=-DTARGET_ALTLINUX=1 have_plymouth=yes ;; mandriva) SYSTEM_SYSVINIT_PATH=/etc/rc.d/init.d AC_DEFINE(TARGET_MANDRIVA, [], [Target is Mandriva]) - M4_DISTRO_FLAG=-DTARGET_MANDRIVA=1 + M4_DEFINES=-DTARGET_MANDRIVA=1 have_plymouth=yes ;; meego) SYSTEM_SYSVINIT_PATH= SYSTEM_SYSVRCND_PATH= AC_DEFINE(TARGET_MEEGO, [], [Target is MeeGo]) - M4_DISTRO_FLAG=-DTARGET_MEEGO=1 + M4_DEFINES=-DTARGET_MEEGO=1 ;; angstrom) SYSTEM_SYSVRCND_PATH=/etc AC_DEFINE(TARGET_ANGSTROM, [], [Target is Ångström]) - M4_DISTRO_FLAG=-DTARGET_ANGSTROM=1 + M4_DEFINES=-DTARGET_ANGSTROM=1 ;; other) ;; @@ -453,11 +455,12 @@ AC_ARG_WITH([sysvrcd-path], AC_SUBST(SYSTEM_SYSVINIT_PATH) AC_SUBST(SYSTEM_SYSVRCND_PATH) -AC_SUBST(M4_DISTRO_FLAG) +AC_SUBST(M4_DEFINES) if test "x${SYSTEM_SYSVINIT_PATH}" != "x" -a "x${SYSTEM_SYSVRCND_PATH}" != "x"; then AC_DEFINE(HAVE_SYSV_COMPAT, [], [SysV init scripts and rcN.d links are supported.]) SYSTEM_SYSV_COMPAT="yes" + M4_DEFINES="$M4_DEFINES -DHAVE_SYSV_COMPAT" elif test "x${SYSTEM_SYSVINIT_PATH}" != "x" -o "x${SYSTEM_SYSVRCND_PATH}" != "x"; then AC_MSG_ERROR([*** You need both --with-sysvinit-path=PATH and --with-sysvrcd-path=PATH to enable SysV compatibility support, or both empty to disable it.]) else diff --git a/src/.gitignore b/src/.gitignore index 778ae5302c..cafff82a75 100644 --- a/src/.gitignore +++ b/src/.gitignore @@ -1,3 +1,7 @@ +load-fragment-gperf-nulstr.c +load-fragment-gperf.c +load-fragment-gperf.gperf +logind-gperf.c org.freedesktop.systemd1.policy.in 99-systemd.rules org.freedesktop.hostname1.policy diff --git a/src/automount.c b/src/automount.c index 51fa0030dd..16babd1fa4 100644 --- a/src/automount.c +++ b/src/automount.c @@ -831,6 +831,10 @@ DEFINE_STRING_TABLE_LOOKUP(automount_state, AutomountState); const UnitVTable automount_vtable = { .suffix = ".automount", + .sections = + "Unit\0" + "Automount\0" + "Install\0", .no_alias = true, .no_instances = true, diff --git a/src/conf-parser.c b/src/conf-parser.c index 02f740a04f..970877650d 100644 --- a/src/conf-parser.c +++ b/src/conf-parser.c @@ -31,50 +31,135 @@ #include "strv.h" #include "log.h" -/* Run the user supplied parser for an assignment */ -static int next_assignment( - const char *filename, - unsigned line, +int config_item_table_lookup( + void *table, const char *section, - const ConfigItem *t, - bool relaxed, const char *lvalue, - const char *rvalue, + ConfigParserCallback *func, + int *ltype, + void **data, void *userdata) { - assert(filename); - assert(t); + ConfigTableItem *t; + + assert(table); assert(lvalue); - assert(rvalue); + assert(func); + assert(ltype); + assert(data); - for (; t->parse || t->lvalue; t++) { + for (t = table; t->lvalue; t++) { - if (t->lvalue && !streq(lvalue, t->lvalue)) + if (!streq(lvalue, t->lvalue)) continue; - if (t->section && !section) + if (!streq_ptr(section, t->section)) continue; - if (t->section && !streq(section, t->section)) - continue; + *func = t->parse; + *ltype = t->ltype; + *data = t->data; + return 1; + } - if (!t->parse) - return 0; + return 0; +} - return t->parse(filename, line, section, lvalue, t->ltype, rvalue, t->data, userdata); +int config_item_perf_lookup( + void *table, + const char *section, + const char *lvalue, + ConfigParserCallback *func, + int *ltype, + void **data, + void *userdata) { + + ConfigPerfItemLookup lookup = (ConfigPerfItemLookup) table; + const ConfigPerfItem *p; + + assert(table); + assert(lvalue); + assert(func); + assert(ltype); + assert(data); + + if (!section) + p = lookup(lvalue, strlen(lvalue)); + else { + char *key; + + if (asprintf(&key, "%s.%s", section, lvalue) < 0) + return -ENOMEM; + + p = lookup(key, strlen(key)); + free(key); } + if (!p) + return 0; + + *func = p->parse; + *ltype = p->ltype; + *data = (uint8_t*) userdata + p->offset; + return 1; +} + +/* Run the user supplied parser for an assignment */ +static int next_assignment( + const char *filename, + unsigned line, + ConfigItemLookup lookup, + void *table, + const char *section, + const char *lvalue, + const char *rvalue, + bool relaxed, + void *userdata) { + + ConfigParserCallback func = NULL; + int ltype = 0; + void *data = NULL; + int r; + + assert(filename); + assert(line > 0); + assert(lookup); + assert(lvalue); + assert(rvalue); + + r = lookup(table, section, lvalue, &func, <ype, &data, userdata); + if (r < 0) + return r; + + if (func) + return func(filename, line, section, lvalue, ltype, rvalue, data, userdata); + /* Warn about unknown non-extension fields. */ if (!relaxed && !startswith(lvalue, "X-")) - log_info("[%s:%u] Unknown lvalue '%s' in section '%s'. Ignoring.", filename, line, lvalue, strna(section)); + log_info("[%s:%u] Unknown lvalue '%s' in section '%s'. Ignoring.", filename, line, lvalue, section); return 0; } /* Parse a variable assignment line */ -static int parse_line(const char *filename, unsigned line, char **section, const char* const * sections, const ConfigItem *t, bool relaxed, char *l, void *userdata) { +static int parse_line( + const char *filename, + unsigned line, + const char *sections, + ConfigItemLookup lookup, + void *table, + bool relaxed, + char **section, + char *l, + void *userdata) { + char *e; + assert(filename); + assert(line > 0); + assert(lookup); + assert(l); + l = strstrip(l); if (!*l) @@ -87,10 +172,11 @@ static int parse_line(const char *filename, unsigned line, char **section, const char *fn; int r; - if (!(fn = file_in_same_dir(filename, strstrip(l+9)))) + fn = file_in_same_dir(filename, strstrip(l+9)); + if (!fn) return -ENOMEM; - r = config_parse(fn, NULL, sections, t, relaxed, userdata); + r = config_parse(fn, NULL, sections, lookup, table, relaxed, userdata); free(fn); return r; @@ -108,22 +194,30 @@ static int parse_line(const char *filename, unsigned line, char **section, const return -EBADMSG; } - if (!(n = strndup(l+1, k-2))) + n = strndup(l+1, k-2); + if (!n) return -ENOMEM; - if (!relaxed && sections && !strv_contains((char**) sections, n)) - log_info("[%s:%u] Unknown section '%s'. Ignoring.", filename, line, n); + if (sections && !nulstr_contains(sections, n)) { - free(*section); - *section = n; + if (!relaxed) + log_info("[%s:%u] Unknown section '%s'. Ignoring.", filename, line, n); + + free(n); + *section = NULL; + } else { + free(*section); + *section = n; + } return 0; } - if (sections && (!*section || !strv_contains((char**) sections, *section))) + if (sections && !*section) return 0; - if (!(e = strchr(l, '='))) { + e = strchr(l, '='); + if (!e) { log_error("[%s:%u] Missing '='.", filename, line); return -EBADMSG; } @@ -131,11 +225,28 @@ static int parse_line(const char *filename, unsigned line, char **section, const *e = 0; e++; - return next_assignment(filename, line, *section, t, relaxed, strstrip(l), strstrip(e), userdata); + return next_assignment( + filename, + line, + lookup, + table, + *section, + strstrip(l), + strstrip(e), + relaxed, + userdata); } /* Go through the file and parse each line */ -int config_parse(const char *filename, FILE *f, const char* const * sections, const ConfigItem *t, bool relaxed, void *userdata) { +int config_parse( + const char *filename, + FILE *f, + const char *sections, + ConfigItemLookup lookup, + void *table, + bool relaxed, + void *userdata) { + unsigned line = 0; char *section = NULL; int r; @@ -143,10 +254,11 @@ int config_parse(const char *filename, FILE *f, const char* const * sections, co char *continuation = NULL; assert(filename); - assert(t); + assert(lookup); if (!f) { - if (!(f = fopen(filename, "re"))) { + f = fopen(filename, "re"); + if (!f) { r = -errno; log_error("Failed to open configuration file '%s': %s", filename, strerror(-r)); goto finish; @@ -171,7 +283,8 @@ int config_parse(const char *filename, FILE *f, const char* const * sections, co truncate_nl(l); if (continuation) { - if (!(c = strappend(continuation, l))) { + c = strappend(continuation, l); + if (!c) { r = -ENOMEM; goto finish; } @@ -194,15 +307,26 @@ int config_parse(const char *filename, FILE *f, const char* const * sections, co if (c) continuation = c; - else if (!(continuation = strdup(l))) { - r = -ENOMEM; - goto finish; + else { + continuation = strdup(l); + if (!c) { + r = -ENOMEM; + goto finish; + } } continue; } - r = parse_line(filename, ++line, §ion, sections, t, relaxed, p, userdata); + r = parse_line(filename, + ++line, + sections, + lookup, + table, + relaxed, + §ion, + p, + userdata); free(c); if (r < 0) @@ -240,8 +364,8 @@ int config_parse_int( assert(data); if ((r = safe_atoi(rvalue, i)) < 0) { - log_error("[%s:%u] Failed to parse numeric value: %s", filename, line, rvalue); - return r; + log_error("[%s:%u] Failed to parse numeric value, ingoring: %s", filename, line, rvalue); + return 0; } return 0; @@ -266,8 +390,8 @@ int config_parse_long( assert(data); if ((r = safe_atoli(rvalue, i)) < 0) { - log_error("[%s:%u] Failed to parse numeric value: %s", filename, line, rvalue); - return r; + log_error("[%s:%u] Failed to parse numeric value, ignoring: %s", filename, line, rvalue); + return 0; } return 0; @@ -292,8 +416,8 @@ int config_parse_uint64( assert(data); if ((r = safe_atou64(rvalue, u)) < 0) { - log_error("[%s:%u] Failed to parse numeric value: %s", filename, line, rvalue); - return r; + log_error("[%s:%u] Failed to parse numeric value, ignoring: %s", filename, line, rvalue); + return 0; } return 0; @@ -345,8 +469,8 @@ int config_parse_size( assert(data); if ((r = safe_atou(rvalue, &u)) < 0) { - log_error("[%s:%u] Failed to parse numeric value: %s", filename, line, rvalue); - return r; + log_error("[%s:%u] Failed to parse numeric value, ignoring: %s", filename, line, rvalue); + return 0; } *sz = (size_t) u; @@ -372,8 +496,8 @@ int config_parse_bool( assert(data); if ((k = parse_boolean(rvalue)) < 0) { - log_error("[%s:%u] Failed to parse boolean value: %s", filename, line, rvalue); - return k; + log_error("[%s:%u] Failed to parse boolean value, ignoring: %s", filename, line, rvalue); + return 0; } *b = !!k; @@ -429,8 +553,8 @@ int config_parse_path( assert(data); if (!path_is_absolute(rvalue)) { - log_error("[%s:%u] Not an absolute path: %s", filename, line, rvalue); - return -EINVAL; + log_error("[%s:%u] Not an absolute path, ignoring: %s", filename, line, rvalue); + return 0; } if (!(n = strdup(rvalue))) @@ -539,9 +663,9 @@ int config_parse_path_strv( } if (!path_is_absolute(n[k])) { - log_error("[%s:%u] Not an absolute path: %s", filename, line, rvalue); - r = -EINVAL; - goto fail; + log_error("[%s:%u] Not an absolute path, ignoring: %s", filename, line, rvalue); + free(n[k]); + continue; } path_kill_slashes(n[k]); @@ -563,3 +687,63 @@ fail: return r; } + +int config_parse_usec( + const char *filename, + unsigned line, + const char *section, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + usec_t *usec = data; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + if (parse_usec(rvalue, usec) < 0) { + log_error("[%s:%u] Failed to parse time value, ignoring: %s", filename, line, rvalue); + return 0; + } + + return 0; +} + +int config_parse_mode( + const char *filename, + unsigned line, + const char *section, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + mode_t *m = data; + long l; + char *x = NULL; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + errno = 0; + l = strtol(rvalue, &x, 8); + if (!x || *x || errno) { + log_error("[%s:%u] Failed to parse mode value, ignoring: %s", filename, line, rvalue); + return 0; + } + + if (l < 0000 || l > 07777) { + log_error("[%s:%u] mode value out of range, ignoring: %s", filename, line, rvalue); + return 0; + } + + *m = (mode_t) l; + return 0; +} diff --git a/src/conf-parser.h b/src/conf-parser.h index 51efe00786..cbb4235d69 100644 --- a/src/conf-parser.h +++ b/src/conf-parser.h @@ -28,21 +28,65 @@ /* An abstract parser for simple, line based, shallow configuration * files consisting of variable assignments only. */ -typedef int (*ConfigParserCallback)(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); - -/* Wraps info for parsing a specific configuration variable */ -typedef struct ConfigItem { - const char *lvalue; /* name of the variable */ - ConfigParserCallback parse; /* Function that is called to parse the variable's value */ - int ltype; /* Distinguish differnt variables passed to the same callback */ - void *data; /* Where to store the variable's data */ - const char *section; -} ConfigItem; - -/* The configuration file parsing routine. Expects a table of - * config_items in *t that is terminated by an item where lvalue is - * NULL */ -int config_parse(const char *filename, FILE *f, const char* const *sections, const ConfigItem *t, bool relaxed, void *userdata); +/* Prototype for a parser for a specific configuration setting */ +typedef int (*ConfigParserCallback)( + const char *filename, + unsigned line, + const char *section, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata); + +/* Wraps information for parsing a specific configuration variable, to + * be stored in a simple array */ +typedef struct ConfigTableItem { + const char *section; /* Section */ + const char *lvalue; /* Name of the variable */ + ConfigParserCallback parse; /* Function that is called to parse the variable's value */ + int ltype; /* Distinguish different variables passed to the same callback */ + void *data; /* Where to store the variable's data */ +} ConfigTableItem; + +/* Wraps information for parsing a specific configuration variable, to + * ve srored in a gperf perfect hashtable */ +typedef struct ConfigPerfItem { + const char *section_and_lvalue; /* Section + "." + name of the variable */ + ConfigParserCallback parse; /* Function that is called to parse the variable's value */ + int ltype; /* Distinguish different variables passed to the same callback */ + size_t offset; /* Offset where to store data, from the beginning of userdata */ +} ConfigPerfItem; + +/* Prototype for a low-level gperf lookup function */ +typedef const ConfigPerfItem* (*ConfigPerfItemLookup)(const char *section_and_lvalue, unsigned length); + +/* Prototype for a generic high-level lookup function */ +typedef int (*ConfigItemLookup)( + void *table, + const char *section, + const char *lvalue, + ConfigParserCallback *func, + int *ltype, + void **data, + void *userdata); + +/* Linear table search implementation of ConfigItemLookup, based on + * ConfigTableItem arrays */ +int config_item_table_lookup(void *table, const char *section, const char *lvalue, ConfigParserCallback *func, int *ltype, void **data, void *userdata); + +/* gperf implementation of ConfigItemLookup, based on gperf + * ConfigPerfItem tables */ +int config_item_perf_lookup(void *table, const char *section, const char *lvalue, ConfigParserCallback *func, int *ltype, void **data, void *userdata); + +int config_parse( + const char *filename, + FILE *f, + const char *sections, /* nulstr */ + ConfigItemLookup lookup, + void *table, + bool relaxed, + void *userdata); /* Generic parsers */ int config_parse_int(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); @@ -55,6 +99,8 @@ int config_parse_string(const char *filename, unsigned line, const char *section int config_parse_path(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_strv(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_path_strv(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_usec(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_mode(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); #define DEFINE_CONFIG_PARSE_ENUM(function,name,type,msg) \ int function( \ diff --git a/src/device.c b/src/device.c index 64b21903ed..bffeca0d10 100644 --- a/src/device.c +++ b/src/device.c @@ -583,6 +583,10 @@ DEFINE_STRING_TABLE_LOOKUP(device_state, DeviceState); const UnitVTable device_vtable = { .suffix = ".device", + .sections = + "Unit\0" + "Device\0" + "Install\0", .no_instances = true, diff --git a/src/install.c b/src/install.c index b843ee156b..7443973502 100644 --- a/src/install.c +++ b/src/install.c @@ -1019,11 +1019,11 @@ static int unit_file_load( const char *path, bool allow_symlink) { - const ConfigItem items[] = { - { "Alias", config_parse_strv, 0, &info->aliases, "Install" }, - { "WantedBy", config_parse_strv, 0, &info->wanted_by, "Install" }, - { "Also", config_parse_also, 0, c, "Install" }, - { NULL, NULL, 0, NULL, NULL } + const ConfigTableItem items[] = { + { "Install", "Alias", config_parse_strv, 0, &info->aliases }, + { "Install", "WantedBy", config_parse_strv, 0, &info->wanted_by }, + { "Install", "Also", config_parse_also, 0, c }, + { NULL, NULL, NULL, 0, NULL } }; int fd; @@ -1044,7 +1044,7 @@ static int unit_file_load( return -ENOMEM; } - r = config_parse(path, f, NULL, items, true, info); + r = config_parse(path, f, NULL, config_item_table_lookup, (void*) items, true, info); fclose(f); if (r < 0) return r; diff --git a/src/load-fragment-gperf.gperf.m4 b/src/load-fragment-gperf.gperf.m4 new file mode 100644 index 0000000000..6f32fe9250 --- /dev/null +++ b/src/load-fragment-gperf.gperf.m4 @@ -0,0 +1,206 @@ +%{ +#include +#include "conf-parser.h" +#include "load-fragment.h" +%} +struct ConfigPerfItem; +%null_strings +%language=ANSI-C +%define slot-name section_and_lvalue +%define hash-function-name load_fragment_gperf_hash +%define lookup-function-name load_fragment_gperf_lookup +%readonly-tables +%omit-struct-type +%struct-type +%includes +%% +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.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) +$1.SupplementaryGroups, config_parse_strv, 0, offsetof($1, exec_context.supplementary_groups) +$1.Nice, config_parse_exec_nice, 0, offsetof($1, exec_context) +$1.OOMScoreAdjust, config_parse_exec_oom_score_adjust, 0, offsetof($1, exec_context) +$1.IOSchedulingClass, config_parse_exec_io_class, 0, offsetof($1, exec_context) +$1.IOSchedulingPriority, config_parse_exec_io_priority, 0, offsetof($1, exec_context) +$1.CPUSchedulingPolicy, config_parse_exec_cpu_sched_policy, 0, offsetof($1, exec_context) +$1.CPUSchedulingPriority, config_parse_exec_cpu_sched_prio, 0, offsetof($1, exec_context) +$1.CPUSchedulingResetOnFork, config_parse_bool, 0, offsetof($1, exec_context.cpu_sched_reset_on_fork) +$1.CPUAffinity, config_parse_exec_cpu_affinity, 0, offsetof($1, exec_context) +$1.UMask, config_parse_mode, 0, offsetof($1, exec_context.umask) +$1.Environment, config_parse_unit_strv_printf, 0, offsetof($1, exec_context.environment) +$1.EnvironmentFile, config_parse_unit_env_file, 0, offsetof($1, exec_context.environment_files) +$1.StandardInput, config_parse_input, 0, offsetof($1, exec_context.std_input) +$1.StandardOutput, config_parse_output, 0, offsetof($1, exec_context.std_output) +$1.StandardError, config_parse_output, 0, offsetof($1, exec_context.std_error) +$1.TTYPath, config_parse_unit_path_printf, 0, offsetof($1, exec_context.tty_path) +$1.TTYReset, config_parse_bool, 0, offsetof($1, exec_context.tty_reset) +$1.TTYVHangup, config_parse_bool, 0, offsetof($1, exec_context.tty_vhangup) +$1.TTYVTDisallocate, config_parse_bool, 0, offsetof($1, exec_context.tty_vt_disallocate) +$1.SyslogIdentifier, config_parse_unit_string_printf, 0, offsetof($1, exec_context.syslog_identifier) +$1.SyslogFacility, config_parse_facility, 0, offsetof($1, exec_context.syslog_priority) +$1.SyslogLevel, config_parse_level, 0, offsetof($1, exec_context.syslog_priority) +$1.SyslogLevelPrefix, config_parse_bool, 0, offsetof($1, exec_context.syslog_level_prefix) +$1.Capabilities, config_parse_exec_capabilities, 0, offsetof($1, exec_context) +$1.SecureBits, config_parse_exec_secure_bits, 0, offsetof($1, exec_context) +$1.CapabilityBoundingSet, config_parse_exec_bounding_set, 0, offsetof($1, exec_context) +$1.TimerSlackNSec, config_parse_exec_timer_slack_nsec, 0, offsetof($1, exec_context) +$1.LimitCPU, config_parse_limit, RLIMIT_CPU, offsetof($1, exec_context.rlimit) +$1.LimitFSIZE, config_parse_limit, RLIMIT_FSIZE, offsetof($1, exec_context.rlimit) +$1.LimitDATA, config_parse_limit, RLIMIT_DATA, offsetof($1, exec_context.rlimit) +$1.LimitSTACK, config_parse_limit, RLIMIT_STACK, offsetof($1, exec_context.rlimit) +$1.LimitCORE, config_parse_limit, RLIMIT_CORE, offsetof($1, exec_context.rlimit) +$1.LimitRSS, config_parse_limit, RLIMIT_RSS, offsetof($1, exec_context.rlimit) +$1.LimitNOFILE, config_parse_limit, RLIMIT_NOFILE, offsetof($1, exec_context.rlimit) +$1.LimitAS, config_parse_limit, RLIMIT_AS, offsetof($1, exec_context.rlimit) +$1.LimitNPROC, config_parse_limit, RLIMIT_NPROC, offsetof($1, exec_context.rlimit) +$1.LimitMEMLOCK, config_parse_limit, RLIMIT_MEMLOCK, offsetof($1, exec_context.rlimit) +$1.LimitLOCKS, config_parse_limit, RLIMIT_LOCKS, offsetof($1, exec_context.rlimit) +$1.LimitSIGPENDING, config_parse_limit, RLIMIT_SIGPENDING, offsetof($1, exec_context.rlimit) +$1.LimitMSGQUEUE, config_parse_limit, RLIMIT_MSGQUEUE, offsetof($1, exec_context.rlimit) +$1.LimitNICE, config_parse_limit, RLIMIT_NICE, offsetof($1, exec_context.rlimit) +$1.LimitRTPRIO, config_parse_limit, RLIMIT_RTPRIO, offsetof($1, exec_context.rlimit) +$1.LimitRTTIME, config_parse_limit, RLIMIT_RTTIME, offsetof($1, exec_context.rlimit) +$1.ControlGroup, config_parse_unit_cgroup, 0, offsetof($1, exec_context) +$1.ReadWriteDirectories, config_parse_path_strv, 0, offsetof($1, exec_context.read_write_dirs) +$1.ReadOnlyDirectories, config_parse_path_strv, 0, offsetof($1, exec_context.read_only_dirs) +$1.InaccessibleDirectories, config_parse_path_strv, 0, offsetof($1, exec_context.inaccessible_dirs) +$1.PrivateTmp, config_parse_bool, 0, offsetof($1, exec_context.private_tmp) +$1.MountFlags, config_parse_exec_mount_flags, 0, offsetof($1, exec_context) +$1.TCPWrapName, config_parse_unit_string_printf, 0, offsetof($1, exec_context.tcpwrap_name) +$1.PAMName, config_parse_unit_string_printf, 0, offsetof($1, exec_context.pam_name) +$1.KillMode, config_parse_kill_mode, 0, offsetof($1, exec_context.kill_mode) +$1.KillSignal, config_parse_kill_signal, 0, offsetof($1, exec_context.kill_signal) +$1.SendSIGKILL, config_parse_bool, 0, offsetof($1, exec_context.send_sigkill) +$1.UtmpIdentifier, config_parse_unit_string_printf, 0, offsetof($1, exec_context.utmp_id) +$1.ControlGroupModify, config_parse_bool, 0, offsetof($1, exec_context.control_group_modify)' +)m4_dnl +Unit.Names, config_parse_unit_names, 0, 0 +Unit.Description, config_parse_unit_string_printf, 0, offsetof(Meta, description) +Unit.Requires, config_parse_unit_deps, UNIT_REQUIRES, 0 +Unit.RequiresOverridable, config_parse_unit_deps, UNIT_REQUIRES_OVERRIDABLE, 0 +Unit.Requisite, config_parse_unit_deps, UNIT_REQUISITE, 0 +Unit.RequisiteOverridable, config_parse_unit_deps, UNIT_REQUISITE_OVERRIDABLE, 0 +Unit.Wants, config_parse_unit_deps, UNIT_WANTS, 0 +Unit.BindTo, config_parse_unit_deps, UNIT_BIND_TO, 0 +Unit.Conflicts, config_parse_unit_deps, UNIT_CONFLICTS, 0 +Unit.Before, config_parse_unit_deps, UNIT_BEFORE, 0 +Unit.After, config_parse_unit_deps, UNIT_AFTER, 0 +Unit.OnFailure, config_parse_unit_deps, UNIT_ON_FAILURE, 0 +Unit.StopWhenUnneeded, config_parse_bool, 0, offsetof(Meta, stop_when_unneeded) +Unit.RefuseManualStart, config_parse_bool, 0, offsetof(Meta, refuse_manual_start) +Unit.RefuseManualStop, config_parse_bool, 0, offsetof(Meta, refuse_manual_stop) +Unit.AllowIsolate, config_parse_bool, 0, offsetof(Meta, allow_isolate) +Unit.DefaultDependencies, config_parse_bool, 0, offsetof(Meta, default_dependencies) +Unit.OnFailureIsolate, config_parse_bool, 0, offsetof(Meta, on_failure_isolate) +Unit.IgnoreOnIsolate, config_parse_bool, 0, offsetof(Meta, ignore_on_isolate) +Unit.IgnoreOnSnapshot, config_parse_bool, 0, offsetof(Meta, ignore_on_snapshot) +Unit.JobTimeoutSec, config_parse_usec, 0, offsetof(Meta, job_timeout) +Unit.ConditionPathExists, config_parse_unit_condition_path, CONDITION_PATH_EXISTS, 0 +Unit.ConditionPathExistsGlob, config_parse_unit_condition_path, CONDITION_PATH_EXISTS_GLOB, 0 +Unit.ConditionPathIsDirectory, config_parse_unit_condition_path, CONDITION_PATH_IS_DIRECTORY, 0 +Unit.ConditionDirectoryNotEmpty, config_parse_unit_condition_path, CONDITION_DIRECTORY_NOT_EMPTY, 0 +Unit.ConditionFileIsExecutable, config_parse_unit_condition_path, CONDITION_FILE_IS_EXECUTABLE, 0 +Unit.ConditionKernelCommandLine, config_parse_unit_condition_string, CONDITION_KERNEL_COMMAND_LINE, 0 +Unit.ConditionVirtualization, config_parse_unit_condition_string, CONDITION_VIRTUALIZATION, 0 +Unit.ConditionSecurity, config_parse_unit_condition_string, CONDITION_SECURITY, 0 +Unit.ConditionNull, config_parse_unit_condition_null, 0, 0 +m4_dnl +Service.PIDFile, config_parse_unit_path_printf, 0, offsetof(Service, pid_file) +Service.ExecStartPre, config_parse_exec, SERVICE_EXEC_START_PRE, offsetof(Service, exec_command) +Service.ExecStart, config_parse_exec, SERVICE_EXEC_START, offsetof(Service, exec_command) +Service.ExecStartPost, config_parse_exec, SERVICE_EXEC_START_POST, offsetof(Service, exec_command) +Service.ExecReload, config_parse_exec, SERVICE_EXEC_RELOAD, offsetof(Service, exec_command) +Service.ExecStop, config_parse_exec, SERVICE_EXEC_STOP, offsetof(Service, exec_command) +Service.ExecStopPost, config_parse_exec, SERVICE_EXEC_STOP_POST, offsetof(Service, exec_command) +Service.RestartSec, config_parse_usec, 0, offsetof(Service, restart_usec) +Service.TimeoutSec, config_parse_usec, 0, offsetof(Service, timeout_usec) +Service.Type, config_parse_service_type, 0, offsetof(Service, type) +Service.Restart, config_parse_service_restart, 0, offsetof(Service, restart) +Service.PermissionsStartOnly, config_parse_bool, 0, offsetof(Service, permissions_start_only) +Service.RootDirectoryStartOnly, config_parse_bool, 0, offsetof(Service, root_directory_start_only) +Service.RemainAfterExit, config_parse_bool, 0, offsetof(Service, remain_after_exit) +Service.GuessMainPID, config_parse_bool, 0, offsetof(Service, guess_main_pid) +m4_ifdef(`HAVE_SYSV_COMPAT', +`Service.SysVStartPriority, config_parse_sysv_priority, 0, offsetof(Service, sysv_start_priority)', +`Service.SysVStartPriority, config_parse_warn_compat, 0, 0' +) +Service.NonBlocking, config_parse_bool, 0, offsetof(Service, exec_context.non_blocking) +Service.BusName, config_parse_unit_string_printf, 0, offsetof(Service, bus_name) +Service.NotifyAccess, config_parse_notify_access, 0, offsetof(Service, notify_access) +Service.Sockets, config_parse_service_sockets, 0, 0 +Service.FsckPassNo, config_parse_fsck_passno, 0, offsetof(Service, fsck_passno) +EXEC_CONTEXT_CONFIG_ITEMS(Service)m4_dnl +m4_dnl +Socket.ListenStream, config_parse_socket_listen, 0, 0 +Socket.ListenDatagram, config_parse_socket_listen, 0, 0 +Socket.ListenSequentialPacket, config_parse_socket_listen, 0, 0 +Socket.ListenFIFO, config_parse_socket_listen, 0, 0 +Socket.ListenNetlink, config_parse_socket_listen, 0, 0 +Socket.ListenSpecial, config_parse_socket_listen, 0, 0 +Socket.ListenMessageQueue, config_parse_socket_listen, 0, 0 +Socket.BindIPv6Only, config_parse_socket_bind, 0, 0, +Socket.Backlog, config_parse_unsigned, 0, offsetof(Socket, backlog) +Socket.BindToDevice, config_parse_socket_bindtodevice, 0, 0 +Socket.ExecStartPre, config_parse_exec, SOCKET_EXEC_START_PRE, offsetof(Socket, exec_command) +Socket.ExecStartPost, config_parse_exec, SOCKET_EXEC_START_POST, offsetof(Socket, exec_command) +Socket.ExecStopPre, config_parse_exec, SOCKET_EXEC_STOP_PRE, offsetof(Socket, exec_command) +Socket.ExecStopPost, config_parse_exec, SOCKET_EXEC_STOP_POST, offsetof(Socket, exec_command) +Socket.TimeoutSec, config_parse_usec, 0, offsetof(Socket, timeout_usec) +Socket.DirectoryMode, config_parse_mode, 0, offsetof(Socket, directory_mode) +Socket.SocketMode, config_parse_mode, 0, offsetof(Socket, socket_mode) +Socket.Accept, config_parse_bool, 0, offsetof(Socket, accept) +Socket.MaxConnections, config_parse_unsigned, 0, offsetof(Socket, max_connections) +Socket.KeepAlive, config_parse_bool, 0, offsetof(Socket, keep_alive) +Socket.Priority, config_parse_int, 0, offsetof(Socket, priority) +Socket.ReceiveBuffer, config_parse_size, 0, offsetof(Socket, receive_buffer) +Socket.SendBuffer, config_parse_size, 0, offsetof(Socket, send_buffer) +Socket.IPTOS, config_parse_ip_tos, 0, offsetof(Socket, ip_tos) +Socket.IPTTL, config_parse_int, 0, offsetof(Socket, ip_ttl) +Socket.Mark, config_parse_int, 0, offsetof(Socket, mark) +Socket.PipeSize, config_parse_size, 0, offsetof(Socket, pipe_size) +Socket.FreeBind, config_parse_bool, 0, offsetof(Socket, free_bind) +Socket.Transparent, config_parse_bool, 0, offsetof(Socket, transparent) +Socket.Broadcast, config_parse_bool, 0, offsetof(Socket, broadcast) +Socket.TCPCongestion, config_parse_string, 0, offsetof(Socket, tcp_congestion) +Socket.MessageQueueMaxMessages, config_parse_long, 0, offsetof(Socket, mq_maxmsg) +Socket.MessageQueueMessageSize, config_parse_long, 0, offsetof(Socket, mq_msgsize) +Socket.Service, config_parse_socket_service, 0, 0 +EXEC_CONTEXT_CONFIG_ITEMS(Socket)m4_dnl +m4_dnl +Mount.What, config_parse_string, 0, offsetof(Mount, parameters_fragment.what) +Mount.Where, config_parse_path, 0, offsetof(Mount, where) +Mount.Options, config_parse_string, 0, offsetof(Mount, parameters_fragment.options) +Mount.Type, config_parse_string, 0, offsetof(Mount, parameters_fragment.fstype) +Mount.TimeoutSec, config_parse_usec, 0, offsetof(Mount, timeout_usec) +Mount.DirectoryMode, config_parse_mode, 0, offsetof(Mount, directory_mode) +EXEC_CONTEXT_CONFIG_ITEMS(Mount)m4_dnl +m4_dnl +Automount.Where, config_parse_path, 0, offsetof(Automount, where) +Automount.DirectoryMode, config_parse_mode, 0, offsetof(Automount, directory_mode) +m4_dnl +Swap.What, config_parse_path, 0, offsetof(Swap, parameters_fragment.what) +Swap.Priority, config_parse_int, 0, offsetof(Swap, parameters_fragment.priority) +Swap.TimeoutSec, config_parse_usec, 0, offsetof(Swap, timeout_usec) +EXEC_CONTEXT_CONFIG_ITEMS(Swap)m4_dnl +m4_dnl +Timer.OnActiveSec, config_parse_timer, 0, 0 +Timer.OnBootSec, config_parse_timer, 0, 0 +Timer.OnStartupSec, config_parse_timer, 0, 0 +Timer.OnUnitActiveSec, config_parse_timer, 0, 0 +Timer.OnUnitInactiveSec, config_parse_timer, 0, 0 +Timer.Unit, config_parse_timer_unit, 0, 0 +m4_dnl +Path.PathExists, config_parse_path_spec, 0, 0 +Path.PathExistsGlob, config_parse_path_spec, 0, 0 +Path.PathChanged, config_parse_path_spec, 0, 0 +Path.DirectoryNotEmpty, config_parse_path_spec, 0, 0 +Path.Unit, config_parse_path_unit, 0, 0 +Path.MakeDirectory, config_parse_bool, 0, offsetof(Path, make_directory) +Path.DirectoryMode, config_parse_mode, 0, offsetof(Path, directory_mode) +m4_dnl The [Install] section is ignored here. +Install.Alias, NULL, 0, 0 +Install.WantedBy, NULL, 0, 0 +Install.Also, NULL, 0, 0 diff --git a/src/load-fragment.c b/src/load-fragment.c index 5c1dff60b8..e448d04783 100644 --- a/src/load-fragment.c +++ b/src/load-fragment.c @@ -45,7 +45,7 @@ #include "bus-errors.h" #ifndef HAVE_SYSV_COMPAT -static int config_parse_warn_compat( +int config_parse_warn_compat( const char *filename, unsigned line, const char *section, @@ -60,7 +60,7 @@ static int config_parse_warn_compat( } #endif -static int config_parse_deps( +int config_parse_unit_deps( const char *filename, unsigned line, const char *section, @@ -70,7 +70,7 @@ static int config_parse_deps( void *data, void *userdata) { - UnitDependency d = PTR_TO_UINT(data); + UnitDependency d = ltype; Unit *u = userdata; char *w; size_t l; @@ -107,7 +107,7 @@ static int config_parse_deps( return 0; } -static int config_parse_names( +int config_parse_unit_names( const char *filename, unsigned line, const char *section, @@ -154,7 +154,7 @@ static int config_parse_names( return 0; } -static int config_parse_string_printf( +int config_parse_unit_string_printf( const char *filename, unsigned line, const char *section, @@ -188,7 +188,7 @@ static int config_parse_string_printf( return 0; } -static int config_parse_strv_printf( +int config_parse_unit_strv_printf( const char *filename, unsigned line, const char *section, @@ -217,7 +217,7 @@ static int config_parse_strv_printf( return r; } -static int config_parse_path_printf( +int config_parse_unit_path_printf( const char *filename, unsigned line, const char *section, @@ -254,7 +254,7 @@ static int config_parse_path_printf( return 0; } -static int config_parse_listen( +int config_parse_socket_listen( const char *filename, unsigned line, const char *section, @@ -365,7 +365,7 @@ static int config_parse_listen( return 0; } -static int config_parse_socket_bind( +int config_parse_socket_bind( const char *filename, unsigned line, const char *section, @@ -400,7 +400,7 @@ static int config_parse_socket_bind( return 0; } -static int config_parse_nice( +int config_parse_exec_nice( const char *filename, unsigned line, const char *section, @@ -434,7 +434,7 @@ static int config_parse_nice( return 0; } -static int config_parse_oom_score_adjust( +int config_parse_exec_oom_score_adjust( const char *filename, unsigned line, const char *section, @@ -468,42 +468,7 @@ static int config_parse_oom_score_adjust( return 0; } -static int config_parse_mode( - const char *filename, - unsigned line, - const char *section, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - mode_t *m = data; - long l; - char *x = NULL; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - errno = 0; - l = strtol(rvalue, &x, 8); - if (!x || *x || errno) { - log_error("[%s:%u] Failed to parse mode value, ignoring: %s", filename, line, rvalue); - return 0; - } - - if (l < 0000 || l > 07777) { - log_error("[%s:%u] mode value out of range, ignoring: %s", filename, line, rvalue); - return 0; - } - - *m = (mode_t) l; - return 0; -} - -static int config_parse_exec( +int config_parse_exec( const char *filename, unsigned line, const char *section, @@ -526,6 +491,8 @@ static int config_parse_exec( * alternatively an absolute prefixed with @ to allow * overriding of argv[0]. */ + e += ltype; + for (;;) { char *w; size_t l; @@ -621,35 +588,10 @@ fail: return -ENOMEM; } -static int config_parse_usec( - const char *filename, - unsigned line, - const char *section, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - usec_t *usec = data; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - if (parse_usec(rvalue, usec) < 0) { - log_error("[%s:%u] Failed to parse time value, ignoring: %s", filename, line, rvalue); - return 0; - } - - return 0; -} - -static DEFINE_CONFIG_PARSE_ENUM(config_parse_service_type, service_type, ServiceType, "Failed to parse service type"); -static DEFINE_CONFIG_PARSE_ENUM(config_parse_service_restart, service_restart, ServiceRestart, "Failed to parse service restart specifier"); +DEFINE_CONFIG_PARSE_ENUM(config_parse_service_type, service_type, ServiceType, "Failed to parse service type"); +DEFINE_CONFIG_PARSE_ENUM(config_parse_service_restart, service_restart, ServiceRestart, "Failed to parse service restart specifier"); -static int config_parse_bindtodevice( +int config_parse_socket_bindtodevice( const char *filename, unsigned line, const char *section, @@ -679,10 +621,10 @@ static int config_parse_bindtodevice( return 0; } -static DEFINE_CONFIG_PARSE_ENUM(config_parse_output, exec_output, ExecOutput, "Failed to parse output specifier"); -static DEFINE_CONFIG_PARSE_ENUM(config_parse_input, exec_input, ExecInput, "Failed to parse input specifier"); +DEFINE_CONFIG_PARSE_ENUM(config_parse_output, exec_output, ExecOutput, "Failed to parse output specifier"); +DEFINE_CONFIG_PARSE_ENUM(config_parse_input, exec_input, ExecInput, "Failed to parse input specifier"); -static int config_parse_facility( +int config_parse_facility( const char *filename, unsigned line, const char *section, @@ -710,7 +652,7 @@ static int config_parse_facility( return 0; } -static int config_parse_level( +int config_parse_level( const char *filename, unsigned line, const char *section, @@ -737,7 +679,7 @@ static int config_parse_level( return 0; } -static int config_parse_io_class( +int config_parse_exec_io_class( const char *filename, unsigned line, const char *section, @@ -766,7 +708,7 @@ static int config_parse_io_class( return 0; } -static int config_parse_io_priority( +int config_parse_exec_io_priority( const char *filename, unsigned line, const char *section, @@ -795,7 +737,7 @@ static int config_parse_io_priority( return 0; } -static int config_parse_cpu_sched_policy( +int config_parse_exec_cpu_sched_policy( const char *filename, unsigned line, const char *section, @@ -825,7 +767,7 @@ static int config_parse_cpu_sched_policy( return 0; } -static int config_parse_cpu_sched_prio( +int config_parse_exec_cpu_sched_prio( const char *filename, unsigned line, const char *section, @@ -855,7 +797,7 @@ static int config_parse_cpu_sched_prio( return 0; } -static int config_parse_cpu_affinity( +int config_parse_exec_cpu_affinity( const char *filename, unsigned line, const char *section, @@ -901,7 +843,7 @@ static int config_parse_cpu_affinity( return 0; } -static int config_parse_capabilities( +int config_parse_exec_capabilities( const char *filename, unsigned line, const char *section, @@ -934,7 +876,7 @@ static int config_parse_capabilities( return 0; } -static int config_parse_secure_bits( +int config_parse_exec_secure_bits( const char *filename, unsigned line, const char *section, @@ -976,7 +918,7 @@ static int config_parse_secure_bits( return 0; } -static int config_parse_bounding_set( +int config_parse_exec_bounding_set( const char *filename, unsigned line, const char *section, @@ -1035,7 +977,7 @@ static int config_parse_bounding_set( return 0; } -static int config_parse_timer_slack_nsec( +int config_parse_exec_timer_slack_nsec( const char *filename, unsigned line, const char *section, @@ -1063,7 +1005,7 @@ static int config_parse_timer_slack_nsec( return 0; } -static int config_parse_limit( +int config_parse_limit( const char *filename, unsigned line, const char *section, @@ -1081,6 +1023,8 @@ static int config_parse_limit( assert(rvalue); assert(data); + rl += ltype; + if (streq(rvalue, "infinity")) u = (unsigned long long) RLIM_INFINITY; else if (safe_atollu(rvalue, &u) < 0) { @@ -1096,7 +1040,7 @@ static int config_parse_limit( return 0; } -static int config_parse_cgroup( +int config_parse_unit_cgroup( const char *filename, unsigned line, const char *section, @@ -1144,7 +1088,7 @@ static int config_parse_cgroup( } #ifdef HAVE_SYSV_COMPAT -static int config_parse_sysv_priority( +int config_parse_sysv_priority( const char *filename, unsigned line, const char *section, @@ -1172,7 +1116,7 @@ static int config_parse_sysv_priority( } #endif -static int config_parse_fsck_passno( +int config_parse_fsck_passno( const char *filename, unsigned line, const char *section, @@ -1199,9 +1143,9 @@ static int config_parse_fsck_passno( return 0; } -static DEFINE_CONFIG_PARSE_ENUM(config_parse_kill_mode, kill_mode, KillMode, "Failed to parse kill mode"); +DEFINE_CONFIG_PARSE_ENUM(config_parse_kill_mode, kill_mode, KillMode, "Failed to parse kill mode"); -static int config_parse_kill_signal( +int config_parse_kill_signal( const char *filename, unsigned line, const char *section, @@ -1228,7 +1172,7 @@ static int config_parse_kill_signal( return 0; } -static int config_parse_mount_flags( +int config_parse_exec_mount_flags( const char *filename, unsigned line, const char *section, @@ -1266,7 +1210,7 @@ static int config_parse_mount_flags( return 0; } -static int config_parse_timer( +int config_parse_timer( const char *filename, unsigned line, const char *section, @@ -1307,7 +1251,7 @@ static int config_parse_timer( return 0; } -static int config_parse_timer_unit( +int config_parse_timer_unit( const char *filename, unsigned line, const char *section, @@ -1342,7 +1286,7 @@ static int config_parse_timer_unit( return 0; } -static int config_parse_path_spec( +int config_parse_path_spec( const char *filename, unsigned line, const char *section, @@ -1389,7 +1333,7 @@ static int config_parse_path_spec( return 0; } -static int config_parse_path_unit( +int config_parse_path_unit( const char *filename, unsigned line, const char *section, @@ -1424,7 +1368,7 @@ static int config_parse_path_unit( return 0; } -static int config_parse_socket_service( +int config_parse_socket_service( const char *filename, unsigned line, const char *section, @@ -1459,7 +1403,7 @@ static int config_parse_socket_service( return 0; } -static int config_parse_service_sockets( +int config_parse_service_sockets( const char *filename, unsigned line, const char *section, @@ -1514,7 +1458,7 @@ static int config_parse_service_sockets( return 0; } -static int config_parse_env_file( +int config_parse_unit_env_file( const char *filename, unsigned line, const char *section, @@ -1554,7 +1498,7 @@ static int config_parse_env_file( return 0; } -static int config_parse_ip_tos( +int config_parse_ip_tos( const char *filename, unsigned line, const char *section, @@ -1581,7 +1525,7 @@ static int config_parse_ip_tos( return 0; } -static int config_parse_condition_path( +int config_parse_unit_condition_path( const char *filename, unsigned line, const char *section, @@ -1619,7 +1563,7 @@ static int config_parse_condition_path( return 0; } -static int config_parse_condition_string( +int config_parse_unit_condition_string( const char *filename, unsigned line, const char *section, @@ -1652,7 +1596,7 @@ static int config_parse_condition_string( return 0; } -static int config_parse_condition_null( +int config_parse_unit_condition_null( const char *filename, unsigned line, const char *section, @@ -1693,7 +1637,7 @@ static int config_parse_condition_null( return 0; } -static DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier"); +DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier"); #define FOLLOW_MAX 8 @@ -1807,313 +1751,7 @@ static int merge_by_names(Unit **u, Set *names, const char *id) { return 0; } -static void dump_items(FILE *f, const ConfigItem *items) { - const ConfigItem *i; - const char *prev_section = NULL; - bool not_first = false; - - struct { - ConfigParserCallback callback; - const char *rvalue; - } table[] = { - { config_parse_int, "INTEGER" }, - { config_parse_unsigned, "UNSIGNED" }, - { config_parse_size, "SIZE" }, - { config_parse_bool, "BOOLEAN" }, - { config_parse_string, "STRING" }, - { config_parse_path, "PATH" }, - { config_parse_path_printf, "PATH" }, - { config_parse_strv, "STRING [...]" }, - { config_parse_nice, "NICE" }, - { config_parse_oom_score_adjust, "OOMSCOREADJUST" }, - { config_parse_io_class, "IOCLASS" }, - { config_parse_io_priority, "IOPRIORITY" }, - { config_parse_cpu_sched_policy, "CPUSCHEDPOLICY" }, - { config_parse_cpu_sched_prio, "CPUSCHEDPRIO" }, - { config_parse_cpu_affinity, "CPUAFFINITY" }, - { config_parse_mode, "MODE" }, - { config_parse_env_file, "FILE" }, - { config_parse_output, "OUTPUT" }, - { config_parse_input, "INPUT" }, - { config_parse_facility, "FACILITY" }, - { config_parse_level, "LEVEL" }, - { config_parse_capabilities, "CAPABILITIES" }, - { config_parse_secure_bits, "SECUREBITS" }, - { config_parse_bounding_set, "BOUNDINGSET" }, - { config_parse_timer_slack_nsec, "TIMERSLACK" }, - { config_parse_limit, "LIMIT" }, - { config_parse_cgroup, "CGROUP [...]" }, - { config_parse_deps, "UNIT [...]" }, - { config_parse_names, "UNIT [...]" }, - { config_parse_exec, "PATH [ARGUMENT [...]]" }, - { config_parse_service_type, "SERVICETYPE" }, - { config_parse_service_restart, "SERVICERESTART" }, -#ifdef HAVE_SYSV_COMPAT - { config_parse_sysv_priority, "SYSVPRIORITY" }, -#else - { config_parse_warn_compat, "NOTSUPPORTED" }, -#endif - { config_parse_kill_mode, "KILLMODE" }, - { config_parse_kill_signal, "SIGNAL" }, - { config_parse_listen, "SOCKET [...]" }, - { config_parse_socket_bind, "SOCKETBIND" }, - { config_parse_bindtodevice, "NETWORKINTERFACE" }, - { config_parse_usec, "SECONDS" }, - { config_parse_path_strv, "PATH [...]" }, - { config_parse_mount_flags, "MOUNTFLAG [...]" }, - { config_parse_string_printf, "STRING" }, - { config_parse_timer, "TIMER" }, - { config_parse_timer_unit, "NAME" }, - { config_parse_path_spec, "PATH" }, - { config_parse_path_unit, "UNIT" }, - { config_parse_notify_access, "ACCESS" }, - { config_parse_ip_tos, "TOS" }, - { config_parse_condition_path, "CONDITION" }, - { config_parse_condition_string, "CONDITION" }, - { config_parse_condition_null, "CONDITION" }, - }; - - assert(f); - assert(items); - - for (i = items; i->lvalue; i++) { - unsigned j; - const char *rvalue = "OTHER"; - - if (!streq_ptr(i->section, prev_section)) { - if (!not_first) - not_first = true; - else - fputc('\n', f); - - fprintf(f, "[%s]\n", i->section); - prev_section = i->section; - } - - for (j = 0; j < ELEMENTSOF(table); j++) - if (i->parse == table[j].callback) { - rvalue = table[j].rvalue; - break; - } - - fprintf(f, "%s=%s\n", i->lvalue, rvalue); - } -} - static int load_from_path(Unit *u, const char *path) { - - static const char* const section_table[_UNIT_TYPE_MAX] = { - [UNIT_SERVICE] = "Service", - [UNIT_TIMER] = "Timer", - [UNIT_SOCKET] = "Socket", - [UNIT_TARGET] = "Target", - [UNIT_DEVICE] = "Device", - [UNIT_MOUNT] = "Mount", - [UNIT_AUTOMOUNT] = "Automount", - [UNIT_SNAPSHOT] = "Snapshot", - [UNIT_SWAP] = "Swap", - [UNIT_PATH] = "Path" - }; - -#define EXEC_CONTEXT_CONFIG_ITEMS(context, section) \ - { "WorkingDirectory", config_parse_path_printf, 0, &(context).working_directory, section }, \ - { "RootDirectory", config_parse_path_printf, 0, &(context).root_directory, section }, \ - { "User", config_parse_string_printf, 0, &(context).user, section }, \ - { "Group", config_parse_string_printf, 0, &(context).group, section }, \ - { "SupplementaryGroups", config_parse_strv, 0, &(context).supplementary_groups, section }, \ - { "Nice", config_parse_nice, 0, &(context), section }, \ - { "OOMScoreAdjust", config_parse_oom_score_adjust,0, &(context), section }, \ - { "IOSchedulingClass", config_parse_io_class, 0, &(context), section }, \ - { "IOSchedulingPriority", config_parse_io_priority, 0, &(context), section }, \ - { "CPUSchedulingPolicy", config_parse_cpu_sched_policy,0, &(context), section }, \ - { "CPUSchedulingPriority", config_parse_cpu_sched_prio, 0, &(context), section }, \ - { "CPUSchedulingResetOnFork", config_parse_bool, 0, &(context).cpu_sched_reset_on_fork, section }, \ - { "CPUAffinity", config_parse_cpu_affinity, 0, &(context), section }, \ - { "UMask", config_parse_mode, 0, &(context).umask, section }, \ - { "Environment", config_parse_strv_printf, 0, &(context).environment, section }, \ - { "EnvironmentFile", config_parse_env_file, 0, &(context).environment_files, section }, \ - { "StandardInput", config_parse_input, 0, &(context).std_input, section }, \ - { "StandardOutput", config_parse_output, 0, &(context).std_output, section }, \ - { "StandardError", config_parse_output, 0, &(context).std_error, section }, \ - { "TTYPath", config_parse_path_printf, 0, &(context).tty_path, section }, \ - { "TTYReset", config_parse_bool, 0, &(context).tty_reset, section }, \ - { "TTYVHangup", config_parse_bool, 0, &(context).tty_vhangup, section }, \ - { "TTYVTDisallocate", config_parse_bool, 0, &(context).tty_vt_disallocate, section }, \ - { "SyslogIdentifier", config_parse_string_printf, 0, &(context).syslog_identifier, section }, \ - { "SyslogFacility", config_parse_facility, 0, &(context).syslog_priority, section }, \ - { "SyslogLevel", config_parse_level, 0, &(context).syslog_priority, section }, \ - { "SyslogLevelPrefix", config_parse_bool, 0, &(context).syslog_level_prefix, section }, \ - { "Capabilities", config_parse_capabilities, 0, &(context), section }, \ - { "SecureBits", config_parse_secure_bits, 0, &(context), section }, \ - { "CapabilityBoundingSet", config_parse_bounding_set, 0, &(context), section }, \ - { "TimerSlackNSec", config_parse_timer_slack_nsec,0, &(context), section }, \ - { "LimitCPU", config_parse_limit, 0, &(context).rlimit[RLIMIT_CPU], section }, \ - { "LimitFSIZE", config_parse_limit, 0, &(context).rlimit[RLIMIT_FSIZE], section }, \ - { "LimitDATA", config_parse_limit, 0, &(context).rlimit[RLIMIT_DATA], section }, \ - { "LimitSTACK", config_parse_limit, 0, &(context).rlimit[RLIMIT_STACK], section }, \ - { "LimitCORE", config_parse_limit, 0, &(context).rlimit[RLIMIT_CORE], section }, \ - { "LimitRSS", config_parse_limit, 0, &(context).rlimit[RLIMIT_RSS], section }, \ - { "LimitNOFILE", config_parse_limit, 0, &(context).rlimit[RLIMIT_NOFILE], section }, \ - { "LimitAS", config_parse_limit, 0, &(context).rlimit[RLIMIT_AS], section }, \ - { "LimitNPROC", config_parse_limit, 0, &(context).rlimit[RLIMIT_NPROC], section }, \ - { "LimitMEMLOCK", config_parse_limit, 0, &(context).rlimit[RLIMIT_MEMLOCK], section }, \ - { "LimitLOCKS", config_parse_limit, 0, &(context).rlimit[RLIMIT_LOCKS], section }, \ - { "LimitSIGPENDING", config_parse_limit, 0, &(context).rlimit[RLIMIT_SIGPENDING], section }, \ - { "LimitMSGQUEUE", config_parse_limit, 0, &(context).rlimit[RLIMIT_MSGQUEUE], section }, \ - { "LimitNICE", config_parse_limit, 0, &(context).rlimit[RLIMIT_NICE], section }, \ - { "LimitRTPRIO", config_parse_limit, 0, &(context).rlimit[RLIMIT_RTPRIO], section }, \ - { "LimitRTTIME", config_parse_limit, 0, &(context).rlimit[RLIMIT_RTTIME], section }, \ - { "ControlGroup", config_parse_cgroup, 0, u, section }, \ - { "ReadWriteDirectories", config_parse_path_strv, 0, &(context).read_write_dirs, section }, \ - { "ReadOnlyDirectories", config_parse_path_strv, 0, &(context).read_only_dirs, section }, \ - { "InaccessibleDirectories",config_parse_path_strv, 0, &(context).inaccessible_dirs, section }, \ - { "PrivateTmp", config_parse_bool, 0, &(context).private_tmp, section }, \ - { "MountFlags", config_parse_mount_flags, 0, &(context), section }, \ - { "TCPWrapName", config_parse_string_printf, 0, &(context).tcpwrap_name, section }, \ - { "PAMName", config_parse_string_printf, 0, &(context).pam_name, section }, \ - { "KillMode", config_parse_kill_mode, 0, &(context).kill_mode, section }, \ - { "KillSignal", config_parse_kill_signal, 0, &(context).kill_signal, section }, \ - { "SendSIGKILL", config_parse_bool, 0, &(context).send_sigkill, section }, \ - { "UtmpIdentifier", config_parse_string_printf, 0, &(context).utmp_id, section }, \ - { "ControlGroupModify", config_parse_bool, 0, &(context).control_group_modify, section } - - const ConfigItem items[] = { - { "Names", config_parse_names, 0, u, "Unit" }, - { "Description", config_parse_string_printf, 0, &u->meta.description, "Unit" }, - { "Requires", config_parse_deps, 0, UINT_TO_PTR(UNIT_REQUIRES), "Unit" }, - { "RequiresOverridable", config_parse_deps, 0, UINT_TO_PTR(UNIT_REQUIRES_OVERRIDABLE), "Unit" }, - { "Requisite", config_parse_deps, 0, UINT_TO_PTR(UNIT_REQUISITE), "Unit" }, - { "RequisiteOverridable", config_parse_deps, 0, UINT_TO_PTR(UNIT_REQUISITE_OVERRIDABLE), "Unit" }, - { "Wants", config_parse_deps, 0, UINT_TO_PTR(UNIT_WANTS), "Unit" }, - { "BindTo", config_parse_deps, 0, UINT_TO_PTR(UNIT_BIND_TO), "Unit" }, - { "Conflicts", config_parse_deps, 0, UINT_TO_PTR(UNIT_CONFLICTS), "Unit" }, - { "Before", config_parse_deps, 0, UINT_TO_PTR(UNIT_BEFORE), "Unit" }, - { "After", config_parse_deps, 0, UINT_TO_PTR(UNIT_AFTER), "Unit" }, - { "OnFailure", config_parse_deps, 0, UINT_TO_PTR(UNIT_ON_FAILURE), "Unit" }, - { "StopWhenUnneeded", config_parse_bool, 0, &u->meta.stop_when_unneeded, "Unit" }, - { "RefuseManualStart", config_parse_bool, 0, &u->meta.refuse_manual_start, "Unit" }, - { "RefuseManualStop", config_parse_bool, 0, &u->meta.refuse_manual_stop, "Unit" }, - { "AllowIsolate", config_parse_bool, 0, &u->meta.allow_isolate, "Unit" }, - { "DefaultDependencies", config_parse_bool, 0, &u->meta.default_dependencies, "Unit" }, - { "OnFailureIsolate", config_parse_bool, 0, &u->meta.on_failure_isolate, "Unit" }, - { "IgnoreOnIsolate", config_parse_bool, 0, &u->meta.ignore_on_isolate, "Unit" }, - { "IgnoreOnSnapshot", config_parse_bool, 0, &u->meta.ignore_on_snapshot, "Unit" }, - { "JobTimeoutSec", config_parse_usec, 0, &u->meta.job_timeout, "Unit" }, - { "ConditionPathExists", config_parse_condition_path, CONDITION_PATH_EXISTS, u, "Unit" }, - { "ConditionPathExistsGlob", config_parse_condition_path, CONDITION_PATH_EXISTS_GLOB, u, "Unit" }, - { "ConditionPathIsDirectory", config_parse_condition_path, CONDITION_PATH_IS_DIRECTORY, u, "Unit" }, - { "ConditionDirectoryNotEmpty", config_parse_condition_path, CONDITION_DIRECTORY_NOT_EMPTY, u, "Unit" }, - { "ConditionFileIsExecutable", config_parse_condition_path, CONDITION_FILE_IS_EXECUTABLE, u, "Unit" }, - { "ConditionKernelCommandLine", config_parse_condition_string, CONDITION_KERNEL_COMMAND_LINE, u, "Unit" }, - { "ConditionVirtualization", config_parse_condition_string, CONDITION_VIRTUALIZATION, u, "Unit" }, - { "ConditionSecurity", config_parse_condition_string, CONDITION_SECURITY, u, "Unit" }, - { "ConditionNull", config_parse_condition_null, 0, u, "Unit" }, - - { "PIDFile", config_parse_path_printf, 0, &u->service.pid_file, "Service" }, - { "ExecStartPre", config_parse_exec, 0, u->service.exec_command+SERVICE_EXEC_START_PRE, "Service" }, - { "ExecStart", config_parse_exec, 0, u->service.exec_command+SERVICE_EXEC_START, "Service" }, - { "ExecStartPost", config_parse_exec, 0, u->service.exec_command+SERVICE_EXEC_START_POST, "Service" }, - { "ExecReload", config_parse_exec, 0, u->service.exec_command+SERVICE_EXEC_RELOAD, "Service" }, - { "ExecStop", config_parse_exec, 0, u->service.exec_command+SERVICE_EXEC_STOP, "Service" }, - { "ExecStopPost", config_parse_exec, 0, u->service.exec_command+SERVICE_EXEC_STOP_POST, "Service" }, - { "RestartSec", config_parse_usec, 0, &u->service.restart_usec, "Service" }, - { "TimeoutSec", config_parse_usec, 0, &u->service.timeout_usec, "Service" }, - { "Type", config_parse_service_type, 0, &u->service.type, "Service" }, - { "Restart", config_parse_service_restart, 0, &u->service.restart, "Service" }, - { "PermissionsStartOnly", config_parse_bool, 0, &u->service.permissions_start_only, "Service" }, - { "RootDirectoryStartOnly", config_parse_bool, 0, &u->service.root_directory_start_only, "Service" }, - { "RemainAfterExit", config_parse_bool, 0, &u->service.remain_after_exit, "Service" }, - { "GuessMainPID", config_parse_bool, 0, &u->service.guess_main_pid, "Service" }, -#ifdef HAVE_SYSV_COMPAT - { "SysVStartPriority", config_parse_sysv_priority, 0, &u->service.sysv_start_priority, "Service" }, -#else - { "SysVStartPriority", config_parse_warn_compat, 0, NULL, "Service" }, -#endif - { "NonBlocking", config_parse_bool, 0, &u->service.exec_context.non_blocking, "Service" }, - { "BusName", config_parse_string_printf, 0, &u->service.bus_name, "Service" }, - { "NotifyAccess", config_parse_notify_access, 0, &u->service.notify_access, "Service" }, - { "Sockets", config_parse_service_sockets, 0, &u->service, "Service" }, - { "FsckPassNo", config_parse_fsck_passno, 0, &u->service.fsck_passno, "Service" }, - EXEC_CONTEXT_CONFIG_ITEMS(u->service.exec_context, "Service"), - - { "ListenStream", config_parse_listen, 0, &u->socket, "Socket" }, - { "ListenDatagram", config_parse_listen, 0, &u->socket, "Socket" }, - { "ListenSequentialPacket", config_parse_listen, 0, &u->socket, "Socket" }, - { "ListenFIFO", config_parse_listen, 0, &u->socket, "Socket" }, - { "ListenNetlink", config_parse_listen, 0, &u->socket, "Socket" }, - { "ListenSpecial", config_parse_listen, 0, &u->socket, "Socket" }, - { "ListenMessageQueue", config_parse_listen, 0, &u->socket, "Socket" }, - { "BindIPv6Only", config_parse_socket_bind, 0, &u->socket, "Socket" }, - { "Backlog", config_parse_unsigned, 0, &u->socket.backlog, "Socket" }, - { "BindToDevice", config_parse_bindtodevice, 0, &u->socket, "Socket" }, - { "ExecStartPre", config_parse_exec, 0, u->socket.exec_command+SOCKET_EXEC_START_PRE, "Socket" }, - { "ExecStartPost", config_parse_exec, 0, u->socket.exec_command+SOCKET_EXEC_START_POST, "Socket" }, - { "ExecStopPre", config_parse_exec, 0, u->socket.exec_command+SOCKET_EXEC_STOP_PRE, "Socket" }, - { "ExecStopPost", config_parse_exec, 0, u->socket.exec_command+SOCKET_EXEC_STOP_POST, "Socket" }, - { "TimeoutSec", config_parse_usec, 0, &u->socket.timeout_usec, "Socket" }, - { "DirectoryMode", config_parse_mode, 0, &u->socket.directory_mode, "Socket" }, - { "SocketMode", config_parse_mode, 0, &u->socket.socket_mode, "Socket" }, - { "Accept", config_parse_bool, 0, &u->socket.accept, "Socket" }, - { "MaxConnections", config_parse_unsigned, 0, &u->socket.max_connections, "Socket" }, - { "KeepAlive", config_parse_bool, 0, &u->socket.keep_alive, "Socket" }, - { "Priority", config_parse_int, 0, &u->socket.priority, "Socket" }, - { "ReceiveBuffer", config_parse_size, 0, &u->socket.receive_buffer, "Socket" }, - { "SendBuffer", config_parse_size, 0, &u->socket.send_buffer, "Socket" }, - { "IPTOS", config_parse_ip_tos, 0, &u->socket.ip_tos, "Socket" }, - { "IPTTL", config_parse_int, 0, &u->socket.ip_ttl, "Socket" }, - { "Mark", config_parse_int, 0, &u->socket.mark, "Socket" }, - { "PipeSize", config_parse_size, 0, &u->socket.pipe_size, "Socket" }, - { "FreeBind", config_parse_bool, 0, &u->socket.free_bind, "Socket" }, - { "Transparent", config_parse_bool, 0, &u->socket.transparent, "Socket" }, - { "Broadcast", config_parse_bool, 0, &u->socket.broadcast, "Socket" }, - { "TCPCongestion", config_parse_string, 0, &u->socket.tcp_congestion, "Socket" }, - { "MessageQueueMaxMessages", config_parse_long, 0, &u->socket.mq_maxmsg, "Socket" }, - { "MessageQueueMessageSize", config_parse_long, 0, &u->socket.mq_msgsize, "Socket" }, - { "Service", config_parse_socket_service, 0, &u->socket, "Socket" }, - EXEC_CONTEXT_CONFIG_ITEMS(u->socket.exec_context, "Socket"), - - { "What", config_parse_string, 0, &u->mount.parameters_fragment.what, "Mount" }, - { "Where", config_parse_path, 0, &u->mount.where, "Mount" }, - { "Options", config_parse_string, 0, &u->mount.parameters_fragment.options, "Mount" }, - { "Type", config_parse_string, 0, &u->mount.parameters_fragment.fstype, "Mount" }, - { "TimeoutSec", config_parse_usec, 0, &u->mount.timeout_usec, "Mount" }, - { "DirectoryMode", config_parse_mode, 0, &u->mount.directory_mode, "Mount" }, - EXEC_CONTEXT_CONFIG_ITEMS(u->mount.exec_context, "Mount"), - - { "Where", config_parse_path, 0, &u->automount.where, "Automount" }, - { "DirectoryMode", config_parse_mode, 0, &u->automount.directory_mode, "Automount" }, - - { "What", config_parse_path, 0, &u->swap.parameters_fragment.what, "Swap" }, - { "Priority", config_parse_int, 0, &u->swap.parameters_fragment.priority, "Swap" }, - { "TimeoutSec", config_parse_usec, 0, &u->swap.timeout_usec, "Swap" }, - EXEC_CONTEXT_CONFIG_ITEMS(u->swap.exec_context, "Swap"), - - { "OnActiveSec", config_parse_timer, 0, &u->timer, "Timer" }, - { "OnBootSec", config_parse_timer, 0, &u->timer, "Timer" }, - { "OnStartupSec", config_parse_timer, 0, &u->timer, "Timer" }, - { "OnUnitActiveSec", config_parse_timer, 0, &u->timer, "Timer" }, - { "OnUnitInactiveSec", config_parse_timer, 0, &u->timer, "Timer" }, - { "Unit", config_parse_timer_unit, 0, &u->timer, "Timer" }, - - { "PathExists", config_parse_path_spec, 0, &u->path, "Path" }, - { "PathExistsGlob", config_parse_path_spec, 0, &u->path, "Path" }, - { "PathChanged", config_parse_path_spec, 0, &u->path, "Path" }, - { "DirectoryNotEmpty", config_parse_path_spec, 0, &u->path, "Path" }, - { "Unit", config_parse_path_unit, 0, &u->path, "Path" }, - { "MakeDirectory", config_parse_bool, 0, &u->path.make_directory, "Path" }, - { "DirectoryMode", config_parse_mode, 0, &u->path.directory_mode, "Path" }, - - /* The [Install] section is ignored here. */ - { "Alias", NULL, 0, NULL, "Install" }, - { "WantedBy", NULL, 0, NULL, "Install" }, - { "Also", NULL, 0, NULL, "Install" }, - - { NULL, NULL, 0, NULL, NULL } - }; - -#undef EXEC_CONTEXT_CONFIG_ITEMS - - const char *sections[4]; int r; Set *symlink_names; FILE *f = NULL; @@ -2121,21 +1759,11 @@ static int load_from_path(Unit *u, const char *path) { Unit *merged; struct stat st; - if (!u) { - /* Dirty dirty hack. */ - dump_items((FILE*) path, items); - return 0; - } - assert(u); assert(path); - sections[0] = "Unit"; - sections[1] = section_table[u->meta.type]; - sections[2] = "Install"; - sections[3] = NULL; - - if (!(symlink_names = set_new(string_hash_func, string_compare_func))) + symlink_names = set_new(string_hash_func, string_compare_func); + if (!symlink_names) return -ENOMEM; if (path_is_absolute(path)) { @@ -2218,7 +1846,8 @@ static int load_from_path(Unit *u, const char *path) { u->meta.load_state = UNIT_MASKED; else { /* Now, parse the file contents */ - if ((r = config_parse(filename, f, sections, items, false, u)) < 0) + r = config_parse(filename, f, UNIT_VTABLE(u)->sections, config_item_perf_lookup, (void*) load_fragment_gperf_lookup, false, u); + if (r < 0) goto finish; u->meta.load_state = UNIT_LOADED; @@ -2323,7 +1952,100 @@ int unit_load_fragment(Unit *u) { } void unit_dump_config_items(FILE *f) { - /* OK, this wins a prize for extreme ugliness. */ + static const struct { + const ConfigParserCallback callback; + const char *rvalue; + } table[] = { + { config_parse_int, "INTEGER" }, + { config_parse_unsigned, "UNSIGNED" }, + { config_parse_size, "SIZE" }, + { config_parse_bool, "BOOLEAN" }, + { config_parse_string, "STRING" }, + { config_parse_path, "PATH" }, + { config_parse_unit_path_printf, "PATH" }, + { config_parse_strv, "STRING [...]" }, + { config_parse_exec_nice, "NICE" }, + { config_parse_exec_oom_score_adjust, "OOMSCOREADJUST" }, + { config_parse_exec_io_class, "IOCLASS" }, + { config_parse_exec_io_priority, "IOPRIORITY" }, + { config_parse_exec_cpu_sched_policy, "CPUSCHEDPOLICY" }, + { config_parse_exec_cpu_sched_prio, "CPUSCHEDPRIO" }, + { config_parse_exec_cpu_affinity, "CPUAFFINITY" }, + { config_parse_mode, "MODE" }, + { config_parse_unit_env_file, "FILE" }, + { config_parse_output, "OUTPUT" }, + { config_parse_input, "INPUT" }, + { config_parse_facility, "FACILITY" }, + { config_parse_level, "LEVEL" }, + { config_parse_exec_capabilities, "CAPABILITIES" }, + { config_parse_exec_secure_bits, "SECUREBITS" }, + { config_parse_exec_bounding_set, "BOUNDINGSET" }, + { config_parse_exec_timer_slack_nsec, "TIMERSLACK" }, + { config_parse_limit, "LIMIT" }, + { config_parse_unit_cgroup, "CGROUP [...]" }, + { config_parse_unit_deps, "UNIT [...]" }, + { config_parse_unit_names, "UNIT [...]" }, + { config_parse_exec, "PATH [ARGUMENT [...]]" }, + { config_parse_service_type, "SERVICETYPE" }, + { config_parse_service_restart, "SERVICERESTART" }, +#ifdef HAVE_SYSV_COMPAT + { config_parse_sysv_priority, "SYSVPRIORITY" }, +#else + { config_parse_warn_compat, "NOTSUPPORTED" }, +#endif + { config_parse_kill_mode, "KILLMODE" }, + { config_parse_kill_signal, "SIGNAL" }, + { config_parse_socket_listen, "SOCKET [...]" }, + { config_parse_socket_bind, "SOCKETBIND" }, + { config_parse_socket_bindtodevice, "NETWORKINTERFACE" }, + { config_parse_usec, "SECONDS" }, + { config_parse_path_strv, "PATH [...]" }, + { config_parse_exec_mount_flags, "MOUNTFLAG [...]" }, + { config_parse_unit_string_printf, "STRING" }, + { config_parse_timer, "TIMER" }, + { config_parse_timer_unit, "NAME" }, + { config_parse_path_spec, "PATH" }, + { config_parse_path_unit, "UNIT" }, + { config_parse_notify_access, "ACCESS" }, + { config_parse_ip_tos, "TOS" }, + { config_parse_unit_condition_path, "CONDITION" }, + { config_parse_unit_condition_string, "CONDITION" }, + { config_parse_unit_condition_null, "CONDITION" }, + }; + + const char *prev = NULL; + const char *i; + + assert(f); - load_from_path(NULL, (const void*) f); + NULSTR_FOREACH(i, load_fragment_gperf_nulstr) { + const char *rvalue = "OTHER", *lvalue; + unsigned j; + size_t prefix_len; + const char *dot; + const ConfigPerfItem *p; + + assert_se(p = load_fragment_gperf_lookup(i, strlen(i))); + + dot = strchr(i, '.'); + lvalue = dot ? dot + 1 : i; + prefix_len = dot-i; + + if (dot) + if (!prev || strncmp(prev, i, prefix_len+1) != 0) { + if (prev) + fputc('\n', f); + + fprintf(f, "[%.*s]\n", (int) prefix_len, i); + } + + for (j = 0; j < ELEMENTSOF(table); j++) + if (p->parse == table[j].callback) { + rvalue = table[j].rvalue; + break; + } + + fprintf(f, "%s=%s\n", lvalue, rvalue); + prev = i; + } } diff --git a/src/load-fragment.h b/src/load-fragment.h index bccfb11a7f..a59046d794 100644 --- a/src/load-fragment.h +++ b/src/load-fragment.h @@ -30,4 +30,55 @@ int unit_load_fragment(Unit *u); void unit_dump_config_items(FILE *f); +int config_parse_warn_compat(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_unit_deps(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_unit_names(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_unit_string_printf(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_unit_strv_printf(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_unit_path_printf(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_socket_listen(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_socket_bind(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_exec_nice(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_exec_oom_score_adjust(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_exec(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_service_type(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_service_restart(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_socket_bindtodevice(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_output(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_input(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_facility(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_level(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_exec_io_class(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_exec_io_priority(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_exec_cpu_sched_policy(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_exec_cpu_sched_prio(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_exec_cpu_affinity(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_exec_capabilities(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_exec_secure_bits(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_exec_bounding_set(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_exec_timer_slack_nsec(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_limit(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_unit_cgroup(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_sysv_priority(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_fsck_passno(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_kill_signal(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_exec_mount_flags(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_timer(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_timer_unit(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_path_spec(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_path_unit(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_socket_service(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_service_sockets(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_unit_env_file(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_ip_tos(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_unit_condition_path(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_unit_condition_string(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_unit_condition_null(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_kill_mode(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_notify_access(const char *filename, unsigned line, const char *section, 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); +extern const char load_fragment_gperf_nulstr[]; + #endif diff --git a/src/logind-gperf.gperf b/src/logind-gperf.gperf new file mode 100644 index 0000000000..940fe10e89 --- /dev/null +++ b/src/logind-gperf.gperf @@ -0,0 +1,22 @@ +%{ +#include +#include "conf-parser.h" +#include "logind.h" +%} +struct ConfigPerfItem; +%null_strings +%language=ANSI-C +%define slot-name section_and_lvalue +%define hash-function-name logind_gperf_hash +%define lookup-function-name logind_gperf_lookup +%readonly-tables +%omit-struct-type +%struct-type +%includes +%% +Login.NAutoVTs, config_parse_unsigned, 0, offsetof(Manager, n_autovts) +Login.KillUserProcesses, config_parse_bool, 0, offsetof(Manager, kill_user_processes) +Login.KillOnlyUsers, config_parse_strv, 0, offsetof(Manager, kill_only_users) +Login.KillExcludeUsers, config_parse_strv, 0, offsetof(Manager, kill_exclude_users) +Login.Controllers, config_parse_strv, 0, offsetof(Manager, controllers) +Login.ResetControllers, config_parse_strv, 0, offsetof(Manager, reset_controllers) diff --git a/src/logind.c b/src/logind.c index 8b99065b23..ca48aa137f 100644 --- a/src/logind.c +++ b/src/logind.c @@ -1160,22 +1160,6 @@ int manager_run(Manager *m) { } static int manager_parse_config_file(Manager *m) { - - const ConfigItem items[] = { - { "NAutoVTs", config_parse_unsigned, 0, &m->n_autovts, "Login" }, - { "KillUserProcesses", config_parse_bool, 0, &m->kill_user_processes, "Login" }, - { "KillOnlyUsers", config_parse_strv, 0, &m->kill_only_users, "Login" }, - { "KillExcludeUsers", config_parse_strv, 0, &m->kill_exclude_users, "Login" }, - { "Controllers", config_parse_strv, 0, &m->controllers, "Login" }, - { "ResetControllers", config_parse_strv, 0, &m->reset_controllers, "Login" }, - { NULL, NULL, 0, NULL, NULL } - }; - - static const char * const sections[] = { - "Login", - NULL - }; - FILE *f; const char *fn; int r; @@ -1192,7 +1176,7 @@ static int manager_parse_config_file(Manager *m) { return -errno; } - r = config_parse(fn, f, sections, items, false, NULL); + r = config_parse(fn, f, "Login\0", config_item_perf_lookup, (void*) logind_gperf_lookup, false, m); if (r < 0) log_warning("Failed to parse configuration file: %s", strerror(-r)); diff --git a/src/logind.h b/src/logind.h index 5a48756982..fd668a2c19 100644 --- a/src/logind.h +++ b/src/logind.h @@ -122,4 +122,7 @@ DBusHandlerResult bus_message_filter(DBusConnection *c, DBusMessage *message, vo int manager_send_changed(Manager *manager, const char *properties); +/* gperf lookup function */ +const struct ConfigPerfItem* logind_gperf_lookup(const char *key, unsigned length); + #endif diff --git a/src/main.c b/src/main.c index 32ccf0bd5c..3409b7f994 100644 --- a/src/main.c +++ b/src/main.c @@ -368,7 +368,7 @@ static int parse_proc_cmdline_word(const char *word) { return 0; } -static int config_parse_level( +static int config_parse_level2( const char *filename, unsigned line, const char *section, @@ -440,7 +440,7 @@ static int config_parse_location( return 0; } -static int config_parse_cpu_affinity( +static int config_parse_cpu_affinity2( const char *filename, unsigned line, const char *section, @@ -494,34 +494,27 @@ static int config_parse_cpu_affinity( return 0; } -static DEFINE_CONFIG_PARSE_ENUM(config_parse_output, exec_output, ExecOutput, "Failed to parse output specifier"); - static int parse_config_file(void) { - const ConfigItem items[] = { - { "LogLevel", config_parse_level, 0, NULL, "Manager" }, - { "LogTarget", config_parse_target, 0, NULL, "Manager" }, - { "LogColor", config_parse_color, 0, NULL, "Manager" }, - { "LogLocation", config_parse_location, 0, NULL, "Manager" }, - { "DumpCore", config_parse_bool, 0, &arg_dump_core, "Manager" }, - { "CrashShell", config_parse_bool, 0, &arg_crash_shell, "Manager" }, - { "ShowStatus", config_parse_bool, 0, &arg_show_status, "Manager" }, + const ConfigTableItem items[] = { + { "Manager", "LogLevel", config_parse_level2, 0, NULL }, + { "Manager", "LogTarget", config_parse_target, 0, NULL }, + { "Manager", "LogColor", config_parse_color, 0, NULL }, + { "Manager", "LogLocation", config_parse_location, 0, NULL }, + { "Manager", "DumpCore", config_parse_bool, 0, &arg_dump_core }, + { "Manager", "CrashShell", config_parse_bool, 0, &arg_crash_shell }, + { "Manager", "ShowStatus", config_parse_bool, 0, &arg_show_status }, #ifdef HAVE_SYSV_COMPAT - { "SysVConsole", config_parse_bool, 0, &arg_sysv_console, "Manager" }, + { "Manager", "SysVConsole", config_parse_bool, 0, &arg_sysv_console }, #endif - { "CrashChVT", config_parse_int, 0, &arg_crash_chvt, "Manager" }, - { "CPUAffinity", config_parse_cpu_affinity, 0, NULL, "Manager" }, - { "MountAuto", config_parse_bool, 0, &arg_mount_auto, "Manager" }, - { "SwapAuto", config_parse_bool, 0, &arg_swap_auto, "Manager" }, - { "DefaultControllers", config_parse_strv, 0, &arg_default_controllers, "Manager" }, - { "DefaultStandardOutput", config_parse_output, 0, &arg_default_std_output, "Manager" }, - { "DefaultStandardError", config_parse_output, 0, &arg_default_std_error, "Manager" }, - { NULL, NULL, 0, NULL, NULL } - }; - - static const char * const sections[] = { - "Manager", - NULL + { "Manager", "CrashChVT", config_parse_int, 0, &arg_crash_chvt }, + { "Manager", "CPUAffinity", config_parse_cpu_affinity2, 0, NULL }, + { "Manager", "MountAuto", config_parse_bool, 0, &arg_mount_auto }, + { "Manager", "SwapAuto", config_parse_bool, 0, &arg_swap_auto }, + { "Manager", "DefaultControllers", config_parse_strv, 0, &arg_default_controllers }, + { "Manager", "DefaultStandardOutput", config_parse_output, 0, &arg_default_std_output }, + { "Manager", "DefaultStandardError", config_parse_output, 0, &arg_default_std_error }, + { NULL, NULL, NULL, 0, NULL } }; FILE *f; @@ -529,8 +522,8 @@ static int parse_config_file(void) { int r; fn = arg_running_as == MANAGER_SYSTEM ? SYSTEM_CONFIG_FILE : USER_CONFIG_FILE; - - if (!(f = fopen(fn, "re"))) { + f = fopen(fn, "re"); + if (!f) { if (errno == ENOENT) return 0; @@ -538,7 +531,8 @@ static int parse_config_file(void) { return 0; } - if ((r = config_parse(fn, f, sections, items, false, NULL)) < 0) + r = config_parse(fn, f, "Manager\0", config_item_table_lookup, (void*) items, false, NULL); + if (r < 0) log_warning("Failed to parse configuration file: %s", strerror(-r)); fclose(f); diff --git a/src/mount.c b/src/mount.c index d26d45f038..c1048d5649 100644 --- a/src/mount.c +++ b/src/mount.c @@ -1835,6 +1835,10 @@ DEFINE_STRING_TABLE_LOOKUP(mount_exec_command, MountExecCommand); const UnitVTable mount_vtable = { .suffix = ".mount", + .sections = + "Unit\0" + "Mount\0" + "Install\0", .no_alias = true, .no_instances = true, diff --git a/src/path.c b/src/path.c index 200fc2bdcb..1d4aa2174a 100644 --- a/src/path.c +++ b/src/path.c @@ -686,6 +686,10 @@ DEFINE_STRING_TABLE_LOOKUP(path_type, PathType); const UnitVTable path_vtable = { .suffix = ".path", + .sections = + "Unit\0" + "Path\0" + "Install\0", .init = path_init, .done = path_done, diff --git a/src/service.c b/src/service.c index 646c093906..340eb1baa4 100644 --- a/src/service.c +++ b/src/service.c @@ -3372,6 +3372,10 @@ DEFINE_STRING_TABLE_LOOKUP(notify_access, NotifyAccess); const UnitVTable service_vtable = { .suffix = ".service", + .sections = + "Unit\0" + "Service\0" + "Install\0", .show_status = true, .init = service_init, diff --git a/src/socket.c b/src/socket.c index 4405155481..468d1018c1 100644 --- a/src/socket.c +++ b/src/socket.c @@ -2091,6 +2091,10 @@ DEFINE_STRING_TABLE_LOOKUP(socket_exec_command, SocketExecCommand); const UnitVTable socket_vtable = { .suffix = ".socket", + .sections = + "Unit\0" + "Socket\0" + "Install\0", .init = socket_init, .done = socket_done, diff --git a/src/swap.c b/src/swap.c index 6e41f9b68e..afc0c5faab 100644 --- a/src/swap.c +++ b/src/swap.c @@ -1339,6 +1339,10 @@ DEFINE_STRING_TABLE_LOOKUP(swap_exec_command, SwapExecCommand); const UnitVTable swap_vtable = { .suffix = ".swap", + .sections = + "Unit\0" + "Swap\0" + "Install\0", .no_alias = true, .no_instances = true, diff --git a/src/target.c b/src/target.c index 54c34daa0d..340e9907f0 100644 --- a/src/target.c +++ b/src/target.c @@ -199,6 +199,10 @@ DEFINE_STRING_TABLE_LOOKUP(target_state, TargetState); const UnitVTable target_vtable = { .suffix = ".target", + .sections = + "Unit\0" + "Target\0" + "Install\0", .load = target_load, .coldplug = target_coldplug, diff --git a/src/timer.c b/src/timer.c index 1477aa5256..e6f207fbb6 100644 --- a/src/timer.c +++ b/src/timer.c @@ -478,6 +478,10 @@ DEFINE_STRING_TABLE_LOOKUP(timer_base, TimerBase); const UnitVTable timer_vtable = { .suffix = ".timer", + .sections = + "Unit\0" + "Timer\0" + "Install\0", .init = timer_init, .done = timer_done, diff --git a/src/tty-ask-password-agent.c b/src/tty-ask-password-agent.c index 02b959ea59..ca183c350b 100644 --- a/src/tty-ask-password-agent.c +++ b/src/tty-ask-password-agent.c @@ -250,13 +250,13 @@ static int parse_password(const char *filename, char **wall) { int socket_fd = -1; bool accept_cached = false; - const ConfigItem items[] = { - { "Socket", config_parse_string, 0, &socket_name, "Ask" }, - { "NotAfter", config_parse_uint64, 0, ¬_after, "Ask" }, - { "Message", config_parse_string, 0, &message, "Ask" }, - { "PID", config_parse_unsigned, 0, &pid, "Ask" }, - { "AcceptCached", config_parse_bool, 0, &accept_cached, "Ask" }, - { NULL, NULL, 0, NULL, NULL } + const ConfigTableItem items[] = { + { "Ask", "Socket", config_parse_string, 0, &socket_name }, + { "Ask", "NotAfter", config_parse_uint64, 0, ¬_after }, + { "Ask", "Message", config_parse_string, 0, &message }, + { "Ask", "PID", config_parse_unsigned, 0, &pid }, + { "Ask", "AcceptCached", config_parse_bool, 0, &accept_cached }, + { NULL, NULL, NULL, 0, NULL } }; FILE *f; @@ -264,8 +264,8 @@ static int parse_password(const char *filename, char **wall) { assert(filename); - if (!(f = fopen(filename, "re"))) { - + f = fopen(filename, "re"); + if (!f) { if (errno == ENOENT) return 0; @@ -273,7 +273,8 @@ static int parse_password(const char *filename, char **wall) { return -errno; } - if ((r = config_parse(filename, f, NULL, items, true, NULL)) < 0) { + r = config_parse(filename, f, NULL, config_item_table_lookup, (void*) items, true, NULL); + if (r < 0) { log_error("Failed to parse password file %s: %s", filename, strerror(-r)); goto finish; } diff --git a/src/unit.h b/src/unit.h index 6893b689a9..3c99817390 100644 --- a/src/unit.h +++ b/src/unit.h @@ -263,6 +263,10 @@ union Unit { struct UnitVTable { const char *suffix; + /* Config file sections this unit type understands, separated + * by NUL chars */ + const char *sections; + /* This should reset all type-specific variables. This should * not allocate memory, and is called with zero-initialized * data. It should hence only initialize variables that need -- cgit v1.2.3-54-g00ecf From 0dd27daff4ba4bdad99b12b85b630ab21c84fa9e Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Tue, 1 Mar 2011 11:18:13 +0100 Subject: systemadm: add a wrappable label and use it for status lines The new WrapLabel is there to work around a deficiency in GTK, namely the fact that it is hard to make labels which are both resizable and wrappable. The code is a port from libview. --- Makefile.am | 3 ++- src/.gitignore | 1 + src/systemadm.vala | 7 +++--- src/wraplabel.vala | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 79 insertions(+), 5 deletions(-) create mode 100644 src/wraplabel.vala (limited to 'src/.gitignore') diff --git a/Makefile.am b/Makefile.am index e1d1186887..ec0f7b5d13 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1418,7 +1418,8 @@ systemd_stdio_bridge_LDADD = \ systemadm_SOURCES = \ src/systemadm.vala \ - src/systemd-interfaces.vala + src/systemd-interfaces.vala \ + src/wraplabel.vala systemadm_CFLAGS = \ $(AM_CFLAGS) \ diff --git a/src/.gitignore b/src/.gitignore index cafff82a75..a3fd20b404 100644 --- a/src/.gitignore +++ b/src/.gitignore @@ -12,4 +12,5 @@ org.freedesktop.systemd1.policy gnome-ask-password-agent.c systemd-interfaces.c systemadm.c +wraplabel.c 73-seat-late.rules diff --git a/src/systemadm.vala b/src/systemadm.vala index 6126eca221..68652d0064 100644 --- a/src/systemadm.vala +++ b/src/systemadm.vala @@ -46,12 +46,11 @@ public class LeftLabel : Label { } } -public class RightLabel : Label { +public class RightLabel : WrapLabel { + public RightLabel(string? text = null) { - set_text_or_na(text); - set_alignment(0, 0); - set_ellipsize(EllipsizeMode.START); set_selectable(true); + set_text_or_na(text); } public void set_text_or_na(string? text = null) { diff --git a/src/wraplabel.vala b/src/wraplabel.vala new file mode 100644 index 0000000000..49858c3222 --- /dev/null +++ b/src/wraplabel.vala @@ -0,0 +1,73 @@ +// Copyright (c) 2005 VMware, Inc. + +// This is a translation of http://git.gnome.org/browse/meld/tree/meld/ui/wraplabel.py, +// which in turn is a translation of WrapLabel from libview. + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +// Python translation from wrapLabel.{cc|h} by Gian Mario Tagliaretti +// Vala translation from wraplabel.py by Zbigniew Jędrzejewski-Szmek + +public class WrapLabel : Gtk.Label { + private int _wrap_width; + + public WrapLabel(string? text = null) { + this._wrap_width = 0; + var layout = get_layout(); + layout.set_wrap(Pango.WrapMode.WORD_CHAR); + if (text != null) + this.set_text(text); + this.set_alignment(0, 0); + } + + public override void size_request(out Gtk.Requisition requisition) { + int width, height; + var layout = get_layout(); + layout.get_pixel_size(out width, out height); + requisition.width = 0; + requisition.height = height; + } + + public override void size_allocate(Gdk.Rectangle allocation) { + base.size_allocate (allocation); + this._set_wrap_width(allocation.width); + } + + public new void set_text(string str) { + base.set_text(str); + this._set_wrap_width(this._wrap_width); + } + + public new void set_markup(string str) { + base.set_markup(str); + this._set_wrap_width(this._wrap_width); + } + + private void _set_wrap_width(int width) { + if (width == 0) + return; + + var layout = get_layout(); + layout.set_width(width * Pango.SCALE); + if (_wrap_width != width) { + this._wrap_width = width; + this.queue_resize(); + } + } +} -- cgit v1.2.3-54-g00ecf From 4deba285591ad2a388496d9c017da25e68db6f30 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 31 Dec 2011 03:24:31 +0100 Subject: logind: move more files into subdirectory --- Makefile.am | 12 ++-- src/.gitignore | 1 - src/libsystemd-login.sym | 35 ------------ src/login/.gitignore | 1 + src/login/libsystemd-login.sym | 35 ++++++++++++ src/login/org.freedesktop.login1.conf | 86 +++++++++++++++++++++++++++++ src/login/org.freedesktop.login1.policy.in | 89 ++++++++++++++++++++++++++++++ src/login/org.freedesktop.login1.service | 12 ++++ src/login/systemd-logind.conf | 16 ++++++ src/org.freedesktop.login1.conf | 86 ----------------------------- src/org.freedesktop.login1.policy.in | 89 ------------------------------ src/org.freedesktop.login1.service | 12 ---- src/systemd-logind.conf | 16 ------ 13 files changed, 245 insertions(+), 245 deletions(-) delete mode 100644 src/libsystemd-login.sym create mode 100644 src/login/.gitignore create mode 100644 src/login/libsystemd-login.sym create mode 100644 src/login/org.freedesktop.login1.conf create mode 100644 src/login/org.freedesktop.login1.policy.in create mode 100644 src/login/org.freedesktop.login1.service create mode 100644 src/login/systemd-logind.conf delete mode 100644 src/org.freedesktop.login1.conf delete mode 100644 src/org.freedesktop.login1.policy.in delete mode 100644 src/org.freedesktop.login1.service delete mode 100644 src/systemd-logind.conf (limited to 'src/.gitignore') diff --git a/Makefile.am b/Makefile.am index f8735dee82..da2e980b13 100644 --- a/Makefile.am +++ b/Makefile.am @@ -258,11 +258,11 @@ endif dist_pkgsysconf_DATA = \ src/system.conf \ src/user.conf \ - src/systemd-logind.conf + src/login/systemd-logind.conf dist_dbuspolicy_DATA = \ src/org.freedesktop.systemd1.conf \ - src/org.freedesktop.login1.conf + src/login/org.freedesktop.login1.conf if ENABLE_HOSTNAMED dist_dbuspolicy_DATA += \ @@ -281,7 +281,7 @@ endif dist_dbussystemservice_DATA = \ src/org.freedesktop.systemd1.service \ - src/org.freedesktop.login1.service + src/login/org.freedesktop.login1.service if ENABLE_HOSTNAMED dist_dbussystemservice_DATA += \ @@ -520,7 +520,7 @@ EXTRA_DIST = \ libsystemd-id128.pc.in \ libsystemd-journal.pc.in \ src/libsystemd-daemon.sym \ - src/libsystemd-login.sym \ + src/login/libsystemd-login.sym \ src/libsystemd-id128.sym \ src/libsystemd-journal.sym \ introspect.awk \ @@ -627,7 +627,7 @@ pkgconfiglib_DATA = \ # Passed through intltool only polkitpolicy_in_files = \ - src/org.freedesktop.login1.policy.in + src/login/org.freedesktop.login1.policy.in if ENABLE_HOSTNAMED polkitpolicy_in_files += \ @@ -1730,7 +1730,7 @@ libsystemd_login_la_CFLAGS = \ libsystemd_login_la_LDFLAGS = \ -shared \ -version-info $(LIBSYSTEMD_LOGIN_CURRENT):$(LIBSYSTEMD_LOGIN_REVISION):$(LIBSYSTEMD_LOGIN_AGE) \ - -Wl,--version-script=$(top_srcdir)/src/libsystemd-login.sym + -Wl,--version-script=$(top_srcdir)/src/login/libsystemd-login.sym libsystemd_login_la_LIBADD = \ libsystemd-basic.la diff --git a/src/.gitignore b/src/.gitignore index a3fd20b404..ff2737b761 100644 --- a/src/.gitignore +++ b/src/.gitignore @@ -1,7 +1,6 @@ load-fragment-gperf-nulstr.c load-fragment-gperf.c load-fragment-gperf.gperf -logind-gperf.c org.freedesktop.systemd1.policy.in 99-systemd.rules org.freedesktop.hostname1.policy diff --git a/src/libsystemd-login.sym b/src/libsystemd-login.sym deleted file mode 100644 index 0d51fa76e7..0000000000 --- a/src/libsystemd-login.sym +++ /dev/null @@ -1,35 +0,0 @@ -/*** - This file is part of systemd. - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. -***/ - -/* Original symbols from systemd v31 */ - -LIBSYSTEMD_LOGIN_31 { -global: - sd_get_seats; - sd_get_sessions; - sd_get_uids; - sd_login_monitor_flush; - sd_login_monitor_get_fd; - sd_login_monitor_new; - sd_login_monitor_unref; - sd_pid_get_owner_uid; - sd_pid_get_session; - sd_seat_can_multi_session; - sd_seat_get_active; - sd_seat_get_sessions; - sd_session_get_seat; - sd_session_get_uid; - sd_session_is_active; - sd_uid_get_seats; - sd_uid_get_sessions; - sd_uid_get_state; - sd_uid_is_on_seat; -local: - *; -}; diff --git a/src/login/.gitignore b/src/login/.gitignore new file mode 100644 index 0000000000..7c420cb09b --- /dev/null +++ b/src/login/.gitignore @@ -0,0 +1 @@ +logind-gperf.c diff --git a/src/login/libsystemd-login.sym b/src/login/libsystemd-login.sym new file mode 100644 index 0000000000..0d51fa76e7 --- /dev/null +++ b/src/login/libsystemd-login.sym @@ -0,0 +1,35 @@ +/*** + This file is part of systemd. + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. +***/ + +/* Original symbols from systemd v31 */ + +LIBSYSTEMD_LOGIN_31 { +global: + sd_get_seats; + sd_get_sessions; + sd_get_uids; + sd_login_monitor_flush; + sd_login_monitor_get_fd; + sd_login_monitor_new; + sd_login_monitor_unref; + sd_pid_get_owner_uid; + sd_pid_get_session; + sd_seat_can_multi_session; + sd_seat_get_active; + sd_seat_get_sessions; + sd_session_get_seat; + sd_session_get_uid; + sd_session_is_active; + sd_uid_get_seats; + sd_uid_get_sessions; + sd_uid_get_state; + sd_uid_is_on_seat; +local: + *; +}; diff --git a/src/login/org.freedesktop.login1.conf b/src/login/org.freedesktop.login1.conf new file mode 100644 index 0000000000..c423ef5930 --- /dev/null +++ b/src/login/org.freedesktop.login1.conf @@ -0,0 +1,86 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/login/org.freedesktop.login1.policy.in b/src/login/org.freedesktop.login1.policy.in new file mode 100644 index 0000000000..adc904886d --- /dev/null +++ b/src/login/org.freedesktop.login1.policy.in @@ -0,0 +1,89 @@ + + + + + + + + The systemd Project + http://www.freedesktop.org/wiki/Software/systemd + + + <_description>Allow non-logged-in users to run programs + <_message>Authentication is required to allow a non-logged-in user to run programs + + auth_admin_keep + auth_admin_keep + auth_admin_keep + + + + + <_description>Allow attaching devices to seats + <_message>Authentication is required to allow attaching a device to a seat + + auth_admin_keep + auth_admin_keep + auth_admin_keep + + + + + <_description>Flush device to seat attachments + <_message>Authentication is required to allow resetting how devices are attached to seats + + auth_admin_keep + auth_admin_keep + auth_admin_keep + + + + + <_description>Power off the system + <_message>Authentication is required to allow powering off the system + + auth_admin_keep + auth_admin_keep + yes + + + + + <_description>Power off the system when other users are logged in + <_message>Authentication is required to allow powering off the system while other users are logged in + + auth_admin_keep + auth_admin_keep + auth_admin_keep + + + + + <_description>Reboot the system + <_message>Authentication is required to allow rebooting the system + + auth_admin_keep + auth_admin_keep + yes + + + + + <_description>Reboot the system when other users are logged in + <_message>Authentication is required to allow rebooting the system while other users are logged in + + auth_admin_keep + auth_admin_keep + auth_admin_keep + + + + diff --git a/src/login/org.freedesktop.login1.service b/src/login/org.freedesktop.login1.service new file mode 100644 index 0000000000..4a64177e30 --- /dev/null +++ b/src/login/org.freedesktop.login1.service @@ -0,0 +1,12 @@ +# This file is part of systemd. +# +# systemd is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. + +[D-BUS Service] +Name=org.freedesktop.login1 +Exec=/bin/false +User=root +SystemdService=dbus-org.freedesktop.login1.service diff --git a/src/login/systemd-logind.conf b/src/login/systemd-logind.conf new file mode 100644 index 0000000000..99098040f4 --- /dev/null +++ b/src/login/systemd-logind.conf @@ -0,0 +1,16 @@ +# This file is part of systemd. +# +# systemd is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# See system-logind.conf(5) for details + +[Login] +#NAutoVTs=6 +#KillUserProcesses=no +#KillOnlyUsers= +#KillExcludeUsers=root +#Controllers= +#ResetControllers=cpu diff --git a/src/org.freedesktop.login1.conf b/src/org.freedesktop.login1.conf deleted file mode 100644 index c423ef5930..0000000000 --- a/src/org.freedesktop.login1.conf +++ /dev/null @@ -1,86 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/org.freedesktop.login1.policy.in b/src/org.freedesktop.login1.policy.in deleted file mode 100644 index adc904886d..0000000000 --- a/src/org.freedesktop.login1.policy.in +++ /dev/null @@ -1,89 +0,0 @@ - - - - - - - - The systemd Project - http://www.freedesktop.org/wiki/Software/systemd - - - <_description>Allow non-logged-in users to run programs - <_message>Authentication is required to allow a non-logged-in user to run programs - - auth_admin_keep - auth_admin_keep - auth_admin_keep - - - - - <_description>Allow attaching devices to seats - <_message>Authentication is required to allow attaching a device to a seat - - auth_admin_keep - auth_admin_keep - auth_admin_keep - - - - - <_description>Flush device to seat attachments - <_message>Authentication is required to allow resetting how devices are attached to seats - - auth_admin_keep - auth_admin_keep - auth_admin_keep - - - - - <_description>Power off the system - <_message>Authentication is required to allow powering off the system - - auth_admin_keep - auth_admin_keep - yes - - - - - <_description>Power off the system when other users are logged in - <_message>Authentication is required to allow powering off the system while other users are logged in - - auth_admin_keep - auth_admin_keep - auth_admin_keep - - - - - <_description>Reboot the system - <_message>Authentication is required to allow rebooting the system - - auth_admin_keep - auth_admin_keep - yes - - - - - <_description>Reboot the system when other users are logged in - <_message>Authentication is required to allow rebooting the system while other users are logged in - - auth_admin_keep - auth_admin_keep - auth_admin_keep - - - - diff --git a/src/org.freedesktop.login1.service b/src/org.freedesktop.login1.service deleted file mode 100644 index 4a64177e30..0000000000 --- a/src/org.freedesktop.login1.service +++ /dev/null @@ -1,12 +0,0 @@ -# This file is part of systemd. -# -# systemd is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. - -[D-BUS Service] -Name=org.freedesktop.login1 -Exec=/bin/false -User=root -SystemdService=dbus-org.freedesktop.login1.service diff --git a/src/systemd-logind.conf b/src/systemd-logind.conf deleted file mode 100644 index 99098040f4..0000000000 --- a/src/systemd-logind.conf +++ /dev/null @@ -1,16 +0,0 @@ -# This file is part of systemd. -# -# systemd is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# See system-logind.conf(5) for details - -[Login] -#NAutoVTs=6 -#KillUserProcesses=no -#KillOnlyUsers= -#KillExcludeUsers=root -#Controllers= -#ResetControllers=cpu -- cgit v1.2.3-54-g00ecf From f5e04665ebf7124f3ea17dcf258793ed73a95fe1 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 14 Jan 2012 00:37:35 +0100 Subject: journal: hook up coredumping with journal --- .gitignore | 1 + Makefile.am | 25 +++++++ configure.ac | 8 +++ src/.gitignore | 1 + src/journal/coredump.c | 173 ++++++++++++++++++++++++++++++++++++++++++++++ src/systemd/sd-messages.h | 2 + sysctl.d/.gitignore | 1 + sysctl.d/Makefile | 1 + sysctl.d/coredump.conf.in | 10 +++ 9 files changed, 222 insertions(+) create mode 100644 src/journal/coredump.c create mode 100644 sysctl.d/.gitignore create mode 120000 sysctl.d/Makefile create mode 100644 sysctl.d/coredump.conf.in (limited to 'src/.gitignore') diff --git a/.gitignore b/.gitignore index c260210311..011aecec95 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +/systemd-coredump /systemd-cat /systemd-rc-local-generator /libsystemd-id128.pc diff --git a/Makefile.am b/Makefile.am index d94de56ff1..607ae7eadd 100644 --- a/Makefile.am +++ b/Makefile.am @@ -52,6 +52,7 @@ bashcompletiondir=$(sysconfdir)/bash_completion.d pkgsysconfdir=$(sysconfdir)/systemd userunitdir=$(prefix)/lib/systemd/user tmpfilesdir=$(prefix)/lib/tmpfiles.d +sysctldir=$(prefix)/lib/sysctl.d usergeneratordir=$(pkglibexecdir)/user-generators pkgincludedir=$(includedir)/systemd @@ -1397,6 +1398,27 @@ EXTRA_DIST += \ CLEANFILES += \ src/journal/journald-gperf.c +if ENABLE_COREDUMP + +systemd_coredump_SOURCES = \ + src/journal/coredump.c + +systemd_coredump_LDADD = \ + libsystemd-basic.la \ + libsystemd-journal.la \ + libsystemd-login.la + +rootlibexec_PROGRAMS += \ + systemd-coredump + +sysctl_DATA = \ + sysctl.d/coredump.conf + +EXTRA_DIST += \ + sysctl.d/coredump.conf.in + +endif + # ------------------------------------------------------------------------------ if ENABLE_BINFMT systemd_binfmt_SOURCES = \ @@ -2074,6 +2096,9 @@ units/%: units/%.in Makefile man/%: man/%.in Makefile $(SED_PROCESS) +sysctl.d/%: sysctl.d/%.in Makefile + $(SED_PROCESS) + %.pc: %.pc.in Makefile $(SED_PROCESS) diff --git a/configure.ac b/configure.ac index 80d0156916..194caa5d5f 100644 --- a/configure.ac +++ b/configure.ac @@ -372,6 +372,13 @@ if test "x$enable_localed" != "xno"; then fi AM_CONDITIONAL(ENABLE_LOCALED, [test "$have_localed" = "yes"]) +have_coredump=no +AC_ARG_ENABLE(coredump, AS_HELP_STRING([--disable-coredump], [disable coredump hook])) +if test "x$enable_coredump" != "xno"; then + have_coredump=yes +fi +AM_CONDITIONAL(ENABLE_COREDUMP, [test "$have_coredump" = "yes"]) + have_gtk=no AC_ARG_ENABLE(gtk, AS_HELP_STRING([--disable-gtk], [disable GTK tools])) if test "x$enable_gtk" != "xno"; then @@ -646,6 +653,7 @@ AC_MSG_RESULT([ hostnamed: ${have_hostnamed} timedated: ${have_timedated} localed: ${have_localed} + coredump: ${have_coredump} plymouth: ${have_plymouth} prefix: ${prefix} rootprefix: ${with_rootprefix} diff --git a/src/.gitignore b/src/.gitignore index ff2737b761..c54c6f6514 100644 --- a/src/.gitignore +++ b/src/.gitignore @@ -1,3 +1,4 @@ +/*.pc load-fragment-gperf-nulstr.c load-fragment-gperf.c load-fragment-gperf.gperf diff --git a/src/journal/coredump.c b/src/journal/coredump.c new file mode 100644 index 0000000000..f160270168 --- /dev/null +++ b/src/journal/coredump.c @@ -0,0 +1,173 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2012 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with systemd; If not, see . +***/ + +#include +#include + +#include +#include + +#include "log.h" +#include "util.h" + +#define COREDUMP_MAX (64*1024) + +enum { + ARG_PID = 1, + ARG_UID, + ARG_GID, + ARG_SIGNAL, + ARG_TIMESTAMP, + ARG_COMM, + _ARG_MAX +}; + +int main(int argc, char* argv[]) { + int r, j = 0; + char *p = NULL; + ssize_t n; + pid_t pid; + struct iovec iovec[14]; + char *core_pid = NULL, *core_uid = NULL, *core_gid = NULL, *core_signal = NULL, + *core_timestamp = NULL, *core_comm = NULL, *core_exe = NULL, *core_unit = NULL, + *core_session = NULL, *core_message = NULL, *core_cmdline = NULL, *t; + + log_set_target(LOG_TARGET_JOURNAL_OR_KMSG); + log_parse_environment(); + log_open(); + + if (argc != _ARG_MAX) { + log_error("Invalid number of arguments passed from kernel."); + r = -EINVAL; + goto finish; + } + + r = parse_pid(argv[ARG_PID], &pid); + if (r < 0) { + log_error("Failed to parse PID."); + r = -EINVAL; + goto finish; + } + + p = malloc(9 + COREDUMP_MAX); + if (!p) { + log_error("Out of memory"); + r = -ENOMEM; + goto finish; + } + + memcpy(p, "COREDUMP=", 9); + + n = loop_read(STDIN_FILENO, p + 9, COREDUMP_MAX, false); + if (n < 0) { + log_error("Failed to read core dump data: %s", strerror(-n)); + r = (int) n; + goto finish; + } + + zero(iovec); + iovec[j].iov_base = p; + iovec[j].iov_len = 9 + n; + j++; + + core_pid = strappend("COREDUMP_PID=", argv[ARG_PID]); + if (core_pid) + IOVEC_SET_STRING(iovec[j++], core_pid); + + core_uid = strappend("COREDUMP_UID=", argv[ARG_UID]); + if (core_uid) + IOVEC_SET_STRING(iovec[j++], core_uid); + + core_gid = strappend("COREDUMP_GID=", argv[ARG_GID]); + if (core_gid) + IOVEC_SET_STRING(iovec[j++], core_gid); + + core_signal = strappend("COREDUMP_SIGNAL=", argv[ARG_SIGNAL]); + if (core_signal) + IOVEC_SET_STRING(iovec[j++], core_signal); + + core_comm = strappend("COREDUMP_COMM=", argv[ARG_COMM]); + if (core_comm) + IOVEC_SET_STRING(iovec[j++], core_comm); + + if (sd_pid_get_session(pid, &t) >= 0) { + core_session = strappend("COREDUMP_SESSION=", t); + free(t); + + if (core_session) + IOVEC_SET_STRING(iovec[j++], core_session); + } + + if (sd_pid_get_unit(pid, &t) >= 0) { + core_unit = strappend("COREDUMP_UNIT=", t); + free(t); + + if (core_unit) + IOVEC_SET_STRING(iovec[j++], core_unit); + } + + if (get_process_exe(pid, &t) >= 0) { + core_exe = strappend("COREDUMP_EXE=", t); + free(t); + + if (core_exe) + IOVEC_SET_STRING(iovec[j++], core_exe); + } + + if (get_process_cmdline(pid, LINE_MAX, false, &t) >= 0) { + core_cmdline = strappend("COREDUMP_CMDLINE=", t); + free(t); + + if (core_cmdline) + IOVEC_SET_STRING(iovec[j++], core_cmdline); + } + + core_timestamp = join("COREDUMP_TIMESTAMP=", argv[ARG_TIMESTAMP], "000000", NULL); + if (core_timestamp) + IOVEC_SET_STRING(iovec[j++], core_timestamp); + + IOVEC_SET_STRING(iovec[j++], "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1"); + IOVEC_SET_STRING(iovec[j++], "PRIORITY=2"); + + core_message = join("MESSAGE=Process ", argv[ARG_PID], " (", argv[ARG_COMM], ") dumped core.", NULL); + if (core_message) + IOVEC_SET_STRING(iovec[j++], core_message); + + r = sd_journal_sendv(iovec, j); + if (r < 0) + log_error("Failed to send coredump: %s", strerror(-r)); + +finish: + free(p); + free(core_pid); + free(core_uid); + free(core_gid); + free(core_signal); + free(core_timestamp); + free(core_comm); + free(core_exe); + free(core_cmdline); + free(core_unit); + free(core_session); + free(core_message); + + return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; +} diff --git a/src/systemd/sd-messages.h b/src/systemd/sd-messages.h index 5fd1aa7e31..c5ac3abd0c 100644 --- a/src/systemd/sd-messages.h +++ b/src/systemd/sd-messages.h @@ -32,6 +32,8 @@ extern "C" { #define SD_MESSAGE_JOURNAL_STOP SD_ID128_MAKE(d9,3f,b3,c9,c2,4d,45,1a,97,ce,a6,15,ce,59,c0,0b) #define SD_MESSAGE_JOURNAL_DROPPED SD_ID128_MAKE(a5,96,d6,fe,7b,fa,49,94,82,8e,72,30,9e,95,d6,1e) +#define SD_MESSAGE_COREDUMP SD_ID128_MAKE(fc,2e,22,bc,6e,e6,47,b6,b9,07,29,ab,34,a2,50,b1) + #ifdef __cplusplus } #endif diff --git a/sysctl.d/.gitignore b/sysctl.d/.gitignore new file mode 100644 index 0000000000..7563539ab0 --- /dev/null +++ b/sysctl.d/.gitignore @@ -0,0 +1 @@ +/coredump.conf diff --git a/sysctl.d/Makefile b/sysctl.d/Makefile new file mode 120000 index 0000000000..bd1047548b --- /dev/null +++ b/sysctl.d/Makefile @@ -0,0 +1 @@ +../src/Makefile \ No newline at end of file diff --git a/sysctl.d/coredump.conf.in b/sysctl.d/coredump.conf.in new file mode 100644 index 0000000000..ab19b1e988 --- /dev/null +++ b/sysctl.d/coredump.conf.in @@ -0,0 +1,10 @@ +# This file is part of systemd. +# +# systemd is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. + +# See sysctl.d(5) for details + +kernel.core_pattern=|@rootlibexecdir@/systemd-coredump %p %u %g %s %t %e -- cgit v1.2.3-54-g00ecf From 131a4dcfd4375f235a1f512339c0909e8bcc730b Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Sun, 22 Jan 2012 18:20:42 +0100 Subject: login: move seat udev rules to login subdir --- Makefile.am | 33 +++---- src/.gitignore | 7 +- src/70-uaccess.rules | 72 ---------------- src/71-seat.rules | 22 ----- src/73-seat-late.rules.in | 17 ---- src/hostname/.gitignore | 1 + src/locale/.gitignore | 1 + src/login/.gitignore | 2 + src/login/70-uaccess.rules | 72 ++++++++++++++++ src/login/71-seat.rules | 22 +++++ src/login/73-seat-late.rules.in | 17 ++++ src/login/sysfs-show.c | 187 ++++++++++++++++++++++++++++++++++++++++ src/sysfs-show.c | 187 ---------------------------------------- src/timedate/.gitignore | 1 + 14 files changed, 322 insertions(+), 319 deletions(-) delete mode 100644 src/70-uaccess.rules delete mode 100644 src/71-seat.rules delete mode 100644 src/73-seat-late.rules.in create mode 100644 src/hostname/.gitignore create mode 100644 src/locale/.gitignore create mode 100644 src/login/70-uaccess.rules create mode 100644 src/login/71-seat.rules create mode 100644 src/login/73-seat-late.rules.in create mode 100644 src/login/sysfs-show.c delete mode 100644 src/sysfs-show.c create mode 100644 src/timedate/.gitignore (limited to 'src/.gitignore') diff --git a/Makefile.am b/Makefile.am index be5e70c9f8..1df603ba60 100644 --- a/Makefile.am +++ b/Makefile.am @@ -73,6 +73,7 @@ pkginclude_HEADERS = lib_LTLIBRARIES = pkgconfiglib_DATA = polkitpolicy_in_files = +dist_udevrules_DATA = AM_CPPFLAGS = \ -include $(top_builddir)/config.h \ @@ -222,11 +223,7 @@ dist_dbuspolicy_DATA = \ dist_dbussystemservice_DATA = \ src/org.freedesktop.systemd1.service -dist_udevrules_DATA = \ - src/71-seat.rules - nodist_udevrules_DATA = \ - src/73-seat-late.rules \ src/99-systemd.rules dbusinterface_DATA = \ @@ -370,7 +367,6 @@ EXTRA_DIST += \ units/user@.service.in \ src/systemd.pc.in \ introspect.awk \ - src/73-seat-late.rules.in \ src/99-systemd.rules.in \ man/custom-html.xsl @@ -1861,11 +1857,11 @@ rootlibexec_PROGRAMS += \ systemd_loginctl_SOURCES = \ src/login/loginctl.c \ + src/login/sysfs-show.c \ src/dbus-common.c \ src/cgroup-show.c \ src/cgroup-util.c \ - src/pager.c \ - src/sysfs-show.c + src/pager.c systemd_loginctl_CFLAGS = \ $(AM_CFLAGS) \ @@ -2017,7 +2013,13 @@ rootlibexec_PROGRAMS += \ systemd-uaccess dist_udevrules_DATA += \ - src/70-uaccess.rules + src/login/70-uaccess.rules + +dist_udevrules_DATA += \ + src/login/71-seat.rules + +nodist_udevrules_DATA += \ + src/login/73-seat-late.rules MANPAGES += \ man/systemd-logind.conf.5 \ @@ -2063,8 +2065,6 @@ man/sd_get_uids.3: man/sd_get_seats.3 EXTRA_DIST += \ src/login/logind-gperf.gperf \ - units/systemd-logind.service.in \ - units/systemd-user-sessions.service.in \ src/login/libsystemd-login.pc.in \ src/login/libsystemd-login.sym \ src/login/logind.h \ @@ -2072,10 +2072,14 @@ EXTRA_DIST += \ src/login/logind-seat.h \ src/login/logind-session.h \ src/login/logind-user.h \ - src/login/logind-acl.h + src/login/logind-acl.h \ + src/login/73-seat-late.rules.in \ + units/systemd-logind.service.in \ + units/systemd-user-sessions.service.in CLEANFILES += \ - src/login/logind-gperf.c + src/login/logind-gperf.c \ + src/login/73-seat-late.rules endif # ------------------------------------------------------------------------------ @@ -2152,11 +2156,10 @@ CLEANFILES += \ $(pkgconfigdata_DATA) \ $(pkgconfiglib_DATA) \ $(nodist_polkitpolicy_DATA) \ - src/73-seat-late.rules \ - src/99-systemd.rules \ src/load-fragment-gperf.gperf \ src/load-fragment-gperf.c \ - src/load-fragment-gperf-nulstr.c + src/load-fragment-gperf-nulstr.c \ + src/99-systemd.rules if HAVE_VALAC CLEANFILES += \ diff --git a/src/.gitignore b/src/.gitignore index c54c6f6514..4b123f86d2 100644 --- a/src/.gitignore +++ b/src/.gitignore @@ -3,14 +3,9 @@ load-fragment-gperf-nulstr.c load-fragment-gperf.c load-fragment-gperf.gperf org.freedesktop.systemd1.policy.in -99-systemd.rules -org.freedesktop.hostname1.policy -org.freedesktop.locale1.policy -org.freedesktop.login1.policy -org.freedesktop.timedate1.policy org.freedesktop.systemd1.policy gnome-ask-password-agent.c systemd-interfaces.c systemadm.c wraplabel.c -73-seat-late.rules +99-systemd.rules diff --git a/src/70-uaccess.rules b/src/70-uaccess.rules deleted file mode 100644 index 6932492260..0000000000 --- a/src/70-uaccess.rules +++ /dev/null @@ -1,72 +0,0 @@ -# This file is part of systemd. -# -# systemd is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. - -ACTION=="remove", GOTO="uaccess_end" -ENV{MAJOR}=="", GOTO="uaccess_end" - -# PTP/MTP protocol devices, cameras, portable media players -SUBSYSTEM=="usb", ENV{ID_USB_INTERFACES}=="", ENV{DEVTYPE}=="usb_device", IMPORT{program}="usb_id --export %p" -SUBSYSTEM=="usb", ENV{ID_USB_INTERFACES}=="*:060101:*", TAG+="uaccess" - -# Digicams with proprietary protocol -ENV{ID_GPHOTO2}=="*?", TAG+="uaccess" - -# SCSI and USB scanners -ENV{libsane_matched}=="yes", TAG+="uaccess" - -# HPLIP devices (necessary for ink level check and HP tool maintenance) -ENV{ID_HPLIP}=="1", TAG+="uaccess" - -# optical drives -SUBSYSTEM=="block", ENV{ID_CDROM}=="1", TAG+="uaccess" -SUBSYSTEM=="scsi_generic", SUBSYSTEMS=="scsi", ATTRS{type}=="4|5", TAG+="uaccess" - -# Sound devices -SUBSYSTEM=="sound", TAG+="uaccess" - -# ffado is an userspace driver for firewire sound cards -SUBSYSTEM=="firewire", ENV{ID_FFADO}=="1", TAG+="uaccess" - -# Webcams, frame grabber, TV cards -SUBSYSTEM=="video4linux", TAG+="uaccess" -SUBSYSTEM=="dvb", TAG+="uaccess" - -# IIDC devices: industrial cameras and some webcams -SUBSYSTEM=="firewire", ATTR{units}=="*0x00a02d:0x00010*", TAG+="uaccess" -SUBSYSTEM=="firewire", ATTR{units}=="*0x00b09d:0x00010*", TAG+="uaccess" -# AV/C devices: camcorders, set-top boxes, TV sets, audio devices, and more -SUBSYSTEM=="firewire", ATTR{units}=="*0x00a02d:0x010001*", TAG+="uaccess" -SUBSYSTEM=="firewire", ATTR{units}=="*0x00a02d:0x014001*", TAG+="uaccess" - -# DRI video devices -SUBSYSTEM=="drm", KERNEL=="card*", TAG+="uaccess" - -# KVM -SUBSYSTEM=="misc", KERNEL=="kvm", TAG+="uaccess" - -# smart-card readers -ENV{ID_SMARTCARD_READER}=="*?", TAG+="uaccess" - -# PDA devices -ENV{ID_PDA}=="*?", TAG+="uaccess" - -# Programmable remote control -ENV{ID_REMOTE_CONTROL}=="1", TAG+="uaccess" - -# joysticks -SUBSYSTEM=="input", ENV{ID_INPUT_JOYSTICK}=="?*", TAG+="uaccess" - -# color measurement devices -ENV{COLOR_MEASUREMENT_DEVICE}=="*?", TAG+="uaccess" - -# DDC/CI device, usually high-end monitors such as the DreamColor -ENV{DDC_DEVICE}=="*?", TAG+="uaccess" - -# media player raw devices (for user-mode drivers, Android SDK, etc.) -SUBSYSTEM=="usb", ENV{ID_MEDIA_PLAYER}=="?*", TAG+="uaccess" - -LABEL="uaccess_end" diff --git a/src/71-seat.rules b/src/71-seat.rules deleted file mode 100644 index 99425adfb7..0000000000 --- a/src/71-seat.rules +++ /dev/null @@ -1,22 +0,0 @@ -# This file is part of systemd. -# -# systemd is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. - -ACTION=="remove", GOTO="seat_end" - -TAG=="uaccess", SUBSYSTEM!="sound", TAG+="seat" -SUBSYSTEM=="sound", KERNEL=="card*", TAG+="seat" -SUBSYSTEM=="input", KERNEL=="input*", TAG+="seat" -SUBSYSTEM=="graphics", KERNEL=="fb[0-9]*", TAG+="seat" -SUBSYSTEM=="usb", ATTR{bDeviceClass}=="09", TAG+="seat" - -# 'Plugable' USB hub, sound, network, graphics adapter -SUBSYSTEM=="usb", ATTR{idVendor}=="2230", ATTR{idProduct}=="000[13]", ENV{ID_AUTOSEAT}="1" - -TAG=="seat", ENV{ID_PATH}=="", IMPORT{program}="path_id %p" -TAG=="seat", ENV{ID_FOR_SEAT}=="", ENV{ID_PATH_TAG}!="", ENV{ID_FOR_SEAT}="$env{SUBSYSTEM}-$env{ID_PATH_TAG}" - -LABEL="seat_end" diff --git a/src/73-seat-late.rules.in b/src/73-seat-late.rules.in deleted file mode 100644 index 0847932d77..0000000000 --- a/src/73-seat-late.rules.in +++ /dev/null @@ -1,17 +0,0 @@ -# This file is part of systemd. -# -# systemd is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. - -ACTION=="remove", GOTO="seat_late_end" - -ENV{ID_SEAT}=="", ENV{ID_AUTOSEAT}=="1", ENV{ID_FOR_SEAT}!="", ENV{ID_SEAT}="seat-$env{ID_FOR_SEAT}" -ENV{ID_SEAT}=="", IMPORT{parent}="ID_SEAT" - -ENV{ID_SEAT}!="", TAG+="$env{ID_SEAT}" - -TAG=="uaccess", ENV{MAJOR}!="", RUN+="@rootlibexecdir@/systemd-uaccess $env{DEVNAME} $env{ID_SEAT}" - -LABEL="seat_late_end" diff --git a/src/hostname/.gitignore b/src/hostname/.gitignore new file mode 100644 index 0000000000..1ff281b231 --- /dev/null +++ b/src/hostname/.gitignore @@ -0,0 +1 @@ +org.freedesktop.hostname1.policy diff --git a/src/locale/.gitignore b/src/locale/.gitignore new file mode 100644 index 0000000000..b1e0ba755e --- /dev/null +++ b/src/locale/.gitignore @@ -0,0 +1 @@ +org.freedesktop.locale1.policy diff --git a/src/login/.gitignore b/src/login/.gitignore index 7c420cb09b..1c0f3995ed 100644 --- a/src/login/.gitignore +++ b/src/login/.gitignore @@ -1 +1,3 @@ logind-gperf.c +org.freedesktop.login1.policy +73-seat-late.rules diff --git a/src/login/70-uaccess.rules b/src/login/70-uaccess.rules new file mode 100644 index 0000000000..6932492260 --- /dev/null +++ b/src/login/70-uaccess.rules @@ -0,0 +1,72 @@ +# This file is part of systemd. +# +# systemd is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. + +ACTION=="remove", GOTO="uaccess_end" +ENV{MAJOR}=="", GOTO="uaccess_end" + +# PTP/MTP protocol devices, cameras, portable media players +SUBSYSTEM=="usb", ENV{ID_USB_INTERFACES}=="", ENV{DEVTYPE}=="usb_device", IMPORT{program}="usb_id --export %p" +SUBSYSTEM=="usb", ENV{ID_USB_INTERFACES}=="*:060101:*", TAG+="uaccess" + +# Digicams with proprietary protocol +ENV{ID_GPHOTO2}=="*?", TAG+="uaccess" + +# SCSI and USB scanners +ENV{libsane_matched}=="yes", TAG+="uaccess" + +# HPLIP devices (necessary for ink level check and HP tool maintenance) +ENV{ID_HPLIP}=="1", TAG+="uaccess" + +# optical drives +SUBSYSTEM=="block", ENV{ID_CDROM}=="1", TAG+="uaccess" +SUBSYSTEM=="scsi_generic", SUBSYSTEMS=="scsi", ATTRS{type}=="4|5", TAG+="uaccess" + +# Sound devices +SUBSYSTEM=="sound", TAG+="uaccess" + +# ffado is an userspace driver for firewire sound cards +SUBSYSTEM=="firewire", ENV{ID_FFADO}=="1", TAG+="uaccess" + +# Webcams, frame grabber, TV cards +SUBSYSTEM=="video4linux", TAG+="uaccess" +SUBSYSTEM=="dvb", TAG+="uaccess" + +# IIDC devices: industrial cameras and some webcams +SUBSYSTEM=="firewire", ATTR{units}=="*0x00a02d:0x00010*", TAG+="uaccess" +SUBSYSTEM=="firewire", ATTR{units}=="*0x00b09d:0x00010*", TAG+="uaccess" +# AV/C devices: camcorders, set-top boxes, TV sets, audio devices, and more +SUBSYSTEM=="firewire", ATTR{units}=="*0x00a02d:0x010001*", TAG+="uaccess" +SUBSYSTEM=="firewire", ATTR{units}=="*0x00a02d:0x014001*", TAG+="uaccess" + +# DRI video devices +SUBSYSTEM=="drm", KERNEL=="card*", TAG+="uaccess" + +# KVM +SUBSYSTEM=="misc", KERNEL=="kvm", TAG+="uaccess" + +# smart-card readers +ENV{ID_SMARTCARD_READER}=="*?", TAG+="uaccess" + +# PDA devices +ENV{ID_PDA}=="*?", TAG+="uaccess" + +# Programmable remote control +ENV{ID_REMOTE_CONTROL}=="1", TAG+="uaccess" + +# joysticks +SUBSYSTEM=="input", ENV{ID_INPUT_JOYSTICK}=="?*", TAG+="uaccess" + +# color measurement devices +ENV{COLOR_MEASUREMENT_DEVICE}=="*?", TAG+="uaccess" + +# DDC/CI device, usually high-end monitors such as the DreamColor +ENV{DDC_DEVICE}=="*?", TAG+="uaccess" + +# media player raw devices (for user-mode drivers, Android SDK, etc.) +SUBSYSTEM=="usb", ENV{ID_MEDIA_PLAYER}=="?*", TAG+="uaccess" + +LABEL="uaccess_end" diff --git a/src/login/71-seat.rules b/src/login/71-seat.rules new file mode 100644 index 0000000000..99425adfb7 --- /dev/null +++ b/src/login/71-seat.rules @@ -0,0 +1,22 @@ +# This file is part of systemd. +# +# systemd is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. + +ACTION=="remove", GOTO="seat_end" + +TAG=="uaccess", SUBSYSTEM!="sound", TAG+="seat" +SUBSYSTEM=="sound", KERNEL=="card*", TAG+="seat" +SUBSYSTEM=="input", KERNEL=="input*", TAG+="seat" +SUBSYSTEM=="graphics", KERNEL=="fb[0-9]*", TAG+="seat" +SUBSYSTEM=="usb", ATTR{bDeviceClass}=="09", TAG+="seat" + +# 'Plugable' USB hub, sound, network, graphics adapter +SUBSYSTEM=="usb", ATTR{idVendor}=="2230", ATTR{idProduct}=="000[13]", ENV{ID_AUTOSEAT}="1" + +TAG=="seat", ENV{ID_PATH}=="", IMPORT{program}="path_id %p" +TAG=="seat", ENV{ID_FOR_SEAT}=="", ENV{ID_PATH_TAG}!="", ENV{ID_FOR_SEAT}="$env{SUBSYSTEM}-$env{ID_PATH_TAG}" + +LABEL="seat_end" diff --git a/src/login/73-seat-late.rules.in b/src/login/73-seat-late.rules.in new file mode 100644 index 0000000000..0847932d77 --- /dev/null +++ b/src/login/73-seat-late.rules.in @@ -0,0 +1,17 @@ +# This file is part of systemd. +# +# systemd is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. + +ACTION=="remove", GOTO="seat_late_end" + +ENV{ID_SEAT}=="", ENV{ID_AUTOSEAT}=="1", ENV{ID_FOR_SEAT}!="", ENV{ID_SEAT}="seat-$env{ID_FOR_SEAT}" +ENV{ID_SEAT}=="", IMPORT{parent}="ID_SEAT" + +ENV{ID_SEAT}!="", TAG+="$env{ID_SEAT}" + +TAG=="uaccess", ENV{MAJOR}!="", RUN+="@rootlibexecdir@/systemd-uaccess $env{DEVNAME} $env{ID_SEAT}" + +LABEL="seat_late_end" diff --git a/src/login/sysfs-show.c b/src/login/sysfs-show.c new file mode 100644 index 0000000000..b8b356d77b --- /dev/null +++ b/src/login/sysfs-show.c @@ -0,0 +1,187 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include + +#include "util.h" +#include "sysfs-show.h" + +static int show_sysfs_one( + struct udev *udev, + const char *seat, + struct udev_list_entry **item, + const char *sub, + const char *prefix, + unsigned n_columns) { + + assert(udev); + assert(seat); + assert(item); + assert(prefix); + + while (*item) { + struct udev_list_entry *next, *lookahead; + struct udev_device *d; + const char *sn, *name, *sysfs, *subsystem, *sysname; + char *l, *k; + + sysfs = udev_list_entry_get_name(*item); + if (!path_startswith(sysfs, sub)) + return 0; + + d = udev_device_new_from_syspath(udev, sysfs); + if (!d) { + *item = udev_list_entry_get_next(*item); + continue; + } + + sn = udev_device_get_property_value(d, "ID_SEAT"); + if (isempty(sn)) + sn = "seat0"; + + /* fixme, also check for tag 'seat' here */ + if (!streq(seat, sn) || !udev_device_has_tag(d, "seat")) { + udev_device_unref(d); + *item = udev_list_entry_get_next(*item); + continue; + } + + name = udev_device_get_sysattr_value(d, "name"); + if (!name) + name = udev_device_get_sysattr_value(d, "id"); + subsystem = udev_device_get_subsystem(d); + sysname = udev_device_get_sysname(d); + + /* Look if there's more coming after this */ + lookahead = next = udev_list_entry_get_next(*item); + while (lookahead) { + const char *lookahead_sysfs; + + lookahead_sysfs = udev_list_entry_get_name(lookahead); + + if (path_startswith(lookahead_sysfs, sub) && + !path_startswith(lookahead_sysfs, sysfs)) { + struct udev_device *lookahead_d; + + lookahead_d = udev_device_new_from_syspath(udev, lookahead_sysfs); + if (lookahead_d) { + const char *lookahead_sn; + bool found; + + lookahead_sn = udev_device_get_property_value(d, "ID_SEAT"); + if (isempty(lookahead_sn)) + lookahead_sn = "seat0"; + + found = streq(seat, lookahead_sn) && udev_device_has_tag(lookahead_d, "seat"); + udev_device_unref(lookahead_d); + + if (found) + break; + } + } + + lookahead = udev_list_entry_get_next(lookahead); + } + + k = ellipsize(sysfs, n_columns, 20); + printf("%s%s %s\n", prefix, lookahead ? "\342\224\234" : "\342\224\224", k ? k : sysfs); + free(k); + + if (asprintf(&l, + "(%s:%s)%s%s%s", + subsystem, sysname, + name ? " \"" : "", name ? name : "", name ? "\"" : "") < 0) { + udev_device_unref(d); + return -ENOMEM; + } + + k = ellipsize(l, n_columns, 70); + printf("%s%s %s\n", prefix, lookahead ? "\342\224\202" : " ", k ? k : l); + free(k); + free(l); + + *item = next; + if (*item) { + char *p; + + p = strappend(prefix, lookahead ? "\342\224\202 " : " "); + show_sysfs_one(udev, seat, item, sysfs, p ? p : prefix, n_columns - 2); + free(p); + } + + udev_device_unref(d); + } + + return 0; +} + +int show_sysfs(const char *seat, const char *prefix, unsigned n_columns) { + struct udev *udev; + struct udev_list_entry *first = NULL; + struct udev_enumerate *e; + int r; + + if (n_columns <= 0) + n_columns = columns(); + + if (!prefix) + prefix = ""; + + if (isempty(seat)) + seat = "seat0"; + + udev = udev_new(); + if (!udev) + return -ENOMEM; + + e = udev_enumerate_new(udev); + if (!e) { + r = -ENOMEM; + goto finish; + } + + if (!streq(seat, "seat0")) + r = udev_enumerate_add_match_tag(e, seat); + else + r = udev_enumerate_add_match_tag(e, "seat"); + + if (r < 0) + goto finish; + + r = udev_enumerate_scan_devices(e); + if (r < 0) + goto finish; + + first = udev_enumerate_get_list_entry(e); + if (first) + show_sysfs_one(udev, seat, &first, "/", prefix, n_columns); + +finish: + if (e) + udev_enumerate_unref(e); + + if (udev) + udev_unref(udev); + + return r; +} diff --git a/src/sysfs-show.c b/src/sysfs-show.c deleted file mode 100644 index b8b356d77b..0000000000 --- a/src/sysfs-show.c +++ /dev/null @@ -1,187 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include - -#include "util.h" -#include "sysfs-show.h" - -static int show_sysfs_one( - struct udev *udev, - const char *seat, - struct udev_list_entry **item, - const char *sub, - const char *prefix, - unsigned n_columns) { - - assert(udev); - assert(seat); - assert(item); - assert(prefix); - - while (*item) { - struct udev_list_entry *next, *lookahead; - struct udev_device *d; - const char *sn, *name, *sysfs, *subsystem, *sysname; - char *l, *k; - - sysfs = udev_list_entry_get_name(*item); - if (!path_startswith(sysfs, sub)) - return 0; - - d = udev_device_new_from_syspath(udev, sysfs); - if (!d) { - *item = udev_list_entry_get_next(*item); - continue; - } - - sn = udev_device_get_property_value(d, "ID_SEAT"); - if (isempty(sn)) - sn = "seat0"; - - /* fixme, also check for tag 'seat' here */ - if (!streq(seat, sn) || !udev_device_has_tag(d, "seat")) { - udev_device_unref(d); - *item = udev_list_entry_get_next(*item); - continue; - } - - name = udev_device_get_sysattr_value(d, "name"); - if (!name) - name = udev_device_get_sysattr_value(d, "id"); - subsystem = udev_device_get_subsystem(d); - sysname = udev_device_get_sysname(d); - - /* Look if there's more coming after this */ - lookahead = next = udev_list_entry_get_next(*item); - while (lookahead) { - const char *lookahead_sysfs; - - lookahead_sysfs = udev_list_entry_get_name(lookahead); - - if (path_startswith(lookahead_sysfs, sub) && - !path_startswith(lookahead_sysfs, sysfs)) { - struct udev_device *lookahead_d; - - lookahead_d = udev_device_new_from_syspath(udev, lookahead_sysfs); - if (lookahead_d) { - const char *lookahead_sn; - bool found; - - lookahead_sn = udev_device_get_property_value(d, "ID_SEAT"); - if (isempty(lookahead_sn)) - lookahead_sn = "seat0"; - - found = streq(seat, lookahead_sn) && udev_device_has_tag(lookahead_d, "seat"); - udev_device_unref(lookahead_d); - - if (found) - break; - } - } - - lookahead = udev_list_entry_get_next(lookahead); - } - - k = ellipsize(sysfs, n_columns, 20); - printf("%s%s %s\n", prefix, lookahead ? "\342\224\234" : "\342\224\224", k ? k : sysfs); - free(k); - - if (asprintf(&l, - "(%s:%s)%s%s%s", - subsystem, sysname, - name ? " \"" : "", name ? name : "", name ? "\"" : "") < 0) { - udev_device_unref(d); - return -ENOMEM; - } - - k = ellipsize(l, n_columns, 70); - printf("%s%s %s\n", prefix, lookahead ? "\342\224\202" : " ", k ? k : l); - free(k); - free(l); - - *item = next; - if (*item) { - char *p; - - p = strappend(prefix, lookahead ? "\342\224\202 " : " "); - show_sysfs_one(udev, seat, item, sysfs, p ? p : prefix, n_columns - 2); - free(p); - } - - udev_device_unref(d); - } - - return 0; -} - -int show_sysfs(const char *seat, const char *prefix, unsigned n_columns) { - struct udev *udev; - struct udev_list_entry *first = NULL; - struct udev_enumerate *e; - int r; - - if (n_columns <= 0) - n_columns = columns(); - - if (!prefix) - prefix = ""; - - if (isempty(seat)) - seat = "seat0"; - - udev = udev_new(); - if (!udev) - return -ENOMEM; - - e = udev_enumerate_new(udev); - if (!e) { - r = -ENOMEM; - goto finish; - } - - if (!streq(seat, "seat0")) - r = udev_enumerate_add_match_tag(e, seat); - else - r = udev_enumerate_add_match_tag(e, "seat"); - - if (r < 0) - goto finish; - - r = udev_enumerate_scan_devices(e); - if (r < 0) - goto finish; - - first = udev_enumerate_get_list_entry(e); - if (first) - show_sysfs_one(udev, seat, &first, "/", prefix, n_columns); - -finish: - if (e) - udev_enumerate_unref(e); - - if (udev) - udev_unref(udev); - - return r; -} diff --git a/src/timedate/.gitignore b/src/timedate/.gitignore new file mode 100644 index 0000000000..48757f0968 --- /dev/null +++ b/src/timedate/.gitignore @@ -0,0 +1 @@ +org.freedesktop.timedate1.policy -- cgit v1.2.3-54-g00ecf From f25626edf4c39bb9409cb165e6ce9551dd130661 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 11 Apr 2012 18:40:22 +0200 Subject: main: disarm watchdog when preparing for reexecution --- TODO | 3 +++ src/.gitignore | 4 ---- src/main.c | 5 +++++ 3 files changed, 8 insertions(+), 4 deletions(-) (limited to 'src/.gitignore') diff --git a/TODO b/TODO index 590351395b..d94aba5639 100644 --- a/TODO +++ b/TODO @@ -16,6 +16,9 @@ Bugfixes: * properly handle .mount unit state tracking when two mount points are stacked one on top of another on the exact same mount point. Features: + +* Make RuntimeWatchdogUSec= property writable + * start polkit agent in systemctl, similar to the password agent, to allow gaining authorizations for privileged operations by entering a password: Interface: diff --git a/src/.gitignore b/src/.gitignore index 4b123f86d2..58d30247b7 100644 --- a/src/.gitignore +++ b/src/.gitignore @@ -4,8 +4,4 @@ load-fragment-gperf.c load-fragment-gperf.gperf org.freedesktop.systemd1.policy.in org.freedesktop.systemd1.policy -gnome-ask-password-agent.c -systemd-interfaces.c -systemadm.c -wraplabel.c 99-systemd.rules diff --git a/src/main.c b/src/main.c index 6656cb4ef0..4e800e7430 100644 --- a/src/main.c +++ b/src/main.c @@ -1631,6 +1631,11 @@ finish: assert(i <= ELEMENTSOF(args)); + /* Close and disarm the watchdog, so that the new + * instance can reinitialize it, but doesn't get + * rebooted while we do that */ + watchdog_close(true); + execv(args[0], (char* const*) args); log_error("Failed to reexecute: %m"); -- cgit v1.2.3-54-g00ecf From d41ba529b4d7a57456c030e5d20546e6f0abfef3 Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Thu, 12 Apr 2012 15:26:39 +0200 Subject: move libsystemd-id128, libsystemd-daemon to subdir --- Makefile.am | 20 +- src/.gitignore | 1 - src/libsystemd-daemon.pc.in | 19 - src/libsystemd-daemon.sym | 27 -- src/libsystemd-daemon/.gitignore | 1 + src/libsystemd-daemon/libsystemd-daemon.pc.in | 19 + src/libsystemd-daemon/libsystemd-daemon.sym | 27 ++ src/libsystemd-daemon/sd-daemon.c | 530 ++++++++++++++++++++++++++ src/libsystemd-id128.pc.in | 18 - src/libsystemd-id128.sym | 21 - src/libsystemd-id128/.gitignore | 1 + src/libsystemd-id128/libsystemd-id128.pc.in | 18 + src/libsystemd-id128/libsystemd-id128.sym | 21 + src/libsystemd-id128/sd-id128.c | 221 +++++++++++ src/sd-daemon.c | 530 -------------------------- src/sd-id128.c | 221 ----------- 16 files changed, 848 insertions(+), 847 deletions(-) delete mode 100644 src/libsystemd-daemon.pc.in delete mode 100644 src/libsystemd-daemon.sym create mode 100644 src/libsystemd-daemon/.gitignore create mode 100644 src/libsystemd-daemon/libsystemd-daemon.pc.in create mode 100644 src/libsystemd-daemon/libsystemd-daemon.sym create mode 100644 src/libsystemd-daemon/sd-daemon.c delete mode 100644 src/libsystemd-id128.pc.in delete mode 100644 src/libsystemd-id128.sym create mode 100644 src/libsystemd-id128/.gitignore create mode 100644 src/libsystemd-id128/libsystemd-id128.pc.in create mode 100644 src/libsystemd-id128/libsystemd-id128.sym create mode 100644 src/libsystemd-id128/sd-id128.c delete mode 100644 src/sd-daemon.c delete mode 100644 src/sd-id128.c (limited to 'src/.gitignore') diff --git a/Makefile.am b/Makefile.am index aa671791f8..9367dd05db 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1160,7 +1160,7 @@ systemd_tty_ask_password_agent_LDADD = \ # ------------------------------------------------------------------------------ libsystemd_daemon_la_SOURCES = \ - src/sd-daemon.c + src/libsystemd-daemon/sd-daemon.c libsystemd_daemon_la_CFLAGS = \ $(AM_CFLAGS) \ @@ -1171,7 +1171,7 @@ libsystemd_daemon_la_LDFLAGS = \ $(AM_LDFLAGS) \ -shared \ -version-info $(LIBSYSTEMD_DAEMON_CURRENT):$(LIBSYSTEMD_DAEMON_REVISION):$(LIBSYSTEMD_DAEMON_AGE) \ - -Wl,--version-script=$(top_srcdir)/src/libsystemd-daemon.sym + -Wl,--version-script=$(top_srcdir)/src/libsystemd-daemon/libsystemd-daemon.sym pkginclude_HEADERS += \ src/systemd/sd-daemon.h @@ -1199,7 +1199,7 @@ lib_LTLIBRARIES += \ libsystemd-daemon.la pkgconfiglib_DATA += \ - src/libsystemd-daemon.pc + src/libsystemd-daemon/libsystemd-daemon.pc MANPAGES += \ man/sd-daemon.7 \ @@ -1222,8 +1222,8 @@ man/sd_is_mq.3: man/sd_is_fifo.3 man/sd_notifyf.3: man/sd_notify.3 EXTRA_DIST += \ - src/libsystemd-daemon.pc.in \ - src/libsystemd-daemon.sym + src/libsystemd-daemon/libsystemd-daemon.pc.in \ + src/libsystemd-daemon/libsystemd-daemon.sym # ------------------------------------------------------------------------------ SUBDIRS += \ @@ -1861,7 +1861,7 @@ udevlibexec_PROGRAMS += \ # ------------------------------------------------------------------------------ libsystemd_id128_la_SOURCES = \ - src/sd-id128.c + src/libsystemd-id128/sd-id128.c libsystemd_id128_la_CFLAGS = \ $(AM_CFLAGS) \ @@ -1871,7 +1871,7 @@ libsystemd_id128_la_LDFLAGS = \ $(AM_LDFLAGS) \ -shared \ -version-info $(LIBSYSTEMD_ID128_CURRENT):$(LIBSYSTEMD_ID128_REVISION):$(LIBSYSTEMD_ID128_AGE) \ - -Wl,--version-script=$(top_srcdir)/src/libsystemd-id128.sym + -Wl,--version-script=$(top_srcdir)/src/libsystemd-id128/libsystemd-id128.sym libsystemd_id128_la_LIBADD = \ libsystemd-shared.la @@ -1893,7 +1893,7 @@ lib_LTLIBRARIES += \ libsystemd-id128.la pkgconfiglib_DATA += \ - src/libsystemd-id128.pc + src/libsystemd-id128/libsystemd-id128.pc # move lib from $(libdir) to $(rootlibdir) and update devel link, if needed libsystemd-id128-install-hook: @@ -1915,8 +1915,8 @@ UNINSTALL_EXEC_HOOKS += \ libsystemd-id128-uninstall-hook EXTRA_DIST += \ - src/libsystemd-id128.pc.in \ - src/libsystemd-id128.sym + src/libsystemd-id128/libsystemd-id128.pc.in \ + src/libsystemd-id128/libsystemd-id128.sym # ------------------------------------------------------------------------------ systemd_journald_SOURCES = \ diff --git a/src/.gitignore b/src/.gitignore index 58d30247b7..afabb6a5d2 100644 --- a/src/.gitignore +++ b/src/.gitignore @@ -1,4 +1,3 @@ -/*.pc load-fragment-gperf-nulstr.c load-fragment-gperf.c load-fragment-gperf.gperf diff --git a/src/libsystemd-daemon.pc.in b/src/libsystemd-daemon.pc.in deleted file mode 100644 index 8bb3a74c87..0000000000 --- a/src/libsystemd-daemon.pc.in +++ /dev/null @@ -1,19 +0,0 @@ -# Permission is hereby granted, free of charge, to any person -# obtaining a copy of this software and associated documentation files -# (the "Software"), to deal in the Software without restriction, -# including without limitation the rights to use, copy, modify, merge, -# publish, distribute, sublicense, and/or sell copies of the Software, -# and to permit persons to whom the Software is furnished to do so, -# subject to the following conditions: - -prefix=@prefix@ -exec_prefix=@exec_prefix@ -libdir=@libdir@ -includedir=@includedir@ - -Name: systemd -Description: systemd Daemon Utility Library -URL: @PACKAGE_URL@ -Version: @PACKAGE_VERSION@ -Libs: -L${libdir} -lsystemd-daemon -Cflags: -I${includedir} diff --git a/src/libsystemd-daemon.sym b/src/libsystemd-daemon.sym deleted file mode 100644 index f440238931..0000000000 --- a/src/libsystemd-daemon.sym +++ /dev/null @@ -1,27 +0,0 @@ -/*** - Permission is hereby granted, free of charge, to any person - obtaining a copy of this software and associated documentation files - (the "Software"), to deal in the Software without restriction, - including without limitation the rights to use, copy, modify, merge, - publish, distribute, sublicense, and/or sell copies of the Software, - and to permit persons to whom the Software is furnished to do so, - subject to the following conditions: -***/ - -/* Original symbols from systemd v31 */ - -LIBSYSTEMD_DAEMON_31 { -global: - sd_booted; - sd_is_fifo; - sd_is_mq; - sd_is_socket; - sd_is_socket_inet; - sd_is_socket_unix; - sd_is_special; - sd_listen_fds; - sd_notify; - sd_notifyf; -local: - *; -}; diff --git a/src/libsystemd-daemon/.gitignore b/src/libsystemd-daemon/.gitignore new file mode 100644 index 0000000000..49ca83d0fe --- /dev/null +++ b/src/libsystemd-daemon/.gitignore @@ -0,0 +1 @@ +/*.pc diff --git a/src/libsystemd-daemon/libsystemd-daemon.pc.in b/src/libsystemd-daemon/libsystemd-daemon.pc.in new file mode 100644 index 0000000000..8bb3a74c87 --- /dev/null +++ b/src/libsystemd-daemon/libsystemd-daemon.pc.in @@ -0,0 +1,19 @@ +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation files +# (the "Software"), to deal in the Software without restriction, +# including without limitation the rights to use, copy, modify, merge, +# publish, distribute, sublicense, and/or sell copies of the Software, +# and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: + +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: systemd +Description: systemd Daemon Utility Library +URL: @PACKAGE_URL@ +Version: @PACKAGE_VERSION@ +Libs: -L${libdir} -lsystemd-daemon +Cflags: -I${includedir} diff --git a/src/libsystemd-daemon/libsystemd-daemon.sym b/src/libsystemd-daemon/libsystemd-daemon.sym new file mode 100644 index 0000000000..f440238931 --- /dev/null +++ b/src/libsystemd-daemon/libsystemd-daemon.sym @@ -0,0 +1,27 @@ +/*** + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation files + (the "Software"), to deal in the Software without restriction, + including without limitation the rights to use, copy, modify, merge, + publish, distribute, sublicense, and/or sell copies of the Software, + and to permit persons to whom the Software is furnished to do so, + subject to the following conditions: +***/ + +/* Original symbols from systemd v31 */ + +LIBSYSTEMD_DAEMON_31 { +global: + sd_booted; + sd_is_fifo; + sd_is_mq; + sd_is_socket; + sd_is_socket_inet; + sd_is_socket_unix; + sd_is_special; + sd_listen_fds; + sd_notify; + sd_notifyf; +local: + *; +}; diff --git a/src/libsystemd-daemon/sd-daemon.c b/src/libsystemd-daemon/sd-daemon.c new file mode 100644 index 0000000000..763e079b4e --- /dev/null +++ b/src/libsystemd-daemon/sd-daemon.c @@ -0,0 +1,530 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + Copyright 2010 Lennart Poettering + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation files + (the "Software"), to deal in the Software without restriction, + including without limitation the rights to use, copy, modify, merge, + publish, distribute, sublicense, and/or sell copies of the Software, + and to permit persons to whom the Software is furnished to do so, + subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +***/ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include +#include +#include +#include +#ifdef __BIONIC__ +#include +#else +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(__linux__) +#include +#endif + +#include "sd-daemon.h" + +#if (__GNUC__ >= 4) +#ifdef SD_EXPORT_SYMBOLS +/* Export symbols */ +#define _sd_export_ __attribute__ ((visibility("default"))) +#else +/* Don't export the symbols */ +#define _sd_export_ __attribute__ ((visibility("hidden"))) +#endif +#else +#define _sd_export_ +#endif + +_sd_export_ int sd_listen_fds(int unset_environment) { + +#if defined(DISABLE_SYSTEMD) || !defined(__linux__) + return 0; +#else + int r, fd; + const char *e; + char *p = NULL; + unsigned long l; + + if (!(e = getenv("LISTEN_PID"))) { + r = 0; + goto finish; + } + + errno = 0; + l = strtoul(e, &p, 10); + + if (errno != 0) { + r = -errno; + goto finish; + } + + if (!p || *p || l <= 0) { + r = -EINVAL; + goto finish; + } + + /* Is this for us? */ + if (getpid() != (pid_t) l) { + r = 0; + goto finish; + } + + if (!(e = getenv("LISTEN_FDS"))) { + r = 0; + goto finish; + } + + errno = 0; + l = strtoul(e, &p, 10); + + if (errno != 0) { + r = -errno; + goto finish; + } + + if (!p || *p) { + r = -EINVAL; + goto finish; + } + + for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + (int) l; fd ++) { + int flags; + + if ((flags = fcntl(fd, F_GETFD)) < 0) { + r = -errno; + goto finish; + } + + if (flags & FD_CLOEXEC) + continue; + + if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) < 0) { + r = -errno; + goto finish; + } + } + + r = (int) l; + +finish: + if (unset_environment) { + unsetenv("LISTEN_PID"); + unsetenv("LISTEN_FDS"); + } + + return r; +#endif +} + +_sd_export_ int sd_is_fifo(int fd, const char *path) { + struct stat st_fd; + + if (fd < 0) + return -EINVAL; + + memset(&st_fd, 0, sizeof(st_fd)); + if (fstat(fd, &st_fd) < 0) + return -errno; + + if (!S_ISFIFO(st_fd.st_mode)) + return 0; + + if (path) { + struct stat st_path; + + memset(&st_path, 0, sizeof(st_path)); + if (stat(path, &st_path) < 0) { + + if (errno == ENOENT || errno == ENOTDIR) + return 0; + + return -errno; + } + + return + st_path.st_dev == st_fd.st_dev && + st_path.st_ino == st_fd.st_ino; + } + + return 1; +} + +_sd_export_ int sd_is_special(int fd, const char *path) { + struct stat st_fd; + + if (fd < 0) + return -EINVAL; + + if (fstat(fd, &st_fd) < 0) + return -errno; + + if (!S_ISREG(st_fd.st_mode) && !S_ISCHR(st_fd.st_mode)) + return 0; + + if (path) { + struct stat st_path; + + if (stat(path, &st_path) < 0) { + + if (errno == ENOENT || errno == ENOTDIR) + return 0; + + return -errno; + } + + if (S_ISREG(st_fd.st_mode) && S_ISREG(st_path.st_mode)) + return + st_path.st_dev == st_fd.st_dev && + st_path.st_ino == st_fd.st_ino; + else if (S_ISCHR(st_fd.st_mode) && S_ISCHR(st_path.st_mode)) + return st_path.st_rdev == st_fd.st_rdev; + else + return 0; + } + + return 1; +} + +static int sd_is_socket_internal(int fd, int type, int listening) { + struct stat st_fd; + + if (fd < 0 || type < 0) + return -EINVAL; + + if (fstat(fd, &st_fd) < 0) + return -errno; + + if (!S_ISSOCK(st_fd.st_mode)) + return 0; + + if (type != 0) { + int other_type = 0; + socklen_t l = sizeof(other_type); + + if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &other_type, &l) < 0) + return -errno; + + if (l != sizeof(other_type)) + return -EINVAL; + + if (other_type != type) + return 0; + } + + if (listening >= 0) { + int accepting = 0; + socklen_t l = sizeof(accepting); + + if (getsockopt(fd, SOL_SOCKET, SO_ACCEPTCONN, &accepting, &l) < 0) + return -errno; + + if (l != sizeof(accepting)) + return -EINVAL; + + if (!accepting != !listening) + return 0; + } + + return 1; +} + +union sockaddr_union { + struct sockaddr sa; + struct sockaddr_in in4; + struct sockaddr_in6 in6; + struct sockaddr_un un; + struct sockaddr_storage storage; +}; + +_sd_export_ int sd_is_socket(int fd, int family, int type, int listening) { + int r; + + if (family < 0) + return -EINVAL; + + if ((r = sd_is_socket_internal(fd, type, listening)) <= 0) + return r; + + if (family > 0) { + union sockaddr_union sockaddr; + socklen_t l; + + memset(&sockaddr, 0, sizeof(sockaddr)); + l = sizeof(sockaddr); + + if (getsockname(fd, &sockaddr.sa, &l) < 0) + return -errno; + + if (l < sizeof(sa_family_t)) + return -EINVAL; + + return sockaddr.sa.sa_family == family; + } + + return 1; +} + +_sd_export_ int sd_is_socket_inet(int fd, int family, int type, int listening, uint16_t port) { + union sockaddr_union sockaddr; + socklen_t l; + int r; + + if (family != 0 && family != AF_INET && family != AF_INET6) + return -EINVAL; + + if ((r = sd_is_socket_internal(fd, type, listening)) <= 0) + return r; + + memset(&sockaddr, 0, sizeof(sockaddr)); + l = sizeof(sockaddr); + + if (getsockname(fd, &sockaddr.sa, &l) < 0) + return -errno; + + if (l < sizeof(sa_family_t)) + return -EINVAL; + + if (sockaddr.sa.sa_family != AF_INET && + sockaddr.sa.sa_family != AF_INET6) + return 0; + + if (family > 0) + if (sockaddr.sa.sa_family != family) + return 0; + + if (port > 0) { + if (sockaddr.sa.sa_family == AF_INET) { + if (l < sizeof(struct sockaddr_in)) + return -EINVAL; + + return htons(port) == sockaddr.in4.sin_port; + } else { + if (l < sizeof(struct sockaddr_in6)) + return -EINVAL; + + return htons(port) == sockaddr.in6.sin6_port; + } + } + + return 1; +} + +_sd_export_ int sd_is_socket_unix(int fd, int type, int listening, const char *path, size_t length) { + union sockaddr_union sockaddr; + socklen_t l; + int r; + + if ((r = sd_is_socket_internal(fd, type, listening)) <= 0) + return r; + + memset(&sockaddr, 0, sizeof(sockaddr)); + l = sizeof(sockaddr); + + if (getsockname(fd, &sockaddr.sa, &l) < 0) + return -errno; + + if (l < sizeof(sa_family_t)) + return -EINVAL; + + if (sockaddr.sa.sa_family != AF_UNIX) + return 0; + + if (path) { + if (length <= 0) + length = strlen(path); + + if (length <= 0) + /* Unnamed socket */ + return l == offsetof(struct sockaddr_un, sun_path); + + if (path[0]) + /* Normal path socket */ + return + (l >= offsetof(struct sockaddr_un, sun_path) + length + 1) && + memcmp(path, sockaddr.un.sun_path, length+1) == 0; + else + /* Abstract namespace socket */ + return + (l == offsetof(struct sockaddr_un, sun_path) + length) && + memcmp(path, sockaddr.un.sun_path, length) == 0; + } + + return 1; +} + +_sd_export_ int sd_is_mq(int fd, const char *path) { +#if !defined(__linux__) + return 0; +#else + struct mq_attr attr; + + if (fd < 0) + return -EINVAL; + + if (mq_getattr(fd, &attr) < 0) + return -errno; + + if (path) { + char fpath[PATH_MAX]; + struct stat a, b; + + if (path[0] != '/') + return -EINVAL; + + if (fstat(fd, &a) < 0) + return -errno; + + strncpy(stpcpy(fpath, "/dev/mqueue"), path, sizeof(fpath) - 12); + fpath[sizeof(fpath)-1] = 0; + + if (stat(fpath, &b) < 0) + return -errno; + + if (a.st_dev != b.st_dev || + a.st_ino != b.st_ino) + return 0; + } + + return 1; +#endif +} + +_sd_export_ int sd_notify(int unset_environment, const char *state) { +#if defined(DISABLE_SYSTEMD) || !defined(__linux__) || !defined(SOCK_CLOEXEC) + return 0; +#else + int fd = -1, r; + struct msghdr msghdr; + struct iovec iovec; + union sockaddr_union sockaddr; + const char *e; + + if (!state) { + r = -EINVAL; + goto finish; + } + + if (!(e = getenv("NOTIFY_SOCKET"))) + return 0; + + /* Must be an abstract socket, or an absolute path */ + if ((e[0] != '@' && e[0] != '/') || e[1] == 0) { + r = -EINVAL; + goto finish; + } + + if ((fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0)) < 0) { + r = -errno; + goto finish; + } + + memset(&sockaddr, 0, sizeof(sockaddr)); + sockaddr.sa.sa_family = AF_UNIX; + strncpy(sockaddr.un.sun_path, e, sizeof(sockaddr.un.sun_path)); + + if (sockaddr.un.sun_path[0] == '@') + sockaddr.un.sun_path[0] = 0; + + memset(&iovec, 0, sizeof(iovec)); + iovec.iov_base = (char*) state; + iovec.iov_len = strlen(state); + + memset(&msghdr, 0, sizeof(msghdr)); + msghdr.msg_name = &sockaddr; + msghdr.msg_namelen = offsetof(struct sockaddr_un, sun_path) + strlen(e); + + if (msghdr.msg_namelen > sizeof(struct sockaddr_un)) + msghdr.msg_namelen = sizeof(struct sockaddr_un); + + msghdr.msg_iov = &iovec; + msghdr.msg_iovlen = 1; + + if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) < 0) { + r = -errno; + goto finish; + } + + r = 1; + +finish: + if (unset_environment) + unsetenv("NOTIFY_SOCKET"); + + if (fd >= 0) + close(fd); + + return r; +#endif +} + +_sd_export_ int sd_notifyf(int unset_environment, const char *format, ...) { +#if defined(DISABLE_SYSTEMD) || !defined(__linux__) + return 0; +#else + va_list ap; + char *p = NULL; + int r; + + va_start(ap, format); + r = vasprintf(&p, format, ap); + va_end(ap); + + if (r < 0 || !p) + return -ENOMEM; + + r = sd_notify(unset_environment, p); + free(p); + + return r; +#endif +} + +_sd_export_ int sd_booted(void) { +#if defined(DISABLE_SYSTEMD) || !defined(__linux__) + return 0; +#else + + struct stat a, b; + + /* We simply test whether the systemd cgroup hierarchy is + * mounted */ + + if (lstat("/sys/fs/cgroup", &a) < 0) + return 0; + + if (lstat("/sys/fs/cgroup/systemd", &b) < 0) + return 0; + + return a.st_dev != b.st_dev; +#endif +} diff --git a/src/libsystemd-id128.pc.in b/src/libsystemd-id128.pc.in deleted file mode 100644 index bb65ffde33..0000000000 --- a/src/libsystemd-id128.pc.in +++ /dev/null @@ -1,18 +0,0 @@ -# This file is part of systemd. -# -# systemd is free software; you can redistribute it and/or modify it -# under the terms of the GNU Lesser General Public License as published by -# the Free Software Foundation; either version 2.1 of the License, or -# (at your option) any later version. - -prefix=@prefix@ -exec_prefix=@exec_prefix@ -libdir=@libdir@ -includedir=@includedir@ - -Name: systemd -Description: systemd 128 Bit ID Utility Library -URL: @PACKAGE_URL@ -Version: @PACKAGE_VERSION@ -Libs: -L${libdir} -lsystemd-id128 -Cflags: -I${includedir} diff --git a/src/libsystemd-id128.sym b/src/libsystemd-id128.sym deleted file mode 100644 index 604c0026c6..0000000000 --- a/src/libsystemd-id128.sym +++ /dev/null @@ -1,21 +0,0 @@ -/*** - This file is part of systemd. - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. -***/ - -/* Original symbols from systemd v38 */ - -LIBSYSTEMD_ID128_38 { -global: - sd_id128_to_string; - sd_id128_from_string; - sd_id128_randomize; - sd_id128_get_machine; - sd_id128_get_boot; -local: - *; -}; diff --git a/src/libsystemd-id128/.gitignore b/src/libsystemd-id128/.gitignore new file mode 100644 index 0000000000..49ca83d0fe --- /dev/null +++ b/src/libsystemd-id128/.gitignore @@ -0,0 +1 @@ +/*.pc diff --git a/src/libsystemd-id128/libsystemd-id128.pc.in b/src/libsystemd-id128/libsystemd-id128.pc.in new file mode 100644 index 0000000000..bb65ffde33 --- /dev/null +++ b/src/libsystemd-id128/libsystemd-id128.pc.in @@ -0,0 +1,18 @@ +# This file is part of systemd. +# +# systemd is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2.1 of the License, or +# (at your option) any later version. + +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: systemd +Description: systemd 128 Bit ID Utility Library +URL: @PACKAGE_URL@ +Version: @PACKAGE_VERSION@ +Libs: -L${libdir} -lsystemd-id128 +Cflags: -I${includedir} diff --git a/src/libsystemd-id128/libsystemd-id128.sym b/src/libsystemd-id128/libsystemd-id128.sym new file mode 100644 index 0000000000..604c0026c6 --- /dev/null +++ b/src/libsystemd-id128/libsystemd-id128.sym @@ -0,0 +1,21 @@ +/*** + This file is part of systemd. + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. +***/ + +/* Original symbols from systemd v38 */ + +LIBSYSTEMD_ID128_38 { +global: + sd_id128_to_string; + sd_id128_from_string; + sd_id128_randomize; + sd_id128_get_machine; + sd_id128_get_boot; +local: + *; +}; diff --git a/src/libsystemd-id128/sd-id128.c b/src/libsystemd-id128/sd-id128.c new file mode 100644 index 0000000000..4286ae7d14 --- /dev/null +++ b/src/libsystemd-id128/sd-id128.c @@ -0,0 +1,221 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2011 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include + +#include "sd-id128.h" + +#include "util.h" +#include "macro.h" + +_public_ char *sd_id128_to_string(sd_id128_t id, char s[33]) { + unsigned n; + + if (!s) + return NULL; + + for (n = 0; n < 16; n++) { + s[n*2] = hexchar(id.bytes[n] >> 4); + s[n*2+1] = hexchar(id.bytes[n] & 0xF); + } + + s[32] = 0; + + return s; +} + +_public_ int sd_id128_from_string(const char s[33], sd_id128_t *ret) { + unsigned n; + sd_id128_t t; + + if (!s) + return -EINVAL; + if (!ret) + return -EINVAL; + + for (n = 0; n < 16; n++) { + int a, b; + + a = unhexchar(s[n*2]); + if (a < 0) + return -EINVAL; + + b = unhexchar(s[n*2+1]); + if (b < 0) + return -EINVAL; + + t.bytes[n] = (a << 4) | b; + } + + if (s[32] != 0) + return -EINVAL; + + *ret = t; + return 0; +} + +static sd_id128_t make_v4_uuid(sd_id128_t id) { + /* Stolen from generate_random_uuid() of drivers/char/random.c + * in the kernel sources */ + + /* Set UUID version to 4 --- truly random generation */ + id.bytes[6] = (id.bytes[6] & 0x0F) | 0x40; + + /* Set the UUID variant to DCE */ + id.bytes[8] = (id.bytes[8] & 0x3F) | 0x80; + + return id; +} + +_public_ int sd_id128_get_machine(sd_id128_t *ret) { + static __thread sd_id128_t saved_machine_id; + static __thread bool saved_machine_id_valid = false; + int fd; + char buf[32]; + ssize_t k; + unsigned j; + sd_id128_t t; + + if (!ret) + return -EINVAL; + + if (saved_machine_id_valid) { + *ret = saved_machine_id; + return 0; + } + + fd = open("/etc/machine-id", O_RDONLY|O_CLOEXEC|O_NOCTTY); + if (fd < 0) + return -errno; + + k = loop_read(fd, buf, 32, false); + close_nointr_nofail(fd); + + if (k < 0) + return (int) k; + + if (k < 32) + return -EIO; + + for (j = 0; j < 16; j++) { + int a, b; + + a = unhexchar(buf[j*2]); + b = unhexchar(buf[j*2+1]); + + if (a < 0 || b < 0) + return -EIO; + + t.bytes[j] = a << 4 | b; + } + + saved_machine_id = t; + saved_machine_id_valid = true; + + *ret = t; + return 0; +} + +_public_ int sd_id128_get_boot(sd_id128_t *ret) { + static __thread sd_id128_t saved_boot_id; + static __thread bool saved_boot_id_valid = false; + int fd; + char buf[36]; + ssize_t k; + unsigned j; + sd_id128_t t; + char *p; + + if (!ret) + return -EINVAL; + + if (saved_boot_id_valid) { + *ret = saved_boot_id; + return 0; + } + + fd = open("/proc/sys/kernel/random/boot_id", O_RDONLY|O_CLOEXEC|O_NOCTTY); + if (fd < 0) + return -errno; + + k = loop_read(fd, buf, 36, false); + close_nointr_nofail(fd); + + if (k < 0) + return (int) k; + + if (k < 36) + return -EIO; + + for (j = 0, p = buf; j < 16; j++) { + int a, b; + + if (*p == '-') + p++; + + a = unhexchar(p[0]); + b = unhexchar(p[1]); + + if (a < 0 || b < 0) + return -EIO; + + t.bytes[j] = a << 4 | b; + + p += 2; + } + + saved_boot_id = t; + saved_boot_id_valid = true; + + *ret = t; + return 0; +} + +_public_ int sd_id128_randomize(sd_id128_t *ret) { + int fd; + ssize_t k; + sd_id128_t t; + + if (!ret) + return -EINVAL; + + fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY); + if (fd < 0) + return -errno; + + k = loop_read(fd, &t, 16, false); + close_nointr_nofail(fd); + + if (k < 0) + return (int) k; + + if (k < 16) + return -EIO; + + /* Turn this into a valid v4 UUID, to be nice. Note that we + * only guarantee this for newly generated UUIDs, not for + * pre-existing ones.*/ + + *ret = make_v4_uuid(t); + return 0; +} diff --git a/src/sd-daemon.c b/src/sd-daemon.c deleted file mode 100644 index 763e079b4e..0000000000 --- a/src/sd-daemon.c +++ /dev/null @@ -1,530 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - Copyright 2010 Lennart Poettering - - Permission is hereby granted, free of charge, to any person - obtaining a copy of this software and associated documentation files - (the "Software"), to deal in the Software without restriction, - including without limitation the rights to use, copy, modify, merge, - publish, distribute, sublicense, and/or sell copies of the Software, - and to permit persons to whom the Software is furnished to do so, - subject to the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. -***/ - -#ifndef _GNU_SOURCE -#define _GNU_SOURCE -#endif - -#include -#include -#include -#include -#ifdef __BIONIC__ -#include -#else -#include -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if defined(__linux__) -#include -#endif - -#include "sd-daemon.h" - -#if (__GNUC__ >= 4) -#ifdef SD_EXPORT_SYMBOLS -/* Export symbols */ -#define _sd_export_ __attribute__ ((visibility("default"))) -#else -/* Don't export the symbols */ -#define _sd_export_ __attribute__ ((visibility("hidden"))) -#endif -#else -#define _sd_export_ -#endif - -_sd_export_ int sd_listen_fds(int unset_environment) { - -#if defined(DISABLE_SYSTEMD) || !defined(__linux__) - return 0; -#else - int r, fd; - const char *e; - char *p = NULL; - unsigned long l; - - if (!(e = getenv("LISTEN_PID"))) { - r = 0; - goto finish; - } - - errno = 0; - l = strtoul(e, &p, 10); - - if (errno != 0) { - r = -errno; - goto finish; - } - - if (!p || *p || l <= 0) { - r = -EINVAL; - goto finish; - } - - /* Is this for us? */ - if (getpid() != (pid_t) l) { - r = 0; - goto finish; - } - - if (!(e = getenv("LISTEN_FDS"))) { - r = 0; - goto finish; - } - - errno = 0; - l = strtoul(e, &p, 10); - - if (errno != 0) { - r = -errno; - goto finish; - } - - if (!p || *p) { - r = -EINVAL; - goto finish; - } - - for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + (int) l; fd ++) { - int flags; - - if ((flags = fcntl(fd, F_GETFD)) < 0) { - r = -errno; - goto finish; - } - - if (flags & FD_CLOEXEC) - continue; - - if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) < 0) { - r = -errno; - goto finish; - } - } - - r = (int) l; - -finish: - if (unset_environment) { - unsetenv("LISTEN_PID"); - unsetenv("LISTEN_FDS"); - } - - return r; -#endif -} - -_sd_export_ int sd_is_fifo(int fd, const char *path) { - struct stat st_fd; - - if (fd < 0) - return -EINVAL; - - memset(&st_fd, 0, sizeof(st_fd)); - if (fstat(fd, &st_fd) < 0) - return -errno; - - if (!S_ISFIFO(st_fd.st_mode)) - return 0; - - if (path) { - struct stat st_path; - - memset(&st_path, 0, sizeof(st_path)); - if (stat(path, &st_path) < 0) { - - if (errno == ENOENT || errno == ENOTDIR) - return 0; - - return -errno; - } - - return - st_path.st_dev == st_fd.st_dev && - st_path.st_ino == st_fd.st_ino; - } - - return 1; -} - -_sd_export_ int sd_is_special(int fd, const char *path) { - struct stat st_fd; - - if (fd < 0) - return -EINVAL; - - if (fstat(fd, &st_fd) < 0) - return -errno; - - if (!S_ISREG(st_fd.st_mode) && !S_ISCHR(st_fd.st_mode)) - return 0; - - if (path) { - struct stat st_path; - - if (stat(path, &st_path) < 0) { - - if (errno == ENOENT || errno == ENOTDIR) - return 0; - - return -errno; - } - - if (S_ISREG(st_fd.st_mode) && S_ISREG(st_path.st_mode)) - return - st_path.st_dev == st_fd.st_dev && - st_path.st_ino == st_fd.st_ino; - else if (S_ISCHR(st_fd.st_mode) && S_ISCHR(st_path.st_mode)) - return st_path.st_rdev == st_fd.st_rdev; - else - return 0; - } - - return 1; -} - -static int sd_is_socket_internal(int fd, int type, int listening) { - struct stat st_fd; - - if (fd < 0 || type < 0) - return -EINVAL; - - if (fstat(fd, &st_fd) < 0) - return -errno; - - if (!S_ISSOCK(st_fd.st_mode)) - return 0; - - if (type != 0) { - int other_type = 0; - socklen_t l = sizeof(other_type); - - if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &other_type, &l) < 0) - return -errno; - - if (l != sizeof(other_type)) - return -EINVAL; - - if (other_type != type) - return 0; - } - - if (listening >= 0) { - int accepting = 0; - socklen_t l = sizeof(accepting); - - if (getsockopt(fd, SOL_SOCKET, SO_ACCEPTCONN, &accepting, &l) < 0) - return -errno; - - if (l != sizeof(accepting)) - return -EINVAL; - - if (!accepting != !listening) - return 0; - } - - return 1; -} - -union sockaddr_union { - struct sockaddr sa; - struct sockaddr_in in4; - struct sockaddr_in6 in6; - struct sockaddr_un un; - struct sockaddr_storage storage; -}; - -_sd_export_ int sd_is_socket(int fd, int family, int type, int listening) { - int r; - - if (family < 0) - return -EINVAL; - - if ((r = sd_is_socket_internal(fd, type, listening)) <= 0) - return r; - - if (family > 0) { - union sockaddr_union sockaddr; - socklen_t l; - - memset(&sockaddr, 0, sizeof(sockaddr)); - l = sizeof(sockaddr); - - if (getsockname(fd, &sockaddr.sa, &l) < 0) - return -errno; - - if (l < sizeof(sa_family_t)) - return -EINVAL; - - return sockaddr.sa.sa_family == family; - } - - return 1; -} - -_sd_export_ int sd_is_socket_inet(int fd, int family, int type, int listening, uint16_t port) { - union sockaddr_union sockaddr; - socklen_t l; - int r; - - if (family != 0 && family != AF_INET && family != AF_INET6) - return -EINVAL; - - if ((r = sd_is_socket_internal(fd, type, listening)) <= 0) - return r; - - memset(&sockaddr, 0, sizeof(sockaddr)); - l = sizeof(sockaddr); - - if (getsockname(fd, &sockaddr.sa, &l) < 0) - return -errno; - - if (l < sizeof(sa_family_t)) - return -EINVAL; - - if (sockaddr.sa.sa_family != AF_INET && - sockaddr.sa.sa_family != AF_INET6) - return 0; - - if (family > 0) - if (sockaddr.sa.sa_family != family) - return 0; - - if (port > 0) { - if (sockaddr.sa.sa_family == AF_INET) { - if (l < sizeof(struct sockaddr_in)) - return -EINVAL; - - return htons(port) == sockaddr.in4.sin_port; - } else { - if (l < sizeof(struct sockaddr_in6)) - return -EINVAL; - - return htons(port) == sockaddr.in6.sin6_port; - } - } - - return 1; -} - -_sd_export_ int sd_is_socket_unix(int fd, int type, int listening, const char *path, size_t length) { - union sockaddr_union sockaddr; - socklen_t l; - int r; - - if ((r = sd_is_socket_internal(fd, type, listening)) <= 0) - return r; - - memset(&sockaddr, 0, sizeof(sockaddr)); - l = sizeof(sockaddr); - - if (getsockname(fd, &sockaddr.sa, &l) < 0) - return -errno; - - if (l < sizeof(sa_family_t)) - return -EINVAL; - - if (sockaddr.sa.sa_family != AF_UNIX) - return 0; - - if (path) { - if (length <= 0) - length = strlen(path); - - if (length <= 0) - /* Unnamed socket */ - return l == offsetof(struct sockaddr_un, sun_path); - - if (path[0]) - /* Normal path socket */ - return - (l >= offsetof(struct sockaddr_un, sun_path) + length + 1) && - memcmp(path, sockaddr.un.sun_path, length+1) == 0; - else - /* Abstract namespace socket */ - return - (l == offsetof(struct sockaddr_un, sun_path) + length) && - memcmp(path, sockaddr.un.sun_path, length) == 0; - } - - return 1; -} - -_sd_export_ int sd_is_mq(int fd, const char *path) { -#if !defined(__linux__) - return 0; -#else - struct mq_attr attr; - - if (fd < 0) - return -EINVAL; - - if (mq_getattr(fd, &attr) < 0) - return -errno; - - if (path) { - char fpath[PATH_MAX]; - struct stat a, b; - - if (path[0] != '/') - return -EINVAL; - - if (fstat(fd, &a) < 0) - return -errno; - - strncpy(stpcpy(fpath, "/dev/mqueue"), path, sizeof(fpath) - 12); - fpath[sizeof(fpath)-1] = 0; - - if (stat(fpath, &b) < 0) - return -errno; - - if (a.st_dev != b.st_dev || - a.st_ino != b.st_ino) - return 0; - } - - return 1; -#endif -} - -_sd_export_ int sd_notify(int unset_environment, const char *state) { -#if defined(DISABLE_SYSTEMD) || !defined(__linux__) || !defined(SOCK_CLOEXEC) - return 0; -#else - int fd = -1, r; - struct msghdr msghdr; - struct iovec iovec; - union sockaddr_union sockaddr; - const char *e; - - if (!state) { - r = -EINVAL; - goto finish; - } - - if (!(e = getenv("NOTIFY_SOCKET"))) - return 0; - - /* Must be an abstract socket, or an absolute path */ - if ((e[0] != '@' && e[0] != '/') || e[1] == 0) { - r = -EINVAL; - goto finish; - } - - if ((fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0)) < 0) { - r = -errno; - goto finish; - } - - memset(&sockaddr, 0, sizeof(sockaddr)); - sockaddr.sa.sa_family = AF_UNIX; - strncpy(sockaddr.un.sun_path, e, sizeof(sockaddr.un.sun_path)); - - if (sockaddr.un.sun_path[0] == '@') - sockaddr.un.sun_path[0] = 0; - - memset(&iovec, 0, sizeof(iovec)); - iovec.iov_base = (char*) state; - iovec.iov_len = strlen(state); - - memset(&msghdr, 0, sizeof(msghdr)); - msghdr.msg_name = &sockaddr; - msghdr.msg_namelen = offsetof(struct sockaddr_un, sun_path) + strlen(e); - - if (msghdr.msg_namelen > sizeof(struct sockaddr_un)) - msghdr.msg_namelen = sizeof(struct sockaddr_un); - - msghdr.msg_iov = &iovec; - msghdr.msg_iovlen = 1; - - if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) < 0) { - r = -errno; - goto finish; - } - - r = 1; - -finish: - if (unset_environment) - unsetenv("NOTIFY_SOCKET"); - - if (fd >= 0) - close(fd); - - return r; -#endif -} - -_sd_export_ int sd_notifyf(int unset_environment, const char *format, ...) { -#if defined(DISABLE_SYSTEMD) || !defined(__linux__) - return 0; -#else - va_list ap; - char *p = NULL; - int r; - - va_start(ap, format); - r = vasprintf(&p, format, ap); - va_end(ap); - - if (r < 0 || !p) - return -ENOMEM; - - r = sd_notify(unset_environment, p); - free(p); - - return r; -#endif -} - -_sd_export_ int sd_booted(void) { -#if defined(DISABLE_SYSTEMD) || !defined(__linux__) - return 0; -#else - - struct stat a, b; - - /* We simply test whether the systemd cgroup hierarchy is - * mounted */ - - if (lstat("/sys/fs/cgroup", &a) < 0) - return 0; - - if (lstat("/sys/fs/cgroup/systemd", &b) < 0) - return 0; - - return a.st_dev != b.st_dev; -#endif -} diff --git a/src/sd-id128.c b/src/sd-id128.c deleted file mode 100644 index 4286ae7d14..0000000000 --- a/src/sd-id128.c +++ /dev/null @@ -1,221 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2011 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include - -#include "sd-id128.h" - -#include "util.h" -#include "macro.h" - -_public_ char *sd_id128_to_string(sd_id128_t id, char s[33]) { - unsigned n; - - if (!s) - return NULL; - - for (n = 0; n < 16; n++) { - s[n*2] = hexchar(id.bytes[n] >> 4); - s[n*2+1] = hexchar(id.bytes[n] & 0xF); - } - - s[32] = 0; - - return s; -} - -_public_ int sd_id128_from_string(const char s[33], sd_id128_t *ret) { - unsigned n; - sd_id128_t t; - - if (!s) - return -EINVAL; - if (!ret) - return -EINVAL; - - for (n = 0; n < 16; n++) { - int a, b; - - a = unhexchar(s[n*2]); - if (a < 0) - return -EINVAL; - - b = unhexchar(s[n*2+1]); - if (b < 0) - return -EINVAL; - - t.bytes[n] = (a << 4) | b; - } - - if (s[32] != 0) - return -EINVAL; - - *ret = t; - return 0; -} - -static sd_id128_t make_v4_uuid(sd_id128_t id) { - /* Stolen from generate_random_uuid() of drivers/char/random.c - * in the kernel sources */ - - /* Set UUID version to 4 --- truly random generation */ - id.bytes[6] = (id.bytes[6] & 0x0F) | 0x40; - - /* Set the UUID variant to DCE */ - id.bytes[8] = (id.bytes[8] & 0x3F) | 0x80; - - return id; -} - -_public_ int sd_id128_get_machine(sd_id128_t *ret) { - static __thread sd_id128_t saved_machine_id; - static __thread bool saved_machine_id_valid = false; - int fd; - char buf[32]; - ssize_t k; - unsigned j; - sd_id128_t t; - - if (!ret) - return -EINVAL; - - if (saved_machine_id_valid) { - *ret = saved_machine_id; - return 0; - } - - fd = open("/etc/machine-id", O_RDONLY|O_CLOEXEC|O_NOCTTY); - if (fd < 0) - return -errno; - - k = loop_read(fd, buf, 32, false); - close_nointr_nofail(fd); - - if (k < 0) - return (int) k; - - if (k < 32) - return -EIO; - - for (j = 0; j < 16; j++) { - int a, b; - - a = unhexchar(buf[j*2]); - b = unhexchar(buf[j*2+1]); - - if (a < 0 || b < 0) - return -EIO; - - t.bytes[j] = a << 4 | b; - } - - saved_machine_id = t; - saved_machine_id_valid = true; - - *ret = t; - return 0; -} - -_public_ int sd_id128_get_boot(sd_id128_t *ret) { - static __thread sd_id128_t saved_boot_id; - static __thread bool saved_boot_id_valid = false; - int fd; - char buf[36]; - ssize_t k; - unsigned j; - sd_id128_t t; - char *p; - - if (!ret) - return -EINVAL; - - if (saved_boot_id_valid) { - *ret = saved_boot_id; - return 0; - } - - fd = open("/proc/sys/kernel/random/boot_id", O_RDONLY|O_CLOEXEC|O_NOCTTY); - if (fd < 0) - return -errno; - - k = loop_read(fd, buf, 36, false); - close_nointr_nofail(fd); - - if (k < 0) - return (int) k; - - if (k < 36) - return -EIO; - - for (j = 0, p = buf; j < 16; j++) { - int a, b; - - if (*p == '-') - p++; - - a = unhexchar(p[0]); - b = unhexchar(p[1]); - - if (a < 0 || b < 0) - return -EIO; - - t.bytes[j] = a << 4 | b; - - p += 2; - } - - saved_boot_id = t; - saved_boot_id_valid = true; - - *ret = t; - return 0; -} - -_public_ int sd_id128_randomize(sd_id128_t *ret) { - int fd; - ssize_t k; - sd_id128_t t; - - if (!ret) - return -EINVAL; - - fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY); - if (fd < 0) - return -errno; - - k = loop_read(fd, &t, 16, false); - close_nointr_nofail(fd); - - if (k < 0) - return (int) k; - - if (k < 16) - return -EIO; - - /* Turn this into a valid v4 UUID, to be nice. Note that we - * only guarantee this for newly generated UUIDs, not for - * pre-existing ones.*/ - - *ret = make_v4_uuid(t); - return 0; -} -- cgit v1.2.3-54-g00ecf