aos/lib/multiboot/grubmenu.c
Daniel Schwyn 6d444bf552 Main handout
Signed-off-by: Daniel Schwyn <daniel.schwyn@inf.ethz.ch>
2022-03-03 14:57:51 +01:00

299 lines
7.3 KiB
C

#include <assert.h>
#include <ctype.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "../../include/grubmenu.h"
static int
skip_line(FILE *infile) {
int c;
do {
c= fgetc(infile);
if(c < 0) return c;
} while(c != '\n');
return 0;
}
static int
skip_whitespace(FILE *infile, int multiline) {
int c;
do {
c = fgetc(infile);
if(c < 0) return c;
if(!multiline && c == '\n') break;
} while(isspace(c));
ungetc(c, infile);
return 0;
}
static int
peek(FILE *f) {
int c= fgetc(f);
if(c >= 0) ungetc(c, f);
return c;
}
#define MAXBUF 255
static int
read_token(FILE *infile, char *buf) {
int c= peek(infile);
if(c == EOF) return 0;
if(c < 0) return c;
while(isspace(c) || c == '#') {
skip_whitespace(infile, 1);
if(c == '#') skip_line(infile);
c= peek(infile);
if(c == EOF) return 0;
if(c < 0) return c;
}
size_t i= 0;
c= fgetc(infile);
while(!isspace(c)) {
assert(i < MAXBUF);
buf[i]= c;
i++;
c= fgetc(infile);
if(c == EOF) break;
if(c < 0) return c;
}
if(c >= 0) ungetc(c, infile);
buf[i]= '\0';
return i + 1;
}
static int
read_line(FILE *infile, char *buf) {
int c;
int len= skip_whitespace(infile, 0);
if(len < 0) return len;
size_t i= 0;
do {
c= fgetc(infile);
if(c < 0) return c;
assert(i < MAXBUF);
if(c != '\n') {
buf[i]= c;
i++;
}
} while(c != '\n');
buf[i]= '\0';
return i + 1;
}
typedef int (*reader_t)(FILE *, char *);
static int
read_string(FILE *f, reader_t reader, char **bufptr) {
char buf[MAXBUF+1];
size_t len= reader(f, buf);
if(len < 0) return len;
*bufptr= malloc(len);
if(!*bufptr) {
perror("malloc");
return 0;
}
memcpy(*bufptr, buf, len);
return len;
}
struct menu_lst *
read_menu_lst(const char *path) {
int len;
FILE *infile= fopen(path, "r");
if(!infile) {
perror("fopen");
return NULL;
}
struct menu_lst *menu= calloc(sizeof(struct menu_lst), 1);
if(!menu) {
perror("malloc");
return NULL;
}
char cmd[MAXBUF+1];
while((len= read_token(infile, cmd)) > 0) {
if(!strcmp(cmd, "title")) {
len= read_string(infile, read_token, &menu->title);
if(len <= 0) {
fprintf(stderr, "Missing title value.\n");
break;
}
}
else if(!strcmp(cmd, "kernel")) {
len= read_string(infile, read_token, &menu->kernel.path);
if(len <= 0) {
fprintf(stderr, "Missing kernel path.\n");
break;
}
len= read_string(infile, read_line, &menu->kernel.args);
if(len <= 0) {
fprintf(stderr, "Missing kernel arguments.\n");
break;
}
}
else if(!strcmp(cmd, "image")) {
len= read_string(infile, read_line, &menu->image);
if(len <= 0) {
fprintf(stderr, "Missing image specifier.\n");
break;
}
}
// handle "module" and "modulenounzip"
else if(!strncmp(cmd, "module", 6)) {
menu->nmodules++;
menu->modules=
realloc(menu->modules,
menu->nmodules * sizeof(struct menu_module));
if(!menu->modules) {
perror("realloc");
return NULL;
}
struct menu_module *mod= &menu->modules[menu->nmodules - 1];
len= read_string(infile, read_token, &mod->path);
if(len <= 0) {
fprintf(stderr, "Missing module path.\n");
break;
}
len= read_string(infile, read_line, &mod->args);
if(len <= 0) {
fprintf(stderr, "Missing module arguments.\n");
break;
}
}
else if(!strcmp(cmd, "mmap")) {
menu->mmap_len++;
menu->mmap=
realloc(menu->mmap,
menu->mmap_len * sizeof(struct menu_mmap_entry));
if(!menu->mmap) {
perror("realloc");
return NULL;
}
struct menu_mmap_entry *entry= &menu->mmap[menu->mmap_len - 1];
len= read_string(infile, read_token, &entry->name);
if(len <= 0) {
fprintf(stderr, "Missing MMAP entry name.\n");
break;
}
char buf[MAXBUF+1];
len= read_token(infile, buf);
if(len <= 0) {
fprintf(stderr, "Missing MMAP start address.\n");
break;
}
errno= 0;
entry->base= strtoull(buf, NULL, 0);
if(errno) {
fprintf(stderr, "Invalid MMAP start address.\n");
break;
}
len= read_token(infile, buf);
if(len <= 0) {
fprintf(stderr, "Missing MMAP length.\n");
break;
}
errno= 0;
entry->length= strtoull(buf, NULL, 0);
if(errno) {
fprintf(stderr, "Invalid MMAP length.\n");
break;
}
len= read_token(infile, buf);
if(len <= 0) {
fprintf(stderr, "Missing MMAP ID.\n");
break;
}
errno= 0;
entry->type= strtoul(buf, NULL, 0);
if(errno) {
fprintf(stderr, "Invalid MMAP ID.\n");
break;
}
}
else if(!strcmp(cmd, "timeout")) {
char buf[MAXBUF+1];
len= read_token(infile, buf);
if(len <= 0) {
fprintf(stderr, "Missing timeout value.\n");
break;
}
errno= 0;
menu->timeout= strtoul(buf, NULL, 0);
if(errno) {
fprintf(stderr, "Invalid timeout value.\n");
break;
}
}
else if(!strcmp(cmd, "bootdriver")) {
len= read_string(infile, read_token, &menu->boot_driver.path);
if(len <= 0) {
fprintf(stderr, "Missing timeout value.\n");
break;
}
}
else if(!strcmp(cmd, "cpudriver")) {
len= read_string(infile, read_token, &menu->kernel.path);
if(len <= 0) {
fprintf(stderr, "Missing timeout value.\n");
break;
}
len= read_string(infile, read_line, &menu->kernel.args);
if(len <= 0) {
fprintf(stderr, "Missing module arguments.\n");
break;
}
}
else if(!strcmp(cmd, "root")) {
char buf[MAXBUF+1];
len= read_token(infile, buf);
if(len <= 0) {
fprintf(stderr, "Missing timeout value.\n");
break;
}
}
else {
fprintf(stderr, "Unknown command: %s\n", cmd);
}
}
if(len < 0) {
perror("read_token");
return NULL;
}
if(fclose(infile)) {
perror("fclose");
return NULL;
}
return menu;
}