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