Advertisement
Guest User

Untitled

a guest
Dec 3rd, 2019
91
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 22.48 KB | None | 0 0
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <ctype.h>
  5. #include <unistd.h>
  6. #include <sys/stat.h>
  7. #include <fcntl.h>
  8.  
  9. #include <sys/wait.h>
  10. #include <sys/types.h>
  11. #include <signal.h>
  12.  
  13. enum states {NONE, OUT, APPEND_STATES, IN, AMPERSAND_STATES, CONV_STATES, OR, AND, SEMI, BRACKETOPEN, BRACKETCLOSE }; //
  14.  
  15. struct cmd {
  16. char **argv;//массив на выполнение
  17. int argc;//кол-во слов
  18. char *infile;
  19. char *outfile;
  20. int append; // >>
  21. int back_ground; // background process
  22. struct cmd * conveyor;
  23. struct cmd * logic;
  24. struct cmd * brackets;
  25. enum states operation;
  26. };
  27. struct cmd struct_noun = {};
  28.  
  29. int is_special(char simvol) {
  30. return (simvol=='(') || (simvol==')') || (simvol=='&') || (simvol=='|') || (simvol==';') || (simvol=='>') || (simvol=='<');
  31. }
  32.  
  33. // структура для хранения пидов фоновых процессов
  34. typedef struct pnode * process_list;
  35. process_list back_ground_pids = NULL; // список фоновых процессов
  36.  
  37. struct pnode {
  38. pid_t process_id;
  39. int msg;
  40. process_list next;
  41. };
  42.  
  43. // добавление процесса к списку процессов
  44. void add_list(process_list *list, pid_t process_id, int msg) {
  45. process_list pointer_main;
  46. pointer_main = malloc(sizeof(*pointer_main));
  47. pointer_main->process_id = process_id;
  48. pointer_main->msg = msg;
  49. pointer_main->next = *list;
  50. *list = list;
  51. }
  52.  
  53. // удаление процесса из списка
  54. void remove_list(process_list *list, pid_t process_id) {
  55. process_list pointer_main;
  56.  
  57.  
  58. if (*list == NULL) {
  59. return;
  60. }
  61. if ((*list)->process_id == process_id) {
  62. pointer_main = *list;
  63. *list = (*list) -> next;
  64. free(pointer_main);
  65. } else {
  66. remove_list(&(*list) -> next, process_id);
  67. }
  68. }
  69.  
  70. // уничтожение списка фоновых процессов с попыткой удалить зомби
  71. void back_ground_destroy_list(process_list list) {
  72. process_list pointer_main;
  73. if (list == NULL) {
  74. return;
  75. }
  76. pointer_main = list;
  77. waitpid(pointer_main->process_id,NULL,WNOHANG);
  78. back_ground_destroy_list(list->next);
  79. free(pointer_main);
  80. }
  81.  
  82. // проверка завершившихся процессов
  83. void back_ground_check(process_list *list) {
  84. process_list pointer_main;
  85. int status;
  86. if (*list == NULL) {
  87. return;
  88. }
  89. int pointer_ground_check;
  90. if ((pointer_ground_check=waitpid((*list)->process_id, &status,WNOHANG)) == (*list)->process_id) {
  91. if ((*list)->msg) {
  92. printf("process %d completed\n",(*list)->process_id);
  93. }
  94. pointer_main = *list;
  95. *list = (*list)->next;
  96. back_ground_check(list);
  97. free(pointer_main);
  98. } else {
  99. //printf("process %d not completed; pointer_main = %d\n",(*list)->process_id, pointer_ground_check);
  100. back_ground_check(&(*list)->next);
  101. }
  102. }
  103.  
  104. // остановка всех незавершившихся фоновых процессов при выходе из программы
  105. void back_ground_stop_all(process_list list) {
  106. process_list pointer_main = list;
  107. while (pointer_main != NULL) {
  108. kill(pointer_main -> process_id, SIGTERM);
  109. pointer_main = pointer_main -> next;
  110. }
  111. back_ground_destroy_list(list);
  112. }
  113.  
  114. char* get_string () {
  115. char*stroka = NULL;
  116. int i = 0, size = 1;
  117. int simvol;
  118. stroka = malloc (size);
  119. stroka[0] = '\0';
  120. do {
  121. simvol = getchar();
  122. if (simvol == EOF ) {
  123. free(stroka);
  124. return NULL;
  125. }
  126. if (simvol == '\n') {
  127. return stroka;
  128. }
  129. if (i + 1 >= size) {
  130. size += 20;
  131. stroka = realloc (stroka, size);
  132. }
  133. stroka[i] = simvol;
  134. i++;
  135. stroka[i]='\0';
  136. } while (1);
  137. }
  138.  
  139. void add_word (char *** pointer_add_word, int *i, int *size, char *pointer_main, int n) {
  140. char **pointer_secondary = *pointer_add_word;
  141. if (*i + 1 >= *size) {
  142. *size+=10;
  143. pointer_secondary = realloc(pointer_secondary, (*size) * sizeof(*pointer_secondary));
  144. }
  145. pointer_secondary[*i] = malloc(n+1);
  146. memcpy(pointer_secondary[*i],pointer_main,n);
  147. pointer_secondary[*i][n]=0;
  148. (*i)++;
  149. pointer_secondary[*i] = NULL;
  150. *pointer_add_word = pointer_secondary;
  151. }
  152.  
  153.  
  154. char* check(char *pointer_main, enum states *state) {
  155. *state = NONE;
  156. switch (*pointer_main) {
  157. case '<':
  158. *state = IN;
  159. pointer_main++;
  160. break;
  161. case '>':
  162. *state = OUT;
  163. pointer_main++;
  164. break;
  165. case '|':
  166. *state = CONV_STATES;
  167. pointer_main++;
  168. break;
  169. case '&':
  170. *state = AMPERSAND_STATES;
  171. pointer_main++;
  172. break;
  173. case ';':
  174. *state = SEMI;
  175. pointer_main++;
  176. break;
  177. case '(':
  178. *state = BRACKETOPEN;
  179. pointer_main++;
  180. break;
  181. case ')':
  182. *state = BRACKETCLOSE;
  183. pointer_main++;
  184. break;
  185. default:
  186. pointer_main++;
  187. break;
  188. }
  189. switch (*state) {
  190. case OUT:
  191. if (*pointer_main=='>') {
  192. *state = APPEND_STATES;
  193. pointer_main++;
  194. }
  195. break;
  196. case AMPERSAND_STATES:
  197. if (*pointer_main=='&') {
  198. *state = AND;
  199. pointer_main++;
  200. }
  201. break;
  202. case CONV_STATES:
  203. if (*pointer_main=='|') {
  204. *state = OR;
  205. pointer_main++;
  206. }
  207. break;
  208. default:
  209. break;
  210. }
  211. return pointer_main;
  212. }
  213.  
  214. char ** parse_words (char *pointer_main) {
  215. int space = 1, mode_flag = 0;
  216. char **pointer_secondary = NULL;
  217. char *first = NULL;
  218. enum states state;
  219. int i =0, size = 0;
  220. while (*pointer_main != '\0') {
  221. if (mode_flag) { // "
  222. if (*pointer_main == '"') {
  223. add_word (&pointer_secondary, &i, &size, first, pointer_main - first);
  224. mode_flag = 0;
  225. space = 1;
  226. }
  227. pointer_main++;
  228. } else if (is_special(*pointer_main)) {
  229. if (!space) {
  230. add_word (&pointer_secondary, &i, &size, first, pointer_main - first);
  231. }
  232. first = pointer_main;
  233. pointer_main = check(pointer_main, &state);
  234. if (pointer_main - first != 0) {
  235. add_word (&pointer_secondary, &i, &size, first, pointer_main - first);
  236. }
  237. space = 1;
  238. }
  239. else {
  240. if (space) {
  241. if (! isspace(*pointer_main)) {
  242. first = pointer_main;
  243. space = 0;
  244. if (*pointer_main == '"') {
  245. first = pointer_main+1;
  246. mode_flag = 1;
  247. }
  248. }
  249. }
  250. else {
  251. if (isspace (*pointer_main)) {
  252. add_word (&pointer_secondary, &i, &size, first, pointer_main - first);
  253. space =1;
  254. }
  255. }
  256. pointer_main++;
  257. }
  258. }
  259. if (mode_flag == 1) {
  260. printf ("unclosed \"\n");
  261. free_words (pointer_secondary);
  262. return NULL;
  263. }
  264. if (!space) {
  265. add_word(&pointer_secondary, &i, &size, first, pointer_main - first);
  266. }
  267. return pointer_secondary;
  268. }
  269.  
  270. void cd (char *word) {
  271. int point;
  272. point = chdir (word);
  273. if ( point == -1) {
  274. printf ("ERROR CD\n");
  275. }
  276. }
  277.  
  278. void add_io(char **name, char *word) {
  279. if (*name != NULL) {
  280. printf("WARNING: duplicated I/O: %s\n", word);
  281. return;
  282. }
  283. *name = malloc(strlen(word) + 1);
  284. strcpy(*name, word);
  285. }
  286.  
  287. struct cmd * start_commands(char **words, int *size) {
  288. struct cmd * pointer_struct = malloc(sizeof(struct cmd)); // запись выделенной памяти
  289. *pointer_struct = struct_noun; // обнуление
  290. *size = 10;
  291. pointer_struct->argv = malloc(*size * sizeof(*pointer_struct->argv));
  292. pointer_struct->argv[pointer_struct->argc] = malloc(strlen(*words) + 1); //выделение памяти под команды
  293. strcpy(pointer_struct->argv[pointer_struct->argc],*words); // копирование команды
  294. pointer_struct->argc++; // argc =1
  295. pointer_struct->argv[pointer_struct->argc] = NULL;
  296. return pointer_struct;
  297. }
  298.  
  299. struct cmd * build_cmd(char ***words) {
  300. if (*words == NULL) {
  301. return NULL;
  302. }
  303.  
  304. struct cmd *pointer_struct = malloc(sizeof(*pointer_struct)), *begin_place = pointer_struct, *begin_first = pointer_struct; // адрес первой команды
  305. *pointer_struct = struct_noun; // обнуление
  306. int size = 0;
  307. enum states state = NONE; // состояние ожидания имени
  308.  
  309. while (**words) {
  310. if (is_special(***words)) {
  311. enum states new_state;
  312. check(**words, &new_state); // записать в new_state тип спец. символа
  313. if (new_state == AMPERSAND_STATES) {
  314. begin_place->back_ground = 1; // ****
  315. } else if (new_state == BRACKETOPEN) {
  316. switch (state) {
  317. case OR:
  318. case AND:
  319. case SEMI:
  320. begin_place->logic = start_commands(*words, &size);
  321. begin_place->operation = state;
  322. begin_place = begin_place->logic;
  323. pointer_struct = begin_place;
  324. state = NONE;
  325. break;
  326. case CONV_STATES:
  327. pointer_struct->conveyor = start_commands(*words, &size);
  328. pointer_struct = pointer_struct->conveyor;
  329. state = NONE;
  330. break;
  331. case BRACKETOPEN:
  332. pointer_struct->brackets = start_commands(*words, &size);
  333. pointer_struct = pointer_struct->brackets;
  334.  
  335. break;
  336. default:
  337. break;
  338. }
  339. (*words)++;
  340. pointer_struct->brackets = build_cmd(words);
  341. state = NONE;
  342. } else if (new_state == BRACKETCLOSE) {
  343. //(*words)++;
  344. break;
  345. } else if (state == NONE) {
  346. state = new_state;
  347. } else {
  348. printf("ERROR: unprocessed special simvol\n");
  349. }
  350. } else {
  351. switch (state) {
  352. case IN:
  353. add_io(&pointer_struct->infile, **words);
  354. state = NONE;
  355. break;
  356. case OUT:
  357. add_io(&pointer_struct->outfile, **words);
  358. state = NONE;
  359. break;
  360. case APPEND_STATES:
  361. add_io(&pointer_struct->outfile, **words);
  362. pointer_struct->append = 1;
  363. state = NONE;
  364. break;
  365. case CONV_STATES:
  366. pointer_struct->conveyor = start_commands(*words, &size);
  367. pointer_struct = pointer_struct->conveyor;
  368. state = NONE;
  369. break;
  370. case OR:
  371. case AND:
  372. case SEMI:
  373. begin_place->logic = start_commands(*words, &size);
  374. begin_place->operation = state;
  375. begin_place = begin_place->logic;
  376. pointer_struct = begin_place;
  377. state = NONE;
  378. break;
  379. case BRACKETOPEN:
  380.  
  381. break;
  382. default:
  383. if (pointer_struct->argc + 1 >= size) {
  384. size+=10;
  385. pointer_struct->argv = realloc(pointer_struct->argv, size * sizeof(*pointer_struct->argv));
  386. }
  387. pointer_struct->argv[pointer_struct->argc] = malloc(strlen(**words) + 1);
  388. strcpy(pointer_struct->argv[pointer_struct->argc],**words);
  389. pointer_struct->argc++;
  390. pointer_struct->argv[pointer_struct->argc] = NULL;
  391. break;
  392. }
  393. }
  394. (*words)++;
  395. }
  396. if (state != NONE) {
  397. printf("ERROR: syntax\n");
  398. }
  399. return begin_first; // возврат первой команды в конвейере
  400. }
  401.  
  402. void print_words (char **pointer_secondary) {
  403. if (pointer_secondary == NULL) {
  404. return;
  405. }
  406. while (*pointer_secondary != NULL) {
  407. fprintf (stderr,"%s ", *pointer_secondary);
  408. pointer_secondary++;
  409. }
  410. }
  411.  
  412. void print_operation(enum states operation) {
  413. if (operation == SEMI) {
  414. fprintf(stderr,"%s ",";");
  415. } else if (operation == OR) {
  416. fprintf(stderr,"%s ","||");
  417. } else if (operation == AND) {
  418. fprintf(stderr,"%s ","&&");
  419. } else {
  420. fprintf(stderr,"none");
  421. }
  422. }
  423.  
  424. void print_command(struct cmd *begin_place) { // печать команд конвейера для отладки
  425. struct cmd *command;
  426. while (begin_place != NULL) {
  427. command = begin_place;
  428. while (command != NULL) {
  429. if (command->brackets != NULL) {
  430. fprintf(stderr," ( ");
  431. print_command(command->brackets);
  432. fprintf(stderr," ) ");
  433. } else {
  434. print_words(command->argv);
  435. }
  436. if (command->infile != NULL) {
  437. fprintf(stderr,"<%s ",command->infile);
  438. }
  439. if (command->outfile != NULL) {
  440. if (command->append) {
  441. fprintf(stderr,">>%s ",command->outfile);
  442. } else {
  443. fprintf(stderr,">%s ",command->outfile);
  444. }
  445. }
  446. command = command->conveyor;
  447. if (command != NULL) {
  448. fprintf(stderr," | ");
  449. }
  450. }
  451. if (begin_place->logic != NULL) {
  452. print_operation(begin_place->operation);
  453. }
  454. begin_place = begin_place->logic;
  455. }
  456. fprintf(stderr,"\n");
  457. }
  458.  
  459. void free_command(struct cmd *begin_place) {
  460. struct cmd *pointer_main;
  461. struct cmd *command, *nextbeg;
  462. while (begin_place != NULL) {
  463. command = begin_place;
  464. nextbeg = begin_place->logic;
  465. while (command != NULL) {
  466. if (command->brackets!= NULL) {
  467. free_command(command->brackets);
  468. } else {
  469. for (int i=0; i < command->argc; i++) {
  470. free(command->argv[i]);
  471. }
  472. }
  473. free(command->argv);
  474. free(command->infile);
  475. free(command->outfile);
  476. pointer_main = command;
  477. command = command -> conveyor; // ****
  478. free(pointer_main);
  479. }
  480. begin_place = nextbeg;
  481. }
  482. }
  483.  
  484. int run(struct cmd * begin_place) {
  485. int input; // файл ввода для процесса; -1 если не надо переназначать
  486. int file_descriptor[2];
  487. pid_t process_id_optional, wait_pid;
  488. struct cmd * command;
  489. int status;
  490. int result = 1;
  491.  
  492. //*begbeg = begin_place; //begin_place - первая команда (нужно для удаления)
  493. while (begin_place != NULL) {
  494. command = begin_place;
  495. file_descriptor[0] = -1;
  496. file_descriptor[1] = -1;
  497. // print_command(command);
  498. while (command != NULL) {
  499. //printf("command = %pointer_main\n",command);
  500. if (command->argv && command->argv[0] != NULL && strcmp(command->argv[0], "cd") == 0) {
  501. cd(command->argv[1]);
  502. }
  503. else {
  504. input = file_descriptor[0]; // определяем стандартный ввод
  505. if (command->conveyor) { // если есть следующий команды
  506. pipe(file_descriptor); // создаем неименованный канал
  507. }
  508. process_id_optional = fork();
  509. if (process_id_optional == 0) {
  510. if (command->conveyor) {
  511. close(file_descriptor[0]);
  512. }
  513. int pointer_f;
  514. if (input != -1) { // если ввод переопределен, копируем в нулевой канал
  515. dup2(input,0);
  516. close(input);
  517. input = -1;
  518. }
  519. if (command->infile) { // или ввод из файла
  520. pointer_f = open(command->infile, O_RDONLY);
  521. if (pointer_f == -1) {
  522. printf("error open file for read: %s\n",command->infile);
  523. exit(1);
  524. }
  525. dup2(pointer_f,0);
  526. close(pointer_f);
  527. }
  528. if (command->outfile) { // вывод
  529. if (command->append == 0) {
  530. pointer_f = creat(command->outfile, 0666);
  531. if (pointer_f == -1) {
  532. printf("error create file: %s\n",command->outfile);
  533. exit(1);
  534. }
  535. } else {
  536. pointer_f = open(command->outfile, O_WRONLY | O_APPEND);
  537. if (pointer_f == -1) {
  538. printf("error open file for append: %s\n",command->outfile);
  539. exit(1);
  540. }
  541. }
  542. dup2(pointer_f,1);
  543. close(pointer_f);
  544. }
  545. else
  546. if (command->conveyor) {
  547. dup2(file_descriptor[1],1);
  548. close(file_descriptor[1]);
  549. file_descriptor[1] = -1;
  550. }
  551. if (command->back_ground) {
  552. pointer_f = open ("/dev/null", O_RDONLY);
  553. if (pointer_f == -1){
  554. printf ("can not open file for read: null\n");
  555. }
  556. dup2 (pointer_f,0);
  557. close (pointer_f);
  558. }
  559.  
  560. if (command->brackets != NULL) {
  561. //fprintf(stderr," launch () \n");
  562. int res = run(command->brackets);
  563. exit (1-res);
  564. } else {
  565. execvp(command->argv[0], &command->argv[0]);
  566. printf("error exec %s\n",command->argv[0]);
  567. exit(0);
  568. }
  569. }
  570. else if (process_id_optional<0) {
  571. printf ("ERROR");
  572. }
  573. if (file_descriptor[1] != -1) {
  574. close(file_descriptor[1]);
  575. file_descriptor[1] = -1;
  576. }
  577. if (command->back_ground) {
  578. add_list(&back_ground_pids, process_id_optional, 1);
  579. }
  580. else {
  581. if (command->conveyor != NULL) {
  582. add_list(&back_ground_pids, process_id_optional, 0);
  583. } else {
  584. wait_pid = process_id_optional;
  585. }
  586. }
  587. back_ground_check(&back_ground_pids);
  588. }
  589. if (input != -1) {
  590. close(input);
  591. input = -1;
  592. }
  593.  
  594. command = command->conveyor;
  595. } //while
  596. waitpid(wait_pid, &status, 0);
  597. result = WIFEXITED(status) && (WEXITSTATUS(status) == 0);
  598. //print_operation(begin_place->operation);
  599. //fprintf(stderr," *result=%d; begin_place->logic=%pointer_main; operation=%d\n",result,begin_place->logic,begin_place->operation);
  600. while ((begin_place->logic != NULL) &&
  601. (((begin_place->operation == AND) && (result == 0)) ||
  602. ((begin_place->operation == OR) && (result != 0)))
  603. ) {
  604. begin_place = begin_place->logic;
  605. }
  606. //fprintf(stderr,"**result=%d; begin_place->logic=%pointer_main\n",result,begin_place->logic);
  607. begin_place = begin_place->logic;
  608. //fprintf(stderr,"**result=%d; begin_place=%pointer_main\n",result,begin_place);
  609. back_ground_check(&back_ground_pids);
  610. } //while
  611. return result;
  612. }
  613.  
  614. void ctrlc(int sig){
  615. printf ("Ctrl+C\n");
  616. }
  617.  
  618.  
  619. int main(int argc, const char * argv[]) {
  620. char *line; //входная строка
  621. char **words; //строка, разбитая на слова
  622. //process_list frg_pids = NULL; // список фоновых процессов
  623. struct cmd * command; // конвейер с командами.
  624.  
  625.  
  626. signal (SIGINT, ctrlc);
  627. printf(":"); fflush(stdout); // fflush - сброс буфера
  628. while ((line = get_string()) != NULL) { // ввод строки
  629. words = parse_words(line); // разбор на слова
  630. free(line);
  631. char ** begwords = words;
  632. command = build_cmd(&words); // разбор на команды
  633. free_words(begwords);
  634. run(command);
  635. printf(":"); fflush(stdout); // fflush - сброс буфера
  636. free(command);
  637. }
  638. back_ground_stop_all(back_ground_pids);
  639. return 0;
  640. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement