summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--TODO4
-rw-r--r--src/bus-errors.h1
-rw-r--r--src/load-fragment.c13
-rw-r--r--src/main.c11
-rw-r--r--src/manager.c13
-rw-r--r--src/path.c3
-rw-r--r--src/systemctl.c6
-rw-r--r--src/unit.c3
-rw-r--r--src/unit.h1
-rw-r--r--src/util.c15
-rw-r--r--src/util.h3
11 files changed, 57 insertions, 16 deletions
diff --git a/TODO b/TODO
index 47f060b1a0..cdb4cc57f3 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 2db1b77f22..8f5c4eb7f3 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 1685c4adb7..54b1af041c 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 6c65e64a2e..d6f5c56c2a 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 4ee04e181f..26a631e9d7 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 7a871246ad..92f99381e8 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 918dcbe8b5..4beec0fca5 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 2f8b92d3b5..d2652bafb2 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 afae580409..a020bd8a0d 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 85ee09d142..12c19b353b 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 8a510ae5c1..2bf86d9979 100644
--- a/src/util.h
+++ b/src/util.h
@@ -31,6 +31,7 @@
#include <signal.h>
#include <sched.h>
#include <limits.h>
+#include <sys/stat.h>
#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)