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