menu.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720
  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. /* Hope we fit. */
  87. KASSERT(strlen(args[0]) < sizeof(progname));
  88. strcpy(progname, args[0]);
  89. result = runprogram(progname, nargs, args);
  90. if (result) {
  91. kprintf("Running program %s failed: %s\n", args[0],
  92. strerror(result));
  93. return;
  94. }
  95. /* NOTREACHED: runprogram only returns on error. */
  96. }
  97. /*
  98. * Common code for cmd_prog and cmd_shell.
  99. *
  100. * Note that this does not wait for the subprogram to finish, but
  101. * returns immediately to the menu. This is usually not what you want,
  102. * so you should have it call your system-calls-assignment waitpid
  103. * code after forking.
  104. *
  105. * Also note that because the subprogram's thread uses the "args"
  106. * array and strings, until you do this a race condition exists
  107. * between that code and the menu input code.
  108. */
  109. static
  110. int
  111. common_prog(int nargs, char **args)
  112. {
  113. struct proc *proc;
  114. int result;
  115. #if OPT_SYNCHPROBS
  116. kprintf("Warning: this probably won't work with a "
  117. "synchronization-problems kernel.\n");
  118. #endif
  119. /* Create a process for the new program to run in. */
  120. proc = proc_create_runprogram(args[0] /* name */);
  121. if (proc == NULL) {
  122. return ENOMEM;
  123. }
  124. result = thread_fork(args[0] /* thread name */,
  125. proc /* new process */,
  126. cmd_progthread /* thread function */,
  127. args /* thread arg */, nargs /* thread arg */);
  128. if (result) {
  129. kprintf("thread_fork failed: %s\n", strerror(result));
  130. proc_destroy(proc);
  131. return result;
  132. }
  133. #ifdef UW
  134. /* wait until the process we have just launched - and any others that it
  135. may fork - is finished before proceeding */
  136. P(no_proc_sem);
  137. #endif // UW
  138. return 0;
  139. }
  140. /*
  141. * Command for running an arbitrary userlevel program.
  142. */
  143. static
  144. int
  145. cmd_prog(int nargs, char **args)
  146. {
  147. if (nargs < 2) {
  148. kprintf("Usage: p program [arguments]\n");
  149. return EINVAL;
  150. }
  151. /* drop the leading "p" */
  152. args++;
  153. nargs--;
  154. return common_prog(nargs, args);
  155. }
  156. /*
  157. * Command for starting the system shell.
  158. */
  159. static
  160. int
  161. cmd_shell(int nargs, char **args)
  162. {
  163. (void)args;
  164. if (nargs != 1) {
  165. kprintf("Usage: s\n");
  166. return EINVAL;
  167. }
  168. args[0] = (char *)_PATH_SHELL;
  169. return common_prog(nargs, args);
  170. }
  171. /*
  172. * Command for changing directory.
  173. */
  174. static
  175. int
  176. cmd_chdir(int nargs, char **args)
  177. {
  178. if (nargs != 2) {
  179. kprintf("Usage: cd directory\n");
  180. return EINVAL;
  181. }
  182. return vfs_chdir(args[1]);
  183. }
  184. /*
  185. * Command for printing the current directory.
  186. */
  187. static
  188. int
  189. cmd_pwd(int nargs, char **args)
  190. {
  191. char buf[PATH_MAX+1];
  192. int result;
  193. struct iovec iov;
  194. struct uio ku;
  195. (void)nargs;
  196. (void)args;
  197. uio_kinit(&iov, &ku, buf, sizeof(buf)-1, 0, UIO_READ);
  198. result = vfs_getcwd(&ku);
  199. if (result) {
  200. kprintf("vfs_getcwd failed (%s)\n", strerror(result));
  201. return result;
  202. }
  203. /* null terminate */
  204. buf[sizeof(buf)-1-ku.uio_resid] = 0;
  205. /* print it */
  206. kprintf("%s\n", buf);
  207. return 0;
  208. }
  209. /*
  210. * Command for running sync.
  211. */
  212. static
  213. int
  214. cmd_sync(int nargs, char **args)
  215. {
  216. (void)nargs;
  217. (void)args;
  218. vfs_sync();
  219. return 0;
  220. }
  221. /*
  222. * Command for doing an intentional panic.
  223. */
  224. static
  225. int
  226. cmd_panic(int nargs, char **args)
  227. {
  228. (void)nargs;
  229. (void)args;
  230. panic("User requested panic\n");
  231. return 0;
  232. }
  233. /*
  234. * Command for shutting down.
  235. */
  236. static
  237. int
  238. cmd_quit(int nargs, char **args)
  239. {
  240. (void)nargs;
  241. (void)args;
  242. vfs_sync();
  243. sys_reboot(RB_POWEROFF);
  244. thread_exit();
  245. return 0;
  246. }
  247. /*
  248. * Command for mounting a filesystem.
  249. */
  250. /* Table of mountable filesystem types. */
  251. static const struct {
  252. const char *name;
  253. int (*func)(const char *device);
  254. } mounttable[] = {
  255. #if OPT_SFS
  256. { "sfs", sfs_mount },
  257. #endif
  258. { NULL, NULL }
  259. };
  260. static
  261. int
  262. cmd_mount(int nargs, char **args)
  263. {
  264. char *fstype;
  265. char *device;
  266. int i;
  267. if (nargs != 3) {
  268. kprintf("Usage: mount fstype device:\n");
  269. return EINVAL;
  270. }
  271. fstype = args[1];
  272. device = args[2];
  273. /* Allow (but do not require) colon after device name */
  274. if (device[strlen(device)-1]==':') {
  275. device[strlen(device)-1] = 0;
  276. }
  277. for (i=0; mounttable[i].name; i++) {
  278. if (!strcmp(mounttable[i].name, fstype)) {
  279. return mounttable[i].func(device);
  280. }
  281. }
  282. kprintf("Unknown filesystem type %s\n", fstype);
  283. return EINVAL;
  284. }
  285. static
  286. int
  287. cmd_unmount(int nargs, char **args)
  288. {
  289. char *device;
  290. if (nargs != 2) {
  291. kprintf("Usage: unmount device:\n");
  292. return EINVAL;
  293. }
  294. device = args[1];
  295. /* Allow (but do not require) colon after device name */
  296. if (device[strlen(device)-1]==':') {
  297. device[strlen(device)-1] = 0;
  298. }
  299. return vfs_unmount(device);
  300. }
  301. /*
  302. * Command to set the "boot fs".
  303. *
  304. * The boot filesystem is the one that pathnames like /bin/sh with
  305. * leading slashes refer to.
  306. *
  307. * The default bootfs is "emu0".
  308. */
  309. static
  310. int
  311. cmd_bootfs(int nargs, char **args)
  312. {
  313. char *device;
  314. if (nargs != 2) {
  315. kprintf("Usage: bootfs device\n");
  316. return EINVAL;
  317. }
  318. device = args[1];
  319. /* Allow (but do not require) colon after device name */
  320. if (device[strlen(device)-1]==':') {
  321. device[strlen(device)-1] = 0;
  322. }
  323. return vfs_setbootfs(device);
  324. }
  325. static
  326. int
  327. cmd_kheapstats(int nargs, char **args)
  328. {
  329. (void)nargs;
  330. (void)args;
  331. kheap_printstats();
  332. return 0;
  333. }
  334. ////////////////////////////////////////
  335. //
  336. // Menus.
  337. static
  338. void
  339. showmenu(const char *name, const char *x[])
  340. {
  341. int ct, half, i;
  342. kprintf("\n");
  343. kprintf("%s\n", name);
  344. for (i=ct=0; x[i]; i++) {
  345. ct++;
  346. }
  347. half = (ct+1)/2;
  348. for (i=0; i<half; i++) {
  349. kprintf(" %-36s", x[i]);
  350. if (i+half < ct) {
  351. kprintf("%s", x[i+half]);
  352. }
  353. kprintf("\n");
  354. }
  355. kprintf("\n");
  356. }
  357. static const char *opsmenu[] = {
  358. "[s] Shell ",
  359. "[p] Other program ",
  360. "[mount] Mount a filesystem ",
  361. "[unmount] Unmount a filesystem ",
  362. "[bootfs] Set \"boot\" filesystem ",
  363. "[pf] Print a file ",
  364. "[cd] Change directory ",
  365. "[pwd] Print current directory ",
  366. "[sync] Sync filesystems ",
  367. "[panic] Intentional panic ",
  368. "[dth] Enable DB_THREADS msgs ",
  369. "[q] Quit and shut down ",
  370. NULL
  371. };
  372. static
  373. int
  374. cmd_opsmenu(int n, char **a)
  375. {
  376. (void)n;
  377. (void)a;
  378. showmenu("OS/161 operations menu", opsmenu);
  379. return 0;
  380. }
  381. static const char *testmenu[] = {
  382. "[at] Array test ",
  383. "[bt] Bitmap test ",
  384. "[km1] Kernel malloc test ",
  385. "[km2] kmalloc stress test ",
  386. "[tt1] Thread test 1 ",
  387. "[tt2] Thread test 2 ",
  388. "[tt3] Thread test 3 ",
  389. #if OPT_NET
  390. "[net] Network test ",
  391. #endif
  392. "[sy1] Semaphore test ",
  393. "[sy2] Lock test (1) ",
  394. "[sy3] CV test (1) ",
  395. #ifdef UW
  396. "[uw1] UW lock test (1) ",
  397. "[uw2] UW vmstats test (3) ",
  398. #endif // UW
  399. "[fs1] Filesystem test ",
  400. "[fs2] FS read stress (4) ",
  401. "[fs3] FS write stress (4) ",
  402. "[fs4] FS write stress 2 (4) ",
  403. "[fs5] FS create stress (4) ",
  404. NULL
  405. };
  406. static
  407. int
  408. cmd_testmenu(int n, char **a)
  409. {
  410. (void)n;
  411. (void)a;
  412. showmenu("OS/161 tests menu", testmenu);
  413. kprintf(" (1) These tests will fail until you finish the "
  414. "synch assignment.\n");
  415. kprintf(" (4) These tests may fail until you finish the "
  416. "file system assignment.\n");
  417. kprintf("\n");
  418. return 0;
  419. }
  420. static const char *mainmenu[] = {
  421. "[?o] Operations menu ",
  422. "[?t] Tests menu ",
  423. #if OPT_SYNCHPROBS
  424. "[sp1] Whale Mating ",
  425. #ifdef UW
  426. "[sp2] Cat/mouse ",
  427. "[sp3] Traffic ",
  428. #endif /* UW */
  429. #endif
  430. "[kh] Kernel heap stats ",
  431. "[q] Quit and shut down ",
  432. NULL
  433. };
  434. static
  435. int
  436. cmd_mainmenu(int n, char **a)
  437. {
  438. (void)n;
  439. (void)a;
  440. showmenu("OS/161 kernel menu", mainmenu);
  441. return 0;
  442. }
  443. static int cmd_dth(int nargs, char **args)
  444. {
  445. (void)nargs;
  446. (void)args;
  447. dbflags = DB_THREADS;
  448. return 0;
  449. }
  450. ////////////////////////////////////////
  451. //
  452. // Command table.
  453. static struct {
  454. const char *name;
  455. int (*func)(int nargs, char **args);
  456. } cmdtable[] = {
  457. /* menus */
  458. { "?", cmd_mainmenu },
  459. { "h", cmd_mainmenu },
  460. { "help", cmd_mainmenu },
  461. { "?o", cmd_opsmenu },
  462. { "?t", cmd_testmenu },
  463. /* operations */
  464. { "s", cmd_shell },
  465. { "p", cmd_prog },
  466. { "mount", cmd_mount },
  467. { "unmount", cmd_unmount },
  468. { "bootfs", cmd_bootfs },
  469. { "pf", printfile },
  470. { "cd", cmd_chdir },
  471. { "pwd", cmd_pwd },
  472. { "sync", cmd_sync },
  473. { "panic", cmd_panic },
  474. { "q", cmd_quit },
  475. { "exit", cmd_quit },
  476. { "halt", cmd_quit },
  477. { "dth", cmd_dth },
  478. #if OPT_SYNCHPROBS
  479. /* in-kernel synchronization problem(s) */
  480. { "sp1", whalemating },
  481. #ifdef UW
  482. { "sp2", catmouse },
  483. { "sp3", traffic_simulation },
  484. #endif /* UW */
  485. #endif
  486. /* stats */
  487. { "kh", cmd_kheapstats },
  488. /* base system tests */
  489. { "at", arraytest },
  490. { "bt", bitmaptest },
  491. { "km1", malloctest },
  492. { "km2", mallocstress },
  493. #if OPT_NET
  494. { "net", nettest },
  495. #endif
  496. { "tt1", threadtest },
  497. { "tt2", threadtest2 },
  498. { "tt3", threadtest3 },
  499. { "sy1", semtest },
  500. /* synchronization assignment tests */
  501. { "sy2", locktest },
  502. { "sy3", cvtest },
  503. #ifdef UW
  504. { "uw1", uwlocktest1 },
  505. { "uw2", uwvmstatstest },
  506. #endif
  507. /* file system assignment tests */
  508. { "fs1", fstest },
  509. { "fs2", readstress },
  510. { "fs3", writestress },
  511. { "fs4", writestress2 },
  512. { "fs5", createstress },
  513. { NULL, NULL }
  514. };
  515. /*
  516. * Process a single command.
  517. */
  518. static
  519. int
  520. cmd_dispatch(char *cmd)
  521. {
  522. time_t beforesecs, aftersecs, secs;
  523. uint32_t beforensecs, afternsecs, nsecs;
  524. char *args[MAXMENUARGS];
  525. int nargs=0;
  526. char *word;
  527. char *context;
  528. int i, result;
  529. for (word = strtok_r(cmd, " \t", &context);
  530. word != NULL;
  531. word = strtok_r(NULL, " \t", &context)) {
  532. if (nargs >= MAXMENUARGS) {
  533. kprintf("Command line has too many words\n");
  534. return E2BIG;
  535. }
  536. args[nargs++] = word;
  537. }
  538. if (nargs==0) {
  539. return 0;
  540. }
  541. for (i=0; cmdtable[i].name; i++) {
  542. if (*cmdtable[i].name && !strcmp(args[0], cmdtable[i].name)) {
  543. KASSERT(cmdtable[i].func!=NULL);
  544. gettime(&beforesecs, &beforensecs);
  545. result = cmdtable[i].func(nargs, args);
  546. gettime(&aftersecs, &afternsecs);
  547. getinterval(beforesecs, beforensecs,
  548. aftersecs, afternsecs,
  549. &secs, &nsecs);
  550. kprintf("Operation took %lu.%09lu seconds\n",
  551. (unsigned long) secs,
  552. (unsigned long) nsecs);
  553. return result;
  554. }
  555. }
  556. kprintf("%s: Command not found\n", args[0]);
  557. return EINVAL;
  558. }
  559. /*
  560. * Evaluate a command line that may contain multiple semicolon-delimited
  561. * commands.
  562. *
  563. * If "isargs" is set, we're doing command-line processing; print the
  564. * comamnds as we execute them and panic if the command is invalid or fails.
  565. */
  566. static
  567. void
  568. menu_execute(char *line, int isargs)
  569. {
  570. char *command;
  571. char *context;
  572. int result;
  573. for (command = strtok_r(line, ";", &context);
  574. command != NULL;
  575. command = strtok_r(NULL, ";", &context)) {
  576. if (isargs) {
  577. kprintf("OS/161 kernel: %s\n", command);
  578. }
  579. result = cmd_dispatch(command);
  580. if (result) {
  581. kprintf("Menu command failed: %s\n", strerror(result));
  582. if (isargs) {
  583. panic("Failure processing kernel arguments\n");
  584. }
  585. }
  586. }
  587. }
  588. /*
  589. * Command menu main loop.
  590. *
  591. * First, handle arguments passed on the kernel's command line from
  592. * the bootloader. Then loop prompting for commands.
  593. *
  594. * The line passed in from the bootloader is treated as if it had been
  595. * typed at the prompt. Semicolons separate commands; spaces and tabs
  596. * separate words (command names and arguments).
  597. *
  598. * So, for instance, to mount an SFS on lhd0 and make it the boot
  599. * filesystem, and then boot directly into the shell, one would use
  600. * the kernel command line
  601. *
  602. * "mount sfs lhd0; bootfs lhd0; s"
  603. */
  604. void
  605. menu(char *args)
  606. {
  607. char buf[64];
  608. menu_execute(args, 1);
  609. while (1) {
  610. kprintf("OS/161 kernel [? for menu]: ");
  611. kgets(buf, sizeof(buf));
  612. menu_execute(buf, 0);
  613. }
  614. }