OS2021_Project1.Shell
Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

701 řádky
12 KiB

před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
před 3 roky
  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. static inline u64_t make64(unsigned long lo, unsigned long hi)
  34. {
  35. return ((u64_t)hi << 32) | (u64_t)lo;
  36. }
  37. int nr_total = 0;
  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;
  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);
  424. if (!end[0] && pid != 0)
  425. {
  426. parse_file(pid);
  427. }
  428. }
  429. closedir(p_dir);
  430. }
  431. void parse_file(pid_t pid)
  432. {
  433. char path[PATH_MAX], name[256], type, state;
  434. int version, endpt, effuid;
  435. unsigned long cycles_hi, cycles_lo;
  436. FILE *fp;
  437. struct proc *p;
  438. int slot;
  439. int i;
  440. sprintf(path, "%d/psinfo", pid);
  441. if ((fp = fopen(path, "r")) == NULL)
  442. return;
  443. if (fscanf(fp, "%d", &version) != 1)
  444. {
  445. fclose(fp);
  446. return;
  447. }
  448. if (version != PSINFO_VERSION)
  449. {
  450. fputs("procfs version mismatch!\n", stderr);
  451. exit(1);
  452. }
  453. if (fscanf(fp, " %c %d", &type, &endpt) != 2)
  454. {
  455. fclose(fp);
  456. return;
  457. }
  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. {
  468. p->p_flags |= IS_TASK;
  469. }
  470. else if (type == TYPE_SYSTEM)
  471. {
  472. p->p_flags |= IS_SYSTEM;
  473. }
  474. p->p_endpoint = endpt;
  475. p->p_pid = pid;
  476. 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)
  477. {
  478. fclose(fp);
  479. return;
  480. }
  481. strncpy(p->p_name, name, sizeof(p->p_name) - 1);
  482. p->p_name[sizeof(p->p_name) - 1] = 0;
  483. if (state != STATE_RUN)
  484. {
  485. p->p_flags |= BLOCKED;
  486. }
  487. p->p_cpucycles[0] = make64(cycles_lo, cycles_hi);
  488. p->p_memory = 0L;
  489. if (!(p->p_flags & IS_TASK))
  490. {
  491. int j;
  492. if ((j = fscanf(fp, " %lu %*u %*u %*c %*d %*u %u %*u %d %*c %*d %*u", &p->p_memory, &effuid, &p->p_nice)) != 3)
  493. {
  494. fclose(fp);
  495. return;
  496. }
  497. p->p_effuid = effuid;
  498. }
  499. else
  500. {
  501. p->p_effuid = 0;
  502. }
  503. for (i = 1; i < CPUTIMENAMES; i++)
  504. {
  505. if (fscanf(fp, " %lu %lu", &cycles_hi, &cycles_lo) == 2)
  506. {
  507. p->p_cpucycles[i] = make64(cycles_lo, cycles_hi);
  508. }
  509. else
  510. {
  511. p->p_cpucycles[i] = 0;
  512. }
  513. }
  514. if ((p->p_flags & IS_TASK))
  515. {
  516. if (fscanf(fp, " %lu", &p->p_memory) != 1)
  517. {
  518. p->p_memory = 0;
  519. }
  520. }
  521. p->p_flags |= USED;
  522. fclose(fp);
  523. }
  524. void getkinfo()
  525. {
  526. FILE *fp;
  527. if ((fp = fopen("/proc/kinfo", "r")) == NULL)
  528. {
  529. fprintf(stderr, "opening " _PATH_PROC "kinfo failed\n");
  530. exit(1);
  531. }
  532. if (fscanf(fp, "%u %u", &nr_procs, &nr_tasks) != 2)
  533. {
  534. fprintf(stderr, "reading from " _PATH_PROC "kinfo failed\n");
  535. exit(1);
  536. }
  537. fclose(fp);
  538. nr_total = (int)(nr_procs + nr_tasks);
  539. }
  540. void print_procs(struct proc *proc1, struct proc *proc2, int cputimemode)
  541. {
  542. int p, nprocs;
  543. u64_t systemticks = 0;
  544. u64_t userticks = 0;
  545. u64_t total_ticks = 0;
  546. int blockedseen = 0;
  547. static struct tp *tick_procs = NULL;
  548. if (tick_procs == NULL)
  549. {
  550. tick_procs = malloc(nr_total * sizeof(tick_procs[0]));
  551. if (tick_procs == NULL)
  552. {
  553. fprintf(stderr, "Out of memory!\n");
  554. exit(1);
  555. }
  556. }
  557. for (p = nprocs = 0; p < nr_total; p++)
  558. {
  559. u64_t uticks;
  560. if (!(proc2[p].p_flags & USED))
  561. {
  562. continue;
  563. }
  564. tick_procs[nprocs].p = proc2 + p;
  565. tick_procs[nprocs].ticks = cputicks(&proc1[p], &proc2[p], cputimemode);
  566. uticks = cputicks(&proc1[p], &proc2[p], 1);
  567. total_ticks = total_ticks + uticks;
  568. if (!(proc2[p].p_flags & IS_TASK))
  569. {
  570. if (proc2[p].p_flags & IS_SYSTEM)
  571. {
  572. systemticks = systemticks + tick_procs[nprocs].ticks;
  573. }
  574. else
  575. {
  576. userticks = userticks + tick_procs[nprocs].ticks;
  577. }
  578. }
  579. nprocs++;
  580. }
  581. if (total_ticks == 0)
  582. {
  583. return;
  584. }
  585. printf("CPU states: %6.2f%% user, ", 100.0 * userticks / total_ticks);
  586. printf("%6.2f%% system", 100.0 * systemticks / total_ticks);
  587. printf("%6.2f%% in total\n", 100.0 * (systemticks + userticks) / total_ticks);
  588. }
  589. u64_t cputicks(struct proc *p1, struct proc *p2, int timemode)
  590. {
  591. int i;
  592. u64_t t = 0;
  593. for (i = 0; i < CPUTIMENAMES; i++)
  594. {
  595. if (!CPUTIME(timemode, i))
  596. {
  597. continue;
  598. }
  599. if (p1->p_endpoint == p2->p_endpoint)
  600. {
  601. {
  602. t = t + p2->p_cpucycles[i] - p1->p_cpucycles[i];
  603. }
  604. }
  605. else
  606. {
  607. t = t + p2->p_cpucycles[i];
  608. }
  609. }
  610. return t;
  611. }