Operating Systems 2017F: Tutorial 3

From Soma-notes
Jump to navigation Jump to search

In this tutorial you will be experimenting with and extending 3000test.c (listed below).

Tasks/Questions

  1. Compile and run 3000test.c. It takes a filename as an argument and reports information on the file. Try giving it the following and see what it reports:
    • a regular text file that exists
    • a directory
    • a symbolic link
    • a device file
  2. Change 3000test to use lstat rather than stat. How does its behavior change?
  3. Modify 3000test so when it is given a symbolic link it reports the name of the target. Use readlink(2).
  4. How does the memory use of 3000test change as it runs? You may want to add calls to sleep(3) so you can observe its memory usage. You can create a 1 GB file of random data with the command dd if=/dev/urandom of=test bs=1024 count=1000000.
  5. Create a program 3000compare.c based on 3000test that compares the contents of two files and says whether or not they differ.
    • If given symbolic links it should report on where they point and only say they are equal if they refer to the same file.
    • If given two device files, it should say that they are equal if they are both the same kind of device file and have the same major and minor numbers.
    • If given two hard links to the same file, it should say that the files are identical because they refer to the same inode.
    • Other kinds of files (directories, pipes) should not be compared. Instead, it should report on the type of each file.

Code

/* 3000test.c */
/* v1 Oct. 1, 2017 */
/* Licenced under the GPLv3, copyright Anil Somayaji */
/* You really shouldn't be incorporating parts of this in any other code,
   it is meant for teaching, not production */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>

void report_error(char *error)
{
        fprintf(stderr, "Error: %s\n", error);

        exit(-1);
}

int main(int argc, char *argv[])
{
        struct stat statbuf;
        char *fn;
        int fd;
        size_t len, i, count;
        
        char *data;

        if (argc < 2) {
                if (argc < 1) {
                        report_error("no command line");
                        fprintf(stderr, "Usage: %s <file>\n", argv[0]); 
                } else {
                        report_error("Not enough arguments");
                        fprintf(stderr, "Usage: %s <file>\n", argv[0]); 
                }
        }

        fn = argv[1];

        if (stat(fn, &statbuf)) {
                report_error(strerror(errno));
        }

        len = statbuf.st_size;
        printf("File %s: \n", fn);
        printf("   inode %ld\n", statbuf.st_ino);
        printf("  length %ld\n", len);        

        if (S_ISREG(statbuf.st_mode)) {
                fd = open(fn, O_RDONLY);
                if (fd == -1) {
                        report_error(strerror(errno));
                }
                data = (char *) mmap(NULL, len,
                                     PROT_READ, MAP_SHARED, fd, 0);
                if (data == MAP_FAILED) {
                        report_error(strerror(errno));
                }

                count = 0;
                for (i=0; i<len; i++) {
                        if (data[i] == 'a') {
                                count++;
                        }
                }

                printf(" a count %ld\n", count);

                if (munmap(data, len) == -1) {
                        report_error(strerror(errno));                        
                }
                close(fd);
        }

        return 0;
}