View | Details | Raw Unified | Return to bug 878853
Collapse All | Expand All

(-)systemd-208.mod.bck/src/core/dbus-scope.c (-9 / +82 lines)
Lines 30-40 Link Here
30
30
31
#define BUS_SCOPE_INTERFACE                                             \
31
#define BUS_SCOPE_INTERFACE                                             \
32
        " <interface name=\"org.freedesktop.systemd1.Scope\">\n"        \
32
        " <interface name=\"org.freedesktop.systemd1.Scope\">\n"        \
33
        "  <method name=\"Abandon\"/>\n"                                \
33
        BUS_UNIT_CGROUP_INTERFACE                                       \
34
        BUS_UNIT_CGROUP_INTERFACE                                       \
35
        "  <property name=\"Controller\" type=\"s\" access=\"read\"/>\n"\
34
        "  <property name=\"TimeoutStopUSec\" type=\"t\" access=\"read\"/>\n" \
36
        "  <property name=\"TimeoutStopUSec\" type=\"t\" access=\"read\"/>\n" \
35
        BUS_KILL_CONTEXT_INTERFACE                                      \
37
        BUS_KILL_CONTEXT_INTERFACE                                      \
36
        BUS_CGROUP_CONTEXT_INTERFACE                                    \
38
        BUS_CGROUP_CONTEXT_INTERFACE                                    \
37
        "  <property name=\"Result\" type=\"s\" access=\"read\"/>\n"    \
39
        "  <property name=\"Result\" type=\"s\" access=\"read\"/>\n"    \
40
        "  <signal name=\"RequestStop\"/>\n"                            \
38
        " </interface>\n"
41
        " </interface>\n"
39
42
40
#define INTROSPECTION                                                   \
43
#define INTROSPECTION                                                   \
Lines 56-61 Link Here
56
static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_scope_append_scope_result, scope_result, ScopeResult);
59
static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_scope_append_scope_result, scope_result, ScopeResult);
57
60
58
static const BusProperty bus_scope_properties[] = {
61
static const BusProperty bus_scope_properties[] = {
62
        { "Controller",             bus_property_append_string,    "s", offsetof(Scope, controller)        },
59
        { "TimeoutStopUSec",        bus_property_append_usec,      "t", offsetof(Scope, timeout_stop_usec) },
63
        { "TimeoutStopUSec",        bus_property_append_usec,      "t", offsetof(Scope, timeout_stop_usec) },
60
        { "Result",                 bus_scope_append_scope_result, "s", offsetof(Scope, result)            },
64
        { "Result",                 bus_scope_append_scope_result, "s", offsetof(Scope, result)            },
61
        {}
65
        {}
Lines 63-81 Link Here
63
67
64
DBusHandlerResult bus_scope_message_handler(Unit *u, DBusConnection *c, DBusMessage *message) {
68
DBusHandlerResult bus_scope_message_handler(Unit *u, DBusConnection *c, DBusMessage *message) {
65
        Scope *s = SCOPE(u);
69
        Scope *s = SCOPE(u);
70
        _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
66
71
67
        const BusBoundProperties bps[] = {
72
        SELINUX_UNIT_ACCESS_CHECK(u, c, message, "status");
73
74
        if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Scope", "Abandon")) {
75
                int r;
76
77
                r = scope_abandon(s);
78
                if (r < 0)
79
                        log_error("Failed to mark scope %s as abandoned : %s", UNIT(s)->id, strerror(-r));
80
81
                reply = dbus_message_new_method_return(message);
82
                if (!reply)
83
                        goto oom;
84
        } else {
85
                const BusBoundProperties bps[] = {
68
                { "org.freedesktop.systemd1.Unit",  bus_unit_properties,           u },
86
                { "org.freedesktop.systemd1.Unit",  bus_unit_properties,           u },
69
                { "org.freedesktop.systemd1.Scope", bus_unit_cgroup_properties,    u },
87
                { "org.freedesktop.systemd1.Scope", bus_unit_cgroup_properties,    u },
70
                { "org.freedesktop.systemd1.Scope", bus_scope_properties,          s },
88
                { "org.freedesktop.systemd1.Scope", bus_scope_properties,          s },
71
                { "org.freedesktop.systemd1.Scope", bus_cgroup_context_properties, &s->cgroup_context },
89
                { "org.freedesktop.systemd1.Scope", bus_cgroup_context_properties, &s->cgroup_context },
72
                { "org.freedesktop.systemd1.Scope", bus_kill_context_properties,   &s->kill_context   },
90
                { "org.freedesktop.systemd1.Scope", bus_kill_context_properties,   &s->kill_context   },
73
                {}
91
                {}
74
        };
92
                };
75
93
76
        SELINUX_UNIT_ACCESS_CHECK(u, c, message, "status");
94
               return  bus_default_message_handler(c, message, INTROSPECTION, INTERFACES_LIST, bps);
95
        }
77
96
78
        return bus_default_message_handler(c, message, INTROSPECTION, INTERFACES_LIST, bps);
97
        if (reply)
98
                if (!bus_maybe_send_reply(c, message, reply))
99
                        goto oom;
100
101
        return DBUS_HANDLER_RESULT_HANDLED;
102
oom:
103
        return DBUS_HANDLER_RESULT_NEED_MEMORY;
79
}
104
}
80
105
81
static int bus_scope_set_transient_property(
106
static int bus_scope_set_transient_property(
Lines 99-108 Link Here
99
                    dbus_message_iter_get_element_type(i) != DBUS_TYPE_UINT32)
124
                    dbus_message_iter_get_element_type(i) != DBUS_TYPE_UINT32)
100
                        return -EINVAL;
125
                        return -EINVAL;
101
126
102
                r = set_ensure_allocated(&s->pids, trivial_hash_func, trivial_compare_func);
103
                if (r < 0)
104
                        return r;
105
106
                dbus_message_iter_recurse(i, &sub);
127
                dbus_message_iter_recurse(i, &sub);
107
                while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_UINT32) {
128
                while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_UINT32) {
108
                        uint32_t pid;
129
                        uint32_t pid;
Lines 113-119 Link Here
113
                                return -EINVAL;
134
                                return -EINVAL;
114
135
115
                        if (mode != UNIT_CHECK) {
136
                        if (mode != UNIT_CHECK) {
116
                                r = set_put(s->pids, LONG_TO_PTR(pid));
137
                                r = unit_watch_pid(UNIT(s), pid);
117
                                if (r < 0 && r != -EEXIST)
138
                                if (r < 0 && r != -EEXIST)
118
                                        return r;
139
                                        return r;
119
                        }
140
                        }
Lines 127-132 Link Here
127
148
128
                return 1;
149
                return 1;
129
150
151
        } else if (streq(name, "Controller")) {
152
                const char *controller;
153
154
                if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_STRING)
155
                        return -EINVAL;
156
157
                dbus_message_iter_get_basic(i, &controller);
158
159
                if (!isempty(controller) && !bus_service_name_is_valid(controller))
160
                        return -EINVAL;
161
162
                if (mode != UNIT_CHECK) {
163
                        char *c = NULL;
164
165
                        if (!isempty(controller)) {
166
                                c = strdup(controller);
167
                                if (!c)
168
                                        return -ENOMEM;
169
                        }
170
171
                        free(s->controller);
172
                        s->controller = c;
173
                }
174
175
                return 1;
130
        } else if (streq(name, "TimeoutStopUSec")) {
176
        } else if (streq(name, "TimeoutStopUSec")) {
131
177
132
                if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_UINT64)
178
                if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_UINT64)
Lines 187-189 Link Here
187
        unit_realize_cgroup(u);
233
        unit_realize_cgroup(u);
188
        return 0;
234
        return 0;
189
}
235
}
236
237
int bus_scope_send_request_stop(Scope *s) {
238
        _cleanup_dbus_message_unref_ DBusMessage *m = NULL;
239
        _cleanup_free_ char *p = NULL;
240
        int r;
241
242
        assert(s);
243
244
        if (!s->controller)
245
                return 0;
246
247
        p = unit_dbus_path(UNIT(s));
248
        if (!p)
249
                return -ENOMEM;
250
251
        m = dbus_message_new_signal(p,
252
                                    "org.freedesktop.systemd1.Scope",
253
                                    "RequestStop");
254
        if (!m)
255
                return 0;
256
257
        r = dbus_message_set_destination(m, s->controller);
258
        if (!r)
259
                return 0;
260
261
        return dbus_connection_send(UNIT(s)->manager->api_bus, m, NULL);
262
}
(-)systemd-208.mod.bck/src/core/dbus-scope.h (+2 lines)
Lines 30-33 Link Here
30
int bus_scope_set_property(Unit *u, const char *name, DBusMessageIter *i, UnitSetPropertiesMode mode, DBusError *error);
30
int bus_scope_set_property(Unit *u, const char *name, DBusMessageIter *i, UnitSetPropertiesMode mode, DBusError *error);
31
int bus_scope_commit_properties(Unit *u);
31
int bus_scope_commit_properties(Unit *u);
32
32
33
int bus_scope_send_request_stop(Scope *s);
34
33
extern const char bus_scope_interface[];
35
extern const char bus_scope_interface[];
(-)systemd-208.mod.bck/src/core/manager.c (-1 / +1 lines)
Lines 1389-1395 Link Here
1389
                log_debug_unit(u->id,
1389
                log_debug_unit(u->id,
1390
                               "Child %lu belongs to %s", (long unsigned) si.si_pid, u->id);
1390
                               "Child %lu belongs to %s", (long unsigned) si.si_pid, u->id);
1391
1391
1392
                hashmap_remove(m->watch_pids, LONG_TO_PTR(si.si_pid));
1392
                unit_unwatch_pid(u, si.si_pid);
1393
                UNIT_VTABLE(u)->sigchld_event(u, si.si_pid, si.si_code, si.si_status);
1393
                UNIT_VTABLE(u)->sigchld_event(u, si.si_pid, si.si_code, si.si_status);
1394
        }
1394
        }
1395
1395
(-)systemd-208.mod.bck/src/core/scope.c (-26 / +79 lines)
Lines 35-40 Link Here
35
static const UnitActiveState state_translation_table[_SCOPE_STATE_MAX] = {
35
static const UnitActiveState state_translation_table[_SCOPE_STATE_MAX] = {
36
        [SCOPE_DEAD] = UNIT_INACTIVE,
36
        [SCOPE_DEAD] = UNIT_INACTIVE,
37
        [SCOPE_RUNNING] = UNIT_ACTIVE,
37
        [SCOPE_RUNNING] = UNIT_ACTIVE,
38
        [SCOPE_ABANDONED] = UNIT_ACTIVE,
38
        [SCOPE_STOP_SIGTERM] = UNIT_DEACTIVATING,
39
        [SCOPE_STOP_SIGTERM] = UNIT_DEACTIVATING,
39
        [SCOPE_STOP_SIGKILL] = UNIT_DEACTIVATING,
40
        [SCOPE_STOP_SIGKILL] = UNIT_DEACTIVATING,
40
        [SCOPE_FAILED] = UNIT_FAILED
41
        [SCOPE_FAILED] = UNIT_FAILED
Lines 64-71 Link Here
64
65
65
        cgroup_context_done(&s->cgroup_context);
66
        cgroup_context_done(&s->cgroup_context);
66
67
67
        set_free(s->pids);
68
        free(s->controller);
68
        s->pids = NULL;
69
        s->controller = NULL;
69
70
70
        unit_unwatch_timer(u, &s->timer_watch);
71
        unit_unwatch_timer(u, &s->timer_watch);
71
}
72
}
Lines 81-86 Link Here
81
            state != SCOPE_STOP_SIGKILL)
82
            state != SCOPE_STOP_SIGKILL)
82
                unit_unwatch_timer(UNIT(s), &s->timer_watch);
83
                unit_unwatch_timer(UNIT(s), &s->timer_watch);
83
84
85
        if (state == SCOPE_DEAD || state == SCOPE_FAILED)
86
                unit_unwatch_all_pids(UNIT(s));
87
84
        if (state != old_state)
88
        if (state != old_state)
85
                log_debug("%s changed %s -> %s",
89
                log_debug("%s changed %s -> %s",
86
                          UNIT(s)->id,
90
                          UNIT(s)->id,
Lines 112-118 Link Here
112
        if (UNIT(s)->load_state != UNIT_LOADED)
116
        if (UNIT(s)->load_state != UNIT_LOADED)
113
                return 0;
117
                return 0;
114
118
115
        if (set_size(s->pids) <= 0 && UNIT(s)->manager->n_reloading <= 0) {
119
        if (set_size(UNIT(s)->pids) <= 0 && UNIT(s)->manager->n_reloading <= 0) {
116
                log_error_unit(UNIT(s)->id, "Scope %s has no PIDs. Refusing.", UNIT(s)->id);
120
                log_error_unit(UNIT(s)->id, "Scope %s has no PIDs. Refusing.", UNIT(s)->id);
117
                return -EINVAL;
121
                return -EINVAL;
118
        }
122
        }
Lines 166-171 Link Here
166
                                return r;
170
                                return r;
167
                }
171
                }
168
172
173
                if (s->deserialized_state != SCOPE_DEAD && s->deserialized_state != SCOPE_FAILED)
174
                        unit_watch_all_pids(UNIT(s));
175
169
                scope_set_state(s, s->deserialized_state);
176
                scope_set_state(s, s->deserialized_state);
170
        }
177
        }
171
178
Lines 198-203 Link Here
198
}
205
}
199
206
200
static void scope_enter_signal(Scope *s, ScopeState state, ScopeResult f) {
207
static void scope_enter_signal(Scope *s, ScopeState state, ScopeResult f) {
208
        bool skip_signal = false;
201
        int r;
209
        int r;
202
210
203
        assert(s);
211
        assert(s);
Lines 205-217 Link Here
205
        if (f != SCOPE_SUCCESS)
213
        if (f != SCOPE_SUCCESS)
206
                s->result = f;
214
                s->result = f;
207
215
208
        r = unit_kill_context(
216
        unit_watch_all_pids(UNIT(s));
217
218
        /* If we have a controller set let's ask the controller nicely
219
         * to terminate the scope, instead of us going directly into
220
         * SIGTERM beserk mode */
221
        if (state == SCOPE_STOP_SIGTERM)
222
                skip_signal = bus_scope_send_request_stop(s) > 0;
223
224
        if (!skip_signal) {
225
                r = unit_kill_context(
209
                        UNIT(s),
226
                        UNIT(s),
210
                        &s->kill_context,
227
                        &s->kill_context,
211
                        state != SCOPE_STOP_SIGTERM,
228
                        state != SCOPE_STOP_SIGTERM,
212
                        -1, -1, false);
229
                        -1, -1, false);
213
        if (r < 0)
230
214
                goto fail;
231
                if (r < 0)
232
                        goto fail;
233
        } else
234
                r = 1;
215
235
216
        if (r > 0) {
236
        if (r > 0) {
217
                if (s->timeout_stop_usec > 0) {
237
                if (s->timeout_stop_usec > 0) {
Lines 257-269 Link Here
257
                return r;
277
                return r;
258
        }
278
        }
259
279
260
        r = cg_attach_many_everywhere(u->manager->cgroup_supported, u->cgroup_path, s->pids);
280
        r = cg_attach_many_everywhere(u->manager->cgroup_supported, u->cgroup_path, UNIT(s)->pids);
261
        if (r < 0)
281
        if (r < 0)
262
                return r;
282
                return r;
263
283
264
        set_free(s->pids);
265
        s->pids = NULL;
266
267
        s->result = SCOPE_SUCCESS;
284
        s->result = SCOPE_SUCCESS;
268
285
269
        scope_set_state(s, SCOPE_RUNNING);
286
        scope_set_state(s, SCOPE_RUNNING);
Lines 274-286 Link Here
274
        Scope *s = SCOPE(u);
291
        Scope *s = SCOPE(u);
275
292
276
        assert(s);
293
        assert(s);
277
        assert(s->state == SCOPE_RUNNING);
278
294
279
        if (s->state == SCOPE_STOP_SIGTERM ||
295
        if (s->state == SCOPE_STOP_SIGTERM ||
280
            s->state == SCOPE_STOP_SIGKILL)
296
            s->state == SCOPE_STOP_SIGKILL)
281
                return 0;
297
                return 0;
282
298
283
        assert(s->state == SCOPE_RUNNING);
299
        assert(s->state == SCOPE_RUNNING ||
300
               s->state == SCOPE_ABANDONED);
284
301
285
        scope_enter_signal(s, SCOPE_STOP_SIGTERM, SCOPE_SUCCESS);
302
        scope_enter_signal(s, SCOPE_STOP_SIGTERM, SCOPE_SUCCESS);
286
        return 0;
303
        return 0;
Lines 344-350 Link Here
344
        /* Never clean up scopes that still have a process around,
361
        /* Never clean up scopes that still have a process around,
345
         * even if the scope is formally dead. */
362
         * even if the scope is formally dead. */
346
363
347
        if (UNIT(s)->cgroup_path) {
364
        if (u->cgroup_path) {
348
                r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, UNIT(s)->cgroup_path, true);
365
                r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, UNIT(s)->cgroup_path, true);
349
                if (r <= 0)
366
                if (r <= 0)
350
                        return true;
367
                        return true;
Lines 353-358 Link Here
353
        return false;
370
        return false;
354
}
371
}
355
372
373
static void scope_notify_cgroup_empty_event(Unit *u) {
374
        Scope *s = SCOPE(u);
375
376
        assert(u);
377
378
        log_debug_unit(u->id, "%s: cgroup is empty", u->id);
379
380
        if (s->state == SCOPE_RUNNING || s->state == SCOPE_ABANDONED ||
381
            s->state == SCOPE_STOP_SIGTERM || SCOPE_STOP_SIGKILL)
382
                scope_enter_dead(s, SCOPE_SUCCESS);
383
}
384
385
static void scope_sigchld_event(Unit *u, pid_t pid, int code, int status) {
386
        /* If we get a SIGCHLD event for one of the processes we were
387
           interested in, then we look for others to watch, under the
388
           assumption that we'll sooner or later get a SIGCHLD for
389
           them, as the original process we watched was probably the
390
           parent of them, and they are hence now our children. */
391
392
        unit_tidy_watch_pids(u, 0, 0);
393
        unit_watch_all_pids(u);
394
395
        /* If the PID set is empty now, then let's finish this off */
396
        if (set_isempty(u->pids))
397
                scope_notify_cgroup_empty_event(u);
398
}
399
356
static void scope_timer_event(Unit *u, uint64_t elapsed, Watch*w) {
400
static void scope_timer_event(Unit *u, uint64_t elapsed, Watch*w) {
357
        Scope *s = SCOPE(u);
401
        Scope *s = SCOPE(u);
358
402
Lines 383-406 Link Here
383
        }
427
        }
384
}
428
}
385
429
386
static void scope_notify_cgroup_empty_event(Unit *u) {
430
int scope_abandon(Scope *s) {
387
        Scope *s = SCOPE(u);
431
        assert(s);
388
        assert(u);
389
432
390
        log_debug_unit(u->id, "%s: cgroup is empty", u->id);
433
        if (s->state != SCOPE_RUNNING && s->state != SCOPE_ABANDONED)
434
                return -ESTALE;
391
435
392
        switch (s->state) {
436
        free(s->controller);
437
        s->controller = NULL;
393
438
394
        case SCOPE_RUNNING:
439
        /* The client is no longer watching the remaining processes,
395
        case SCOPE_STOP_SIGTERM:
440
         * so let's step in here, under the assumption that the
396
        case SCOPE_STOP_SIGKILL:
441
         * remaining processes will be sooner or later reassigned to
397
                scope_enter_dead(s, SCOPE_SUCCESS);
442
         * us as parent. */
398
443
399
                break;
444
        unit_tidy_watch_pids(UNIT(s), 0, 0);
445
        unit_watch_all_pids(UNIT(s));
400
446
401
        default:
447
        /* If the PID set is empty now, then let's finish this off */
402
                ;
448
        if (set_isempty(UNIT(s)->pids))
403
        }
449
                scope_notify_cgroup_empty_event(UNIT(s));
450
        else
451
                scope_set_state(s, SCOPE_ABANDONED);
452
453
        return 0;
404
}
454
}
405
455
406
_pure_ static UnitActiveState scope_active_state(Unit *u) {
456
_pure_ static UnitActiveState scope_active_state(Unit *u) {
Lines 418-423 Link Here
418
static const char* const scope_state_table[_SCOPE_STATE_MAX] = {
468
static const char* const scope_state_table[_SCOPE_STATE_MAX] = {
419
        [SCOPE_DEAD] = "dead",
469
        [SCOPE_DEAD] = "dead",
420
        [SCOPE_RUNNING] = "running",
470
        [SCOPE_RUNNING] = "running",
471
        [SCOPE_ABANDONED] = "abandoned",
421
        [SCOPE_STOP_SIGTERM] = "stop-sigterm",
472
        [SCOPE_STOP_SIGTERM] = "stop-sigterm",
422
        [SCOPE_STOP_SIGKILL] = "stop-sigkill",
473
        [SCOPE_STOP_SIGKILL] = "stop-sigkill",
423
        [SCOPE_FAILED] = "failed",
474
        [SCOPE_FAILED] = "failed",
Lines 467-472 Link Here
467
518
468
        .check_gc = scope_check_gc,
519
        .check_gc = scope_check_gc,
469
520
521
        .sigchld_event = scope_sigchld_event,
522
470
        .timer_event = scope_timer_event,
523
        .timer_event = scope_timer_event,
471
524
472
        .reset_failed = scope_reset_failed,
525
        .reset_failed = scope_reset_failed,
(-)systemd-208.mod.bck/src/core/scope.h (-1 / +4 lines)
Lines 29-34 Link Here
29
typedef enum ScopeState {
29
typedef enum ScopeState {
30
        SCOPE_DEAD,
30
        SCOPE_DEAD,
31
        SCOPE_RUNNING,
31
        SCOPE_RUNNING,
32
        SCOPE_ABANDONED,
32
        SCOPE_STOP_SIGTERM,
33
        SCOPE_STOP_SIGTERM,
33
        SCOPE_STOP_SIGKILL,
34
        SCOPE_STOP_SIGKILL,
34
        SCOPE_FAILED,
35
        SCOPE_FAILED,
Lines 55-67 Link Here
55
56
56
        usec_t timeout_stop_usec;
57
        usec_t timeout_stop_usec;
57
58
58
        Set *pids;
59
        char *controller;
59
60
60
        Watch timer_watch;
61
        Watch timer_watch;
61
};
62
};
62
63
63
extern const UnitVTable scope_vtable;
64
extern const UnitVTable scope_vtable;
64
65
66
int scope_abandon(Scope *s);
67
65
const char* scope_state_to_string(ScopeState i) _const_;
68
const char* scope_state_to_string(ScopeState i) _const_;
66
ScopeState scope_state_from_string(const char *s) _pure_;
69
ScopeState scope_state_from_string(const char *s) _pure_;
67
70
(-)systemd-208.mod.bck/src/core/service.c (-56 / +84 lines)
Lines 1612-1617 Link Here
1612
                s->control_command_id = _SERVICE_EXEC_COMMAND_INVALID;
1612
                s->control_command_id = _SERVICE_EXEC_COMMAND_INVALID;
1613
        }
1613
        }
1614
1614
1615
        if (state == SERVICE_DEAD ||
1616
            state == SERVICE_FAILED ||
1617
            state == SERVICE_AUTO_RESTART)
1618
                unit_unwatch_all_pids(UNIT(s));
1619
1615
        if (state != SERVICE_START_PRE &&
1620
        if (state != SERVICE_START_PRE &&
1616
            state != SERVICE_START &&
1621
            state != SERVICE_START &&
1617
            state != SERVICE_START_POST &&
1622
            state != SERVICE_START_POST &&
Lines 1711-1718 Link Here
1711
                                        return r;
1716
                                        return r;
1712
                        }
1717
                        }
1713
1718
1719
                if (s->deserialized_state != SERVICE_DEAD &&
1720
                    s->deserialized_state != SERVICE_FAILED &&
1721
                    s->deserialized_state != SERVICE_AUTO_RESTART)
1722
                        unit_watch_all_pids(UNIT(s));
1723
1714
                if (s->deserialized_state == SERVICE_START_POST ||
1724
                if (s->deserialized_state == SERVICE_START_POST ||
1715
                    s->deserialized_state == SERVICE_RUNNING)
1725
                    s->deserialized_state == SERVICE_RUNNING ||
1726
                    s->deserialized_state == SERVICE_RELOAD)
1716
                        service_handle_watchdog(s);
1727
                        service_handle_watchdog(s);
1717
1728
1718
                service_set_state(s, s->deserialized_state);
1729
                service_set_state(s, s->deserialized_state);
Lines 2020-2025 Link Here
2020
                s->result = f;
2031
                s->result = f;
2021
2032
2022
        service_unwatch_control_pid(s);
2033
        service_unwatch_control_pid(s);
2034
        unit_watch_all_pids(UNIT(s));
2023
2035
2024
        s->control_command = s->exec_command[SERVICE_EXEC_STOP_POST];
2036
        s->control_command = s->exec_command[SERVICE_EXEC_STOP_POST];
2025
        if (s->control_command) {
2037
        if (s->control_command) {
Lines 2060-2065 Link Here
2060
        if (f != SERVICE_SUCCESS)
2072
        if (f != SERVICE_SUCCESS)
2061
                s->result = f;
2073
                s->result = f;
2062
2074
2075
        unit_watch_all_pids(UNIT(s));
2076
2063
        r = unit_kill_context(
2077
        r = unit_kill_context(
2064
                        UNIT(s),
2078
                        UNIT(s),
2065
                        &s->kill_context,
2079
                        &s->kill_context,
Lines 2105-2110 Link Here
2105
                s->result = f;
2119
                s->result = f;
2106
2120
2107
        service_unwatch_control_pid(s);
2121
        service_unwatch_control_pid(s);
2122
        unit_watch_all_pids(UNIT(s));
2108
2123
2109
        s->control_command = s->exec_command[SERVICE_EXEC_STOP];
2124
        s->control_command = s->exec_command[SERVICE_EXEC_STOP];
2110
        if (s->control_command) {
2125
        if (s->control_command) {
Lines 3016-3021 Link Here
3016
        service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_FAILURE_RESOURCES);
3031
        service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_FAILURE_RESOURCES);
3017
}
3032
}
3018
3033
3034
static void service_notify_cgroup_empty_event(Unit *u) {
3035
        Service *s = SERVICE(u);
3036
3037
        assert(u);
3038
3039
        log_debug_unit(u->id, "%s: cgroup is empty", u->id);
3040
3041
        switch (s->state) {
3042
3043
                /* Waiting for SIGCHLD is usually more interesting,
3044
                 * because it includes return codes/signals. Which is
3045
                 * why we ignore the cgroup events for most cases,
3046
                 * except when we don't know pid which to expect the
3047
                 * SIGCHLD for. */
3048
3049
        case SERVICE_START:
3050
        case SERVICE_START_POST:
3051
                /* If we were hoping for the daemon to write its PID file,
3052
                 * we can give up now. */
3053
                if (s->pid_file_pathspec) {
3054
                        log_warning_unit(u->id,
3055
                                         "%s never wrote its PID file. Failing.", UNIT(s)->id);
3056
                        service_unwatch_pid_file(s);
3057
                        if (s->state == SERVICE_START)
3058
                                service_enter_signal(s, SERVICE_FINAL_SIGTERM, SERVICE_FAILURE_RESOURCES);
3059
                        else
3060
                                service_enter_stop(s, SERVICE_FAILURE_RESOURCES);
3061
                }
3062
                break;
3063
3064
        case SERVICE_RUNNING:
3065
                /* service_enter_running() will figure out what to do */
3066
                service_enter_running(s, SERVICE_SUCCESS);
3067
                break;
3068
3069
        case SERVICE_STOP_SIGTERM:
3070
        case SERVICE_STOP_SIGKILL:
3071
3072
                if (main_pid_good(s) <= 0 && !control_pid_good(s))
3073
                        service_enter_stop_post(s, SERVICE_SUCCESS);
3074
3075
                break;
3076
3077
        case SERVICE_STOP_POST:
3078
        case SERVICE_FINAL_SIGTERM:
3079
        case SERVICE_FINAL_SIGKILL:
3080
                if (main_pid_good(s) <= 0 && !control_pid_good(s))
3081
                        service_enter_dead(s, SERVICE_SUCCESS, true);
3082
3083
                break;
3084
3085
        default:
3086
                ;
3087
        }
3088
}
3089
3019
static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
3090
static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
3020
        Service *s = SERVICE(u);
3091
        Service *s = SERVICE(u);
3021
        ServiceResult f;
3092
        ServiceResult f;
Lines 3284-3289 Link Here
3284
3355
3285
        /* Notify clients about changed exit status */
3356
        /* Notify clients about changed exit status */
3286
        unit_add_to_dbus_queue(u);
3357
        unit_add_to_dbus_queue(u);
3358
3359
        /* We got one SIGCHLD for the service, let's watch all
3360
         * processes that are now running of the service, and watch
3361
         * that. Among the PIDs we then watch will be children
3362
         * reassigned to us, which hopefully allows us to identify
3363
         * when all children are gone */
3364
        unit_tidy_watch_pids(u, s->main_pid, s->control_pid);
3365
        unit_watch_all_pids(u);
3366
3367
        /* If the PID set is empty now, then let's finish this off */
3368
        if (set_isempty(u->pids))
3369
                service_notify_cgroup_empty_event(u);
3287
}
3370
}
3288
3371
3289
static void service_timer_event(Unit *u, uint64_t elapsed, Watch* w) {
3372
static void service_timer_event(Unit *u, uint64_t elapsed, Watch* w) {
Lines 3387-3447 Link Here
3387
        }
3470
        }
3388
}
3471
}
3389
3472
3390
static void service_notify_cgroup_empty_event(Unit *u) {
3391
        Service *s = SERVICE(u);
3392
3393
        assert(u);
3394
3395
        log_debug_unit(u->id, "%s: cgroup is empty", u->id);
3396
3397
        switch (s->state) {
3398
3399
                /* Waiting for SIGCHLD is usually more interesting,
3400
                 * because it includes return codes/signals. Which is
3401
                 * why we ignore the cgroup events for most cases,
3402
                 * except when we don't know pid which to expect the
3403
                 * SIGCHLD for. */
3404
3405
        case SERVICE_START:
3406
        case SERVICE_START_POST:
3407
                /* If we were hoping for the daemon to write its PID file,
3408
                 * we can give up now. */
3409
                if (s->pid_file_pathspec) {
3410
                        log_warning_unit(u->id,
3411
                                         "%s never wrote its PID file. Failing.", UNIT(s)->id);
3412
                        service_unwatch_pid_file(s);
3413
                        if (s->state == SERVICE_START)
3414
                                service_enter_signal(s, SERVICE_FINAL_SIGTERM, SERVICE_FAILURE_RESOURCES);
3415
                        else
3416
                                service_enter_stop(s, SERVICE_FAILURE_RESOURCES);
3417
                }
3418
                break;
3419
3420
        case SERVICE_RUNNING:
3421
                /* service_enter_running() will figure out what to do */
3422
                service_enter_running(s, SERVICE_SUCCESS);
3423
                break;
3424
3425
        case SERVICE_STOP_SIGTERM:
3426
        case SERVICE_STOP_SIGKILL:
3427
3428
                if (main_pid_good(s) <= 0 && !control_pid_good(s))
3429
                        service_enter_stop_post(s, SERVICE_SUCCESS);
3430
3431
                break;
3432
3433
        case SERVICE_FINAL_SIGTERM:
3434
        case SERVICE_FINAL_SIGKILL:
3435
                if (main_pid_good(s) <= 0 && !control_pid_good(s))
3436
                        service_enter_dead(s, SERVICE_SUCCESS, true);
3437
3438
                break;
3439
3440
        default:
3441
                ;
3442
        }
3443
}
3444
3445
static void service_notify_message(Unit *u, pid_t pid, char **tags) {
3473
static void service_notify_message(Unit *u, pid_t pid, char **tags) {
3446
        Service *s = SERVICE(u);
3474
        Service *s = SERVICE(u);
3447
        const char *e;
3475
        const char *e;
(-)systemd-208.mod.bck/src/core/service.c.orig (-3 / +3 lines)
Lines 2725-2731 Link Here
2725
                unit_serialize_item(u, f, "var-tmp-dir", s->exec_context.var_tmp_dir);
2725
                unit_serialize_item(u, f, "var-tmp-dir", s->exec_context.var_tmp_dir);
2726
2726
2727
        if (s->forbid_restart)
2727
        if (s->forbid_restart)
2728
                unit_serialize_item(u, f, "forbid_restart", yes_no(s->forbid_restart));
2728
                unit_serialize_item(u, f, "forbid-restart", yes_no(s->forbid_restart));
2729
2729
2730
        return 0;
2730
        return 0;
2731
}
2731
}
Lines 2863-2874 Link Here
2863
                        return log_oom();
