OS2021_Project1.Shell

698 line
12 KiB

3 年之前
3 年之前
3 年之前
3 年之前
3 年之前
3 年之前
3 年之前
3 年之前
3 年之前
3 年之前
3 年之前
3 年之前
3 年之前
3 年之前
3 年之前
3 年之前
3 年之前
3 年之前
3 年之前
3 年之前
3 年之前
3 年之前
3 年之前
3 年之前
3 年之前
3 年之前
3 年之前
3 年之前
3 年之前
3 年之前
3 年之前
3 年之前
3 年之前
3 年之前
3 年之前
3 年之前
3 年之前
3 年之前
3 年之前
3 年之前
3 年之前
3 年之前
3 年之前
3 年之前
3 年之前
3 年之前
3 年之前
3 年之前
3 年之前
3 年之前
3 年之前
3 年之前
3 年之前
3 年之前
3 年之前
3 年之前
3 年之前
3 年之前
3 年之前
3 年之前
3 年之前
3 年之前
3 年之前
3 年之前
3 年之前
3 年之前
3 年之前
3 年之前
3 年之前
3 年之前
3 年之前
3 年之前
3 年之前
3 年之前
3 年之前
3 年之前
3 年之前
3 年之前
3 年之前
3 年之前
3 年之前
3 年之前
3 年之前
3 年之前
3 年之前
3 年之前
3 年之前
3 年之前
3 年之前
3 年之前
3 年之前
3 年之前
3 年之前
3 年之前
3 年之前
3 年之前
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <unistd.h>
  4. #include <string.h>
  5. #include <dirent.h>
  6. #include <signal.h>
  7. #include <errno.h>
  8. #include <fcntl.h>
  9. #include <termcap.h>
  10. #include <termios.h>
  11. #include <curses.h>
  12. #include <limits.h>
  13. #include <pwd.h>
  14. #include <assert.h>
  15. #include <sys/types.h>
  16. #include <sys/wait.h>
  17. #include <sys/stat.h>
  18. #include <sys/times.h>
  19. #include <sys/time.h>
  20. #include <sys/select.h>
  21. #include <minix/com.h>
  22. #include <minix/config.h>
  23. #include <minix/type.h>
  24. #include <minix/endpoint.h>
  25. #include <minix/const.h>
  26. #include <minix/u64.h>
  27. #include <minix/procfs.h>
  28. #include <paths.h>
  29. #include "yeeshell.h"
  30. /* record cmdline history */
  31. char *history[CMDLINE_HISTORY_MAX_QUANTITY];
  32. int cmdline_amount = 0;
  33. struct proc *proc = NULL, *prev_proc = NULL;
  34. int nr_total = 0;
  35. unsigned int nr_procs, nr_tasks;
  36. int main()
  37. {
  38. char *cmdline = NULL, *pwd = NULL;
  39. char *args[ARGS_MAX_QUANTITY];
  40. int status = 1;
  41. pwd = (char *)calloc(PATH_MAX_SIZE, sizeof(char));
  42. for (int i = 0; i < CMDLINE_HISTORY_MAX_QUANTITY; i++)
  43. {
  44. history[i] = (char *)calloc(CMDLINE_MAX_SIZE, sizeof(char));
  45. }
  46. /* execute the shell's read, parse and execution loop */
  47. do
  48. {
  49. if (!getcwd(pwd, PATH_MAX_SIZE))
  50. {
  51. printf("yeeshell: The current path cannot be obtained!\n");
  52. exit(0);
  53. }
  54. printf("[root@yeeshell %s]# ", pwd);
  55. cmdline = readline();
  56. strcpy(history[cmdline_amount++], cmdline);
  57. status = execute(cmdline, args);
  58. free(cmdline);
  59. } while (status);
  60. for (int i = 0; i < CMDLINE_HISTORY_MAX_QUANTITY; i++)
  61. {
  62. free(history[i]);
  63. }
  64. exit(EXIT_SUCCESS);
  65. }
  66. char *readline()
  67. {
  68. char *cmdline = NULL;
  69. ssize_t bufsize = 0;
  70. getline(&cmdline, &bufsize, stdin);
  71. return cmdline;
  72. }
  73. int parseline(char *cmdline, char **args)
  74. {
  75. static char array[CMDLINE_MAX_SIZE]; /* holds local copy of command line */
  76. char *buf = array; /* ptr that traverses command line */
  77. char *delim; /* points to first space delimiter */
  78. int argc; /* number of args */
  79. int bg; /* background job? */
  80. strcpy(buf, cmdline);
  81. buf[strlen(buf) - 1] = ' '; /* replace trailing '\n' with space */
  82. while (*buf && (*buf == ' ')) /* ignore leading spaces */
  83. {
  84. buf++;
  85. }
  86. /* Build the argv list */
  87. argc = 0;
  88. if (*buf == '\'')
  89. {
  90. buf++;
  91. delim = strchr(buf, '\'');
  92. }
  93. else
  94. {
  95. delim = strchr(buf, ' ');
  96. }
  97. while (delim)
  98. {
  99. args[argc++] = buf;
  100. *delim = '\0';
  101. buf = delim + 1;
  102. while (*buf && (*buf == ' ')) /* ignore spaces */
  103. {
  104. buf++;
  105. }
  106. if (*buf == '\'')
  107. {
  108. buf++;
  109. delim = strchr(buf, '\'');
  110. }
  111. else
  112. {
  113. delim = strchr(buf, ' ');
  114. }
  115. }
  116. args[argc] = NULL;
  117. if (argc == 0) /* ignore blank line */
  118. {
  119. return 1;
  120. }
  121. /* should the job run in the background? */
  122. if ((bg = (*args[argc - 1] == '&')) != 0)
  123. {
  124. args[--argc] = NULL;
  125. }
  126. return bg;
  127. }
  128. int check_redirect(char **args, char *redirect_filename, char **redirect_args)
  129. {
  130. int i = 0, j = 0, redirect_flag = REDIRECT_NO;
  131. while (args[i] != NULL)
  132. {
  133. if (!strcmp(args[i], ">"))
  134. {
  135. redirect_flag = REDIRECT_OUT;
  136. break;
  137. }
  138. else if (!strcmp(args[i], "<"))
  139. {
  140. redirect_flag = REDIRECT_IN;
  141. break;
  142. }
  143. i++;
  144. }
  145. if ((redirect_flag == 1) || (redirect_flag == 2))
  146. {
  147. strcpy(redirect_filename, args[i + 1]);
  148. for (j = 0; j < i; j++)
  149. {
  150. redirect_args[j] = args[j];
  151. }
  152. }
  153. return redirect_flag;
  154. }
  155. int do_redirect(int redirect_flag, char *redirect_filename, char **redirect_args)
  156. {
  157. pid_t pid;
  158. int fd = 1;
  159. if ((pid = fork()) == 0) /* Child process */
  160. {
  161. if (redirect_flag == 1) /* in or out? */
  162. {
  163. fd = open(redirect_filename, O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR | S_IWUSR | S_IXUSR);
  164. close(1);
  165. dup(fd);
  166. }
  167. else if (redirect_flag == 2)
  168. {
  169. fd = open(redirect_filename, O_RDONLY, S_IRUSR);
  170. close(0);
  171. dup(fd);
  172. }
  173. if (execvp(redirect_args[0], redirect_args) <= 0)
  174. {
  175. printf("%s: Command not found\n", redirect_args[0]);
  176. exit(0);
  177. }
  178. close(fd);
  179. }
  180. else /* parent process */
  181. {
  182. waitpid(pid, NULL, 0);
  183. }
  184. return 1;
  185. }
  186. int check_pipe(char **args, char **pipe_arg_1, char **pipe_arg_2)
  187. {
  188. int pipe_flag = 0, i = 0, j = 0;
  189. while (args[i] != NULL)
  190. {
  191. if (!strcmp(args[i], "|"))
  192. {
  193. pipe_flag = 1;
  194. break;
  195. }
  196. pipe_arg_1[j++] = args[i++];
  197. }
  198. pipe_arg_1[j] = NULL;
  199. j = 0;
  200. i++;
  201. while (args[i] != NULL)
  202. {
  203. pipe_arg_2[j++] = args[i++];
  204. }
  205. pipe_arg_2[j] = NULL;
  206. return pipe_flag;
  207. }
  208. int do_pipe(char **pipe_arg_1, char **pipe_arg_2)
  209. {
  210. int fds[2];
  211. pipe(fds);
  212. pid_t prog_1, prog_2;
  213. if ((prog_1 = fork()) == 0) /* Child process 1 */
  214. {
  215. close(1);
  216. dup(fds[1]);
  217. close(fds[0]);
  218. close(fds[1]);
  219. if (execvp(pipe_arg_1[0], pipe_arg_1) <= 0)
  220. {
  221. printf("%s: Command not found\n", pipe_arg_1[0]);
  222. exit(0);
  223. }
  224. }
  225. if ((prog_2 = fork()) == 0) /* Child process 1 */
  226. {
  227. dup2(fds[0], 0);
  228. close(fds[0]);
  229. close(fds[1]);
  230. if (execvp(pipe_arg_2[0], pipe_arg_2) <= 0)
  231. {
  232. printf("%s: Command not found\n", pipe_arg_2[0]);
  233. exit(0);
  234. }
  235. }
  236. close(fds[0]);
  237. close(fds[1]);
  238. waitpid(prog_1, NULL, 0);
  239. waitpid(prog_2, NULL, 0);
  240. return 1;
  241. }
  242. int do_bg_fg(char **args, int bg)
  243. {
  244. pid_t pid;
  245. if ((pid = fork()) == 0)
  246. {
  247. if (execvp(args[0], args) <= 0)
  248. {
  249. printf("%s: Command not found\n", args[0]);
  250. exit(0);
  251. }
  252. }
  253. else
  254. {
  255. if (bg)
  256. {
  257. signal(SIGCHLD, SIG_IGN);
  258. }
  259. else
  260. {
  261. waitpid(pid, NULL, 0);
  262. }
  263. }
  264. return 1;
  265. }
  266. int execute(char *cmdline, char **args)
  267. {
  268. int bg = 0, i = 0, redirect_flag = 0, pipe_num = 0;
  269. pid_t pid;
  270. char *redirect_filename = NULL;
  271. char *redirect_args[ARGS_MAX_QUANTITY];
  272. char *pipe_arg_1[ARGS_MAX_QUANTITY];
  273. char *pipe_arg_2[ARGS_MAX_QUANTITY];
  274. redirect_filename = (char *)calloc(REDIRECT_FILENAME_MAX_SIZE, sizeof(char));
  275. memset(redirect_args, NULL, sizeof(redirect_args));
  276. bg = parseline(cmdline, args);
  277. redirect_flag = check_redirect(args, redirect_filename, redirect_args);
  278. pipe_num = check_pipe(args, pipe_arg_1, pipe_arg_2);
  279. if (args[0] == NULL)
  280. {
  281. return 1;
  282. }
  283. if (pipe_num == 0) /* no pipe */
  284. {
  285. if (!built_in(args)) /* built-in cmd? */
  286. {
  287. if (redirect_flag != 0) /* redirection? */
  288. {
  289. return do_redirect(redirect_flag, redirect_filename, redirect_args);
  290. }
  291. else
  292. {
  293. return do_bg_fg(args, bg);
  294. }
  295. }
  296. else
  297. {
  298. return 1;
  299. }
  300. }
  301. else
  302. {
  303. return do_pipe(pipe_arg_1, pipe_arg_2);
  304. }
  305. }
  306. int built_in(char **args)
  307. {
  308. if (!strcmp(args[0], "exit"))
  309. {
  310. exit(0);
  311. }
  312. else if (!strcmp(args[0], "cd"))
  313. {
  314. return builtin_cd(args);
  315. }
  316. else if (!strcmp(args[0], "history"))
  317. {
  318. return builtin_history(args);
  319. }
  320. else if (!strcmp(args[0], "mytop"))
  321. {
  322. return builtin_mytop();
  323. }
  324. else
  325. {
  326. return 0;
  327. }
  328. }
  329. int builtin_cd(char **args)
  330. {
  331. if (args[1] == NULL)
  332. {
  333. return 1;
  334. }
  335. else
  336. {
  337. if (chdir(args[1]) != 0)
  338. {
  339. perror("yeeshell");
  340. }
  341. return 1;
  342. }
  343. }
  344. int builtin_history(char **args)
  345. {
  346. int n = 0;
  347. if (args[1] == NULL)
  348. {
  349. n = cmdline_amount;
  350. }
  351. else
  352. {
  353. n = atoi(args[1]) < cmdline_amount ? atoi(args[1]) : cmdline_amount;
  354. }
  355. printf("ID\tCommandline\n");
  356. for (int i = 0; i < n; i++)
  357. {
  358. printf("%d\t%s\n", i + 1, history[i]);
  359. }
  360. return 1;
  361. }
  362. int builtin_mytop()
  363. {
  364. int cputimemode = 1;
  365. mytop_memory();
  366. getkinfo();
  367. get_procs();
  368. if (prev_proc == NULL)
  369. get_procs();
  370. print_procs(prev_proc, proc, cputimemode);
  371. return 1;
  372. }
  373. void mytop_memory()
  374. {
  375. FILE *fp = NULL;
  376. int pagesize;
  377. long total = 0, free = 0, cached = 0;
  378. if ((fp = fopen("/proc/meminfo", "r")) == NULL)
  379. {
  380. exit(0);
  381. }
  382. fscanf(fp, "%u %lu %lu %lu", &pagesize, &total, &free, &cached);
  383. fclose(fp);
  384. printf("memory(KBytes):\t%ld total\t%ld free\t%ld cached\n", (pagesize * total) / 1024, (pagesize * free) / 1024, (pagesize * cached) / 1024);
  385. return;
  386. }
  387. void get_procs()
  388. {
  389. struct proc *p;
  390. int i;
  391. p = prev_proc;
  392. prev_proc = proc;
  393. proc = p;
  394. if (proc == NULL)
  395. {
  396. proc = malloc(nr_total * sizeof(proc[0]));
  397. if (proc == NULL)
  398. {
  399. fprintf(stderr, "Out of memory!\n");
  400. exit(1);
  401. }
  402. }
  403. for (i = 0; i < nr_total; i++)
  404. proc[i].p_flags = 0;
  405. parse_dir();
  406. }
  407. void parse_dir()
  408. {
  409. DIR *p_dir;
  410. struct dirent *p_ent;
  411. pid_t pid;
  412. char *end;
  413. if ((p_dir = opendir("/proc")) == NULL)
  414. {
  415. perror("opendir on " _PATH_PROC);
  416. exit(1);
  417. }
  418. for (p_ent = readdir(p_dir); p_ent != NULL; p_ent = readdir(p_dir))
  419. {
  420. pid = strtol(p_ent->d_name, &end, 10);
  421. if (!end[0] && pid != 0)
  422. {
  423. parse_file(pid);
  424. }
  425. }
  426. closedir(p_dir);
  427. }
  428. void parse_file(pid_t pid)
  429. {
  430. char path[PATH_MAX], name[256], type, state;
  431. int version, endpt, effuid;
  432. unsigned long cycles_hi, cycles_lo;
  433. FILE *fp;
  434. struct proc *p;
  435. int slot;
  436. int i;
  437. sprintf(path, "%d/psinfo", pid);
  438. if ((fp = fopen(path, "r")) == NULL)
  439. return;
  440. if (fscanf(fp, "%d", &version) != 1)
  441. {
  442. fclose(fp);
  443. return;
  444. }
  445. if (version != PSINFO_VERSION)
  446. {
  447. fputs("procfs version mismatch!\n", stderr);
  448. exit(1);
  449. }
  450. if (fscanf(fp, " %c %d", &type, &endpt) != 2)
  451. {
  452. fclose(fp);
  453. return;
  454. }
  455. slot = SLOT_NR(endpt);
  456. if (slot < 0 || slot >= nr_total)
  457. {
  458. //fprintf(stderr, "top: unreasonable endpoint number %d\n", endpt);
  459. fclose(fp);
  460. return;
  461. }
  462. p = &proc[slot];
  463. if (type == TYPE_TASK)
  464. {
  465. p->p_flags |= IS_TASK;
  466. }
  467. else if (type == TYPE_SYSTEM)
  468. {
  469. p->p_flags |= IS_SYSTEM;
  470. }
  471. p->p_endpoint = endpt;
  472. p->p_pid = pid;
  473. if (fscanf(fp, " %255s %c %d %d %lu %*u %lu %lu", name, &state, &p->p_blocked, &p->p_priority, &p->p_user_time, &cycles_hi, &cycles_lo) != 7)
  474. {
  475. fclose(fp);
  476. return;
  477. }
  478. strncpy(p->p_name, name, sizeof(p->p_name) - 1);
  479. p->p_name[sizeof(p->p_name) - 1] = 0;
  480. if (state != STATE_RUN)
  481. {
  482. p->p_flags |= BLOCKED;
  483. }
  484. p->p_cpucycles[0] = make64(cycles_lo, cycles_hi);
  485. p->p_memory = 0L;
  486. if (!(p->p_flags & IS_TASK))
  487. {
  488. int j;
  489. if ((j = fscanf(fp, " %lu %*u %*u %*c %*d %*u %u %*u %d %*c %*d %*u", &p->p_memory, &effuid, &p->p_nice)) != 3)
  490. {
  491. fclose(fp);
  492. return;
  493. }
  494. p->p_effuid = effuid;
  495. }
  496. else
  497. {
  498. p->p_effuid = 0;
  499. }
  500. for (i = 1; i < CPUTIMENAMES; i++)
  501. {
  502. if (fscanf(fp, " %lu %lu", &cycles_hi, &cycles_lo) == 2)
  503. {
  504. p->p_cpucycles[i] = make64(cycles_lo, cycles_hi);
  505. }
  506. else
  507. {
  508. p->p_cpucycles[i] = 0;
  509. }
  510. }
  511. if ((p->p_flags & IS_TASK))
  512. {
  513. if (fscanf(fp, " %lu", &p->p_memory) != 1)
  514. {
  515. p->p_memory = 0;
  516. }
  517. }
  518. p->p_flags |= USED;
  519. fclose(fp);
  520. }
  521. void getkinfo()
  522. {
  523. FILE *fp;
  524. if ((fp = fopen("/proc/kinfo", "r")) == NULL)
  525. {
  526. fprintf(stderr, "opening " _PATH_PROC "kinfo failed\n");
  527. exit(1);
  528. }
  529. if (fscanf(fp, "%u %u", &nr_procs, &nr_tasks) != 2)
  530. {
  531. fprintf(stderr, "reading from " _PATH_PROC "kinfo failed\n");
  532. exit(1);
  533. }
  534. fclose(fp);
  535. nr_total = (int)(nr_procs + nr_tasks);
  536. }
  537. void print_procs(struct proc *proc1, struct proc *proc2, int cputimemode)
  538. {
  539. int p, nprocs;
  540. u64_t systemticks = 0;
  541. u64_t userticks = 0;
  542. u64_t total_ticks = 0;
  543. int blockedseen = 0;
  544. static struct tp *tick_procs = NULL;
  545. if (tick_procs == NULL)
  546. {
  547. tick_procs = malloc(nr_total * sizeof(tick_procs[0]));
  548. if (tick_procs == NULL)
  549. {
  550. fprintf(stderr, "Out of memory!\n");
  551. exit(1);
  552. }
  553. }
  554. for (p = nprocs = 0; p < nr_total; p++)
  555. {
  556. u64_t uticks;
  557. if (!(proc2[p].p_flags & USED))
  558. {
  559. continue;
  560. }
  561. tick_procs[nprocs].p = proc2 + p;
  562. tick_procs[nprocs].ticks = cputicks(&proc1[p], &proc2[p], cputimemode);
  563. uticks = cputicks(&proc1[p], &proc2[p], 1);
  564. total_ticks = total_ticks + uticks;
  565. if (!(proc2[p].p_flags & IS_TASK))
  566. {
  567. if (proc2[p].p_flags & IS_SYSTEM)
  568. {
  569. systemticks = systemticks + tick_procs[nprocs].ticks;
  570. }
  571. else
  572. {
  573. userticks = userticks + tick_procs[nprocs].ticks;
  574. }
  575. }
  576. nprocs++;
  577. }
  578. if (total_ticks == 0)
  579. {
  580. return;
  581. }
  582. printf("CPU states: %6.2f%% user, ", 100.0 * userticks / total_ticks);
  583. printf("%6.2f%% system", 100.0 * systemticks / total_ticks);
  584. printf("%6.2f%% in total\n", 100.0 * (systemticks + userticks) / total_ticks);
  585. }
  586. u64_t cputicks(struct proc *p1, struct proc *p2, int timemode)
  587. {
  588. int i;
  589. u64_t t = 0;
  590. for (i = 0; i < CPUTIMENAMES; i++)
  591. {
  592. if (!CPUTIME(timemode, i))
  593. {
  594. continue;
  595. }
  596. if (p1->p_endpoint == p2->p_endpoint)
  597. {
  598. {
  599. t = t + p2->p_cpucycles[i] - p1->p_cpucycles[i];
  600. }
  601. }
  602. else
  603. {
  604. t = t + p2->p_cpucycles[i];
  605. }
  606. }
  607. return t;
  608. }