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, ...) {