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