#include "mkdir.h"
#include "label.h"
#include "fileio-label.h"
+#include "bus-errors.h"
const UnitVTable * const unit_vtable[_UNIT_TYPE_MAX] = {
[UNIT_SERVICE] = &service_vtable,
strv_free(u->documentation);
free(u->fragment_path);
free(u->source_path);
+ strv_free(u->dropin_paths);
free(u->instance);
set_free_free(u->names);
if (u->source_path)
fprintf(f, "%s\tSource Path: %s\n", prefix, u->source_path);
+ STRV_FOREACH(j, u->dropin_paths)
+ fprintf(f, "%s\tDropIn Path: %s\n", prefix, *j);
+
if (u->job_timeout > 0)
- fprintf(f, "%s\tJob Timeout: %s\n", prefix, format_timespan(timespan, sizeof(timespan), u->job_timeout));
+ fprintf(f, "%s\tJob Timeout: %s\n", prefix, format_timespan(timespan, sizeof(timespan), u->job_timeout, 0));
condition_dump_list(u->conditions, f, prefix);
!UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other)))
manager_add_job(u->manager, JOB_START, other, JOB_FAIL, false, NULL, NULL);
- SET_FOREACH(other, u->dependencies[UNIT_REQUISITE], i)
- if (!set_get(u->dependencies[UNIT_AFTER], other) &&
- !UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other)))
- manager_add_job(u->manager, JOB_START, other, JOB_REPLACE, true, NULL, NULL);
-
SET_FOREACH(other, u->dependencies[UNIT_WANTS], i)
if (!set_get(u->dependencies[UNIT_AFTER], other) &&
!UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other)))
}
void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_success) {
+ Manager *m;
bool unexpected;
assert(u);
* behavior here. For example: if a mount point is remounted
* this function will be called too! */
- if (u->manager->n_reloading <= 0) {
+ m = u->manager;
+
+ if (m->n_reloading <= 0) {
dual_timestamp ts;
dual_timestamp_get(&ts);
if (UNIT_IS_INACTIVE_OR_FAILED(ns))
cgroup_bonding_trim_list(u->cgroup_bondings, true);
+ if (UNIT_IS_INACTIVE_OR_FAILED(os) != UNIT_IS_INACTIVE_OR_FAILED(ns)) {
+ ExecContext *ec = unit_get_exec_context(u);
+ if (ec && exec_context_may_touch_console(ec)) {
+ if (UNIT_IS_INACTIVE_OR_FAILED(ns))
+ m->n_on_console--;
+ else
+ m->n_on_console++;
+ }
+ }
+
if (u->job) {
unexpected = false;
} else
unexpected = true;
- if (u->manager->n_reloading <= 0) {
+ if (m->n_reloading <= 0) {
/* If this state change happened without being
* requested by a job, then let's retroactively start
/* The bus just might have become available,
* hence try to connect to it, if we aren't
* yet connected. */
- bus_init(u->manager, true);
+ bus_init(m, true);
if (u->type == UNIT_SERVICE &&
!UNIT_IS_ACTIVE_OR_RELOADING(os) &&
- u->manager->n_reloading <= 0) {
+ m->n_reloading <= 0) {
/* Write audit record if we have just finished starting up */
- manager_send_unit_audit(u->manager, u, AUDIT_SERVICE_START, true);
+ manager_send_unit_audit(m, u, AUDIT_SERVICE_START, true);
u->in_audit = true;
}
if (!UNIT_IS_ACTIVE_OR_RELOADING(os))
- manager_send_unit_plymouth(u->manager, u);
+ manager_send_unit_plymouth(m, u);
} else {
if (u->type == UNIT_SERVICE &&
UNIT_IS_INACTIVE_OR_FAILED(ns) &&
!UNIT_IS_INACTIVE_OR_FAILED(os) &&
- u->manager->n_reloading <= 0) {
+ m->n_reloading <= 0) {
/* Hmm, if there was no start record written
* write it now, so that we always have a nice
* pair */
if (!u->in_audit) {
- manager_send_unit_audit(u->manager, u, AUDIT_SERVICE_START, ns == UNIT_INACTIVE);
+ manager_send_unit_audit(m, u, AUDIT_SERVICE_START, ns == UNIT_INACTIVE);
if (ns == UNIT_INACTIVE)
- manager_send_unit_audit(u->manager, u, AUDIT_SERVICE_STOP, true);
+ manager_send_unit_audit(m, u, AUDIT_SERVICE_STOP, true);
} else
/* Write audit record if we have just finished shutting down */
- manager_send_unit_audit(u->manager, u, AUDIT_SERVICE_STOP, ns == UNIT_INACTIVE);
+ manager_send_unit_audit(m, u, AUDIT_SERVICE_STOP, ns == UNIT_INACTIVE);
u->in_audit = false;
}
}
- manager_recheck_journal(u->manager);
+ manager_recheck_journal(m);
/* Maybe we finished startup and are now ready for being
* stopped because unneeded? */
- unit_check_unneeded(u);
+ if (u->manager->n_reloading <= 0)
+ unit_check_unneeded(u);
unit_add_to_dbus_queue(u);
unit_add_to_gc_queue(u);
job_free(j);
return r;
}
+
+ if (j->state == JOB_RUNNING)
+ u->manager->n_running_jobs++;
} else {
/* legacy */
JobType type = job_type_from_string(v);
}
bool unit_need_daemon_reload(Unit *u) {
+ _cleanup_strv_free_ char **t = NULL;
+ char **path;
struct stat st;
+ unsigned loaded_cnt, current_cnt;
assert(u);
return true;
}
- return false;
+ t = unit_find_dropin_paths(u);
+ loaded_cnt = strv_length(t);
+ current_cnt = strv_length(u->dropin_paths);
+
+ if (loaded_cnt == current_cnt) {
+ if (loaded_cnt == 0)
+ return false;
+
+ if (strv_overlap(u->dropin_paths, t)) {
+ STRV_FOREACH(path, u->dropin_paths) {
+ zero(st);
+ if (stat(*path, &st) < 0)
+ return true;
+
+ if (u->dropin_mtime > 0 &&
+ timespec_load(&st.st_mtim) > u->dropin_mtime)
+ return true;
+ }
+
+ return false;
+ } else
+ return true;
+ } else
+ return true;
}
void unit_reset_failed(Unit *u) {
return UNIT_VTABLE(u)->kill(u, w, signo, error);
}
+int unit_kill_common(
+ Unit *u,
+ KillWho who,
+ int signo,
+ pid_t main_pid,
+ pid_t control_pid,
+ DBusError *error) {
+
+ int r = 0;
+
+ if (who == KILL_MAIN && main_pid <= 0) {
+ if (main_pid < 0)
+ dbus_set_error(error, BUS_ERROR_NO_SUCH_PROCESS, "%s units have no main processes", unit_type_to_string(u->type));
+ else
+ dbus_set_error(error, BUS_ERROR_NO_SUCH_PROCESS, "No main process to kill");
+ return -ESRCH;
+ }
+
+ if (who == KILL_CONTROL && control_pid <= 0) {
+ if (control_pid < 0)
+ dbus_set_error(error, BUS_ERROR_NO_SUCH_PROCESS, "%s units have no control processes", unit_type_to_string(u->type));
+ else
+ dbus_set_error(error, BUS_ERROR_NO_SUCH_PROCESS, "No control process to kill");
+ return -ESRCH;
+ }
+
+ if (who == KILL_CONTROL || who == KILL_ALL)
+ if (control_pid > 0)
+ if (kill(control_pid, signo) < 0)
+ r = -errno;
+
+ if (who == KILL_MAIN || who == KILL_ALL)
+ if (main_pid > 0)
+ if (kill(main_pid, signo) < 0)
+ r = -errno;
+
+ if (who == KILL_ALL) {
+ _cleanup_set_free_ Set *pid_set = NULL;
+ int q;
+
+ pid_set = set_new(trivial_hash_func, trivial_compare_func);
+ if (!pid_set)
+ return -ENOMEM;
+
+ /* Exclude the control/main pid from being killed via the cgroup */
+ if (control_pid > 0) {
+ q = set_put(pid_set, LONG_TO_PTR(control_pid));
+ if (q < 0)
+ return q;
+ }
+
+ if (main_pid > 0) {
+ q = set_put(pid_set, LONG_TO_PTR(main_pid));
+ if (q < 0)
+ return q;
+ }
+
+ q = cgroup_bonding_kill_list(u->cgroup_bondings, signo, false, false, pid_set, NULL);
+ if (q < 0 && q != -EAGAIN && q != -ESRCH && q != -ENOENT)
+ r = q;
+ }
+
+ return r;
+}
+
int unit_following_set(Unit *u, Set **s) {
assert(u);
assert(s);
return r;
mkdir_p(p, 0755);
- return write_one_line_file_atomic_label(q, data);
+ return write_string_file_atomic_label(q, data);
}
int unit_remove_drop_in(Unit *u, bool runtime, const char *name) {