Operating Systems 2017F: Tutorial 3: Difference between revisions
| Line 75: | Line 75: | ||
                 data = (char *) mmap(NULL, len,  |                  data = (char *) mmap(NULL, len,  | ||
                                      PROT_READ, MAP_SHARED, fd, 0);  |                                       PROT_READ, MAP_SHARED, fd, 0);  | ||
                 if (data ==   |                  if (data == MAP_FAILED) {  | ||
                         report_error(strerror(errno));  |                          report_error(strerror(errno));  | ||
                 }  |                  }  | ||
| Line 85: | Line 85: | ||
                         }  |                          }  | ||
                 }  |                  }  | ||
                 printf(" a count %ld\n", count);  |                  printf(" a count %ld\n", count);  | ||
                if (munmap(data, len) == -1) {  | |||
                        report_error(strerror(errno));                          | |||
                }  | |||
                close(fd);  | |||
         }  |          }  | ||
Revision as of 17:31, 1 October 2017
In this tutorial you will be experimenting with and extending 3000test.c (listed below).
Tasks/Questions
- 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
 
 - Change 3000test to use lstat rather than stat. How does its behavior change?
 - Modify 3000test so when it is given a symbolic link it reports the name of the target. Use readlink(2).
 - 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.
 
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;
}