2863
                        return log_oom();
2864
2864
2865
                s->exec_context.var_tmp_dir = t;
2865
                s->exec_context.var_tmp_dir = t;
2866
        } else if (streq(key, "forbid_restart")) {
2866
        } else if (streq(key, "forbid-restart")) {
2867
                int b;
2867
                int b;
2868
2868
2869
                b = parse_boolean(value);
2869
                b = parse_boolean(value);
2870
                if (b < 0)
2870
                if (b < 0)
2871
                        log_debug_unit(u->id, "Failed to parse forbid_restart value %s", value);
2871
                        log_debug_unit(u->id, "Failed to parse forbid-restart value %s", value);
2872
                else
2872
                else
2873
                        s->forbid_restart = b;
2873
                        s->forbid_restart = b;
2874
        } else
2874
        } else
(-)systemd-208.mod.bck/src/core/unit.c (-1 / +111 lines)
Lines 472-477 Link Here
472
472
473
        set_free_free(u->names);
473
        set_free_free(u->names);
474
474
475
        unit_unwatch_all_pids(u);
476
475
        condition_free_list(u->conditions);
477
        condition_free_list(u->conditions);
476
478
477
        unit_ref_unset(&u->slice);
479
        unit_ref_unset(&u->slice);
Lines 1652-1664 Link Here
1652
}
1654
}
1653
1655
1654
int unit_watch_pid(Unit *u, pid_t pid) {
1656
int unit_watch_pid(Unit *u, pid_t pid) {
1657
        int q, r;
1658
1655
        assert(u);
1659
        assert(u);
1656
        assert(pid >= 1);
1660
        assert(pid >= 1);
1657
1661
1662
        r = set_ensure_allocated(&u->pids, trivial_hash_func, trivial_compare_func);
1663
        if (r < 0)
1664
                return r;
1665
1658
        /* Watch a specific PID. We only support one unit watching
1666
        /* Watch a specific PID. We only support one unit watching
1659
         * each PID for now. */
1667
         * each PID for now. */
1660
1668
1661
        return hashmap_put(u->manager->watch_pids, LONG_TO_PTR(pid), u);
1669
        r = set_put(u->pids, LONG_TO_PTR(pid));
1670
1671
        q = hashmap_put(u->manager->watch_pids, LONG_TO_PTR(pid), u);
1672
        if (q < 0)
1673
                return q;
1674
1675
        return r;
1662
}
1676
}
1663
1677
1664
void unit_unwatch_pid(Unit *u, pid_t pid) {
1678
void unit_unwatch_pid(Unit *u, pid_t pid) {
Lines 1666-1671 Link Here
1666
        assert(pid >= 1);
1680
        assert(pid >= 1);
1667
1681
1668
        hashmap_remove_value(u->manager->watch_pids, LONG_TO_PTR(pid), u);
1682
        hashmap_remove_value(u->manager->watch_pids, LONG_TO_PTR(pid), u);
1683
        set_remove(u->pids, LONG_TO_PTR(pid));
1684
}
1685
1686
static int watch_pids_in_path(Unit *u, const char *path) {
1687
        _cleanup_closedir_ DIR *d = NULL;
1688
        _cleanup_fclose_ FILE *f = NULL;
1689
        int ret = 0, r;
1690
1691
        assert(u);
1692
        assert(path);
1693
1694
        /* Adds all PIDs from a specific cgroup path to the set of PIDs we watch. */
1695
1696
        r = cg_enumerate_processes(SYSTEMD_CGROUP_CONTROLLER, path, &f);
1697
        if (r >= 0) {
1698
                pid_t pid;
1699
1700
                while ((r = cg_read_pid(f, &pid)) > 0) {
1701
                        r = unit_watch_pid(u, pid);
1702
                        if (r < 0 && ret >= 0)
1703
                                ret = r;
1704
                }
1705
                if (r < 0 && ret >= 0)
1706
                        ret = r;
1707
1708
        } else if (ret >= 0)
1709
                ret = r;
1710
1711
        r = cg_enumerate_subgroups(SYSTEMD_CGROUP_CONTROLLER, path, &d);
1712
        if (r >= 0) {
1713
                char *fn;
1714
1715
                while ((r = cg_read_subgroup(d, &fn)) > 0) {
1716
                        _cleanup_free_ char *p = NULL;
1717
1718
                        p = strjoin(path, "/", fn, NULL);
1719
                        free(fn);
1720
1721
                        if (!p)
1722
                                return -ENOMEM;
1723
1724
                        r = watch_pids_in_path(u, p);
1725
                        if (r < 0 && ret >= 0)
1726
                                ret = r;
1727
                }
1728
                if (r < 0 && ret >= 0)
1729
                        ret = r;
1730
1731
        } else if (ret >= 0)
1732
                ret = r;
1733
1734
        return ret;
1735
}
1736
1737
1738
int unit_watch_all_pids(Unit *u) {
1739
        assert(u);
1740
1741
        if (!u->cgroup_path)
1742
                return -ENOENT;
1743
1744
        /* Adds all PIDs from our cgroup to the set of PIDs we watch */
1745
1746
        return watch_pids_in_path(u, u->cgroup_path);
1747
}
1748
1749
void unit_unwatch_all_pids(Unit *u) {
1750
        Iterator i;
1751
        void *e;
1752
1753
        assert(u);
1754
1755
        SET_FOREACH(e, u->pids, i)
1756
                hashmap_remove_value(u->manager->watch_pids, e, u);
1757
1758
        set_free(u->pids);
1759
        u->pids = NULL;
1760
}
1761
1762
void unit_tidy_watch_pids(Unit *u, pid_t except1, pid_t except2) {
1763
        Iterator i;
1764
        void *e;
1765
1766
        assert(u);
1767
1768
        /* Cleans dead PIDs from our list */
1769
1770
        SET_FOREACH(e, u->pids, i) {
1771
                pid_t pid = PTR_TO_LONG(e);
1772
1773
                if (pid == except1 || pid == except2)
1774
                        continue;
1775
1776
                if (kill(pid, 0) < 0 && errno == ESRCH)
1777
                        set_remove(u->pids, e);
1778
        }
1669
}
1779
}
1670
1780
1671
int unit_watch_timer(Unit *u, clockid_t clock_id, bool relative, usec_t usec, Watch *w) {
1781
int unit_watch_timer(Unit *u, clockid_t clock_id, bool relative, usec_t usec, Watch *w) {
(-)systemd-208.mod.bck/src/core/unit.c.orig (+3159 lines)
Line 0 Link Here
1
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3
/***
4
  This file is part of systemd.
5
6
  Copyright 2010 Lennart Poettering
7
8
  systemd is free software; you can redistribute it and/or modify it
9
  under the terms of the GNU Lesser General Public License as published by
10
  the Free Software Foundation; either version 2.1 of the License, or
11
  (at your option) any later version.
12
13
  systemd is distributed in the hope that it will be useful, but
14
  WITHOUT ANY WARRANTY; without even the implied warranty of
15
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16
  Lesser General Public License for more details.
17
18
  You should have received a copy of the GNU Lesser General Public License
19
  along with systemd; If not, see <http://www.gnu.org/licenses/>.
20
***/
21
22
#include <assert.h>
23
#include <errno.h>
24
#include <string.h>
25
#include <sys/epoll.h>
26
#include <sys/timerfd.h>
27
#include <sys/poll.h>
28
#include <stdlib.h>
29
#include <unistd.h>
30
#include <sys/stat.h>
31
32
#include "systemd/sd-id128.h"
33
#include "systemd/sd-messages.h"
34
#include "set.h"
35
#include "unit.h"
36
#include "macro.h"
37
#include "strv.h"
38
#include "path-util.h"
39
#include "load-fragment.h"
40
#include "load-dropin.h"
41
#include "log.h"
42
#include "unit-name.h"
43
#include "dbus-unit.h"
44
#include "special.h"
45
#include "cgroup-util.h"
46
#include "missing.h"
47
#include "mkdir.h"
48
#include "label.h"
49
#include "fileio-label.h"
50
#include "bus-errors.h"
51
52
const UnitVTable * const unit_vtable[_UNIT_TYPE_MAX] = {
53
        [UNIT_SERVICE] = &service_vtable,
54
        [UNIT_TIMER] = &timer_vtable,
55
        [UNIT_SOCKET] = &socket_vtable,
56
        [UNIT_TARGET] = &target_vtable,
57
        [UNIT_DEVICE] = &device_vtable,
58
        [UNIT_MOUNT] = &mount_vtable,
59
        [UNIT_AUTOMOUNT] = &automount_vtable,
60
        [UNIT_SNAPSHOT] = &snapshot_vtable,
61
        [UNIT_SWAP] = &swap_vtable,
62
        [UNIT_PATH] = &path_vtable,
63
        [UNIT_SLICE] = &slice_vtable,
64
        [UNIT_SCOPE] = &scope_vtable
65
};
66
67
Unit *unit_new(Manager *m, size_t size) {
68
        Unit *u;
69
70
        assert(m);
71
        assert(size >= sizeof(Unit));
72
73
        u = malloc0(size);
74
        if (!u)
75
                return NULL;
76
77
        u->names = set_new(string_hash_func, string_compare_func);
78
        if (!u->names) {
79
                free(u);
80
                return NULL;
81
        }
82
83
        u->manager = m;
84
        u->type = _UNIT_TYPE_INVALID;
85
        u->deserialized_job = _JOB_TYPE_INVALID;
86
        u->default_dependencies = true;
87
        u->unit_file_state = _UNIT_FILE_STATE_INVALID;
88
89
        return u;
90
}
91
92
bool unit_has_name(Unit *u, const char *name) {
93
        assert(u);
94
        assert(name);
95
96
        return !!set_get(u->names, (char*) name);
97
}
98
99
int unit_add_name(Unit *u, const char *text) {
100
        UnitType t;
101
        char *s, *i = NULL;
102
        int r;
103
104
        assert(u);
105
        assert(text);
106
107
        if (unit_name_is_template(text)) {
108
                if (!u->instance)
109
                        return -EINVAL;
110
111
                s = unit_name_replace_instance(text, u->instance);
112
        } else
113
                s = strdup(text);
114
115
        if (!s)
116
                return -ENOMEM;
117
118
        if (!unit_name_is_valid(s, false)) {
119
                r = -EINVAL;
120
                goto fail;
121
        }
122
123
        assert_se((t = unit_name_to_type(s)) >= 0);
124
125
        if (u->type != _UNIT_TYPE_INVALID && t != u->type) {
126
                r = -EINVAL;
127
                goto fail;
128
        }
129
130
        if ((r = unit_name_to_instance(s, &i)) < 0)
131
                goto fail;
132
133
        if (i && unit_vtable[t]->no_instances) {
134
                r = -EINVAL;
135
                goto fail;
136
        }
137
138
        /* Ensure that this unit is either instanced or not instanced,
139
         * but not both. */
140
        if (u->type != _UNIT_TYPE_INVALID && !u->instance != !i) {
141
                r = -EINVAL;
142
                goto fail;
143
        }
144
145
        if (unit_vtable[t]->no_alias &&
146
            !set_isempty(u->names) &&
147
            !set_get(u->names, s)) {
148
                r = -EEXIST;
149
                goto fail;
150
        }
151
152
        if (hashmap_size(u->manager->units) >= MANAGER_MAX_NAMES) {
153
                r = -E2BIG;
154
                goto fail;
155
        }
156
157
        if ((r = set_put(u->names, s)) < 0) {
158
                if (r == -EEXIST)
159
                        r = 0;
160
                goto fail;
161
        }
162
163
        if ((r = hashmap_put(u->manager->units, s, u)) < 0) {
164
                set_remove(u->names, s);
165
                goto fail;
166
        }
167
168
        if (u->type == _UNIT_TYPE_INVALID) {
169
170
                u->type = t;
171
                u->id = s;
172
                u->instance = i;
173
174
                LIST_PREPEND(Unit, units_by_type, u->manager->units_by_type[t], u);
175
176
                if (UNIT_VTABLE(u)->init)
177
                        UNIT_VTABLE(u)->init(u);
178
        } else
179
                free(i);
180
181
        unit_add_to_dbus_queue(u);
182
        return 0;
183
184
fail:
185
        free(s);
186
        free(i);
187
188
        return r;
189
}
190
191
int unit_choose_id(Unit *u, const char *name) {
192
        char *s, *i;
193
        _cleanup_free_ char *t = NULL;
194
        int r;
195
196
        assert(u);
197
        assert(name);
198
199
        if (unit_name_is_template(name)) {
200
201
                if (!u->instance)
202
                        return -EINVAL;
203
204
                if (!(t = unit_name_replace_instance(name, u->instance)))
205
                        return -ENOMEM;
206
207
                name = t;
208
        }
209
210
        /* Selects one of the names of this unit as the id */
211
        s = set_get(u->names, (char*) name);
212
213
        if (!s)
214
                return -ENOENT;
215
216
        if ((r = unit_name_to_instance(s, &i)) < 0)
217
                return r;
218
219
        u->id = s;
220
221
        free(u->instance);
222
        u->instance = i;
223
224
        unit_add_to_dbus_queue(u);
225
226
        return 0;
227
}
228
229
int unit_set_description(Unit *u, const char *description) {
230
        char *s;
231
232
        assert(u);
233
234
        if (isempty(description))
235
                s = NULL;
236
        else {
237
                s = strdup(description);
238
                if (!s)
239
                        return -ENOMEM;
240
        }
241
242
        free(u->description);
243
        u->description = s;
244
245
        unit_add_to_dbus_queue(u);
246
        return 0;
247
}
248
249
bool unit_check_gc(Unit *u) {
250
        assert(u);
251
252
        if (u->load_state == UNIT_STUB)
253
                return true;
254
255
        if (UNIT_VTABLE(u)->no_gc)
256
                return true;
257
258
        if (u->no_gc)
259
                return true;
260
261
        if (u->job)
262
                return true;
263
264
        if (u->nop_job)
265
                return true;
266
267
        if (unit_active_state(u) != UNIT_INACTIVE)
268
                return true;
269
270
        if (u->refs)
271
                return true;
272
273
        if (UNIT_VTABLE(u)->check_gc)
274
                if (UNIT_VTABLE(u)->check_gc(u))
275
                        return true;
276
277
        return false;
278
}
279
280
void unit_add_to_load_queue(Unit *u) {
281
        assert(u);
282
        assert(u->type != _UNIT_TYPE_INVALID);
283
284
        if (u->load_state != UNIT_STUB || u->in_load_queue)
285
                return;
286
287
        LIST_PREPEND(Unit, load_queue, u->manager->load_queue, u);
288
        u->in_load_queue = true;
289
}
290
291
void unit_add_to_cleanup_queue(Unit *u) {
292
        assert(u);
293
294
        if (u->in_cleanup_queue)
295
                return;
296
297
        LIST_PREPEND(Unit, cleanup_queue, u->manager->cleanup_queue, u);
298
        u->in_cleanup_queue = true;
299
}
300
301
void unit_add_to_gc_queue(Unit *u) {
302
        assert(u);
303
304
        if (u->in_gc_queue || u->in_cleanup_queue)
305
                return;
306
307
        if (unit_check_gc(u))
308
                return;
309
310
        LIST_PREPEND(Unit, gc_queue, u->manager->gc_queue, u);
311
        u->in_gc_queue = true;
312
313
        u->manager->n_in_gc_queue ++;
314
}
315
316
void unit_add_to_dbus_queue(Unit *u) {
317
        assert(u);
318
        assert(u->type != _UNIT_TYPE_INVALID);
319
320
        if (u->load_state == UNIT_STUB || u->in_dbus_queue)
321
                return;
322
323
        /* Shortcut things if nobody cares */
324
        if (!bus_has_subscriber(u->manager)) {
325
                u->sent_dbus_new_signal = true;
326
                return;
327
        }
328
329
        LIST_PREPEND(Unit, dbus_queue, u->manager->dbus_unit_queue, u);
330
        u->in_dbus_queue = true;
331
}
332
333
static void bidi_set_free(Unit *u, Set *s) {
334
        Iterator i;
335
        Unit *other;
336
337
        assert(u);
338
339
        /* Frees the set and makes sure we are dropped from the
340
         * inverse pointers */
341
342
        SET_FOREACH(other, s, i) {
343
                UnitDependency d;
344
345
                for (d = 0; d < _UNIT_DEPENDENCY_MAX; d++)
346
                        set_remove(other->dependencies[d], u);
347
348
                unit_add_to_gc_queue(other);
349
        }
350
351
        set_free(s);
352
}
353
354
static void unit_remove_transient(Unit *u) {
355
        char **i;
356
357
        assert(u);
358
359
        if (!u->transient)
360
                return;
361
362
        if (u->fragment_path)
363
                unlink(u->fragment_path);
364
365
        STRV_FOREACH(i, u->dropin_paths) {
366
                _cleanup_free_ char *p = NULL;
367
                int r;
368
369
                unlink(*i);
370
371
                r = path_get_parent(*i, &p);
372
                if (r >= 0)
373
                        rmdir(p);
374
        }
375
}
376
377
static void unit_free_requires_mounts_for(Unit *u) {
378
        char **j;
379
380
        STRV_FOREACH(j, u->requires_mounts_for) {
381
                char s[strlen(*j) + 1];
382
383
                PATH_FOREACH_PREFIX_MORE(s, *j) {
384
                        char *y;
385
                        Set *x;
386
387
                        x = hashmap_get2(u->manager->units_requiring_mounts_for, s, (void**) &y);
388
                        if (!x)
389
                                continue;
390
391
                        set_remove(x, u);
392
393
                        if (set_isempty(x)) {
394
                                hashmap_remove(u->manager->units_requiring_mounts_for, y);
395
                                free(y);
396
                                set_free(x);
397
                        }
398
                }
399
        }
400
401
        strv_free(u->requires_mounts_for);
402
        u->requires_mounts_for = NULL;
403
}
404
405
void unit_free(Unit *u) {
406
        UnitDependency d;
407
        Iterator i;
408
        char *t;
409
410
        assert(u);
411
412
        if (u->manager->n_reloading <= 0)
413
                unit_remove_transient(u);
414
415
        bus_unit_send_removed_signal(u);
416
417
        if (u->load_state != UNIT_STUB)
418
                if (UNIT_VTABLE(u)->done)
419
                        UNIT_VTABLE(u)->done(u);
420
421
        unit_free_requires_mounts_for(u);
422
423
        SET_FOREACH(t, u->names, i)
424
                hashmap_remove_value(u->manager->units, t, u);
425
426
        if (u->job) {
427
                Job *j = u->job;
428
                job_uninstall(j);
429
                job_free(j);
430
        }
431
432
        if (u->nop_job) {
433
                Job *j = u->nop_job;
434
                job_uninstall(j);
435
                job_free(j);
436
        }
437
438
        for (d = 0; d < _UNIT_DEPENDENCY_MAX; d++)
439
                bidi_set_free(u, u->dependencies[d]);
440
441
        if (u->type != _UNIT_TYPE_INVALID)
442
                LIST_REMOVE(Unit, units_by_type, u->manager->units_by_type[u->type], u);
443
444
        if (u->in_load_queue)
445
                LIST_REMOVE(Unit, load_queue, u->manager->load_queue, u);
446
447
        if (u->in_dbus_queue)
448
                LIST_REMOVE(Unit, dbus_queue, u->manager->dbus_unit_queue, u);
449
450
        if (u->in_cleanup_queue)
451
                LIST_REMOVE(Unit, cleanup_queue, u->manager->cleanup_queue, u);
452
453
        if (u->in_gc_queue) {
454
                LIST_REMOVE(Unit, gc_queue, u->manager->gc_queue, u);
455
                u->manager->n_in_gc_queue--;
456
        }
457
458
        if (u->in_cgroup_queue)
459
                LIST_REMOVE(Unit, cgroup_queue, u->manager->cgroup_queue, u);
460
461
        if (u->cgroup_path) {
462
                hashmap_remove(u->manager->cgroup_unit, u->cgroup_path);
463
                free(u->cgroup_path);
464
        }
465
466
        free(u->description);
467
        strv_free(u->documentation);
468
        free(u->fragment_path);
469
        free(u->source_path);
470
        strv_free(u->dropin_paths);
471
        free(u->instance);
472
473
        set_free_free(u->names);
474
475
        condition_free_list(u->conditions);
476
477
        unit_ref_unset(&u->slice);
478
479
        while (u->refs)
480
                unit_ref_unset(u->refs);
481
482
        free(u);
483
}
484
485
UnitActiveState unit_active_state(Unit *u) {
486
        assert(u);
487
488
        if (u->load_state == UNIT_MERGED)
489
                return unit_active_state(unit_follow_merge(u));
490
491
        /* After a reload it might happen that a unit is not correctly
492
         * loaded but still has a process around. That's why we won't
493
         * shortcut failed loading to UNIT_INACTIVE_FAILED. */
494
495
        return UNIT_VTABLE(u)->active_state(u);
496
}
497
498
const char* unit_sub_state_to_string(Unit *u) {
499
        assert(u);
500
501
        return UNIT_VTABLE(u)->sub_state_to_string(u);
502
}
503
504
static void complete_move(Set **s, Set **other) {
505
        assert(s);
506
        assert(other);
507
508
        if (!*other)
509
                return;
510
511
        if (*s)
512
                set_move(*s, *other);
513
        else {
514
                *s = *other;
515
                *other = NULL;
516
        }
517
}
518
519
static void merge_names(Unit *u, Unit *other) {
520
        char *t;
521
        Iterator i;
522
523
        assert(u);
524
        assert(other);
525
526
        complete_move(&u->names, &other->names);
527
528
        set_free_free(other->names);
529
        other->names = NULL;
530
        other->id = NULL;
531
532
        SET_FOREACH(t, u->names, i)
533
                assert_se(hashmap_replace(u->manager->units, t, u) == 0);
534
}
535
536
static void merge_dependencies(Unit *u, Unit *other, UnitDependency d) {
537
        Iterator i;
538
        Unit *back;
539
        int r;
540
541
        assert(u);
542
        assert(other);
543
        assert(d < _UNIT_DEPENDENCY_MAX);
544
545
        /* Fix backwards pointers */
546
        SET_FOREACH(back, other->dependencies[d], i) {
547
                UnitDependency k;
548
549
                for (k = 0; k < _UNIT_DEPENDENCY_MAX; k++)
550
                        if ((r = set_remove_and_put(back->dependencies[k], other, u)) < 0) {
551
552
                                if (r == -EEXIST)
553
                                        set_remove(back->dependencies[k], other);
554
                                else
555
                                        assert(r == -ENOENT);
556
                        }
557
        }
558
559
        complete_move(&u->dependencies[d], &other->dependencies[d]);
560
561
        set_free(other->dependencies[d]);
562
        other->dependencies[d] = NULL;
563
}
564
565
int unit_merge(Unit *u, Unit *other) {
566
        UnitDependency d;
567
568
        assert(u);
569
        assert(other);
570
        assert(u->manager == other->manager);
571
        assert(u->type != _UNIT_TYPE_INVALID);
572
573
        other = unit_follow_merge(other);
574
575
        if (other == u)
576
                return 0;
577
578
        if (u->type != other->type)
579
                return -EINVAL;
580
581
        if (!u->instance != !other->instance)
582
                return -EINVAL;
583
584
        if (other->load_state != UNIT_STUB &&
585
            other->load_state != UNIT_NOT_FOUND)
586
                return -EEXIST;
587
588
        if (other->job)
589
                return -EEXIST;
590
591
        if (other->nop_job)
592
                return -EEXIST;
593
594
        if (!UNIT_IS_INACTIVE_OR_FAILED(unit_active_state(other)))
595
                return -EEXIST;
596
597
        /* Merge names */
598
        merge_names(u, other);
599
600
        /* Redirect all references */
601
        while (other->refs)
602
                unit_ref_set(other->refs, u);
603
604
        /* Merge dependencies */
605
        for (d = 0; d < _UNIT_DEPENDENCY_MAX; d++)
606
                merge_dependencies(u, other, d);
607
608
        other->load_state = UNIT_MERGED;
609
        other->merged_into = u;
610
611
        /* If there is still some data attached to the other node, we
612
         * don't need it anymore, and can free it. */
613
        if (other->load_state != UNIT_STUB)
614
                if (UNIT_VTABLE(other)->done)
615
                        UNIT_VTABLE(other)->done(other);
616
617
        unit_add_to_dbus_queue(u);
618
        unit_add_to_cleanup_queue(other);
619
620
        return 0;
621
}
622
623
int unit_merge_by_name(Unit *u, const char *name) {
624
        Unit *other;
625
        int r;
626
        _cleanup_free_ char *s = NULL;
627
628
        assert(u);
629
        assert(name);
630
631
        if (unit_name_is_template(name)) {
632
                if (!u->instance)
633
                        return -EINVAL;
634
635
                if (!(s = unit_name_replace_instance(name, u->instance)))
636
                        return -ENOMEM;
637
638
                name = s;
639
        }
640
641
        other = manager_get_unit(u->manager, name);
642
        if (!other)
643
                r = unit_add_name(u, name);
644
        else
645
                r = unit_merge(u, other);
646
647
        return r;
648
}
649
650
Unit* unit_follow_merge(Unit *u) {
651
        assert(u);
652
653
        while (u->load_state == UNIT_MERGED)
654
                assert_se(u = u->merged_into);
655
656
        return u;
657
}
658
659
int unit_add_exec_dependencies(Unit *u, ExecContext *c) {
660
        int r;
661
662
        assert(u);
663
        assert(c);
664
665
        if (c->std_output != EXEC_OUTPUT_KMSG &&
666
            c->std_output != EXEC_OUTPUT_SYSLOG &&
667
            c->std_output != EXEC_OUTPUT_JOURNAL &&
668
            c->std_output != EXEC_OUTPUT_KMSG_AND_CONSOLE &&
669
            c->std_output != EXEC_OUTPUT_SYSLOG_AND_CONSOLE &&
670
            c->std_output != EXEC_OUTPUT_JOURNAL_AND_CONSOLE &&
671
            c->std_error != EXEC_OUTPUT_KMSG &&
672
            c->std_error != EXEC_OUTPUT_SYSLOG &&
673
            c->std_error != EXEC_OUTPUT_JOURNAL &&
674
            c->std_error != EXEC_OUTPUT_KMSG_AND_CONSOLE &&
675
            c->std_error != EXEC_OUTPUT_JOURNAL_AND_CONSOLE &&
676
            c->std_error != EXEC_OUTPUT_SYSLOG_AND_CONSOLE)
677
                return 0;
678
679
        /* If syslog or kernel logging is requested, make sure our own
680
         * logging daemon is run first. */
681
682
        if (u->manager->running_as == SYSTEMD_SYSTEM) {
683
                r = unit_add_dependency_by_name(u, UNIT_AFTER, SPECIAL_JOURNALD_SOCKET, NULL, true);
684
                if (r < 0)
685
                        return r;
686
        }
687
688
        return 0;
689
}
690
691
const char *unit_description(Unit *u) {
692
        assert(u);
693
694
        if (u->description)
695
                return u->description;
696
697
        return strna(u->id);
698
}
699
700
void unit_dump(Unit *u, FILE *f, const char *prefix) {
701
        char *t, **j;
702
        UnitDependency d;
703
        Iterator i;
704
        _cleanup_free_ char *p2 = NULL;
705
        const char *prefix2;
706
        char
707
                timestamp1[FORMAT_TIMESTAMP_MAX],
708
                timestamp2[FORMAT_TIMESTAMP_MAX],
709
                timestamp3[FORMAT_TIMESTAMP_MAX],
710
                timestamp4[FORMAT_TIMESTAMP_MAX],
711
                timespan[FORMAT_TIMESPAN_MAX];
712
        Unit *following;
713
714
        assert(u);
715
        assert(u->type >= 0);
716
717
        if (!prefix)
718
                prefix = "";
719
        p2 = strappend(prefix, "\t");
720
        prefix2 = p2 ? p2 : prefix;
721
722
        fprintf(f,
723
                "%s-> Unit %s:\n"
724
                "%s\tDescription: %s\n"
725
                "%s\tInstance: %s\n"
726
                "%s\tUnit Load State: %s\n"
727
                "%s\tUnit Active State: %s\n"
728
                "%s\tInactive Exit Timestamp: %s\n"
729
                "%s\tActive Enter Timestamp: %s\n"
730
                "%s\tActive Exit Timestamp: %s\n"
731
                "%s\tInactive Enter Timestamp: %s\n"
732
                "%s\tGC Check Good: %s\n"
733
                "%s\tNeed Daemon Reload: %s\n"
734
                "%s\tTransient: %s\n"
735
                "%s\tSlice: %s\n"
736
                "%s\tCGroup: %s\n"
737
                "%s\tCGroup realized: %s\n"
738
                "%s\tCGroup mask: 0x%x\n",
739
                prefix, u->id,
740
                prefix, unit_description(u),
741
                prefix, strna(u->instance),
742
                prefix, unit_load_state_to_string(u->load_state),
743
                prefix, unit_active_state_to_string(unit_active_state(u)),
744
                prefix, strna(format_timestamp(timestamp1, sizeof(timestamp1), u->inactive_exit_timestamp.realtime)),
745
                prefix, strna(format_timestamp(timestamp2, sizeof(timestamp2), u->active_enter_timestamp.realtime)),
746
                prefix, strna(format_timestamp(timestamp3, sizeof(timestamp3), u->active_exit_timestamp.realtime)),
747
                prefix, strna(format_timestamp(timestamp4, sizeof(timestamp4), u->inactive_enter_timestamp.realtime)),
748
                prefix, yes_no(unit_check_gc(u)),
749
                prefix, yes_no(unit_need_daemon_reload(u)),
750
                prefix, yes_no(u->transient),
751
                prefix, strna(unit_slice_name(u)),
752
                prefix, strna(u->cgroup_path),
753
                prefix, yes_no(u->cgroup_realized),
754
                prefix, u->cgroup_mask);
755
756
        SET_FOREACH(t, u->names, i)
757
                fprintf(f, "%s\tName: %s\n", prefix, t);
758
759
        STRV_FOREACH(j, u->documentation)
760
                fprintf(f, "%s\tDocumentation: %s\n", prefix, *j);
761
762
        if ((following = unit_following(u)))
763
                fprintf(f, "%s\tFollowing: %s\n", prefix, following->id);
764
765
        if (u->fragment_path)
766
                fprintf(f, "%s\tFragment Path: %s\n", prefix, u->fragment_path);
767
768
        if (u->source_path)
769
                fprintf(f, "%s\tSource Path: %s\n", prefix, u->source_path);
770
771
        STRV_FOREACH(j, u->dropin_paths)
772
                fprintf(f, "%s\tDropIn Path: %s\n", prefix, *j);
773
774
        if (u->job_timeout > 0)
775
                fprintf(f, "%s\tJob Timeout: %s\n", prefix, format_timespan(timespan, sizeof(timespan), u->job_timeout, 0));
776
777
        condition_dump_list(u->conditions, f, prefix);
778
779
        if (dual_timestamp_is_set(&u->condition_timestamp))
780
                fprintf(f,
781
                        "%s\tCondition Timestamp: %s\n"
782
                        "%s\tCondition Result: %s\n",
783
                        prefix, strna(format_timestamp(timestamp1, sizeof(timestamp1), u->condition_timestamp.realtime)),
784
                        prefix, yes_no(u->condition_result));
785
786
        for (d = 0; d < _UNIT_DEPENDENCY_MAX; d++) {
787
                Unit *other;
788
789
                SET_FOREACH(other, u->dependencies[d], i)
790
                        fprintf(f, "%s\t%s: %s\n", prefix, unit_dependency_to_string(d), other->id);
791
        }
792
793
        if (!strv_isempty(u->requires_mounts_for)) {
794
                fprintf(f,
795
                        "%s\tRequiresMountsFor:", prefix);
796
797
                STRV_FOREACH(j, u->requires_mounts_for)
798
                        fprintf(f, " %s", *j);
799
800
                fputs("\n", f);
801
        }
802
803
        if (u->load_state == UNIT_LOADED) {
804
805
                fprintf(f,
806
                        "%s\tStopWhenUnneeded: %s\n"
807
                        "%s\tRefuseManualStart: %s\n"
808
                        "%s\tRefuseManualStop: %s\n"
809
                        "%s\tDefaultDependencies: %s\n"
810
                        "%s\tOnFailureIsolate: %s\n"
811
                        "%s\tIgnoreOnIsolate: %s\n"
812
                        "%s\tIgnoreOnSnapshot: %s\n",
813
                        prefix, yes_no(u->stop_when_unneeded),
814
                        prefix, yes_no(u->refuse_manual_start),
815
                        prefix, yes_no(u->refuse_manual_stop),
816
                        prefix, yes_no(u->default_dependencies),
817
                        prefix, yes_no(u->on_failure_isolate),
818
                        prefix, yes_no(u->ignore_on_isolate),
819
                        prefix, yes_no(u->ignore_on_snapshot));
820
821
                if (UNIT_VTABLE(u)->dump)
822
                        UNIT_VTABLE(u)->dump(u, f, prefix2);
823
824
        } else if (u->load_state == UNIT_MERGED)
825
                fprintf(f,
826
                        "%s\tMerged into: %s\n",
827
                        prefix, u->merged_into->id);
828
        else if (u->load_state == UNIT_ERROR)
829
                fprintf(f, "%s\tLoad Error Code: %s\n", prefix, strerror(-u->load_error));
830
831
832
        if (u->job)
833
                job_dump(u->job, f, prefix2);
834
835
        if (u->nop_job)
836
                job_dump(u->nop_job, f, prefix2);
837
838
}
839
840
/* Common implementation for multiple backends */
841
int unit_load_fragment_and_dropin(Unit *u) {
842
        int r;
843
844
        assert(u);
845
846
        /* Load a .service file */
847
        r = unit_load_fragment(u);
848
        if (r < 0)
849
                return r;
850
851
        if (u->load_state == UNIT_STUB)
852
                return -ENOENT;
853
854
        /* Load drop-in directory data */
855
        r = unit_load_dropin(unit_follow_merge(u));
856
        if (r < 0)
857
                return r;
858
859
        return 0;
860
}
861
862
/* Common implementation for multiple backends */
863
int unit_load_fragment_and_dropin_optional(Unit *u) {
864
        int r;
865
866
        assert(u);
867
868
        /* Same as unit_load_fragment_and_dropin(), but whether
869
         * something can be loaded or not doesn't matter. */
870
871
        /* Load a .service file */
872
        r = unit_load_fragment(u);
873
        if (r < 0)
874
                return r;
875
876
        if (u->load_state == UNIT_STUB)
877
                u->load_state = UNIT_LOADED;
878
879
        /* Load drop-in directory data */
880
        r = unit_load_dropin(unit_follow_merge(u));
881
        if (r < 0)
882
                return r;
883
884
        return 0;
885
}
886
887
int unit_add_default_target_dependency(Unit *u, Unit *target) {
888
        assert(u);
889
        assert(target);
890
891
        if (target->type != UNIT_TARGET)
892
                return 0;
893
894
        /* Only add the dependency if both units are loaded, so that
895
         * that loop check below is reliable */
896
        if (u->load_state != UNIT_LOADED ||
897
            target->load_state != UNIT_LOADED)
898
                return 0;
899
900
        /* If either side wants no automatic dependencies, then let's
901
         * skip this */
902
        if (!u->default_dependencies ||
903
            !target->default_dependencies)
904
                return 0;
905
906
        /* Don't create loops */
907
        if (set_get(target->dependencies[UNIT_BEFORE], u))
908
                return 0;
909
910
        return unit_add_dependency(target, UNIT_AFTER, u, true);
911
}
912
913
static int unit_add_default_dependencies(Unit *u) {
914
915
        static const UnitDependency deps[] = {
916
                UNIT_REQUIRED_BY,
917
                UNIT_REQUIRED_BY_OVERRIDABLE,
918
                UNIT_WANTED_BY,
919
                UNIT_BOUND_BY
920
        };
921
922
        Unit *target;
923
        Iterator i;
924
        int r;
925
        unsigned k;
926
927
        assert(u);
928
929
        for (k = 0; k < ELEMENTSOF(deps); k++)
930
                SET_FOREACH(target, u->dependencies[deps[k]], i) {
931
                        r = unit_add_default_target_dependency(u, target);
932
                        if (r < 0)
933
                                return r;
934
                }
935
936
        if (u->default_dependencies && unit_get_cgroup_context(u)) {
937
                if (UNIT_ISSET(u->slice))
938
                        r = unit_add_two_dependencies(u, UNIT_AFTER, UNIT_WANTS, UNIT_DEREF(u->slice), true);
939
                else
940
                        r = unit_add_two_dependencies_by_name(u, UNIT_AFTER, UNIT_WANTS, SPECIAL_ROOT_SLICE, NULL, true);
941
942
                if (r < 0)
943
                        return r;
944
        }
945
946
        return 0;
947
}
948
949
int unit_load(Unit *u) {
950
        int r;
951
952
        assert(u);
953
954
        if (u->in_load_queue) {
955
                LIST_REMOVE(Unit, load_queue, u->manager->load_queue, u);
956
                u->in_load_queue = false;
957
        }
958
959
        if (u->type == _UNIT_TYPE_INVALID)
960
                return -EINVAL;
961
962
        if (u->load_state != UNIT_STUB)
963
                return 0;
964
965
        if (UNIT_VTABLE(u)->load) {
966
                r = UNIT_VTABLE(u)->load(u);
967
                if (r < 0)
968
                        goto fail;
969
        }
970
971
        if (u->load_state == UNIT_STUB) {
972
                r = -ENOENT;
973
                goto fail;
974
        }
975
976
        if (u->load_state == UNIT_LOADED) {
977
978
                if (u->default_dependencies) {
979
                        r = unit_add_default_dependencies(u);
980
                        if (r < 0)
981
                                goto fail;
982
                }
983
984
                r = unit_add_mount_links(u);
985
                if (r < 0)
986
                        goto fail;
987
988
                if (u->on_failure_isolate &&
989
                    set_size(u->dependencies[UNIT_ON_FAILURE]) > 1) {
990
991
                        log_error_unit(u->id,
992
                                       "More than one OnFailure= dependencies specified for %s but OnFailureIsolate= enabled. Refusing.", u->id);
993
994
                        r = -EINVAL;
995
                        goto fail;
996
                }
997
        }
998
999
        assert((u->load_state != UNIT_MERGED) == !u->merged_into);
1000
1001
        unit_add_to_dbus_queue(unit_follow_merge(u));
1002
        unit_add_to_gc_queue(u);
1003
1004
        return 0;
1005
1006
fail:
1007
        u->load_state = u->load_state == UNIT_STUB ? UNIT_NOT_FOUND : UNIT_ERROR;
1008
        u->load_error = r;
1009
        unit_add_to_dbus_queue(u);
1010
        unit_add_to_gc_queue(u);
1011
1012
        log_debug_unit(u->id, "Failed to load configuration for %s: %s",
1013
                       u->id, strerror(-r));
1014
1015
        return r;
1016
}
1017
1018
bool unit_condition_test(Unit *u) {
1019
        assert(u);
1020
1021
        dual_timestamp_get(&u->condition_timestamp);
1022
        u->condition_result = condition_test_list(u->id, u->conditions);
1023
1024
        return u->condition_result;
1025
}
1026
1027
_pure_ static const char* unit_get_status_message_format(Unit *u, JobType t) {
1028
        const UnitStatusMessageFormats *format_table;
1029
1030
        assert(u);
1031
        assert(t >= 0);
1032
        assert(t < _JOB_TYPE_MAX);
1033
1034
        if (t != JOB_START && t != JOB_STOP)
1035
                return NULL;
1036
1037
        format_table = &UNIT_VTABLE(u)->status_message_formats;
1038
        if (!format_table)
1039
                return NULL;
1040
1041
        return format_table->starting_stopping[t == JOB_STOP];
1042
}
1043
1044
_pure_ static const char *unit_get_status_message_format_try_harder(Unit *u, JobType t) {
1045
        const char *format;
1046
1047
        assert(u);
1048
        assert(t >= 0);
1049
        assert(t < _JOB_TYPE_MAX);
1050
1051
        format = unit_get_status_message_format(u, t);
1052
        if (format)
1053
                return format;
1054
1055
        /* Return generic strings */
1056
        if (t == JOB_START)
1057
                return "Starting %s.";
1058
        else if (t == JOB_STOP)
1059
                return "Stopping %s.";
1060
        else if (t == JOB_RELOAD)
1061
                return "Reloading %s.";
1062
1063
        return NULL;
1064
}
1065
1066
static void unit_status_print_starting_stopping(Unit *u, JobType t) {
1067
        const char *format;
1068
1069
        assert(u);
1070
1071
        /* We only print status messages for selected units on
1072
         * selected operations. */
1073
1074
        format = unit_get_status_message_format(u, t);
1075
        if (!format)
1076
                return;
1077
1078
        unit_status_printf(u, "", format);
1079
}
1080
1081
#pragma GCC diagnostic push
1082
#pragma GCC diagnostic ignored "-Wformat-nonliteral"
1083
static void unit_status_log_starting_stopping_reloading(Unit *u, JobType t) {
1084
        const char *format;
1085
        char buf[LINE_MAX];
1086
        sd_id128_t mid;
1087
1088
        assert(u);
1089
1090
        if (t != JOB_START && t != JOB_STOP && t != JOB_RELOAD)
1091
                return;
1092
1093
        if (log_on_console())
1094
                return;
1095
1096
        /* We log status messages for all units and all operations. */
1097
1098
        format = unit_get_status_message_format_try_harder(u, t);
1099
        if (!format)
1100
                return;
1101
1102
        snprintf(buf, sizeof(buf), format, unit_description(u));
1103
        char_array_0(buf);
1104
1105
        mid = t == JOB_START ? SD_MESSAGE_UNIT_STARTING :
1106
              t == JOB_STOP  ? SD_MESSAGE_UNIT_STOPPING :
1107
                               SD_MESSAGE_UNIT_RELOADING;
1108
1109
        log_struct_unit(LOG_INFO,
1110
                        u->id,
1111
                        MESSAGE_ID(mid),
1112
                        "MESSAGE=%s", buf,
1113
                        NULL);
1114
}
1115
#pragma GCC diagnostic pop
1116
1117
/* Errors:
1118
 *         -EBADR:     This unit type does not support starting.
1119
 *         -EALREADY:  Unit is already started.
1120
 *         -EAGAIN:    An operation is already in progress. Retry later.
1121
 *         -ECANCELED: Too many requests for now.
1122
 */
1123
int unit_start(Unit *u) {
1124
        UnitActiveState state;
1125
        Unit *following;
1126
1127
        assert(u);
1128
1129
        if (u->load_state != UNIT_LOADED)
1130
                return -EINVAL;
1131
1132
        /* If this is already started, then this will succeed. Note
1133
         * that this will even succeed if this unit is not startable
1134
         * by the user. This is relied on to detect when we need to
1135
         * wait for units and when waiting is finished. */
1136
        state = unit_active_state(u);
1137
        if (UNIT_IS_ACTIVE_OR_RELOADING(state))
1138
                return -EALREADY;
1139
1140
        /* If the conditions failed, don't do anything at all. If we
1141
         * already are activating this call might still be useful to
1142
         * speed up activation in case there is some hold-off time,
1143
         * but we don't want to recheck the condition in that case. */
1144
        if (state != UNIT_ACTIVATING &&
1145
            !unit_condition_test(u)) {
1146
                log_debug_unit(u->id, "Starting of %s requested but condition failed. Ignoring.", u->id);
1147
                return -EALREADY;
1148
        }
1149
1150
        /* Forward to the main object, if we aren't it. */
1151
        following = unit_following(u);
1152
        if (following) {
1153
                log_debug_unit(u->id, "Redirecting start request from %s to %s.",
1154
                               u->id, following->id);
1155
                return unit_start(following);
1156
        }
1157
1158
        unit_status_log_starting_stopping_reloading(u, JOB_START);
1159
        unit_status_print_starting_stopping(u, JOB_START);
1160
1161
        /* If it is stopped, but we cannot start it, then fail */
1162
        if (!UNIT_VTABLE(u)->start)
1163
                return -EBADR;
1164
1165
        /* We don't suppress calls to ->start() here when we are
1166
         * already starting, to allow this request to be used as a
1167
         * "hurry up" call, for example when the unit is in some "auto
1168
         * restart" state where it waits for a holdoff timer to elapse
1169
         * before it will start again. */
1170
1171
        unit_add_to_dbus_queue(u);
1172
1173
        return UNIT_VTABLE(u)->start(u);
1174
}
1175
1176
bool unit_can_start(Unit *u) {
1177
        assert(u);
1178
1179
        return !!UNIT_VTABLE(u)->start;
1180
}
1181
1182
bool unit_can_isolate(Unit *u) {
1183
        assert(u);
1184
1185
        return unit_can_start(u) &&
1186
                u->allow_isolate;
1187
}
1188
1189
/* Errors:
1190
 *         -EBADR:    This unit type does not support stopping.
1191
 *         -EALREADY: Unit is already stopped.
1192
 *         -EAGAIN:   An operation is already in progress. Retry later.
1193
 */
1194
int unit_stop(Unit *u) {
1195
        UnitActiveState state;
1196
        Unit *following;
1197
1198
        assert(u);
1199
1200
        state = unit_active_state(u);
1201
        if (UNIT_IS_INACTIVE_OR_FAILED(state))
1202
                return -EALREADY;
1203
1204
        if ((following = unit_following(u))) {
1205
                log_debug_unit(u->id, "Redirecting stop request from %s to %s.",
1206
                               u->id, following->id);
1207
                return unit_stop(following);
1208
        }
1209
1210
        unit_status_log_starting_stopping_reloading(u, JOB_STOP);
1211
        unit_status_print_starting_stopping(u, JOB_STOP);
1212
1213
        if (!UNIT_VTABLE(u)->stop)
1214
                return -EBADR;
1215
1216
        unit_add_to_dbus_queue(u);
1217
1218
        return UNIT_VTABLE(u)->stop(u);
1219
}
1220
1221
/* Errors:
1222
 *         -EBADR:    This unit type does not support reloading.
1223
 *         -ENOEXEC:  Unit is not started.
1224
 *         -EAGAIN:   An operation is already in progress. Retry later.
1225
 */
1226
int unit_reload(Unit *u) {
1227
        UnitActiveState state;
1228
        Unit *following;
1229
1230
        assert(u);
1231
1232
        if (u->load_state != UNIT_LOADED)
1233
                return -EINVAL;
1234
1235
        if (!unit_can_reload(u))
1236
                return -EBADR;
1237
1238
        state = unit_active_state(u);
1239
        if (state == UNIT_RELOADING)
1240
                return -EALREADY;
1241
1242
        if (state != UNIT_ACTIVE)
1243
                return -ENOEXEC;
1244
1245
        if ((following = unit_following(u))) {
1246
                log_debug_unit(u->id, "Redirecting reload request from %s to %s.",
1247
                               u->id, following->id);
1248
                return unit_reload(following);
1249
        }
1250
1251
        unit_status_log_starting_stopping_reloading(u, JOB_RELOAD);
1252
1253
        unit_add_to_dbus_queue(u);
1254
        return UNIT_VTABLE(u)->reload(u);
1255
}
1256
1257
bool unit_can_reload(Unit *u) {
1258
        assert(u);
1259
1260
        if (!UNIT_VTABLE(u)->reload)
1261
                return false;
1262
1263
        if (!UNIT_VTABLE(u)->can_reload)
1264
                return true;
1265
1266
        return UNIT_VTABLE(u)->can_reload(u);
1267
}
1268
1269
static void unit_check_unneeded(Unit *u) {
1270
        Iterator i;
1271
        Unit *other;
1272
1273
        assert(u);
1274
1275
        /* If this service shall be shut down when unneeded then do
1276
         * so. */
1277
1278
        if (!u->stop_when_unneeded)
1279
                return;
1280
1281
        if (!UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(u)))
1282
                return;
1283
1284
        SET_FOREACH(other, u->dependencies[UNIT_REQUIRED_BY], i)
1285
                if (unit_active_or_pending(other))
1286
                        return;
1287
1288
        SET_FOREACH(other, u->dependencies[UNIT_REQUIRED_BY_OVERRIDABLE], i)
1289
                if (unit_active_or_pending(other))
1290
                        return;
1291
1292
        SET_FOREACH(other, u->dependencies[UNIT_WANTED_BY], i)
1293
                if (unit_active_or_pending(other))
1294
                        return;
1295
1296
        SET_FOREACH(other, u->dependencies[UNIT_BOUND_BY], i)
1297
                if (unit_active_or_pending(other))
1298
                        return;
1299
1300
        log_info_unit(u->id, "Service %s is not needed anymore. Stopping.", u->id);
1301
1302
        /* Ok, nobody needs us anymore. Sniff. Then let's commit suicide */
1303
        manager_add_job(u->manager, JOB_STOP, u, JOB_FAIL, true, NULL, NULL);
1304
}
1305
1306
static void retroactively_start_dependencies(Unit *u) {
1307
        Iterator i;
1308
        Unit *other;
1309
1310
        assert(u);
1311
        assert(UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(u)));
1312
1313
        SET_FOREACH(other, u->dependencies[UNIT_REQUIRES], i)
1314
                if (!set_get(u->dependencies[UNIT_AFTER], other) &&
1315
                    !UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other)))
