menu.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724
  1. /*
  2. * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
  3. * The President and Fellows of Harvard College.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions
  7. * are met:
  8. * 1. Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * 2. Redistributions in binary form must reproduce the above copyright
  11. * notice, this list of conditions and the following disclaimer in the
  12. * documentation and/or other materials provided with the distribution.
  13. * 3. Neither the name of the University nor the names of its contributors
  14. * may be used to endorse or promote products derived from this software
  15. * without specific prior written permission.
  16. *
  17. * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
  18. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  19. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  20. * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
  21. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  22. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  23. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  24. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  25. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  26. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  27. * SUCH DAMAGE.
  28. */
  29. #include <types.h>
  30. #include <kern/errno.h>
  31. #include <kern/reboot.h>
  32. #include <kern/unistd.h>
  33. #include <limits.h>
  34. #include <lib.h>
  35. #include <uio.h>
  36. #include <clock.h>
  37. #include <thread.h>
  38. #include <proc.h>
  39. #include <synch.h>
  40. #include <vfs.h>
  41. #include <sfs.h>
  42. #include <syscall.h>
  43. #include <test.h>
  44. #include "opt-synchprobs.h"
  45. #include "opt-sfs.h"
  46. #include "opt-net.h"
  47. /*
  48. * In-kernel menu and command dispatcher.
  49. */
  50. #define _PATH_SHELL "/bin/sh"
  51. #define MAXMENUARGS 16
  52. // XXX this should not be in this file
  53. void
  54. getinterval(time_t s1, uint32_t ns1, time_t s2, uint32_t ns2,
  55. time_t *rs, uint32_t *rns)
  56. {
  57. if (ns2 < ns1) {
  58. ns2 += 1000000000;
  59. s2--;
  60. }
  61. *rns = ns2 - ns1;
  62. *rs = s2 - s1;
  63. }
  64. ////////////////////////////////////////////////////////////
  65. //
  66. // Command menu functions
  67. /*
  68. * Function for a thread that runs an arbitrary userlevel program by
  69. * name.
  70. *
  71. * Note: this cannot pass arguments to the program. You may wish to
  72. * change it so it can, because that will make testing much easier
  73. * in the future.
  74. *
  75. * It copies the program name because runprogram destroys the copy
  76. * it gets by passing it to vfs_open().
  77. */
  78. static
  79. void
  80. cmd_progthread(void *ptr, unsigned long nargs)
  81. {
  82. char **args = ptr;
  83. char progname[128];
  84. int result;
  85. KASSERT(nargs >= 1);
  86. if (nargs > 2) {
  87. kprintf("Warning: argument passing from menu not supported\n");
  88. }
  89. /* Hope we fit. */
  90. KASSERT(strlen(args[0]) < sizeof(progname));
  91. strcpy(progname, args[0]);
  92. result = runprogram(progname);
  93. if (result) {
  94. kprintf("Running program %s failed: %s\n", args[0],
  95. strerror(result));
  96. return;
  97. }
  98. /* NOTREACHED: runprogram only returns on error. */
  99. }
  100. /*
  101. * Common code for cmd_prog and cmd_shell.
  102. *
  103. * Note that this does not wait for the subprogram to finish, but
  104. * returns immediately to the menu. This is usually not what you want,
  105. * so you should have it call your system-calls-assignment waitpid
  106. * code after forking.
  107. *
  108. * Also note that because the subprogram's thread uses the "args"
  109. * array and strings, until you do this a race condition exists
  110. * between that code and the menu input code.
  111. */
  112. static
  113. int
  114. common_prog(int nargs, char **args)
  115. {
  116. struct proc *proc;
  117. int result;
  118. #if OPT_SYNCHPROBS
  119. kprintf("Warning: this probably won't work with a "
  120. "synchronization-problems kernel.\n");
  121. #endif
  122. /* Create a process for the new program to run in. */
  123. proc = proc_create_runprogram(args[0] /* name */);
  124. if (proc == NULL) {
  125. return ENOMEM;
  126. }
  127. result = thread_fork(args[0] /* thread name */,
  128. proc /* new process */,
  129. cmd_progthread /* thread function */,
  130. args /* thread arg */, nargs /* thread arg */);
  131. if (result) {
  132. kprintf("thread_fork failed: %s\n", strerror(result));
  133. proc_destroy(proc);
  134. return result;
  135. }
  136. #ifdef UW
  137. /* wait until the process we have just launched - and any others that it
  138. may fork - is finished before proceeding */
  139. P(no_proc_sem);
  140. #endif // UW
  141. return 0;
  142. }
  143. /*
  144. * Command for running an arbitrary userlevel program.
  145. */
  146. static
  147. int
  148. cmd_prog(int nargs, char **args)
  149. {
  150. if (nargs < 2) {
  151. kprintf("Usage: p program [arguments]\n");
  152. return EINVAL;
  153. }
  154. /* drop the leading "p" */
  155. args++;
  156. nargs--;
  157. return common_prog(nargs, args);
  158. }
  159. /*
  160. * Command for starting the system shell.
  161. */
  162. static
  163. int
  164. cmd_shell(int nargs, char **args)
  165. {
  166. (void)args;
  167. if (nargs != 1) {
  168. kprintf("Usage: s\n");
  169. return EINVAL;
  170. }
  171. args[0] = (char *)_PATH_SHELL;
  172. return common_prog(nargs, args);
  173. }
  174. /*
  175. * Command for changing directory.
  176. */
  177. static
  178. int
  179. cmd_chdir(int nargs, char **args)
  180. {
  181. if (nargs != 2) {
  182. kprintf("Usage: cd directory\n");
  183. return EINVAL;
  184. }
  185. return vfs_chdir(args[1]);
  186. }
  187. /*
  188. * Command for printing the current directory.
  189. */
  190. static
  191. int
  192. cmd_pwd(int nargs, char **args)
  193. {
  194. char buf[PATH_MAX+1];
  195. int result;
  196. struct iovec iov;
  197. struct uio ku;
  198. (void)nargs;
  199. (void)args;
  200. uio_kinit(&iov, &ku, buf, sizeof(buf)-1, 0, UIO_READ);
  201. result = vfs_getcwd(&ku);
  202. if (result) {
  203. kprintf("vfs_getcwd failed (%s)\n", strerror(result));
  204. return result;
  205. }
  206. /* null terminate */
  207. buf[sizeof(buf)-1-ku.uio_resid] = 0;
  208. /* print it */
  209. kprintf("%s\n", buf);
  210. return 0;
  211. }
  212. /*
  213. * Command for running sync.
  214. */
  215. static
  216. int
  217. cmd_sync(int nargs, char **args)
  218. {
  219. (void)nargs;
  220. (void)args;
  221. vfs_sync();
  222. return 0;
  223. }
  224. /*
  225. * Command for doing an intentional panic.
  226. */
  227. static
  228. int
  229. cmd_panic(int nargs, char **args)
  230. {
  231. (void)nargs;
  232. (void)args;
  233. panic("User requested panic\n");
  234. return 0;
  235. }
  236. /*
  237. * Command for shutting down.
  238. */
  239. static
  240. int
  241. cmd_quit(int nargs, char **args)
  242. {
  243. (void)nargs;
  244. (void)args;
  245. vfs_sync();
  246. sys_reboot(RB_POWEROFF);
  247. thread_exit();
  248. return 0;
  249. }
  250. /*
  251. * Command for mounting a filesystem.
  252. */
  253. /* Table of mountable filesystem types. */
  254. static const struct {
  255. const char *name;
  256. int (*func)(const char *device);
  257. } mounttable[] = {
  258. #if OPT_SFS
  259. { "sfs", sfs_mount },
  260. #endif
  261. { NULL, NULL }
  262. };
  263. static
  264. int
  265. cmd_mount(int nargs, char **args)
  266. {
  267. char *fstype;
  268. char *device;
  269. int i;
  270. if (nargs != 3) {
  271. kprintf("Usage: mount fstype device:\n");
  272. return EINVAL;
  273. }
  274. fstype = args[1];
  275. device = args[2];
  276. /* Allow (but do not require) colon after device name */
  277. if (device[strlen(device)-1]==':') {
  278. device[strlen(device)-1] = 0;
  279. }
  280. for (i=0; mounttable[i].name; i++) {
  281. if (!strcmp(mounttable[i].name, fstype)) {
  282. return mounttable[i].func(device);
  283. }
  284. }
  285. kprintf("Unknown filesystem type %s\n", fstype);
  286. return EINVAL;
  287. }
  288. static
  289. int
  290. cmd_unmount(int nargs, char **args)
  291. {
  292. char *device;
  293. if (nargs != 2) {
  294. kprintf("Usage: unmount device:\n");
  295. return EINVAL;
  296. }
  297. device = args[1];
  298. /* Allow (but do not require) colon after device name */
  299. if (device[strlen(device)-1]==':') {
  300. device[strlen(device)-1] = 0;
  301. }
  302. return vfs_unmount(device);
  303. }
  304. /*
  305. * Command to set the "boot fs".
  306. *
  307. * The boot filesystem is the one that pathnames like /bin/sh with
  308. * leading slashes refer to.
  309. *
  310. * The default bootfs is "emu0".
  311. */
  312. static
  313. int
  314. cmd_bootfs(int nargs, char **args)
  315. {
  316. char *device;
  317. if (nargs != 2) {
  318. kprintf("Usage: bootfs device\n");
  319. return EINVAL;
  320. }
  321. device = args[1];
  322. /* Allow (but do not require) colon after device name */
  323. if (device[strlen(device)-1]==':') {
  324. device[strlen(device)-1] = 0;
  325. }
  326. return vfs_setbootfs(device);
  327. }
  328. static
  329. int
  330. cmd_kheapstats(int nargs, char **args)
  331. {
  332. (void)nargs;
  333. (void)args;
  334. kheap_printstats();
  335. return 0;
  336. }
  337. ////////////////////////////////////////
  338. //
  339. // Menus.
  340. static
  341. void
  342. showmenu(const char *name, const char *x[])
  343. {
  344. int ct, half, i;
  345. kprintf("\n");
  346. kprintf("%s\n", name);
  347. for (i=ct=0; x[i]; i++) {
  348. ct++;
  349. }
  350. half = (ct+1)/2;
  351. for (i=0; i<half; i++) {
  352. kprintf(" %-36s", x[i]);
  353. if (i+half < ct) {
  354. kprintf("%s", x[i+half]);
  355. }
  356. kprintf("\n");
  357. }
  358. kprintf("\n");
  359. }
  360. static const char *opsmenu[] = {
  361. "[s] Shell ",
  362. "[p] Other program ",
  363. "[mount] Mount a filesystem ",
  364. "[unmount] Unmount a filesystem ",
  365. "[bootfs] Set \"boot\" filesystem ",
  366. "[pf] Print a file ",
  367. "[cd] Change directory ",
  368. "[pwd] Print current directory ",
  369. "[sync] Sync filesystems ",
  370. "[panic] Intentional panic ",
  371. "[dth] Enable DB_THREADS msgs ",
  372. "[q] Quit and shut down ",
  373. NULL
  374. };
  375. static
  376. int
  377. cmd_opsmenu(int n, char **a)
  378. {
  379. (void)n;
  380. (void)a;
  381. showmenu("OS/161 operations menu", opsmenu);
  382. return 0;
  383. }
  384. static const char *testmenu[] = {
  385. "[at] Array test ",
  386. "[bt] Bitmap test ",
  387. "[km1] Kernel malloc test ",
  388. "[km2] kmalloc stress test ",
  389. "[tt1] Thread test 1 ",
  390. "[tt2] Thread test 2 ",
  391. "[tt3] Thread test 3 ",
  392. #if OPT_NET
  393. "[net] Network test ",
  394. #endif
  395. "[sy1] Semaphore test ",
  396. "[sy2] Lock test (1) ",
  397. "[sy3] CV test (1) ",
  398. #ifdef UW
  399. "[uw1] UW lock test (1) ",
  400. "[uw2] UW vmstats test (3) ",
  401. #endif // UW
  402. "[fs1] Filesystem test ",
  403. "[fs2] FS read stress (4) ",
  404. "[fs3] FS write stress (4) ",
  405. "[fs4] FS write stress 2 (4) ",
  406. "[fs5] FS create stress (4) ",
  407. NULL
  408. };
  409. static
  410. int
  411. cmd_testmenu(int n, char **a)
  412. {
  413. (void)n;
  414. (void)a;
  415. showmenu("OS/161 tests menu", testmenu);
  416. kprintf(" (1) These tests will fail until you finish the "
  417. "synch assignment.\n");
  418. kprintf(" (4) These tests may fail until you finish the "
  419. "file system assignment.\n");
  420. kprintf("\n");
  421. return 0;
  422. }
  423. static const char *mainmenu[] = {
  424. "[?o] Operations menu ",
  425. "[?t] Tests menu ",
  426. #if OPT_SYNCHPROBS
  427. "[sp1] Whale Mating ",
  428. #ifdef UW
  429. "[sp2] Cat/mouse ",
  430. "[sp3] Traffic ",
  431. #endif /* UW */
  432. #endif
  433. "[kh] Kernel heap stats ",
  434. "[q] Quit and shut down ",
  435. NULL
  436. };
  437. static
  438. int
  439. cmd_mainmenu(int n, char **a)
  440. {
  441. (void)n;
  442. (void)a;
  443. showmenu("OS/161 kernel menu", mainmenu);
  444. return 0;
  445. }
  446. static int cmd_dth(int nargs, char **args)
  447. {
  448. (void)nargs;
  449. (void)args;
  450. dbflags = DB_THREADS;
  451. return 0;
  452. }
  453. ////////////////////////////////////////
  454. //
  455. // Command table.
  456. static struct {
  457. const char *name;
  458. int (*func)(int nargs, char **args);
  459. } cmdtable[] = {
  460. /* menus */
  461. { "?", cmd_mainmenu },
  462. { "h", cmd_mainmenu },
  463. { "help", cmd_mainmenu },
  464. { "?o", cmd_opsmenu },
  465. { "?t", cmd_testmenu },
  466. /* operations */
  467. { "s", cmd_shell },
  468. { "p", cmd_prog },
  469. { "mount", cmd_mount },
  470. { "unmount", cmd_unmount },
  471. { "bootfs", cmd_bootfs },
  472. { "pf", printfile },
  473. { "cd", cmd_chdir },
  474. { "pwd", cmd_pwd },
  475. { "sync", cmd_sync },
  476. { "panic", cmd_panic },
  477. { "q", cmd_quit },
  478. { "exit", cmd_quit },
  479. { "halt", cmd_quit },
  480. { "dth", cmd_dth },
  481. #if OPT_SYNCHPROBS
  482. /* in-kernel synchronization problem(s) */
  483. { "sp1", whalemating },
  484. #ifdef UW
  485. { "sp2", catmouse },
  486. { "sp3", traffic_simulation },
  487. #endif /* UW */
  488. #endif
  489. /* stats */
  490. { "kh", cmd_kheapstats },
  491. /* base system tests */
  492. { "at", arraytest },
  493. { "bt", bitmaptest },
  494. { "km1", malloctest },
  495. { "km2", mallocstress },
  496. #if OPT_NET
  497. { "net", nettest },
  498. #endif
  499. { "tt1", threadtest },
  500. { "tt2", threadtest2 },
  501. { "tt3", threadtest3 },
  502. { "sy1", semtest },
  503. /* synchronization assignment tests */
  504. { "sy2", locktest },
  505. { "sy3", cvtest },
  506. #ifdef UW
  507. { "uw1", uwlocktest1 },
  508. { "uw2", uwvmstatstest },
  509. #endif
  510. /* file system assignment tests */
  511. { "fs1", fstest },
  512. { "fs2", readstress },
  513. { "fs3", writestress },
  514. { "fs4", writestress2 },
  515. { "fs5", createstress },
  516. { NULL, NULL }
  517. };
  518. /*
  519. * Process a single command.
  520. */
  521. static
  522. int
  523. cmd_dispatch(char *cmd)
  524. {
  525. time_t beforesecs, aftersecs, secs;
  526. uint32_t beforensecs, afternsecs, nsecs;
  527. char *args[MAXMENUARGS];
  528. int nargs=0;
  529. char *word;
  530. char *context;
  531. int i, result;
  532. for (word = strtok_r(cmd, " \t", &context);
  533. word != NULL;
  534. word = strtok_r(NULL, " \t", &context)) {
  535. if (nargs >= MAXMENUARGS) {
  536. kprintf("Command line has too many words\n");
  537. return E2BIG;
  538. }
  539. args[nargs++] = word;
  540. }
  541. if (nargs==0) {
  542. return 0;
  543. }
  544. for (i=0; cmdtable[i].name; i++) {
  545. if (*cmdtable[i].name && !strcmp(args[0], cmdtable[i].name)) {
  546. KASSERT(cmdtable[i].func!=NULL);
  547. gettime(&beforesecs, &beforensecs);
  548. result = cmdtable[i].func(nargs, args);
  549. gettime(&aftersecs, &afternsecs);
  550. getinterval(beforesecs, beforensecs,
  551. aftersecs, afternsecs,
  552. &secs, &nsecs);
  553. kprintf("Operation took %lu.%09lu seconds\n",
  554. (unsigned long) secs,
  555. (unsigned long) nsecs);
  556. return result;
  557. }
  558. }
  559. kprintf("%s: Command not found\n", args[0]);
  560. return EINVAL;
  561. }
  562. /*
  563. * Evaluate a command line that may contain multiple semicolon-delimited
  564. * commands.
  565. *
  566. * If "isargs" is set, we're doing command-line processing; print the
  567. * comamnds as we execute them and panic if the command is invalid or fails.
  568. */
  569. static
  570. void
  571. menu_execute(char *line, int isargs)
  572. {
  573. char *command;
  574. char *context;
  575. int result;
  576. for (command = strtok_r(line, ";", &context);
  577. command != NULL;
  578. command = strtok_r(NULL, ";", &context)) {
  579. if (isargs) {
  580. kprintf("OS/161 kernel: %s\n", command);
  581. }
  582. result = cmd_dispatch(command);
  583. if (result) {
  584. kprintf("Menu command failed: %s\n", strerror(result));
  585. if (isargs) {
  586. panic("Failure processing kernel arguments\n");
  587. }
  588. }
  589. }
  590. }
  591. /*
  592. * Command menu main loop.
  593. *
  594. * First, handle arguments passed on the kernel's command line from
  595. * the bootloader. Then loop prompting for commands.
  596. *
  597. * The line passed in from the bootloader is treated as if it had been
  598. * typed at the prompt. Semicolons separate commands; spaces and tabs
  599. * separate words (command names and arguments).
  600. *
  601. * So, for instance, to mount an SFS on lhd0 and make it the boot
  602. * filesystem, and then boot directly into the shell, one would use
  603. * the kernel command line
  604. *
  605. * "mount sfs lhd0; bootfs lhd0; s"
  606. */
  607. void
  608. menu(char *args)
  609. {
  610. char buf[64];
  611. menu_execute(args, 1);
  612. while (1) {
  613. kprintf("OS/161 kernel [? for menu]: ");
  614. kgets(buf, sizeof(buf));
  615. menu_execute(buf, 0);
  616. }
  617. }