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