From 00dc5d769ac4a4019d6b6fe22e8383ec8b030a96 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 8 Oct 2010 02:31:36 +0200 Subject: [PATCH] unit: introduce 'banned' load state for units symlinked to /dev/null --- TODO | 4 ---- src/bus-errors.h | 1 + src/load-fragment.c | 13 +++++++++---- src/main.c | 11 +++++++++-- src/manager.c | 13 +++++++++++-- src/path.c | 3 ++- src/systemctl.c | 6 ++++-- src/unit.c | 3 ++- src/unit.h | 1 + src/util.c | 15 +++++++++++++++ src/util.h | 3 +++ 11 files changed, 57 insertions(+), 16 deletions(-) diff --git a/TODO b/TODO index 47f060b1a..cdb4cc57f 100644 --- a/TODO +++ b/TODO @@ -1,5 +1,3 @@ -* do not throw error when .service file is linked to /dev/null - * oneshot services which do not remain: 'exited' instead of 'dead'? it should be visible in 'systemctl' that they have been run @@ -9,8 +7,6 @@ * implicitly import "defaults" settings file into all types -* "disabled" load state? - * ability to kill services? i.e. in contrast to stopping them, go directly into killing mode? diff --git a/src/bus-errors.h b/src/bus-errors.h index 2db1b77f2..8f5c4eb7f 100644 --- a/src/bus-errors.h +++ b/src/bus-errors.h @@ -37,6 +37,7 @@ #define BUS_ERROR_ONLY_BY_DEPENDENCY "org.freedesktop.systemd1.OnlyByDependency" #define BUS_ERROR_NO_ISOLATION "org.freedesktop.systemd1.NoIsolation" #define BUS_ERROR_LOAD_FAILED "org.freedesktop.systemd1.LoadFailed" +#define BUS_ERROR_BANNED "org.freedesktop.systemd1.Banned" #define BUS_ERROR_JOB_TYPE_NOT_APPLICABLE "org.freedesktop.systemd1.JobTypeNotApplicable" #define BUS_ERROR_TRANSACTION_IS_DESTRUCTIVE "org.freedesktop.systemd1.TransactionIsDestructive" #define BUS_ERROR_TRANSACTION_JOBS_CONFLICTING "org.freedesktop.systemd1.TransactionJobsConflicting" diff --git a/src/load-fragment.c b/src/load-fragment.c index 1685c4adb..54b1af041 100644 --- a/src/load-fragment.c +++ b/src/load-fragment.c @@ -1883,9 +1883,15 @@ static int load_from_path(Unit *u, const char *path) { goto finish; } - /* Now, parse the file contents */ - if ((r = config_parse(filename, f, sections, items, false, u)) < 0) - goto finish; + if (null_or_empty(&st)) + u->meta.load_state = UNIT_BANNED; + else { + /* Now, parse the file contents */ + if ((r = config_parse(filename, f, sections, items, false, u)) < 0) + goto finish; + + u->meta.load_state = UNIT_LOADED; + } free(u->meta.fragment_path); u->meta.fragment_path = filename; @@ -1893,7 +1899,6 @@ static int load_from_path(Unit *u, const char *path) { u->meta.fragment_mtime = timespec_load(&st.st_mtim); - u->meta.load_state = UNIT_LOADED; r = 0; finish: diff --git a/src/main.c b/src/main.c index 6c65e64a2..d6f5c56c2 100644 --- a/src/main.c +++ b/src/main.c @@ -1060,8 +1060,10 @@ int main(int argc, char *argv[]) { if ((r = manager_load_unit(m, arg_default_unit, NULL, &error, &target)) < 0) { log_error("Failed to load default target: %s", bus_error(&error, r)); dbus_error_free(&error); - } else if (target->meta.load_state != UNIT_LOADED) + } else if (target->meta.load_state == UNIT_ERROR) log_error("Failed to load default target: %s", strerror(-target->meta.load_error)); + else if (target->meta.load_state == UNIT_BANNED) + log_error("Default target banned."); if (!target || target->meta.load_state != UNIT_LOADED) { log_info("Trying to load rescue target..."); @@ -1070,12 +1072,17 @@ int main(int argc, char *argv[]) { log_error("Failed to load rescue target: %s", bus_error(&error, r)); dbus_error_free(&error); goto finish; - } else if (target->meta.load_state != UNIT_LOADED) { + } else if (target->meta.load_state == UNIT_ERROR) { log_error("Failed to load rescue target: %s", strerror(-target->meta.load_error)); goto finish; + } else if (target->meta.load_state == UNIT_BANNED) { + log_error("Rescue target banned."); + goto finish; } } + assert(target->meta.load_state == UNIT_LOADED); + if (arg_action == ACTION_TEST) { printf("-> By units:\n"); manager_dump_units(m, stdout, "\t"); diff --git a/src/manager.c b/src/manager.c index 4ee04e181..26a631e9d 100644 --- a/src/manager.c +++ b/src/manager.c @@ -1398,18 +1398,27 @@ static int transaction_add_job_and_dependencies( assert(type < _JOB_TYPE_MAX); assert(unit); - if (unit->meta.load_state != UNIT_LOADED && unit->meta.load_state != UNIT_ERROR) { + if (unit->meta.load_state != UNIT_LOADED && + unit->meta.load_state != UNIT_ERROR && + unit->meta.load_state != UNIT_BANNED) { dbus_set_error(e, BUS_ERROR_LOAD_FAILED, "Unit %s is not loaded properly.", unit->meta.id); return -EINVAL; } if (type != JOB_STOP && unit->meta.load_state == UNIT_ERROR) { - dbus_set_error(e, BUS_ERROR_LOAD_FAILED, "Unit %s failed to load: %s. You might find more information in the system logs.", + dbus_set_error(e, BUS_ERROR_LOAD_FAILED, + "Unit %s failed to load: %s. " + "You might find more information in the system logs.", unit->meta.id, strerror(-unit->meta.load_error)); return -EINVAL; } + if (type != JOB_STOP && unit->meta.load_state == UNIT_BANNED) { + dbus_set_error(e, BUS_ERROR_BANNED, "Unit %s is banned.", unit->meta.id); + return -EINVAL; + } + if (!unit_job_is_applicable(unit, type)) { dbus_set_error(e, BUS_ERROR_JOB_TYPE_NOT_APPLICABLE, "Job type %s is not applicable for unit %s.", job_type_to_string(type), unit->meta.id); return -EBADR; diff --git a/src/path.c b/src/path.c index 7a871246a..92f99381e 100644 --- a/src/path.c +++ b/src/path.c @@ -389,7 +389,8 @@ static int path_start(Unit *u) { return -ENOENT; p->failure = false; -path_enter_waiting(p, true); + path_enter_waiting(p, true); + return 0; } diff --git a/src/systemctl.c b/src/systemctl.c index 918dcbe8b..4beec0fca 100644 --- a/src/systemctl.c +++ b/src/systemctl.c @@ -297,7 +297,8 @@ static void output_units_list(const struct unit_info *unit_infos, unsigned c) { if (!output_show_job(u)) continue; - if (!streq(u->load_state, "loaded")) { + if (!streq(u->load_state, "loaded") && + !streq(u->load_state, "banned")) { on_loaded = ansi_highlight(true); off_loaded = ansi_highlight(false); } else @@ -1628,7 +1629,8 @@ static void print_status_info(UnitStatusInfo *i) { printf("\n"); - if (streq_ptr(i->load_state, "failed")) { + if (streq_ptr(i->load_state, "failed") || + streq_ptr(i->load_state, "banned")) { on = ansi_highlight(true); off = ansi_highlight(false); } else diff --git a/src/unit.c b/src/unit.c index 2f8b92d3b..d2652bafb 100644 --- a/src/unit.c +++ b/src/unit.c @@ -2236,7 +2236,8 @@ static const char* const unit_load_state_table[_UNIT_LOAD_STATE_MAX] = { [UNIT_STUB] = "stub", [UNIT_LOADED] = "loaded", [UNIT_ERROR] = "error", - [UNIT_MERGED] = "merged" + [UNIT_MERGED] = "merged", + [UNIT_BANNED] = "banned" }; DEFINE_STRING_TABLE_LOOKUP(unit_load_state, UnitLoadState); diff --git a/src/unit.h b/src/unit.h index afae58040..a020bd8a0 100644 --- a/src/unit.h +++ b/src/unit.h @@ -62,6 +62,7 @@ enum UnitLoadState { UNIT_LOADED, UNIT_ERROR, UNIT_MERGED, + UNIT_BANNED, _UNIT_LOAD_STATE_MAX, _UNIT_LOAD_STATE_INVALID = -1 }; diff --git a/src/util.c b/src/util.c index 85ee09d14..12c19b353 100644 --- a/src/util.c +++ b/src/util.c @@ -3313,6 +3313,21 @@ void freeze(void) { pause(); } +bool null_or_empty(struct stat *st) { + assert(st); + + if (S_ISREG(st->st_mode) && st->st_size <= 0) + return true; + + /* /dev/null has major/minor of 1:3 */ + if (S_ISCHR(st->st_mode) && + major(st->st_rdev) == 1 && + minor(st->st_rdev) == 3) + return true; + + return false; +} + 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 8a510ae5c..2bf86d997 100644 --- a/src/util.h +++ b/src/util.h @@ -31,6 +31,7 @@ #include #include #include +#include #include "macro.h" @@ -358,6 +359,8 @@ int wait_for_terminate_and_warn(const char *name, pid_t pid); _noreturn_ void freeze(void); +bool null_or_empty(struct stat *st); + #define NULSTR_FOREACH(i, l) \ for ((i) = (l); (i) && *(i); (i) = strchr((i), 0)+1) -- 2.30.2