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.

705 regels
12 KiB

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