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.

712 lines
12 KiB

пре 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 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); /* getline(<char array>,<number>,<file descriptor>) */
  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, '\''); /* strchr - To find the first match of a given character in a string */
  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) /* 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) /* in */
  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. dup(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 (bg)
  252. {
  253. int fd = open("/dev/null", O_RDWR);
  254. dup2(fd, 0);
  255. dup2(fd, 1);
  256. }
  257. if (execvp(args[0], args) <= 0)
  258. {
  259. printf("%s: Command not found\n", args[0]);
  260. }
  261. exit(0);
  262. }
  263. else
  264. {
  265. if (bg)
  266. {
  267. signal(SIGCHLD, SIG_IGN);
  268. }
  269. else
  270. {
  271. waitpid(pid, NULL, 0);
  272. }
  273. }
  274. return 1;
  275. }
  276. int execute(char *cmdline, char **args)
  277. {
  278. int bg = 0, i = 0, redirect_flag = 0, pipe_num = 0;
  279. pid_t pid;
  280. char *redirect_filename = NULL;
  281. char *redirect_args[ARGS_MAX_QUANTITY];
  282. char *pipe_arg_1[ARGS_MAX_QUANTITY];
  283. char *pipe_arg_2[ARGS_MAX_QUANTITY];
  284. redirect_filename = (char *)calloc(REDIRECT_FILENAME_MAX_SIZE, sizeof(char));
  285. memset(redirect_args, NULL, sizeof(redirect_args));
  286. bg = parseline(cmdline, args);
  287. redirect_flag = check_redirect(args, redirect_filename, redirect_args);
  288. pipe_num = check_pipe(args, pipe_arg_1, pipe_arg_2);
  289. if (args[0] == NULL)
  290. {
  291. return 1;
  292. }
  293. if (pipe_num == 0) /* no pipe */
  294. {
  295. if (!built_in(args)) /* built-in cmd? */
  296. {
  297. if (redirect_flag != 0) /* redirection? */
  298. {
  299. return do_redirect(redirect_flag, redirect_filename, redirect_args);
  300. }
  301. else
  302. {
  303. return do_bg_fg(args, bg);
  304. }
  305. }
  306. else
  307. {
  308. return 1;
  309. }
  310. }
  311. else
  312. {
  313. return do_pipe(pipe_arg_1, pipe_arg_2);
  314. }
  315. }
  316. int built_in(char **args)
  317. {
  318. if (!strcmp(args[0], "exit"))
  319. {
  320. exit(0);
  321. }
  322. else if (!strcmp(args[0], "cd"))
  323. {
  324. return builtin_cd(args);
  325. }
  326. else if (!strcmp(args[0], "history"))
  327. {
  328. return builtin_history(args);
  329. }
  330. else if (!strcmp(args[0], "mytop"))
  331. {
  332. return builtin_mytop();
  333. }
  334. else
  335. {
  336. return 0;
  337. }
  338. }
  339. int builtin_cd(char **args)
  340. {
  341. if (args[1] == NULL)
  342. {
  343. return 1;
  344. }
  345. else
  346. {
  347. if (chdir(args[1]) != 0)
  348. {
  349. perror("yeeshell");
  350. }
  351. return 1;
  352. }
  353. }
  354. int builtin_history(char **args)
  355. {
  356. int n = 0;
  357. if (args[1] == NULL)
  358. {
  359. n = cmdline_amount;
  360. }
  361. else
  362. {
  363. n = atoi(args[1]) < cmdline_amount ? atoi(args[1]) : cmdline_amount;
  364. }
  365. printf("ID\tCommandline\n");
  366. for (int i = 0; i < n; i++)
  367. {
  368. printf("%d\t%s\n", i + 1, history[i]);
  369. }
  370. return 1;
  371. }
  372. int builtin_mytop()
  373. {
  374. int cputimemode = 1;
  375. mytop_memory();
  376. getkinfo();
  377. get_procs();
  378. if (prev_proc == NULL)
  379. get_procs();
  380. print_procs(prev_proc, proc, cputimemode);
  381. return 1;
  382. }
  383. void mytop_memory()
  384. {
  385. FILE *fp = NULL;
  386. int pagesize;
  387. long total = 0, free = 0, cached = 0;
  388. if ((fp = fopen("/proc/meminfo", "r")) == NULL)
  389. {
  390. exit(0);
  391. }
  392. fscanf(fp, "%u %lu %lu %lu", &pagesize, &total, &free, &cached);
  393. fclose(fp);
  394. printf("memory(KBytes):\t%ld total\t%ld free\t%ld cached\n", (pagesize * total) / 1024, (pagesize * free) / 1024, (pagesize * cached) / 1024);
  395. return;
  396. }
  397. void get_procs()
  398. {
  399. struct proc *p;
  400. int i;
  401. p = prev_proc;
  402. prev_proc = proc;
  403. proc = p;
  404. if (proc == NULL)
  405. {
  406. proc = malloc(nr_total * sizeof(proc[0]));
  407. if (proc == NULL)
  408. {
  409. fprintf(stderr, "Out of memory!\n");
  410. exit(1);
  411. }
  412. }
  413. for (i = 0; i < nr_total; i++)
  414. {
  415. proc[i].p_flags = 0;
  416. }
  417. parse_dir();
  418. }
  419. void parse_dir()
  420. {
  421. DIR *p_dir;
  422. struct dirent *p_ent;
  423. pid_t pid;
  424. char *end;
  425. if ((p_dir = opendir("/proc")) == NULL)
  426. {
  427. perror("opendir on " _PATH_PROC);
  428. exit(1);
  429. }
  430. for (p_ent = readdir(p_dir); p_ent != NULL; p_ent = readdir(p_dir))
  431. {
  432. pid = strtol(p_ent->d_name, &end, 10);
  433. if (!end[0] && pid != 0)
  434. {
  435. parse_file(pid);
  436. }
  437. }
  438. closedir(p_dir);
  439. }
  440. void parse_file(pid_t pid)
  441. {
  442. char path[PATH_MAX], name[256], type, state;
  443. int version, endpt, effuid;
  444. unsigned long cycles_hi, cycles_lo;
  445. FILE *fp;
  446. struct proc *p;
  447. int i;
  448. sprintf(path, "/proc/%d/psinfo", pid);
  449. if ((fp = fopen(path, "r")) == NULL)
  450. {
  451. return;
  452. }
  453. if (fscanf(fp, "%d", &version) != 1)
  454. {
  455. fclose(fp);
  456. return;
  457. }
  458. if (version != PSINFO_VERSION)
  459. {
  460. fputs("procfs version mismatch!\n", stderr);
  461. exit(1);
  462. }
  463. if (fscanf(fp, " %c %d", &type, &endpt) != 2)
  464. {
  465. fclose(fp);
  466. return;
  467. }
  468. slot++;
  469. if (slot < 0 || slot >= nr_total)
  470. {
  471. fprintf(stderr, "top: unreasonable endpoint number %d\n", endpt);
  472. fclose(fp);
  473. return;
  474. }
  475. p = &proc[slot];
  476. if (type == TYPE_TASK)
  477. {
  478. p->p_flags |= IS_TASK;
  479. }
  480. else if (type == TYPE_SYSTEM)
  481. {
  482. p->p_flags |= IS_SYSTEM;
  483. }
  484. p->p_endpoint = endpt;
  485. p->p_pid = pid;
  486. if (fscanf(fp, " %255s %c %d %d %lu %*u %lu %lu",
  487. name, &state, &p->p_blocked, &p->p_priority,
  488. &p->p_user_time, &cycles_hi, &cycles_lo) != 7)
  489. {
  490. fclose(fp);
  491. return;
  492. }
  493. strncpy(p->p_name, name, sizeof(p->p_name) - 1);
  494. p->p_name[sizeof(p->p_name) - 1] = 0;
  495. if (state != STATE_RUN)
  496. {
  497. p->p_flags |= BLOCKED;
  498. }
  499. p->p_cpucycles[0] = make64(cycles_lo, cycles_hi);
  500. p->p_memory = 0L;
  501. if (!(p->p_flags & IS_TASK))
  502. {
  503. int j;
  504. if ((j = fscanf(fp, " %lu %*u %*u %*c %*d %*u %u %*u %d %*c %*d %*u",
  505. &p->p_memory, &effuid, &p->p_nice)) != 3)
  506. {
  507. fclose(fp);
  508. return;
  509. }
  510. p->p_effuid = effuid;
  511. }
  512. else
  513. p->p_effuid = 0;
  514. for (i = 1; i < CPUTIMENAMES; i++)
  515. {
  516. if (fscanf(fp, " %lu %lu",
  517. &cycles_hi, &cycles_lo) == 2)
  518. {
  519. p->p_cpucycles[i] = make64(cycles_lo, cycles_hi);
  520. }
  521. else
  522. {
  523. p->p_cpucycles[i] = 0;
  524. }
  525. }
  526. if ((p->p_flags & IS_TASK))
  527. {
  528. if (fscanf(fp, " %lu", &p->p_memory) != 1)
  529. {
  530. p->p_memory = 0;
  531. }
  532. }
  533. p->p_flags |= USED;
  534. fclose(fp);
  535. }
  536. void getkinfo()
  537. {
  538. FILE *fp;
  539. if ((fp = fopen("/proc/kinfo", "r")) == NULL)
  540. {
  541. fprintf(stderr, "opening " _PATH_PROC "kinfo failed\n");
  542. exit(1);
  543. }
  544. if (fscanf(fp, "%u %u", &nr_procs, &nr_tasks) != 2)
  545. {
  546. fprintf(stderr, "reading from " _PATH_PROC "kinfo failed\n");
  547. exit(1);
  548. }
  549. fclose(fp);
  550. nr_total = (int)(nr_procs + nr_tasks);
  551. }
  552. void print_procs(struct proc *proc1, struct proc *proc2, int cputimemode)
  553. {
  554. int p, nprocs;
  555. u64_t systemticks = 0;
  556. u64_t userticks = 0;
  557. u64_t total_ticks = 0;
  558. int blockedseen = 0;
  559. static struct tp *tick_procs = NULL;
  560. if (tick_procs == NULL)
  561. {
  562. tick_procs = malloc(nr_total * sizeof(tick_procs[0]));
  563. if (tick_procs == NULL)
  564. {
  565. fprintf(stderr, "Out of memory!\n");
  566. exit(1);
  567. }
  568. }
  569. for (p = nprocs = 0; p < nr_total; p++)
  570. {
  571. u64_t uticks;
  572. if (!(proc2[p].p_flags & USED))
  573. {
  574. continue;
  575. }
  576. tick_procs[nprocs].p = proc2 + p;
  577. tick_procs[nprocs].ticks = cputicks(&proc1[p], &proc2[p], cputimemode);
  578. uticks = cputicks(&proc1[p], &proc2[p], 1);
  579. total_ticks = total_ticks + uticks;
  580. if (!(proc2[p].p_flags & IS_TASK))
  581. {
  582. if (proc2[p].p_flags & IS_SYSTEM)
  583. {
  584. systemticks = systemticks + tick_procs[nprocs].ticks;
  585. }
  586. else
  587. {
  588. userticks = userticks + tick_procs[nprocs].ticks;
  589. }
  590. }
  591. nprocs++;
  592. }
  593. if (total_ticks == 0)
  594. {
  595. return;
  596. }
  597. printf("CPU states: %6.2f%% user\t", 100.0 * userticks / total_ticks);
  598. printf("%6.2f%% system\t", 100.0 * systemticks / total_ticks);
  599. printf("%6.2f%% in total\n", 100.0 * (systemticks + userticks) / total_ticks);
  600. }
  601. u64_t cputicks(struct proc *p1, struct proc *p2, int timemode)
  602. {
  603. int i;
  604. u64_t t = 0;
  605. for (i = 0; i < CPUTIMENAMES; i++)
  606. {
  607. if (!CPUTIME(timemode, i))
  608. {
  609. continue;
  610. }
  611. if (p1->p_endpoint == p2->p_endpoint)
  612. {
  613. t = t + p2->p_cpucycles[i] - p1->p_cpucycles[i];
  614. }
  615. else
  616. {
  617. t = t + p2->p_cpucycles[i];
  618. }
  619. }
  620. return t;
  621. }