Fix random bytes in string in kboot parser
[petitboot] / devices / yaboot-parser.c
1
2 #include "parser.h"
3 #include "params.h"
4 #include "yaboot-cfg.h"
5
6 #include <stdlib.h>
7 #include <stdio.h>
8 #include <string.h>
9 #include <sys/types.h>
10 #include <sys/stat.h>
11 #include <unistd.h>
12 #include <fcntl.h>
13 #include <ctype.h>
14 #include <sys/param.h>
15
16 static struct device *dev;
17 static const char *mountpoint;
18 static char partition_mntpoint[PATH_MAX];
19 static char *defimage;
20
21 char *
22 make_params(char *label, char *params)
23 {
24      char *p, *q;
25      static char buffer[2048];
26
27      q = buffer;
28      *q = 0;
29
30      p = cfg_get_strg(label, "literal");
31      if (p) {
32           strcpy(q, p);
33           q = strchr(q, 0);
34           if (params) {
35                if (*p)
36                     *q++ = ' ';
37                strcpy(q, params);
38           }
39           return buffer;
40      }
41
42      p = cfg_get_strg(label, "root");
43      if (p) {
44           strcpy (q, "root=");
45           strcpy (q + 5, p);
46           q = strchr (q, 0);
47           *q++ = ' ';
48      }
49      if (cfg_get_flag(label, "read-only")) {
50           strcpy (q, "ro ");
51           q += 3;
52      }
53      if (cfg_get_flag(label, "read-write")) {
54           strcpy (q, "rw ");
55           q += 3;
56      }
57      p = cfg_get_strg(label, "ramdisk");
58      if (p) {
59           strcpy (q, "ramdisk=");
60           strcpy (q + 8, p);
61           q = strchr (q, 0);
62           *q++ = ' ';
63      }
64      p = cfg_get_strg(label, "initrd-size");
65      if (p) {
66           strcpy (q, "ramdisk_size=");
67           strcpy (q + 13, p);
68           q = strchr (q, 0);
69           *q++ = ' ';
70      }
71      if (cfg_get_flag(label, "novideo")) {
72           strcpy (q, "video=ofonly");
73           q = strchr (q, 0);
74           *q++ = ' ';
75      }
76      p = cfg_get_strg (label, "append");
77      if (p) {
78           strcpy (q, p);
79           q = strchr (q, 0);
80           *q++ = ' ';
81      }
82      *q = 0;
83      if (params)
84           strcpy(q, params);
85
86      return buffer;
87 }
88
89 static int check_and_add_device(struct device *dev)
90 {
91         if (!dev->icon_file)
92                 dev->icon_file = strdup(generic_icon_file(guess_device_type()));
93
94         return !add_device(dev);
95 }
96
97 void process_image(char *label)
98 {
99         struct boot_option opt;
100         char *cfgopt;
101
102         memset(&opt, 0, sizeof(opt));
103
104         opt.name = label;
105         cfgopt = cfg_get_strg(label, "image");
106         opt.boot_image_file = join_paths(mountpoint, cfgopt);
107         if (cfgopt == defimage)
108                 pb_log("This one is default. What do we do about it?\n");
109
110         cfgopt = cfg_get_strg(label, "initrd");
111         if (cfgopt)
112                 opt.initrd_file = join_paths(mountpoint, cfgopt);
113
114         opt.boot_args = make_params(label, NULL);
115
116         add_boot_option(&opt);
117
118         if (opt.initrd_file)
119                 free(opt.initrd_file);
120 }
121
122 static int yaboot_parse(const char *devicepath, const char *_mountpoint)
123 {
124         char *filepath;
125         char *conf_file;
126         char *tmpstr;
127         ssize_t conf_len;
128         int fd;
129         struct stat st;
130         char *label;
131
132         mountpoint = _mountpoint;
133
134         filepath = join_paths(mountpoint, "/etc/yaboot.conf");
135
136         fd = open(filepath, O_RDONLY);
137         if (fd < 0) {
138                 free(filepath);
139                 filepath = join_paths(mountpoint, "/yaboot.conf");
140                 fd = open(filepath, O_RDONLY);
141                 
142                 if (fd < 0)
143                         return 0;
144         }
145
146         if (fstat(fd, &st)) {
147                 close(fd);
148                 return 0;
149         }
150
151         conf_file = malloc(st.st_size+1);
152         if (!conf_file) {
153                 close(fd);
154                 return 0;
155         }
156         
157         conf_len = read(fd, conf_file, st.st_size);
158         if (conf_len < 0) {
159                 close(fd);
160                 return 0;
161         }
162         conf_file[conf_len] = 0;
163
164         close(fd);
165         
166         if (cfg_parse(filepath, conf_file, conf_len)) {
167                 pb_log("Error parsing yaboot.conf\n");
168                 return 0;
169         }
170
171         free(filepath);
172
173         dev = malloc(sizeof(*dev));
174         memset(dev, 0, sizeof(*dev));
175         dev->id = strdup(devicepath);
176         if (cfg_get_strg(0, "init-message")) {
177                 char *newline;
178                 dev->description = strdup(cfg_get_strg(0, "init-message"));
179                 newline = strchr(dev->description, '\n');
180                 if (newline)
181                         *newline = 0;
182         }
183         dev->icon_file = strdup(generic_icon_file(guess_device_type()));
184
185         /* Mount the 'partition' which is what all the image filenames
186            are relative to */
187         tmpstr = cfg_get_strg(0, "partition");
188         if (tmpstr) {
189                 char *endp;
190                 int partnr = strtol(tmpstr, &endp, 10);
191                 if (endp != tmpstr && !*endp) {
192                         char *new_dev = malloc(strlen(devicepath) + strlen(tmpstr) + 1);
193                         if (!new_dev)
194                                 return 0;
195
196                         strcpy(new_dev, devicepath);
197
198                         /* Strip digits (partition number) from string */
199                         endp = &new_dev[strlen(devicepath) - 1];
200                         while (isdigit(*endp))
201                                 *(endp--) = 0;
202
203                         /* and add our own... */
204                         sprintf(endp+1, "%d", partnr);
205
206                         /* FIXME: udev may not have created the device node
207                            yet. And on removal, unmount_device() only unmounts
208                            it once, while in fact it may be mounted twice. */
209                         if (mount_device(new_dev, partition_mntpoint)) {
210                                 pb_log("Error mounting image partition\n");
211                                 return 0;
212                         }
213                         mountpoint = partition_mntpoint;
214                         dev->id = new_dev;
215                 }                               
216         }
217
218         defimage = cfg_get_default();
219         if (!defimage)
220                 return 0;
221         defimage = cfg_get_strg(defimage, "image");
222
223         label = cfg_next_image(NULL);
224         if (!label || !check_and_add_device(dev))
225                 return 0;
226
227         do {
228                 process_image(label);
229         } while ((label = cfg_next_image(label)));
230
231         return 1;
232 }
233
234 struct parser yaboot_parser = {
235         .name = "yaboot.conf parser",
236         .priority = 99,
237         .parse    = yaboot_parse
238 };