Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <csse2310a3.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <dirent.h>
- #include <errno.h>
- #include <fcntl.h>
- #include <sys/stat.h>
- #include <unistd.h>
- #include <sys/wait.h>
- #include <locale.h>
- #include <time.h>
- #include <assert.h>
- #include <stdbool.h>
- #include <signal.h>
- #define READ_END 0
- #define WRITE_END 1
- #define NOT_ACTIVE 0
- #define ACTIVE 1
- #define NOT_GIVEN NULL
- #define PIPE_ENDS 2
- #define ZERO 0;
- typedef struct {
- int attempts;
- int successes;
- int nonZeros;
- int sigterms;
- int nonExecs;
- } Statistics;
- typedef struct {
- int** pipes;
- int pipeCount;
- int stdoutfp;
- } PipeManager;
- typedef struct {
- struct dirent** entries;
- int entryCount;
- } DirectoryManager;
- typedef struct {
- struct stat sbuf;
- char* path;
- char* absolutePath;
- } AbsPath;
- typedef struct {
- int descend;
- int parallel;
- int statistics;
- int allfiles;
- int directoryGiven;
- int everyFile;
- char* cmd;
- CommandPipeline* cm;
- char* directory;
- Statistics* stats;
- PipeManager* pm;
- } Params;
- typedef enum {
- STANDARD = 0,
- USAGE = 8,
- DIRECTORY = 2,
- COMMAND = 12,
- FAILURE = 17,
- INTERRUPTED = 20,
- DNE = 99
- } ExitStatus;
- const char* const directoryArg = "--directory";
- const char* const statisticsArg = "--statistics";
- const char* const parallelArg = "--parallel";
- const char* const allfilesArg = "--allfiles";
- const char* const descendArg = "--descend";
- static bool sigint = false;
- const char* const filePlaceHolder = "{}";
- const char* const errorUsage
- = "Usage: uqfindexec [--directory dirname] [--statistics] [--parallel] "
- "[--allfiles] [--descend] [cmd]\n";
- const char* const errorCannotRead
- = "uqfindexec: cannot read directory \"%s\"\n";
- const char* const errorInvalidCmd = "uqfindexec: command is invalid\n";
- const char* const errorBadInputFile
- = "uqfindexec: unable to read \"%s\" while processing \"%s\"\n";
- const char* const errorBadOutFile = "uqfindexec: unable to open \"%s\" for "
- "writing while processing \"%s\"\n";
- const char* const errorBadCmd
- = "uqfindexec: unable to execute \"%s\" while processing \"%s\"\n";
- const char* const statistics
- = "Attempted to operate on a total of %s files\n- operations "
- "succeeded for %s files\n- non-zero exit status detected when "
- "processing %s files\n- processing was terminated by signal for %s "
- "files\n- operations unable to be executed for %s files\n";
- /////////////////////////////////////////////////////////
- void usage_error(void);
- void directory_error(const char* directoryName);
- void cmd_error(void);
- void input_file_error(const char* f1, const char* f2, int errv);
- void output_file_error(const char* f1, const char* f2, int errv);
- void run_cmd_error(const char* f, const char* cmd, int errv);
- void statistics_exit(Statistics* stats);
- void free_directory(DirectoryManager dm);
- int hidden_filter(const struct dirent* directory);
- Params directory_parser(Params params);
- Params cmd_parser(Params params);
- DirectoryManager directory_manager_initialiser(Params params);
- void execute_command(Params params, char* path);
- Params prepare_command(Params params);
- void sigint_handler(int sig);
- AbsPath sbuf_initialiser(char* directory, char* path);
- Params validate_arguments(Params params);
- void exiter(Statistics* stats);
- Params process_command_line(int argc, char** argv);
- Params path_adder(Params params, char* path);
- void redirect_io(Params params, char* path, char* basePath, int cmd);
- void execute_commands(Params params, char* path, char* basePath, int cmd);
- /////////////////////////////////////////////////////////
- Params process_command_line(int argc, char** argv)
- {
- Params params = {NOT_ACTIVE, NOT_ACTIVE, NOT_ACTIVE, NOT_ACTIVE, NOT_ACTIVE,
- NOT_ACTIVE, NOT_GIVEN, NOT_GIVEN, NOT_GIVEN, NOT_GIVEN, NOT_GIVEN};
- argc--;
- argv++;
- while (argc && strncmp(argv[0], "--", 2) == 0) {
- if (!strcmp(argv[0], directoryArg) && argc != 1 && strlen(argv[1]) > 0
- && strncmp(argv[1], "--", 2) && !params.directoryGiven) {
- params.directoryGiven = ACTIVE;
- params.directory = argv[1];
- argc -= 2;
- argv += 2;
- } else if (!strcmp(argv[0], allfilesArg) && !params.allfiles) {
- params.allfiles = ACTIVE;
- argc--;
- argv++;
- } else if (!strcmp(argv[0], descendArg) && !params.descend) {
- params.descend = ACTIVE;
- argc--;
- argv++;
- } else if (!strcmp(argv[0], statisticsArg) && !params.statistics) {
- params.statistics = ACTIVE;
- argc--;
- argv++;
- } else if (!strcmp(argv[0], parallelArg) && !params.parallel) {
- params.parallel = ACTIVE;
- argc--;
- argv++;
- } else {
- usage_error();
- }
- }
- if (argc == 1 && strncmp(argv[argc - 1], "--", 2) != 0
- && strcmp(argv[argc - 1], "")) {
- params.cmd = argv[argc - 1];
- argc--;
- argv++;
- }
- if (argc) {
- usage_error();
- }
- params = cmd_parser(params);
- return params;
- }
- Params validate_arguments(Params params)
- {
- if (params.directoryGiven) {
- struct stat sbuf;
- if (stat(params.directory, &sbuf)) {
- directory_error(params.directory);
- }
- if (!S_ISDIR(sbuf.st_mode)) {
- directory_error(params.directory);
- }
- } else {
- params.directory = ".";
- }
- params = directory_parser(params);
- return params;
- }
- Params path_adder(Params params, char* path)
- {
- for (int i = 0; i < params.cm->numCmds; i++) {
- int j = 0;
- while (params.cm->cmdArray[i][j] != NULL) {
- if (!strcmp(params.cm->cmdArray[i][j], "{}")) {
- params.cm->cmdArray[i][j] = path;
- }
- j++;
- }
- }
- return params;
- }
- void redirect_io(Params params, char* path, char* basePath, int cmd)
- {
- int inputFile;
- int outputFile;
- if (params.cm->stdinFileName && cmd == 0) {
- if (!strcmp(params.cm->stdinFileName, "{}")) {
- params.cm->stdinFileName = path;
- }
- inputFile = open(params.cm->stdinFileName, O_RDONLY, S_IWUSR | S_IRUSR);
- if (inputFile < 0) {
- if (params.directoryGiven) {
- input_file_error(params.cm->stdinFileName, path, DNE);
- } else {
- input_file_error(params.cm->stdinFileName, basePath, DNE);
- }
- } else {
- dup2(inputFile, STDIN_FILENO);
- close(inputFile);
- }
- }
- if (params.cm->stdoutFileName && (cmd + 1) == params.cm->numCmds) {
- if (strstr(params.cm->stdoutFileName, "{}")) {
- char* brackets = strtok(params.cm->stdoutFileName, "{}");
- path = strcat(path, brackets);
- params.cm->stdoutFileName = path;
- }
- outputFile = open(params.cm->stdoutFileName,
- O_WRONLY | O_CREAT | O_TRUNC, S_IRWXU);
- if (outputFile < 0) {
- if (params.directoryGiven) {
- output_file_error(params.cm->stdoutFileName, path, DNE);
- } else {
- output_file_error(params.cm->stdoutFileName, basePath, DNE);
- }
- } else {
- dup2(outputFile, STDOUT_FILENO);
- close(outputFile);
- }
- }
- }
- PipeManager* pipe_manager(Params params) {
- PipeManager* pm = malloc(sizeof(PipeManager));
- pm->pipeCount = params.cm->numCmds - 1;
- pm->pipes = malloc(sizeof(int*) * pm->pipeCount);
- for (int i = 0; i < pm->pipeCount; i++) {
- int fp[PIPE_ENDS];
- pipe(fp);
- pm->pipes[i] = fp;
- }
- return pm;
- }
- void cmd_pipeliner(Params params, int cmd) {
- if (params.cm->numCmds == 1) {
- return;
- } else if (!params.pm) {
- params.pm = pipe_manager(params);
- }
- if (cmd == 0) {
- close(params.pm->pipes[cmd][READ_END]);
- params.pm->stdoutfp = dup(STDOUT_FILENO);
- dup2(params.pm->pipes[cmd][WRITE_END], STDOUT_FILENO);
- fflush(stdout);
- close(params.pm->pipes[cmd][WRITE_END]);
- }
- else if (cmd + 1 == params.cm->numCmds) {
- close(params.pm->pipes[cmd - 1][WRITE_END]);
- dup2(params.pm->pipes[cmd - 1][READ_END], STDIN_FILENO);
- close(params.pm->pipes[cmd - 1][READ_END]);
- dup2(params.pm->stdoutfp, STDOUT_FILENO);
- fflush(stdout);
- } else {
- close(params.pm->pipes[cmd - 1][WRITE_END]);
- dup2(params.pm->pipes[cmd - 1][READ_END], params.pm->pipes[cmd][WRITE_END]);
- close(params.pm->pipes[cmd - 1][READ_END]);
- }
- }
- void execute_commands(Params params, char* path, char* basePath, int cmd)
- {
- redirect_io(params, path, basePath, cmd);
- cmd_pipeliner(params, cmd);
- execvp(params.cm->cmdArray[cmd][0], params.cm->cmdArray[cmd]);
- run_cmd_error(params.cm->cmdArray[cmd][0], basePath, DNE);
- }
- Statistics* stats_initialiser(void)
- {
- Statistics* stats = malloc(sizeof(Statistics));
- stats->attempts = 0;
- stats->successes = 0;
- stats->nonZeros = 0;
- stats->sigterms = 0;
- stats->nonExecs = 0;
- return stats;
- }
- void update_statistics(Statistics* stats, int wstatus)
- {
- int rval;
- stats->attempts++;
- if (WIFEXITED(wstatus)) {
- rval = WEXITSTATUS(wstatus);
- if (rval == STANDARD) {
- stats->successes++;
- } else if (rval == DNE) {
- stats->nonExecs++;
- } else {
- stats->nonZeros++;
- }
- }
- if (WIFSIGNALED(wstatus)) {
- rval = WTERMSIG(wstatus);
- stats->sigterms++;
- }
- }
- Params every_file_handler(Params params, AbsPath path)
- {
- if (params.everyFile) {
- if (params.directoryGiven) {
- params = path_adder(params, path.absolutePath);
- } else {
- params = path_adder(params, path.path);
- }
- }
- return params;
- }
- Params prepare_command(Params params)
- {
- DirectoryManager dm = directory_manager_initialiser(params);
- params.stats = stats_initialiser();
- int childrenCount = 1;
- pid_t* children = malloc(sizeof(pid_t) * childrenCount);
- for (int i = 0; i < dm.entryCount; i++) {
- int wstatus;
- pid_t child;
- AbsPath path
- = sbuf_initialiser(params.directory, dm.entries[i]->d_name);
- for (int j = 0; j < params.cm->numCmds; j++) {
- if (!S_ISDIR(path.sbuf.st_mode) && !(child = fork())) {
- params = every_file_handler(params, path);
- execute_commands(params, path.absolutePath, path.path, j);
- }
- children[childrenCount - 1] = child;
- childrenCount++;
- waitpid(child, &wstatus, 0);
- update_statistics(params.stats, wstatus);
- }
- }
- free_directory(dm);
- return params;
- }
- void exiter(Statistics* stats)
- {
- if (sigint) {
- exit(INTERRUPTED);
- }
- if (stats->nonExecs) {
- exit(FAILURE);
- } else if (sigint) {
- exit(INTERRUPTED);
- }
- exit(STANDARD);
- }
- int main(int argc, char** argv)
- {
- struct sigaction sa;
- sa.sa_handler = sigint_handler;
- sigaction(SIGINT, &sa, NULL);
- while (!sigint) {
- setlocale(LC_COLLATE, "en_AU");
- Params params = process_command_line(argc, argv);
- /// printf("%s and %s and %s\n",
- /// params.cm->cmdArray[0][0],params.cm->cmdArray[0][1],
- /// params.cm->cmdArray[0][1]);
- params = validate_arguments(params);
- params = prepare_command(params);
- free_pipeline(params.cm);
- exiter(params.stats);
- }
- }
- /////////////////////////////////////////////////////////////////
- // Error Handling Functions
- /////////////////////////////////////////////////////////////////
- void usage_error(void)
- {
- fprintf(stderr, errorUsage);
- exit(USAGE);
- }
- void directory_error(const char* directoryName)
- {
- fprintf(stderr, errorCannotRead, directoryName);
- exit(DIRECTORY);
- }
- void cmd_error(void)
- {
- fprintf(stderr, errorInvalidCmd);
- exit(COMMAND);
- }
- void input_file_error(const char* f1, const char* f2, int errv)
- {
- fprintf(stderr, errorBadInputFile, f1, f2);
- exit(errv);
- }
- void output_file_error(const char* f1, const char* f2, int errv)
- {
- fprintf(stderr, errorBadOutFile, f1, f2);
- exit(errv);
- }
- void run_cmd_error(const char* f, const char* cmd, int errv)
- {
- fprintf(stderr, errorBadCmd, f, cmd);
- exit(errv);
- }
- void statistics_exit(Statistics* stats)
- {
- fprintf(stderr, statistics, stats->attempts, stats->successes,
- stats->nonZeros, stats->sigterms, stats->nonExecs);
- exiter(stats);
- }
- void sigint_handler(int sig)
- {
- if (sig == SIGINT) {
- sigint = true;
- }
- exit(INTERRUPTED);
- }
- /////////////////////////////////////////////////////////////////
- // Parser, Manager and Filter Functions
- /////////////////////////////////////////////////////////////////
- int hidden_filter(const struct dirent* directory)
- {
- return !(directory->d_name[0] == '.');
- }
- Params cmd_parser(Params params)
- {
- if (params.cmd) {
- params.cm = parse_pipeline_string(params.cmd);
- } else {
- params.cm = parse_pipeline_string("echo {}");
- }
- if (params.cm == NOT_GIVEN) {
- cmd_error();
- } else {
- int j = 0;
- while (params.cm->cmdArray[0][j] != NULL) {
- if (!strcmp(params.cm->cmdArray[0][j], "{}")) {
- params.everyFile = ACTIVE;
- return params;
- }
- j++;
- }
- }
- return params;
- }
- Params directory_parser(Params params)
- {
- if (params.directoryGiven
- && params.directory[strlen(params.directory) - 1] != '/') {
- strcat(params.directory, "/");
- } else if (!strcmp(params.directory, ".")) {
- params.directory = "./";
- }
- return params;
- }
- DirectoryManager directory_manager_initialiser(Params params)
- {
- struct dirent** entries;
- int entryCount;
- if (params.allfiles) {
- entryCount = scandir(params.directory, &entries, NULL, alphasort);
- } else {
- entryCount
- = scandir(params.directory, &entries, hidden_filter, alphasort);
- }
- DirectoryManager dm = {entries, entryCount};
- return dm;
- }
- AbsPath sbuf_initialiser(char* directory, char* path)
- {
- struct stat sbuf;
- char absolutePath[PATH_MAX];
- strcpy(absolutePath, directory);
- strcat(absolutePath, path);
- stat(absolutePath, &sbuf);
- AbsPath abs = {sbuf, path, absolutePath};
- return abs;
- }
- /////////////////////////////////////////////////////////////////
- // Memory Freeing Functions
- /////////////////////////////////////////////////////////////////
- void free_directory(DirectoryManager dm)
- {
- for (int i = 0; i < dm.entryCount; i++) {
- free(dm.entries[i]);
- }
- free(dm.entries);
- }
Advertisement
Add Comment
Please, Sign In to add comment