configure: Use AC_GNU_SOURCE
[petitboot] / discover / pxe-parser.c
1
2 #if defined(HAVE_CONFIG_H)
3 #include "config.h"
4 #endif
5 #include <string.h>
6
7 #include <talloc/talloc.h>
8 #include <url/url.h>
9
10 #include "parser.h"
11 #include "parser-conf.h"
12 #include "parser-utils.h"
13 #include "resource.h"
14 #include "paths.h"
15 #include "user-event.h"
16
17 struct pxe_parser_info {
18         struct discover_boot_option *opt;
19         const char *default_name;
20 };
21
22 static void pxe_finish(struct conf_context *conf)
23 {
24         struct pxe_parser_info *info = conf->parser_info;
25         if (info->opt)
26                 discover_context_add_boot_option(conf->dc, info->opt);
27 }
28
29 static void pxe_process_pair(struct conf_context *ctx,
30                 const char *name, char *value)
31 {
32         struct pxe_parser_info *parser_info = ctx->parser_info;
33         struct discover_boot_option *opt = parser_info->opt;
34         struct pb_url *url;
35
36         /* quirk in the syslinux config format: initrd can be separated
37          * by an '=' */
38         if (!name && !strncasecmp(value, "initrd=", strlen("initrd="))) {
39                 name = "initrd";
40                 value += strlen("initrd=");
41         }
42
43         if (!name)
44                 return;
45
46         if (streq(name, "DEFAULT")) {
47                 parser_info->default_name = talloc_strdup(parser_info, value);
48                 return;
49         }
50
51         if (streq(name, "LABEL")) {
52                 if (opt)
53                         pxe_finish(ctx);
54
55                 opt = discover_boot_option_create(ctx->dc, ctx->dc->device);
56
57                 opt->option->name = talloc_strdup(opt, value);
58                 opt->option->id = talloc_asprintf(opt, "%s@%p",
59                                 ctx->dc->device->device->id, opt);
60
61                 opt->option->is_default = parser_info->default_name &&
62                                         streq(parser_info->default_name, value);
63
64                 parser_info->opt = opt;
65                 return;
66         }
67
68         /* all other parameters need an option */
69         if (!opt)
70                 return;
71
72         if (streq(name, "KERNEL")) {
73                 url = pb_url_join(ctx->dc, ctx->dc->conf_url, value);
74                 opt->boot_image = create_url_resource(opt, url);
75
76         } else if (streq(name, "INITRD")) {
77                 url = pb_url_join(ctx->dc, ctx->dc->conf_url, value);
78                 opt->initrd = create_url_resource(opt, url);
79
80         } else if (streq(name, "APPEND")) {
81                 char *str, *end;
82
83                 opt->option->boot_args = talloc_strdup(opt->option, value);
84
85                 str = strcasestr(value, "INITRD=");
86                 if (str) {
87                         str += strlen("INITRD=");
88                         end = strchrnul(str, ' ');
89                         *end = '\0';
90
91                         url = pb_url_join(ctx->dc, ctx->dc->conf_url, str);
92                         opt->initrd = create_url_resource(opt, url);
93                 }
94         }
95
96 }
97
98 static int pxe_parse(struct discover_context *dc)
99 {
100         struct pxe_parser_info *parser_info;
101         char **pxe_conf_files, **filename;
102         struct pb_url *conf_url, *url;
103         struct conf_context *conf;
104         int len, rc;
105         char *buf;
106
107         /* Expects dhcp event parameters to support network boot */
108         if (!dc->event)
109                 return -1;
110
111         conf = talloc_zero(dc, struct conf_context);
112
113         if (!conf)
114                 goto out;
115
116         conf->dc = dc;
117         conf->get_pair = conf_get_pair_space;
118         conf->process_pair = pxe_process_pair;
119         conf->finish = pxe_finish;
120
121         parser_info = talloc_zero(conf, struct pxe_parser_info);
122         conf->parser_info = parser_info;
123
124         conf_url = user_event_parse_conf_url(dc, dc->event);
125         if (!conf_url)
126                 goto out_conf;
127
128         if (dc->conf_url) {
129                 rc = parser_request_url(dc, dc->conf_url, &buf, &len);
130                 if (rc)
131                         goto out_conf;
132         } else {
133                 pxe_conf_files = user_event_parse_conf_filenames(dc, dc->event);
134                 if (!pxe_conf_files)
135                         goto out_conf;
136
137                 rc = -1;
138
139                 for (filename = pxe_conf_files; *filename; filename++) {
140                         url = pb_url_join(dc, conf_url, *filename);
141                         if (!url)
142                                 goto out_pxe_conf;
143
144                         rc = parser_request_url(dc, url, &buf, &len);
145                         if (!rc) /* found one, just break */
146                                 break;
147
148                         talloc_free(url);
149                 }
150
151                 /* No configuration file found on the boot server */
152                 if (rc)
153                         goto out_pxe_conf;
154
155                 dc->conf_url = url;
156
157                 talloc_free(conf_url);
158                 talloc_free(pxe_conf_files);
159         }
160
161         /* Call the config file parser with the data read from the file */
162         conf_parse_buf(conf, buf, len);
163
164         talloc_free(buf);
165         talloc_free(conf);
166
167         return 0;
168
169 out_pxe_conf:
170         talloc_free(pxe_conf_files);
171 out_conf:
172         talloc_free(conf);
173 out:
174         return -1;
175 }
176
177 static struct parser pxe_parser = {
178         .name                   = "pxe",
179         .parse                  = pxe_parse,
180 };
181
182 register_parser(pxe_parser);