1316
                        manager_add_job(u->manager, JOB_START, other, JOB_REPLACE, true, NULL, NULL);
1317
1318
        SET_FOREACH(other, u->dependencies[UNIT_BINDS_TO], i)
1319
                if (!set_get(u->dependencies[UNIT_AFTER], other) &&
1320
                    !UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other)))
1321
                        manager_add_job(u->manager, JOB_START, other, JOB_REPLACE, true, NULL, NULL);
1322
1323
        SET_FOREACH(other, u->dependencies[UNIT_REQUIRES_OVERRIDABLE], i)
1324
                if (!set_get(u->dependencies[UNIT_AFTER], other) &&
1325
                    !UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other)))
1326
                        manager_add_job(u->manager, JOB_START, other, JOB_FAIL, false, NULL, NULL);
1327
1328
        SET_FOREACH(other, u->dependencies[UNIT_WANTS], i)
1329
                if (!set_get(u->dependencies[UNIT_AFTER], other) &&
1330
                    !UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other)))
1331
                        manager_add_job(u->manager, JOB_START, other, JOB_FAIL, false, NULL, NULL);
1332
1333
        SET_FOREACH(other, u->dependencies[UNIT_CONFLICTS], i)
1334
                if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
1335
                        manager_add_job(u->manager, JOB_STOP, other, JOB_REPLACE, true, NULL, NULL);
