1#include <assert.h> 2#include <ctype.h> 3#include <errno.h> 4#include <stdio.h> 5#include <stdlib.h> 6#include <string.h> 7 8#include "../../include/grubmenu.h" 9 10static int 11skip_line(FILE *infile) { 12 int c; 13 14 do { 15 c= fgetc(infile); 16 if(c < 0) return c; 17 } while(c != '\n'); 18 19 return 0; 20} 21 22static int 23skip_whitespace(FILE *infile, int multiline) { 24 int c; 25 do { 26 c = fgetc(infile); 27 if(c < 0) return c; 28 if(!multiline && c == '\n') break; 29 } while(isspace(c)); 30 ungetc(c, infile); 31 32 return 0; 33} 34 35static int 36peek(FILE *f) { 37 int c= fgetc(f); 38 if(c >= 0) ungetc(c, f); 39 return c; 40} 41 42#define MAXBUF 255 43 44static int 45read_token(FILE *infile, char *buf) { 46 int c= peek(infile); 47 if(c == EOF) return 0; 48 if(c < 0) return c; 49 50 while(isspace(c) || c == '#') { 51 skip_whitespace(infile, 1); 52 if(c == '#') skip_line(infile); 53 c= peek(infile); 54 if(c == EOF) return 0; 55 if(c < 0) return c; 56 } 57 58 size_t i= 0; 59 c= fgetc(infile); 60 while(!isspace(c)) { 61 assert(i < MAXBUF); 62 buf[i]= c; 63 i++; 64 c= fgetc(infile); 65 if(c == EOF) break; 66 if(c < 0) return c; 67 } 68 if(c >= 0) ungetc(c, infile); 69 70 buf[i]= '\0'; 71 return i + 1; 72} 73 74static int 75read_line(FILE *infile, char *buf) { 76 int c; 77 78 int len= skip_whitespace(infile, 0); 79 if(len < 0) return len; 80 81 size_t i= 0; 82 do { 83 c= fgetc(infile); 84 if(c < 0) return c; 85 assert(i < MAXBUF); 86 if(c != '\n') { 87 buf[i]= c; 88 i++; 89 } 90 } while(c != '\n'); 91 92 buf[i]= '\0'; 93 return i + 1; 94} 95 96typedef int (*reader_t)(FILE *, char *); 97 98static int 99read_string(FILE *f, reader_t reader, char **bufptr) { 100 char buf[MAXBUF+1]; 101 102 size_t len= reader(f, buf); 103 if(len < 0) return len; 104 105 *bufptr= malloc(len); 106 if(!*bufptr) { 107 perror("malloc"); 108 return 0; 109 } 110 111 memcpy(*bufptr, buf, len); 112 return len; 113} 114 115struct menu_lst * 116read_menu_lst(const char *path) { 117 int len; 118 119 FILE *infile= fopen(path, "r"); 120 if(!infile) { 121 perror("fopen"); 122 return NULL; 123 } 124 125 struct menu_lst *menu= calloc(sizeof(struct menu_lst), 1); 126 if(!menu) { 127 perror("malloc"); 128 return NULL; 129 } 130 131 char cmd[MAXBUF+1]; 132 while((len= read_token(infile, cmd)) > 0) { 133 if(!strcmp(cmd, "title")) { 134 len= read_string(infile, read_token, &menu->title); 135 if(len <= 0) { 136 fprintf(stderr, "Missing title value.\n"); 137 break; 138 } 139 } 140 else if(!strcmp(cmd, "kernel")) { 141 len= read_string(infile, read_token, &menu->kernel.path); 142 if(len <= 0) { 143 fprintf(stderr, "Missing kernel path.\n"); 144 break; 145 } 146 147 len= read_string(infile, read_line, &menu->kernel.args); 148 if(len <= 0) { 149 fprintf(stderr, "Missing kernel arguments.\n"); 150 break; 151 } 152 } 153 else if(!strcmp(cmd, "image")) { 154 len= read_string(infile, read_line, &menu->image); 155 if(len <= 0) { 156 fprintf(stderr, "Missing image specifier.\n"); 157 break; 158 } 159 } 160 // handle "module" and "modulenounzip" 161 else if(!strncmp(cmd, "module", 6)) { 162 menu->nmodules++; 163 164 menu->modules= 165 realloc(menu->modules, 166 menu->nmodules * sizeof(struct menu_module)); 167 if(!menu->modules) { 168 perror("realloc"); 169 return NULL; 170 } 171 172 struct menu_module *mod= &menu->modules[menu->nmodules - 1]; 173 174 len= read_string(infile, read_token, &mod->path); 175 if(len <= 0) { 176 fprintf(stderr, "Missing module path.\n"); 177 break; 178 } 179 180 len= read_string(infile, read_line, &mod->args); 181 if(len <= 0) { 182 fprintf(stderr, "Missing module arguments.\n"); 183 break; 184 } 185 } 186 else if(!strcmp(cmd, "mmap")) { 187 menu->mmap_len++; 188 189 menu->mmap= 190 realloc(menu->mmap, 191 menu->mmap_len * sizeof(struct menu_mmap_entry)); 192 if(!menu->mmap) { 193 perror("realloc"); 194 return NULL; 195 } 196 197 struct menu_mmap_entry *entry= &menu->mmap[menu->mmap_len - 1]; 198 199 len= read_string(infile, read_token, &entry->name); 200 if(len <= 0) { 201 fprintf(stderr, "Missing MMAP entry name.\n"); 202 break; 203 } 204 205 char buf[MAXBUF+1]; 206 len= read_token(infile, buf); 207 if(len <= 0) { 208 fprintf(stderr, "Missing MMAP start address.\n"); 209 break; 210 } 211 errno= 0; 212 entry->base= strtoull(buf, NULL, 0); 213 if(errno) { 214 fprintf(stderr, "Invalid MMAP start address.\n"); 215 break; 216 } 217 218 len= read_token(infile, buf); 219 if(len <= 0) { 220 fprintf(stderr, "Missing MMAP length.\n"); 221 break; 222 } 223 errno= 0; 224 entry->length= strtoull(buf, NULL, 0); 225 if(errno) { 226 fprintf(stderr, "Invalid MMAP length.\n"); 227 break; 228 } 229 230 len= read_token(infile, buf); 231 if(len <= 0) { 232 fprintf(stderr, "Missing MMAP ID.\n"); 233 break; 234 } 235 errno= 0; 236 entry->type= strtoul(buf, NULL, 0); 237 if(errno) { 238 fprintf(stderr, "Invalid MMAP ID.\n"); 239 break; 240 } 241 } 242 else if(!strcmp(cmd, "timeout")) { 243 char buf[MAXBUF+1]; 244 len= read_token(infile, buf); 245 if(len <= 0) { 246 fprintf(stderr, "Missing timeout value.\n"); 247 break; 248 } 249 errno= 0; 250 menu->timeout= strtoul(buf, NULL, 0); 251 if(errno) { 252 fprintf(stderr, "Invalid timeout value.\n"); 253 break; 254 } 255 } 256 else if(!strcmp(cmd, "bootdriver")) { 257 len= read_string(infile, read_token, &menu->boot_driver.path); 258 if(len <= 0) { 259 fprintf(stderr, "Missing timeout value.\n"); 260 break; 261 } 262 } 263 else if(!strcmp(cmd, "cpudriver")) { 264 len= read_string(infile, read_token, &menu->kernel.path); 265 if(len <= 0) { 266 fprintf(stderr, "Missing timeout value.\n"); 267 break; 268 } 269 len= read_string(infile, read_line, &menu->kernel.args); 270 if(len <= 0) { 271 fprintf(stderr, "Missing module arguments.\n"); 272 break; 273 } 274 } 275 else if(!strcmp(cmd, "root")) { 276 char buf[MAXBUF+1]; 277 len= read_token(infile, buf); 278 if(len <= 0) { 279 fprintf(stderr, "Missing timeout value.\n"); 280 break; 281 } 282 } 283 else { 284 fprintf(stderr, "Unknown command: %s\n", cmd); 285 } 286 } 287 if(len < 0) { 288 perror("read_token"); 289 return NULL; 290 } 291 292 if(fclose(infile)) { 293 perror("fclose"); 294 return NULL; 295 } 296 297 return menu; 298} 299