1 #include <u.h> 2 #include <libc.h> 3 #include <auth.h> 4 #include <fcall.h> 5 #include "../boot/boot.h" 6 7 char cputype[64]; 8 char sys[2*64]; 9 char reply[256]; 10 int printcol; 11 int mflag; 12 int fflag; 13 int kflag; 14 15 char *bargv[Nbarg]; 16 int bargc; 17 18 static void swapproc(void); 19 static Method *rootserver(char*); 20 static void usbinit(void); 21 static void kbmap(void); 22 23 void 24 boot(int argc, char *argv[]) 25 { 26 int fd, afd; 27 Method *mp; 28 char *cmd, cmdbuf[64], *iargv[16]; 29 char rootbuf[64]; 30 int islocal, ishybrid; 31 char *rp, *rsp; 32 int iargc, n; 33 char buf[32]; 34 AuthInfo *ai; 35 36 fmtinstall('r', errfmt); 37 38 bind("#c", "/dev", MBEFORE); 39 open("/dev/cons", OREAD); 40 open("/dev/cons", OWRITE); 41 open("/dev/cons", OWRITE); 42 /* 43 * init will reinitialize its namespace. 44 * #ec gets us plan9.ini settings (*var variables). 45 */ 46 bind("#ec", "/env", MREPL); 47 bind("#e", "/env", MBEFORE|MCREATE); 48 bind("#s", "/srv", MREPL|MCREATE); 49 #ifdef DEBUG 50 print("argc=%d\n", argc); 51 for(fd = 0; fd < argc; fd++) 52 print("%lux %s ", argv[fd], argv[fd]); 53 print("\n"); 54 #endif DEBUG 55 56 ARGBEGIN{ 57 case 'k': 58 kflag = 1; 59 break; 60 case 'm': 61 mflag = 1; 62 break; 63 case 'f': 64 fflag = 1; 65 break; 66 }ARGEND 67 68 readfile("#e/cputype", cputype, sizeof(cputype)); 69 70 /* 71 * set up usb keyboard, mouse and disk, if any. 72 */ 73 usbinit(); 74 75 /* 76 * pick a method and initialize it 77 */ 78 if(method[0].name == nil) 79 fatal("no boot methods"); 80 mp = rootserver(argc ? *argv : 0); 81 (*mp->config)(mp); 82 islocal = strcmp(mp->name, "local") == 0; 83 ishybrid = strcmp(mp->name, "hybrid") == 0; 84 85 /* 86 * load keymap if it's there. 87 */ 88 kbmap(); 89 90 /* 91 * authentication agent 92 */ 93 authentication(cpuflag); 94 95 /* 96 * connect to the root file system 97 */ 98 fd = (*mp->connect)(); 99 if(fd < 0) 100 fatal("can't connect to file server"); 101 if(getenv("srvold9p")) 102 fd = old9p(fd); 103 if(!islocal && !ishybrid){ 104 if(cfs) 105 fd = (*cfs)(fd); 106 } 107 print("version..."); 108 buf[0] = '\0'; 109 n = fversion(fd, 0, buf, sizeof buf); 110 if(n < 0) 111 fatal("can't init 9P"); 112 srvcreate("boot", fd); 113 114 /* 115 * create the name space, mount the root fs 116 */ 117 if(bind("/", "/", MREPL) < 0) 118 fatal("bind /"); 119 rp = getenv("rootspec"); 120 if(rp == nil) 121 rp = ""; 122 123 afd = fauth(fd, rp); 124 if(afd >= 0){ 125 ai = auth_proxy(afd, auth_getkey, "proto=p9any role=client"); 126 if(ai == nil) 127 print("authentication failed (%r), trying mount anyways\n"); 128 } 129 if(mount(fd, afd, "/root", MREPL|MCREATE, rp) < 0) 130 fatal("mount /"); 131 rsp = rp; 132 rp = getenv("rootdir"); 133 if(rp == nil) 134 rp = rootdir; 135 if(bind(rp, "/", MAFTER|MCREATE) < 0){ 136 if(strncmp(rp, "/root", 5) == 0){ 137 fprint(2, "boot: couldn't bind $rootdir=%s to root: %r\n", rp); 138 fatal("second bind /"); 139 } 140 snprint(rootbuf, sizeof rootbuf, "/root/%s", rp); 141 rp = rootbuf; 142 if(bind(rp, "/", MAFTER|MCREATE) < 0){ 143 fprint(2, "boot: couldn't bind $rootdir=%s to root: %r\n", rp); 144 if(strcmp(rootbuf, "/root//plan9") == 0){ 145 fprint(2, "**** warning: remove rootdir=/plan9 entry from plan9.ini\n"); 146 rp = "/root"; 147 if(bind(rp, "/", MAFTER|MCREATE) < 0) 148 fatal("second bind /"); 149 }else 150 fatal("second bind /"); 151 } 152 } 153 close(fd); 154 setenv("rootdir", rp); 155 156 settime(islocal, afd, rsp); 157 if(afd > 0) 158 close(afd); 159 swapproc(); 160 161 cmd = getenv("init"); 162 if(cmd == nil){ 163 sprint(cmdbuf, "/%s/init -%s%s", cputype, 164 cpuflag ? "c" : "t", mflag ? "m" : ""); 165 cmd = cmdbuf; 166 } 167 iargc = tokenize(cmd, iargv, nelem(iargv)-1); 168 cmd = iargv[0]; 169 170 /* make iargv[0] basename(iargv[0]) */ 171 if(iargv[0] = strrchr(iargv[0], '/')) 172 iargv[0]++; 173 else 174 iargv[0] = cmd; 175 176 iargv[iargc] = nil; 177 178 exec(cmd, iargv); 179 fatal(cmd); 180 } 181 182 static Method* 183 findmethod(char *a) 184 { 185 Method *mp; 186 int i, j; 187 char *cp; 188 189 if((i = strlen(a)) == 0) 190 return nil; 191 cp = strchr(a, '!'); 192 if(cp) 193 i = cp - a; 194 for(mp = method; mp->name; mp++){ 195 j = strlen(mp->name); 196 if(j > i) 197 j = i; 198 if(strncmp(a, mp->name, j) == 0) 199 break; 200 } 201 if(mp->name) 202 return mp; 203 return nil; 204 } 205 206 /* 207 * ask user from whence cometh the root file system 208 */ 209 static Method* 210 rootserver(char *arg) 211 { 212 char prompt[256]; 213 Method *mp; 214 char *cp; 215 int n; 216 217 /* look for required reply */ 218 readfile("#e/nobootprompt", reply, sizeof(reply)); 219 if(reply[0]){ 220 mp = findmethod(reply); 221 if(mp) 222 goto HaveMethod; 223 print("boot method %s not found\n", reply); 224 reply[0] = 0; 225 } 226 227 /* make list of methods */ 228 mp = method; 229 n = sprint(prompt, "root is from (%s", mp->name); 230 for(mp++; mp->name; mp++) 231 n += sprint(prompt+n, ", %s", mp->name); 232 sprint(prompt+n, ")"); 233 234 /* create default reply */ 235 readfile("#e/bootargs", reply, sizeof(reply)); 236 if(reply[0] == 0 && arg != 0) 237 strcpy(reply, arg); 238 if(reply[0]){ 239 mp = findmethod(reply); 240 if(mp == 0) 241 reply[0] = 0; 242 } 243 if(reply[0] == 0) 244 strcpy(reply, method->name); 245 246 /* parse replies */ 247 do{ 248 outin(prompt, reply, sizeof(reply)); 249 mp = findmethod(reply); 250 }while(mp == nil); 251 252 HaveMethod: 253 bargc = tokenize(reply, bargv, Nbarg-2); 254 bargv[bargc] = nil; 255 cp = strchr(reply, '!'); 256 if(cp) 257 strcpy(sys, cp+1); 258 return mp; 259 } 260 261 static void 262 swapproc(void) 263 { 264 int fd; 265 266 fd = open("#c/swap", OWRITE); 267 if(fd < 0){ 268 warning("opening #c/swap"); 269 return; 270 } 271 if(write(fd, "start", 5) <= 0) 272 warning("starting swap kproc"); 273 close(fd); 274 } 275 276 int 277 old9p(int fd) 278 { 279 int p[2]; 280 281 if(pipe(p) < 0) 282 fatal("pipe"); 283 284 print("srvold9p..."); 285 switch(fork()) { 286 case -1: 287 fatal("rfork srvold9p"); 288 case 0: 289 dup(fd, 1); 290 close(fd); 291 dup(p[0], 0); 292 close(p[0]); 293 close(p[1]); 294 execl("/srvold9p", "srvold9p", "-s", 0); 295 fatal("exec srvold9p"); 296 default: 297 close(fd); 298 close(p[0]); 299 } 300 return p[1]; 301 } 302 303 static void 304 run(char *prog, char **args) 305 { 306 int i, pid; 307 308 if (access(args[0], AEXIST) < 0) 309 return; /* avoid error messages */ 310 print("%s...", prog); 311 switch(pid = fork()){ 312 case -1: 313 fatal("fork"); 314 case 0: 315 exec(args[0], args); 316 fatal(smprint("can't exec %s: %r", args[0])); 317 } 318 while ((i = waitpid()) != pid && i != -1) 319 ; 320 if(i == -1) 321 fatal(smprint("waitpid for %s failed", args[0])); 322 } 323 324 static void 325 usbinit(void) 326 { 327 static char *darg[] = { "/boot/usbd", nil }; 328 329 if(bind("#u", "/dev", MAFTER) >= 0 && access("/dev/usb", 0) >= 0) 330 run("usbd", darg); 331 } 332 333 static void 334 kbmap(void) 335 { 336 char *f; 337 int n, in, out; 338 char buf[1024]; 339 340 f = getenv("kbmap"); 341 if(f == nil) 342 return; 343 if(bind("#κ", "/dev", MAFTER) < 0){ 344 warning("can't bind #κ"); 345 return; 346 } 347 348 in = open(f, OREAD); 349 if(in < 0){ 350 warning("can't open kbd map: %r"); 351 return; 352 } 353 out = open("/dev/kbmap", OWRITE); 354 if(out < 0) { 355 warning("can't open /dev/kbmap: %r"); 356 close(in); 357 return; 358 } 359 while((n = read(in, buf, sizeof(buf))) > 0) 360 if(write(out, buf, n) != n){ 361 warning("write to /dev/kbmap failed"); 362 break; 363 } 364 close(in); 365 close(out); 366 } 367