]> git.ipfire.org Git - thirdparty/systemd.git/blame - device.c
fix impact minimizing code
[thirdparty/systemd.git] / device.c
CommitLineData
5cb5a6ff
LP
1/*-*- Mode: C; c-basic-offset: 8 -*-*/
2
25ac040b
LP
3#include <errno.h>
4#include <libudev.h>
5
87f0e418 6#include "unit.h"
5cb5a6ff
LP
7#include "device.h"
8#include "strv.h"
25ac040b 9#include "log.h"
5cb5a6ff 10
f50e0a01
LP
11static const UnitActiveState state_translation_table[_DEVICE_STATE_MAX] = {
12 [DEVICE_DEAD] = UNIT_INACTIVE,
13 [DEVICE_AVAILABLE] = UNIT_ACTIVE
14};
15
16static const char* const state_string_table[_DEVICE_STATE_MAX] = {
17 [DEVICE_DEAD] = "dead",
18 [DEVICE_AVAILABLE] = "available"
19};
20
87f0e418
LP
21static void device_done(Unit *u) {
22 Device *d = DEVICE(u);
034c6ed7
LP
23
24 assert(d);
25ac040b 25 free(d->sysfs);
034c6ed7
LP
26}
27
f50e0a01
LP
28static void device_set_state(Device *d, DeviceState state) {
29 DeviceState old_state;
30 assert(d);
5cb5a6ff 31
f50e0a01
LP
32 old_state = d->state;
33 d->state = state;
5cb5a6ff 34
f50e0a01
LP
35 log_debug("%s changed %s → %s", unit_id(UNIT(d)), state_string_table[old_state], state_string_table[state]);
36
37 unit_notify(UNIT(d), state_translation_table[old_state], state_translation_table[state]);
38}
39
40static int device_coldplug(Unit *u) {
41 Device *d = DEVICE(u);
42
43 assert(d);
44 assert(d->state == DEVICE_DEAD);
45
46 if (d->sysfs)
47 device_set_state(d, DEVICE_AVAILABLE);
48
49 return 0;
50}
51
52static void device_dump(Unit *u, FILE *f, const char *prefix) {
25ac040b 53 Device *d = DEVICE(u);
5cb5a6ff 54
25ac040b 55 assert(d);
5cb5a6ff
LP
56
57 fprintf(f,
25ac040b
LP
58 "%sDevice State: %s\n"
59 "%sSysfs Path: %s\n",
f50e0a01
LP
60 prefix, state_string_table[d->state],
61 prefix, strna(d->sysfs));
62}
63
64static UnitActiveState device_active_state(Unit *u) {
65 assert(u);
66
67 return state_translation_table[DEVICE(u)->state];
25ac040b
LP
68}
69
b08d03ff 70static int device_add_escaped_name(Unit *u, const char *prefix, const char *dn, bool make_id) {
25ac040b
LP
71 char *e;
72 int r;
73
74 assert(u);
75 assert(dn);
76 assert(dn[0] == '/');
77
b08d03ff 78 if (!(e = unit_name_escape_path(prefix, dn+1, ".device")))
25ac040b
LP
79 return -ENOMEM;
80
81 r = unit_add_name(u, e);
b08d03ff
LP
82
83 if (r >= 0 && make_id)
84 unit_choose_id(u, e);
85
25ac040b
LP
86 free(e);
87
88 if (r < 0 && r != -EEXIST)
89 return r;
90
91 return 0;
92}
93
94static int device_process_device(Manager *m, struct udev_device *dev) {
95 const char *dn, *names, *wants, *sysfs;
96 Unit *u = NULL;
97 int r;
98 char *e, *w, *state;
99 size_t l;
100 bool delete;
101 struct udev_list_entry *item = NULL, *first = NULL;
102
103 assert(m);
104
105 /* Check whether this entry is even relevant for us. */
106 dn = udev_device_get_devnode(dev);
107 names = udev_device_get_property_value(dev, "SYSTEMD_NAMES");
108 wants = udev_device_get_property_value(dev, "SYSTEMD_WANTS");
109
110 if (!dn && !names && !wants)
111 return 0;
112
113 /* Ok, seems kinda interesting. Now, let's see if this one
114 * already exists. */
115
116 if (!(sysfs = udev_device_get_syspath(dev)))
117 return -ENOMEM;
118
119 assert(sysfs[0] == '/');
b08d03ff 120 if (!(e = unit_name_escape_path("sysfs-", sysfs+1, ".device")))
25ac040b
LP
121 return -ENOMEM;
122
123 if (!(u = manager_get_unit(m, e))) {
124 const char *model;
125
126 delete = true;
127
128 if (!(u = unit_new(m))) {
129 free(e);
130 return -ENOMEM;
131 }
132
133 r = unit_add_name(u, e);
134 free(e);
135
136 if (r < 0)
137 goto fail;
138
139 if (!(DEVICE(u)->sysfs = strdup(sysfs))) {
140 r = -ENOMEM;
141 goto fail;
142 }
143
144 if ((model = udev_device_get_property_value(dev, "ID_MODEL_FROM_DATABASE")) ||
f50e0a01
LP
145 (model = udev_device_get_property_value(dev, "ID_MODEL")))
146 if ((r = unit_set_description(u, model)) < 0)
25ac040b 147 goto fail;
25ac040b
LP
148
149 } else {
150 delete = false;
151 free(e);
152 }
153
154 if (dn)
b08d03ff 155 if ((r = device_add_escaped_name(u, "node-", dn, true)) < 0)
25ac040b
LP
156 goto fail;
157
158 first = udev_device_get_devlinks_list_entry(dev);
159 udev_list_entry_foreach(item, first)
b08d03ff 160 if ((r = device_add_escaped_name(u, "node-", udev_list_entry_get_name(item), false)) < 0)
25ac040b
LP
161 goto fail;
162
163 if (names) {
164 FOREACH_WORD(w, l, names, state) {
165 if (!(e = strndup(w, l)))
166 goto fail;
167
168 r = unit_add_name(u, e);
169 free(e);
170
171 if (r < 0 && r != -EEXIST)
172 goto fail;
173 }
174 }
175
176
177 if (set_isempty(u->meta.names)) {
178 r = -EEXIST;
179 goto fail;
180 }
181
182 if (wants) {
183 FOREACH_WORD(w, l, wants, state) {
184 if (!(e = strndup(w, l)))
185 goto fail;
186
187 r = unit_add_dependency_by_name(u, UNIT_WANTS, e);
188 free(e);
189
190 if (r < 0)
191 goto fail;
192 }
193 }
194
195 unit_add_to_load_queue(u);
196 return 0;
197
198fail:
199 if (delete && u)
200 unit_free(u);
201 return r;
202}
203
204static int device_process_path(Manager *m, const char *path) {
205 int r;
206 struct udev_device *dev;
207
208 assert(m);
209 assert(path);
210
211 if (!(dev = udev_device_new_from_syspath(m->udev, path))) {
212 log_warning("Failed to get udev device object from udev for path %s.", path);
213 return -ENOMEM;
214 }
215
216 r = device_process_device(m, dev);
217 udev_device_unref(dev);
218 return r;
219}
220
221static void device_shutdown(Manager *m) {
222 assert(m);
223
224 if (m->udev)
225 udev_unref(m->udev);
226}
227
228static int device_enumerate(Manager *m) {
229 int r;
230 struct udev_enumerate *e = NULL;
231 struct udev_list_entry *item = NULL, *first = NULL;
232
233 assert(m);
234
235 if (!(m->udev = udev_new()))
236 return -ENOMEM;
237
238 if (!(e = udev_enumerate_new(m->udev))) {
239 r = -ENOMEM;
240 goto fail;
241 }
242
243 if (udev_enumerate_scan_devices(e) < 0) {
244 r = -EIO;
245 goto fail;
246 }
247
248 first = udev_enumerate_get_list_entry(e);
249 udev_list_entry_foreach(item, first)
250 device_process_path(m, udev_list_entry_get_name(item));
251
252 udev_enumerate_unref(e);
253
254 return 0;
255
256fail:
257 if (e)
258 udev_enumerate_unref(e);
259
260 device_shutdown(m);
261 return r;
5cb5a6ff
LP
262}
263
87f0e418 264const UnitVTable device_vtable = {
5cb5a6ff
LP
265 .suffix = ".device",
266
87f0e418 267 .init = unit_load_fragment_and_dropin,
034c6ed7 268 .done = device_done,
f50e0a01
LP
269 .coldplug = device_coldplug,
270
5cb5a6ff
LP
271 .dump = device_dump,
272
f50e0a01 273 .active_state = device_active_state,
25ac040b 274
f50e0a01
LP
275 .enumerate = device_enumerate,
276 .shutdown = device_shutdown
5cb5a6ff 277};