chiark / gitweb /
name: add simple name string validator
[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         /* Not much initialization happening here at this time */
69         n->meta.manager = m;
70         n->meta.type = _NAME_TYPE_INVALID;
71         n->meta.state = NAME_STUB;
72
73         /* We don't link the name here, that is left for name_link() */
74
75         return n;
76 }
77
78 int name_link(Name *n) {
79         char **t;
80         int r;
81
82         assert(n);
83         assert(!n->meta.linked);
84
85         STRV_FOREACH(t, n->meta.names)
86                 if ((r = hashmap_put(n->meta.manager->names, *t, n)) < 0)
87                         goto fail;
88
89         if (n->meta.state == NAME_STUB)
90                 LIST_PREPEND(Meta, n->meta.manager->load_queue, &n->meta);
91
92         n->meta.linked = true;
93
94         return 0;
95
96 fail:
97         t--;
98         STRV_FOREACH_BACKWARDS(t, n->meta.names)
99                 hashmap_remove(n->meta.manager->names, *t);
100
101         return r;
102 }
103
104 void name_free(Name *name) {
105
106         assert(name);
107
108         /* Detach from next 'bigger' objects */
109
110         if (name->meta.linked) {
111                 char **t;
112
113                 STRV_FOREACH(t, name->meta.names)
114                         hashmap_remove(name->meta.manager->names, *t);
115
116                 if (name->meta.job)
117                         job_free(name->meta.job);
118         }
119
120         /* Free data and next 'smaller' objects */
121
122         if (name->meta.job)
123                 job_free(name->meta.job);
124
125         /* FIXME: Other names pointing to us should probably drop their refs to us when we get destructed */
126         set_free(name->meta.requires);
127         set_free(name->meta.soft_requires);
128         set_free(name->meta.wants);
129         set_free(name->meta.requisite);
130         set_free(name->meta.soft_requires);
131         set_free(name->meta.conflicts);
132         set_free(name->meta.before);
133         set_free(name->meta.after);
134
135         switch (name->meta.type) {
136
137                 case NAME_SOCKET: {
138                         unsigned i;
139                         Socket *s = SOCKET(name);
140
141                         for (i = 0; i < s->n_fds; i++)
142                                 nointr_close(s->fds[i]);
143                         break;
144                 }
145
146                 case NAME_DEVICE: {
147                         Device *d = DEVICE(name);
148
149                         free(d->sysfs);
150                         break;
151                 }
152
153                 case NAME_MOUNT: {
154                         Mount *m = MOUNT(name);
155
156                         free(m->path);
157                         break;
158                 }
159
160                 case NAME_AUTOMOUNT: {
161                         Automount *a = AUTOMOUNT(name);
162
163                         free(a->path);
164                         break;
165                 }
166
167                 default:
168                         ;
169         }
170
171         free(name->meta.description);
172         strv_free(name->meta.names);
173
174         free(name);
175 }
176
177 bool name_is_ready(Name *name) {
178
179         assert(name);
180
181         if (name->meta.state != NAME_LOADED)
182                 return false;
183
184         assert(name->meta.type < _NAME_TYPE_MAX);
185
186         switch (name->meta.type) {
187                 case NAME_SERVICE: {
188                         Service *s = SERVICE(name);
189
190                         return
191                                 s->state == SERVICE_RUNNING ||
192                                 s->state == SERVICE_RELOAD_PRE ||
193                                 s->state == SERVICE_RELOAD ||
194                                 s->state == SERVICE_RELOAD_POST;
195                 }
196
197                 case NAME_TIMER: {
198                         Timer *t = TIMER(name);
199
200                         return
201                                 t->state == TIMER_WAITING ||
202                                 t->state == TIMER_RUNNING;
203                 }
204
205                 case NAME_SOCKET: {
206                         Socket *s = SOCKET(name);
207
208                         return
209                                 s->state == SOCKET_LISTENING ||
210                                 s->state == SOCKET_RUNNING;
211                 }
212
213                 case NAME_MILESTONE:
214                         return MILESTONE(name)->state == MILESTONE_ACTIVE;
215
216                 case NAME_DEVICE:
217                         return DEVICE(name)->state == DEVICE_AVAILABLE;
218
219                 case NAME_MOUNT:
220                         return MOUNT(name)->state == MOUNT_MOUNTED;
221
222                 case NAME_AUTOMOUNT: {
223                         Automount *a = AUTOMOUNT(name);
224
225                         return
226                                 a->state == AUTOMOUNT_WAITING ||
227                                 a->state == AUTOMOUNT_RUNNING;
228                 }
229
230                 case NAME_SNAPSHOT:
231                         return SNAPSHOT(name)->state == SNAPSHOT_ACTIVE;
232
233
234                 case _NAME_TYPE_MAX:
235                 case _NAME_TYPE_INVALID:
236                         ;
237         }
238
239         assert_not_reached("Unknown name type.");
240         return false;
241 }
242
243 static int ensure_in_set(Set **s, void *data) {
244         int r;
245
246         assert(s);
247         assert(data);
248
249         if (!*s)
250                 if (!(*s = set_new(trivial_hash_func, trivial_compare_func)))
251                         return -ENOMEM;
252
253         if ((r = set_put(*s, data) < 0))
254                 if (r != -EEXIST)
255                         return r;
256
257         return 0;
258 }
259
260 int name_augment(Name *n) {
261         int r;
262         void* state;
263         Name *other;
264
265         assert(n);
266
267         /* Adds in the missing links to make all dependencies both-ways */
268
269         SET_FOREACH(other, n->meta.before, state)
270                 if ((r = ensure_in_set(&other->meta.after, n) < 0))
271                         return r;
272         SET_FOREACH(other, n->meta.after, state)
273                 if ((r = ensure_in_set(&other->meta.before, n) < 0))
274                         return r;
275
276         SET_FOREACH(other, n->meta.conflicts, state)
277                 if ((r = ensure_in_set(&other->meta.conflicts, n) < 0))
278                         return r;
279
280         SET_FOREACH(other, n->meta.requires, state)
281                 if ((r = ensure_in_set(&other->meta.required_by, n) < 0))
282                         return r;
283         SET_FOREACH(other, n->meta.soft_requires, state)
284                 if ((r = ensure_in_set(&other->meta.required_by, n) < 0))
285                         return r;
286         SET_FOREACH(other, n->meta.requisite, state)
287                 if ((r = ensure_in_set(&other->meta.required_by, n) < 0))
288                         return r;
289         SET_FOREACH(other, n->meta.soft_requisite, state)
290                 if ((r = ensure_in_set(&other->meta.required_by, n) < 0))
291                         return r;
292
293         return r;
294 }