diff options
Diffstat (limited to 'pgm3')
-rw-r--r-- | pgm3/accessed.c | 122 | ||||
-rw-r--r-- | pgm3/pgm3test.d/fileinfo.c | 30 | ||||
-rw-r--r-- | pgm3/pgm3test.d/link.c | 30 | ||||
-rw-r--r-- | pgm3/pgm3test.d/script | 24 | ||||
-rw-r--r-- | pgm3/pgm3test.d/subdir/subfileinfo.c | 30 | ||||
-rw-r--r-- | pgm3/pgm3test.d/subdir/subsubdir/file1 | bin | 0 -> 1023 bytes | |||
-rw-r--r-- | pgm3/pgm3test.d/subdir/subsubdir/file2 | bin | 0 -> 1023 bytes | |||
-rw-r--r-- | pgm3/pgm3test.d/subdir/subsubdir/file3 | bin | 0 -> 1023 bytes | |||
-rw-r--r-- | pgm3/pgm3test.d/symlink.c | 30 | ||||
-rw-r--r-- | pgm3/report.c | 232 | ||||
-rw-r--r-- | pgm3/totalsize.c | 126 |
11 files changed, 624 insertions, 0 deletions
diff --git a/pgm3/accessed.c b/pgm3/accessed.c new file mode 100644 index 0000000..b1007a9 --- /dev/null +++ b/pgm3/accessed.c @@ -0,0 +1,122 @@ +#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 <time.h> +#include <unistd.h> + +#define FALSE 0 +#define FILE_BUFF 4096 +#define TRUE 1 + +struct NODE { + char filename[FILE_BUFF]; + int inode; + long atime; + struct NODE *next; +}; + +int makeList(struct NODE **head) { + /* + * makeList builds a linked list of nodes representing the filenames + * given on stdin and their access time. + */ + char filename[FILE_BUFF]; + int inList = FALSE; + struct NODE *currentNode = NULL; + struct NODE *newNode = NULL; + struct stat statData; + + while (scanf(" %s", filename) == 1) { + + if (stat(filename, &statData) == 0 && S_ISREG(statData.st_mode)) { + inList = FALSE; + + for (currentNode = *head; currentNode != NULL; currentNode = currentNode->next) { + + if (currentNode->inode == statData.st_ino) { + inList = TRUE; + } + + } + + if (!inList) { + newNode = (struct NODE *) malloc(sizeof(struct NODE)); + newNode->inode = statData.st_ino; + strcpy(newNode->filename, filename); + newNode->atime = (time(NULL) - statData.st_atime) / 86400; + newNode->next = *head; + *head = newNode; + } + + } + + } + + return 0; +} + +int main(int argc, char *argv[]) { + /* + * accessed takes in filenames from stdin and one command line argument, + * "num". It then builds a linked list of the unique, regular files and + * prints out those files not accessed in "num" days (if num is positive) + * or prints out those files accesssed within "num" days (if num is + * negative). + */ + int accessedNum = 0; + struct NODE *currentNode = NULL; + struct NODE *list = NULL; + + // Go through args + if (argc != 2) { + fprintf(stderr, "accessed: usage: ./accessed [num days]\n"); + exit(1); + } + + accessedNum = strtol(argv[1], NULL, 10); + + if (errno == EINVAL) { + fprintf(stderr, "accessed: error: num must be integer type.\n"); + exit(1); + } + else if (errno == ERANGE) { + fprintf(stderr, "accessed: error: num must be of integer size.\n"); + exit(1); + } + else if (accessedNum == 0) { + fprintf(stderr, "accessed: error: num must be nonzero integer.\n"); + exit(1); + } + + if (makeList(&list) != 0) { + fprintf(stderr, "accessed: error: could not build linked list.\n"); + exit(1); + } + + // print out filenames that match requested access time + for (currentNode = list; currentNode != NULL; currentNode = currentNode->next) { + + if (accessedNum > 0 && currentNode->atime > accessedNum) { // not within num days + printf("%s\n", currentNode->filename); + } + + if (accessedNum < 0 && currentNode->atime <= (accessedNum * -1)) { // within num days + printf("%s\n", currentNode->filename); + } + + } + + // free list + while (currentNode != NULL) { + currentNode = list; + list = list->next; + free(currentNode); + } + + exit(0); +} diff --git a/pgm3/pgm3test.d/fileinfo.c b/pgm3/pgm3test.d/fileinfo.c new file mode 100644 index 0000000..eed7902 --- /dev/null +++ b/pgm3/pgm3test.d/fileinfo.c @@ -0,0 +1,30 @@ +#include <sys/types.h> +#include <sys/stat.h> +#include <stdio.h> +#include <errno.h> +#include <sys/sysmacros.h> +#include <sys/time.h> + +main(argc,argv) +int argc; char *argv[]; +{ + + struct stat info; + + if (argc != 2) { + fprintf(stderr, "fileinfo: usage fileinfo filename\n"); + exit(1); + } + + if (stat(argv[1], &info) != 0) { + fprintf(stderr,"fileinfo: cannot stat %s:", argv[1]); + perror(NULL); + } + printf("%s: ", argv[1]); + printf("(device,i_number)=(%d/%d,%ld)", major(info.st_dev), minor(info.st_dev), (long) info.st_ino); + printf(" last accessed %d seconds ago\n", time(NULL)-info.st_atime); + if (S_ISREG(info.st_mode)) + printf("\tdesignated a regular file\n"); + if (S_ISLNK(info.st_mode)) + printf("\tdesignated a symlink\n"); +} diff --git a/pgm3/pgm3test.d/link.c b/pgm3/pgm3test.d/link.c new file mode 100644 index 0000000..eed7902 --- /dev/null +++ b/pgm3/pgm3test.d/link.c @@ -0,0 +1,30 @@ +#include <sys/types.h> +#include <sys/stat.h> +#include <stdio.h> +#include <errno.h> +#include <sys/sysmacros.h> +#include <sys/time.h> + +main(argc,argv) +int argc; char *argv[]; +{ + + struct stat info; + + if (argc != 2) { + fprintf(stderr, "fileinfo: usage fileinfo filename\n"); + exit(1); + } + + if (stat(argv[1], &info) != 0) { + fprintf(stderr,"fileinfo: cannot stat %s:", argv[1]); + perror(NULL); + } + printf("%s: ", argv[1]); + printf("(device,i_number)=(%d/%d,%ld)", major(info.st_dev), minor(info.st_dev), (long) info.st_ino); + printf(" last accessed %d seconds ago\n", time(NULL)-info.st_atime); + if (S_ISREG(info.st_mode)) + printf("\tdesignated a regular file\n"); + if (S_ISLNK(info.st_mode)) + printf("\tdesignated a symlink\n"); +} diff --git a/pgm3/pgm3test.d/script b/pgm3/pgm3test.d/script new file mode 100644 index 0000000..9bb8248 --- /dev/null +++ b/pgm3/pgm3test.d/script @@ -0,0 +1,24 @@ +#!/bin/sh + +# after doing a +# cp -a ~kearns/public/415/P3/pgm3test.d . +# run ./script to set access times +# +# ./script should be run before every test to +# reset access times to well-known values + +OLD='2005-01-01' +NEW='yesterday' + +TOUCH=/usr/bin/touch + +#give a.out current access time +$TOUCH --time=access ./a.out + +# give fileinfo.c access time of Jan 1, 2005 +$TOUCH --time=access --date=$OLD ./fileinfo.c + +# subdir/subsubdir files given staggered access times +$TOUCH --time=access --date=$OLD ./subdir/subsubdir/file1 +$TOUCH --time=access --date=$NEW ./subdir/subsubdir/file2 +$TOUCH --time=access --date=$NEW ./subdir/subsubdir/file3 diff --git a/pgm3/pgm3test.d/subdir/subfileinfo.c b/pgm3/pgm3test.d/subdir/subfileinfo.c new file mode 100644 index 0000000..eed7902 --- /dev/null +++ b/pgm3/pgm3test.d/subdir/subfileinfo.c @@ -0,0 +1,30 @@ +#include <sys/types.h> +#include <sys/stat.h> +#include <stdio.h> +#include <errno.h> +#include <sys/sysmacros.h> +#include <sys/time.h> + +main(argc,argv) +int argc; char *argv[]; +{ + + struct stat info; + + if (argc != 2) { + fprintf(stderr, "fileinfo: usage fileinfo filename\n"); + exit(1); + } + + if (stat(argv[1], &info) != 0) { + fprintf(stderr,"fileinfo: cannot stat %s:", argv[1]); + perror(NULL); + } + printf("%s: ", argv[1]); + printf("(device,i_number)=(%d/%d,%ld)", major(info.st_dev), minor(info.st_dev), (long) info.st_ino); + printf(" last accessed %d seconds ago\n", time(NULL)-info.st_atime); + if (S_ISREG(info.st_mode)) + printf("\tdesignated a regular file\n"); + if (S_ISLNK(info.st_mode)) + printf("\tdesignated a symlink\n"); +} diff --git a/pgm3/pgm3test.d/subdir/subsubdir/file1 b/pgm3/pgm3test.d/subdir/subsubdir/file1 Binary files differnew file mode 100644 index 0000000..1bce2be --- /dev/null +++ b/pgm3/pgm3test.d/subdir/subsubdir/file1 diff --git a/pgm3/pgm3test.d/subdir/subsubdir/file2 b/pgm3/pgm3test.d/subdir/subsubdir/file2 Binary files differnew file mode 100644 index 0000000..1bce2be --- /dev/null +++ b/pgm3/pgm3test.d/subdir/subsubdir/file2 diff --git a/pgm3/pgm3test.d/subdir/subsubdir/file3 b/pgm3/pgm3test.d/subdir/subsubdir/file3 Binary files differnew file mode 100644 index 0000000..1bce2be --- /dev/null +++ b/pgm3/pgm3test.d/subdir/subsubdir/file3 diff --git a/pgm3/pgm3test.d/symlink.c b/pgm3/pgm3test.d/symlink.c new file mode 100644 index 0000000..eed7902 --- /dev/null +++ b/pgm3/pgm3test.d/symlink.c @@ -0,0 +1,30 @@ +#include <sys/types.h> +#include <sys/stat.h> +#include <stdio.h> +#include <errno.h> +#include <sys/sysmacros.h> +#include <sys/time.h> + +main(argc,argv) +int argc; char *argv[]; +{ + + struct stat info; + + if (argc != 2) { + fprintf(stderr, "fileinfo: usage fileinfo filename\n"); + exit(1); + } + + if (stat(argv[1], &info) != 0) { + fprintf(stderr,"fileinfo: cannot stat %s:", argv[1]); + perror(NULL); + } + printf("%s: ", argv[1]); + printf("(device,i_number)=(%d/%d,%ld)", major(info.st_dev), minor(info.st_dev), (long) info.st_ino); + printf(" last accessed %d seconds ago\n", time(NULL)-info.st_atime); + if (S_ISREG(info.st_mode)) + printf("\tdesignated a regular file\n"); + if (S_ISLNK(info.st_mode)) + printf("\tdesignated a symlink\n"); +} 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); +} diff --git a/pgm3/totalsize.c b/pgm3/totalsize.c new file mode 100644 index 0000000..c15a72d --- /dev/null +++ b/pgm3/totalsize.c @@ -0,0 +1,126 @@ +#include <errno.h> +#include <math.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 <time.h> +#include <unistd.h> + +#define FALSE 0 +#define FILE_BUFF 4096 +#define TRUE 1 + +struct NODE { + int inode; + long size; + struct NODE *next; +}; + +int main() { + /* + * totalsize takes in a list of filenames on its stdin and adds up the + * total size of those files (using stat) and prints the results as + * either bytes or kilobytes. It checks the UNITS environment variable to + * know whether to print in bytes or kilobytes. It checks the TSTALL + * environment variable for an integer to use as a delay before checking + * for files. It also checks the TMOM environment variable for the + * process ID of a parent process to send a SIGUSR1 signal to. + * + * totalsize builds a linked list out of the entered filenames and then + * goes through the unique, regular files and uses stat() to grab + * information about those files (inode, size). + */ + char *envar = NULL; + char filename[FILE_BUFF]; + int inList = FALSE; + int sigPID; + int sleepTime; + long long byteSum = 0; + struct NODE *currentNode = NULL; + struct NODE *head = NULL; + struct NODE *newNode = NULL; + struct stat statData; + + // Check TSTALL for time delay + errno = 0; + + if ((envar = getenv("TSTALL")) != NULL + && (sleepTime = strtol(envar, NULL, 10)) > 0 + && errno == 0) { + sleep(sleepTime); + } + + // Take in standard input and build linked list. + while (scanf(" %s", filename) == 1) { + + if (stat(filename, &statData) == 0 && S_ISREG(statData.st_mode)) { + inList = FALSE; + + for (currentNode = head; currentNode != NULL; currentNode = currentNode->next) { + + if (currentNode->inode == statData.st_ino) { + inList = TRUE; + } + + } + + if (!inList) { + newNode = (struct NODE *) malloc(sizeof(struct NODE)); + newNode->inode = statData.st_ino; + newNode->size = statData.st_size; + newNode->next = head; + head = newNode; + } + + } + + // Check TSTALL for time delay + errno = 0; + + if ((envar = getenv("TSTALL")) != NULL + && (sleepTime = strtol(envar, NULL, 10)) > 0 + && errno == 0) { + sleep(sleepTime); + } + + } + + // Add up the number of bytes and print out the results + byteSum = 0; + + for (currentNode = head; currentNode != NULL; currentNode = currentNode->next) { + byteSum += currentNode->size; + } + + if ((envar = getenv("UNITS")) != NULL + && (envar[0] == 'k' || envar[0] == 'K') + && envar[1] == '\0') { + byteSum /= 1024; + printf("%lldkB\n", byteSum); + } + else { + printf("%lld\n", byteSum); + } + + // Free list + while (currentNode != NULL) { + currentNode = head; + head = head->next; + free(currentNode); + } + + errno = 0; + + // Send SIGNUSR1 signal to calling parent + if ((envar = getenv("TMOM")) != NULL + && (sigPID = strtol(envar, NULL, 10)) > 0 + && errno == 0) { + kill(sigPID, SIGUSR1); + } + + exit(0); +} |