chiark / gitweb /
util: add parsers for boolean and integers
[elogind.git] / name.c
1 /*-*- Mode: C; c-basic-offset: 8 -*-*/
2
3 #include <assert.h>
4 #include <errno.h>
5
6 #include "set.h"
7 #include "name.h"
8 #include "macro.h"
9 #include "strv.h"
10
11 NameType name_type_from_string(const char *n) {
12         NameType t;
13         static const char* suffixes[_NAME_TYPE_MAX] = {
14                 [NAME_SERVICE] = ".service",
15                 [NAME_TIMER] = ".timer",
16                 [NAME_SOCKET] = ".socket",
17                 [NAME_MILESTONE] = ".milestone",
18                 [NAME_DEVICE] = ".device",
19                 [NAME_MOUNT] = ".mount",
20                 [NAME_AUTOMOUNT] = ".automount",
21                 [NAME_SNAPSHOT] = ".snapshot",
22         };
23
24         assert(n);
25
26         for (t = 0; t < _NAME_TYPE_MAX; t++)
27                 if (endswith(n, suffixes[t]))
28                         return t;
29
30         return _NAME_TYPE_INVALID;
31 }
32
33 Name *name_new(Manager *m) {
34         Name *n;
35
36         assert(m);
37
38         if (!(n = new0(Name, 1)))
39                 return NULL;
40
41         /* Not much initialization happening here at this time */
42         n->meta.manager = m;
43         n->meta.type = _NAME_TYPE_INVALID;
44         n->meta.state = NAME_STUB;
45
46         /* We don't link the name here, that is left for name_link() */
47
48         return n;
49 }
50
51 int name_link(Name *n) {
52         char **t;
53         int r;
54
55         assert(n);
56         assert(!n->meta.linked);
57
58         STRV_FOREACH(t, n->meta.names)
59                 if ((r = hashmap_put(n->meta.manager->names, *t, n)) < 0)
60                         goto fail;
61
62         if (n->meta.state == NAME_STUB)
63                 LIST_PREPEND(Meta, n->meta.manager->load_queue, &n->meta);
64
65         n->meta.linked = true;
66
67         return 0;
68
69 fail:
70         t--;
71         STRV_FOREACH_BACKWARDS(t, n->meta.names)
72                 hashmap_remove(n->meta.manager->names, *t);
73
74         return r;
75 }
76
77 void name_free(Name *name) {
78
79         assert(name);
80
81         /* Detach from next 'bigger' objects */
82
83         if (name->meta.linked) {
84                 char **t;
85
86                 STRV_FOREACH(t, name->meta.names)
87                         hashmap_remove(name->meta.manager->names, *t);
88
89                 if (name->meta.job)
90                         job_free(name->meta.job);
91         }
92
93         /* Free data and next 'smaller' objects */
94
95         if (name->meta.job)
96                 job_free(name->meta.job);
97
98         /* FIXME: Other names pointing to us should probably drop their refs to us when we get destructed */
99         set_free(name->meta.requires);
100         set_free(name->meta.soft_requires);
101         set_free(name->meta.wants);
102         set_free(name->meta.requisite);
103         set_free(name->meta.soft_requires);
104         set_free(name->meta.conflicts);
105         set_free(name->meta.before);
106         set_free(name->meta.after);
107
108         switch (name->meta.type) {
109
110                 case NAME_SOCKET: {
111                         unsigned i;
112                         Socket *s = SOCKET(name);
113
114                         for (i = 0; i < s->n_fds; i++)
115                                 nointr_close(s->fds[i]);
116                         break;
117                 }
118
119                 case NAME_DEVICE: {
120                         Device *d = DEVICE(name);
121
122                         free(d->sysfs);
123                         break;
124                 }
125
126                 case NAME_MOUNT: {
127                         Mount *m = MOUNT(name);
128
129                         free(m->path);
130                         break;
131                 }
132
133                 case NAME_AUTOMOUNT: {
134                         Automount *a = AUTOMOUNT(name);
135
136                         free(a->path);
137                         break;
138                 }
139
140                 default:
141                         ;
142         }
143
144         free(name->meta.description);
145         strv_free(name->meta.names);
146
147         free(name);
148 }
149
150 bool name_is_ready(Name *name) {
151
152         assert(name);
153
154         if (name->meta.state != NAME_LOADED)
155                 return false;
156
157         assert(name->meta.type < _NAME_TYPE_MAX);
158
159         switch (name->meta.type) {
160                 case NAME_SERVICE: {
161                         Service *s = SERVICE(name);
162
163                         return
164                                 s->state == SERVICE_RUNNING ||
165                                 s->state == SERVICE_RELOAD_PRE ||
166                                 s->state == SERVICE_RELOAD ||
167                                 s->state == SERVICE_RELOAD_POST;
168                 }
169
170                 case NAME_TIMER: {
171                         Timer *t = TIMER(name);
172
173                         return
174                                 t->state == TIMER_WAITING ||
175                                 t->state == TIMER_RUNNING;
176                 }
177
178                 case NAME_SOCKET: {
179                         Socket *s = SOCKET(name);
180
181                         return
182                                 s->state == SOCKET_LISTENING ||
183                                 s->state == SOCKET_RUNNING;
184                 }
185
186                 case NAME_MILESTONE:
187                         return MILESTONE(name)->state == MILESTONE_ACTIVE;
188
189                 case NAME_DEVICE:
190                         return DEVICE(name)->state == DEVICE_AVAILABLE;
191
192                 case NAME_MOUNT:
193                         return MOUNT(name)->state == MOUNT_MOUNTED;
194
195                 case NAME_AUTOMOUNT: {
196                         Automount *a = AUTOMOUNT(name);
197
198                         return
199                                 a->state == AUTOMOUNT_WAITING ||
200                                 a->state == AUTOMOUNT_RUNNING;
201                 }
202
203                 case NAME_SNAPSHOT:
204                         return SNAPSHOT(name)->state == SNAPSHOT_ACTIVE;
205
206
207                 case _NAME_TYPE_MAX:
208                 case _NAME_TYPE_INVALID:
209                         ;
210         }
211
212         assert_not_reached("Unknown name type.");
213         return false;
214 }
215
216 static int ensure_in_set(Set **s, void *data) {
217         int r;
218
219         assert(s);
220         assert(data);
221
222         if (!*s)
223                 if (!(*s = set_new(trivial_hash_func, trivial_compare_func)))
224                         return -ENOMEM;
225
226         if ((r = set_put(*s, data) < 0))
227                 if (r != -EEXIST)
228                         return r;
229
230         return 0;
231 }
232
233 int name_augment(Name *n) {
234         int r;
235         void* state;
236         Name *other;
237
238         assert(n);
239
240         /* Adds in the missing links to make all dependencies both-ways */
241
242         SET_FOREACH(other, n->meta.before, state)
243                 if ((r = ensure_in_set(&other->meta.after, n) < 0))
244                         return r;
245         SET_FOREACH(other, n->meta.after, state)
246                 if ((r = ensure_in_set(&other->meta.before, n) < 0))
247                         return r;
248
249         SET_FOREACH(other, n->meta.conflicts, state)
250                 if ((r = ensure_in_set(&other->meta.conflicts, n) < 0))
251                         return r;
252
253         SET_FOREACH(other, n->meta.requires, state)
254                 if ((r = ensure_in_set(&other->meta.required_by, n) < 0))
255                         return r;
256         SET_FOREACH(other, n->meta.soft_requires, state)
257                 if ((r = ensure_in_set(&other->meta.required_by, n) < 0))
258                         return r;
259         SET_FOREACH(other, n->meta.requisite, state)
260                 if ((r = ensure_in_set(&other->meta.required_by, n) < 0))
261                         return r;
262         SET_FOREACH(other, n->meta.soft_requisite, state)
263                 if ((r = ensure_in_set(&other->meta.required_by, n) < 0))
264                         return r;
265
266         return r;
267 }