boot.c 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439
  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 void swapproc(void);
  22. static Method *rootserver(char*);
  23. static void kbmap(void);
  24. /*
  25. * we should inherit the standard fds all referring to /dev/cons,
  26. * but we're being paranoid.
  27. */
  28. static void
  29. opencons(void)
  30. {
  31. close(0);
  32. close(1);
  33. close(2);
  34. bind("#c", "/dev", MBEFORE);
  35. open("/dev/cons", OREAD);
  36. open("/dev/cons", OWRITE);
  37. open("/dev/cons", OWRITE);
  38. }
  39. /*
  40. * init will reinitialize its namespace.
  41. * #ec gets us plan9.ini settings (*var variables).
  42. */
  43. static void
  44. bindenvsrv(void)
  45. {
  46. bind("#ec", "/env", MREPL);
  47. bind("#e", "/env", MBEFORE|MCREATE);
  48. bind("#s", "/srv/", MREPL|MCREATE);
  49. }
  50. static void
  51. debuginit(int argc, char **argv)
  52. {
  53. int fd;
  54. if(getenv("debugboot"))
  55. debugboot = 1;
  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. SET(fd, argc, argv); USED(fd, argc, argv);
  63. }
  64. /*
  65. * read disk partition tables here so that readnvram via factotum
  66. * can see them. ideally we would have this information in
  67. * environment variables before attaching #S, which would then
  68. * parse them and create partitions.
  69. */
  70. static void
  71. partinit(void)
  72. {
  73. char *rdparts;
  74. rdparts = getenv("readparts");
  75. if(rdparts)
  76. readparts();
  77. free(rdparts);
  78. }
  79. /*
  80. * pick a method and initialize it
  81. */
  82. static Method *
  83. pickmethod(int argc, char **argv)
  84. {
  85. Method *mp;
  86. if(method[0].name == nil)
  87. fatal("no boot methods");
  88. mp = rootserver(argc ? *argv : 0);
  89. (*mp->config)(mp);
  90. return mp;
  91. }
  92. /*
  93. * authentication agent
  94. * sets hostowner, creating an auth discontinuity
  95. */
  96. static void
  97. doauth(int cpuflag)
  98. {
  99. if(debugboot)
  100. fprint(2, "auth...");
  101. authentication(cpuflag);
  102. }
  103. /*
  104. * connect to the root file system
  105. */
  106. static int
  107. connectroot(Method *mp, int islocal, int ishybrid)
  108. {
  109. int fd, n;
  110. char buf[32];
  111. fd = (*mp->connect)();
  112. if(fd < 0)
  113. fatal("can't connect to file server");
  114. if(getenv("srvold9p"))
  115. fd = old9p(fd);
  116. if(!islocal && !ishybrid){
  117. if(cfs)
  118. fd = (*cfs)(fd);
  119. }
  120. print("version...");
  121. buf[0] = '\0';
  122. n = fversion(fd, 0, buf, sizeof buf);
  123. if(n < 0)
  124. fatal("can't init 9P");
  125. srvcreate("boot", fd);
  126. return fd;
  127. }
  128. /*
  129. * create the name space, mount the root fs
  130. */
  131. static int
  132. nsinit(int fd, char **rspp)
  133. {
  134. int afd;
  135. char *rp, *rsp;
  136. AuthInfo *ai;
  137. static char rootbuf[64];
  138. if(bind("/", "/", MREPL) < 0)
  139. fatal("bind /");
  140. rp = getenv("rootspec");
  141. if(rp == nil)
  142. rp = "";
  143. afd = fauth(fd, rp);
  144. if(afd >= 0){
  145. ai = auth_proxy(afd, auth_getkey, "proto=p9any role=client");
  146. if(ai == nil)
  147. print("authentication failed (%r), trying mount anyways\n");
  148. }
  149. if(mount(fd, afd, "/root", MREPL|MCREATE, rp) < 0)
  150. fatal("mount /");
  151. rsp = rp;
  152. rp = getenv("rootdir");
  153. if(rp == nil)
  154. rp = rootdir;
  155. if(bind(rp, "/", MAFTER|MCREATE) < 0){
  156. if(strncmp(rp, "/root", 5) == 0){
  157. fprint(2, "boot: couldn't bind $rootdir=%s to root: %r\n", rp);
  158. fatal("second bind /");
  159. }
  160. snprint(rootbuf, sizeof rootbuf, "/root/%s", rp);
  161. rp = rootbuf;
  162. if(bind(rp, "/", MAFTER|MCREATE) < 0){
  163. fprint(2, "boot: couldn't bind $rootdir=%s to root: %r\n", rp);
  164. if(strcmp(rootbuf, "/root//plan9") != 0)
  165. fatal("second bind /");
  166. /* undo installer's work */
  167. fprint(2, "**** warning: remove rootdir=/plan9 "
  168. "entry from plan9.ini\n");
  169. rp = "/root";
  170. if(bind(rp, "/", MAFTER|MCREATE) < 0)
  171. fatal("second bind /");
  172. }
  173. }
  174. setenv("rootdir", rp);
  175. *rspp = rsp;
  176. return afd;
  177. }
  178. static void
  179. execinit(void)
  180. {
  181. int iargc;
  182. char *cmd, cmdbuf[64], *iargv[16];
  183. /* exec init */
  184. cmd = getenv("init");
  185. if(cmd == nil){
  186. sprint(cmdbuf, "/%s/init -%s%s", cputype,
  187. cpuflag ? "c" : "t", mflag ? "m" : "");
  188. cmd = cmdbuf;
  189. }
  190. iargc = tokenize(cmd, iargv, nelem(iargv)-1);
  191. cmd = iargv[0];
  192. /* make iargv[0] basename(iargv[0]) */
  193. if(iargv[0] = strrchr(iargv[0], '/'))
  194. iargv[0]++;
  195. else
  196. iargv[0] = cmd;
  197. iargv[iargc] = nil;
  198. chmod("/srv/" PARTSRV, 0600);
  199. exec(cmd, iargv);
  200. fatal(cmd);
  201. }
  202. void
  203. boot(int argc, char *argv[])
  204. {
  205. int fd, afd, islocal, ishybrid;
  206. char *rsp;
  207. Method *mp;
  208. fmtinstall('r', errfmt);
  209. opencons();
  210. bindenvsrv();
  211. debuginit(argc, argv);
  212. ARGBEGIN{
  213. case 'k':
  214. kflag = 1;
  215. break;
  216. case 'm':
  217. mflag = 1;
  218. break;
  219. case 'f':
  220. fflag = 1;
  221. break;
  222. }ARGEND
  223. readfile("#e/cputype", cputype, sizeof(cputype));
  224. /*
  225. * set up usb keyboard & mouse, if any.
  226. * starts partfs on first disk, if any, to permit nvram on usb.
  227. */
  228. usbinit(Dontpost);
  229. mp = pickmethod(argc, argv);
  230. islocal = strcmp(mp->name, "local") == 0;
  231. ishybrid = strcmp(mp->name, "hybrid") == 0;
  232. kbmap(); /* load keymap if it's there. */
  233. /* don't trigger aoe until the network has been configured */
  234. bind("#æ", "/dev", MAFTER); /* nvram could be here */
  235. bind("#S", "/dev", MAFTER); /* nvram could be here */
  236. partinit();
  237. doauth(cpuflag); /* authentication usually changes hostowner */
  238. rfork(RFNAMEG); /* leave existing subprocs in own namespace */
  239. usbinit(Post); /* restart partfs under the new hostowner id */
  240. fd = connectroot(mp, islocal, ishybrid);
  241. afd = nsinit(fd, &rsp);
  242. close(fd);
  243. settime(islocal, afd, rsp);
  244. if(afd > 0)
  245. close(afd);
  246. swapproc();
  247. execinit();
  248. exits("failed to exec init");
  249. }
  250. static Method*
  251. findmethod(char *a)
  252. {
  253. Method *mp;
  254. int i, j;
  255. char *cp;
  256. if((i = strlen(a)) == 0)
  257. return nil;
  258. cp = strchr(a, '!');
  259. if(cp)
  260. i = cp - a;
  261. for(mp = method; mp->name; mp++){
  262. j = strlen(mp->name);
  263. if(j > i)
  264. j = i;
  265. if(strncmp(a, mp->name, j) == 0)
  266. break;
  267. }
  268. if(mp->name)
  269. return mp;
  270. return nil;
  271. }
  272. /*
  273. * ask user from whence cometh the root file system
  274. */
  275. static Method*
  276. rootserver(char *arg)
  277. {
  278. char prompt[256];
  279. Method *mp;
  280. char *cp;
  281. int n;
  282. /* look for required reply */
  283. readfile("#e/nobootprompt", reply, sizeof(reply));
  284. if(reply[0]){
  285. mp = findmethod(reply);
  286. if(mp)
  287. goto HaveMethod;
  288. print("boot method %s not found\n", reply);
  289. reply[0] = 0;
  290. }
  291. /* make list of methods */
  292. mp = method;
  293. n = sprint(prompt, "root is from (%s", mp->name);
  294. for(mp++; mp->name; mp++)
  295. n += sprint(prompt+n, ", %s", mp->name);
  296. sprint(prompt+n, ")");
  297. /* create default reply */
  298. readfile("#e/bootargs", reply, sizeof(reply));
  299. if(reply[0] == 0 && arg != 0)
  300. strcpy(reply, arg);
  301. if(reply[0]){
  302. mp = findmethod(reply);
  303. if(mp == 0)
  304. reply[0] = 0;
  305. }
  306. if(reply[0] == 0)
  307. strcpy(reply, method->name);
  308. /* parse replies */
  309. do{
  310. outin(prompt, reply, sizeof(reply));
  311. mp = findmethod(reply);
  312. }while(mp == nil);
  313. HaveMethod:
  314. bargc = tokenize(reply, bargv, Nbarg-2);
  315. bargv[bargc] = nil;
  316. cp = strchr(reply, '!');
  317. if(cp)
  318. strcpy(sys, cp+1);
  319. return mp;
  320. }
  321. static void
  322. swapproc(void)
  323. {
  324. int fd;
  325. fd = open("#c/swap", OWRITE);
  326. if(fd < 0){
  327. warning("opening #c/swap");
  328. return;
  329. }
  330. if(write(fd, "start", 5) <= 0)
  331. warning("starting swap kproc");
  332. close(fd);
  333. }
  334. int
  335. old9p(int fd)
  336. {
  337. int p[2];
  338. if(pipe(p) < 0)
  339. fatal("pipe");
  340. print("srvold9p...");
  341. switch(fork()) {
  342. case -1:
  343. fatal("rfork srvold9p");
  344. case 0:
  345. dup(fd, 1);
  346. close(fd);
  347. dup(p[0], 0);
  348. close(p[0]);
  349. close(p[1]);
  350. execl("/srvold9p", "srvold9p", "-s", 0);
  351. fatal("exec srvold9p");
  352. default:
  353. close(fd);
  354. close(p[0]);
  355. }
  356. return p[1];
  357. }
  358. static void
  359. kbmap(void)
  360. {
  361. char *f;
  362. int n, in, out;
  363. char buf[1024];
  364. f = getenv("kbmap");
  365. if(f == nil)
  366. return;
  367. if(bind("#κ", "/dev", MAFTER) < 0){
  368. warning("can't bind #κ");
  369. return;
  370. }
  371. in = open(f, OREAD);
  372. if(in < 0){
  373. warning("can't open kbd map");
  374. return;
  375. }
  376. out = open("/dev/kbmap", OWRITE);
  377. if(out < 0) {
  378. warning("can't open /dev/kbmap");
  379. close(in);
  380. return;
  381. }
  382. while((n = read(in, buf, sizeof(buf))) > 0)
  383. if(write(out, buf, n) != n){
  384. warning("write to /dev/kbmap failed");
  385. break;
  386. }
  387. close(in);
  388. close(out);
  389. }