1336
1337
        SET_FOREACH(other, u->dependencies[UNIT_CONFLICTED_BY], i)
1338
                if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
1339
                        manager_add_job(u->manager, JOB_STOP, other, JOB_REPLACE, true, NULL, NULL);
1340
}
1341
1342
static void retroactively_stop_dependencies(Unit *u) {
1343
        Iterator i;
1344
        Unit *other;
1345
1346
        assert(u);
1347
        assert(UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(u)));
1348
1349
        /* Pull down units which are bound to us recursively if enabled */
1350
        SET_FOREACH(other, u->dependencies[UNIT_BOUND_BY], i)
1351
                if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
1352
                        manager_add_job(u->manager, JOB_STOP, other, JOB_REPLACE, true, NULL, NULL);
1353
}
1354
1355
static void check_unneeded_dependencies(Unit *u) {
1356
        Iterator i;
1357
        Unit *other;
1358
1359
        assert(u);
1360
        assert(UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(u)));
1361
1362
        /* Garbage collect services that might not be needed anymore, if enabled */
1363
        SET_FOREACH(other, u->dependencies[UNIT_REQUIRES], i)
1364
                if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
1365
                        unit_check_unneeded(other);
1366
        SET_FOREACH(other, u->dependencies[UNIT_REQUIRES_OVERRIDABLE], i)
1367
                if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
1368
                        unit_check_unneeded(other);
1369
        SET_FOREACH(other, u->dependencies[UNIT_WANTS], i)
1370
                if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
1371
                        unit_check_unneeded(other);
1372
        SET_FOREACH(other, u->dependencies[UNIT_REQUISITE], i)
1373
                if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
1374
                        unit_check_unneeded(other);
1375
        SET_FOREACH(other, u->dependencies[UNIT_REQUISITE_OVERRIDABLE], i)
1376
                if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
1377
                        unit_check_unneeded(other);
1378
        SET_FOREACH(other, u->dependencies[UNIT_BINDS_TO], i)
1379
                if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
1380
                        unit_check_unneeded(other);
