lib/process: replace pb_run_cmd_pipe
[petitboot] / lib / pb-config / storage-powerpc-nvram.c
1
2 #include <string.h>
3 #include <stdlib.h>
4 #include <sys/types.h>
5 #include <sys/wait.h>
6
7 #include <talloc/talloc.h>
8 #include <list/list.h>
9 #include <log/log.h>
10 #include <process/process.h>
11
12 #include "pb-config.h"
13 #include "storage.h"
14
15 static const char *partition = "common";
16
17 struct param {
18         char                    *name;
19         char                    *value;
20         bool                    modified;
21         struct list_item        list;
22 };
23
24 struct powerpc_nvram_storage {
25         struct config_storage   storage;
26         struct list             params;
27 };
28
29 static const char *known_params[] = {
30         "auto-boot?",
31         "petitboot,network",
32         NULL,
33 };
34
35 #define to_powerpc_nvram_storage(s) \
36         container_of(s, struct powerpc_nvram_storage, storage)
37
38 /* a partition max a max size of 64k * 16bytes = 1M */
39 static const int max_partition_size = 64 * 1024 * 16;
40
41 static bool param_is_known(const char *param, unsigned int len)
42 {
43         const char *known_param;
44         unsigned int i;
45
46         for (i = 0; known_params[i]; i++) {
47                 known_param = known_params[i];
48                 if (len == strlen(known_param) &&
49                                 !strncmp(param, known_param, len))
50                         return true;
51         }
52
53         return false;
54 }
55
56 static int parse_nvram_params(struct powerpc_nvram_storage *nv,
57                 char *buf, int len)
58 {
59         char *pos, *name, *value;
60         unsigned int paramlen;
61         int i, count;
62
63         /* discard 2 header lines:
64          * "common" partiton"
65          * ------------------
66          */
67         pos = buf;
68         count = 0;
69
70         for (i = 0; i < len; i++) {
71                 if (pos[i] == '\n')
72                         count++;
73                 if (count == 2)
74                         break;
75         }
76
77         if (i == len) {
78                 fprintf(stderr, "failure parsing nvram output\n");
79                 return -1;
80         }
81
82         for (pos = buf + i; pos < buf + len; pos += paramlen + 1) {
83                 unsigned int namelen;
84                 struct param *param;
85                 char *newline;
86
87                 newline = strchr(pos, '\n');
88                 if (!newline)
89                         break;
90
91                 *newline = '\0';
92
93                 paramlen = strlen(pos);
94
95                 name = pos;
96                 value = strchr(pos, '=');
97                 if (!value)
98                         continue;
99
100                 namelen = value - name;
101                 if (namelen == 0)
102                         continue;
103
104                 if (!param_is_known(name, namelen))
105                         continue;
106
107                 value++;
108
109                 param = talloc(nv, struct param);
110                 param->modified = false;
111                 param->name = talloc_strndup(nv, name, namelen);
112                 param->value = talloc_strdup(nv, value);
113                 list_add(&nv->params, &param->list);
114         }
115
116         return 0;
117 }
118
119 static int parse_nvram(struct powerpc_nvram_storage *nv)
120 {
121         struct process *process;
122         const char *argv[5];
123         int rc;
124
125         argv[0] = "nvram";
126         argv[1] = "--print-config";
127         argv[2] = "--partition";
128         argv[3] = partition;
129         argv[4] = NULL;
130
131         process = process_create(nv);
132         process->path = "nvram";
133         process->argv = argv;
134         process->keep_stdout = true;
135
136         rc = process_run_sync(process);
137
138         if (rc || !WIFEXITED(process->exit_status)
139                         || WEXITSTATUS(process->exit_status)) {
140                 fprintf(stderr, "nvram process returned "
141                                 "non-zero exit status\n");
142                 rc = -1;
143         } else {
144                 rc = parse_nvram_params(nv, process->stdout_buf,
145                                             process->stdout_len);
146         }
147
148         process_release(process);
149         return rc;
150 }
151
152 static const char *get_param(struct powerpc_nvram_storage *nv,
153                 const char *name)
154 {
155         struct param *param;
156
157         list_for_each_entry(&nv->params, param, list)
158                 if (!strcmp(param->name, name))
159                         return param->value;
160         return NULL;
161 }
162
163 static int parse_hwaddr(struct interface_config *ifconf, char *str)
164 {
165         int i;
166
167         if (strlen(str) != strlen("00:00:00:00:00:00"))
168                 return -1;
169
170         for (i = 0; i < HWADDR_SIZE; i++) {
171                 char byte[3], *endp;
172                 unsigned long x;
173
174                 byte[0] = str[i * 3 + 0];
175                 byte[1] = str[i * 3 + 1];
176                 byte[2] = '\0';
177
178                 x = strtoul(byte, &endp, 16);
179                 if (endp != byte + 2)
180                         return -1;
181
182                 ifconf->hwaddr[i] = x & 0xff;
183         }
184
185         return 0;
186 }
187
188 static int parse_one_interface_config(struct config *config,
189                 char *confstr)
190 {
191         struct interface_config *ifconf;
192         char *tok, *saveptr;
193
194         ifconf = talloc(config, struct interface_config);
195
196         if (!confstr || !strlen(confstr))
197                 goto out_err;
198
199         /* first token should be the mac address */
200         tok = strtok_r(confstr, ",", &saveptr);
201         if (!tok)
202                 goto out_err;
203
204         if (parse_hwaddr(ifconf, tok))
205                 goto out_err;
206
207         /* second token is the method */
208         tok = strtok_r(NULL, ",", &saveptr);
209         if (!tok || !strlen(tok) || !strcmp(tok, "ignore")) {
210                 ifconf->ignore = true;
211
212         } else if (!strcmp(tok, "dhcp")) {
213                 ifconf->method = CONFIG_METHOD_DHCP;
214
215         } else if (!strcmp(tok, "static")) {
216                 ifconf->method = CONFIG_METHOD_STATIC;
217
218                 /* ip/mask, [optional] gateway */
219                 tok = strtok_r(NULL, ",", &saveptr);
220                 if (!tok)
221                         goto out_err;
222                 ifconf->static_config.address =
223                         talloc_strdup(ifconf, tok);
224
225                 tok = strtok_r(NULL, ",", &saveptr);
226                 if (tok) {
227                         ifconf->static_config.gateway =
228                                 talloc_strdup(ifconf, tok);
229                 }
230
231         } else {
232                 pb_log("Unknown network configuration method %s\n", tok);
233                 goto out_err;
234         }
235
236         config->network.interfaces = talloc_realloc(config,
237                         config->network.interfaces,
238                         struct interface_config *,
239                         ++config->network.n_interfaces);
240
241         config->network.interfaces[config->network.n_interfaces - 1] = ifconf;
242
243         return 0;
244 out_err:
245         talloc_free(ifconf);
246         return -1;
247 }
248
249 static int parse_one_dns_config(struct config *config,
250                 char *confstr)
251 {
252         char *tok, *saveptr;
253
254         for (tok = strtok_r(confstr, ",", &saveptr); tok;
255                         tok = strtok_r(NULL, ",", &saveptr)) {
256
257                 char *server = talloc_strdup(config, tok);
258
259                 config->network.dns_servers = talloc_realloc(config,
260                                 config->network.dns_servers, const char *,
261                                 ++config->network.n_dns_servers);
262
263                 config->network.dns_servers[config->network.n_dns_servers - 1]
264                                 = server;
265         }
266
267         return 0;
268 }
269
270 static void populate_network_config(struct powerpc_nvram_storage *nv,
271                 struct config *config)
272 {
273         const char *cval;
274         char *val;
275         int i;
276
277         cval = get_param(nv, "petitboot,network");
278         if (!cval || !strlen(cval))
279                 return;
280
281         val = talloc_strdup(config, cval);
282
283         for (i = 0; ; i++) {
284                 char *tok, *saveptr;
285
286                 tok = strtok_r(i == 0 ? val : NULL, " ", &saveptr);
287                 if (!tok)
288                         break;
289
290                 if (!strncasecmp(tok, "dns,", strlen("dns,")))
291                         parse_one_dns_config(config, tok + strlen("dns,"));
292                 else
293                         parse_one_interface_config(config, tok);
294
295         }
296
297         talloc_free(val);
298 }
299
300 static void populate_config(struct powerpc_nvram_storage *nv,
301                 struct config *config)
302 {
303         const char *val;
304
305         /* if the "auto-boot?' property is present and "false", disable auto
306          * boot */
307         val = get_param(nv, "auto-boot?");
308         config->autoboot_enabled = !val || strcmp(val, "false");
309
310         populate_network_config(nv, config);
311 }
312
313 static int load(struct config_storage *st, struct config *config)
314 {
315         struct powerpc_nvram_storage *nv = to_powerpc_nvram_storage(st);
316         int rc;
317
318         rc = parse_nvram(nv);
319         if (rc)
320                 return rc;
321
322         populate_config(nv, config);
323
324         return 0;
325 }
326
327 struct config_storage *create_powerpc_nvram_storage(void *ctx)
328 {
329         struct powerpc_nvram_storage *nv;
330
331         nv = talloc(ctx, struct powerpc_nvram_storage);
332         nv->storage.load = load;
333         list_init(&nv->params);
334
335         return &nv->storage;
336 }