boot.c 7.0 KB

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