1381
}
1382
1383
void unit_start_on_failure(Unit *u) {
1384
        Unit *other;
1385
        Iterator i;
1386
1387
        assert(u);
1388
1389
        if (set_size(u->dependencies[UNIT_ON_FAILURE]) <= 0)
1390
                return;
1391
1392
        log_info_unit(u->id, "Triggering OnFailure= dependencies of %s.", u->id);
1393
1394
        SET_FOREACH(other, u->dependencies[UNIT_ON_FAILURE], i) {
1395
                int r;
1396
1397
                r = manager_add_job(u->manager, JOB_START, other, u->on_failure_isolate ? JOB_ISOLATE : JOB_REPLACE, true, NULL, NULL);
1398
                if (r < 0)
1399
                        log_error_unit(u->id, "Failed to enqueue OnFailure= job: %s", strerror(-r));
1400
        }
1401
}
1402
1403
void unit_trigger_notify(Unit *u) {
1404
        Unit *other;
1405
        Iterator i;
1406
1407
        assert(u);
1408
1409
        SET_FOREACH(other, u->dependencies[UNIT_TRIGGERED_BY], i)
1410
                if (UNIT_VTABLE(other)->trigger_notify)
1411
                        UNIT_VTABLE(other)->trigger_notify(other, u);
1412
}
1413
1414
void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_success) {
1415
        Manager *m;
1416
        bool unexpected;
1417
1418
        assert(u);
1419
        assert(os < _UNIT_ACTIVE_STATE_MAX);
1420
        assert(ns < _UNIT_ACTIVE_STATE_MAX);
1421
1422
        /* Note that this is called for all low-level state changes,
1423
         * even if they might map to the same high-level
1424
         * UnitActiveState! That means that ns == os is OK an expected
1425
         * behavior here. For example: if a mount point is remounted
1426
         * this function will be called too! */
1427
1428
        m = u->manager;
1429
1430
        if (m->n_reloading <= 0) {
1431
                dual_timestamp ts;
1432
1433
                dual_timestamp_get(&ts);
1434
1435
                if (UNIT_IS_INACTIVE_OR_FAILED(os) && !UNIT_IS_INACTIVE_OR_FAILED(ns))
1436
                        u->inactive_exit_timestamp = ts;
1437
                else if (!UNIT_IS_INACTIVE_OR_FAILED(os) && UNIT_IS_INACTIVE_OR_FAILED(ns))
1438
                        u->inactive_enter_timestamp = ts;
1439
1440
                if (!UNIT_IS_ACTIVE_OR_RELOADING(os) && UNIT_IS_ACTIVE_OR_RELOADING(ns))
1441
                        u->active_enter_timestamp = ts;
1442
                else if (UNIT_IS_ACTIVE_OR_RELOADING(os) && !UNIT_IS_ACTIVE_OR_RELOADING(ns))
1443
                        u->active_exit_timestamp = ts;
1444
        }
1445
1446
        if (UNIT_IS_INACTIVE_OR_FAILED(ns))
1447
                unit_destroy_cgroup(u);
1448
1449
        if (UNIT_IS_INACTIVE_OR_FAILED(os) != UNIT_IS_INACTIVE_OR_FAILED(ns)) {
1450
                ExecContext *ec = unit_get_exec_context(u);
1451
                if (ec && exec_context_may_touch_console(ec)) {
1452
                        if (UNIT_IS_INACTIVE_OR_FAILED(ns)) {
1453
                                m->n_on_console --;
1454
1455
                                if (m->n_on_console == 0)
1456
                                        /* unset no_console_output flag, since the console is free */
1457
                                        m->no_console_output = 0;
1458
                        } else
1459
                                m->n_on_console ++;
1460
                }
1461
        }
1462
1463
        if (u->job) {
1464
                unexpected = false;
1465
1466
                if (u->job->state == JOB_WAITING)
1467
1468
                        /* So we reached a different state for this
1469
                         * job. Let's see if we can run it now if it
1470
                         * failed previously due to EAGAIN. */
1471
                        job_add_to_run_queue(u->job);
1472
1473
                /* Let's check whether this state change constitutes a
1474
                 * finished job, or maybe contradicts a running job and
1475
                 * hence needs to invalidate jobs. */
1476
1477
                switch (u->job->type) {
1478
1479
                case JOB_START:
1480
                case JOB_VERIFY_ACTIVE:
1481
1482
                        if (UNIT_IS_ACTIVE_OR_RELOADING(ns))
1483
                                job_finish_and_invalidate(u->job, JOB_DONE, true);
1484
                        else if (u->job->state == JOB_RUNNING && ns != UNIT_ACTIVATING) {
1485
                                unexpected = true;
1486
1487
                                if (UNIT_IS_INACTIVE_OR_FAILED(ns))
1488
                                        job_finish_and_invalidate(u->job, ns == UNIT_FAILED ? JOB_FAILED : JOB_DONE, true);
1489
                        }
1490
1491
                        break;
1492
1493
                case JOB_RELOAD:
1494
                case JOB_RELOAD_OR_START:
1495
1496
                        if (u->job->state == JOB_RUNNING) {
1497
                                if (ns == UNIT_ACTIVE)
1498
                                        job_finish_and_invalidate(u->job, reload_success ? JOB_DONE : JOB_FAILED, true);
1499
                                else if (ns != UNIT_ACTIVATING && ns != UNIT_RELOADING) {
1500
                                        unexpected = true;
1501
1502
                                        if (UNIT_IS_INACTIVE_OR_FAILED(ns))
1503
                                                job_finish_and_invalidate(u->job, ns == UNIT_FAILED ? JOB_FAILED : JOB_DONE, true);
1504
                                }
1505
                        }
1506
1507
                        break;
1508
1509
                case JOB_STOP:
1510
                case JOB_RESTART:
1511
                case JOB_TRY_RESTART:
1512
1513
                        if (UNIT_IS_INACTIVE_OR_FAILED(ns))
1514
                                job_finish_and_invalidate(u->job, JOB_DONE, true);
1515
                        else if (u->job->state == JOB_RUNNING && ns != UNIT_DEACTIVATING) {
1516
                                unexpected = true;
1517
                                job_finish_and_invalidate(u->job, JOB_FAILED, true);
1518
                        }
1519
1520
                        break;
1521
1522
                default:
1523
                        assert_not_reached("Job type unknown");
1524
                }
1525
1526
        } else
1527
                unexpected = true;
1528
1529
        if (m->n_reloading <= 0) {
1530
1531
                /* If this state change happened without being
1532
                 * requested by a job, then let's retroactively start
1533
                 * or stop dependencies. We skip that step when
1534
                 * deserializing, since we don't want to create any
1535
                 * additional jobs just because something is already
1536
                 * activated. */
1537
1538
                if (unexpected) {
1539
                        if (UNIT_IS_INACTIVE_OR_FAILED(os) && UNIT_IS_ACTIVE_OR_ACTIVATING(ns))
1540
                                retroactively_start_dependencies(u);
1541
                        else if (UNIT_IS_ACTIVE_OR_ACTIVATING(os) && UNIT_IS_INACTIVE_OR_DEACTIVATING(ns))
1542
                                retroactively_stop_dependencies(u);
1543
                }
1544
1545
                /* stop unneeded units regardless if going down was expected or not */
1546
                if (UNIT_IS_ACTIVE_OR_ACTIVATING(os) && UNIT_IS_INACTIVE_OR_DEACTIVATING(ns))
1547
                        check_unneeded_dependencies(u);
1548
1549
                if (ns != os && ns == UNIT_FAILED) {
1550
                        log_notice_unit(u->id,
1551
                                        "Unit %s entered failed state.", u->id);
1552
                        unit_start_on_failure(u);
1553
                }
1554
        }
1555
1556
        /* Some names are special */
1557
        if (UNIT_IS_ACTIVE_OR_RELOADING(ns)) {
1558
1559
                if (unit_has_name(u, SPECIAL_DBUS_SERVICE))
1560
                        /* The bus just might have become available,
1561
                         * hence try to connect to it, if we aren't
1562
                         * yet connected. */
1563
                        bus_init(m, true);
1564
1565
                if (u->type == UNIT_SERVICE &&
1566
                    !UNIT_IS_ACTIVE_OR_RELOADING(os) &&
1567
                    m->n_reloading <= 0) {
1568
                        /* Write audit record if we have just finished starting up */
1569
                        manager_send_unit_audit(m, u, AUDIT_SERVICE_START, true);
1570
                        u->in_audit = true;
1571
                }
1572
1573
                if (!UNIT_IS_ACTIVE_OR_RELOADING(os))
1574
                        manager_send_unit_plymouth(m, u);
1575
1576
        } else {
1577
1578
                /* We don't care about D-Bus here, since we'll get an
1579
                 * asynchronous notification for it anyway. */
1580
1581
                if (u->type == UNIT_SERVICE &&
1582
                    UNIT_IS_INACTIVE_OR_FAILED(ns) &&
1583
                    !UNIT_IS_INACTIVE_OR_FAILED(os) &&
1584
                    m->n_reloading <= 0) {
1585
1586
                        /* Hmm, if there was no start record written
1587
                         * write it now, so that we always have a nice
1588
                         * pair */
1589
                        if (!u->in_audit) {
1590
                                manager_send_unit_audit(m, u, AUDIT_SERVICE_START, ns == UNIT_INACTIVE);
1591
1592
                                if (ns == UNIT_INACTIVE)
1593
                                        manager_send_unit_audit(m, u, AUDIT_SERVICE_STOP, true);
1594
                        } else
1595
                                /* Write audit record if we have just finished shutting down */
1596
                                manager_send_unit_audit(m, u, AUDIT_SERVICE_STOP, ns == UNIT_INACTIVE);
1597
1598
                        u->in_audit = false;
1599
                }
1600
        }
1601
1602
        manager_recheck_journal(m);
1603
        unit_trigger_notify(u);
1604
1605
        /* Maybe we finished startup and are now ready for being
1606
         * stopped because unneeded? */
1607
        if (u->manager->n_reloading <= 0)
1608
                unit_check_unneeded(u);
1609
1610
        unit_add_to_dbus_queue(u);
1611
        unit_add_to_gc_queue(u);
1612
}
1613
1614
int unit_watch_fd(Unit *u, int fd, uint32_t events, Watch *w) {
1615
        struct epoll_event ev = {
1616
                .data.ptr = w,
1617
                .events = events,
1618
        };
1619
1620
        assert(u);
1621
        assert(fd >= 0);
1622
        assert(w);
1623
        assert(w->type == WATCH_INVALID || (w->type == WATCH_FD && w->fd == fd && w->data.unit == u));
1624
1625
        if (epoll_ctl(u->manager->epoll_fd,
1626
                      w->type == WATCH_INVALID ? EPOLL_CTL_ADD : EPOLL_CTL_MOD,
1627
                      fd,
1628
                      &ev) < 0)
1629
                return -errno;
1630
1631
        w->fd = fd;
1632
        w->type = WATCH_FD;
1633
        w->data.unit = u;
1634
1635
        return 0;
1636
}
1637
1638
void unit_unwatch_fd(Unit *u, Watch *w) {
1639
        assert(u);
1640
        assert(w);
1641
1642
        if (w->type == WATCH_INVALID)
1643
                return;
1644
1645
        assert(w->type == WATCH_FD);
1646
        assert(w->data.unit == u);
1647
        assert_se(epoll_ctl(u->manager->epoll_fd, EPOLL_CTL_DEL, w->fd, NULL) >= 0);
1648
1649
        w->fd = -1;
1650
        w->type = WATCH_INVALID;
1651
        w->data.unit = NULL;
1652
}
1653
1654
int unit_watch_pid(Unit *u, pid_t pid) {
1655
        assert(u);
1656
        assert(pid >= 1);
1657
1658
        /* Watch a specific PID. We only support one unit watching
1659
         * each PID for now. */
1660
1661
        return hashmap_put(u->manager->watch_pids, LONG_TO_PTR(pid), u);
1662
}
1663
1664
void unit_unwatch_pid(Unit *u, pid_t pid) {
1665
        assert(u);
1666
        assert(pid >= 1);
1667
1668
        hashmap_remove_value(u->manager->watch_pids, LONG_TO_PTR(pid), u);
1669
}
1670
1671
int unit_watch_timer(Unit *u, clockid_t clock_id, bool relative, usec_t usec, Watch *w) {
1672
        struct itimerspec its = {};
1673
        int flags, fd;
1674
        bool ours;
1675
1676
        assert(u);
1677
        assert(w);
1678
        assert(w->type == WATCH_INVALID || (w->type == WATCH_UNIT_TIMER && w->data.unit == u));
1679
1680
        /* This will try to reuse the old timer if there is one */
1681
1682
        if (w->type == WATCH_UNIT_TIMER) {
1683
                assert(w->data.unit == u);
1684
                assert(w->fd >= 0);
1685
1686
                ours = false;
1687
                fd = w->fd;
1688
        } else if (w->type == WATCH_INVALID) {
1689
1690
                ours = true;
1691
                fd = timerfd_create(clock_id, TFD_NONBLOCK|TFD_CLOEXEC);
1692
                if (fd < 0)
1693
                        return -errno;
1694
        } else
1695
                assert_not_reached("Invalid watch type");
1696
1697
        if (usec <= 0) {
1698
                /* Set absolute time in the past, but not 0, since we
1699
                 * don't want to disarm the timer */
1700
                its.it_value.tv_sec = 0;
1701
                its.it_value.tv_nsec = 1;
1702
1703
                flags = TFD_TIMER_ABSTIME;
1704
        } else {
1705
                timespec_store(&its.it_value, usec);
1706
                flags = relative ? 0 : TFD_TIMER_ABSTIME;
1707
        }
1708
1709
        /* This will also flush the elapse counter */
1710
        if (timerfd_settime(fd, flags, &its, NULL) < 0)
1711
                goto fail;
1712
1713
        if (w->type == WATCH_INVALID) {
1714
                struct epoll_event ev = {
1715
                        .data.ptr = w,
1716
                        .events = EPOLLIN,
1717
                };
1718
1719
                if (epoll_ctl(u->manager->epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0)
1720
                        goto fail;
1721
        }
1722
1723
        w->type = WATCH_UNIT_TIMER;
1724
        w->fd = fd;
1725
        w->data.unit = u;
1726
1727
        return 0;
1728
1729
fail:
1730
        if (ours)
1731
                close_nointr_nofail(fd);
1732
1733
        return -errno;
1734
}
1735
1736
void unit_unwatch_timer(Unit *u, Watch *w) {
1737
        assert(u);
1738
        assert(w);
1739
1740
        if (w->type == WATCH_INVALID)
1741
                return;
1742
1743
        assert(w->type == WATCH_UNIT_TIMER);
1744
        assert(w->data.unit == u);
1745
        assert(w->fd >= 0);
1746
1747
        assert_se(epoll_ctl(u->manager->epoll_fd, EPOLL_CTL_DEL, w->fd, NULL) >= 0);
1748
        close_nointr_nofail(w->fd);
1749
1750
        w->fd = -1;
1751
        w->type = WATCH_INVALID;
1752
        w->data.unit = NULL;
1753
}
1754
1755
bool unit_job_is_applicable(Unit *u, JobType j) {
1756
        assert(u);
1757
        assert(j >= 0 && j < _JOB_TYPE_MAX);
1758
1759
        switch (j) {
1760
1761
        case JOB_VERIFY_ACTIVE:
1762
        case JOB_START:
1763
        case JOB_STOP:
1764
        case JOB_NOP:
1765
                return true;
1766
1767
        case JOB_RESTART:
1768
        case JOB_TRY_RESTART:
1769
                return unit_can_start(u);
1770
1771
        case JOB_RELOAD:
1772
                return unit_can_reload(u);
1773
1774
        case JOB_RELOAD_OR_START:
1775
                return unit_can_reload(u) && unit_can_start(u);
1776
1777
        default:
1778
                assert_not_reached("Invalid job type");
1779
        }
1780
}
1781
1782
int unit_add_dependency(Unit *u, UnitDependency d, Unit *other, bool add_reference) {
1783
1784
        static const UnitDependency inverse_table[_UNIT_DEPENDENCY_MAX] = {
1785
                [UNIT_REQUIRES] = UNIT_REQUIRED_BY,
1786
                [UNIT_REQUIRES_OVERRIDABLE] = UNIT_REQUIRED_BY_OVERRIDABLE,
1787
                [UNIT_WANTS] = UNIT_WANTED_BY,
1788
                [UNIT_REQUISITE] = UNIT_REQUIRED_BY,
1789
                [UNIT_REQUISITE_OVERRIDABLE] = UNIT_REQUIRED_BY_OVERRIDABLE,
1790
                [UNIT_BINDS_TO] = UNIT_BOUND_BY,
1791
                [UNIT_PART_OF] = UNIT_CONSISTS_OF,
1792
                [UNIT_REQUIRED_BY] = _UNIT_DEPENDENCY_INVALID,
1793
                [UNIT_REQUIRED_BY_OVERRIDABLE] = _UNIT_DEPENDENCY_INVALID,
1794
                [UNIT_WANTED_BY] = _UNIT_DEPENDENCY_INVALID,
1795
                [UNIT_BOUND_BY] = UNIT_BINDS_TO,
1796
                [UNIT_CONSISTS_OF] = UNIT_PART_OF,
1797
                [UNIT_CONFLICTS] = UNIT_CONFLICTED_BY,
1798
                [UNIT_CONFLICTED_BY] = UNIT_CONFLICTS,
1799
                [UNIT_BEFORE] = UNIT_AFTER,
1800
                [UNIT_AFTER] = UNIT_BEFORE,
1801
                [UNIT_ON_FAILURE] = _UNIT_DEPENDENCY_INVALID,
1802
                [UNIT_REFERENCES] = UNIT_REFERENCED_BY,
1803
                [UNIT_REFERENCED_BY] = UNIT_REFERENCES,
1804
                [UNIT_TRIGGERS] = UNIT_TRIGGERED_BY,
1805
                [UNIT_TRIGGERED_BY] = UNIT_TRIGGERS,
1806
                [UNIT_PROPAGATES_RELOAD_TO] = UNIT_RELOAD_PROPAGATED_FROM,
1807
                [UNIT_RELOAD_PROPAGATED_FROM] = UNIT_PROPAGATES_RELOAD_TO,
1808
        };
1809
        int r, q = 0, v = 0, w = 0;
1810
1811
        assert(u);
1812
        assert(d >= 0 && d < _UNIT_DEPENDENCY_MAX);
1813
        assert(other);
1814
1815
        u = unit_follow_merge(u);
1816
        other = unit_follow_merge(other);
1817
1818
        /* We won't allow dependencies on ourselves. We will not
1819
         * consider them an error however. */
1820
        if (u == other)
1821
                return 0;
1822
1823
        if ((r = set_ensure_allocated(&u->dependencies[d], trivial_hash_func, trivial_compare_func)) < 0)
1824
                return r;
1825
1826
        if (inverse_table[d] != _UNIT_DEPENDENCY_INVALID)
1827
                if ((r = set_ensure_allocated(&other->dependencies[inverse_table[d]], trivial_hash_func, trivial_compare_func)) < 0)
1828
                        return r;
1829
1830
        if (add_reference)
1831
                if ((r = set_ensure_allocated(&u->dependencies[UNIT_REFERENCES], trivial_hash_func, trivial_compare_func)) < 0 ||
1832
                    (r = set_ensure_allocated(&other->dependencies[UNIT_REFERENCED_BY], trivial_hash_func, trivial_compare_func)) < 0)
1833
                        return r;
1834
1835
        if ((q = set_put(u->dependencies[d], other)) < 0)
1836
                return q;
1837
1838
        if (inverse_table[d] != _UNIT_DEPENDENCY_INVALID)
1839
                if ((v = set_put(other->dependencies[inverse_table[d]], u)) < 0) {
1840
                        r = v;
1841
                        goto fail;
1842
                }
1843
1844
        if (add_reference) {
1845
                if ((w = set_put(u->dependencies[UNIT_REFERENCES], other)) < 0) {
1846
                        r = w;
1847
                        goto fail;
1848
                }
1849
1850
                if ((r = set_put(other->dependencies[UNIT_REFERENCED_BY], u)) < 0)
1851
                        goto fail;
1852
        }
1853
1854
        unit_add_to_dbus_queue(u);
1855
        return 0;
1856
1857
fail:
1858
        if (q > 0)
1859
                set_remove(u->dependencies[d], other);
1860
1861
        if (v > 0)
1862
                set_remove(other->dependencies[inverse_table[d]], u);
1863
1864
        if (w > 0)
1865
                set_remove(u->dependencies[UNIT_REFERENCES], other);
1866
1867
        return r;
1868
}
1869
1870
int unit_add_two_dependencies(Unit *u, UnitDependency d, UnitDependency e, Unit *other, bool add_reference) {
1871
        int r;
1872
1873
        assert(u);
1874
1875
        if ((r = unit_add_dependency(u, d, other, add_reference)) < 0)
1876
                return r;
1877
1878
        if ((r = unit_add_dependency(u, e, other, add_reference)) < 0)
1879
                return r;
1880
1881
        return 0;
1882
}
1883
1884
static const char *resolve_template(Unit *u, const char *name, const char*path, char **p) {
1885
        char *s;
1886
1887
        assert(u);
1888
        assert(name || path);
1889
        assert(p);
1890
1891
        if (!name)
1892
                name = path_get_file_name(path);
1893
1894
        if (!unit_name_is_template(name)) {
1895
                *p = NULL;
1896
                return name;
1897
        }
1898
1899
        if (u->instance)
1900
                s = unit_name_replace_instance(name, u->instance);
1901
        else {
1902
                _cleanup_free_ char *i = NULL;
1903
1904
                i = unit_name_to_prefix(u->id);
1905
                if (!i)
1906
                        return NULL;
1907
1908
                s = unit_name_replace_instance(name, i);
1909
        }
1910
1911
        if (!s)
1912
                return NULL;
1913
1914
        *p = s;
1915
        return s;
1916
}
1917
1918
int unit_add_dependency_by_name(Unit *u, UnitDependency d, const char *name, const char *path, bool add_reference) {
1919
        Unit *other;
1920
        int r;
1921
        _cleanup_free_ char *s = NULL;
1922
1923
        assert(u);
1924
        assert(name || path);
1925
1926
        name = resolve_template(u, name, path, &s);
1927
        if (!name)
1928
                return -ENOMEM;
1929
1930
        r = manager_load_unit(u->manager, name, path, NULL, &other);
1931
        if (r < 0)
1932
                return r;
1933
1934
        return unit_add_dependency(u, d, other, add_reference);
1935
}
1936
1937
int unit_add_two_dependencies_by_name(Unit *u, UnitDependency d, UnitDependency e, const char *name, const char *path, bool add_reference) {
1938
        Unit *other;
1939
        int r;
1940
        _cleanup_free_ char *s = NULL;
1941
1942
        assert(u);
1943
        assert(name || path);
1944
1945
        if (!(name = resolve_template(u, name, path, &s)))
1946
                return -ENOMEM;
1947
1948
        if ((r = manager_load_unit(u->manager, name, path, NULL, &other)) < 0)
1949
                return r;
1950
1951
        r = unit_add_two_dependencies(u, d, e, other, add_reference);
1952
1953
        return r;
1954
}
1955
1956
int unit_add_dependency_by_name_inverse(Unit *u, UnitDependency d, const char *name, const char *path, bool add_reference) {
1957
        Unit *other;
1958
        int r;
1959
        _cleanup_free_ char *s = NULL;
1960
1961
        assert(u);
1962
        assert(name || path);
1963
1964
        if (!(name = resolve_template(u, name, path, &s)))
1965
                return -ENOMEM;
1966
1967
        if ((r = manager_load_unit(u->manager, name, path, NULL, &other)) < 0)
1968
                return r;
1969
1970
        r = unit_add_dependency(other, d, u, add_reference);
1971
1972
        return r;
1973
}
1974
1975
int unit_add_two_dependencies_by_name_inverse(Unit *u, UnitDependency d, UnitDependency e, const char *name, const char *path, bool add_reference) {
1976
        Unit *other;
1977
        int r;
1978
        _cleanup_free_ char *s = NULL;
1979
1980
        assert(u);
1981
        assert(name || path);
1982
1983
        if (!(name = resolve_template(u, name, path, &s)))
1984
                return -ENOMEM;
1985
1986
        if ((r = manager_load_unit(u->manager, name, path, NULL, &other)) < 0)
1987
                return r;
1988
1989
        if ((r = unit_add_two_dependencies(other, d, e, u, add_reference)) < 0)
1990
                return r;
1991
1992
        return r;
1993
}
1994
1995
int set_unit_path(const char *p) {
1996
        _cleanup_free_ char *c = NULL;
1997
1998
        /* This is mostly for debug purposes */
1999
        c = path_make_absolute_cwd(p);
2000
        if (setenv("SYSTEMD_UNIT_PATH", c, 0) < 0)
2001
                return -errno;
2002
2003
        return 0;
2004
}
2005
2006
char *unit_dbus_path(Unit *u) {
2007
        assert(u);
2008
2009
        if (!u->id)
2010
                return NULL;
2011
2012
        return unit_dbus_path_from_name(u->id);
2013
}
2014
2015
char *unit_default_cgroup_path(Unit *u) {
2016
        _cleanup_free_ char *escaped = NULL, *slice = NULL;
2017
        int r;
2018
2019
        assert(u);
2020
2021
        if (unit_has_name(u, SPECIAL_ROOT_SLICE))
2022
                return strdup(u->manager->cgroup_root);
2023
2024
        if (UNIT_ISSET(u->slice) && !unit_has_name(UNIT_DEREF(u->slice), SPECIAL_ROOT_SLICE)) {
2025
                r = cg_slice_to_path(UNIT_DEREF(u->slice)->id, &slice);
2026
                if (r < 0)
2027
                        return NULL;
2028
        }
2029
2030
        escaped = cg_escape(u->id);
2031
        if (!escaped)
2032
                return NULL;
2033
2034
        if (slice)
2035
                return strjoin(u->manager->cgroup_root, "/", slice, "/", escaped, NULL);
2036
        else
2037
                return strjoin(u->manager->cgroup_root, "/", escaped, NULL);
2038
}
2039
2040
int unit_add_default_slice(Unit *u) {
2041
        _cleanup_free_ char *b = NULL;
2042
        const char *slice_name;
2043
        Unit *slice;
2044
        int r;
2045
2046
        assert(u);
2047
2048
        if (UNIT_ISSET(u->slice))
2049
                return 0;
2050
2051
        if (!unit_get_cgroup_context(u))
2052
                return 0;
2053
2054
        if (u->instance) {
2055
                _cleanup_free_ char *prefix = NULL, *escaped = NULL;
2056
2057
                /* Implicitly place all instantiated units in their
2058
                 * own per-template slice */
2059
2060
                prefix = unit_name_to_prefix(u->id);
2061
                if (!prefix)
2062
                        return -ENOMEM;
2063
2064
                /* The prefix is already escaped, but it might include
2065
                 * "-" which has a special meaning for slice units,
2066
                 * hence escape it here extra. */
2067
                escaped = strreplace(prefix, "-", "\\x2d");
2068
                if (!escaped)
2069
                        return -ENOMEM;
2070
2071
                if (u->manager->running_as == SYSTEMD_SYSTEM)
2072
                        b = strjoin("system-", escaped, ".slice", NULL);
2073
                else
2074
                        b = strappend(escaped, ".slice");
2075
                if (!b)
2076
                        return -ENOMEM;
2077
2078
                slice_name = b;
2079
        } else
2080
                slice_name =
2081
                        u->manager->running_as == SYSTEMD_SYSTEM
2082
                        ? SPECIAL_SYSTEM_SLICE
2083
                        : SPECIAL_ROOT_SLICE;
2084
2085
        r = manager_load_unit(u->manager, slice_name, NULL, NULL, &slice);
2086
        if (r < 0)
2087
                return r;
2088
2089
        unit_ref_set(&u->slice, slice);
2090
        return 0;
2091
}
2092
2093
const char *unit_slice_name(Unit *u) {
2094
        assert(u);
2095
2096
        if (!UNIT_ISSET(u->slice))
2097
                return NULL;
2098
2099
        return UNIT_DEREF(u->slice)->id;
2100
}
2101
2102
int unit_load_related_unit(Unit *u, const char *type, Unit **_found) {
2103
        _cleanup_free_ char *t = NULL;
2104
        int r;
2105
2106
        assert(u);
2107
        assert(type);
2108
        assert(_found);
2109
2110
        t = unit_name_change_suffix(u->id, type);
2111
        if (!t)
2112
                return -ENOMEM;
2113
2114
        assert(!unit_has_name(u, t));
2115
2116
        r = manager_load_unit(u->manager, t, NULL, NULL, _found);
2117
        assert(r < 0 || *_found != u);
2118
        return r;
2119
}
2120
2121
int unit_get_related_unit(Unit *u, const char *type, Unit **_found) {
2122
        _cleanup_free_ char *t = NULL;
2123
        Unit *found;
2124
2125
        assert(u);
2126
        assert(type);
2127
        assert(_found);
2128
2129
        t = unit_name_change_suffix(u->id, type);
2130
        if (!t)
2131
                return -ENOMEM;
2132
2133
        assert(!unit_has_name(u, t));
2134
2135
        found = manager_get_unit(u->manager, t);
2136
        if (!found)
2137
                return -ENOENT;
2138
2139
        *_found = found;
2140
        return 0;
2141
}
2142
2143
int unit_watch_bus_name(Unit *u, const char *name) {
2144
        assert(u);
2145
        assert(name);
2146
2147
        /* Watch a specific name on the bus. We only support one unit
2148
         * watching each name for now. */
2149
2150
        return hashmap_put(u->manager->watch_bus, name, u);
2151
}
2152
2153
void unit_unwatch_bus_name(Unit *u, const char *name) {
2154
        assert(u);
2155
        assert(name);
2156
2157
        hashmap_remove_value(u->manager->watch_bus, name, u);
2158
}
2159
2160
bool unit_can_serialize(Unit *u) {
2161
        assert(u);
2162
2163
        return UNIT_VTABLE(u)->serialize && UNIT_VTABLE(u)->deserialize_item;
2164
}
2165
2166
int unit_serialize(Unit *u, FILE *f, FDSet *fds, bool serialize_jobs) {
2167
        int r;
2168
2169
        assert(u);
2170
        assert(f);
2171
        assert(fds);
2172
2173
        if (!unit_can_serialize(u))
2174
                return 0;
2175
2176
        r = UNIT_VTABLE(u)->serialize(u, f, fds);
2177
        if (r < 0)
2178
                return r;
2179
2180
2181
        if (serialize_jobs) {
2182
                if (u->job) {
2183
                        fprintf(f, "job\n");
2184
                        job_serialize(u->job, f, fds);
2185
                }
2186
2187
                if (u->nop_job) {
2188
                        fprintf(f, "job\n");
2189
                        job_serialize(u->nop_job, f, fds);
2190
                }
2191
        }
2192
2193
        dual_timestamp_serialize(f, "inactive-exit-timestamp", &u->inactive_exit_timestamp);
2194
        dual_timestamp_serialize(f, "active-enter-timestamp", &u->active_enter_timestamp);
2195
        dual_timestamp_serialize(f, "active-exit-timestamp", &u->active_exit_timestamp);
2196
        dual_timestamp_serialize(f, "inactive-enter-timestamp", &u->inactive_enter_timestamp);
2197
        dual_timestamp_serialize(f, "condition-timestamp", &u->condition_timestamp);
2198
2199
        if (dual_timestamp_is_set(&u->condition_timestamp))
2200
                unit_serialize_item(u, f, "condition-result", yes_no(u->condition_result));
2201
2202
        unit_serialize_item(u, f, "transient", yes_no(u->transient));
2203
2204
        if (u->cgroup_path)
2205
                unit_serialize_item(u, f, "cgroup", u->cgroup_path);
2206
2207
        /* End marker */
2208
        fputc('\n', f);
2209
        return 0;
2210
}
2211
2212
void unit_serialize_item_format(Unit *u, FILE *f, const char *key, const char *format, ...) {
2213
        va_list ap;
2214
2215
        assert(u);
2216
        assert(f);
2217
        assert(key);
2218
        assert(format);
2219
2220
        fputs(key, f);
2221
        fputc('=', f);
2222
2223
        va_start(ap, format);
2224
        vfprintf(f, format, ap);
2225
        va_end(ap);
2226
2227
        fputc('\n', f);
2228
}
2229
2230
void unit_serialize_item(Unit *u, FILE *f, const char *key, const char *value) {
2231
        assert(u);
2232
        assert(f);
2233
        assert(key);
2234
        assert(value);
2235
2236
        fprintf(f, "%s=%s\n", key, value);
2237
}
2238
2239
int unit_deserialize(Unit *u, FILE *f, FDSet *fds) {
2240
        int r;
2241
2242
        assert(u);
2243
        assert(f);
2244
        assert(fds);
2245
2246
        if (!unit_can_serialize(u))
2247
                return 0;
2248
2249
        for (;;) {
2250
                char line[LINE_MAX], *l, *v;
2251
                size_t k;
2252
2253
                if (!fgets(line, sizeof(line), f)) {
2254
                        if (feof(f))
2255
                                return 0;
2256
                        return -errno;
2257
                }
2258
2259
                char_array_0(line);
2260
                l = strstrip(line);
2261
2262
                /* End marker */
2263
                if (l[0] == 0)
2264
                        return 0;
2265
2266
                k = strcspn(l, "=");
2267
2268
                if (l[k] == '=') {
2269
                        l[k] = 0;
2270
                        v = l+k+1;
2271
                } else
2272
                        v = l+k;
2273
2274
                if (streq(l, "job")) {
2275
                        if (v[0] == '\0') {
2276
                                /* new-style serialized job */
2277
                                Job *j = job_new_raw(u);
2278
                                if (!j)
2279
                                        return -ENOMEM;
2280
2281
                                r = job_deserialize(j, f, fds);
2282
                                if (r < 0) {
2283
                                        job_free(j);
2284
                                        return r;
2285
                                }
2286
2287
                                r = hashmap_put(u->manager->jobs, UINT32_TO_PTR(j->id), j);
2288
                                if (r < 0) {
2289
                                        job_free(j);
2290
                                        return r;
2291
                                }
2292
2293
                                r = job_install_deserialized(j);
2294
                                if (r < 0) {
2295
                                        hashmap_remove(u->manager->jobs, UINT32_TO_PTR(j->id));
2296
                                        job_free(j);
2297
                                        return r;
2298
                                }
2299
2300
                                if (j->state == JOB_RUNNING)
2301
                                        u->manager->n_running_jobs++;
2302
                        } else {
2303
                                /* legacy */
2304
                                JobType type = job_type_from_string(v);
2305
                                if (type < 0)
2306
                                        log_debug("Failed to parse job type value %s", v);
2307
                                else
2308
                                        u->deserialized_job = type;
2309
                        }
2310
                        continue;
2311
                } else if (streq(l, "inactive-exit-timestamp")) {
2312
                        dual_timestamp_deserialize(v, &u->inactive_exit_timestamp);
2313
                        continue;
2314
                } else if (streq(l, "active-enter-timestamp")) {
2315
                        dual_timestamp_deserialize(v, &u->active_enter_timestamp);
2316
                        continue;
2317
                } else if (streq(l, "active-exit-timestamp")) {
2318
                        dual_timestamp_deserialize(v, &u->active_exit_timestamp);
2319
                        continue;
2320
                } else if (streq(l, "inactive-enter-timestamp")) {
2321
                        dual_timestamp_deserialize(v, &u->inactive_enter_timestamp);
2322
                        continue;
2323
                } else if (streq(l, "condition-timestamp")) {
2324
                        dual_timestamp_deserialize(v, &u->condition_timestamp);
2325
                        continue;
2326
                } else if (streq(l, "condition-result")) {
2327
                        int b;
2328
2329
                        b = parse_boolean(v);
2330
                        if (b < 0)
2331
                                log_debug("Failed to parse condition result value %s", v);
2332
                        else
2333
                                u->condition_result = b;
2334
2335
                        continue;
2336
2337
                } else if (streq(l, "transient")) {
2338
                        int b;
2339
2340
                        b = parse_boolean(v);
2341
                        if (b < 0)
2342
                                log_debug("Failed to parse transient bool %s", v);
2343
                        else
2344
                                u->transient = b;
2345
2346
                        continue;
2347
                } else if (streq(l, "cgroup")) {
2348
                        char *s;
2349
2350
                        s = strdup(v);
2351
                        if (!s)
2352
                                return -ENOMEM;
2353
2354
                        free(u->cgroup_path);
2355
                        u->cgroup_path = s;
2356
2357
                        assert(hashmap_put(u->manager->cgroup_unit, s, u) == 1);
2358
                        continue;
2359
                }
2360
2361
                r = UNIT_VTABLE(u)->deserialize_item(u, l, v, fds);
2362
                if (r < 0)
2363
                        return r;
2364
        }
2365
}
2366
2367
int unit_add_node_link(Unit *u, const char *what, bool wants) {
2368
        Unit *device;
2369
        _cleanup_free_ char *e = NULL;
2370
        int r;
2371
2372
        assert(u);
2373
2374
        if (!what)
2375
                return 0;
2376
2377
        /* Adds in links to the device node that this unit is based on */
2378
2379
        if (!is_device_path(what))
2380
                return 0;
2381
2382
        e = unit_name_from_path(what, ".device");
2383
        if (!e)
2384
                return -ENOMEM;
2385
2386
        r = manager_load_unit(u->manager, e, NULL, NULL, &device);
2387
2388
        if (r < 0)
2389
                return r;
2390
2391
        r = unit_add_two_dependencies(u, UNIT_AFTER, UNIT_BINDS_TO, device, true);
2392
        if (r < 0)
2393
                return r;
2394
2395
        if (wants) {
2396
                r = unit_add_dependency(device, UNIT_WANTS, u, false);
2397
                if (r < 0)
2398
                        return r;
2399
        }
2400
2401
        return 0;
2402
}
2403
2404
int unit_coldplug(Unit *u) {
2405
        int r;
2406
2407
        assert(u);
2408
2409
        if (UNIT_VTABLE(u)->coldplug)
2410
                if ((r = UNIT_VTABLE(u)->coldplug(u)) < 0)
2411
                        return r;
2412
2413
        if (u->job) {
2414
                r = job_coldplug(u->job);
2415
                if (r < 0)
2416
                        return r;
2417
        } else if (u->deserialized_job >= 0) {
2418
                /* legacy */
2419
                r = manager_add_job(u->manager, u->deserialized_job, u, JOB_IGNORE_REQUIREMENTS, false, NULL, NULL);
2420
                if (r < 0)
2421
                        return r;
2422
2423
                u->deserialized_job = _JOB_TYPE_INVALID;
2424
        }
2425
2426
        return 0;
2427
}
2428
2429
#pragma GCC diagnostic push
2430
#pragma GCC diagnostic ignored "-Wformat-nonliteral"
2431
void unit_status_printf(Unit *u, const char *status, const char *unit_status_msg_format) {
2432
        manager_status_printf(u->manager, false, status, unit_status_msg_format, unit_description(u));
2433
}
2434
#pragma GCC diagnostic pop
2435
2436
bool unit_need_daemon_reload(Unit *u) {
2437
        _cleanup_strv_free_ char **t = NULL;
2438
        char **path;
2439
        struct stat st;
2440
        unsigned loaded_cnt, current_cnt;
2441
2442
        assert(u);
2443
2444
        if (u->fragment_path) {
2445
                zero(st);
2446
                if (stat(u->fragment_path, &st) < 0)
2447
                        /* What, cannot access this anymore? */
2448
                        return true;
2449
2450
                if (u->fragment_mtime > 0 &&
2451
                    timespec_load(&st.st_mtim) != u->fragment_mtime)
2452
                        return true;
2453
        }
2454
2455
        if (u->source_path) {
2456
                zero(st);
2457
                if (stat(u->source_path, &st) < 0)
2458
                        return true;
2459
2460
                if (u->source_mtime > 0 &&
2461
                    timespec_load(&st.st_mtim) != u->source_mtime)
2462
                        return true;
2463
        }
2464
2465
        t = unit_find_dropin_paths(u);
2466
        loaded_cnt = strv_length(t);
2467
        current_cnt = strv_length(u->dropin_paths);
2468
2469
        if (loaded_cnt == current_cnt) {
2470
                if (loaded_cnt == 0)
2471
                        return false;
2472
2473
                if (strv_overlap(u->dropin_paths, t)) {
2474
                        STRV_FOREACH(path, u->dropin_paths) {
2475
                                zero(st);
2476
                                if (stat(*path, &st) < 0)
2477
                                        return true;
2478
2479
                                if (u->dropin_mtime > 0 &&
2480
                                    timespec_load(&st.st_mtim) > u->dropin_mtime)
2481
                                        return true;
2482
                        }
2483
2484
                        return false;
2485
                } else
2486
                        return true;
2487
        } else
2488
                return true;
2489
}
2490
2491
void unit_reset_failed(Unit *u) {
2492
        assert(u);
2493
2494
        if (UNIT_VTABLE(u)->reset_failed)
2495
                UNIT_VTABLE(u)->reset_failed(u);
2496
}
2497
2498
Unit *unit_following(Unit *u) {
2499
        assert(u);
2500
2501
        if (UNIT_VTABLE(u)->following)
2502
                return UNIT_VTABLE(u)->following(u);
2503
2504
        return NULL;
2505
}
2506
2507
bool unit_stop_pending(Unit *u) {
2508
        assert(u);
2509
2510
        /* This call does check the current state of the unit. It's
2511
         * hence useful to be called from state change calls of the
2512
         * unit itself, where the state isn't updated yet. This is
2513
         * different from unit_inactive_or_pending() which checks both
2514
         * the current state and for a queued job. */
2515
2516
        return u->job && u->job->type == JOB_STOP;
2517
}
2518
2519
bool unit_inactive_or_pending(Unit *u) {
2520
        assert(u);
2521
2522
        /* Returns true if the unit is inactive or going down */
2523
2524
        if (UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(u)))
2525
                return true;
2526
2527
        if (unit_stop_pending(u))
2528
                return true;
2529
2530
        return false;
2531
}
2532
2533
bool unit_active_or_pending(Unit *u) {
2534
        assert(u);
2535
2536
        /* Returns true if the unit is active or going up */
2537
2538
        if (UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(u)))
