chiark / gitweb /
rework socket handling
[elogind.git] / load-fragment.c
1 /*-*- Mode: C; c-basic-offset: 8 -*-*/
2
3 #include <assert.h>
4 #include <errno.h>
5 #include <string.h>
6
7 #include "name.h"
8 #include "strv.h"
9 #include "conf-parser.h"
10 #include "load-fragment.h"
11 #include "log.h"
12
13 static int config_parse_deps(
14                 const char *filename,
15                 unsigned line,
16                 const char *section,
17                 const char *lvalue,
18                 const char *rvalue,
19                 void *data,
20                 void *userdata) {
21
22         Set **set = data;
23         Name *name = userdata;
24         char *w;
25         size_t l;
26         char *state;
27
28         assert(filename);
29         assert(lvalue);
30         assert(rvalue);
31         assert(data);
32
33         FOREACH_WORD(w, &l, rvalue, state) {
34                 char *t;
35                 int r;
36                 Name *other;
37
38                 if (!(t = strndup(w, l)))
39                         return -ENOMEM;
40
41                 r = manager_load_name(name->meta.manager, t, &other);
42                 free(t);
43
44                 if (r < 0)
45                         return r;
46
47                 if (!*set)
48                         if (!(*set = set_new(trivial_hash_func, trivial_compare_func)))
49                                 return -ENOMEM;
50
51                 if ((r = set_put(*set, other)) < 0)
52                         return r;
53         }
54
55         return 0;
56 }
57
58 static int config_parse_names(
59                 const char *filename,
60                 unsigned line,
61                 const char *section,
62                 const char *lvalue,
63                 const char *rvalue,
64                 void *data,
65                 void *userdata) {
66
67         Set **set = data;
68         Name *name = userdata;
69         char *w;
70         size_t l;
71         char *state;
72
73         assert(filename);
74         assert(lvalue);
75         assert(rvalue);
76         assert(data);
77
78         FOREACH_WORD(w, &l, rvalue, state) {
79                 char *t;
80                 int r;
81                 Name *other;
82
83                 if (!(t = strndup(w, l)))
84                         return -ENOMEM;
85
86                 other = manager_get_name(name->meta.manager, t);
87
88                 if (other) {
89
90                         if (other != name) {
91
92                                 if (other->meta.load_state != NAME_STUB) {
93                                         free(t);
94                                         return -EEXIST;
95                                 }
96
97                                 if ((r = name_merge(name, other)) < 0) {
98                                         free(t);
99                                         return r;
100                                 }
101                         }
102
103                 } else {
104
105                         if (!*set)
106                                 if (!(*set = set_new(trivial_hash_func, trivial_compare_func))) {
107                                         free(t);
108                                         return -ENOMEM;
109                                 }
110
111                         if ((r = set_put(*set, t)) < 0) {
112                                 free(t);
113                                 return r;
114                         }
115
116                         t = NULL;
117                 }
118
119                 free(t);
120         }
121
122         return 0;
123 }
124
125 static int config_parse_listen(
126                 const char *filename,
127                 unsigned line,
128                 const char *section,
129                 const char *lvalue,
130                 const char *rvalue,
131                 void *data,
132                 void *userdata) {
133
134         int r;
135         SocketPort *p;
136         Socket *s;
137
138         assert(filename);
139         assert(lvalue);
140         assert(rvalue);
141         assert(data);
142
143         s = (Socket*) data;
144
145         if (!(p = new0(SocketPort, 1)))
146                 return -ENOMEM;
147
148         if (streq(lvalue, "ListenFIFO")) {
149                 p->type = SOCKET_FIFO;
150
151                 if (!(p->path = strdup(rvalue))) {
152                         free(p);
153                         return -ENOMEM;
154                 }
155         } else {
156                 p->type = SOCKET_SOCKET;
157
158                 if ((r = socket_address_parse(&p->address, rvalue)) < 0) {
159                         log_error("[%s:%u] Failed to parse address value: %s", filename, line, rvalue);
160                         free(p);
161                         return r;
162                 }
163
164                 if (streq(lvalue, "ListenStream"))
165                         p->address.type = SOCK_STREAM;
166                 else if (streq(lvalue, "ListenDatagram"))
167                         p->address.type = SOCK_DGRAM;
168                 else {
169                         assert(streq(lvalue, "ListenSequentialPacket"));
170                         p->address.type = SOCK_SEQPACKET;
171                 }
172
173                 if (socket_address_family(&p->address) != AF_LOCAL && p->address.type == SOCK_SEQPACKET) {
174                         free(p);
175                         return -EPROTONOSUPPORT;
176                 }
177         }
178
179         p->fd = -1;
180         LIST_PREPEND(SocketPort, s->ports, p);
181
182         return 0;
183 }
184
185 static int config_parse_bind(
186                 const char *filename,
187                 unsigned line,
188                 const char *section,
189                 const char *lvalue,
190                 const char *rvalue,
191                 void *data,
192                 void *userdata) {
193
194         int r;
195         Socket *s;
196
197         assert(filename);
198         assert(lvalue);
199         assert(rvalue);
200         assert(data);
201
202         s = (Socket*) data;
203
204         if ((r = parse_boolean(rvalue)) < 0) {
205                 log_error("[%s:%u] Failed to parse bind IPv6 only value: %s", filename, line, rvalue);
206                 return r;
207         }
208
209         s->bind_ipv6_only = r ? SOCKET_ADDRESS_IPV6_ONLY : SOCKET_ADDRESS_BOTH;
210
211         return 0;
212 }
213
214 int name_load_fragment(Name *n) {
215
216         static const char* const section_table[_NAME_TYPE_MAX] = {
217                 [NAME_SERVICE]   = "Service",
218                 [NAME_TIMER]     = "Timer",
219                 [NAME_SOCKET]    = "Socket",
220                 [NAME_MILESTONE] = "Milestone",
221                 [NAME_DEVICE]    = "Device",
222                 [NAME_MOUNT]     = "Mount",
223                 [NAME_AUTOMOUNT] = "Automount",
224                 [NAME_SNAPSHOT]  = "Snapshot"
225         };
226
227         const ConfigItem items[] = {
228                 { "Names",                  config_parse_names,    &n->meta.names,                           "Meta"   },
229                 { "Description",            config_parse_string,   &n->meta.description,                     "Meta"   },
230                 { "Requires",               config_parse_deps,     n->meta.dependencies+NAME_REQUIRES,       "Meta"   },
231                 { "SoftRequires",           config_parse_deps,     n->meta.dependencies+NAME_SOFT_REQUIRES,  "Meta"   },
232                 { "Wants",                  config_parse_deps,     n->meta.dependencies+NAME_WANTS,          "Meta"   },
233                 { "Requisite",              config_parse_deps,     n->meta.dependencies+NAME_REQUISITE,      "Meta"   },
234                 { "SoftRequisite",          config_parse_deps,     n->meta.dependencies+NAME_SOFT_REQUISITE, "Meta"   },
235                 { "Conflicts",              config_parse_deps,     n->meta.dependencies+NAME_CONFLICTS,      "Meta"   },
236                 { "Before",                 config_parse_deps,     n->meta.dependencies+NAME_BEFORE,         "Meta"   },
237                 { "After",                  config_parse_deps,     n->meta.dependencies+NAME_AFTER,          "Meta"   },
238                 { "ListenStream",           config_parse_listen,   &n->socket,                               "Socket" },
239                 { "ListenDatagram",         config_parse_listen,   &n->socket,                               "Socket" },
240                 { "ListenSequentialPacket", config_parse_listen,   &n->socket,                               "Socket" },
241                 { "ListenFIFO",             config_parse_listen,   &n->socket,                               "Socket" },
242                 { "BindIPv6Only",           config_parse_bind,     &n->socket,                               "Socket" },
243                 { "Backlog",                config_parse_unsigned, &n->socket.backlog,                       "Socket" },
244                 { NULL, NULL, NULL, NULL }
245         };
246
247         const
248
249         char *t;
250         int r;
251         void *state;
252         const char *sections[3];
253
254         assert(n);
255         assert(n->meta.load_state == NAME_STUB);
256
257         sections[0] = "Meta";
258         sections[1] = section_table[n->meta.type];
259         sections[2] = NULL;
260
261         SET_FOREACH(t, n->meta.names, state)
262                 if ((r = config_parse(t, sections, items, n)) < 0)
263                         goto fail;
264
265         r = 0;
266
267 fail:
268         return r;
269 }