Try Firefox!

IC221 Lab 5: Reimplementing 'touch'

Background
The filesystem in Unix is all-important. One reason, of course, is simply that files are important. However, in Unix the filesystem is used for more than just files. In this lab you'll use some system calls to query and modify file properties: specifically access time/date information.

Lab setup
  1. Create a directory lab05 for this lab.
  2. Copy the following compressed archive file to your lab05 directory:
    ~wcbrown/courses/IC221/labs/L05/lab05.tar.gz
    	    
  3. Unzip and untar the archive.
  4. Enter the command make at the command line. This will compile the source file mytouch.c and create the executable mytouch, which does nothing. As you add code to mytouch.c, you can recompile by simply typing make. You'll learn more about make later.

Lab Purpose
With this lab you will re-implement the touch utility program which, given a file name, sets the access and modification times of the file if it exists, or creates the file if it does not already exist. Unlike the real touch program which isn't verbose, our version prints information. On the other hand, our version will only be able to handle a single file. The point of this lab is to:

  1. Provide experience with making system calls, i.e. direct calls to functions executed by the kernel, not C standard libraries.
  2. Give you more experience programming in C.
  3. Teach you where to look for information on the standard UNIX types, like mode_t and others found in the header file: /usr/include/sys/types.h
  4. Help you to understand what information is contained in an i-node by examining the struct stat data type.
  5. Cause you and your fellow students pain.

What to do
Here's how the user will interface with your program:
    $ mytouch <file>   ← The angle brackets indicate that the argument is mandatory. 
For example entering mytouch hello.txt at the prompt would be OK, but simply mytouch would not. Remember the UNIX philosophy, never die silently! So your program will output a helpful error message if the user doesn't use the program correctly (see the desired output, in 6 below).

  1. Read the UNIX manual page describing the UNIX Manual pages, i.e, man man. Note how man must be invoked to read an entry in a particular section of the manual.
  2. Read these entries from Section 2 of the UNIX Manual pages: time, stat, utime. You can also read about them in the textbook.
  3. Read the entry on ctime from Section 3C of the UNIX Manual.
  4. Read the man page on getpwuid.
  5. Make note of which header files to #include to be able to use these functions: time, stat, ctime, utime, getpwuid
  6. Complete the program skeleton provided in the tar archive you downloaded. Here's what the solution will look like:
    $ ls hello.txt
    hello.txt: No such file or directory
    $ ls -la
    total 30
    drwxr-x--- 2 stahl faculty 512 Feb 6 15:25 .
    drwsr-x--- 7 stahl faculty 512 Feb 6 15:23 ..
    -rw-r----- 1 stahl faculty 192 Feb 6 15:20 Makefile
    -rwxr----- 1 stahl faculty 10136 Feb 6 15:24 mytouch
    -rw-r----- 1 stahl faculty 1486 Feb 21 2007 mytouch.c
    $ mytouch hello.txt
    The time is: Wed Feb 6 15:25:42 2008
    Before mytouch:
    Last accessed: Wed Feb 6 15:25:42 2008
    Last modified: Wed Feb 6 15:25:42 2008
    After mytouch:
    Last accessed: Wed Feb 6 15:25:42 2008
    Last modified: Wed Feb 6 15:25:42 2008
    File is owned by: stahl
    $ ls -l hello.txt
    -rw-r----- 1 stahl scs 0 Feb 6 15:25 hello.txt
    $ mytouch
    Argument missing.
    Usage: mytouch <filename>
    $ mytouch foo bar
    Too many arguments
    Usage: mytouch <filename>
    $
    	    
Submission instructions
Follow the general submission instructions and submit the lab05 directory which, at a minimum, will contain mytouch.c, Makefile and a file README that contains you name and alpha, and the answers to the following questions:

1) Given the definition:

       uid_t bar = 9707;

   which of the following is a correct call to getpwuid?

   a) struct passwd foo = getpwuid(bar);
   b) struct passwd *foo = getpwuid(bar);
   c) struct passwd foo = getpwuid(&bar);
   d) struct passwd *foo = getpwuid(&bar);

   HINT: RTFM!


2) Assuming foo has type "struct utimbuf", which of the following
   is a correct call to utime? HINT: RTFM!

   a) int  bar = utime("myfile",foo);
   b) int *bar = utime("myfile",foo);
   c) int  bar = utime("myfile",&foo);
   d) int *bar = utime("myfile",&foo);

3) Assuming foo has type "struct stat", which of the following
   is a correct call stat?   HINT: RTFM!

   a) int bar = stat("argv[1]",foo);
   b) int bar = stat(argv[1],foo);
   c) int bar = stat("argv[1]",&foo);
   d) int bar = stat(argv[1],&foo);

4) For each of the following expressions, give the type of the
   expression (using the exact type, e.g. "int*" not "pointer to int")
   or ERROR if the expression is invalid.  You may assume the following
   definitions:

   struct stat foo;
   struct stat *p1;
   struct passwd bar;
   struct passwd *p2;
   struct utimbuf urg;
   struct utimbuf *p3;

   a) foo.st_mode

   b) p1->st_atime

   c) p1->st_fstype[2]

   d) bar->pw_name

   e) getpwuid((uid_t)9702)

   f) p2->pw_shell

   g) (uid_t)1100

   h) urg.modtime

   i) &urg.modtime

   j) *&urg.modtime

   k) *p3


5) The prototype for stat shows us that its second argument must
   be "struct stat*", i.e. a pointer to a struct stat.  Why is it set
   up that way?  Why *must* stat be passed a pointer rather than a
   struct stat object?


	      


Christopher W Brown
Last modified: Wed Feb 4 16:38:13 EST 2009