2539
                return true;
2540
2541
        if (u->job &&
2542
            (u->job->type == JOB_START ||
2543
             u->job->type == JOB_RELOAD_OR_START ||
2544
             u->job->type == JOB_RESTART))
2545
                return true;
2546
2547
        return false;
2548
}
2549
2550
int unit_kill(Unit *u, KillWho w, int signo, DBusError *error) {
2551
        assert(u);
2552
        assert(w >= 0 && w < _KILL_WHO_MAX);
2553
        assert(signo > 0);
2554
        assert(signo < _NSIG);
2555
2556
        if (!UNIT_VTABLE(u)->kill)
2557
                return -ENOTSUP;
2558
2559
        return UNIT_VTABLE(u)->kill(u, w, signo, error);
2560
}
2561
2562
static Set *unit_pid_set(pid_t main_pid, pid_t control_pid) {
2563
        Set *pid_set;
2564
        int r;
2565
2566
        pid_set = set_new(trivial_hash_func, trivial_compare_func);
2567
        if (!pid_set)
2568
                return NULL;
2569
2570
        /* Exclude the main/control pids from being killed via the cgroup */
2571
        if (main_pid > 0) {
2572
                r = set_put(pid_set, LONG_TO_PTR(main_pid));
2573
                if (r < 0)
2574
                        goto fail;
2575
        }
2576
2577
        if (control_pid > 0) {
2578
                r = set_put(pid_set, LONG_TO_PTR(control_pid));
2579
                if (r < 0)
2580
                        goto fail;
2581
        }
2582
2583
        return pid_set;
2584
2585
fail:
2586
        set_free(pid_set);
2587
        return NULL;
2588
}
2589
2590
int unit_kill_common(
2591
                Unit *u,
2592
                KillWho who,
2593
                int signo,
2594
                pid_t main_pid,
2595
                pid_t control_pid,
2596
                DBusError *error) {
2597
2598
        int r = 0;
2599
2600
        if (who == KILL_MAIN && main_pid <= 0) {
2601
                if (main_pid < 0)
2602
                        dbus_set_error(error, BUS_ERROR_NO_SUCH_PROCESS, "%s units have no main processes", unit_type_to_string(u->type));
2603
                else
2604
                        dbus_set_error(error, BUS_ERROR_NO_SUCH_PROCESS, "No main process to kill");
2605
                return -ESRCH;
2606
        }
2607
2608
        if (who == KILL_CONTROL && control_pid <= 0) {
2609
                if (control_pid < 0)
2610
                        dbus_set_error(error, BUS_ERROR_NO_SUCH_PROCESS, "%s units have no control processes", unit_type_to_string(u->type));
2611
                else
2612
                        dbus_set_error(error, BUS_ERROR_NO_SUCH_PROCESS, "No control process to kill");
2613
                return -ESRCH;
2614
        }
2615
2616
        if (who == KILL_CONTROL || who == KILL_ALL)
2617
                if (control_pid > 0)
2618
                        if (kill(control_pid, signo) < 0)
2619
                                r = -errno;
2620
2621
        if (who == KILL_MAIN || who == KILL_ALL)
2622
                if (main_pid > 0)
2623
                        if (kill(main_pid, signo) < 0)
2624
                                r = -errno;
2625
2626
        if (who == KILL_ALL && u->cgroup_path) {
2627
                _cleanup_set_free_ Set *pid_set = NULL;
2628
                int q;
2629
2630
                /* Exclude the main/control pids from being killed via the cgroup */
2631
                pid_set = unit_pid_set(main_pid, control_pid);
2632
                if (!pid_set)
2633
                        return -ENOMEM;
2634
2635
                q = cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, signo, false, true, false, pid_set);
2636
                if (q < 0 && q != -EAGAIN && q != -ESRCH && q != -ENOENT)
2637
                        r = q;
2638
        }
2639
2640
        return r;
2641
}
2642
2643
int unit_following_set(Unit *u, Set **s) {
2644
        assert(u);
2645
        assert(s);
2646
2647
        if (UNIT_VTABLE(u)->following_set)
2648
                return UNIT_VTABLE(u)->following_set(u, s);
2649
2650
        *s = NULL;
2651
        return 0;
2652
}
2653
2654
UnitFileState unit_get_unit_file_state(Unit *u) {
2655
        assert(u);
2656
2657
        if (u->unit_file_state < 0 && u->fragment_path)
2658
                u->unit_file_state = unit_file_get_state(
2659
                                u->manager->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER,
2660
                                NULL, path_get_file_name(u->fragment_path));
2661
2662
        return u->unit_file_state;
2663
}
2664
2665
Unit* unit_ref_set(UnitRef *ref, Unit *u) {
2666
        assert(ref);
2667
        assert(u);
2668
2669
        if (ref->unit)
2670
                unit_ref_unset(ref);
2671
2672
        ref->unit = u;
2673
        LIST_PREPEND(UnitRef, refs, u->refs, ref);
2674
        return u;
2675
}
2676
2677
void unit_ref_unset(UnitRef *ref) {
2678
        assert(ref);
2679
2680
        if (!ref->unit)
2681
                return;
2682
2683
        LIST_REMOVE(UnitRef, refs, ref->unit->refs, ref);
2684
        ref->unit = NULL;
2685
}
2686
2687
int unit_add_mount_links(Unit *u) {
2688
        char **i;
2689
        int r;
2690
2691
        assert(u);
2692
2693
        STRV_FOREACH(i, u->requires_mounts_for) {
2694
                char prefix[strlen(*i) + 1];
2695
2696
                PATH_FOREACH_PREFIX_MORE(prefix, *i) {
2697
                        Unit *m;
2698
2699
                        r = manager_get_unit_by_path(u->manager, prefix, ".mount", &m);
2700
                        if (r < 0)
2701
                                return r;
2702
                        if (r == 0)
2703
                                continue;
2704
                        if (m == u)
2705
                                continue;
2706
2707
                        if (m->load_state != UNIT_LOADED)
2708
                                continue;
2709
2710
                        r = unit_add_dependency(u, UNIT_AFTER, m, true);
2711
                        if (r < 0)
2712
                                return r;
2713
2714
                        if (m->fragment_path) {
2715
                                r = unit_add_dependency(u, UNIT_REQUIRES, m, true);
2716
                                if (r < 0)
2717
                                        return r;
2718
                        }
2719
                }
2720
        }
2721
2722
        return 0;
2723
}
2724
2725
int unit_exec_context_defaults(Unit *u, ExecContext *c) {
2726
        unsigned i;
2727
        int r;
2728
2729
        assert(u);
2730
        assert(c);
2731
2732
        /* This only copies in the ones that need memory */
2733
        for (i = 0; i < RLIMIT_NLIMITS; i++)
2734
                if (u->manager->rlimit[i] && !c->rlimit[i]) {
2735
                        c->rlimit[i] = newdup(struct rlimit, u->manager->rlimit[i], 1);
2736
                        if (!c->rlimit[i])
2737
                                return -ENOMEM;
2738
                }
2739
2740
        if (u->manager->running_as == SYSTEMD_USER &&
2741
            !c->working_directory) {
2742
2743
                r = get_home_dir(&c->working_directory);
2744
                if (r < 0)
2745
                        return r;
2746
        }
2747
2748
        return 0;
2749
}
2750
2751
ExecContext *unit_get_exec_context(Unit *u) {
2752
        size_t offset;
2753
        assert(u);
2754
2755
        offset = UNIT_VTABLE(u)->exec_context_offset;
2756
        if (offset <= 0)
2757
                return NULL;
2758
2759
        return (ExecContext*) ((uint8_t*) u + offset);
2760
}
2761
2762
CGroupContext *unit_get_cgroup_context(Unit *u) {
2763
        size_t offset;
2764
2765
        offset = UNIT_VTABLE(u)->cgroup_context_offset;
2766
        if (offset <= 0)
2767
                return NULL;
2768
2769
        return (CGroupContext*) ((uint8_t*) u + offset);
2770
}
2771
2772
static int drop_in_file(Unit *u, UnitSetPropertiesMode mode, const char *name, char **_p, char **_q) {
2773
        _cleanup_free_ char *b = NULL;
2774
        char *p, *q;
2775
        int r;
2776
2777
        assert(u);
2778
        assert(name);
2779
        assert(_p);
2780
        assert(_q);
2781
        assert(mode & (UNIT_PERSISTENT|UNIT_RUNTIME));
2782
2783
        b = xescape(name, "/.");
2784
        if (!b)
2785
                return -ENOMEM;
2786
2787
        if (!filename_is_safe(b))
2788
                return -EINVAL;
2789
2790
        if (u->manager->running_as == SYSTEMD_USER) {
2791
                _cleanup_free_ char *c = NULL;
2792
2793
                r = user_config_home(&c);
2794
                if (r < 0)
2795
                        return r;
2796
                if (r == 0)
2797
                        return -ENOENT;
2798
2799
                p = strjoin(c, "/", u->id, ".d", NULL);
2800
        } else if (mode & UNIT_PERSISTENT)
2801
                p = strjoin("/etc/systemd/system/", u->id, ".d", NULL);
2802
        else
2803
                p = strjoin("/run/systemd/system/", u->id, ".d", NULL);
2804
        if (!p)
2805
                return -ENOMEM;
2806
2807
        q = strjoin(p, "/90-", b, ".conf", NULL);
2808
        if (!q) {
2809
                free(p);
2810
                return -ENOMEM;
2811
        }
2812
2813
        *_p = p;
2814
        *_q = q;
2815
        return 0;
2816
}
2817
2818
int unit_write_drop_in(Unit *u, UnitSetPropertiesMode mode, const char *name, const char *data) {
2819
        _cleanup_free_ char *p = NULL, *q = NULL;
2820
        int r;
2821
2822
        assert(u);
2823
        assert(name);
2824
        assert(data);
2825
2826
        if (!(mode & (UNIT_PERSISTENT|UNIT_RUNTIME)))
2827
                return 0;
2828
2829
        r = drop_in_file(u, mode, name, &p, &q);
2830
        if (r < 0)
2831
                return r;
2832
2833
        mkdir_p(p, 0755);
2834
        return write_string_file_atomic_label(q, data);
2835
}
2836
2837
int unit_write_drop_in_format(Unit *u, UnitSetPropertiesMode mode, const char *name, const char *format, ...) {
2838
        _cleanup_free_ char *p = NULL;
2839
        va_list ap;
2840
        int r;
2841
2842
        assert(u);
2843
        assert(name);
2844
        assert(format);
2845
2846
        if (!(mode & (UNIT_PERSISTENT|UNIT_RUNTIME)))
2847
                return 0;
2848
2849
        va_start(ap, format);
2850
        r = vasprintf(&p, format, ap);
2851
        va_end(ap);
2852
2853
        if (r < 0)
2854
                return -ENOMEM;
2855
2856
        return unit_write_drop_in(u, mode, name, p);
2857
}
2858
2859
int unit_write_drop_in_private(Unit *u, UnitSetPropertiesMode mode, const char *name, const char *data) {
2860
        _cleanup_free_ char *ndata = NULL;
2861
2862
        assert(u);
2863
        assert(name);
2864
        assert(data);
2865
2866
        if (!UNIT_VTABLE(u)->private_section)
2867
                return -EINVAL;
2868
2869
        if (!(mode & (UNIT_PERSISTENT|UNIT_RUNTIME)))
2870
                return 0;
2871
2872
        ndata = strjoin("[", UNIT_VTABLE(u)->private_section, "]\n", data, NULL);
2873
        if (!ndata)
2874
                return -ENOMEM;
2875
2876
        return unit_write_drop_in(u, mode, name, ndata);
2877
}
2878
2879
int unit_write_drop_in_private_format(Unit *u, UnitSetPropertiesMode mode, const char *name, const char *format, ...) {
2880
        _cleanup_free_ char *p = NULL;
2881
        va_list ap;
2882
        int r;
2883
2884
        assert(u);
2885
        assert(name);
2886
        assert(format);
2887
2888
        if (!(mode & (UNIT_PERSISTENT|UNIT_RUNTIME)))
2889
                return 0;
2890
2891
        va_start(ap, format);
2892
        r = vasprintf(&p, format, ap);
2893
        va_end(ap);
2894
2895
        if (r < 0)
2896
                return -ENOMEM;
2897
2898
        return unit_write_drop_in_private(u, mode, name, p);
2899
}
2900
2901
int unit_remove_drop_in(Unit *u, UnitSetPropertiesMode mode, const char *name) {
2902
        _cleanup_free_ char *p = NULL, *q = NULL;
2903
        int r;
2904
2905
        assert(u);
2906
2907
        if (!(mode & (UNIT_PERSISTENT|UNIT_RUNTIME)))
2908
                return 0;
2909
2910
        r = drop_in_file(u, mode, name, &p, &q);
2911
        if (r < 0)
2912
                return r;
2913
2914
        if (unlink(q) < 0)
2915
                r = errno == ENOENT ? 0 : -errno;
2916
        else
2917
                r = 1;
2918
2919
        rmdir(p);
2920
        return r;
2921
}
2922
2923
int unit_make_transient(Unit *u) {
2924
        int r;
2925
2926
        assert(u);
2927
2928
        u->load_state = UNIT_STUB;
2929
        u->load_error = 0;
2930
        u->transient = true;
2931
2932
        free(u->fragment_path);
2933
        u->fragment_path = NULL;
2934
2935
        if (u->manager->running_as == SYSTEMD_USER) {
2936
                _cleanup_free_ char *c = NULL;
2937
2938
                r = user_config_home(&c);
2939
                if (r < 0)
2940
                        return r;
2941
                if (r == 0)
2942
                        return -ENOENT;
2943
2944
                u->fragment_path = strjoin(c, "/", u->id, NULL);
2945
                if (!u->fragment_path)
2946
                        return -ENOMEM;
2947
2948
                mkdir_p(c, 0755);
2949
        } else {
2950
                u->fragment_path = strappend("/run/systemd/system/", u->id);
2951
                if (!u->fragment_path)
2952
                        return -ENOMEM;
2953
2954
                mkdir_p("/run/systemd/system", 0755);
2955
        }
2956
2957
        return write_string_file_atomic_label(u->fragment_path, "# Transient stub");
2958
}
2959
2960
int unit_kill_context(
2961
                Unit *u,
2962
                KillContext *c,
2963
                bool sigkill,
2964
                pid_t main_pid,
2965
                pid_t control_pid,
2966
                bool main_pid_alien) {
2967
2968
        int sig, wait_for_exit = 0, r;
2969
2970
        assert(u);
2971
        assert(c);
2972
2973
        if (c->kill_mode == KILL_NONE)
2974
                return 0;
2975
2976
        sig = sigkill ? SIGKILL : c->kill_signal;
2977
2978
        if (main_pid > 0) {
2979
                r = kill_and_sigcont(main_pid, sig);
2980
2981
                if (r < 0 && r != -ESRCH) {
2982
                        _cleanup_free_ char *comm = NULL;
2983
                        get_process_comm(main_pid, &comm);
2984
2985
                        log_warning_unit(u->id, "Failed to kill main process %li (%s): %s",
2986
                                         (long) main_pid, strna(comm), strerror(-r));
2987
                } else {
2988
                        wait_for_exit = !main_pid_alien;
2989
2990
                        if (c->send_sighup)
2991
                                kill(main_pid, SIGHUP);
2992
                }
2993
        }
2994
2995
        if (control_pid > 0) {
2996
                r = kill_and_sigcont(control_pid, sig);
2997
2998
                if (r < 0 && r != -ESRCH) {
2999
                        _cleanup_free_ char *comm = NULL;
3000
                        get_process_comm(control_pid, &comm);
3001
3002
                        log_warning_unit(u->id,
3003
                                         "Failed to kill control process %li (%s): %s",
3004
                                         (long) control_pid, strna(comm), strerror(-r));
3005
                } else {
3006
                        wait_for_exit = true;
3007
3008
                        if (c->send_sighup)
3009
                                kill(control_pid, SIGHUP);
3010
                }
3011
        }
3012
3013
        if (c->kill_mode == KILL_CONTROL_GROUP && u->cgroup_path) {
3014
                _cleanup_set_free_ Set *pid_set = NULL;
3015
3016
                /* Exclude the main/control pids from being killed via the cgroup */
3017
                pid_set = unit_pid_set(main_pid, control_pid);
3018
                if (!pid_set)
3019
                        return -ENOMEM;
3020
3021
                r = cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, sig, true, true, false, pid_set);
3022
                if (r < 0) {
3023
                        if (r != -EAGAIN && r != -ESRCH && r != -ENOENT)
3024
                                log_warning_unit(u->id, "Failed to kill control group: %s", strerror(-r));
3025
                } else if (r > 0) {
3026
                        wait_for_exit = true;
3027
                        if (c->send_sighup) {
3028
                                set_free(pid_set);
3029
3030
                                pid_set = unit_pid_set(main_pid, control_pid);
3031
                                if (!pid_set)
3032
                                        return -ENOMEM;
3033
3034
                                cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, SIGHUP, true, true, false, pid_set);
3035
                        }
3036
                }
3037
        }
3038
3039
        return wait_for_exit;
