]> git.ozlabs.org Git - petitboot/blob - lib/pb-config/storage-powerpc-nvram.c
96d279c4041dc65d7a950e883d3342575de16bb2
[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) {
82                 unsigned int namelen;
83                 struct param *param;
84
85                 paramlen = strlen(pos);
86
87                 name = pos;
88                 value = strchr(pos, '=');
89                 if (!value)
90                         continue;
91
92                 namelen = name - value;
93
94                 if (!param_is_known(name, namelen))
95                         continue;
96
97                 value++;
98
99                 param = talloc(nv, struct param);
100                 param->modified = false;
101                 param->name = talloc_strndup(nv, name, namelen);
102                 param->value = talloc_strdup(nv, value);
103                 list_add(&nv->params, &param->list);
104         }
105
106         return 0;
107 }
108
109 static int parse_nvram(struct powerpc_nvram_storage *nv)
110 {
111         int rc, len, buf_len;
112         int pipefds[2], status;
113         char *buf;
114         pid_t pid;
115
116         rc = pipe(pipefds);
117         if (rc) {
118                 perror("pipe");
119                 return -1;
120         }
121
122         pid = fork();
123
124         if (pid < 0) {
125                 perror("fork");
126                 return -1;
127         }
128
129         if (pid == 0) {
130                 close(STDIN_FILENO);
131                 close(pipefds[0]);
132                 dup2(pipefds[1], STDOUT_FILENO);
133                 execlp("nvram", "nvram", "--print-config",
134                                 "--partition", partition, NULL);
135                 exit(EXIT_FAILURE);
136         }
137
138         close(pipefds[1]);
139
140         len = 0;
141         buf_len = max_partition_size;
142         buf = talloc_array(nv, char, buf_len);
143
144         for (;;) {
145                 rc = read(pipefds[0], buf + len, buf_len - len);
146
147                 if (rc < 0) {
148                         perror("read");
149                         break;
150                 }
151
152                 if (rc == 0)
153                         break;
154
155                 len += rc;
156         }
157
158         waitpid(pid, &status, 0);
159         if (!WIFEXITED(status) || WEXITSTATUS(status)) {
160                 fprintf(stderr, "nvram process returned "
161                                 "non-zero exit status\n");
162                 return -1;
163         }
164
165         if (rc < 0)
166                 return rc;
167
168         return parse_nvram_params(nv, buf, len);
169 }
170
171 static const char *get_param(struct powerpc_nvram_storage *nv,
172                 const char *name)
173 {
174         struct param *param;
175
176         list_for_each_entry(&nv->params, param, list)
177                 if (!strcmp(param->name, name))
178                         return param->value;
179         return NULL;
180 }
181
182 static int parse_hwaddr(struct network_config *config, char *str)
183 {
184         int i;
185
186         if (strlen(str) != strlen("00:00:00:00:00:00"))
187                 return -1;
188
189         for (i = 0; i < HWADDR_SIZE; i++) {
190                 char byte[3], *endp;
191                 unsigned long x;
192
193                 byte[0] = str[i * 3 + 0];
194                 byte[1] = str[i * 3 + 1];
195                 byte[2] = '\0';
196
197                 x = strtoul(byte, &endp, 16);
198                 if (endp != byte + 2)
199                         return -1;
200
201                 config->hwaddr[i] = x & 0xff;
202         }
203
204         return 0;
205 }
206
207 static int parse_one_network_config(struct network_config *config,
208                 char *confstr)
209 {
210         char *tok, *saveptr;
211
212         if (!confstr || !strlen(confstr))
213                 return -1;
214
215         /* first token should be the mac address */
216         tok = strtok_r(confstr, ",", &saveptr);
217         if (!tok)
218                 return -1;
219
220         if (parse_hwaddr(config, tok))
221                 return -1;
222
223         /* second token is the method */
224         tok = strtok_r(NULL, ",", &saveptr);
225         if (!tok || !strlen(tok) || !strcmp(tok, "ignore")) {
226                 config->ignore = true;
227                 return 0;
228         }
229
230         if (!strcmp(tok, "dhcp")) {
231                 config->method = CONFIG_METHOD_DHCP;
232
233         } else if (!strcmp(tok, "static")) {
234                 config->method = CONFIG_METHOD_STATIC;
235
236                 /* ip/mask, [optional] gateway, [optional] dns */
237                 tok = strtok_r(NULL, ",", &saveptr);
238                 if (!tok)
239                         return -1;
240                 config->static_config.address =
241                         talloc_strdup(config, tok);
242
243                 tok = strtok_r(NULL, ",", &saveptr);
244                 if (tok) {
245                         config->static_config.gateway =
246                                 talloc_strdup(config, tok);
247                         tok = strtok_r(NULL, ",", &saveptr);
248                 }
249
250                 if (tok) {
251                         config->static_config.dns =
252                                 talloc_strdup(config, tok);
253                 }
254         } else {
255                 pb_log("Unknown network configuration method %s\n", tok);
256                 return -1;
257         }
258
259         return 0;
260 }
261
262 static void populate_network_config(struct powerpc_nvram_storage *nv,
263                 struct config *config)
264 {
265         const char *cval;
266         char *val;
267         int i;
268
269         cval = get_param(nv, "petitboot,network");
270         if (!cval || !strlen(cval))
271                 return;
272
273         val = talloc_strdup(config, cval);
274
275         for (i = 0; ; i++) {
276                 struct network_config *netconf;
277                 char *tok, *saveptr;
278                 int rc;
279
280                 tok = strtok_r(i == 0 ? val : NULL, " ", &saveptr);
281                 if (!tok)
282                         break;
283
284                 netconf = talloc(nv, struct network_config);
285
286                 rc = parse_one_network_config(netconf, tok);
287                 if (rc) {
288                         talloc_free(netconf);
289                         continue;
290                 }
291
292                 config->network_configs = talloc_realloc(nv,
293                                                 config->network_configs,
294                                                 struct network_config *,
295                                                 ++config->n_network_configs);
296
297                 config->network_configs[config->n_network_configs - 1] =
298                                                 netconf;
299         }
300
301         talloc_free(val);
302 }
303
304 static void populate_config(struct powerpc_nvram_storage *nv,
305                 struct config *config)
306 {
307         const char *val;
308
309         /* if the "auto-boot?' property is present and "false", disable auto
310          * boot */
311         val = get_param(nv, "auto-boot?");
312         config->autoboot_enabled = !val || strcmp(val, "false");
313
314         populate_network_config(nv, config);
315 }
316
317 static int load(struct config_storage *st, struct config *config)
318 {
319         struct powerpc_nvram_storage *nv = to_powerpc_nvram_storage(st);
320         int rc;
321
322         rc = parse_nvram(nv);
323         if (rc)
324                 return rc;
325
326         populate_config(nv, config);
327
328         return 0;
329 }
330
331 struct config_storage *create_powerpc_nvram_storage(void *ctx)
332 {
333         struct powerpc_nvram_storage *nv;
334
335         nv = talloc(ctx, struct powerpc_nvram_storage);
336         nv->storage.load = load;
337         list_init(&nv->params);
338
339         return &nv->storage;
340 }