#include #include #include #include #include #include #include #include #include #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); }