diff options
Diffstat (limited to 'pgm3/report.c')
-rw-r--r-- | pgm3/report.c | 232 |
1 files changed, 232 insertions, 0 deletions
diff --git a/pgm3/report.c b/pgm3/report.c new file mode 100644 index 0000000..623de6f --- /dev/null +++ b/pgm3/report.c @@ -0,0 +1,232 @@ +#include <errno.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/sysmacros.h> +#include <unistd.h> + +#define FALSE 0 +#define FILE_BUFF 4096 +#define TRUE 1 + +int terminateFlag = 1; // Used with signal handler function. + +void sigHandler(int signum) { + /* + * sigHandler() waits for a SIGUSR1 signal. Upon receiving this signal it + * decrements terminateFlag, lowering it to zero. + */ + + if (signum == SIGUSR1) { + terminateFlag--; + } + +} + +int main(int argc, char *argv[]) { + /* + * report takes in one required argument ("num") and two optional arguments. + * -k specifies that output should be printed in kilobytes, not bytes + * -d specifies a delay that should be waited before reading each filename + * into the totalsize child process. + * + * Report takes in filenames on its stdin and then calls four child + * processes. Two execute accessed, one with num as an arg and one with + * -num as an arg. report writes its stdin to the stdin of the accessed + * children. The accessed children then print their output to the stdin + * of two more children that execute totalsize. These totalsize + * children run through the filenames they're given and print out the + * size of those files back into report. This is all done via pipes. + * + * report then prints out the results it receives from its children. + */ + char byteSum[10]; + char delayStr[10]; + char *envar = NULL; + char filename[FILE_BUFF]; + char numNeg[11]; + char thisPID[10]; + int accessedNum; + int delay = 0; + int i = 2; + + // Go through args. + if (argc < 2) { + fprintf(stderr, "usage: ./report [num days] {-k} {-d} [delay]\n"); + exit(1); + } + + // Fetch accessedNum parameter + accessedNum = strtol(argv[1], NULL, 10); + errno = 0; + + if (accessedNum <= 0) { + fprintf(stderr, "report: num must be positive, nonzero integer.\n"); + exit(1); + } + else if (errno == ERANGE) { + fprintf(stderr, "report: num must be of integer size.\n"); + exit(1); + } + else if (errno == EINVAL) { + fprintf(stderr, "report: num must be integer type.\n"); + exit(1); + } + + // Set the second accessed num as negative. + sprintf(numNeg, "%d", accessedNum * -1); + + while (argv[i]) { + + if (strcmp(argv[i], "-k") == 0) { + setenv("UNITS", "k", 1); + } + else if (strcmp(argv[i], "-d") == 0) { + delay = strtol(argv[i+1], NULL, 10); + errno = 0; + + if (delay <= 0) { + fprintf(stderr, "report: delay must be positive, nonzero integer.\n"); + exit(1); + } + else if (errno == ERANGE) { + fprintf(stderr, "report: delay must be of integer size.\n"); + exit(1); + } + else if (errno == EINVAL) { + fprintf(stderr, "report: delay must be integer type.\n"); + exit(1); + } + + sprintf(delayStr, "%d", delay); + setenv("TSTALL", delayStr, 1); + i++; + } + else { + fprintf(stderr, "usage: ./report [num days] {-k} {-d} [delay]\n"); + exit(1); + } + + i++; + } + + // Set up signal handling. + sprintf(thisPID, "%d", getpid()); + setenv("TMOM", thisPID, 1); + signal(SIGUSR1, sigHandler); + + // Set up pipes. + int pipeRtoA1[2]; pipe(pipeRtoA1); + int pipeRtoA2[2]; pipe(pipeRtoA2); + int pipeA1toT1[2]; pipe(pipeA1toT1); + int pipeA2toT2[2]; pipe(pipeA2toT2); + int pipeT1toR[2]; pipe(pipeT1toR); + int pipeT2toR[2]; pipe(pipeT2toR); + + if (fork() == 0) { // accessed 1 + // Close unneeded pipes ===================== + close(pipeRtoA1[1]); + close(pipeRtoA2[0]); close(pipeRtoA2[1]); + close(pipeA1toT1[0]); + close(pipeA2toT2[0]); close(pipeA2toT2[1]); + close(pipeT1toR[0]); close(pipeT1toR[1]); + close(pipeT2toR[0]); close(pipeT2toR[1]); + // ========================================== + + // Dup read end to stdin and write end to stdout + close(0); dup(pipeRtoA1[0]); close(pipeRtoA1[0]); + close(1); dup(pipeA1toT1[1]); close(pipeA1toT1[1]); + execl("accessed", "accessed", argv[1], NULL); + } + else if (fork() == 0) { // accessed 2 + // Close unneeded pipes ===================== + close(pipeRtoA1[0]); close(pipeRtoA1[1]); + close(pipeRtoA2[1]); + close(pipeA1toT1[0]); close(pipeA1toT1[1]); + close(pipeA2toT2[0]); + close(pipeT1toR[0]); close(pipeT1toR[1]); + close(pipeT2toR[0]); close(pipeT2toR[1]); + // ========================================== + + close(0); dup(pipeRtoA2[0]); close(pipeRtoA2[0]); + close(1); dup(pipeA2toT2[1]); close(pipeA2toT2[1]); + execl("accessed", "accessed", numNeg, NULL); + } + else if (fork() == 0) { // totalsize 1 + // Close unneeded pipes ===================== + close(pipeRtoA1[0]); close(pipeRtoA1[1]); + close(pipeRtoA2[0]); close(pipeRtoA2[1]); + close(pipeA1toT1[1]); + close(pipeA2toT2[0]); close(pipeA2toT2[1]); + close(pipeT1toR[0]); + close(pipeT2toR[0]); close(pipeT2toR[1]); + // ========================================== + + close(0); dup(pipeA1toT1[0]); close(pipeA1toT1[0]); + close(1); dup(pipeT1toR[1]); close(pipeT1toR[1]); + execl("totalsize", "totalsize", NULL); + } + else if (fork() == 0) { // totalsize 2 + // Close unneeded pipes ===================== + close(pipeRtoA1[0]); close(pipeRtoA1[1]); + close(pipeRtoA2[0]); close(pipeRtoA2[1]); + close(pipeA1toT1[0]); close(pipeA1toT1[1]); + close(pipeA2toT2[1]); + close(pipeT1toR[0]); close(pipeT1toR[1]); + close(pipeT2toR[0]); + // ========================================== + + close(0); dup(pipeA2toT2[0]); close(pipeA2toT2[0]); + close(1); dup(pipeT2toR[1]); close(pipeT2toR[1]); + execl("totalsize", "totalsize", NULL); + } + + // Close those pipes which parent report does not need + close(pipeRtoA1[0]); + close(pipeRtoA2[0]); + close(pipeA1toT1[0]); close(pipeA1toT1[1]); + close(pipeA2toT2[0]); close(pipeA2toT2[1]); + close(pipeT1toR[1]); + close(pipeT2toR[1]); + + // Write stdin from report to accessed children + while (scanf("%s", filename) == 1) { + write(pipeRtoA1[1], strcat(filename, " "), strlen(filename) + 1); + write(pipeRtoA2[1], strcat(filename, " "), strlen(filename) + 1); + } + + // Close remaining pipes. + close(pipeRtoA1[1]); close(pipeRtoA2[1]); + + // Enter non-terminating loop to wait for children + while (terminateFlag) { + printf("*"); + sleep(1); + } + + // Print results of first totalsize child + read(pipeT1toR[0], byteSum, sizeof(byteSum)); close(pipeT1toR[0]); + sscanf(byteSum, " %s ", byteSum); + printf("\nA total of %s ", byteSum); + + if ((envar = getenv("UNITS")) == NULL || !(envar[0] != 'k' || envar[0] != 'K')) { + printf("bytes "); + } + + printf("are in regular files not accessed for %s days.\n----------\n", argv[1]); + + // Print results of second totalsize child + read(pipeT2toR[0], byteSum, sizeof(byteSum)); close(pipeT2toR[0]); + sscanf(byteSum, " %s ", byteSum); + printf("A total of %s ", byteSum); + + if ((envar = getenv("UNITS")) == NULL || !(envar[0] != 'k' || envar[0] != 'K')) { + printf("bytes "); + } + + printf("are in regular files accessed within %s days.\n\n", argv[1]); + exit(0); +} |