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