Guest User

Untitled

a guest
May 6th, 2023
38
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 19.26 KB | None | 0 0
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <unistd.h>
  5. #include <sys/wait.h>
  6. #include <signal.h>
  7. #include <fcntl.h>
  8.  
  9.  
  10. #define MAX_INPUT_LENGTH 510
  11. #define MAX_ARGS 10
  12.  
  13. // Using LinkedList to store vars
  14. typedef struct node {
  15. char *name;
  16. char *value;
  17. struct node *next;
  18. } Node;
  19.  
  20. typedef struct linked_list {
  21. Node *head;
  22. } LinkedList;
  23.  
  24. int get_input(char *input);
  25.  
  26. void parse_input(char *input, char **args, LinkedList *vars, int *stopped_process_pid);
  27.  
  28. void exec_command(char **args, int ampersand, char *file_name, int pipe_num, int pipe_amount, int* pipefd, int* prev_pipefd);
  29.  
  30. char *replace_vars(char *input, LinkedList *vars);
  31.  
  32. void quots_remover(char *str);
  33.  
  34. int is_echo(char *str);
  35.  
  36. int is_CD(char *str);
  37.  
  38. int is_BG(char *str);
  39.  
  40. int is_redirection(char *str);
  41.  
  42. int is_pipe(char *str);
  43.  
  44. void pipe_parse(char **args, char *str, int pipes_amount);
  45.  
  46. int have_illegal_spaces(char *str);
  47.  
  48. void spaces_remover(char *str);
  49.  
  50. void prompt_printer(int legCmds, int args);
  51.  
  52. void splitToEqual(const char *str, char *left_string, char *right_string);
  53.  
  54. int ampersand_finder_remover(char *str);
  55.  
  56. void initialize(LinkedList *list);
  57.  
  58. void insert(LinkedList *list, char *name, char *value);
  59.  
  60. Node *search(LinkedList *list, char *name);
  61.  
  62. void terminate(LinkedList *list);
  63.  
  64. void sig_child_handler(int n);
  65.  
  66. void father_handler(int n);
  67.  
  68.  
  69. int pidd = 0;
  70. int last_pid = 0;
  71. int redirect_flag = 0;
  72. int legalArgs = 0, legalCmds = 0;
  73.  
  74. int main() {
  75. signal(SIGCHLD, sig_child_handler);
  76. int noCmdCounter = 0, inputStatus, stopped_process_pid = 0;
  77. char input[MAX_INPUT_LENGTH + 5];
  78. char *args[MAX_ARGS];
  79. for (int i = 0; i < MAX_ARGS; ++i) {
  80. args[i] = "\0";
  81. }
  82.  
  83. // int* pidd = malloc(sizeof(int));
  84.  
  85. LinkedList vars;
  86. initialize(&vars);
  87.  
  88. while (1) {
  89. // prompt
  90. prompt_printer(legalCmds, legalArgs);
  91. inputStatus = get_input(input);
  92.  
  93. // input len is greater than max
  94. if (inputStatus == 0) {
  95. printf("ERR\n");
  96. continue;
  97. }
  98.  
  99. // user pressed enter 3 times in a row
  100. else if (inputStatus == -1) {
  101. noCmdCounter++;
  102.  
  103. if (noCmdCounter == 3)
  104. break;
  105.  
  106. continue;
  107. }
  108.  
  109. // legal input
  110. else {
  111. noCmdCounter = 0;
  112. parse_input(input, args, &vars, &stopped_process_pid);
  113. }
  114. }
  115. terminate(&vars);
  116. }
  117.  
  118. /* function that gets command input from the user */
  119. int get_input(char *input) {
  120. // printf("student@student-virtual-machine ~/ex1 $ ");
  121. fgets(input, MAX_INPUT_LENGTH + 5, stdin);
  122. input[strcspn(input, "\n")] = '\0'; // replaces last char (new-line char) to NULL terminator
  123.  
  124. if (strlen(input) > MAX_INPUT_LENGTH)
  125. return 0; // if illegal input length
  126.  
  127. else if (strlen(input) == 0)
  128. return -1; // if no cmd entered
  129.  
  130. return 1; // if legal input length
  131. }
  132.  
  133. /* function that divides the commands and their arguments */
  134. void parse_input(char *input, char **args, LinkedList *vars, int *stopped_process_pid) {
  135. char temp_str[520], temp_arg[520];
  136. char *token;
  137. int input_len = strlen(input), equal_val = '=', idx, quot_counter = 0, ampersand_flag, pipe_counter = 0;
  138.  
  139. // ----------------------copying each command seperated by ';'-----------------------------------
  140. for (int i = 0, j = 0; i <= input_len; ++i) { // copying each command seperated by ';'
  141. if (input[i] == '\"') {
  142. if (quot_counter == 1)
  143. quot_counter = 0;
  144. else quot_counter = 1;
  145. }
  146.  
  147. if ((input[i] == ';' || input[i] == '\0') && quot_counter == 0) { // end of command
  148. char *file_name;
  149. temp_str[j] = '\0';
  150. redirect_flag = 0;
  151. ampersand_flag = 0;
  152. ampersand_flag = ampersand_finder_remover(temp_str);
  153. quot_counter = 0;
  154. printf("command is : %s\n", temp_str);
  155. j = 0;
  156. // ******************working on each command***********************
  157. pipe_counter = is_pipe(temp_str);
  158. if (pipe_counter > 0){
  159. pipe_parse(args, temp_str, pipe_counter);
  160. continue;
  161. }
  162.  
  163. // redirection
  164. if (is_redirection(temp_str) == 1) {
  165. redirect_flag = 1;
  166.  
  167. char *command_to_redirect = strtok(temp_str, ">"); // holds the cmd
  168. file_name = strtok(NULL, ">"); // holds the file name
  169. spaces_remover(file_name);
  170. printf("@%s@\t@%s@\n", command_to_redirect, file_name);
  171. printf("--%s--\n", temp_str);
  172. }
  173.  
  174. if (is_CD(temp_str) == 1) {
  175. printf("CD not supported!\n");
  176. continue;
  177. }
  178.  
  179. // 'echo' cmd
  180. if (is_echo(temp_str) == 1 && pipe_counter == 0) {
  181. token = strtok(temp_str, " ");
  182. args[0] = token; // inserting "echo" to first exec array element
  183. token = strtok(NULL, "\0");
  184. args[1] = token; // inserting echo's argument into second exec array element
  185. args[2] = "\0";
  186. for (int k = 0; k < 10; ++k) {
  187. if (k != 0 && k != 1) args[k] = '\0';
  188. if (k == 1) {
  189. strcpy(temp_arg, replace_vars(args[1], vars));
  190. quots_remover(temp_arg);
  191. args[1] = temp_arg;
  192. }
  193. }
  194. }
  195.  
  196. // if cmd has '=' then it's a variable cmd
  197. else if (strchr(temp_str, equal_val) != NULL && pipe_counter == 0) {
  198. char temp_str2[520];
  199. strcpy(temp_str2, temp_str);
  200. if (have_illegal_spaces(temp_str2) == 0) {
  201. char left[520], right[520];
  202. splitToEqual(temp_str, left, right); // left/right holds the two parts of the variable
  203.  
  204. char var_name[520];
  205. strcpy(var_name, left);
  206. spaces_remover(var_name);
  207.  
  208. char var_value[520];
  209. strcpy(var_value, right);
  210. quots_remover(var_value);
  211.  
  212. insert(vars, var_name, var_value);
  213. continue;
  214. }
  215. }
  216.  
  217. else if (is_BG(temp_str) == 1 && pipe_counter == 0) {
  218. kill(last_pid, SIGCONT);
  219. continue;
  220. }
  221.  
  222. // regular command
  223. else {
  224. idx = 0;
  225. char *p = (char *) malloc(sizeof(char *));
  226. p = replace_vars(temp_str, vars);
  227. strcpy(temp_arg, p);
  228.  
  229. token = strtok(temp_arg, " ");
  230. while (token != NULL) {
  231. spaces_remover(token);
  232. args[idx++] = token;
  233. token = strtok(NULL, " ");
  234. }
  235. while (idx < 10) {
  236. args[idx++] = NULL;
  237. }
  238. }
  239.  
  240. if (redirect_flag == 1) {
  241. exec_command(args, ampersand_flag, file_name, 0, 0, NULL, NULL);
  242. continue;
  243. }
  244. exec_command(args, ampersand_flag, NULL, 0, 0, NULL, NULL);
  245. }
  246.  
  247. // ***************************************************************
  248. else { // copying next letter
  249. temp_str[j] = input[i];
  250. j++;
  251. }
  252. }
  253. // --------------------------------------------------------------------------------------------
  254. }
  255.  
  256. void printArr(char **arr) {
  257. fprintf(stderr, "printArr:\n");
  258.  
  259. for (int i = 0; arr[i] != NULL; i++)
  260. fprintf(stderr, "%s\n", arr[i]);
  261. }
  262.  
  263. /* function that creates a son process and sends the command to execvp */
  264. void exec_command(char **args, int ampersand, char *file_name, int pipe_num, int pipe_amount, int* pipefd, int* prev_pipefd) {
  265. int status;
  266. pidd = fork();
  267.  
  268. // child
  269. if (pidd == 0) {
  270. signal(SIGTSTP, SIG_DFL);
  271.  
  272. if (redirect_flag == 1) {
  273. int fd = open(file_name, O_WRONLY | O_TRUNC | O_CREAT, 0644);
  274. dup2(fd, STDOUT_FILENO);
  275. if (fd == -1) perror("ERR file");
  276. }
  277.  
  278. if (pipe_amount != 0) {
  279. for (int i = 0; i < 10; ++i)
  280. printf("!%s\t", args[i]);
  281. printf("\n");
  282.  
  283. // first pipe
  284. if (pipe_num == 0) {
  285. printf("first pipe\n");
  286. close(pipefd[0]); // close read
  287. if (dup2(pipefd[1], STDOUT_FILENO) == -1) { // redirect stdout to write
  288. perror("pipe 1 dup");
  289. exit(EXIT_FAILURE);
  290. }
  291. }
  292.  
  293. // last pipe
  294. else if (pipe_num == pipe_amount){
  295. printf("last pipe\n");
  296. close(prev_pipefd[1]); // close unused write end of previous pipe
  297. if(dup2(prev_pipefd[0], STDIN_FILENO) == -1) { // redirect stdin to read end of previous pipe
  298. perror("pipe 3 dup");
  299. exit(EXIT_FAILURE);
  300. }
  301. close(pipefd[0]); // close unused read end of pipe
  302. }
  303.  
  304. // mid pipes
  305. else{
  306. printf("mid pipe\n");
  307. close(prev_pipefd[1]); // close unused write end of previous pipe
  308. dup2(prev_pipefd[0], STDIN_FILENO); // redirect stdin to read end of previous pipe
  309. close(pipefd[0]); // close unused read end of pipe
  310. dup2(pipefd[1], STDOUT_FILENO); // redirect stdout to write end of pipe
  311. }
  312. }
  313.  
  314. execvp(args[0], args);
  315. printf("after exec\n");
  316. perror("ERR0");
  317. exit(1);
  318. }
  319.  
  320. // error
  321. else if (pidd < 0) {
  322. perror("ERR1\n");
  323. exit(0);
  324. }
  325.  
  326. // parent
  327. else {
  328. if (pipe_amount != 0) {
  329. if (prev_pipefd[0] != -1) close(prev_pipefd[0]);
  330. if (prev_pipefd[1] != -1) close(prev_pipefd[1]);
  331. prev_pipefd[0] = pipefd[0];
  332. prev_pipefd[1] = pipefd[1];
  333. printf("parent process\n");
  334. }
  335.  
  336. signal(SIGTSTP, father_handler);
  337.  
  338. if (ampersand == 0)
  339. waitpid(pidd, &status, WUNTRACED);
  340.  
  341. legalCmds += 1; // inc cmds counter
  342.  
  343. for (int i = 0; i < 10; ++i) // inc args counter
  344. if (args[i] != NULL)
  345. legalArgs += 1;
  346. }
  347.  
  348. // if (prev_pipefd[0] != -1) close(prev_pipefd[0]);
  349. // if (prev_pipefd[1] != -1) close(prev_pipefd[1]);
  350. }
  351.  
  352. /* function that removes quots from a string */
  353. void quots_remover(char *str) {
  354. int len = strlen(str);
  355. int i, j;
  356. for (i = 0, j = 0; i < len; i++)
  357. if (str[i] != '\"')
  358. str[j++] = str[i];
  359. str[j] = '\0';
  360. }
  361.  
  362. /* function that checks if it's an echo command */
  363. int is_echo(char *str) {
  364. int counter = 0;
  365.  
  366. for (int i = 0; i < strlen(str); ++i) {
  367. if (str[i] == 'e') {
  368. counter++;
  369. continue;
  370. }
  371. if (str[i] == 'c' && counter == 1) {
  372. counter++;
  373. continue;
  374. }
  375. if (str[i] == 'h' && counter == 2) {
  376. counter++;
  377. continue;
  378. }
  379. if (str[i] == 'o' && counter == 3) {
  380. counter++;
  381. break;
  382. }
  383.  
  384. counter = 0;
  385. }
  386. if (counter == 4)
  387. return 1;
  388. return 0;
  389. }
  390.  
  391. int is_CD(char *str) {
  392. int counter = 0;
  393.  
  394. for (int i = 0; i < strlen(str); ++i) {
  395. if (str[i] == 'c') {
  396. counter++;
  397. continue;
  398. }
  399. if (str[i] == 'd' && counter == 1) {
  400. counter++;
  401. break;
  402. }
  403.  
  404. counter = 0;
  405. }
  406. if (counter == 2)
  407. return 1;
  408. return 0;
  409. }
  410.  
  411. int is_BG(char *str) {
  412. int counter = 0;
  413.  
  414. for (int i = 0; i < strlen(str); ++i) {
  415. if (str[i] == 'b') {
  416. counter++;
  417. continue;
  418. }
  419. if (str[i] == 'g' && counter == 1) {
  420. counter++;
  421. break;
  422. }
  423.  
  424. counter = 0;
  425. }
  426. if (counter == 2)
  427. return 1;
  428. return 0;
  429. }
  430.  
  431. /* function that determines how many pipes the command have, if any */
  432. int is_pipe(char *str) {
  433. int counter = 0;
  434. for (int i = 0; i < strlen(str); ++i)
  435. if (str[i] == '|') counter++;
  436. return counter;
  437. }
  438.  
  439. /* function that parses the command by pipes */
  440. void pipe_parse(char **args, char *str, int pipes_amount) {
  441. char curr_cmd[510];
  442. for (int i = 0; i < 510; ++i) curr_cmd[i] = '\0';
  443. int pipes_executed = 0;
  444. char *token;
  445.  
  446. int pipefd[2];
  447. int prev_pipefd[2] = {-1, -1};
  448. if (pipe(pipefd) == -1) {
  449. perror("ERR pipe");
  450. exit(1);
  451. }
  452.  
  453. for (int i = 0, j = 0; i < strlen(str); ++i) {
  454. if (str[i] == '|' || str[i] == '\0') {
  455. curr_cmd[j] = '\0';
  456. j = 0;
  457. //printf("@%s@\n", curr_cmd);
  458. token = strtok(curr_cmd, " ");
  459. args[0] = token;
  460.  
  461. int k = 0;
  462. for (; token != NULL; k++, token = strtok(NULL, " "))
  463. args[k] = token;
  464.  
  465. for (; k < 10; k++) args[k] = NULL;
  466.  
  467.  
  468. exec_command(args, 0, NULL, pipes_executed, pipes_amount, pipefd, prev_pipefd);
  469. pipes_executed++;
  470. }
  471.  
  472. else {
  473. curr_cmd[j++] = str[i];
  474. }
  475. }
  476.  
  477.  
  478. }
  479.  
  480. /* function that checks if an environmental variable command has illegal spaces*/
  481. int have_illegal_spaces(char *str) {
  482.  
  483. char *temp = str;
  484. char *toke = strtok(temp, "=");
  485. int flag = 0;
  486. for (int i = 0; i < strlen(toke); ++i) {
  487. if (temp[i] != ' ') {
  488. flag = 1;
  489. }
  490. if (temp[i] == ' ' && flag != 0)
  491. return 1;
  492. }
  493. return 0;
  494. }
  495.  
  496. /* function that removes spaces */
  497. void spaces_remover(char *str) {
  498. int len = strlen(str);
  499. int i, j;
  500. for (i = 0, j = 0; i < len; i++)
  501. if (str[i] != ' ')
  502. str[j++] = str[i];
  503. str[j] = '\0';
  504. }
  505.  
  506. /* function that prints the prompt line */
  507. void prompt_printer(int legCmds, int args) {
  508. char cwd[256];
  509.  
  510. if (getcwd(cwd, sizeof(cwd)) == NULL)
  511. printf("ERR getcwd"); // TODO: CHANGE TO WHAT?
  512. else
  513. printf("#cmd:%d|#args:%d@%s ", legCmds, args, cwd);
  514. }
  515.  
  516. /* function that replaces all variables calls with their values */
  517. char *replace_vars(char *input, LinkedList *vars) {
  518. char *temp = (char *) malloc(520);
  519. memset(temp, '\0', sizeof(*temp)); // TODO: add * before temp inside sizeof ??
  520. char name_temp[520];
  521. memset(name_temp, '\0', sizeof(name_temp));
  522. int flag = 0, tempIdx = 0, nameIdx = 0;
  523. char c[2];
  524. c[1] = 0;
  525.  
  526. for (int i = 0; i < strlen(input) + 1; ++i) {
  527. if (input[i] == '$')
  528. flag = 1;
  529. else if (input[i] == ' ' || input[i] == '\0' || input[i] == '\"') { // check for var in list
  530. flag = 0;
  531. Node *temp_node = search(vars, name_temp);
  532. if (temp_node != NULL) { // var exist
  533. strcat(temp, temp_node->value);
  534. }
  535. else { // var doesn't exist
  536. strcat(temp, " ");
  537. }
  538. memset(name_temp, '\0', sizeof(name_temp));
  539. if (input[i] == ' ') {
  540. strcat(temp, " ");
  541. }
  542. }
  543. else if (input[i] != ' ') { // copy char
  544. sprintf(c, "%c", input[i]);
  545. //printf("%c\n", c[0]);
  546. if (flag == 1) { // copy to name
  547. strcat(name_temp, c);
  548. }
  549. else { // copy to temp
  550. strcat(temp, c);
  551. }
  552. }
  553. }
  554. return temp;
  555. }
  556.  
  557. /* function that splits the environmental variable */
  558. void splitToEqual(const char *str, char *left, char *right) {
  559. memset(left, '\0', MAX_INPUT_LENGTH);
  560. memset(right, '\0', MAX_INPUT_LENGTH);
  561. int flag = 0, j = 0;
  562. for (int i = 0; i < strlen(str); ++i) {
  563. if (str[i] == '=') {
  564. flag = 1, j = 0;
  565. }
  566. else {
  567. if (flag == 0) left[j++] = str[i];
  568. else right[j++] = str[i];
  569. }
  570. }
  571. }
  572.  
  573. void sig_child_handler(int n) {
  574. waitpid(-1, NULL, WNOHANG);
  575. }
  576.  
  577. void father_handler(int n) {
  578. last_pid = pidd;
  579. }
  580.  
  581. /* function that looks if command has ampersand, if it does it'll delete it */
  582. int ampersand_finder_remover(char *str) {
  583. int i, j;
  584. int insideQuotes = 0;
  585. int deleted = 0;
  586. for (i = 0, j = 0; str[i]; i++) {
  587. if (str[i] == '\"') {
  588. insideQuotes = !insideQuotes; // toggle flag
  589. }
  590. else if (str[i] == '&' && !insideQuotes) {
  591. deleted = 1;
  592. continue; // skip ampersand if not inside quotes
  593. }
  594. else {
  595. str[j++] = str[i];
  596. }
  597. }
  598. str[j] = '\0';
  599. return deleted;
  600. }
  601.  
  602. /* function that checks for '>' char and determines if the cmd is a concat cmd */
  603. int is_redirection(char *str) {
  604. for (int i = 0; i < strlen(str); ++i)
  605. if (str[i] == '>')
  606. return 1;
  607. return 0;
  608. }
  609.  
  610. /* Function to initialize the linked list */
  611. void initialize(LinkedList *list) {
  612. list->head = NULL;
  613. }
  614.  
  615. // function to insert a new node into the linked list
  616. void insert(LinkedList *list, char *name, char *value) {
  617. Node *new_node = malloc(sizeof(Node));
  618. if (new_node == NULL) {
  619. printf("ERR");
  620. exit(1);
  621. }
  622. new_node->name = strdup(name);
  623. new_node->value = strdup(value);
  624. new_node->next = NULL;
  625.  
  626. // check if list is empty
  627. if (list->head == NULL) {
  628. list->head = new_node;
  629. }
  630. else {
  631. // search the node with the same name
  632. Node *current_node = list->head;
  633. while (current_node != NULL) {
  634. if (strcmp(current_node->name, name) == 0) {
  635. // replace the existing node with the new node
  636. free(current_node->value);
  637. current_node->value = strdup(value);
  638. free(new_node->name);
  639. free(new_node->value);
  640. free(new_node);
  641. return;
  642. }
  643. current_node = current_node->next;
  644. }
  645.  
  646. /* Insert the new node at the end of the list */
  647. current_node = list->head;
  648. while (current_node->next != NULL) {
  649. current_node = current_node->next;
  650. }
  651. current_node->next = new_node;
  652. }
  653. }
  654.  
  655. /* Function to search for a node with a given name */
  656. Node *search(LinkedList *list, char *name) {
  657. Node *current_node = list->head;
  658. while (current_node != NULL) {
  659. if (strcmp(current_node->name, name) == 0) {
  660. return current_node;
  661. }
  662. current_node = current_node->next;
  663. }
  664. return NULL;
  665. }
  666.  
  667. // function to terminate the linked list and free all memory
  668. void terminate(LinkedList *list) {
  669. Node *current_node = list->head;
  670. while (current_node != NULL) {
  671. Node *next_node = current_node->next;
  672. free(current_node->name);
  673. free(current_node->value);
  674. free(current_node);
  675. current_node = next_node;
  676. }
  677. list->head = NULL;
  678. }
  679.  
Add Comment
Please, Sign In to add comment