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.

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