X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fcore%2Funit.c;h=7cd704351cb0e30300cf37436fed9c0c49156cd7;hp=9df398ad4e207dab27808c41e079bdb67e3cba84;hb=628c89cc68ab96fce2de7ebba5933725d147aecc;hpb=31938a8560a664c32a9d72f1fc2d4347b232e6e9
diff --git a/src/core/unit.c b/src/core/unit.c
index 9df398ad4..7cd704351 100644
--- a/src/core/unit.c
+++ b/src/core/unit.c
@@ -19,12 +19,8 @@
along with systemd; If not, see .
***/
-#include
#include
#include
-#include
-#include
-#include
#include
#include
#include
@@ -45,12 +41,10 @@
#include "cgroup-util.h"
#include "missing.h"
#include "mkdir.h"
-#include "label.h"
#include "fileio-label.h"
-#include "bus-errors.h"
+#include "bus-common-errors.h"
#include "dbus.h"
#include "execute.h"
-#include "virt.h"
#include "dropin.h"
const UnitVTable * const unit_vtable[_UNIT_TYPE_MAX] = {
@@ -92,6 +86,7 @@ Unit *unit_new(Manager *m, size_t size) {
u->deserialized_job = _JOB_TYPE_INVALID;
u->default_dependencies = true;
u->unit_file_state = _UNIT_FILE_STATE_INVALID;
+ u->unit_file_preset = -1;
u->on_failure_job_mode = JOB_REPLACE;
return u;
@@ -277,21 +272,32 @@ int unit_set_description(Unit *u, const char *description) {
}
bool unit_check_gc(Unit *u) {
+ UnitActiveState state;
assert(u);
- if (UNIT_VTABLE(u)->no_gc)
+ if (u->job)
return true;
- if (u->no_gc)
+ if (u->nop_job)
return true;
- if (u->job)
+ state = unit_active_state(u);
+
+ /* If the unit is inactive and failed and no job is queued for
+ * it, then release its runtime resources */
+ if (UNIT_IS_INACTIVE_OR_FAILED(state) &&
+ UNIT_VTABLE(u)->release_resources)
+ UNIT_VTABLE(u)->release_resources(u);
+
+ /* But we keep the unit object around for longer when it is
+ * referenced or configured to not be gc'ed */
+ if (state != UNIT_INACTIVE)
return true;
- if (u->nop_job)
+ if (UNIT_VTABLE(u)->no_gc)
return true;
- if (unit_active_state(u) != UNIT_INACTIVE)
+ if (u->no_gc)
return true;
if (u->refs)
@@ -510,7 +516,7 @@ void unit_free(Unit *u) {
free(u->cgroup_path);
}
- set_remove(u->manager->failed_units, u);
+ manager_update_failed_units(u->manager, u, false);
set_remove(u->manager->startup_units, u);
free(u->description);
@@ -608,7 +614,7 @@ static int reserve_dependencies(Unit *u, Unit *other, UnitDependency d) {
/*
* If u does not have this dependency set allocated, there is no need
- * to reserve anything. In that case other's set will be transfered
+ * to reserve anything. In that case other's set will be transferred
* as a whole to u by complete_move().
*/
if (!u->dependencies[d])
@@ -856,7 +862,7 @@ void unit_dump(Unit *u, FILE *f, const char *prefix) {
assert(u->type >= 0);
prefix = strempty(prefix);
- prefix2 = strappenda(prefix, "\t");
+ prefix2 = strjoina(prefix, "\t");
fprintf(f,
"%s-> Unit %s:\n"
@@ -1387,7 +1393,6 @@ static void unit_status_log_starting_stopping_reloading(Unit *u, JobType t) {
DISABLE_WARNING_FORMAT_NONLITERAL;
snprintf(buf, sizeof(buf), format, unit_description(u));
- char_array_0(buf);
REENABLE_WARNING;
mid = t == JOB_START ? SD_MESSAGE_UNIT_STARTING :
@@ -1411,6 +1416,7 @@ static void unit_status_log_starting_stopping_reloading(Unit *u, JobType t) {
int unit_start(Unit *u) {
UnitActiveState state;
Unit *following;
+ int r;
assert(u);
@@ -1449,8 +1455,8 @@ int unit_start(Unit *u) {
return unit_start(following);
}
- unit_status_log_starting_stopping_reloading(u, JOB_START);
- unit_status_print_starting_stopping(u, JOB_START);
+ if (UNIT_VTABLE(u)->supported && !UNIT_VTABLE(u)->supported(u->manager))
+ return -ENOTSUP;
/* If it is stopped, but we cannot start it, then fail */
if (!UNIT_VTABLE(u)->start)
@@ -1464,7 +1470,14 @@ int unit_start(Unit *u) {
unit_add_to_dbus_queue(u);
- return UNIT_VTABLE(u)->start(u);
+ r = UNIT_VTABLE(u)->start(u);
+ if (r <= 0)
+ return r;
+
+ /* Log if the start function actually did something */
+ unit_status_log_starting_stopping_reloading(u, JOB_START);
+ unit_status_print_starting_stopping(u, JOB_START);
+ return r;
}
bool unit_can_start(Unit *u) {
@@ -1488,6 +1501,7 @@ bool unit_can_isolate(Unit *u) {
int unit_stop(Unit *u) {
UnitActiveState state;
Unit *following;
+ int r;
assert(u);
@@ -1495,21 +1509,24 @@ int unit_stop(Unit *u) {
if (UNIT_IS_INACTIVE_OR_FAILED(state))
return -EALREADY;
- if ((following = unit_following(u))) {
- log_unit_debug(u->id, "Redirecting stop request from %s to %s.",
- u->id, following->id);
+ following = unit_following(u);
+ if (following) {
+ log_unit_debug(u->id, "Redirecting stop request from %s to %s.", u->id, following->id);
return unit_stop(following);
}
- unit_status_log_starting_stopping_reloading(u, JOB_STOP);
- unit_status_print_starting_stopping(u, JOB_STOP);
-
if (!UNIT_VTABLE(u)->stop)
return -EBADR;
unit_add_to_dbus_queue(u);
- return UNIT_VTABLE(u)->stop(u);
+ r = UNIT_VTABLE(u)->stop(u);
+ if (r <= 0)
+ return r;
+
+ unit_status_log_starting_stopping_reloading(u, JOB_STOP);
+ unit_status_print_starting_stopping(u, JOB_STOP);
+ return r;
}
/* Errors:
@@ -1520,6 +1537,7 @@ int unit_stop(Unit *u) {
int unit_reload(Unit *u) {
UnitActiveState state;
Unit *following;
+ int r;
assert(u);
@@ -1534,22 +1552,24 @@ int unit_reload(Unit *u) {
return -EALREADY;
if (state != UNIT_ACTIVE) {
- log_unit_warning(u->id, "Unit %s cannot be reloaded because it is inactive.",
- u->id);
+ log_unit_warning(u->id, "Unit %s cannot be reloaded because it is inactive.", u->id);
return -ENOEXEC;
}
following = unit_following(u);
if (following) {
- log_unit_debug(u->id, "Redirecting reload request from %s to %s.",
- u->id, following->id);
+ log_unit_debug(u->id, "Redirecting reload request from %s to %s.", u->id, following->id);
return unit_reload(following);
}
- unit_status_log_starting_stopping_reloading(u, JOB_RELOAD);
-
unit_add_to_dbus_queue(u);
- return UNIT_VTABLE(u)->reload(u);
+
+ r = UNIT_VTABLE(u)->reload(u);
+ if (r <= 0)
+ return r;
+
+ unit_status_log_starting_stopping_reloading(u, JOB_RELOAD);
+ return r;
}
bool unit_can_reload(Unit *u) {
@@ -1622,12 +1642,14 @@ static void unit_check_binds_to(Unit *u) {
continue;
stop = true;
+ break;
}
if (!stop)
return;
- log_unit_info(u->id, "Unit %s is bound to inactive service. Stopping, too.", u->id);
+ assert(other);
+ log_unit_info(u->id, "Unit %s is bound to inactive unit %s. Stopping, too.", u->id, other->id);
/* A unit we need to run is gone. Sniff. Let's stop this. */
manager_add_job(u->manager, JOB_STOP, u, JOB_FAIL, true, NULL, NULL);
@@ -1775,14 +1797,11 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su
}
/* Keep track of failed units */
- if (ns == UNIT_FAILED)
- set_put(u->manager->failed_units, u);
- else
- set_remove(u->manager->failed_units, u);
+ manager_update_failed_units(u->manager, u, ns == UNIT_FAILED);
/* Make sure the cgroup is always removed when we become inactive */
if (UNIT_IS_INACTIVE_OR_FAILED(ns))
- unit_destroy_cgroup(u);
+ unit_destroy_cgroup_if_empty(u);
/* Note that this doesn't apply to RemainAfterExit services exiting
* successfully, since there's no change of state in that case. Which is
@@ -2672,7 +2691,9 @@ int unit_deserialize(Unit *u, FILE *f, FDSet *fds) {
if (streq(l, "job")) {
if (v[0] == '\0') {
/* new-style serialized job */
- Job *j = job_new_raw(u);
+ Job *j;
+
+ j = job_new_raw(u);
if (!j)
return -ENOMEM;
@@ -2694,12 +2715,11 @@ int unit_deserialize(Unit *u, FILE *f, FDSet *fds) {
job_free(j);
return r;
}
-
- if (j->state == JOB_RUNNING)
- u->manager->n_running_jobs++;
} else {
/* legacy */
- JobType type = job_type_from_string(v);
+ JobType type;
+
+ type = job_type_from_string(v);
if (type < 0)
log_debug("Failed to parse job type value %s", v);
else
@@ -2814,11 +2834,10 @@ int unit_add_node_link(Unit *u, const char *what, bool wants) {
return -ENOMEM;
r = manager_load_unit(u->manager, e, NULL, NULL, &device);
-
if (r < 0)
return r;
- r = unit_add_two_dependencies(u, UNIT_AFTER, UNIT_BINDS_TO, device, true);
+ r = unit_add_two_dependencies(u, UNIT_AFTER, u->manager->running_as == SYSTEMD_SYSTEM ? UNIT_BINDS_TO : UNIT_WANTS, device, true);
if (r < 0)
return r;
@@ -2892,7 +2911,7 @@ bool unit_need_daemon_reload(Unit *u) {
return true;
}
- t = unit_find_dropin_paths(u);
+ (void) unit_find_dropin_paths(u, &t);
loaded_cnt = strv_length(t);
current_cnt = strv_length(u->dropin_paths);
@@ -3090,6 +3109,17 @@ UnitFileState unit_get_unit_file_state(Unit *u) {
return u->unit_file_state;
}
+int unit_get_unit_file_preset(Unit *u) {
+ assert(u);
+
+ if (u->unit_file_preset < 0 && u->fragment_path)
+ u->unit_file_preset = unit_file_query_preset(
+ u->manager->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER,
+ NULL, basename(u->fragment_path));
+
+ return u->unit_file_preset;
+}
+
Unit* unit_ref_set(UnitRef *ref, Unit *u) {
assert(ref);
assert(u);
@@ -3140,6 +3170,10 @@ int unit_patch_contexts(Unit *u) {
r = get_home_dir(&ec->working_directory);
if (r < 0)
return r;
+
+ /* Allow user services to run, even if the
+ * home directory is missing */
+ ec->working_directory_missing_ok = true;
}
if (u->manager->running_as == SYSTEMD_USER &&
@@ -3260,7 +3294,7 @@ static int unit_drop_in_file(Unit *u,
int unit_write_drop_in(Unit *u, UnitSetPropertiesMode mode, const char *name, const char *data) {
- _cleanup_free_ char *dir = NULL;
+ _cleanup_free_ char *dir = NULL, *p = NULL, *q = NULL;
int r;
assert(u);
@@ -3272,7 +3306,24 @@ int unit_write_drop_in(Unit *u, UnitSetPropertiesMode mode, const char *name, co
if (r < 0)
return r;
- return write_drop_in(dir, u->id, 50, name, data);
+ r = write_drop_in(dir, u->id, 50, name, data);
+ if (r < 0)
+ return r;
+
+ r = drop_in_file(dir, u->id, 50, name, &p, &q);
+ if (r < 0)
+ return r;
+
+ r = strv_extend(&u->dropin_paths, q);
+ if (r < 0)
+ return r;
+
+ strv_sort(u->dropin_paths);
+ strv_uniq(u->dropin_paths);
+
+ u->dropin_mtime = now(CLOCK_REALTIME);
+
+ return 0;
}
int unit_write_drop_in_format(Unit *u, UnitSetPropertiesMode mode, const char *name, const char *format, ...) {