-* 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
* 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?
#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"
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;
u->meta.fragment_mtime = timespec_load(&st.st_mtim);
- u->meta.load_state = UNIT_LOADED;
r = 0;
finish:
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...");
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");
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;
return -ENOENT;
p->failure = false;
-path_enter_waiting(p, true);
+ path_enter_waiting(p, true);
+
return 0;
}
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
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
[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);
UNIT_LOADED,
UNIT_ERROR,
UNIT_MERGED,
+ UNIT_BANNED,
_UNIT_LOAD_STATE_MAX,
_UNIT_LOAD_STATE_INVALID = -1
};
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",
#include <signal.h>
#include <sched.h>
#include <limits.h>
+#include <sys/stat.h>
#include "macro.h"
_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)