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/file1Binary files differ new 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/file2Binary files differ new 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/file3Binary files differ new 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); +} |