discover/network: Send DHCP client architecture type
[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         bool complete_url;
105         int len, rc;
106         char *buf;
107
108         /* Expects dhcp event parameters to support network boot */
109         if (!dc->event)
110                 return -1;
111
112         conf = talloc_zero(dc, struct conf_context);
113
114         if (!conf)
115                 goto out;
116
117         conf->dc = dc;
118         conf->get_pair = conf_get_pair_space;
119         conf->process_pair = pxe_process_pair;
120         conf->finish = pxe_finish;
121
122         parser_info = talloc_zero(conf, struct pxe_parser_info);
123         conf->parser_info = parser_info;
124
125         conf_url = user_event_parse_conf_url(dc, dc->event, &complete_url);
126         if (!conf_url)
127                 goto out_conf;
128
129         if (complete_url) {
130                 /* we have a complete URL; use this and we're done. */
131                 dc->conf_url = conf_url;
132                 rc = parser_request_url(dc, dc->conf_url, &buf, &len);
133                 if (rc)
134                         goto out_conf;
135         } else {
136                 pxe_conf_files = user_event_parse_conf_filenames(dc, dc->event);
137                 if (!pxe_conf_files)
138                         goto out_conf;
139
140                 rc = -1;
141
142                 for (filename = pxe_conf_files; *filename; filename++) {
143                         url = pb_url_join(dc, conf_url, *filename);
144                         if (!url)
145                                 goto out_pxe_conf;
146
147                         rc = parser_request_url(dc, url, &buf, &len);
148                         if (!rc) /* found one, just break */
149                                 break;
150
151                         talloc_free(url);
152                 }
153
154                 /* No configuration file found on the boot server */
155                 if (rc)
156                         goto out_pxe_conf;
157
158                 dc->conf_url = url;
159
160                 talloc_free(conf_url);
161                 talloc_free(pxe_conf_files);
162         }
163
164         /* Call the config file parser with the data read from the file */
165         conf_parse_buf(conf, buf, len);
166
167         talloc_free(buf);
168         talloc_free(conf);
169
170         return 0;
171
172 out_pxe_conf:
173         talloc_free(pxe_conf_files);
174 out_conf:
175         talloc_free(conf);
176 out:
177         return -1;
178 }
179
180 static struct parser pxe_parser = {
181         .name                   = "pxe",
182         .parse                  = pxe_parse,
183 };
184
185 register_parser(pxe_parser);