Created
April 1, 2020 23:59
-
-
Save MyriaCore/1d89559f7bac723d5987b30c64b5d5ad to your computer and use it in GitHub Desktop.
SPFIND
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/****************************************************************************** | |
* Author: Marcus Simpkins | |
* Date: 4/1/2020 | |
* Pledge: I pledge my honor that I have abided by the Stevens Honor System. | |
* Project: HW4 - Permission Find & Sort | |
******************************************************************************/ | |
#include <stdio.h> // pipe | |
#include <stdlib.h> | |
#include <string.h> // strlen, strerror, etc | |
#include <stdbool.h> // bool values | |
#include <libgen.h> // basename | |
#include <getopt.h> // getpopt, etc | |
#include <errno.h> // errors! :D | |
#include <limits.h> // PATH_MAX | |
#include <dirent.h> // readdir, struct dirent, etc. | |
#include <sys/stat.h> // lstat, struct stat, etc. | |
#include <sys/wait.h> // wait | |
#include <unistd.h> | |
/** | |
* Displays the program's usage message when given a path to the program. | |
**/ | |
void display_usage(char *path) { | |
char *prog_name = basename(path); | |
printf("Usage: ./%s -d <directory> -p <permissions string> [-h]\n", prog_name); | |
} | |
/** | |
* Returns true if the given string is valid, and returns false otherwise. | |
**/ | |
bool valid_permstring(const char *permstring) { | |
bool valid = (strlen(permstring) == 9); | |
for(int i = 0; i < 9 && valid; i += 3) { | |
if (permstring[i] != 'r' && permstring[i] != '-') valid = false; | |
if (permstring[i+1] != 'w' && permstring[i+1] != '-') valid = false; | |
if (permstring[i+2] != 'x' && permstring[i+2] != '-') valid = false; | |
} | |
return valid; | |
} | |
/** | |
* Main program logic | |
**/ | |
int main(int argc, char *argv[]) { | |
// print usage if no args given | |
if (argc == 1) { | |
display_usage(argv[0]); | |
return EXIT_SUCCESS; | |
} | |
// handle command line options | |
char *dirpath = NULL; char *permstring = NULL; | |
char opt; opterr = 0; | |
while ((opt = getopt(argc, argv, "d:p:h")) != -1) { | |
switch (opt) { | |
case 'd': | |
dirpath = optarg; | |
break; | |
case 'p': | |
permstring = optarg; | |
break; | |
case 'h': | |
display_usage(argv[0]); | |
return EXIT_SUCCESS; | |
/* case '?': */ | |
/* fprintf(stderr, "Error: Unknown option '-%c' recieved.\n", optopt); */ | |
/* return EXIT_FAILURE; */ | |
case ':': | |
fprintf(stderr, "Error: Option -%c expects argument.\n", optopt); | |
return EXIT_FAILURE; | |
} | |
} | |
// ensure option arguments were properly passed | |
if (dirpath == NULL) { | |
fprintf(stderr, "Error: Required argument -d <directory> not found.\n"); | |
return EXIT_FAILURE; | |
} | |
if (permstring == NULL) { | |
fprintf(stderr, "Error: Required argument -p <permissions string> not found.\n"); | |
return EXIT_FAILURE; | |
} | |
// validate directory | |
DIR *dir = opendir(dirpath); | |
if (dir == NULL) { | |
if (errno != EACCES) | |
fprintf(stderr, "Error: Cannot stat '%s'. No such file or directory.\n", dirpath); | |
else { | |
char pathbuf[PATH_MAX + 1]; | |
realpath(dirpath, pathbuf); | |
fprintf(stderr, "Error: Cannot open directory '%s'. Permission denied.\n", pathbuf); | |
} | |
return EXIT_FAILURE; | |
} else closedir(dir); | |
// validate permstring | |
if (!valid_permstring(permstring)) { | |
fprintf(stderr, "Error: Permissions string '%s' is invalid.\n", permstring); | |
return EXIT_FAILURE; | |
} | |
// forks and pipes | |
int pfind_to_sort[2], sort_to_parent[2]; | |
pipe(pfind_to_sort); pipe(sort_to_parent); | |
pid_t pid[2]; // pid[0] = pfind, pid[1] = sort | |
int status[2]; // exit status for pfind and sort. | |
// fork: pfind | |
if ((pid[0] = fork()) == 0) { | |
// setup related pipes | |
close(pfind_to_sort[0]); | |
dup2(pfind_to_sort[1], STDOUT_FILENO); | |
// close unrelated pipes | |
close(sort_to_parent[0]); | |
close(sort_to_parent[1]); | |
// call pfind | |
execlp("./pfind", "pfind", argv[1], argv[2], argv[3], argv[4], NULL); | |
return EXIT_FAILURE; | |
} | |
// fork: sort | |
if ((pid[1] = fork()) == 0) { | |
// close old pipes | |
close(pfind_to_sort[1]); | |
// setup related pipes | |
dup2(pfind_to_sort[0], STDIN_FILENO); | |
dup2(sort_to_parent[1], STDOUT_FILENO); | |
// close unrelated pipes | |
close(sort_to_parent[0]); | |
// call sort | |
execlp("sort", "sort", NULL); | |
} | |
// close old pipes | |
close(sort_to_parent[1]); | |
// setup related pipes | |
dup2(sort_to_parent[0], STDIN_FILENO); | |
// close all unrelated pipes | |
close(pfind_to_sort[0]); | |
close(pfind_to_sort[1]); | |
// print from the pipe character-by-character | |
char c; int num_matches = 0; // start at -1 b/c there'll always be at least 1 newline | |
while(read(STDIN_FILENO, &c, sizeof(char)) != 0) { | |
putc(c, stdout); | |
if (c == '\n') num_matches++; | |
} | |
// validate pfind's exit status | |
wait(&status[0]); | |
if (WEXITSTATUS(status[0]) != EXIT_SUCCESS) { | |
fprintf(stderr, "Error: pfind failed.\n"); | |
return EXIT_FAILURE; | |
} | |
// validate sort's exit status | |
wait(&status[1]); | |
if (WEXITSTATUS(status[1]) != EXIT_SUCCESS) { | |
fprintf(stderr, "Error: sort failed.\n"); | |
return EXIT_FAILURE; | |
} | |
printf("Total matches: %d\n", num_matches); | |
return EXIT_SUCCESS; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment