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