3040
}
3041
3042
int unit_require_mounts_for(Unit *u, const char *path) {
3043
        char prefix[strlen(path) + 1], *p;
3044
        int r;
3045
3046
        assert(u);
3047
        assert(path);
3048
3049
        /* Registers a unit for requiring a certain path and all its
3050
         * prefixes. We keep a simple array of these paths in the
3051
         * unit, since its usually short. However, we build a prefix
3052
         * table for all possible prefixes so that new appearing mount
3053
         * units can easily determine which units to make themselves a
3054
         * dependency of. */
3055
3056
        p = strdup(path);
3057
        if (!p)
3058
                return -ENOMEM;
3059
3060
        path_kill_slashes(p);
3061
3062
        if (!path_is_absolute(p)) {
3063
                free(p);
3064
                return -EINVAL;
3065
        }
3066
3067
        if (!path_is_safe(p)) {
3068
                free(p);
3069
                return -EPERM;
3070
        }
3071
3072
        if (strv_contains(u->requires_mounts_for, p)) {
3073
                free(p);
3074
                return 0;
3075
        }
3076
3077
        r = strv_push(&u->requires_mounts_for, p);
3078
        if (r < 0) {
3079
                free(p);
3080
                return r;
3081
        }
3082
3083
        PATH_FOREACH_PREFIX_MORE(prefix, p) {
3084
                Set *x;
3085
3086
                x = hashmap_get(u->manager->units_requiring_mounts_for, prefix);
3087
                if (!x) {
3088
                        char *q;
3089
3090
                        if (!u->manager->units_requiring_mounts_for) {
3091
                                u->manager->units_requiring_mounts_for = hashmap_new(string_hash_func, string_compare_func);
3092
                                if (!u->manager->units_requiring_mounts_for)
3093
                                        return -ENOMEM;
3094
                        }
3095
3096
                        q = strdup(prefix);
3097
                        if (!q)
3098
                                return -ENOMEM;
3099
3100
                        x = set_new(NULL, NULL);
3101
                        if (!x) {
3102
                                free(q);
3103
                                return -ENOMEM;
3104
                        }
3105
3106
                        r = hashmap_put(u->manager->units_requiring_mounts_for, q, x);
3107
                        if (r < 0) {
3108
                                free(q);
3109
                                set_free(x);
3110
                                return r;
3111
                        }
3112
                }
3113
3114
                r = set_put(x, u);
3115
                if (r < 0)
3116
                        return r;
3117
        }
3118
3119
        return 0;
3120
}
3121
3122
static const char* const unit_active_state_table[_UNIT_ACTIVE_STATE_MAX] = {
3123
        [UNIT_ACTIVE] = "active",
3124
        [UNIT_RELOADING] = "reloading",
3125
        [UNIT_INACTIVE] = "inactive",
3126
        [UNIT_FAILED] = "failed",
3127
        [UNIT_ACTIVATING] = "activating",
3128
        [UNIT_DEACTIVATING] = "deactivating"
3129
};
3130
3131
DEFINE_STRING_TABLE_LOOKUP(unit_active_state, UnitActiveState);
3132
3133
static const char* const unit_dependency_table[_UNIT_DEPENDENCY_MAX] = {
3134
        [UNIT_REQUIRES] = "Requires",
3135
        [UNIT_REQUIRES_OVERRIDABLE] = "RequiresOverridable",
3136
        [UNIT_REQUISITE] = "Requisite",
3137
        [UNIT_REQUISITE_OVERRIDABLE] = "RequisiteOverridable",
3138
        [UNIT_WANTS] = "Wants",
3139
        [UNIT_BINDS_TO] = "BindsTo",
3140
        [UNIT_PART_OF] = "PartOf",
3141
        [UNIT_REQUIRED_BY] = "RequiredBy",
3142
        [UNIT_REQUIRED_BY_OVERRIDABLE] = "RequiredByOverridable",
3143
        [UNIT_WANTED_BY] = "WantedBy",
3144
        [UNIT_BOUND_BY] = "BoundBy",
3145
        [UNIT_CONSISTS_OF] = "ConsistsOf",
3146
        [UNIT_CONFLICTS] = "Conflicts",
3147
        [UNIT_CONFLICTED_BY] = "ConflictedBy",
3148
        [UNIT_BEFORE] = "Before",
3149
        [UNIT_AFTER] = "After",
3150
        [UNIT_ON_FAILURE] = "OnFailure",
3151
        [UNIT_TRIGGERS] = "Triggers",
3152
        [UNIT_TRIGGERED_BY] = "TriggeredBy",
3153
        [UNIT_PROPAGATES_RELOAD_TO] = "PropagatesReloadTo",
3154
        [UNIT_RELOAD_PROPAGATED_FROM] = "ReloadPropagatedFrom",
3155
        [UNIT_REFERENCES] = "References",
3156
        [UNIT_REFERENCED_BY] = "ReferencedBy",
3157
};
3158
3159
DEFINE_STRING_TABLE_LOOKUP(unit_dependency, UnitDependency);
(-)systemd-208.mod.bck/src/core/unit.h (+9 lines)
Lines 198-203 Link Here
198
        /* CGroup realize members queue */
198
        /* CGroup realize members queue */
199
        LIST_FIELDS(Unit, cgroup_queue);
199
        LIST_FIELDS(Unit, cgroup_queue);
200
200
201
        /* PIDs we keep an eye on. Note that a unit might have many
202
         * more, but these are the ones we care enough about to
203
         * process SIGCHLD for */
204
        Set *pids;
205
201
        /* Used during GC sweeps */
206
        /* Used during GC sweeps */
202
        unsigned gc_marker;
207
        unsigned gc_marker;
203
208
Lines 531-536 Link Here
531
536
532
int unit_watch_pid(Unit *u, pid_t pid);
537
int unit_watch_pid(Unit *u, pid_t pid);
533
void unit_unwatch_pid(Unit *u, pid_t pid);
538
void unit_unwatch_pid(Unit *u, pid_t pid);
539
int unit_watch_all_pids(Unit *u);
540
void unit_unwatch_all_pids(Unit *u);
541
542
void unit_tidy_watch_pids(Unit *u, pid_t except1, pid_t except2);
534
543
535
int unit_watch_timer(Unit *u, clockid_t, bool relative, usec_t usec, Watch *w);
544
int unit_watch_timer(Unit *u, clockid_t, bool relative, usec_t usec, Watch *w);
536
void unit_unwatch_timer(Unit *u, Watch *w);
545
void unit_unwatch_timer(Unit *u, Watch *w);
(-)systemd-208.mod.bck/src/login/logind.c (-3 / +20 lines)
Lines 80-89 Link Here
80
        m->session_fds = hashmap_new(trivial_hash_func, trivial_compare_func);
80
        m->session_fds = hashmap_new(trivial_hash_func, trivial_compare_func);
81
        m->inhibitor_fds = hashmap_new(trivial_hash_func, trivial_compare_func);
81
        m->inhibitor_fds = hashmap_new(trivial_hash_func, trivial_compare_func);
82
        m->button_fds = hashmap_new(trivial_hash_func, trivial_compare_func);
82
        m->button_fds = hashmap_new(trivial_hash_func, trivial_compare_func);
83
        m->timer_fds = hashmap_new(trivial_hash_func, trivial_compare_func);
83
84
84
        if (!m->devices || !m->seats || !m->sessions || !m->users || !m->inhibitors || !m->buttons || !m->busnames ||
85
        if (!m->devices || !m->seats || !m->sessions || !m->users || !m->inhibitors || !m->buttons || !m->busnames ||
85
            !m->user_units || !m->session_units ||
86
            !m->user_units || !m->session_units ||
86
            !m->session_fds || !m->inhibitor_fds || !m->button_fds) {
87
            !m->session_fds || !m->inhibitor_fds || !m->button_fds || !m->timer_fds) {
87
                manager_free(m);
88
                manager_free(m);
88
                return NULL;
89
                return NULL;
89
        }
90
        }
Lines 149-154 Link Here
149
        hashmap_free(m->session_fds);
150
        hashmap_free(m->session_fds);
150
        hashmap_free(m->inhibitor_fds);
151
        hashmap_free(m->inhibitor_fds);
151
        hashmap_free(m->button_fds);
152
        hashmap_free(m->button_fds);
153
        hashmap_free(m->timer_fds);
152
154
153
        if (m->console_active_fd >= 0)
155
        if (m->console_active_fd >= 0)
154
                close_nointr_nofail(m->console_active_fd);
156
                close_nointr_nofail(m->console_active_fd);
Lines 620-625 Link Here
620
                return;
622
                return;
621
        }
623
        }
622
624
625
        s = hashmap_get(m->timer_fds, INT_TO_PTR(fd + 1));
626
        if (s) {
627
                assert(s->timer_fd == fd);
628
                session_stop(s);
629
                return;
630
        }
631
623
        i = hashmap_get(m->inhibitor_fds, INT_TO_PTR(fd + 1));
632
        i = hashmap_get(m->inhibitor_fds, INT_TO_PTR(fd + 1));
624
        if (i) {
633
        if (i) {
625
                assert(i->fifo_fd == fd);
634
                assert(i->fifo_fd == fd);
Lines 942-949 Link Here
942
                LIST_REMOVE(Session, gc_queue, m->session_gc_queue, session);
951
                LIST_REMOVE(Session, gc_queue, m->session_gc_queue, session);
943
                session->in_gc_queue = false;
952
                session->in_gc_queue = false;
944
953
945
                if (session_check_gc(session, drop_not_started) == 0) {
954
                /* First, if we are not closing yet, initiate stopping */
955
                if (!session_check_gc(session, drop_not_started) &&
956
                    session_get_state(session) != SESSION_CLOSING)
946
                        session_stop(session);
957
                        session_stop(session);
958
959
                if (!session_check_gc(session, drop_not_started)) {
947
                        session_finalize(session);
960
                        session_finalize(session);
948
                        session_free(session);
961
                        session_free(session);
949
                }
962
                }
Lines 953-960 Link Here
953
                LIST_REMOVE(User, gc_queue, m->user_gc_queue, user);
966
                LIST_REMOVE(User, gc_queue, m->user_gc_queue, user);
954
                user->in_gc_queue = false;
967
                user->in_gc_queue = false;
955
968
956
                if (user_check_gc(user, drop_not_started) == 0) {
969
                if (!user_check_gc(user, drop_not_started) &&
970
                    user_get_state(user) != USER_CLOSING)
957
                        user_stop(user);
971
                        user_stop(user);
972
973
                if (!user_check_gc(user, drop_not_started)) {
958
                        user_finalize(user);
974
                        user_finalize(user);
959
                        user_free(user);
975
                        user_free(user);
960
                }
976
                }
Lines 1032-1037 Link Here
1032
1048
1033
        return r;
1049
        return r;
1034
}
1050
}
1051
1035
int manager_startup(Manager *m) {
1052
int manager_startup(Manager *m) {
1036
        int r;
1053
        int r;
1037
        Seat *seat;
1054
        Seat *seat;
(-)systemd-208.mod.bck/src/login/logind-dbus.c (-26 / +39 lines)
Lines 1746-1758 Link Here
1746
                if (!session)
1746
                if (!session)
1747
                        return bus_send_error_reply(connection, message, &error, -ENOENT);
1747
                        return bus_send_error_reply(connection, message, &error, -ENOENT);
1748
1748
1749
                /* We use the FIFO to detect stray sessions where the
1749
                session_release(session);
1750
                process invoking PAM dies abnormally. We need to make
1751
                sure that that process is not killed if at the clean
1752
                end of the session it closes the FIFO. Hence, with
1753
                this call explicitly turn off the FIFO logic, so that
1754
                the PAM code can finish clean up on its own */
1755
                session_remove_fifo(session);
1756
1750
1757
                reply = dbus_message_new_method_return(message);
1751
                reply = dbus_message_new_method_return(message);
1758
                if (!reply)
1752
                if (!reply)
Lines 2550-2563 Link Here
2550
                const char *slice,
2544
                const char *slice,
2551
                const char *description,
2545
                const char *description,
2552
                const char *after,
2546
                const char *after,
2553
                const char *kill_mode,
2547
                const char *after2,
2554
                DBusError *error,
2548
                DBusError *error,
2555
                char **job) {
2549
                char **job) {
2556
2550
2557
        const char *timeout_stop_property = "TimeoutStopUSec", *send_sighup_property = "SendSIGHUP", *pids_property = "PIDs";
2551
        const char *send_sighup_property = "SendSIGHUP", *pids_property = "PIDs", *after_property = "After";
2558
        _cleanup_dbus_message_unref_ DBusMessage *m = NULL, *reply = NULL;
2552
        _cleanup_dbus_message_unref_ DBusMessage *m = NULL, *reply = NULL;
2559
        DBusMessageIter iter, sub, sub2, sub3, sub4;
2553
        DBusMessageIter iter, sub, sub2, sub3, sub4;
2560
        uint64_t timeout = 500 * USEC_PER_MSEC;
2561
        dbus_bool_t send_sighup = true;
2554
        dbus_bool_t send_sighup = true;
2562
        const char *fail = "fail";
2555
        const char *fail = "fail";
2563
        uint32_t u;
2556
        uint32_t u;
Lines 2609-2616 Link Here
2609
        }
2602
        }
2610
2603
2611
        if (!isempty(after)) {
2604
        if (!isempty(after)) {
2612
                const char *after_property = "After";
2613
2614
                if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
2605
                if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
2615
                    !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &after_property) ||
2606
                    !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &after_property) ||
2616
                    !dbus_message_iter_open_container(&sub2, DBUS_TYPE_VARIANT, "as", &sub3) ||
2607
                    !dbus_message_iter_open_container(&sub2, DBUS_TYPE_VARIANT, "as", &sub3) ||
Lines 2622-2634 Link Here
2622
                        return log_oom();
2613
                        return log_oom();
2623
        }
2614
        }
2624
2615
2625
        if (!isempty(kill_mode)) {
2616
        if (!isempty(after2)) {
2626
                const char *kill_mode_property = "KillMode";
2627
2628
                if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
2617
                if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
2629
                    !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &kill_mode_property) ||
2618
                    !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &after_property) ||
2630
                    !dbus_message_iter_open_container(&sub2, DBUS_TYPE_VARIANT, "s", &sub3) ||
2619
                    !dbus_message_iter_open_container(&sub2, DBUS_TYPE_VARIANT, "as", &sub3) ||
2631
                    !dbus_message_iter_append_basic(&sub3, DBUS_TYPE_STRING, &kill_mode) ||
2620
                    !dbus_message_iter_open_container(&sub3, DBUS_TYPE_ARRAY, "s", &sub4) ||
2621
                    !dbus_message_iter_append_basic(&sub4, DBUS_TYPE_STRING, &after2) ||
2622
                    !dbus_message_iter_close_container(&sub3, &sub4) ||
2632
                    !dbus_message_iter_close_container(&sub2, &sub3) ||
2623
                    !dbus_message_iter_close_container(&sub2, &sub3) ||
2633
                    !dbus_message_iter_close_container(&sub, &sub2))
2624
                    !dbus_message_iter_close_container(&sub, &sub2))
2634
                        return log_oom();
2625
                        return log_oom();
Lines 2639-2652 Link Here
2639
         * stop timeout for sessions, so that we don't wait
2630
         * stop timeout for sessions, so that we don't wait
2640
         * forever. */
2631
         * forever. */
2641
2632
2642
        if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
2643
            !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &timeout_stop_property) ||
2644
            !dbus_message_iter_open_container(&sub2, DBUS_TYPE_VARIANT, "t", &sub3) ||
2645
            !dbus_message_iter_append_basic(&sub3, DBUS_TYPE_UINT64, &timeout) ||
2646
            !dbus_message_iter_close_container(&sub2, &sub3) ||
2647
            !dbus_message_iter_close_container(&sub, &sub2))
2648
                return log_oom();
2649
2650
        /* Make sure that the session shells are terminated with
2633
        /* Make sure that the session shells are terminated with
2651
         * SIGHUP since bash and friends tend to ignore SIGTERM */
2634
         * SIGHUP since bash and friends tend to ignore SIGTERM */
2652
        if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
2635
        if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
Lines 2790-2795 Link Here
2790
        }
2773
        }
2791
2774
2792
        return 1;
2775
        return 1;
2776
}
2777
2778
int manager_abandon_scope(Manager *manager, const char *scope, DBusError *error) {
2779
        _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
2780
        _cleanup_free_ char *path = NULL;
2781
        int r;
2782
2783
        assert(manager);
2784
        assert(scope);
2785
2786
        path = unit_dbus_path_from_name(scope);
2787
        if (!path)
2788
                return -ENOMEM;
2789
2790
        r = bus_method_call_with_reply(
2791
                manager->bus,
2792
                "org.freedesktop.systemd1",
2793
                path,
2794
                "org.freedesktop.systemd1.Scope",
2795
                "Abandon",
2796
                &reply,
2797
                error,
2798
                DBUS_TYPE_INVALID);
2799
2800
        if (r < 0) {
2801
                log_error("Failed to abandon scope %s", scope);
2802
                return r;
2803
        }
2804
2805
        return 1;
2793
}
2806
}
2794
2807
2795
int manager_kill_unit(Manager *manager, const char *unit, KillWho who, int signo, DBusError *error) {
2808
int manager_kill_unit(Manager *manager, const char *unit, KillWho who, int signo, DBusError *error) {
(-)systemd-208.mod.bck/src/login/logind.h (-1 / +3 lines)
Lines 88-93 Link Here
88
        Hashmap *session_fds;
88
        Hashmap *session_fds;
89
        Hashmap *inhibitor_fds;
89
        Hashmap *inhibitor_fds;
90
        Hashmap *button_fds;
90
        Hashmap *button_fds;
91
        Hashmap *timer_fds;
91
92
92
        usec_t inhibit_delay_max;
93
        usec_t inhibit_delay_max;
93
94
Lines 183-191 Link Here
183
184
184
int manager_dispatch_delayed(Manager *manager);
185
int manager_dispatch_delayed(Manager *manager);
185
186
186
int manager_start_scope(Manager *manager, const char *scope, pid_t pid, const char *slice, const char *description, const char *after, const char *kill_mode, DBusError *error, char **job);
187
int manager_start_scope(Manager *manager, const char *scope, pid_t pid, const char *slice, const char *description, const char *after, const char *after2, DBusError *error, char **job);
187
int manager_start_unit(Manager *manager, const char *unit, DBusError *error, char **job);
188
int manager_start_unit(Manager *manager, const char *unit, DBusError *error, char **job);
188
int manager_stop_unit(Manager *manager, const char *unit, DBusError *error, char **job);
189
int manager_stop_unit(Manager *manager, const char *unit, DBusError *error, char **job);
190
int manager_abandon_scope(Manager *manager, const char *scope, DBusError *error);
189
int manager_kill_unit(Manager *manager, const char *unit, KillWho who, int signo, DBusError *error);
191
int manager_kill_unit(Manager *manager, const char *unit, KillWho who, int signo, DBusError *error);
190
int manager_unit_is_active(Manager *manager, const char *unit);
192
int manager_unit_is_active(Manager *manager, const char *unit);
191
193
(-)systemd-208.mod.bck/src/login/logind-session.c (-29 / +104 lines)
Lines 24-29 Link Here
24
#include <unistd.h>
24
#include <unistd.h>
25
#include <sys/epoll.h>
25
#include <sys/epoll.h>
26
#include <fcntl.h>
26
#include <fcntl.h>
27
#include <sys/timerfd.h>
27
28
28
#include <systemd/sd-id128.h>
29
#include <systemd/sd-id128.h>
29
#include <systemd/sd-messages.h>
30
#include <systemd/sd-messages.h>
Lines 36-41 Link Here
36
#include "dbus-common.h"
37
#include "dbus-common.h"
37
#include "logind-session.h"
38
#include "logind-session.h"
38
39
40
#define RELEASE_SEC 20
41
39
static unsigned devt_hash_func(const void *p) {
42
static unsigned devt_hash_func(const void *p) {
40
        uint64_t u = *(const dev_t*)p;
43
        uint64_t u = *(const dev_t*)p;
41
44
Lines 86-91 Link Here
86
89
87
        s->manager = m;
90
        s->manager = m;
88
        s->fifo_fd = -1;
91
        s->fifo_fd = -1;
92
        s->timer_fd = -1;
89
93
90
        return s;
94
        return s;
91
}
95
}
Lines 505-511 Link Here
505
509
506
        if (!s->scope) {
510
        if (!s->scope) {
507
                _cleanup_free_ char *description = NULL;
511
                _cleanup_free_ char *description = NULL;
508
                const char *kill_mode;
509
                char *scope, *job;
512
                char *scope, *job;
510
513
511
                description = strjoin("Session ", s->id, " of user ", s->user->name, NULL);
514
                description = strjoin("Session ", s->id, " of user ", s->user->name, NULL);
Lines 516-524 Link Here
516
                if (!scope)
519
                if (!scope)
517
                        return log_oom();
520
                        return log_oom();
518
521
519
                kill_mode = manager_shall_kill(s->manager, s->user->name) ? "control-group" : "none";
522
                r = manager_start_scope(s->manager, scope, s->leader, s->user->slice, description, "systemd-logind.service", "systemd-user-sessions.service", &error, &job);
520
521
                r = manager_start_scope(s->manager, scope, s->leader, s->user->slice, description, "systemd-user-sessions.service", kill_mode, &error, &job);
522
                if (r < 0) {
523
                if (r < 0) {
523
                        log_error("Failed to start session scope %s: %s %s",
524
                        log_error("Failed to start session scope %s: %s %s",
524
                                  scope, bus_error(&error, r), error.name);
525
                                  scope, bus_error(&error, r), error.name);
Lines 579-601 Link Here
579
580
580
        s->started = true;
581
        s->started = true;
581
582
582
        /* Save session data */
583
        /* Save data */
583
        session_save(s);
584
        session_save(s);
584
        user_save(s->user);
585
        user_save(s->user);
586
        if (s->seat)
587
                seat_save(s->seat);
585
588
589
        /* Send signals */
586
        session_send_signal(s, true);
590
        session_send_signal(s, true);
591
        user_send_changed(s->user, "Sessions\0");
587
592
588
        if (s->seat) {
593
        if (s->seat) {
589
                seat_save(s->seat);
590
591
                if (s->seat->active == s)
594
                if (s->seat->active == s)
592
                        seat_send_changed(s->seat, "Sessions\0ActiveSession\0");
595
                        seat_send_changed(s->seat, "Sessions\0ActiveSession\0");
593
                else
596
                else
594
                        seat_send_changed(s->seat, "Sessions\0");
597
                        seat_send_changed(s->seat, "Sessions\0");
595
        }
598
        }
596
599
597
        user_send_changed(s->user, "Sessions\0");
598
599
        return 0;
600
        return 0;
600
}
601
}
601
602
Lines 611-625 Link Here
611
        if (!s->scope)
612
        if (!s->scope)
612
                return 0;
613
                return 0;
613
614
614
        r = manager_stop_unit(s->manager, s->scope, &error, &job);
615
        if (manager_shall_kill(s->manager, s->user->name)) {
615
        if (r < 0) {
616
                r = manager_stop_unit(s->manager, s->scope, &error, &job);
616
                log_error("Failed to stop session scope: %s", bus_error(&error, r));
617
                if (r < 0) {
617
                dbus_error_free(&error);
618
                        log_error("Failed to stop session scope: %s", bus_error(&error, r));
618
                return r;
619
                        dbus_error_free(&error);
619
        }
620
                        return r;
621
                }
620
622
621
        free(s->scope_job);
623
                free(s->scope_job);
622
        s->scope_job = job;
624
                s->scope_job = job;
625
        } else {
626
                r = manager_abandon_scope(s->manager, s->scope, &error);
627
                if (r < 0) {
628
                        log_error("Failed to abandon session scope: %s", bus_error(&error, r));
629
                        dbus_error_free(&error);
630
                        return r;
631
                }
632
        }
623
633
624
        return 0;
634
        return 0;
625
}
635
}
Lines 644-649 Link Here
644
        return r < 0 ? -errno : 0;
654
        return r < 0 ? -errno : 0;
645
}
655
}
646
656
657
static void session_close_timer_fd(Session *s) {
658
        assert(s);
659
660
        if (s->timer_fd <= 0)
661
                return;
662
663
        hashmap_remove(s->manager->timer_fds, INT_TO_PTR(s->timer_fd + 1));
664
        epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_DEL, s->timer_fd, NULL);
665
666
        close_nointr(s->timer_fd);
667
        s->timer_fd = -1;
