chiark / gitweb /
f29ce2298bbf3f73d2f203deb4b3f22cd71b5c06
[elogind.git] / name.c
1 /*-*- Mode: C; c-basic-offset: 8 -*-*/
2
3 #include <assert.h>
4 #include <errno.h>
5 #include <string.h>
6
7 #include "set.h"
8 #include "name.h"
9 #include "macro.h"
10 #include "strv.h"
11
12 NameType name_type_from_string(const char *n) {
13         NameType t;
14         static const char* suffixes[_NAME_TYPE_MAX] = {
15                 [NAME_SERVICE] = ".service",
16                 [NAME_TIMER] = ".timer",
17                 [NAME_SOCKET] = ".socket",
18                 [NAME_MILESTONE] = ".milestone",
19                 [NAME_DEVICE] = ".device",
20                 [NAME_MOUNT] = ".mount",
21                 [NAME_AUTOMOUNT] = ".automount",
22                 [NAME_SNAPSHOT] = ".snapshot",
23         };
24
25         assert(n);
26
27         for (t = 0; t < _NAME_TYPE_MAX; t++)
28                 if (endswith(n, suffixes[t]))
29                         return t;
30
31         return _NAME_TYPE_INVALID;
32 }
33
34 #define VALID_CHARS                             \
35         "0123456789"                            \
36         "abcdefghijklmnopqrstuvwxyz"            \
37         "ABCDEFGHIJKLMNOPQRSTUVWXYZ"            \
38         "-_"
39
40 bool name_is_valid(const char *n) {
41         NameType t;
42         const char *e, *i;
43
44         assert(n);
45
46         t = name_type_from_string(n);
47         if (t < 0 || t >= _NAME_TYPE_MAX)
48                 return false;
49
50         if (!(e = strrchr(n, '.')))
51                 return false;
52
53         for (i = n; i < e; i++)
54                 if (!strchr(VALID_CHARS, *i))
55                         return false;
56
57         return true;
58 }
59
60 Name *name_new(Manager *m) {
61         Name *n;
62
63         assert(m);
64
65         if (!(n = new0(Name, 1)))
66                 return NULL;
67
68         if (!(n->meta.names = set_new(string_hash_func, string_compare_func))) {
69                 free(n);
70                 return NULL;
71         }
72
73         /* Not much initialization happening here at this time */
74         n->meta.manager = m;
75         n->meta.type = _NAME_TYPE_INVALID;
76         n->meta.state = NAME_STUB;
77
78         /* We don't link the name here, that is left for name_link() */
79
80         return n;
81 }
82
83 int name_link(Name *n) {
84         char **t;
85         int r;
86         void *state;
87
88         assert(n);
89         assert(!set_isempty(n->meta.names));
90         assert(!n->meta.linked);
91
92         SET_FOREACH(t, n->meta.names, state)
93                 if ((r = hashmap_put(n->meta.manager->names, t, n)) < 0)
94                         goto fail;
95
96         if (n->meta.state == NAME_STUB)
97                 LIST_PREPEND(Meta, n->meta.manager->load_queue, &n->meta);
98
99         n->meta.linked = true;
100
101         return 0;
102
103 fail:
104         SET_FOREACH(t, n->meta.names, state)
105                 assert_se(hashmap_remove(n->meta.manager->names, t) == n);
106
107         return r;
108 }
109
110 static void bidi_set_free(Name *name, Set *s) {
111         void *state;
112         Name *other;
113
114         assert(name);
115         assert(s);
116
117         /* Frees the set and makes sure we are dropped from the
118          * inverse pointers */
119
120         SET_FOREACH(other, s, state) {
121                 NameDependency d;
122
123                 for (d = 0; d < _NAME_DEPENDENCY_MAX; d++)
124                         set_remove(other->meta.dependencies[d], name);
125         }
126
127         set_free(s);
128 }
129
130 void name_free(Name *name) {
131         NameDependency d;
132         char *t;
133
134         assert(name);
135
136         /* Detach from next 'bigger' objects */
137         if (name->meta.linked) {
138                 char **t;
139                 void *state;
140
141                 SET_FOREACH(t, name->meta.names, state)
142                         assert_se(hashmap_remove(name->meta.manager->names, t) == name);
143
144                 if (name->meta.state == NAME_STUB)
145                         LIST_REMOVE(Meta, name->meta.manager->load_queue, &name->meta);
146         }
147
148         /* Free data and next 'smaller' objects */
149         if (name->meta.job)
150                 job_free(name->meta.job);
151
152         for (d = 0; d < _NAME_DEPENDENCY_MAX; d++)
153                 bidi_set_free(name, name->meta.dependencies[d]);
154
155         switch (name->meta.type) {
156
157                 case NAME_SOCKET: {
158                         unsigned i;
159                         Socket *s = SOCKET(name);
160
161                         for (i = 0; i < s->n_fds; i++)
162                                 nointr_close(s->fds[i]);
163                         break;
164                 }
165
166                 case NAME_DEVICE: {
167                         Device *d = DEVICE(name);
168
169                         free(d->sysfs);
170                         break;
171                 }
172
173                 case NAME_MOUNT: {
174                         Mount *m = MOUNT(name);
175
176                         free(m->path);
177                         break;
178                 }
179
180                 case NAME_AUTOMOUNT: {
181                         Automount *a = AUTOMOUNT(name);
182
183                         free(a->path);
184                         break;
185                 }
186
187                 default:
188                         ;
189         }
190
191         free(name->meta.description);
192
193         while ((t = set_steal_first(name->meta.names)))
194                 free(t);
195         set_free(name->meta.names);
196
197         free(name);
198 }
199
200 bool name_is_ready(Name *name) {
201
202         assert(name);
203
204         if (name->meta.state != NAME_LOADED)
205                 return false;
206
207         assert(name->meta.type < _NAME_TYPE_MAX);
208
209         switch (name->meta.type) {
210                 case NAME_SERVICE: {
211                         Service *s = SERVICE(name);
212
213                         return
214                                 s->state == SERVICE_RUNNING ||
215                                 s->state == SERVICE_RELOAD_PRE ||
216                                 s->state == SERVICE_RELOAD ||
217                                 s->state == SERVICE_RELOAD_POST;
218                 }
219
220                 case NAME_TIMER: {
221                         Timer *t = TIMER(name);
222
223                         return
224                                 t->state == TIMER_WAITING ||
225                                 t->state == TIMER_RUNNING;
226                 }
227
228                 case NAME_SOCKET: {
229                         Socket *s = SOCKET(name);
230
231                         return
232                                 s->state == SOCKET_LISTENING ||
233                                 s->state == SOCKET_RUNNING;
234                 }
235
236                 case NAME_MILESTONE:
237                         return MILESTONE(name)->state == MILESTONE_ACTIVE;
238
239                 case NAME_DEVICE:
240                         return DEVICE(name)->state == DEVICE_AVAILABLE;
241
242                 case NAME_MOUNT:
243                         return MOUNT(name)->state == MOUNT_MOUNTED;
244
245                 case NAME_AUTOMOUNT: {
246                         Automount *a = AUTOMOUNT(name);
247
248                         return
249                                 a->state == AUTOMOUNT_WAITING ||
250                                 a->state == AUTOMOUNT_RUNNING;
251                 }
252
253                 case NAME_SNAPSHOT:
254                         return SNAPSHOT(name)->state == SNAPSHOT_ACTIVE;
255
256
257                 case _NAME_TYPE_MAX:
258                 case _NAME_TYPE_INVALID:
259                         ;
260         }
261
262         assert_not_reached("Unknown name type.");
263         return false;
264 }
265
266 static int ensure_in_set(Set **s, void *data) {
267         int r;
268
269         assert(s);
270         assert(data);
271
272         if (!*s)
273                 if (!(*s = set_new(trivial_hash_func, trivial_compare_func)))
274                         return -ENOMEM;
275
276         if ((r = set_put(*s, data) < 0))
277                 if (r != -EEXIST)
278                         return r;
279
280         return 0;
281 }
282
283 int name_augment(Name *n) {
284         int r;
285         void* state;
286         Name *other;
287
288         assert(n);
289
290         /* Adds in the missing links to make all dependencies bidirectional */
291
292         SET_FOREACH(other, n->meta.dependencies[NAME_BEFORE], state)
293                 if ((r = ensure_in_set(&other->meta.dependencies[NAME_AFTER], n) < 0))
294                         return r;
295         SET_FOREACH(other, n->meta.dependencies[NAME_AFTER], state)
296                 if ((r = ensure_in_set(&other->meta.dependencies[NAME_BEFORE], n) < 0))
297                         return r;
298
299         SET_FOREACH(other, n->meta.dependencies[NAME_CONFLICTS], state)
300                 if ((r = ensure_in_set(&other->meta.dependencies[NAME_CONFLICTS], n) < 0))
301                         return r;
302
303         SET_FOREACH(other, n->meta.dependencies[NAME_REQUIRES], state)
304                 if ((r = ensure_in_set(&other->meta.dependencies[NAME_REQUIRED_BY], n) < 0))
305                         return r;
306         SET_FOREACH(other, n->meta.dependencies[NAME_REQUISITE], state)
307                 if ((r = ensure_in_set(&other->meta.dependencies[NAME_REQUIRED_BY], n) < 0))
308                         return r;
309
310         SET_FOREACH(other, n->meta.dependencies[NAME_WANTS], state)
311                 if ((r = ensure_in_set(&other->meta.dependencies[NAME_WANTED_BY], n) < 0))
312                         return r;
313         SET_FOREACH(other, n->meta.dependencies[NAME_SOFT_REQUIRES], state)
314                 if ((r = ensure_in_set(&other->meta.dependencies[NAME_WANTED_BY], n) < 0))
315                         return r;
316         SET_FOREACH(other, n->meta.dependencies[NAME_SOFT_REQUISITE], state)
317                 if ((r = ensure_in_set(&other->meta.dependencies[NAME_WANTED_BY], n) < 0))
318                         return r;
319
320         return r;
321 }
322
323 static int ensure_merge(Set **s, Set *other) {
324
325         if (!other)
326                 return 0;
327
328         if (*s)
329                 return set_merge(*s, other);
330
331         if (!(*s = set_copy(other)))
332                 return -ENOMEM;
333
334         return 0;
335 }
336
337 int name_merge(Name *name, Name *other) {
338         int r;
339         NameDependency d;
340
341         assert(name);
342         assert(other);
343
344         assert(name->meta.manager == other->meta.manager);
345
346         if (name->meta.type != other->meta.type)
347                 return -EINVAL;
348
349         if (other->meta.state != NAME_STUB)
350                 return -EINVAL;
351
352         /* Merge names */
353         if ((r = ensure_merge(&name->meta.names, other->meta.names)) < 0)
354                 return r;
355
356         /* Merge dependencies */
357         for (d = 0; d < _NAME_DEPENDENCY_MAX; d++)
358                 if ((r = ensure_merge(&name->meta.dependencies[d], other->meta.dependencies[d])) < 0)
359                         return r;
360
361         return 0;
362 }