Skip to content

Instantly share code, notes, and snippets.

@MyriaCore
Created April 1, 2020 23:59
Show Gist options
  • Save MyriaCore/1d89559f7bac723d5987b30c64b5d5ad to your computer and use it in GitHub Desktop.
Save MyriaCore/1d89559f7bac723d5987b30c64b5d5ad to your computer and use it in GitHub Desktop.
SPFIND
/******************************************************************************
* 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