668
}
669
647
int session_stop(Session *s) {
670
int session_stop(Session *s) {
648
        int r;
671
        int r;
649
672
Lines 652-661 Link Here
652
        if (!s->user)
675
        if (!s->user)
653
                return -ESTALE;
676
                return -ESTALE;
654
677
678
        session_close_timer_fd(s);
679
680
        /* We are going down, don't care about FIFOs anymore */
681
        session_remove_fifo(s);
682
655
        /* Kill cgroup */
683
        /* Kill cgroup */
656
        r = session_stop_scope(s);
684
        r = session_stop_scope(s);
657
685
686
        s->stopping = true;
687
658
        session_save(s);
688
        session_save(s);
689
        user_save(s->user);
659
690
660
        return r;
691
        return r;
661
}
692
}
Lines 678-683 Link Here
678
                           "MESSAGE=Removed session %s.", s->id,
709
                           "MESSAGE=Removed session %s.", s->id,
679
                           NULL);
710
                           NULL);
680
711
712
        session_close_timer_fd(s);
713
681
        /* Kill session devices */
714
        /* Kill session devices */
682
        while ((sd = hashmap_first(s->devices)))
715
        while ((sd = hashmap_first(s->devices)))
683
                session_device_free(sd);
716
                session_device_free(sd);
Lines 698-713 Link Here
698
                if (s->seat->active == s)
731
                if (s->seat->active == s)
699
                        seat_set_active(s->seat, NULL);
732
                        seat_set_active(s->seat, NULL);
700
733
701
                seat_send_changed(s->seat, "Sessions\0");
702
                seat_save(s->seat);
734
                seat_save(s->seat);
735
                seat_send_changed(s->seat, "Sessions\0");
703
        }
736
        }
704
737
705
        user_send_changed(s->user, "Sessions\0");
706
        user_save(s->user);
738
        user_save(s->user);
739
        user_send_changed(s->user, "Sessions\0");
707
740
708
        return r;
741
        return r;
709
}
742
}
710
743
744
void session_release(Session *s) {
745
        int r;
746
747
        struct itimerspec its = { .it_value.tv_sec = RELEASE_SEC };
748
        struct epoll_event ev = {};
749
750
        assert(s);
751
752
        if (!s->started || s->stopping)
753
                return;
754
755
        if (s->timer_fd >= 0)
756
                return;
757
758
        s->timer_fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK|TFD_CLOEXEC);
759
        if (s->timer_fd < 0) {
760
                log_error("Failed to create session release timer fd");
761
                goto out;
762
        }
763
764
        r = hashmap_put(s->manager->timer_fds, INT_TO_PTR(s->timer_fd + 1), s);
765
        if (r < 0) {
766
                log_error("Failed to store session release timer fd");
767
                goto out;
768
        }
769
770
        ev.events = EPOLLONESHOT;
771
        ev.data.u32 = FD_OTHER_BASE + s->timer_fd;
772
773
        r = epoll_ctl(s->manager->epoll_fd, EPOLL_CTL_ADD, s->timer_fd, &ev);
774
        if (r < 0) {
775
                log_error("Failed to add session release timer fd to epoll instance");
776
                goto out;
777
        }
778
779
        r = timerfd_settime(s->timer_fd, TFD_TIMER_ABSTIME, &its, NULL);
780
        if (r < 0) {
781
                log_error("Failed to arm timer : %m");
782
                goto out;
783
        }
784
785
out:
786
        if (s->timer_fd >= 0) {
787
                close_nointr(s->timer_fd);
788
                s->timer_fd = -1;
789
        }
790
}
791
711
bool session_is_active(Session *s) {
792
bool session_is_active(Session *s) {
712
        assert(s);
793
        assert(s);
713
794
Lines 904-911 Link Here
904
}
985
}
905
986
906
int session_check_gc(Session *s, bool drop_not_started) {
987
int session_check_gc(Session *s, bool drop_not_started) {
907
        int r;
908
909
        assert(s);
988
        assert(s);
910
989
911
        if (drop_not_started && !s->started)
990
        if (drop_not_started && !s->started)
Lines 915-925 Link Here
915
                return 0;
994
                return 0;
916
995
917
        if (s->fifo_fd >= 0) {
996
        if (s->fifo_fd >= 0) {
918
                r = pipe_eof(s->fifo_fd);
997
                if (pipe_eof(s->fifo_fd) <= 0)
919
                if (r < 0)
920
                        return r;
921
922
                if (r == 0)
923
                        return 1;
998
                        return 1;
924
        }
999
        }
925
1000
Lines 945-959 Link Here
945
SessionState session_get_state(Session *s) {
1020
SessionState session_get_state(Session *s) {
946
        assert(s);
1021
        assert(s);
947
1022
1023
        if (s->stopping || s->timer_fd >= 0)
1024
                return SESSION_CLOSING;
1025
948
        if (s->closing)
1026
        if (s->closing)
949
                return SESSION_CLOSING;
1027
                return SESSION_CLOSING;
950
1028
951
        if (s->scope_job)
1029
        if (s->scope_job)
952
                return SESSION_OPENING;
1030
                return SESSION_OPENING;
953
1031
954
        if (s->fifo_fd < 0)
955
                return SESSION_CLOSING;
956
957
        if (session_is_active(s))
1032
        if (session_is_active(s))
958
                return SESSION_ACTIVE;
1033
                return SESSION_ACTIVE;
959
1034
(-)systemd-208.mod.bck/src/login/logind-session.h (+4 lines)
Lines 98-108 Link Here
98
        int fifo_fd;
98
        int fifo_fd;
99
        char *fifo_path;
99
        char *fifo_path;
100
100
101
        int timer_fd;
102
101
        bool idle_hint;
103
        bool idle_hint;
102
        dual_timestamp idle_hint_timestamp;
104
        dual_timestamp idle_hint_timestamp;
103
105
104
        bool in_gc_queue:1;
106
        bool in_gc_queue:1;
105
        bool started:1;
107
        bool started:1;
108
        bool stopping:1;
106
        bool closing:1;
109
        bool closing:1;
107
110
108
        DBusMessage *create_message;
111
        DBusMessage *create_message;
Lines 130-135 Link Here
130
int session_start(Session *s);
133
int session_start(Session *s);
131
int session_stop(Session *s);
134
int session_stop(Session *s);
132
int session_finalize(Session *s);
135
int session_finalize(Session *s);
136
void session_release(Session *s);
133
int session_save(Session *s);
137
int session_save(Session *s);
134
int session_load(Session *s);
138
int session_load(Session *s);
135
int session_kill(Session *s, KillWho who, int signo);
139
int session_kill(Session *s, KillWho who, int signo);
(-)systemd-208.mod.bck/src/login/logind-user.c (-9 / +16 lines)
Lines 529-534 Link Here
529
        if (k < 0)
529
        if (k < 0)
530
                r = k;
530
                r = k;
531
531
532
        u->stopping = true;
533
532
        user_save(u);
534
        user_save(u);
533
535
534
        return r;
536
        return r;
Lines 644-669 Link Here
644
646
645
UserState user_get_state(User *u) {
647
UserState user_get_state(User *u) {
646
        Session *i;
648
        Session *i;
647
        bool all_closing = true;
648
649
649
        assert(u);
650
        assert(u);
650
651
651
        if (u->closing)
652
        if (u->closing)
652
                return USER_CLOSING;
653
                return USER_CLOSING;
653
654
655
        if (u->stopping)
656
                return USER_CLOSING;
657
654
        if (u->slice_job || u->service_job)
658
        if (u->slice_job || u->service_job)
655
                return USER_OPENING;
659
                return USER_OPENING;
656
660
657
        LIST_FOREACH(sessions_by_user, i, u->sessions) {
661
        if (u->sessions) {
658
                if (session_is_active(i))
662
                bool all_closing = true;
659
                        return USER_ACTIVE;
660
                if (session_get_state(i) != SESSION_CLOSING)
661
                        all_closing = false;
662
        }
663
663
664
        if (u->sessions)
664
                LIST_FOREACH(sessions_by_user, i, u->sessions) {
665
                return all_closing ? USER_CLOSING : USER_ONLINE;
665
                        if (session_is_active(i))
666
                                return USER_ACTIVE;
667
                        if (session_get_state(i) != SESSION_CLOSING)
668
                                all_closing = false;
669
                }
666
670
671
                return all_closing ? USER_CLOSING : USER_ONLINE;
672
        }
673
       
667
        if (user_check_linger_file(u) > 0)
674
        if (user_check_linger_file(u) > 0)
668
                return USER_LINGERING;
675
                return USER_LINGERING;
669
676
(-)systemd-208.mod.bck/src/login/logind-user.h (+1 lines)
Lines 61-66 Link Here
61
61
62
        bool in_gc_queue:1;
62
        bool in_gc_queue:1;
63
        bool started:1;
63
        bool started:1;
64
        bool stopping:1;
64
        bool closing:1;
65
        bool closing:1;
65
66
66
        LIST_HEAD(Session, sessions);
67
        LIST_HEAD(Session, sessions);
(-)systemd-208.mod.bck/src/login/pam-module.c (-4 / +7 lines)
Lines 490-496 Link Here
490
                int flags,
490
                int flags,
491
                int argc, const char **argv) {
491
                int argc, const char **argv) {
492
492
493
        const void *p = NULL, *existing = NULL;
493
        const void *existing = NULL;
494
        const char *id;
494
        const char *id;
495
        DBusConnection *bus = NULL;
495
        DBusConnection *bus = NULL;
496
        DBusMessage *m = NULL, *reply = NULL;
496
        DBusMessage *m = NULL, *reply = NULL;
Lines 547-558 Link Here
547
                }
547
                }
548
        }
548
        }
549
549
550
551
        /* Note that we are knowingly leaking the FIFO fd here. This
552
         * way, logind can watch us die. If we closed it here it would
553
         * not have any clue when that is completed. Given that one
554
         * cannot really have multiple PAM sessions open from the same
555
         * process this means we will leak one FD at max. */
550
        r = PAM_SUCCESS;
556
        r = PAM_SUCCESS;
551
557
552
finish:
558
finish:
553
        pam_get_data(handle, "systemd.session-fd", &p);
554
        if (p)
555
                close_nointr(PTR_TO_INT(p) - 1);
556
559
557
        dbus_error_free(&error);
560
        dbus_error_free(&error);
558
561
(-)systemd-208.mod.bck/src/run/run.c (+8 lines)
Lines 309-314 Link Here
309
        if (r < 0)
309
        if (r < 0)
310
                return r;
310
                return r;
311
311
312
        {
313
                const char *unique_id;
314
                sd_bus_get_unique_name(bus, &unique_id);
315
                r = sd_bus_message_append(m, "(sv)", "Controller", "s", unique_id);
316
                if (r < 0)
317
                        return r;
318
        }
319
312
        r = sd_bus_message_append(m, "(sv)", "PIDs", "au", 1, (uint32_t) getpid());
320
        r = sd_bus_message_append(m, "(sv)", "PIDs", "au", 1, (uint32_t) getpid());
313
        if (r < 0)
321
        if (r < 0)
314
                return r;
322
                return r;
(-)systemd-208.mod.bck/src/run/run.c.orig (+376 lines)
Line 0 Link Here
1
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3
/***
4
  This file is part of systemd.
5
6
  Copyright 2013 Lennart Poettering
7
8
  systemd is free software; you can redistribute it and/or modify it
9
  under the terms of the GNU Lesser General Public License as published by
10
  the Free Software Foundation; either version 2.1 of the License, or
11
  (at your option) any later version.
12
13
  systemd is distributed in the hope that it will be useful, but
14
  WITHOUT ANY WARRANTY; without even the implied warranty of
15
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16
  Lesser General Public License for more details.
17
18
  You should have received a copy of the GNU Lesser General Public License
19
  along with systemd; If not, see <http://www.gnu.org/licenses/>.
20
***/
21
22
#include <stdio.h>
23
#include <getopt.h>
24
25
#include "sd-bus.h"
26
#include "bus-internal.h"
27
#include "bus-message.h"
28
#include "strv.h"
29
#include "build.h"
30
#include "unit-name.h"
31
#include "path-util.h"
32
33
static bool arg_scope = false;
34
static bool arg_user = false;
35
static bool arg_remain_after_exit = false;
36
static const char *arg_unit = NULL;
37
static const char *arg_description = NULL;
38
static const char *arg_slice = NULL;
39
static bool arg_send_sighup = false;
40
41
static int help(void) {
42
43
        printf("%s [OPTIONS...] COMMAND [ARGS...]\n\n"
44
               "Run the specified command in a transient scope or service unit.\n\n"
45
               "  -h --help               Show this help\n"
46
               "     --version            Show package version\n"
47
               "     --user               Run as user unit\n"
48
               "     --scope              Run this as scope rather than service\n"
49
               "     --unit=UNIT          Run under the specified unit name\n"
50
               "     --description=TEXT   Description for unit\n"
51
               "     --slice=SLICE        Run in the specified slice\n"
52
               "  -r --remain-after-exit  Leave service around until explicitly stopped\n"
53
               "     --send-sighup        Send SIGHUP when terminating\n",
54
               program_invocation_short_name);
55
56
        return 0;
57
}
58
59
static int parse_argv(int argc, char *argv[]) {
60
61
        enum {
62
                ARG_VERSION = 0x100,
63
                ARG_USER,
64
                ARG_SCOPE,
65
                ARG_UNIT,
66
                ARG_DESCRIPTION,
67
                ARG_SLICE,
68
                ARG_SEND_SIGHUP,
69
        };
70
71
        static const struct option options[] = {
72
                { "help",              no_argument,       NULL, 'h'             },
73
                { "version",           no_argument,       NULL, ARG_VERSION     },
74
                { "user",              no_argument,       NULL, ARG_USER        },
75
                { "scope",             no_argument,       NULL, ARG_SCOPE       },
76
                { "unit",              required_argument, NULL, ARG_UNIT        },
77
                { "description",       required_argument, NULL, ARG_DESCRIPTION },
78
                { "slice",             required_argument, NULL, ARG_SLICE       },
79
                { "remain-after-exit", no_argument,       NULL, 'r'             },
80
                { "send-sighup",       no_argument,       NULL, ARG_SEND_SIGHUP },
81
                { NULL,                0,                 NULL, 0               },
82
        };
83
84
        int c;
85
86
        assert(argc >= 0);
87
        assert(argv);
88
89
        while ((c = getopt_long(argc, argv, "+hr", options, NULL)) >= 0) {
90
91
                switch (c) {
92
93
                case 'h':
94
                        help();
95
                        return 0;
96
97
                case ARG_VERSION:
98
                        puts(PACKAGE_STRING);
99
                        puts(SYSTEMD_FEATURES);
100
                        return 0;
101
102
                case ARG_USER:
103
                        arg_user = true;
104
                        break;
105
106
                case ARG_SCOPE:
107
                        arg_scope = true;
108
                        break;
109
110
                case ARG_UNIT:
111
                        arg_unit = optarg;
112
                        break;
113
114
                case ARG_DESCRIPTION:
115
                        arg_description = optarg;
116
                        break;
117
118
                case ARG_SLICE:
119
                        arg_slice = optarg;
120
                        break;
121
122
                case ARG_SEND_SIGHUP:
123
                        arg_send_sighup = true;
124
                        break;
125
126
                case 'r':
127
                        arg_remain_after_exit = true;
128
                        break;
129
130
                case '?':
131
                        return -EINVAL;
132
133
                default:
134
                        log_error("Unknown option code %c", c);
135
                        return -EINVAL;
136
                }
137
        }
138
139
        if (optind >= argc) {
140
                log_error("Command line to execute required.");
141
                return -EINVAL;
142
        }
143
144
        return 1;
145
}
146
147
static int message_start_transient_unit_new(sd_bus *bus, const char *name, sd_bus_message **ret) {
148
        _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
149
        int r;
150
151
        log_info("Running as unit %s.", name);
152
153
        r = sd_bus_message_new_method_call(
154
                        bus,
155
                        "org.freedesktop.systemd1",
156
                        "/org/freedesktop/systemd1",
157
                        "org.freedesktop.systemd1.Manager",
158
                        "StartTransientUnit", &m);
159
        if (r < 0)
160
                return r;
161
162
        r = sd_bus_message_append(m, "ss", name, "fail");
163
        if (r < 0)
164
                return r;
165
166
        r = sd_bus_message_open_container(m, 'a', "(sv)");
167
        if (r < 0)
168
                return r;
169
170
        r = sd_bus_message_append(m, "(sv)", "Description", "s", arg_description);
171
        if (r < 0)
172
                return r;
173
174
        if (!isempty(arg_slice)) {
175
                _cleanup_free_ char *slice;
176
177
                slice = unit_name_mangle_with_suffix(arg_slice, ".slice");
178
                if (!slice)
179
                        return -ENOMEM;
180
181
                r = sd_bus_message_append(m, "(sv)", "Slice", "s", slice);
182
                if (r < 0)
183
                        return r;
184
        }
185
186
        r = sd_bus_message_append(m, "(sv)", "SendSIGHUP", "b", arg_send_sighup);
187
        if (r < 0)
188
                return r;
189
190
        *ret = m;
191
        m = NULL;
192
193
        return 0;
194
}
195
196
static int message_start_transient_unit_send(sd_bus *bus, sd_bus_message *m, sd_bus_error *error, sd_bus_message **reply) {
197
        int r;
198
199
        r = sd_bus_message_close_container(m);
200
        if (r < 0)
201
                return r;
202
203
        return sd_bus_send_with_reply_and_block(bus, m, 0, error, reply);
204
}
205
206
static int start_transient_service(
207
                sd_bus *bus,
208
                char **argv,
209
                sd_bus_error *error) {
210
211
        _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
212
        _cleanup_free_ char *name = NULL;
213
        char **i;
214
        int r;
215
216
        if (arg_unit)
217
                name = unit_name_mangle_with_suffix(arg_unit, ".service");
218
        else
219
                asprintf(&name, "run-%lu.service", (unsigned long) getpid());
220
        if (!name)
221
                return -ENOMEM;
222
223
        r = message_start_transient_unit_new(bus, name, &m);
224
        if (r < 0)
225
                return r;
226
227
        r = sd_bus_message_append(m, "(sv)", "RemainAfterExit", "b", arg_remain_after_exit);
228
        if (r < 0)
229
                return r;
230
231
        r = sd_bus_message_open_container(m, 'r', "sv");
232
        if (r < 0)
233
                return r;
234
235
        r = sd_bus_message_append(m, "s", "ExecStart");
236
        if (r < 0)
237
                return r;
238
239
        r = sd_bus_message_open_container(m, 'v', "a(sasb)");
240
        if (r < 0)
241
                return r;
242
243
        r = sd_bus_message_open_container(m, 'a', "(sasb)");
244
        if (r < 0)
245
                return r;
246
247
        r = sd_bus_message_open_container(m, 'r', "sasb");
248
        if (r < 0)
249
                return r;
250
251
        r = sd_bus_message_append(m, "s", argv[0]);
252
        if (r < 0)
253
                return r;
254
255
        r = sd_bus_message_open_container(m, 'a', "s");
256
        if (r < 0)
257
                return r;
258
259
        STRV_FOREACH(i, argv) {
260
                r = sd_bus_message_append(m, "s", *i);
261
                if (r < 0)
262
                        return r;
263
        }
264
265
        r = sd_bus_message_close_container(m);
266
        if (r < 0)
267
                return r;
268
269
        r = sd_bus_message_append(m, "b", false);
270
        if (r < 0)
271
                return r;
272
273
        r = sd_bus_message_close_container(m);
274
        if (r < 0)
275
                return r;
276
277
        r = sd_bus_message_close_container(m);
278
        if (r < 0)
279
                return r;
280
281
        r = sd_bus_message_close_container(m);
282
        if (r < 0)
283
                return r;
284
285
        r = sd_bus_message_close_container(m);
286
        if (r < 0)
287
                return r;
288
289
        return  message_start_transient_unit_send(bus, m, error, &reply);
290
}
291
292
static int start_transient_scope(
293
                sd_bus *bus,
294
                char **argv,
295
                sd_bus_error *error) {
296
297
        _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
298
        _cleanup_free_ char *name = NULL;
299
        int r;
300
301
        if (arg_unit)
302
                name = unit_name_mangle_with_suffix(arg_unit, ".scope");
303
        else
304
                asprintf(&name, "run-%lu.scope", (unsigned long) getpid());
305
        if (!name)
306
                return -ENOMEM;
307
308
        r = message_start_transient_unit_new(bus, name, &m);
309
        if (r < 0)
310
                return r;
311
312
        r = sd_bus_message_append(m, "(sv)", "PIDs", "au", 1, (uint32_t) getpid());
313
        if (r < 0)
314
                return r;
315
316
        r = message_start_transient_unit_send(bus, m, error, &reply);
317
        if (r < 0)
318
                return r;
319
320
        execvp(argv[0], argv);
321
        log_error("Failed to execute: %m");
322
        return -errno;
323
}
324
325
int main(int argc, char* argv[]) {
326
        sd_bus_error error = SD_BUS_ERROR_NULL;
327
        _cleanup_bus_unref_ sd_bus *bus = NULL;
328
        _cleanup_free_ char *description = NULL, *command = NULL;
329
        int r;
330
331
        log_parse_environment();
332
        log_open();
333
334
        r = parse_argv(argc, argv);
335
        if (r <= 0)
336
                goto fail;
337
338
        r = find_binary(argv[optind], &command);
339
        if (r < 0) {
340
                log_error("Failed to find executable %s: %s", argv[optind], strerror(-r));
341
                goto fail;
342
        }
343
        argv[optind] = command;
344
345
        if (!arg_description) {
346
                description = strv_join(argv + optind, " ");
347
                if (!description) {
348
                        r = log_oom();
349
                        goto fail;
350
                }
351
352
                arg_description = description;
353
        }
354
355
        if (arg_user)
356
                r = sd_bus_open_user(&bus);
357
        else
358
                r = sd_bus_open_system(&bus);
359
        if (r < 0) {
360
                log_error("Failed to create new bus connection: %s", strerror(-r));
361
                goto fail;
362
        }
363
364
        if (arg_scope)
365
                r = start_transient_scope(bus, argv + optind, &error);
366
        else
367
                r = start_transient_service(bus, argv + optind, &error);
368
        if (r < 0) {
369
                log_error("Failed start transient unit: %s", error.message ? error.message : strerror(-r));
370
                sd_bus_error_free(&error);
371
                goto fail;
372
        }
373
374
fail:
375
        return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
376
}
(-)systemd-208.mod.bck/src/shared/dbus-common.c (+42 lines)
Lines 1428-1430 Link Here
1428
1428
1429
        return ":no-sender";
1429
        return ":no-sender";
1430
}
1430
}
1431
1432
bool bus_service_name_is_valid(const char *p) {
1433
        const char *q;
1434
        bool dot, found_dot = false, unique;
1435
1436
        if (isempty(p))
1437
                return false;
1438
1439
        unique = p[0] == ':';
1440
1441
        for (dot = true, q = unique ? p+1 : p; *q; q++)
1442
                if (*q == '.') {
1443
                        if (dot)
1444
                                return false;
1445
1446
                        found_dot = dot = true;
1447
                } else {
1448
                        bool good;
1449
1450
                        good =
1451
                                (*q >= 'a' && *q <= 'z') ||
1452
                                (*q >= 'A' && *q <= 'Z') ||
1453
                                ((!dot || unique) && *q >= '0' && *q <= '9') ||
1454
                                *q == '_' || *q == '-';
1455
1456
                        if (!good)
1457
                                return false;
1458
1459
                        dot = false;
1460
                }
1461
1462
        if (q - p > 255)
1463
                return false;
1464
1465
        if (dot)
1466
                return false;
1467
1468
        if (!found_dot)
1469
                return false;
1470
1471
        return true;
1472
}
(-)systemd-208.mod.bck/src/shared/dbus-common.h (+2 lines)
Lines 242-246 Link Here
242
242
243
void bus_message_unrefp(DBusMessage **reply);
243
void bus_message_unrefp(DBusMessage **reply);
244
244
245
bool bus_service_name_is_valid(const char *p);
246
245
#define _cleanup_dbus_message_unref_ __attribute__((cleanup(bus_message_unrefp)))
247
#define _cleanup_dbus_message_unref_ __attribute__((cleanup(bus_message_unrefp)))
246
#define _cleanup_dbus_error_free_ __attribute__((cleanup(dbus_error_free)))
248
#define _cleanup_dbus_error_free_ __attribute__((cleanup(dbus_error_free)))

Return to bug 878853