Add some basic yaboot.conf parsing support
[petitboot] / devices / yaboot-parser.c
1
2 #include "udev-helper.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 char *prepend_mountpoint(const char *path)
90 {
91         char *full_path;
92
93         full_path = malloc(strlen(path) + strlen(mountpoint) + 2);
94
95         strcpy(full_path, mountpoint);
96         if (path[0] != '/')
97                 strcat(full_path, "/");
98         strcat(full_path, path);
99
100         return full_path;
101 }
102
103 static int check_and_add_device(struct device *dev)
104 {
105         if (!dev->icon_file)
106                 dev->icon_file = strdup(generic_icon_file(guess_device_type()));
107
108         return !add_device(dev);
109 }
110
111 void process_image(char *label)
112 {
113         struct boot_option opt;
114         char *cfgopt;
115
116         memset(&opt, 0, sizeof(opt));
117
118         opt.name = label;
119         cfgopt = cfg_get_strg(label, "image");
120         opt.boot_image_file = prepend_mountpoint(cfgopt);
121         if (cfgopt == defimage)
122                 printf("This one is default. What do we do about it?\n");
123
124         cfgopt = cfg_get_strg(label, "initrd");
125         if (cfgopt)
126                 opt.initrd_file = prepend_mountpoint(cfgopt);
127
128         opt.boot_args = make_params(label, NULL);
129
130         add_boot_option(&opt);
131
132         if (opt.initrd_file)
133                 free(opt.initrd_file);
134 }
135
136 static int yaboot_parse(const char *devicepath, const char *_mountpoint)
137 {
138         char *filepath;
139         char *conf_file;
140         char *tmpstr;
141         ssize_t conf_len;
142         int fd;
143         struct stat st;
144         char *label;
145
146         mountpoint = _mountpoint;
147
148         filepath = prepend_mountpoint("/etc/yaboot.conf");
149
150         fd = open(filepath, O_RDONLY);
151         if (fd < 0) {
152                 free(filepath);
153                 filepath = prepend_mountpoint("/yaboot.conf");
154                 fd = open(filepath, O_RDONLY);
155                 
156                 if (fd < 0)
157                         return 0;
158         }
159
160         if (fstat(fd, &st)) {
161                 close(fd);
162                 return 0;
163         }
164
165         conf_file = malloc(st.st_size+1);
166         if (!conf_file) {
167                 close(fd);
168                 return 0;
169         }
170         
171         conf_len = read(fd, conf_file, st.st_size);
172         if (conf_len < 0) {
173                 close(fd);
174                 return 0;
175         }
176         conf_file[conf_len] = 0;
177
178         close(fd);
179         
180         if (cfg_parse(filepath, conf_file, conf_len)) {
181                 printf("Error parsing yaboot.conf\n");
182                 return 0;
183         }
184
185         free(filepath);
186
187         dev = malloc(sizeof(*dev));
188         memset(dev, 0, sizeof(*dev));
189         dev->id = strdup(devicepath);
190         if (cfg_get_strg(0, "init-message")) {
191                 char *newline;
192                 dev->description = strdup(cfg_get_strg(0, "init-message"));
193                 newline = strchr(dev->description, '\n');
194                 if (newline)
195                         *newline = 0;
196         }
197         dev->icon_file = strdup(generic_icon_file(guess_device_type()));
198
199         /* Mount the 'partition' which is what all the image filenames
200            are relative to */
201         tmpstr = cfg_get_strg(0, "partition");
202         if (tmpstr) {
203                 char *endp;
204                 int partnr = strtol(tmpstr, &endp, 10);
205                 if (endp != tmpstr && !*endp) {
206                         char *new_dev = malloc(strlen(devicepath) + strlen(tmpstr) + 1);
207                         if (!new_dev)
208                                 return 0;
209
210                         strcpy(new_dev, devicepath);
211
212                         /* Strip digits (partition number) from string */
213                         endp = &new_dev[strlen(devicepath) - 1];
214                         while (isdigit(*endp))
215                                 *(endp--) = 0;
216
217                         /* and add our own... */
218                         sprintf(endp+1, "%d", partnr);
219
220                         /* FIXME: udev may not have created the device node
221                            yet. And on removal, unmount_device() only unmounts
222                            it once, while in fact it may be mounted twice. */
223                         if (mount_device(new_dev, partition_mntpoint)) {
224                                 printf("Error mounting image partition\n");
225                                 return 0;
226                         }
227                         mountpoint = partition_mntpoint;
228                         dev->id = new_dev;
229                 }                               
230         }
231
232         defimage = cfg_get_default();
233         if (!defimage)
234                 return 0;
235         defimage = cfg_get_strg(defimage, "image");
236
237         label = cfg_next_image(NULL);
238         if (!label || !check_and_add_device(dev))
239                 return 0;
240
241         do {
242                 process_image(label);
243         } while ((label = cfg_next_image(label)));
244
245         return 1;
246 }
247
248 struct parser yaboot_parser = {
249         .name = "yaboot.conf parser",
250         .priority = 99,
251         .parse    = yaboot_parse
252 };