boot.c 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <auth.h>
  4. #include <fcall.h>
  5. #include "../boot/boot.h"
  6. #define PARTSRV "partfs.sdXX"
  7. enum {
  8. Dontpost,
  9. Post,
  10. };
  11. char cputype[64];
  12. char sys[2*64];
  13. char reply[256];
  14. int printcol;
  15. int mflag;
  16. int fflag;
  17. int kflag;
  18. int debugboot;
  19. char *bargv[Nbarg];
  20. int bargc;
  21. static char usbdisk0[] = "/dev/sdU0.0";
  22. static char sdxxctl[] = "/dev/sdXX/ctl";
  23. static void swapproc(void);
  24. static Method *rootserver(char*);
  25. static void kbmap(void);
  26. /*
  27. * run argv[0] (short name is name) and wait awhile for file to appear.
  28. * file must be generated by running argv[0]; if it already exists, we're done.
  29. */
  30. static int
  31. start(char *name, char **argv, char *file)
  32. {
  33. int cnt;
  34. if(access(file, AEXIST) >= 0)
  35. return 0;
  36. if(access(argv[0], AEXIST) < 0) {
  37. fprint(2, "no %s...", argv[0]);
  38. return -1;
  39. }
  40. if(debugboot)
  41. fprint(2, "%s...", name);
  42. runv(argv);
  43. for(cnt = 10; cnt > 0 && access(file, AEXIST) < 0; cnt--)
  44. sleep(100);
  45. if (cnt <= 0) {
  46. fprint(2, "no %s...", name);
  47. return -1;
  48. }
  49. return 0;
  50. }
  51. static int
  52. chmod(char *file, int mode)
  53. {
  54. Dir *dir;
  55. dir = dirstat(file);
  56. if (dir == nil) {
  57. if(debugboot)
  58. fprint(2, "can't stat %s: %r\n", file);
  59. return -1;
  60. }
  61. dir->mode &= ~0777;
  62. dir->mode |= mode & 0777;
  63. dirwstat("/srv/" PARTSRV, dir);
  64. free(dir);
  65. return 0;
  66. }
  67. /* start partfs on first usb disk, if any */
  68. static int
  69. startpartfs(int post)
  70. {
  71. int r, i;
  72. char *parts;
  73. char *partfsv[32];
  74. if(access(usbdisk0, AEXIST) < 0)
  75. return -1; /* can't run partfs until usbd is mounted */
  76. if (post)
  77. remove("/srv/" PARTSRV);
  78. i = 0;
  79. partfsv[i++] = "/boot/partfs";
  80. /*
  81. * hack for booting from usb: if /env/sdB0part (from 9load) exists,
  82. * pass it to partfs for sdXX.
  83. */
  84. parts = getenv("sdB0part");
  85. if (parts != nil) {
  86. partfsv[i++] = "-p";
  87. partfsv[i++] = parts;
  88. }
  89. if (post) {
  90. partfsv[i++] = "-s";
  91. partfsv[i++] = PARTSRV;
  92. }
  93. partfsv[i++] = usbdisk0;
  94. partfsv[i] = nil;
  95. r = start("partfs", partfsv, sdxxctl);
  96. if (post)
  97. chmod("/srv/" PARTSRV, 0666);
  98. return r;
  99. }
  100. static int
  101. mountusb(void)
  102. {
  103. int fd;
  104. if(debugboot)
  105. fprint(2, "mount usbd...");
  106. fd = open("/srv/usb", ORDWR);
  107. if(fd < 0)
  108. warning("can't open /srv/usb");
  109. else if(mount(fd, -1, "/dev", MBEFORE, "") < 0) {
  110. warning("mount -a /srv/usb /dev");
  111. close(fd);
  112. } else
  113. return 0; /* mount closed fd */
  114. return -1;
  115. }
  116. int
  117. mountusbparts(void)
  118. {
  119. mountusb();
  120. return startpartfs(Post);
  121. }
  122. static void
  123. usbinit(int post)
  124. {
  125. int cnt;
  126. static char *usbdv[] = { "/boot/usbd", nil };
  127. if(access("#u/usb/ctl", 0) < 0 || bind("#u", "/dev", MAFTER) < 0)
  128. return;
  129. if(debugboot)
  130. fprint(2, "usbinit...");
  131. start("usbd", usbdv, "/srv/usb");
  132. /* allow a little time for usbd's device discovery */
  133. for(cnt = 20; cnt > 0 && access(usbdisk0, AEXIST) < 0; cnt--)
  134. sleep(100);
  135. if(cnt > 0)
  136. startpartfs(post);
  137. else if(debugboot)
  138. fprint(2, "no usb disk...");
  139. }
  140. void
  141. boot(int argc, char *argv[])
  142. {
  143. int fd, afd;
  144. Method *mp;
  145. char *cmd, cmdbuf[64], *iargv[16];
  146. char rootbuf[64];
  147. int islocal, ishybrid;
  148. char *rp, *rsp;
  149. int iargc, n;
  150. char buf[32];
  151. AuthInfo *ai;
  152. fmtinstall('r', errfmt);
  153. /*
  154. * we should inherit the standard fds all referring to /dev/cons,
  155. * but we're being paranoid.
  156. */
  157. close(0);
  158. close(1);
  159. close(2);
  160. bind("#c", "/dev", MBEFORE);
  161. open("/dev/cons", OREAD);
  162. open("/dev/cons", OWRITE);
  163. open("/dev/cons", OWRITE);
  164. /*
  165. * init will reinitialize its namespace.
  166. * #ec gets us plan9.ini settings (*var variables).
  167. */
  168. bind("#ec", "/env", MREPL);
  169. bind("#e", "/env", MBEFORE|MCREATE);
  170. bind("#s", "/srv/", MREPL|MCREATE);
  171. if(getenv("debugboot"))
  172. debugboot = 1;
  173. #ifdef DEBUG
  174. print("argc=%d\n", argc);
  175. for(fd = 0; fd < argc; fd++)
  176. print("%#p %s ", argv[fd], argv[fd]);
  177. print("\n");
  178. #endif /* DEBUG */
  179. ARGBEGIN{
  180. case 'k':
  181. kflag = 1;
  182. break;
  183. case 'm':
  184. mflag = 1;
  185. break;
  186. case 'f':
  187. fflag = 1;
  188. break;
  189. }ARGEND
  190. readfile("#e/cputype", cputype, sizeof(cputype));
  191. /*
  192. * set up usb keyboard & mouse, if any.
  193. * starts usbd, which mounts itself on /dev.
  194. * starts partfs on first disk, if any, to permit nvram on usb.
  195. */
  196. usbinit(Dontpost);
  197. /*
  198. * pick a method and initialize it
  199. */
  200. if(method[0].name == nil)
  201. fatal("no boot methods");
  202. mp = rootserver(argc ? *argv : 0);
  203. (*mp->config)(mp);
  204. islocal = strcmp(mp->name, "local") == 0;
  205. ishybrid = strcmp(mp->name, "hybrid") == 0;
  206. /*
  207. * load keymap if it's there.
  208. */
  209. kbmap();
  210. /*
  211. * authentication agent
  212. * sets hostowner, creating an auth discontinuity
  213. */
  214. if(debugboot)
  215. fprint(2, "auth...");
  216. authentication(cpuflag);
  217. /* leave existing subprocesses in their own namespace */
  218. rfork(RFNAMEG);
  219. /*
  220. * restart partfs under the new hostowner id
  221. */
  222. usbinit(Post);
  223. /*
  224. * connect to the root file system
  225. */
  226. fd = (*mp->connect)();
  227. if(fd < 0)
  228. fatal("can't connect to file server");
  229. if(getenv("srvold9p"))
  230. fd = old9p(fd);
  231. if(!islocal && !ishybrid){
  232. if(cfs)
  233. fd = (*cfs)(fd);
  234. }
  235. print("version...");
  236. buf[0] = '\0';
  237. n = fversion(fd, 0, buf, sizeof buf);
  238. if(n < 0)
  239. fatal("can't init 9P");
  240. srvcreate("boot", fd);
  241. /*
  242. * create the name space, mount the root fs
  243. */
  244. if(bind("/", "/", MREPL) < 0)
  245. fatal("bind /");
  246. rp = getenv("rootspec");
  247. if(rp == nil)
  248. rp = "";
  249. afd = fauth(fd, rp);
  250. if(afd >= 0){
  251. ai = auth_proxy(afd, auth_getkey, "proto=p9any role=client");
  252. if(ai == nil)
  253. print("authentication failed (%r), trying mount anyways\n");
  254. }
  255. if(mount(fd, afd, "/root", MREPL|MCREATE, rp) < 0)
  256. fatal("mount /");
  257. rsp = rp;
  258. rp = getenv("rootdir");
  259. if(rp == nil)
  260. rp = rootdir;
  261. if(bind(rp, "/", MAFTER|MCREATE) < 0){
  262. if(strncmp(rp, "/root", 5) == 0){
  263. fprint(2, "boot: couldn't bind $rootdir=%s to root: %r\n", rp);
  264. fatal("second bind /");
  265. }
  266. snprint(rootbuf, sizeof rootbuf, "/root/%s", rp);
  267. rp = rootbuf;
  268. if(bind(rp, "/", MAFTER|MCREATE) < 0){
  269. fprint(2, "boot: couldn't bind $rootdir=%s to root: %r\n", rp);
  270. if(strcmp(rootbuf, "/root//plan9") == 0){
  271. fprint(2, "**** warning: remove rootdir=/plan9 entry from plan9.ini\n");
  272. rp = "/root";
  273. if(bind(rp, "/", MAFTER|MCREATE) < 0)
  274. fatal("second bind /");
  275. }else
  276. fatal("second bind /");
  277. }
  278. }
  279. close(fd);
  280. setenv("rootdir", rp);
  281. settime(islocal, afd, rsp);
  282. if(afd > 0)
  283. close(afd);
  284. swapproc();
  285. cmd = getenv("init");
  286. if(cmd == nil){
  287. sprint(cmdbuf, "/%s/init -%s%s", cputype,
  288. cpuflag ? "c" : "t", mflag ? "m" : "");
  289. cmd = cmdbuf;
  290. }
  291. iargc = tokenize(cmd, iargv, nelem(iargv)-1);
  292. cmd = iargv[0];
  293. /* make iargv[0] basename(iargv[0]) */
  294. if(iargv[0] = strrchr(iargv[0], '/'))
  295. iargv[0]++;
  296. else
  297. iargv[0] = cmd;
  298. iargv[iargc] = nil;
  299. chmod("/srv/" PARTSRV, 0600);
  300. exec(cmd, iargv);
  301. fatal(cmd);
  302. }
  303. static Method*
  304. findmethod(char *a)
  305. {
  306. Method *mp;
  307. int i, j;
  308. char *cp;
  309. if((i = strlen(a)) == 0)
  310. return nil;
  311. cp = strchr(a, '!');
  312. if(cp)
  313. i = cp - a;
  314. for(mp = method; mp->name; mp++){
  315. j = strlen(mp->name);
  316. if(j > i)
  317. j = i;
  318. if(strncmp(a, mp->name, j) == 0)
  319. break;
  320. }
  321. if(mp->name)
  322. return mp;
  323. return nil;
  324. }
  325. /*
  326. * ask user from whence cometh the root file system
  327. */
  328. static Method*
  329. rootserver(char *arg)
  330. {
  331. char prompt[256];
  332. Method *mp;
  333. char *cp;
  334. int n;
  335. /* look for required reply */
  336. readfile("#e/nobootprompt", reply, sizeof(reply));
  337. if(reply[0]){
  338. mp = findmethod(reply);
  339. if(mp)
  340. goto HaveMethod;
  341. print("boot method %s not found\n", reply);
  342. reply[0] = 0;
  343. }
  344. /* make list of methods */
  345. mp = method;
  346. n = sprint(prompt, "root is from (%s", mp->name);
  347. for(mp++; mp->name; mp++)
  348. n += sprint(prompt+n, ", %s", mp->name);
  349. sprint(prompt+n, ")");
  350. /* create default reply */
  351. readfile("#e/bootargs", reply, sizeof(reply));
  352. if(reply[0] == 0 && arg != 0)
  353. strcpy(reply, arg);
  354. if(reply[0]){
  355. mp = findmethod(reply);
  356. if(mp == 0)
  357. reply[0] = 0;
  358. }
  359. if(reply[0] == 0)
  360. strcpy(reply, method->name);
  361. /* parse replies */
  362. do{
  363. outin(prompt, reply, sizeof(reply));
  364. mp = findmethod(reply);
  365. }while(mp == nil);
  366. HaveMethod:
  367. bargc = tokenize(reply, bargv, Nbarg-2);
  368. bargv[bargc] = nil;
  369. cp = strchr(reply, '!');
  370. if(cp)
  371. strcpy(sys, cp+1);
  372. return mp;
  373. }
  374. static void
  375. swapproc(void)
  376. {
  377. int fd;
  378. fd = open("#c/swap", OWRITE);
  379. if(fd < 0){
  380. warning("opening #c/swap");
  381. return;
  382. }
  383. if(write(fd, "start", 5) <= 0)
  384. warning("starting swap kproc");
  385. close(fd);
  386. }
  387. int
  388. old9p(int fd)
  389. {
  390. int p[2];
  391. if(pipe(p) < 0)
  392. fatal("pipe");
  393. print("srvold9p...");
  394. switch(fork()) {
  395. case -1:
  396. fatal("rfork srvold9p");
  397. case 0:
  398. dup(fd, 1);
  399. close(fd);
  400. dup(p[0], 0);
  401. close(p[0]);
  402. close(p[1]);
  403. execl("/srvold9p", "srvold9p", "-s", 0);
  404. fatal("exec srvold9p");
  405. default:
  406. close(fd);
  407. close(p[0]);
  408. }
  409. return p[1];
  410. }
  411. static void
  412. kbmap(void)
  413. {
  414. char *f;
  415. int n, in, out;
  416. char buf[1024];
  417. f = getenv("kbmap");
  418. if(f == nil)
  419. return;
  420. if(bind("#κ", "/dev", MAFTER) < 0){
  421. warning("can't bind #κ");
  422. return;
  423. }
  424. in = open(f, OREAD);
  425. if(in < 0){
  426. warning("can't open kbd map");
  427. return;
  428. }
  429. out = open("/dev/kbmap", OWRITE);
  430. if(out < 0) {
  431. warning("can't open /dev/kbmap");
  432. close(in);
  433. return;
  434. }
  435. while((n = read(in, buf, sizeof(buf))) > 0)
  436. if(write(out, buf, n) != n){
  437. warning("write to /dev/kbmap failed");
  438. break;
  439. }
  440. close(in);
  441. close(out);
  442. }