discover: Send options to client in order
[petitboot] / discover / parser.c
1
2 #include <fcntl.h>
3 #include <stdlib.h>
4 #include <sys/types.h>
5 #include <sys/stat.h>
6
7 #include "types/types.h"
8 #include <log/log.h>
9 #include <talloc/talloc.h>
10
11 #include "device-handler.h"
12 #include "parser.h"
13 #include "parser-utils.h"
14 #include "paths.h"
15
16 struct p_item {
17         struct list_item list;
18         struct parser *parser;
19 };
20
21 STATIC_LIST(parsers);
22
23 static const int max_file_size = 1024 * 1024;
24
25 static int read_file(struct discover_context *ctx,
26                 const char *filename, char **bufp, int *lenp)
27 {
28         struct stat statbuf;
29         int rc, fd, i, len;
30         char *buf;
31
32         fd = open(filename, O_RDONLY);
33         if (fd < 0)
34                 return -1;
35
36         rc = fstat(fd, &statbuf);
37         if (rc < 0)
38                 goto err_close;
39
40         len = statbuf.st_size;
41         if (len > max_file_size)
42                 goto err_close;
43
44         buf = talloc_array(ctx, char, len + 1);
45         if (!buf)
46                 goto err_close;
47
48         for (i = 0; i < len; i += rc) {
49                 rc = read(fd, buf + i, len - i);
50
51                 /* unexpected EOF: trim and return */
52                 if (rc == 0) {
53                         len = i;
54                         break;
55                 }
56
57                 if (rc < 0)
58                         goto err_free;
59
60         }
61
62         buf[len] = '\0';
63
64         close(fd);
65         *bufp = buf;
66         *lenp = len;
67         return 0;
68
69 err_free:
70         talloc_free(buf);
71 err_close:
72         close(fd);
73         return -1;
74 }
75
76 static char *local_path(struct discover_context *ctx,
77                 const char *filename)
78 {
79         return join_paths(ctx, ctx->device->mount_path, filename);
80 }
81
82 static int download_config(struct discover_context *ctx, char **buf, int *len)
83 {
84         unsigned tempfile;
85         const char *file;
86         int rc;
87
88         file = load_url(ctx, ctx->conf_url, &tempfile);
89         if (!file)
90                 return -1;
91
92         rc = read_file(ctx, file, buf, len);
93         if (rc)
94                 goto out_clean;
95
96         return 0;
97
98 out_clean:
99         if (tempfile)
100                 unlink(file);
101         return -1;
102 }
103
104 static void iterate_parser_files(struct discover_context *ctx,
105                 const struct parser *parser)
106 {
107         const char * const *filename;
108         const char *path;
109
110         if (!parser->filenames)
111                 return;
112
113         for (filename = parser->filenames; *filename; filename++) {
114                 int rc, len;
115                 char *buf;
116
117                 path = local_path(ctx, *filename);
118                 if (!path)
119                         continue;
120
121                 rc = read_file(ctx, path, &buf, &len);
122                 if (!rc) {
123                         pb_log("Running parser %s on file %s\n",
124                                         parser->name, *filename);
125                         parser->parse(ctx, buf, len);
126                         talloc_free(buf);
127                 }
128         }
129 }
130
131 void iterate_parsers(struct discover_context *ctx, enum conf_method method)
132 {
133         struct p_item* i;
134         int rc, len;
135         char *buf;
136
137         pb_log("trying parsers for %s\n", ctx->device->device->id);
138
139         switch (method) {
140         case CONF_METHOD_LOCAL_FILE:
141                 list_for_each_entry(&parsers, i, list) {
142                         if (i->parser->method != CONF_METHOD_LOCAL_FILE)
143                                 continue;
144
145                         pb_log("\ttrying parser '%s'\n", i->parser->name);
146                         ctx->parser = i->parser;
147                         iterate_parser_files(ctx, ctx->parser);
148                 }
149                 ctx->parser = NULL;
150                 break;
151
152         case CONF_METHOD_DHCP:
153                 rc = download_config(ctx, &buf, &len);
154                 if (rc) {
155                         pb_log("\tdownload failed, aborting\n");
156                         return;
157                 }
158
159                 list_for_each_entry(&parsers, i, list) {
160                         if (i->parser->method != method)
161                                 continue;
162
163                         pb_log("\ttrying parser '%s'\n", i->parser->name);
164                         ctx->parser = i->parser;
165                         i->parser->parse(ctx, buf, len);
166                 }
167
168                 break;
169
170         case CONF_METHOD_UNKNOWN:
171                 break;
172
173         }
174 }
175
176 void __register_parser(struct parser *parser)
177 {
178         struct p_item* i = talloc(NULL, struct p_item);
179
180         i->parser = parser;
181         list_add(&parsers, &i->list);
182 }
183
184 void parser_init(void)
185 {
186 }