[systemd-commits] 4 commits - configure.ac fixme .gitignore Makefile.am man/systemd.unit.xml src/dbus.c src/dbus-manager.c src/dbus-unit.c src/dbus-unit.h src/load-fragment.c src/manager.c src/manager.h src/missing.h src/system.conf src/unit.c src/unit.h src/update-utmp.c src/util.c src/utmp-wtmp.c units/basic.target units/fedora units/gentoo units/shutdown.target units/sysinit.target.m4 units/umount.target
Lennart Poettering
lennart at kemper.freedesktop.org
Tue Aug 10 16:44:45 PDT 2010
.gitignore | 1
Makefile.am | 33 +++
configure.ac | 36 +++
fixme | 12 +
man/systemd.unit.xml | 24 +-
src/dbus-manager.c | 7
src/dbus-unit.c | 30 ++-
src/dbus-unit.h | 9
src/dbus.c | 2
src/load-fragment.c | 3
src/manager.c | 82 ++------
src/manager.h | 12 -
src/missing.h | 8
src/system.conf | 1
src/unit.c | 32 +--
src/unit.h | 9
src/update-utmp.c | 410 +++++++++++++++++++++++++++++++++++++++++++
src/util.c | 53 ++---
src/utmp-wtmp.c | 6
units/basic.target | 2
units/fedora/killall.service | 2
units/gentoo/killall.service | 2
units/shutdown.target | 2
units/sysinit.target.m4 | 2
units/umount.target | 2
25 files changed, 644 insertions(+), 138 deletions(-)
New commits:
commit 4927fcae48de061393b3ce9c12d49f80d73fbf1d
Author: Lennart Poettering <lennart at poettering.net>
Date: Wed Aug 11 01:43:23 2010 +0200
audit,utmp: implement audit logic and rip utmp stuff out of the main daemon and into a helper binary
diff --git a/.gitignore b/.gitignore
index 6ff8519..b143ad1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
+systemd-update-utmp
test-env-replace
systemd-cgls
systemd.pc
diff --git a/Makefile.am b/Makefile.am
index b6041b5..cb23184 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -68,7 +68,8 @@ endif
rootlibexec_PROGRAMS = \
systemd-logger \
systemd-cgroups-agent \
- systemd-initctl
+ systemd-initctl \
+ systemd-update-utmp
noinst_PROGRAMS = \
test-engine \
@@ -243,6 +244,13 @@ libsystemd_basic_la_SOURCES = \
src/log.c \
src/ratelimit.c
+libsystemd_basic_la_CFLAGS = \
+ $(AM_CFLAGS) \
+ $(SELINUX_CFLAGS)
+
+libsystemd_basic_la_LIBADD = \
+ $(SELINUX_LIBS)
+
libsystemd_core_la_SOURCES = \
src/unit.c \
src/job.c \
@@ -282,7 +290,6 @@ libsystemd_core_la_SOURCES = \
src/loopback-setup.c \
src/kmod-setup.c \
src/modprobe-setup.c \
- src/utmp-wtmp.c \
src/specifier.c \
src/unit-name.c \
src/fdset.c \
@@ -293,7 +300,10 @@ libsystemd_core_la_SOURCES = \
libsystemd_core_la_CFLAGS = \
$(AM_CFLAGS) \
$(DBUS_CFLAGS) \
- $(UDEV_CFLAGS)
+ $(UDEV_CFLAGS) \
+ $(LIBWRAP_CFLAGS) \
+ $(PAM_CFLAGS) \
+ $(AUDIT_CFLAGS)
libsystemd_core_la_LIBADD = \
libsystemd-basic.la \
@@ -301,7 +311,7 @@ libsystemd_core_la_LIBADD = \
$(UDEV_LIBS) \
$(LIBWRAP_LIBS) \
$(PAM_LIBS) \
- $(SELINUX_LIBS)
+ $(AUDIT_LIBS)
# This is needed because automake is buggy in how it generates the
# rules for C programs, but not Vala programs. We therefore can't
@@ -480,6 +490,21 @@ systemd_initctl_LDADD = \
libsystemd-basic.la \
$(DBUS_LIBS)
+systemd_update_utmp_SOURCES = \
+ src/update-utmp.c \
+ src/dbus-common.c \
+ src/utmp-wtmp.c
+
+systemd_update_utmp_CFLAGS = \
+ $(AM_CFLAGS) \
+ $(DBUS_CFLAGS) \
+ $(AUDIT_CFLAGS)
+
+systemd_update_utmp_LDADD = \
+ libsystemd-basic.la \
+ $(DBUS_LIBS) \
+ $(AUDIT_LIBS)
+
systemd_cgroups_agent_SOURCES = \
src/cgroups-agent.c \
src/dbus-common.c
diff --git a/configure.ac b/configure.ac
index f5dba3a..72218e4 100644
--- a/configure.ac
+++ b/configure.ac
@@ -186,6 +186,42 @@ fi
AC_SUBST(PAM_LIBS)
AM_CONDITIONAL([HAVE_PAM], [test "x$have_pam" != xno])
+AC_ARG_ENABLE([audit],
+ AS_HELP_STRING([--disable-audit],[Disable optional AUDIT support]),
+ [case "${enableval}" in
+ yes) have_audit=yes ;;
+ no) have_audit=no ;;
+ *) AC_MSG_ERROR(bad value ${enableval} for --disable-audit) ;;
+ esac],
+ [have_audit=auto])
+
+if test "x${have_audit}" != xno ; then
+ AC_CHECK_HEADERS(
+ [libaudit.h],
+ [have_audit=yes],
+ [if test "x$have_audit" = xyes ; then
+ AC_MSG_ERROR([*** AUDIT headers not found.])
+ fi])
+
+ AC_CHECK_LIB(
+ [audit],
+ [audit_open],
+ [have_audit=yes],
+ [if test "x$have_audit" = xyes ; then
+ AC_MSG_ERROR([*** libaudit not found.])
+ fi])
+
+ if test "x$have_audit" = xyes ; then
+ AUDIT_LIBS="-laudit"
+ AC_DEFINE(HAVE_AUDIT, 1, [AUDIT available])
+ else
+ have_audit=no
+ fi
+else
+ AUDIT_LIBS=
+fi
+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
diff --git a/fixme b/fixme
index 3614c11..be771ab 100644
--- a/fixme
+++ b/fixme
@@ -79,9 +79,9 @@
* don't show file not found msgs for irrelevant units
-* audit
+* j->installed issue
-* env vars must be replaced by ""
+* plymouth boot.log
External:
diff --git a/src/manager.c b/src/manager.c
index ddb253a..25eb4e7 100644
--- a/src/manager.c
+++ b/src/manager.c
@@ -37,6 +37,7 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
+#include <libaudit.h>
#include "manager.h"
#include "hashmap.h"
@@ -202,6 +203,10 @@ int manager_new(ManagerRunningAs running_as, Manager **_m) {
m->exit_code = _MANAGER_EXIT_CODE_INVALID;
m->pin_cgroupfs_fd = -1;
+#ifdef HAVE_AUDIT
+ m->audit_fd = -1;
+#endif
+
m->signal_watch.fd = m->mount_watch.fd = m->udev_watch.fd = m->epoll_fd = m->dev_autofs_fd = -1;
m->current_job_id = 1; /* start as id #1, so that we can leave #0 around as "null-like" value */
@@ -245,6 +250,9 @@ int manager_new(ManagerRunningAs running_as, Manager **_m) {
if ((r = bus_init(m)) < 0)
goto fail;
+ if ((m->audit_fd = audit_open()) < 0)
+ log_error("Failed to connect to audit log: %m");
+
*_m = m;
return 0;
@@ -429,6 +437,11 @@ void manager_free(Manager *m) {
if (m->notify_watch.fd >= 0)
close_nointr_nofail(m->notify_watch.fd);
+#ifdef HAVE_AUDIT
+ if (m->audit_fd >= 0)
+ audit_close(m->audit_fd);
+#endif
+
free(m->notify_socket);
lookup_paths_free(&m->lookup_paths);
@@ -567,10 +580,6 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) {
m->n_deserializing --;
}
- /* Now that the initial devices are available, let's see if we
- * can write the utmp file */
- manager_write_utmp_reboot(m);
-
return r;
}
@@ -2234,70 +2243,25 @@ int manager_get_job_from_dbus_path(Manager *m, const char *s, Job **_j) {
return 0;
}
-static bool manager_utmp_good(Manager *m) {
- int r;
-
- assert(m);
-
- if ((r = mount_path_is_mounted(m, _PATH_UTMPX)) <= 0) {
-
- if (r < 0)
- log_warning("Failed to determine whether " _PATH_UTMPX " is mounted: %s", strerror(-r));
-
- return false;
- }
-
- return true;
-}
-
-void manager_write_utmp_reboot(Manager *m) {
- int r;
-
- assert(m);
-
- if (m->utmp_reboot_written)
- return;
+void manager_send_unit_audit(Manager *m, Unit *u, int type, bool success) {
- if (m->running_as != MANAGER_SYSTEM)
- return;
+#ifdef HAVE_AUDIT
+ char *p;
- if (!manager_utmp_good(m))
+ if (m->audit_fd < 0)
return;
- if ((r = utmp_put_reboot(m->startup_timestamp.realtime)) < 0) {
-
- if (r != -ENOENT && r != -EROFS)
- log_warning("Failed to write utmp/wtmp: %s", strerror(-r));
-
+ if (!(p = unit_name_to_prefix_and_instance(u->meta.id))) {
+ log_error("Failed to allocate unit name for audit message: %s", strerror(ENOMEM));
return;
}
- m->utmp_reboot_written = true;
-}
-
-void manager_write_utmp_runlevel(Manager *m, Unit *u) {
- int runlevel, r;
-
- assert(m);
- assert(u);
-
- if (u->meta.type != UNIT_TARGET)
- return;
+ if (audit_log_user_comm_message(m->audit_fd, type, "", p, NULL, NULL, NULL, success) < 0)
+ log_error("Failed to send audit message: %m");
- if (m->running_as != MANAGER_SYSTEM)
- return;
-
- if (!manager_utmp_good(m))
- return;
+ free(p);
+#endif
- if ((runlevel = target_get_runlevel(TARGET(u))) <= 0)
- return;
-
- if ((r = utmp_put_runlevel(0, runlevel, 0)) < 0) {
-
- if (r != -ENOENT && r != -EROFS)
- log_warning("Failed to write utmp/wtmp: %s", strerror(-r));
- }
}
void manager_dispatch_bus_name_owner_changed(
diff --git a/src/manager.h b/src/manager.h
index a762dbc..c1f787f 100644
--- a/src/manager.h
+++ b/src/manager.h
@@ -185,6 +185,11 @@ struct Manager {
* file system */
int pin_cgroupfs_fd;
+ /* Audit fd */
+#ifdef HAVE_AUDIT
+ int audit_fd;
+#endif
+
/* Flags */
ManagerRunningAs running_as;
ManagerExitCode exit_code:4;
@@ -193,8 +198,6 @@ struct Manager {
bool dispatching_run_queue:1;
bool dispatching_dbus_queue:1;
- bool utmp_reboot_written:1;
-
int n_deserializing;
bool show_status;
@@ -234,9 +237,6 @@ unsigned manager_dispatch_dbus_queue(Manager *m);
int manager_loop(Manager *m);
-void manager_write_utmp_reboot(Manager *m);
-void manager_write_utmp_runlevel(Manager *m, Unit *t);
-
void manager_dispatch_bus_name_owner_changed(Manager *m, const char *name, const char* old_owner, const char *new_owner);
void manager_dispatch_bus_query_pid_done(Manager *m, const char *name, pid_t pid);
@@ -251,6 +251,8 @@ bool manager_is_booting_or_shutting_down(Manager *m);
void manager_reset_maintenance(Manager *m);
+void manager_send_unit_audit(Manager *m, Unit *u, int type, bool success);
+
const char *manager_running_as_to_string(ManagerRunningAs i);
ManagerRunningAs manager_running_as_from_string(const char *s);
diff --git a/src/missing.h b/src/missing.h
index 5914b01..d6114cc 100644
--- a/src/missing.h
+++ b/src/missing.h
@@ -63,4 +63,12 @@ static inline int pivot_root(const char *new_root, const char *put_old) {
/* static void nss_disable_nscd(void) _weakref_(__nss_disable_nscd); */
+#ifndef AUDIT_SERVICE_START
+#define AUDIT_SERVICE_START 1130 /* Service (daemon) start */
+#endif
+
+#ifndef AUDIT_SERVICE_STOP
+#define AUDIT_SERVICE_STOP 1131 /* Service (daemon) stop */
+#endif
+
#endif
diff --git a/src/unit.c b/src/unit.c
index 9ccf7a4..3c4bdec 100644
--- a/src/unit.c
+++ b/src/unit.c
@@ -41,6 +41,7 @@
#include "dbus-unit.h"
#include "special.h"
#include "cgroup-util.h"
+#include "missing.h"
const UnitVTable * const unit_vtable[_UNIT_TYPE_MAX] = {
[UNIT_SERVICE] = &service_vtable,
@@ -1094,12 +1095,11 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns) {
/* Some names are special */
if (UNIT_IS_ACTIVE_OR_RELOADING(ns)) {
- if (unit_has_name(u, SPECIAL_DBUS_SERVICE)) {
+ if (unit_has_name(u, SPECIAL_DBUS_SERVICE))
/* The bus just might have become available,
* hence try to connect to it, if we aren't
* yet connected. */
bus_init(u->meta.manager);
- }
if (unit_has_name(u, SPECIAL_SYSLOG_SERVICE))
/* The syslog daemon just might have become
@@ -1107,17 +1107,12 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns) {
* we aren't yet connected. */
log_open();
- if (u->meta.type == UNIT_MOUNT)
- /* Another directory became available, let's
- * check if that is enough to write our utmp
- * entry. */
- manager_write_utmp_reboot(u->meta.manager);
-
- if (u->meta.type == UNIT_TARGET)
- /* A target got activated, maybe this is a runlevel? */
- manager_write_utmp_runlevel(u->meta.manager, u);
+ if (u->meta.type == UNIT_SERVICE &&
+ !UNIT_IS_ACTIVE_OR_RELOADING(os))
+ /* Write audit record if we have just finished starting up */
+ manager_send_unit_audit(u->meta.manager, u, AUDIT_SERVICE_START, 1);
- } else if (!UNIT_IS_ACTIVE_OR_RELOADING(ns)) {
+ } else {
if (unit_has_name(u, SPECIAL_SYSLOG_SERVICE))
/* The syslog daemon might just have
@@ -1127,6 +1122,13 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns) {
/* We don't care about D-Bus here, since we'll get an
* asynchronous notification for it anyway. */
+
+ if (u->meta.type == UNIT_SERVICE &&
+ UNIT_IS_INACTIVE_OR_MAINTENANCE(ns) &&
+ !UNIT_IS_INACTIVE_OR_MAINTENANCE(os))
+
+ /* Write audit record if we have just finished shutting down */
+ manager_send_unit_audit(u->meta.manager, u, AUDIT_SERVICE_STOP, ns == UNIT_INACTIVE);
}
/* Maybe we finished startup and are now ready for being
diff --git a/src/update-utmp.c b/src/update-utmp.c
new file mode 100644
index 0000000..e64a819
--- /dev/null
+++ b/src/update-utmp.c
@@ -0,0 +1,410 @@
+/*-*- 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 <http://www.gnu.org/licenses/>.
+***/
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+#include <libaudit.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <dbus/dbus.h>
+
+#include "log.h"
+#include "macro.h"
+#include "util.h"
+#include "special.h"
+#include "utmp-wtmp.h"
+#include "dbus-common.h"
+
+typedef struct Context {
+ DBusConnection *bus;
+#ifdef HAVE_AUDIT
+ int audit_fd;
+#endif
+} Context;
+
+static usec_t get_startup_time(Context *c) {
+ const char
+ *interface = "org.freedesktop.systemd1.Manager",
+ *property = "StartupTimestamp";
+
+ DBusError error;
+ usec_t t = 0;
+ DBusMessage *m = NULL, *reply = NULL;
+ DBusMessageIter iter, sub;
+
+ dbus_error_init(&error);
+
+ assert(c);
+
+ if (!(m = dbus_message_new_method_call(
+ "org.freedesktop.systemd1",
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.DBus.Properties",
+ "Get"))) {
+ log_error("Could not allocate message.");
+ goto finish;
+ }
+
+ 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(c->bus, m, -1, &error))) {
+ log_error("Failed to send command: %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 (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_UINT64) {
+ log_error("Failed to parse reply.");
+ goto finish;
+ }
+
+ dbus_message_iter_get_basic(&sub, &t);
+
+finish:
+ if (m)
+ dbus_message_unref(m);
+
+ if (reply)
+ dbus_message_unref(reply);
+
+ dbus_error_free(&error);
+
+ return t;
+}
+
+static int get_current_runlevel(Context *c) {
+ static const struct {
+ const int runlevel;
+ const char *special;
+ } table[] = {
+ /* The first target of this list that is active or has
+ * a job scheduled wins */
+ { '0', SPECIAL_POWEROFF_TARGET },
+ { '6', SPECIAL_REBOOT_TARGET },
+ { '5', SPECIAL_RUNLEVEL5_TARGET },
+ { '4', SPECIAL_RUNLEVEL4_TARGET },
+ { '3', SPECIAL_RUNLEVEL3_TARGET },
+ { '2', SPECIAL_RUNLEVEL2_TARGET },
+ { '1', SPECIAL_RESCUE_TARGET },
+ };
+ const char
+ *interface = "org.freedesktop.systemd1.Unit",
+ *property = "ActiveState";
+
+ DBusMessage *m = NULL, *reply = NULL;
+ int r = 0;
+ unsigned i;
+ DBusError error;
+
+ assert(c);
+
+ dbus_error_init(&error);
+
+ for (i = 0; i < ELEMENTSOF(table); i++) {
+ const char *path = NULL, *state;
+ DBusMessageIter iter, sub;
+
+ if (!(m = dbus_message_new_method_call(
+ "org.freedesktop.systemd1",
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ "GetUnit"))) {
+ log_error("Could not allocate message.");
+ r = -ENOMEM;
+ goto finish;
+ }
+
+ if (!dbus_message_append_args(m,
+ DBUS_TYPE_STRING, &table[i].special,
+ DBUS_TYPE_INVALID)) {
+ log_error("Could not append arguments to message.");
+ r = -ENOMEM;
+ goto finish;
+ }
+
+ if (!(reply = dbus_connection_send_with_reply_and_block(c->bus, m, -1, &error))) {
+ dbus_error_free(&error);
+ continue;
+ }
+
+ 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.");
+ r = -ENOMEM;
+ goto finish;
+ }
+
+ 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(c->bus, m, -1, &error))) {
+ log_error("Failed to send command: %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, &state);
+
+ if (streq(state, "active") || streq(state, "reloading"))
+ r = table[i].runlevel;
+
+ dbus_message_unref(m);
+ dbus_message_unref(reply);
+ m = reply = NULL;
+
+ if (r)
+ break;
+ }
+
+finish:
+ if (m)
+ dbus_message_unref(m);
+
+ if (reply)
+ dbus_message_unref(reply);
+
+ dbus_error_free(&error);
+
+ return r;
+}
+
+static int on_reboot(Context *c) {
+ int r = 0, q;
+ usec_t t;
+
+ assert(c);
+
+ /* We finished start-up, so let's write the utmp
+ * record and send the audit msg */
+
+#ifdef HAVE_AUDIT
+ if (c->audit_fd >= 0)
+ if (audit_log_user_message(c->audit_fd, AUDIT_SYSTEM_BOOT, "", NULL, NULL, NULL, 1) < 0) {
+ log_error("Failed to send audit message: %m");
+ r = -errno;
+ }
+#endif
+
+ /* If this call fails it will return 0, which
+ * utmp_put_reboot() will then fix to the current time */
+ t = get_startup_time(c);
+
+ if ((q = utmp_put_reboot(t)) < 0) {
+ log_error("Failed to write utmp record: %s", strerror(-q));
+ r = q;
+ }
+
+ return r;
+}
+
+static int on_shutdown(Context *c) {
+ int r = 0, q;
+
+ assert(c);
+
+ /* We started shut-down, so let's write the utmp
+ * record and send the audit msg */
+
+#ifdef HAVE_AUDIT
+ if (c->audit_fd >= 0)
+ if (audit_log_user_message(c->audit_fd, AUDIT_SYSTEM_SHUTDOWN, "", NULL, NULL, NULL, 1) < 0) {
+ log_error("Failed to send audit message: %m");
+ r = -errno;
+ }
+#endif
+
+ if ((q = utmp_put_shutdown(0)) < 0) {
+ log_error("Failed to write utmp record: %s", strerror(-q));
+ r = q;
+ }
+
+ return r;
+}
+
+static int on_runlevel(Context *c) {
+ int r = 0, q, previous, runlevel;
+
+ assert(c);
+
+ /* We finished changing runlevel, so let's write the
+ * utmp record and send the audit msg */
+
+ /* First, get last runlevel */
+ if ((q = utmp_get_runlevel(&previous, NULL)) < 0) {
+
+ if (q != -ESRCH && q != -ENOENT) {
+ log_error("Failed to get current runlevel: %s", strerror(-q));
+ return q;
+ }
+
+ /* Hmm, we didn't find any runlevel, that means we
+ * have been rebooted */
+ r = on_reboot(c);
+ previous = 0;
+ }
+
+ /* Second get new runlevel */
+ if ((runlevel = get_current_runlevel(c)) < 0)
+ return runlevel;
+
+ if (previous == runlevel)
+ return 0;
+
+#ifdef HAVE_AUDIT
+ if (c->audit_fd >= 0) {
+ char *s = NULL;
+
+ if (asprintf(&s, "old-level=%c new-level=%c", previous, runlevel) < 0)
+ return -ENOMEM;
+
+ if (audit_log_user_message(c->audit_fd, AUDIT_SYSTEM_RUNLEVEL, s, NULL, NULL, NULL, 1) < 0) {
+ log_error("Failed to send audit message: %m");
+ r = -errno;
+ }
+
+ free(s);
+ }
+#endif
+
+ if ((q = utmp_put_runlevel(0, runlevel, previous)) < 0) {
+ log_error("Failed to write utmp record: %s", strerror(-q));
+ r = q;
+ }
+
+ return r;
+}
+
+int main(int argc, char *argv[]) {
+ int r;
+ DBusError error;
+ Context c;
+
+ dbus_error_init(&error);
+
+ zero(c);
+#ifdef HAVE_AUDIT
+ c.audit_fd = -1;
+#endif
+
+ /* if (getppid() != 1) { */
+ /* log_error("This program should be invoked by init only."); */
+ /* return 1; */
+ /* } */
+
+ if (argc != 2) {
+ log_error("This program requires one argument.");
+ return 1;
+ }
+
+ log_set_target(LOG_TARGET_SYSLOG_OR_KMSG);
+ log_parse_environment();
+
+#ifdef HAVE_AUDIT
+ if ((c.audit_fd = audit_open()) < 0)
+ log_error("Failed to connect to audit log: %m");
+#endif
+
+ if (bus_connect(DBUS_BUS_SYSTEM, &c.bus, NULL, &error) < 0) {
+ log_error("Failed to get D-Bus connection: %s", error.message);
+ r = -EIO;
+ goto finish;
+ }
+
+ log_info("systemd-update-utmp running as pid %lu", (unsigned long) getpid());
+
+ if (streq(argv[1], "reboot"))
+ r = on_reboot(&c);
+ else if (streq(argv[1], "shutdown"))
+ r = on_shutdown(&c);
+ else if (streq(argv[1], "runlevel"))
+ r = on_runlevel(&c);
+ else {
+ log_error("Unknown command %s", argv[1]);
+ r = -EINVAL;
+ }
+
+ log_info("systemd-update-utmp stopped as pid %lu", (unsigned long) getpid());
+finish:
+
+#ifdef HAVE_AUDIT
+ if (c.audit_fd >= 0)
+ audit_close(c.audit_fd);
+#endif
+
+ if (c.bus) {
+ dbus_connection_close(c.bus);
+ dbus_connection_unref(c.bus);
+ }
+
+ dbus_error_free(&error);
+ dbus_shutdown();
+
+ return r < 0 ? 1 : 0;
+}
diff --git a/src/utmp-wtmp.c b/src/utmp-wtmp.c
index 45da79c..46dfba3 100644
--- a/src/utmp-wtmp.c
+++ b/src/utmp-wtmp.c
@@ -202,11 +202,11 @@ int utmp_put_runlevel(usec_t t, int runlevel, int previous) {
previous = 0;
}
-
- if (previous == runlevel)
- return 0;
}
+ if (previous == runlevel)
+ return 0;
+
init_entry(&store, t);
store.ut_type = RUN_LVL;
commit b95cf3629e8d78a0d28e71b0f5559fa9a8c038b5
Author: Lennart Poettering <lennart at poettering.net>
Date: Tue Aug 10 21:05:19 2010 +0200
util: when replacing env vars replace unset envvars by nothing
This makes it easier to support /etc/sysconfig/xxxx with command line
env vars in style of $OPTIONS which might or might not be set.
diff --git a/fixme b/fixme
index 397f5c3..3614c11 100644
--- a/fixme
+++ b/fixme
@@ -79,8 +79,6 @@
* don't show file not found msgs for irrelevant units
-* hide plymouth in multi-user mode
-
* audit
* env vars must be replaced by ""
diff --git a/src/util.c b/src/util.c
index 7281b70..a2def28 100644
--- a/src/util.c
+++ b/src/util.c
@@ -3085,18 +3085,18 @@ char *replace_env(const char *format, char **env) {
case VARIABLE:
if (*e == '}') {
- char *t;
+ const char *t;
- if ((t = strv_env_get_with_length(env, word+2, e-word-2))) {
- if (!(k = strappend(r, t)))
- goto fail;
+ if (!(t = strv_env_get_with_length(env, word+2, e-word-2)))
+ t = "";
- free(r);
- r = k;
+ if (!(k = strappend(r, t)))
+ goto fail;
- word = e+1;
- }
+ free(r);
+ r = k;
+ word = e+1;
state = WORD;
}
break;
@@ -3126,36 +3126,39 @@ char **replace_env_argv(char **argv, char **env) {
STRV_FOREACH(i, argv) {
/* If $FOO appears as single word, replace it by the split up variable */
- if ((*i)[0] == '$') {
- char *e = strv_env_get(env, *i+1);
+ if ((*i)[0] == '$' && (*i)[1] != '{') {
+ char *e;
+ char **w, **m;
+ unsigned q;
- if (e) {
- char **w, **m;
- unsigned q;
+ if ((e = strv_env_get(env, *i+1))) {
if (!(m = strv_split_quoted(e))) {
r[k] = NULL;
strv_free(r);
return NULL;
}
+ } else
+ m = NULL;
- q = strv_length(m);
- l = l + q - 1;
+ q = strv_length(m);
+ l = l + q - 1;
- if (!(w = realloc(r, sizeof(char*) * (l+1)))) {
- r[k] = NULL;
- strv_free(r);
- strv_free(m);
- return NULL;
- }
+ if (!(w = realloc(r, sizeof(char*) * (l+1)))) {
+ r[k] = NULL;
+ strv_free(r);
+ strv_free(m);
+ return NULL;
+ }
- r = w;
+ r = w;
+ if (m) {
memcpy(r + k, m, q * sizeof(char*));
free(m);
-
- k += q;
- continue;
}
+
+ k += q;
+ continue;
}
/* If ${FOO} appears as part of a word, replace it by the variable as-is */
commit 3454f9e519260c1b9908dda23870a6c6cdd79f22
Author: Lennart Poettering <lennart at poettering.net>
Date: Tue Aug 10 20:59:01 2010 +0200
conf: add commented default SysVConsole= value
diff --git a/src/system.conf b/src/system.conf
index 20218d1..11885e0 100644
--- a/src/system.conf
+++ b/src/system.conf
@@ -15,5 +15,6 @@
#DumpCore=yes
#CrashShell=no
#ShowStatus=yes
+#SysVConsole=yes
#CrashChVT=1
#CPUAffinity=1 2
commit b5e9dba8d60b8fb80b6302b6ea2cd665b3ab370c
Author: Lennart Poettering <lennart at poettering.net>
Date: Tue Aug 10 20:57:21 2010 +0200
unit: rename OnlyByDependency= to RefuseManualStart= and introduce RefuseManualStop=
Some unit shall never be start on user request (e.g. shutdown.target)
others never be stopped on user request (e.g. auditd.servce), hence
offer options for both.
diff --git a/fixme b/fixme
index 45dfb62..397f5c3 100644
--- a/fixme
+++ b/fixme
@@ -81,6 +81,10 @@
* hide plymouth in multi-user mode
+* audit
+
+* env vars must be replaced by ""
+
External:
* sysv functions should color when stdout is tty, not stdin
@@ -105,6 +109,14 @@ https://bugs.freedesktop.org/show_bug.cgi?id=29194 -- ConsoleKit
https://bugs.freedesktop.org/show_bug.cgi?id=29205 -- udisks
http://article.gmane.org/gmane.linux.bluez.kernel/6479 -- bluez
http://www.spinics.net/lists/linux-nfs/msg14371.html -- rpcbind
+https://bugzilla.redhat.com/show_bug.cgi?id=617328 -- ntp
+https://bugzilla.redhat.com/show_bug.cgi?id=617320 -- at
+https://bugzilla.redhat.com/show_bug.cgi?id=617326 -- fprintd
+https://bugzilla.redhat.com/show_bug.cgi?id=617333 -- yum
+https://bugzilla.redhat.com/show_bug.cgi?id=617317 -- acpid
+https://bugzilla.redhat.com/show_bug.cgi?id=617327 -- gpm
+https://bugzilla.redhat.com/show_bug.cgi?id=617330 -- pcsc-lite
+https://bugzilla.redhat.com/show_bug.cgi?id=617321 -- audit
Regularly:
diff --git a/man/systemd.unit.xml b/man/systemd.unit.xml
index e5d5968..bb11682 100644
--- a/man/systemd.unit.xml
+++ b/man/systemd.unit.xml
@@ -461,20 +461,26 @@
</varlistentry>
<varlistentry>
- <term><varname>OnlyByDependency=</varname></term>
+ <term><varname>RefuseManualStart=</varname></term>
+ <term><varname>RefuseManualStop=</varname></term>
<listitem><para>Takes a boolean
argument. If <option>true</option>
this unit can only be activated
- indirectly. In this case explicit
- start-up requested by the user is
- denied, however if it is started as a
+ (resp. deactivated) indirectly. In
+ this case explicit start-up
+ (resp. termination) requested by the
+ user is denied, however if it is
+ started (resp. stopped) as a
dependency of another unit, start-up
- will succeed. This is mostly a safety
- feature to ensure that the user does
- not accidentally activate units that are
- not intended to be activated
- explicitly. This option defaults to
+ (resp. termination) will succeed. This
+ is mostly a safety feature to ensure
+ that the user does not accidentally
+ activate units that are not intended
+ to be activated explicitly, and not
+ accidentally deactivate units that are
+ not intended to be deactivated.
+ These options default to
<option>false</option>.</para></listitem>
</varlistentry>
diff --git a/src/dbus-manager.c b/src/dbus-manager.c
index 549f175..6d0ecc3 100644
--- a/src/dbus-manager.c
+++ b/src/dbus-manager.c
@@ -801,8 +801,11 @@ static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection,
job_type = JOB_RELOAD;
}
- if (job_type == JOB_START && u->meta.only_by_dependency) {
- dbus_set_error(&error, BUS_ERROR_ONLY_BY_DEPENDENCY, "Unit may be activated by dependency only.");
+ if ((job_type == JOB_START && u->meta.refuse_manual_start) ||
+ (job_type == JOB_STOP && u->meta.refuse_manual_stop) ||
+ ((job_type == JOB_RESTART || job_type == JOB_TRY_RESTART) &&
+ (u->meta.refuse_manual_start || u->meta.refuse_manual_stop))) {
+ dbus_set_error(&error, BUS_ERROR_ONLY_BY_DEPENDENCY, "Operation refused, may be requested by dependency only.");
return bus_send_error_reply(m, connection, message, &error, -EPERM);
}
diff --git a/src/dbus-unit.c b/src/dbus-unit.c
index c9ccac1..2d59242 100644
--- a/src/dbus-unit.c
+++ b/src/dbus-unit.c
@@ -147,7 +147,28 @@ int bus_unit_append_can_start(Manager *m, DBusMessageIter *i, const char *proper
assert(u);
b = unit_can_start(u) &&
- !u->meta.only_by_dependency;
+ !u->meta.refuse_manual_start;
+
+ if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
+ return -ENOMEM;
+
+ return 0;
+}
+
+int bus_unit_append_can_stop(Manager *m, DBusMessageIter *i, const char *property, void *data) {
+ Unit *u = data;
+ dbus_bool_t b;
+
+ assert(m);
+ assert(i);
+ assert(property);
+ assert(u);
+
+ /* On the lower levels we assume that every unit we can start
+ * we can also stop */
+
+ b = unit_can_start(u) &&
+ !u->meta.refuse_manual_stop;
if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
return -ENOMEM;
@@ -334,8 +355,11 @@ static DBusHandlerResult bus_unit_message_dispatch(Unit *u, DBusConnection *conn
Job *j;
int r;
- if (job_type == JOB_START && u->meta.only_by_dependency) {
- dbus_set_error(&error, BUS_ERROR_ONLY_BY_DEPENDENCY, "Unit may be activated by dependency only.");
+ if ((job_type == JOB_START && u->meta.refuse_manual_start) ||
+ (job_type == JOB_STOP && u->meta.refuse_manual_stop) ||
+ ((job_type == JOB_RESTART || job_type == JOB_TRY_RESTART) &&
+ (u->meta.refuse_manual_start || u->meta.refuse_manual_stop))) {
+ dbus_set_error(&error, BUS_ERROR_ONLY_BY_DEPENDENCY, "Operation refused, may be requested by dependency only.");
return bus_send_error_reply(m, connection, message, &error, -EPERM);
}
diff --git a/src/dbus-unit.h b/src/dbus-unit.h
index 0744377..05892b8 100644
--- a/src/dbus-unit.h
+++ b/src/dbus-unit.h
@@ -85,10 +85,12 @@
" <property name=\"InactiveEnterTimestamp\" type=\"t\" access=\"read\"/>\n" \
" <property name=\"CanReload\" type=\"b\" access=\"read\"/>\n" \
" <property name=\"CanStart\" type=\"b\" access=\"read\"/>\n" \
+ " <property name=\"CanStop\" type=\"b\" access=\"read\"/>\n" \
" <property name=\"Job\" type=\"(uo)\" access=\"read\"/>\n" \
" <property name=\"RecursiveStop\" type=\"b\" access=\"read\"/>\n" \
" <property name=\"StopWhenUneeded\" type=\"b\" access=\"read\"/>\n" \
- " <property name=\"OnlyByDependency\" type=\"b\" access=\"read\"/>\n" \
+ " <property name=\"RefuseManualStart\" type=\"b\" access=\"read\"/>\n" \
+ " <property name=\"RefuseManualStop\" type=\"b\" access=\"read\"/>\n" \
" <property name=\"DefaultDependencies\" type=\"b\" access=\"read\"/>\n" \
" <property name=\"DefaultControlGroup\" type=\"s\" access=\"read\"/>\n" \
" <property name=\"ControlGroups\" type=\"as\" access=\"read\"/>\n" \
@@ -123,11 +125,13 @@
{ "org.freedesktop.systemd1.Unit", "ActiveExitTimestamp", bus_property_append_uint64, "t", &u->meta.active_exit_timestamp.realtime }, \
{ "org.freedesktop.systemd1.Unit", "InactiveEnterTimestamp",bus_property_append_uint64, "t", &u->meta.inactive_enter_timestamp.realtime }, \
{ "org.freedesktop.systemd1.Unit", "CanStart", bus_unit_append_can_start, "b", u }, \
+ { "org.freedesktop.systemd1.Unit", "CanStop", bus_unit_append_can_stop, "b", u }, \
{ "org.freedesktop.systemd1.Unit", "CanReload", bus_unit_append_can_reload, "b", u }, \
{ "org.freedesktop.systemd1.Unit", "Job", bus_unit_append_job, "(uo)", u }, \
{ "org.freedesktop.systemd1.Unit", "RecursiveStop", bus_property_append_bool, "b", &u->meta.recursive_stop }, \
{ "org.freedesktop.systemd1.Unit", "StopWhenUneeded", bus_property_append_bool, "b", &u->meta.stop_when_unneeded }, \
- { "org.freedesktop.systemd1.Unit", "OnlyByDependency", bus_property_append_bool, "b", &u->meta.only_by_dependency }, \
+ { "org.freedesktop.systemd1.Unit", "RefuseManualStart", bus_property_append_bool, "b", &u->meta.refuse_manual_start }, \
+ { "org.freedesktop.systemd1.Unit", "RefuseManualStop", bus_property_append_bool, "b", &u->meta.refuse_manual_stop }, \
{ "org.freedesktop.systemd1.Unit", "DefaultDependencies", bus_property_append_bool, "b", &u->meta.default_dependencies }, \
{ "org.freedesktop.systemd1.Unit", "DefaultControlGroup", bus_unit_append_default_cgroup, "s", u }, \
{ "org.freedesktop.systemd1.Unit", "ControlGroups", bus_unit_append_cgroups, "as", u }, \
@@ -142,6 +146,7 @@ int bus_unit_append_load_state(Manager *m, DBusMessageIter *i, const char *prope
int bus_unit_append_active_state(Manager *m, DBusMessageIter *i, const char *property, void *data);
int bus_unit_append_sub_state(Manager *m, DBusMessageIter *i, const char *property, void *data);
int bus_unit_append_can_start(Manager *m, DBusMessageIter *i, const char *property, void *data);
+int bus_unit_append_can_stop(Manager *m, DBusMessageIter *i, const char *property, void *data);
int bus_unit_append_can_reload(Manager *m, DBusMessageIter *i, const char *property, void *data);
int bus_unit_append_job(Manager *m, DBusMessageIter *i, const char *property, void *data);
int bus_unit_append_default_cgroup(Manager *m, DBusMessageIter *i, const char *property, void *data);
diff --git a/src/dbus.c b/src/dbus.c
index 0ab55b8..cb580e1 100644
--- a/src/dbus.c
+++ b/src/dbus.c
@@ -385,7 +385,7 @@ static DBusHandlerResult api_bus_message_filter(DBusConnection *connection, DBus
r = manager_load_unit(m, name, NULL, &error, &u);
- if (r >= 0 && u->meta.only_by_dependency)
+ if (r >= 0 && u->meta.refuse_manual_start)
r = -EPERM;
if (r >= 0)
diff --git a/src/load-fragment.c b/src/load-fragment.c
index f2f2d72..1a87a96 100644
--- a/src/load-fragment.c
+++ b/src/load-fragment.c
@@ -1566,7 +1566,8 @@ static int load_from_path(Unit *u, const char *path) {
{ "OnFailure", config_parse_deps, UINT_TO_PTR(UNIT_ON_FAILURE), "Unit" },
{ "RecursiveStop", config_parse_bool, &u->meta.recursive_stop, "Unit" },
{ "StopWhenUnneeded", config_parse_bool, &u->meta.stop_when_unneeded, "Unit" },
- { "OnlyByDependency", config_parse_bool, &u->meta.only_by_dependency, "Unit" },
+ { "RefuseManualStart", config_parse_bool, &u->meta.refuse_manual_start, "Unit" },
+ { "RefuseManualStop", config_parse_bool, &u->meta.refuse_manual_stop, "Unit" },
{ "DefaultDependencies", config_parse_bool, &u->meta.default_dependencies, "Unit" },
{ "IgnoreDependencyFailure",config_parse_bool, &u->meta.ignore_dependency_failure, "Unit" },
{ "JobTimeoutSec", config_parse_usec, &u->meta.job_timeout, "Unit" },
diff --git a/src/unit.c b/src/unit.c
index d205ca4..9ccf7a4 100644
--- a/src/unit.c
+++ b/src/unit.c
@@ -646,12 +646,14 @@ void unit_dump(Unit *u, FILE *f, const char *prefix) {
fprintf(f,
"%s\tRecursive Stop: %s\n"
"%s\tStopWhenUnneeded: %s\n"
- "%s\tOnlyByDependency: %s\n"
+ "%s\tRefuseManualStart: %s\n"
+ "%s\tRefuseManualStop: %s\n"
"%s\tDefaultDependencies: %s\n"
"%s\tIgnoreDependencyFailure: %s\n",
prefix, yes_no(u->meta.recursive_stop),
prefix, yes_no(u->meta.stop_when_unneeded),
- prefix, yes_no(u->meta.only_by_dependency),
+ prefix, yes_no(u->meta.refuse_manual_start),
+ prefix, yes_no(u->meta.refuse_manual_stop),
prefix, yes_no(u->meta.default_dependencies),
prefix, yes_no(u->meta.ignore_dependency_failure));
diff --git a/src/unit.h b/src/unit.h
index f657aea..1c97e15 100644
--- a/src/unit.h
+++ b/src/unit.h
@@ -186,15 +186,18 @@ struct Meta {
/* Garbage collect us we nobody wants or requires us anymore */
bool stop_when_unneeded;
- /* Refuse manual starting, allow starting only indirectly via dependency. */
- bool only_by_dependency;
-
/* Create default depedencies */
bool default_dependencies;
/* Bring up this unit even if a dependency fails to start */
bool ignore_dependency_failure;
+ /* Refuse manual starting, allow starting only indirectly via dependency. */
+ bool refuse_manual_start;
+
+ /* Don't allow the user to stop this unit manually, allow stopping only indirectly via dependency. */
+ bool refuse_manual_stop;
+
/* When deserializing, temporarily store the job type for this
* unit here, if there was a job scheduled */
int deserialized_job; /* This is actually of type JobType */
diff --git a/units/basic.target b/units/basic.target
index aa94b94..ecd72ef 100644
--- a/units/basic.target
+++ b/units/basic.target
@@ -11,4 +11,4 @@
Description=Basic System
Requires=sysinit.target local-fs.target swap.target sockets.target
After=sysinit.target local-fs.target swap.target sockets.target
-OnlyByDependency=yes
+RefuseManualStart=yes
diff --git a/units/fedora/killall.service b/units/fedora/killall.service
index 73a0569..3b27375 100644
--- a/units/fedora/killall.service
+++ b/units/fedora/killall.service
@@ -9,7 +9,7 @@
Description=Kill All Processes
DefaultDependencies=no
After=shutdown.target
-OnlyByDependency=yes
+RefuseManualStart=yes
[Service]
Type=finish
diff --git a/units/gentoo/killall.service b/units/gentoo/killall.service
index 0d2f923..3f107e3 100644
--- a/units/gentoo/killall.service
+++ b/units/gentoo/killall.service
@@ -9,7 +9,7 @@
Description=Kill All Processes
DefaultDependencies=no
After=shutdown.target
-OnlyByDependency=yes
+RefuseManualStart=yes
[Service]
Type=finish
diff --git a/units/shutdown.target b/units/shutdown.target
index 586ca4a..6d1fb6f 100644
--- a/units/shutdown.target
+++ b/units/shutdown.target
@@ -9,5 +9,5 @@
[Unit]
Description=Shutdown
-OnlyByDependency=yes
+RefuseManualStart=yes
IgnoreDependencyFailure=yes
diff --git a/units/sysinit.target.m4 b/units/sysinit.target.m4
index 8ca37ff..029bb3c 100644
--- a/units/sysinit.target.m4
+++ b/units/sysinit.target.m4
@@ -11,7 +11,7 @@
Description=System Initialization
Conflicts=emergency.service emergency.target
After=emergency.service emergency.target
-OnlyByDependency=yes
+RefuseManualStart=yes
m4_dnl
m4_ifdef(`TARGET_FEDORA',
m4_dnl Hook in Fedora's /etc/rc.d/rc.sysinit
diff --git a/units/umount.target b/units/umount.target
index 6a00c31..c25696e 100644
--- a/units/umount.target
+++ b/units/umount.target
@@ -9,5 +9,5 @@
[Unit]
Description=Unmount All Filesystems
-OnlyByDependency=yes
+RefuseManualStart=yes
IgnoreDependencyFailure=yes
More information about the systemd-commits
mailing list