parseopts.c (4880B)
1 #include <unistd.h> 2 #include <stdint.h> 3 #include <string.h> 4 #include <unistd.h> 5 6 #include "opts.h" 7 8 9 static int begins_with(char * str, char * prefix) 10 { 11 while(*prefix) { 12 if(*str == '\0') return 0; 13 if(*str != *prefix) return 0; 14 str++; 15 prefix++; 16 } 17 return 1; 18 } 19 20 char * pr_u32(int32_t input) { 21 static char buf[9]; 22 const char *digits = "0123456789abcdef"; 23 int i=0; 24 25 buf[i] = digits[(input & 0xf0000000) >> 28]; 26 buf[i+1] = digits[(input & 0x0f000000) >> 24]; 27 if(buf[i] != '0' || buf[i+1] != '0') i+=2; 28 29 buf[i] = digits[(input & 0x00f00000) >> 20]; 30 buf[i+1] = digits[(input & 0x000f0000) >> 16]; 31 if(buf[i] != '0' || buf[i+1] != '0') i+=2; 32 33 buf[i] = digits[(input & 0x0000f000) >> 12]; 34 buf[i+1] = digits[(input & 0x00000f00) >> 8]; 35 if(buf[i] != '0' || buf[i+1] != '0') i+=2; 36 37 buf[i] = digits[(input & 0x000000f0) >> 4]; 38 buf[i+1] = digits[(input & 0x0000000f)]; 39 i+=2; 40 41 buf[i] ='\0'; 42 if(write(2, buf, i)) 43 return buf; 44 else 45 return NULL; 46 } 47 48 static char *eat_word(char *p) 49 { 50 while(*p && (*p != ' ')) p++; 51 52 if(*p) { 53 *p = '\0'; 54 p++; 55 }; 56 return p; 57 } 58 59 static char * eat_param(char *p, char *param_name, char **out) 60 { 61 if(begins_with(p, param_name)) { 62 *out = p + strlen(param_name); 63 p = eat_word(p); 64 }; 65 return p; 66 } 67 68 void parseopts(char * cmdline, struct root_opts *opts) { 69 for(char *p = cmdline; *p; p++) { 70 p = eat_param(p, "root=", &(opts->device)); 71 p = eat_param(p, "rootfstype=", &(opts->fstype)); 72 p = eat_param(p, "rootflags=", &(opts->mount_opts)); 73 }; 74 } 75 76 #ifdef TESTS 77 #include <assert.h> 78 #include <stdio.h> 79 #include <stdlib.h> 80 81 // cc -DTESTS -o parseopts parseopts.c && ./parseopts 82 83 #define die(fmt, ...) do { printf(fmt, __VA_ARGS__); exit(1); } while(0) 84 #define S(x) #x 85 #define expect_equal(actual, expected) \ 86 if(!actual || strcmp(actual, expected)) die("%d: expected \"%s\", got \"%s\"", __LINE__, expected, actual); 87 88 89 int main() 90 { 91 struct root_opts opts = { 92 .device = "/dev/hda1", 93 .fstype = "xiafs", 94 .mount_opts = NULL 95 }; 96 char *buf; 97 98 // finds root= rootfstype= rootflags= options 99 buf = strdup("liminix console=ttyS0,115200 panic=10 oops=panic init=/bin/init loglevel=8 root=/dev/ubi0_4 rootfstype=ubifs rootflags=subvol=1 fw_devlink=off mtdparts=phram0:18M(rootfs) phram.phram=phram0,0x40400000,18874368,65536 root=/dev/mtdblock0 foo"); 100 memset(&opts, '\0', sizeof opts); parseopts(buf, &opts); 101 expect_equal(opts.device, "/dev/mtdblock0"); 102 expect_equal(opts.fstype, "ubifs"); 103 expect_equal(opts.mount_opts, "subvol=1"); 104 105 // in case of duplicates, chooses the latter 106 // also: works if the option is end of string 107 buf = strdup("liminix console=ttyS0,115200 panic=10 oops=panic init=/bin/init loglevel=8 root=/dev/ubi0_4 rootfstype=ubifs fw_devlink=off mtdparts=phram0:18M(rootfs) phram.phram=phram0,0x40400000,18874368,65536 root=/dev/mtdblock0"); 108 memset(&opts, '\0', sizeof opts); parseopts(buf, &opts); 109 expect_equal(opts.device, "/dev/mtdblock0"); 110 expect_equal(opts.fstype, "ubifs"); 111 112 // options may appear in either order 113 buf = strdup("liminix fw_devlink=off root=/dev/hda1 rootfstype=ubifs foo"); 114 memset(&opts, '\0', sizeof opts); parseopts(buf, &opts); 115 expect_equal(opts.device, "/dev/hda1"); 116 expect_equal(opts.fstype, "ubifs"); 117 118 // works when rootflags is the last option 119 buf = strdup("liminix fw_devlink=off root=/dev/hda1 rootfstype=ubifs rootflags=subvol=@"); 120 memset(&opts, '\0', sizeof opts); parseopts(buf, &opts); 121 expect_equal(opts.device, "/dev/hda1"); 122 expect_equal(opts.fstype, "ubifs"); 123 expect_equal(opts.mount_opts, "subvol=@"); 124 125 buf = strdup("liminix rootfstype=ubifs fw_devlink=off root=/dev/hda1 foo"); 126 memset(&opts, '\0', sizeof opts); parseopts(buf, &opts); 127 expect_equal(opts.fstype, "ubifs"); 128 expect_equal(opts.device, "/dev/hda1"); 129 130 // provides NULL for missing options 131 buf = strdup("liminix rufustype=ubifs fw_devlink=off foot=/dev/hda1"); 132 memset(&opts, '\0', sizeof opts); parseopts(buf, &opts); 133 134 if(opts.fstype) die("expected null rootfstype, got \"%s\"", opts.fstype); 135 if(opts.device) die("expected null root, got \"%s\"", opts.device); 136 if(opts.mount_opts) die("expected null mount_opts, got \"%s\"", opts.mount_opts); 137 138 // provides empty strings for empty options 139 buf = strdup("liminix rootfstype= fw_devlink=off root= /dev/hda1"); 140 memset(&opts, '\0', sizeof opts); parseopts(buf, &opts); 141 142 if(strlen(opts.fstype)) die("expected empty rootfstype, got \"%s\"", opts.fstype); 143 if(strlen(opts.device)) die("expected null root, got \"%s\"", opts.device); 144 145 expect_equal("01", pr_u32(1)); 146 expect_equal("ab", pr_u32(0xab)); 147 expect_equal("0abc", pr_u32(0xabc)); 148 expect_equal("aabc", pr_u32(0xaabc)); 149 expect_equal("deadcafe", pr_u32(0xdeadcafe)); 150 } 151 152 #endif