summaryrefslogtreecommitdiff
path: root/pgm3/report.c
diff options
context:
space:
mode:
Diffstat (limited to 'pgm3/report.c')
-rw-r--r--pgm3/report.c232
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);
+}