Coverage Report

Created: 2019-06-19 13:33

/src/systemd/src/core/target.c
Line
Count
Source (jump to first uncovered line)
1
/* SPDX-License-Identifier: LGPL-2.1+ */
2
3
#include "dbus-target.h"
4
#include "dbus-unit.h"
5
#include "log.h"
6
#include "serialize.h"
7
#include "special.h"
8
#include "string-util.h"
9
#include "target.h"
10
#include "unit-name.h"
11
#include "unit.h"
12
13
static const UnitActiveState state_translation_table[_TARGET_STATE_MAX] = {
14
        [TARGET_DEAD] = UNIT_INACTIVE,
15
        [TARGET_ACTIVE] = UNIT_ACTIVE
16
};
17
18
0
static void target_set_state(Target *t, TargetState state) {
19
0
        TargetState old_state;
20
0
        assert(t);
21
0
22
0
        if (t->state != state)
23
0
                bus_unit_send_pending_change_signal(UNIT(t), false);
24
0
25
0
        old_state = t->state;
26
0
        t->state = state;
27
0
28
0
        if (state != old_state)
29
0
                log_debug("%s changed %s -> %s",
30
0
                          UNIT(t)->id,
31
0
                          target_state_to_string(old_state),
32
0
                          target_state_to_string(state));
33
0
34
0
        unit_notify(UNIT(t), state_translation_table[old_state], state_translation_table[state], 0);
35
0
}
36
37
0
static int target_add_default_dependencies(Target *t) {
38
0
39
0
        static const UnitDependency deps[] = {
40
0
                UNIT_REQUIRES,
41
0
                UNIT_REQUISITE,
42
0
                UNIT_WANTS,
43
0
                UNIT_BINDS_TO,
44
0
                UNIT_PART_OF
45
0
        };
46
0
47
0
        int r;
48
0
        unsigned k;
49
0
50
0
        assert(t);
51
0
52
0
        if (!UNIT(t)->default_dependencies)
53
0
                return 0;
54
0
55
0
        /* Imply ordering for requirement dependencies on target units. Note that when the user created a contradicting
56
0
         * ordering manually we won't add anything in here to make sure we don't create a loop. */
57
0
58
0
        for (k = 0; k < ELEMENTSOF(deps); k++) {
59
0
                Unit *other;
60
0
                Iterator i;
61
0
                void *v;
62
0
63
0
                HASHMAP_FOREACH_KEY(v, other, UNIT(t)->dependencies[deps[k]], i) {
64
0
                        r = unit_add_default_target_dependency(other, UNIT(t));
65
0
                        if (r < 0)
66
0
                                return r;
67
0
                }
68
0
        }
69
0
70
0
        if (unit_has_name(UNIT(t), SPECIAL_SHUTDOWN_TARGET))
71
0
                return 0;
72
0
73
0
        /* Make sure targets are unloaded on shutdown */
74
0
        return unit_add_two_dependencies_by_name(UNIT(t), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, true, UNIT_DEPENDENCY_DEFAULT);
75
0
}
76
77
1.18k
static int target_load(Unit *u) {
78
1.18k
        Target *t = TARGET(u);
79
1.18k
        int r;
80
1.18k
81
1.18k
        assert(t);
82
1.18k
83
1.18k
        r = unit_load_fragment_and_dropin(u);
84
1.18k
        if (r < 0)
85
1.18k
                return r;
86
0
87
0
        /* This is a new unit? Then let's add in some extras */
88
0
        if (u->load_state == UNIT_LOADED) {
89
0
                r = target_add_default_dependencies(t);
90
0
                if (r < 0)
91
0
                        return r;
92
0
        }
93
0
94
0
        return 0;
95
0
}
96
97
0
static int target_coldplug(Unit *u) {
98
0
        Target *t = TARGET(u);
99
0
100
0
        assert(t);
101
0
        assert(t->state == TARGET_DEAD);
102
0
103
0
        if (t->deserialized_state != t->state)
104
0
                target_set_state(t, t->deserialized_state);
105
0
106
0
        return 0;
107
0
}
108
109
0
static void target_dump(Unit *u, FILE *f, const char *prefix) {
110
0
        Target *t = TARGET(u);
111
0
112
0
        assert(t);
113
0
        assert(f);
114
0
115
0
        fprintf(f,
116
0
                "%sTarget State: %s\n",
117
0
                prefix, target_state_to_string(t->state));
118
0
}
119
120
0
static int target_start(Unit *u) {
121
0
        Target *t = TARGET(u);
122
0
        int r;
123
0
124
0
        assert(t);
125
0
        assert(t->state == TARGET_DEAD);
126
0
127
0
        r = unit_acquire_invocation_id(u);
128
0
        if (r < 0)
129
0
                return r;
130
0
131
0
        target_set_state(t, TARGET_ACTIVE);
132
0
        return 1;
133
0
}
134
135
0
static int target_stop(Unit *u) {
136
0
        Target *t = TARGET(u);
137
0
138
0
        assert(t);
139
0
        assert(t->state == TARGET_ACTIVE);
140
0
141
0
        target_set_state(t, TARGET_DEAD);
142
0
        return 1;
143
0
}
144
145
0
static int target_serialize(Unit *u, FILE *f, FDSet *fds) {
146
0
        Target *s = TARGET(u);
147
0
148
0
        assert(s);
149
0
        assert(f);
150
0
        assert(fds);
151
0
152
0
        (void) serialize_item(f, "state", target_state_to_string(s->state));
153
0
        return 0;
154
0
}
155
156
0
static int target_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
157
0
        Target *s = TARGET(u);
158
0
159
0
        assert(u);
160
0
        assert(key);
161
0
        assert(value);
162
0
        assert(fds);
163
0
164
0
        if (streq(key, "state")) {
165
0
                TargetState state;
166
0
167
0
                state = target_state_from_string(value);
168
0
                if (state < 0)
169
0
                        log_debug("Failed to parse state value %s", value);
170
0
                else
171
0
                        s->deserialized_state = state;
172
0
173
0
        } else
174
0
                log_debug("Unknown serialization key '%s'", key);
175
0
176
0
        return 0;
177
0
}
178
179
4.28k
_pure_ static UnitActiveState target_active_state(Unit *u) {
180
4.28k
        assert(u);
181
4.28k
182
4.28k
        return state_translation_table[TARGET(u)->state];
183
4.28k
}
184
185
0
_pure_ static const char *target_sub_state_to_string(Unit *u) {
186
0
        assert(u);
187
0
188
0
        return target_state_to_string(TARGET(u)->state);
189
0
}
190
191
const UnitVTable target_vtable = {
192
        .object_size = sizeof(Target),
193
194
        .sections =
195
                "Unit\0"
196
                "Target\0"
197
                "Install\0",
198
199
        .load = target_load,
200
        .coldplug = target_coldplug,
201
202
        .dump = target_dump,
203
204
        .start = target_start,
205
        .stop = target_stop,
206
207
        .serialize = target_serialize,
208
        .deserialize_item = target_deserialize_item,
209
210
        .active_state = target_active_state,
211
        .sub_state_to_string = target_sub_state_to_string,
212
213
        .bus_vtable = bus_target_vtable,
214
215
        .status_message_formats = {
216
                .finished_start_job = {
217
                        [JOB_DONE]       = "Reached target %s.",
218
                },
219
                .finished_stop_job = {
220
                        [JOB_DONE]       = "Stopped target %s.",
221
                },
222
        },
223
};