《操作系统》的实验代码。
25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

254 lines
5.8 KiB

  1. #include <ulib.h>
  2. #include <stdio.h>
  3. #include <string.h>
  4. #include <dir.h>
  5. #include <file.h>
  6. #include <error.h>
  7. #include <unistd.h>
  8. #define printf(...) fprintf(1, __VA_ARGS__)
  9. #define putc(c) printf("%c", c)
  10. #define BUFSIZE 4096
  11. #define WHITESPACE " \t\r\n"
  12. #define SYMBOLS "<|>&;"
  13. char shcwd[BUFSIZE];
  14. int
  15. gettoken(char **p1, char **p2) {
  16. char *s;
  17. if ((s = *p1) == NULL) {
  18. return 0;
  19. }
  20. while (strchr(WHITESPACE, *s) != NULL) {
  21. *s ++ = '\0';
  22. }
  23. if (*s == '\0') {
  24. return 0;
  25. }
  26. *p2 = s;
  27. int token = 'w';
  28. if (strchr(SYMBOLS, *s) != NULL) {
  29. token = *s, *s ++ = '\0';
  30. }
  31. else {
  32. bool flag = 0;
  33. while (*s != '\0' && (flag || strchr(WHITESPACE SYMBOLS, *s) == NULL)) {
  34. if (*s == '"') {
  35. *s = ' ', flag = !flag;
  36. }
  37. s ++;
  38. }
  39. }
  40. *p1 = (*s != '\0' ? s : NULL);
  41. return token;
  42. }
  43. char *
  44. readline(const char *prompt) {
  45. static char buffer[BUFSIZE];
  46. if (prompt != NULL) {
  47. printf("%s", prompt);
  48. }
  49. int ret, i = 0;
  50. while (1) {
  51. char c;
  52. if ((ret = read(0, &c, sizeof(char))) < 0) {
  53. return NULL;
  54. }
  55. else if (ret == 0) {
  56. if (i > 0) {
  57. buffer[i] = '\0';
  58. break;
  59. }
  60. return NULL;
  61. }
  62. if (c == 3) {
  63. return NULL;
  64. }
  65. else if (c >= ' ' && i < BUFSIZE - 1) {
  66. putc(c);
  67. buffer[i ++] = c;
  68. }
  69. else if (c == '\b' && i > 0) {
  70. putc(c);
  71. i --;
  72. }
  73. else if (c == '\n' || c == '\r') {
  74. putc(c);
  75. buffer[i] = '\0';
  76. break;
  77. }
  78. }
  79. return buffer;
  80. }
  81. void
  82. usage(void) {
  83. printf("usage: sh [command-file]\n");
  84. }
  85. int
  86. reopen(int fd2, const char *filename, uint32_t open_flags) {
  87. int ret, fd1;
  88. close(fd2);
  89. if ((ret = open(filename, open_flags)) >= 0 && ret != fd2) {
  90. close(fd2);
  91. fd1 = ret, ret = dup2(fd1, fd2);
  92. close(fd1);
  93. }
  94. return ret < 0 ? ret : 0;
  95. }
  96. int
  97. testfile(const char *name) {
  98. int ret;
  99. if ((ret = open(name, O_RDONLY)) < 0) {
  100. return ret;
  101. }
  102. close(ret);
  103. return 0;
  104. }
  105. int
  106. runcmd(char *cmd) {
  107. static char argv0[BUFSIZE];
  108. const char *argv[EXEC_MAX_ARG_NUM + 1];
  109. char *t;
  110. int argc, token, ret, p[2];
  111. again:
  112. argc = 0;
  113. while (1) {
  114. switch (token = gettoken(&cmd, &t)) {
  115. case 'w':
  116. if (argc == EXEC_MAX_ARG_NUM) {
  117. printf("sh error: too many arguments\n");
  118. return -1;
  119. }
  120. argv[argc ++] = t;
  121. break;
  122. case '<':
  123. if (gettoken(&cmd, &t) != 'w') {
  124. printf("sh error: syntax error: < not followed by word\n");
  125. return -1;
  126. }
  127. if ((ret = reopen(0, t, O_RDONLY)) != 0) {
  128. return ret;
  129. }
  130. break;
  131. case '>':
  132. if (gettoken(&cmd, &t) != 'w') {
  133. printf("sh error: syntax error: > not followed by word\n");
  134. return -1;
  135. }
  136. if ((ret = reopen(1, t, O_RDWR | O_TRUNC | O_CREAT)) != 0) {
  137. return ret;
  138. }
  139. break;
  140. case '|':
  141. // if ((ret = pipe(p)) != 0) {
  142. // return ret;
  143. // }
  144. if ((ret = fork()) == 0) {
  145. close(0);
  146. if ((ret = dup2(p[0], 0)) < 0) {
  147. return ret;
  148. }
  149. close(p[0]), close(p[1]);
  150. goto again;
  151. }
  152. else {
  153. if (ret < 0) {
  154. return ret;
  155. }
  156. close(1);
  157. if ((ret = dup2(p[1], 1)) < 0) {
  158. return ret;
  159. }
  160. close(p[0]), close(p[1]);
  161. goto runit;
  162. }
  163. break;
  164. case 0:
  165. goto runit;
  166. case ';':
  167. if ((ret = fork()) == 0) {
  168. goto runit;
  169. }
  170. else {
  171. if (ret < 0) {
  172. return ret;
  173. }
  174. waitpid(ret, NULL);
  175. goto again;
  176. }
  177. break;
  178. default:
  179. printf("sh error: bad return %d from gettoken\n", token);
  180. return -1;
  181. }
  182. }
  183. runit:
  184. if (argc == 0) {
  185. return 0;
  186. }
  187. else if (strcmp(argv[0], "cd") == 0) {
  188. if (argc != 2) {
  189. return -1;
  190. }
  191. strcpy(shcwd, argv[1]);
  192. return 0;
  193. }
  194. if ((ret = testfile(argv[0])) != 0) {
  195. if (ret != -E_NOENT) {
  196. return ret;
  197. }
  198. snprintf(argv0, sizeof(argv0), "/%s", argv[0]);
  199. argv[0] = argv0;
  200. }
  201. argv[argc] = NULL;
  202. return __exec(NULL, argv);
  203. }
  204. int
  205. main(int argc, char **argv) {
  206. printf("user sh is running!!!");
  207. int ret, interactive = 1;
  208. if (argc == 2) {
  209. if ((ret = reopen(0, argv[1], O_RDONLY)) != 0) {
  210. return ret;
  211. }
  212. interactive = 0;
  213. }
  214. else if (argc > 2) {
  215. usage();
  216. return -1;
  217. }
  218. //shcwd = malloc(BUFSIZE);
  219. assert(shcwd != NULL);
  220. char *buffer;
  221. while ((buffer = readline((interactive) ? "$ " : NULL)) != NULL) {
  222. shcwd[0] = '\0';
  223. int pid;
  224. if ((pid = fork()) == 0) {
  225. ret = runcmd(buffer);
  226. exit(ret);
  227. }
  228. assert(pid >= 0);
  229. if (waitpid(pid, &ret) == 0) {
  230. if (ret == 0 && shcwd[0] != '\0') {
  231. ret = 0;
  232. }
  233. if (ret != 0) {
  234. printf("error: %d - %e\n", ret, ret);
  235. }
  236. }
  237. }
  238. return 0;
  239. }