Guest User

Untitled

a guest
May 2nd, 2024
61
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 16.62 KB | None | 0 0
  1. #include <csse2310a3.h>
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include <dirent.h>
  6. #include <errno.h>
  7. #include <fcntl.h>
  8. #include <sys/stat.h>
  9. #include <unistd.h>
  10. #include <sys/wait.h>
  11. #include <locale.h>
  12. #include <time.h>
  13. #include <assert.h>
  14. #include <stdbool.h>
  15. #include <signal.h>
  16.  
  17. #define READ_END 0
  18. #define WRITE_END 1
  19. #define NOT_ACTIVE 0
  20. #define ACTIVE 1
  21. #define NOT_GIVEN NULL
  22. #define PIPE_ENDS 2
  23. #define ZERO 0;
  24.  
  25. typedef struct {
  26.     int attempts;
  27.     int successes;
  28.     int nonZeros;
  29.     int sigterms;
  30.     int nonExecs;
  31. } Statistics;
  32.  
  33. typedef struct {
  34.     int p1[2];
  35.     int p2[2];
  36.     int pipeCount;
  37.     int stdoutfp;
  38. } PipeManager;
  39.  
  40. typedef struct {
  41.     struct dirent** entries;
  42.     int entryCount;
  43. } DirectoryManager;
  44.  
  45. typedef struct {
  46.     struct stat sbuf;
  47.     char* path;
  48.     char* absolutePath;
  49. } AbsPath;
  50.  
  51. typedef struct {
  52.     int descend;
  53.     int parallel;
  54.     int statistics;
  55.     int allfiles;
  56.     int directoryGiven;
  57.     int everyFile;
  58.     char* cmd;
  59.     CommandPipeline* cm;
  60.     char* directory;
  61.     Statistics* stats;
  62.     PipeManager* pm;
  63. } Params;
  64.  
  65. typedef enum {
  66.     STANDARD = 0,
  67.     USAGE = 8,
  68.     DIRECTORY = 2,
  69.     COMMAND = 12,
  70.     FAILURE = 17,
  71.     INTERRUPTED = 20,
  72.     DNE = 99
  73. } ExitStatus;
  74.  
  75. const char* const directoryArg = "--directory";
  76. const char* const statisticsArg = "--statistics"; const char* const parallelArg = "--parallel";
  77. const char* const allfilesArg = "--allfiles";
  78. const char* const descendArg = "--descend";
  79. static bool sigint = false;
  80.  
  81. const char* const filePlaceHolder = "{}";
  82.  
  83. const char* const errorUsage
  84.         = "Usage: uqfindexec [--directory dirname] [--statistics] [--parallel] "
  85.           "[--allfiles] [--descend] [cmd]\n";
  86. const char* const errorCannotRead
  87.         = "uqfindexec: cannot read directory \"%s\"\n";
  88. const char* const errorInvalidCmd = "uqfindexec: command is invalid\n";
  89. const char* const errorBadInputFile
  90.         = "uqfindexec: unable to read \"%s\" while processing \"%s\"\n";
  91. const char* const errorBadOutFile = "uqfindexec: unable to open \"%s\" for "
  92.                                     "writing while processing \"%s\"\n";
  93. const char* const errorBadCmd
  94.         = "uqfindexec: unable to execute \"%s\" while processing \"%s\"\n";
  95. const char* const statistics
  96.         = "Attempted to operate on a total of %s files\n-  operations "
  97.           "succeeded for %s files\n-  non-zero exit status detected when "
  98.           "processing %s files\n- processing was terminated by signal for %s "
  99.           "files\n- operations unable to be executed for %s files\n";
  100. /////////////////////////////////////////////////////////
  101. void usage_error(void);
  102. void directory_error(const char* directoryName);
  103. void cmd_error(void);
  104. void input_file_error(const char* f1, const char* f2, int errv);
  105. void output_file_error(const char* f1, const char* f2, int errv);
  106. void run_cmd_error(const char* f, const char* cmd, int errv);
  107. void statistics_exit(Statistics* stats);
  108. void free_directory(DirectoryManager dm);
  109. int hidden_filter(const struct dirent* directory);
  110. Params directory_parser(Params params);
  111. Params cmd_parser(Params params);
  112. DirectoryManager directory_manager_initialiser(Params params);
  113. void execute_command(Params params, char* path);
  114. Params prepare_command(Params params);
  115. void sigint_handler(int sig);
  116. AbsPath sbuf_initialiser(char* directory, char* path);
  117. Params validate_arguments(Params params);
  118. void exiter(Statistics* stats);
  119. Params process_command_line(int argc, char** argv);
  120. Params path_adder(Params params, char* path);
  121. void redirect_io(Params params, char* path, char* basePath, int cmd);
  122. void execute_commands(Params params, char* path, char* basePath, int cmd);
  123.  
  124. /////////////////////////////////////////////////////////
  125.  
  126. Params process_command_line(int argc, char** argv)
  127. {
  128.     Params params = {NOT_ACTIVE, NOT_ACTIVE, NOT_ACTIVE, NOT_ACTIVE, NOT_ACTIVE,
  129.             NOT_ACTIVE, NOT_GIVEN, NOT_GIVEN, NOT_GIVEN, NOT_GIVEN, NOT_GIVEN};
  130.  
  131.     argc--;
  132.     argv++;
  133.  
  134.     while (argc && strncmp(argv[0], "--", 2) == 0) {
  135.         if (!strcmp(argv[0], directoryArg) && argc != 1 && strlen(argv[1]) > 0
  136.                 && strncmp(argv[1], "--", 2) && !params.directoryGiven) {
  137.             params.directoryGiven = ACTIVE;
  138.             params.directory = argv[1];
  139.             argc -= 2;
  140.             argv += 2;
  141.         } else if (!strcmp(argv[0], allfilesArg) && !params.allfiles) {
  142.             params.allfiles = ACTIVE;
  143.             argc--;
  144.             argv++;
  145.         } else if (!strcmp(argv[0], descendArg) && !params.descend) {
  146.             params.descend = ACTIVE;
  147.             argc--;
  148.             argv++;
  149.         } else if (!strcmp(argv[0], statisticsArg) && !params.statistics) {
  150.             params.statistics = ACTIVE;
  151.             argc--;
  152.             argv++;
  153.         } else if (!strcmp(argv[0], parallelArg) && !params.parallel) {
  154.             params.parallel = ACTIVE;
  155.             argc--;
  156.             argv++;
  157.         } else {
  158.             usage_error();
  159.         }
  160.     }
  161.     if (argc == 1 && strncmp(argv[argc - 1], "--", 2) != 0
  162.             && strcmp(argv[argc - 1], "")) {
  163.         params.cmd = argv[argc - 1];
  164.         argc--;
  165.         argv++;
  166.     }
  167.     if (argc) {
  168.         usage_error();
  169.     }
  170.     params = cmd_parser(params);
  171.     return params;
  172. }
  173.  
  174. Params validate_arguments(Params params)
  175. {
  176.     if (params.directoryGiven) {
  177.         struct stat sbuf;
  178.         if (stat(params.directory, &sbuf)) {
  179.             directory_error(params.directory);
  180.         }
  181.         if (!S_ISDIR(sbuf.st_mode)) {
  182.             directory_error(params.directory);
  183.         }
  184.     } else {
  185.         params.directory = ".";
  186.     }
  187.     params = directory_parser(params);
  188.     return params;
  189. }
  190.  
  191. Params path_adder(Params params, char* path)
  192. {
  193.     for (int i = 0; i < params.cm->numCmds; i++) {
  194.         int j = 0;
  195.         while (params.cm->cmdArray[i][j] != NULL) {
  196.             if (!strcmp(params.cm->cmdArray[i][j], "{}")) {
  197.                 params.cm->cmdArray[i][j] = path;
  198.             }
  199.             j++;
  200.         }
  201.     }
  202.     return params;
  203. }
  204.  
  205. void redirect_io(Params params, char* path, char* basePath, int cmd)
  206. {
  207.     int inputFile;
  208.     int outputFile;
  209.     if (params.cm->stdinFileName && cmd == 0) {
  210.         if (!strcmp(params.cm->stdinFileName, "{}")) {
  211.             params.cm->stdinFileName = path;
  212.         }
  213.         inputFile = open(params.cm->stdinFileName, O_RDONLY, S_IWUSR | S_IRUSR);
  214.         if (inputFile < 0) {
  215.             if (params.directoryGiven) {
  216.                 input_file_error(params.cm->stdinFileName, path, DNE);
  217.             } else {
  218.                 input_file_error(params.cm->stdinFileName, basePath, DNE);
  219.             }
  220.         } else {
  221.             dup2(inputFile, STDIN_FILENO);
  222.             close(inputFile);
  223.         }
  224.     }
  225.     if (params.cm->stdoutFileName && (cmd + 1) == params.cm->numCmds) {
  226.         if (strstr(params.cm->stdoutFileName, "{}")) {
  227.             char* brackets = strtok(params.cm->stdoutFileName, "{}");
  228.             path = strcat(path, brackets);
  229.             params.cm->stdoutFileName = path;
  230.         }
  231.         outputFile = open(params.cm->stdoutFileName,
  232.                 O_WRONLY | O_CREAT | O_TRUNC, S_IRWXU);
  233.         if (outputFile < 0) {
  234.             if (params.directoryGiven) {
  235.                 output_file_error(params.cm->stdoutFileName, path, DNE);
  236.             } else {
  237.                 output_file_error(params.cm->stdoutFileName, basePath, DNE);
  238.             }
  239.         } else {
  240.             dup2(outputFile, STDOUT_FILENO);
  241.             close(outputFile);
  242.         }
  243.     }
  244. }
  245.  
  246. PipeManager* pipe_manager(Params params) {
  247.     PipeManager* pm = malloc(sizeof(PipeManager));
  248.     pm->pipeCount = params.cm->numCmds - 1;
  249.     //pm->stdoutfp = dup(STDOUT_FILENO);
  250.     //pm->pipes = malloc(sizeof(int[PIPE_ENDS]) * 2);
  251.     for (int i = 0; i < pm->pipeCount; i++) {
  252.         //pipe(pm->pipes[i]);
  253.     }
  254.     return pm;
  255. }
  256.  
  257. void cmd_pipeliner(Params params, int cmd) {
  258.     if (params.cm->numCmds == 1) {
  259.         return;
  260.     }
  261.     //pipe(params.pm->pipes[cmd]);
  262.     if (cmd == 0) {
  263.         close(params.pm->p2[READ_END]);
  264.         dup2(params.pm->p2[WRITE_END], STDOUT_FILENO);
  265.         close(params.pm->p2[WRITE_END]);
  266.         //close(params.pm->pipes[cmd][READ_END]);
  267.        // dup2(params.pm->pipes[cmd][WRITE_END], STDOUT_FILENO);
  268.         //close(params.pm->pipes[cmd][WRITE_END]);
  269.     }
  270.     else if ((cmd + 1) == params.cm->numCmds) {
  271.         close(params.pm->p1[WRITE_END]);
  272.         dup2(params.pm->p1[READ_END], STDIN_FILENO);
  273.         close(params.pm->p1[READ_END]);
  274.         //close(params.pm->pipes[cmd - 1][WRITE_END]);
  275.         //dup2(params.pm->pipes[cmd - 1][READ_END], STDIN_FILENO);
  276.         //close(params.pm->pipes[cmd - 1][READ_END]);
  277.         //dup2(params.pm->stdoutfp, STDOUT_FILENO);
  278.     } else {
  279.         dup2(params.pm->p2[WRITE_END], STDOUT_FILENO);
  280.         close(params.pm->p2[WRITE_END]);
  281.         dup2(params.pm->p1[READ_END], STDIN_FILENO);
  282.         close(params.pm->p1[READ_END]);
  283.         //dup2(params.pm->pipes[cmd - 1][READ_END], STDIN_FILENO);
  284.         //close(params.pm->pipes[cmd - 1][READ_END]);
  285.         //dup2(params.pm->pipes[cmd][WRITE_END], STDOUT_FILENO);
  286.         //close(params.pm->pipes[cmd][WRITE_END]);
  287.     }
  288.     for (int i = 0; i < params.pm->pipeCount; i++) {
  289.         //close(params.pm->pipes[i][READ_END]);
  290.         //close(params.pm->pipes[i][WRITE_END]);
  291.     }
  292. }
  293.  
  294. void execute_commands(Params params, char* path, char* basePath, int cmd)
  295. {
  296.     //fprintf(stderr, "2: cmd: %s\n", params.cm->cmdArray[cmd][0]);
  297.     fflush(stderr);
  298.     redirect_io(params, path, basePath, cmd);
  299.     //fprintf(stderr, "3: cmd: %s\n", params.cm->cmdArray[cmd][0]);
  300.     fflush(stderr);
  301.     cmd_pipeliner(params, cmd);
  302.     fprintf(stderr, "4: cmd: %s for loop x-%d\n", params.cm->cmdArray[cmd][0], cmd);
  303.     fflush(stderr);
  304.     execvp(params.cm->cmdArray[cmd][0], params.cm->cmdArray[cmd]);
  305.     run_cmd_error(params.cm->cmdArray[cmd][0], basePath, DNE);
  306.  
  307. }
  308.  
  309. Statistics* stats_initialiser(void)
  310. {
  311.     Statistics* stats = malloc(sizeof(Statistics));
  312.     stats->attempts = 0;
  313.     stats->successes = 0;
  314.     stats->nonZeros = 0;
  315.     stats->sigterms = 0;
  316.     stats->nonExecs = 0;
  317.     return stats;
  318. }
  319.  
  320. void update_statistics(Statistics* stats, int wstatus)
  321. {
  322.     int rval;
  323.     stats->attempts++;
  324.     if (WIFEXITED(wstatus)) {
  325.         rval = WEXITSTATUS(wstatus);
  326.         if (rval == STANDARD) {
  327.             stats->successes++;
  328.         } else if (rval == DNE) {
  329.             stats->nonExecs++;
  330.         } else {
  331.             stats->nonZeros++;
  332.         }
  333.     }
  334.     if (WIFSIGNALED(wstatus)) {
  335.         rval = WTERMSIG(wstatus);
  336.         stats->sigterms++;
  337.     }
  338. }
  339.  
  340. Params every_file_handler(Params params, AbsPath path)
  341. {
  342.     if (params.everyFile) {
  343.         if (params.directoryGiven) {
  344.             params = path_adder(params, path.absolutePath);
  345.         } else {
  346.             params = path_adder(params, path.path);
  347.         }
  348.     }
  349.     return params;
  350. }
  351.  
  352. Params prepare_command(Params params)
  353. {
  354.     DirectoryManager dm = directory_manager_initialiser(params);
  355.     params.stats = stats_initialiser();
  356.     params.pm = pipe_manager(params);
  357.     int childrenCount = 1;
  358.     pid_t* children = malloc(sizeof(pid_t) * childrenCount);
  359.     for (int i = 0; i < dm.entryCount; i++) {
  360.         int wstatus;
  361.         pid_t child;
  362.         AbsPath path
  363.                 = sbuf_initialiser(params.directory, dm.entries[i]->d_name);
  364.         for (int j = 0; j < params.cm->numCmds; j++) {
  365.             printf("LOOP STARTED ----------------------\n");
  366.             if (j == 0) {
  367.                 pipe(params.pm->p2);
  368.             }
  369.             if ((j+1) != params.cm->numCmds) {
  370.                 params.pm->p1 = params.pm->p2;
  371.             } else {
  372.                 params.pm->p1 = params.pm->p2;
  373.                 pipe(params.pm->p2);
  374.             }
  375.             if (!S_ISDIR(path.sbuf.st_mode) && !(child = fork())) {
  376.     fprintf(stderr, "1: cmd: %s, for loop %d-%d\n", params.cm->cmdArray[j][0], i, j);
  377.     fflush(stderr);
  378.                 params = every_file_handler(params, path);
  379.                 execute_commands(params, path.absolutePath, path.path, j);
  380.             }
  381.             if ((j + 1) != params.cm->numCmds) {
  382.                 close(params.pm->p2[WRITE_END]);
  383.                 //close(params.pm->pipes[j][WRITE_END]);
  384.             }
  385.             children[childrenCount - 1] = child;
  386.             childrenCount++;
  387.             waitpid(child, &wstatus, 0);
  388.             update_statistics(params.stats, wstatus);
  389.             printf("CHILD CAUGHT\n");
  390.         }
  391.     }
  392.     free_directory(dm);
  393.     return params;
  394. }
  395.  
  396. void exiter(Statistics* stats)
  397. {
  398.     if (sigint) {
  399.         exit(INTERRUPTED);
  400.     }
  401.     if (stats->nonExecs) {
  402.         exit(FAILURE);
  403.     } else if (sigint) {
  404.         exit(INTERRUPTED);
  405.     }
  406.     exit(STANDARD);
  407. }
  408.  
  409. int main(int argc, char** argv)
  410. {
  411.     struct sigaction sa;
  412.     sa.sa_handler = sigint_handler;
  413.     sigaction(SIGINT, &sa, NULL);
  414.     while (!sigint) {
  415.         setlocale(LC_COLLATE, "en_AU");
  416.         Params params = process_command_line(argc, argv);
  417.         /// printf("%s and %s and %s\n",
  418.         /// params.cm->cmdArray[0][0],params.cm->cmdArray[0][1],
  419.         /// params.cm->cmdArray[0][1]);
  420.         params = validate_arguments(params);
  421.         params = prepare_command(params);
  422.         free_pipeline(params.cm);
  423.         exiter(params.stats);
  424.     }
  425. }
  426.  
  427. /////////////////////////////////////////////////////////////////
  428. // Error Handling Functions
  429. /////////////////////////////////////////////////////////////////
  430. void usage_error(void)
  431. {
  432.     fprintf(stderr, errorUsage);
  433.     exit(USAGE);
  434. }
  435.  
  436. void directory_error(const char* directoryName)
  437. {
  438.     fprintf(stderr, errorCannotRead, directoryName);
  439.     exit(DIRECTORY);
  440. }
  441.  
  442. void cmd_error(void)
  443. {
  444.     fprintf(stderr, errorInvalidCmd);
  445.     exit(COMMAND);
  446. }
  447.  
  448. void input_file_error(const char* f1, const char* f2, int errv)
  449. {
  450.     fprintf(stderr, errorBadInputFile, f1, f2);
  451.     exit(errv);
  452. }
  453.  
  454. void output_file_error(const char* f1, const char* f2, int errv)
  455. {
  456.     fprintf(stderr, errorBadOutFile, f1, f2);
  457.     exit(errv);
  458. }
  459.  
  460. void run_cmd_error(const char* f, const char* cmd, int errv)
  461. {
  462.     fprintf(stderr, errorBadCmd, f, cmd);
  463.     exit(errv);
  464. }
  465.  
  466. void statistics_exit(Statistics* stats)
  467. {
  468.     fprintf(stderr, statistics, stats->attempts, stats->successes,
  469.             stats->nonZeros, stats->sigterms, stats->nonExecs);
  470.     exiter(stats);
  471. }
  472.  
  473. void sigint_handler(int sig)
  474. {
  475.     if (sig == SIGINT) {
  476.         sigint = true;
  477.     }
  478.     exit(INTERRUPTED);
  479. }
  480.  
  481. /////////////////////////////////////////////////////////////////
  482. // Parser, Manager and Filter Functions
  483. /////////////////////////////////////////////////////////////////
  484. int hidden_filter(const struct dirent* directory)
  485. {
  486.     return !(directory->d_name[0] == '.');
  487. }
  488.  
  489. Params cmd_parser(Params params)
  490. {
  491.     if (params.cmd) {
  492.         params.cm = parse_pipeline_string(params.cmd);
  493.     } else {
  494.         params.cm = parse_pipeline_string("echo {}");
  495.     }
  496.     if (params.cm == NOT_GIVEN) {
  497.         cmd_error();
  498.     } else {
  499.         int j = 0;
  500.         while (params.cm->cmdArray[0][j] != NULL) {
  501.             if (!strcmp(params.cm->cmdArray[0][j], "{}")) {
  502.                 params.everyFile = ACTIVE;
  503.                 return params;
  504.             }
  505.             j++;
  506.         }
  507.     }
  508.     return params;
  509. }
  510.  
  511. Params directory_parser(Params params)
  512. {
  513.     if (params.directoryGiven
  514.             && params.directory[strlen(params.directory) - 1] != '/') {
  515.         strcat(params.directory, "/");
  516.     } else if (!strcmp(params.directory, ".")) {
  517.         params.directory = "./";
  518.     }
  519.     return params;
  520. }
  521.  
  522. DirectoryManager directory_manager_initialiser(Params params)
  523. {
  524.     struct dirent** entries;
  525.     int entryCount;
  526.     if (params.allfiles) {
  527.         entryCount = scandir(params.directory, &entries, NULL, alphasort);
  528.     } else {
  529.         entryCount
  530.                 = scandir(params.directory, &entries, hidden_filter, alphasort);
  531.     }
  532.     DirectoryManager dm = {entries, entryCount};
  533.     return dm;
  534. }
  535.  
  536. AbsPath sbuf_initialiser(char* directory, char* path)
  537. {
  538.     struct stat sbuf;
  539.     char absolutePath[PATH_MAX];
  540.     strcpy(absolutePath, directory);
  541.     strcat(absolutePath, path);
  542.     stat(absolutePath, &sbuf);
  543.     AbsPath abs = {sbuf, path, absolutePath};
  544.     return abs;
  545. }
  546.  
  547. /////////////////////////////////////////////////////////////////
  548. // Memory Freeing Functions
  549. /////////////////////////////////////////////////////////////////
  550. void free_directory(DirectoryManager dm)
  551. {
  552.     for (int i = 0; i < dm.entryCount; i++) {
  553.         free(dm.entries[i]);
  554.     }
  555.     free(dm.entries);
  556. }
Advertisement
Add Comment
Please, Sign In to add comment