OS2021_Project1.Shell
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

706 lines
12 KiB

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