/* test_lock.c

This is a program that may be used to test if file locking is working
on a Unix/Linux storage area.  It is especially helpful in determining
when file locking has failed on NFS mounted storage.

The original program of the same name by Holger Froening was found on the web here:

http://groups.google.com/group/novell.support.suse.linux.professional/msg/82218ba68f58c302?dmode=source&hl=en

V1.0.1, 10/16/06, David Mathog.  Various changes from the original;
   1.  Eliminated all user interaction and use of errno
   2.  Emit a status value to stdout: PASSED, FAILED_OPEN, FAILED_LOCK, etc.
   3.  If one or more arguments are present it shows PASS_whatever for each step.
   4.  Testfile name changed to <username>_testlock_file.
   5.  Extensively reformatted
*/


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

/* show FAILED_message if bad is TRUE, PASSED_message if bad is FALSE */
void test_and_show(int bad, int verbose, char *message){
  if(bad){
    (void) fprintf(stdout,"FAILED_%s\n",message);
    exit (EXIT_FAILURE);
  }
  else if(verbose){  
    (void) fprintf(stdout,"PASSED_%s\n",message);
  }
}

int main(int argc, char *argv[]){
  int handle;
  int result;
  int verbose;
  struct flock lock;
  char *testname;

  if(argc>=2){   verbose=1; }
  else {         verbose=0; }
  

  testname=malloc(sizeof(char) * 128);
  test_and_show(testname == NULL,verbose,"ALLOCATE");

  result=sprintf(testname,"%s_testlock_file",cuserid(NULL));
  test_and_show(result == 0,verbose,"MAKENAME");

  handle = open (testname, O_RDWR | O_CREAT, S_IWUSR | S_IRUSR);
  test_and_show(handle == -1,verbose,"OPEN");

  lock.l_type   = F_WRLCK;
  lock.l_whence = SEEK_SET;
  lock.l_start  = 0;
  lock.l_len    = 0;
  result = fcntl (handle, F_SETLK, &lock);
  test_and_show(result == -1,verbose,"LOCK");

  lock.l_type   = F_UNLCK;
  result = fcntl (handle, F_SETLK, &lock);
  test_and_show(result == -1,verbose,"UNLOCK");
  
  result = close(handle);
  test_and_show(result == -1,verbose,"CLOSE");

  result = unlink (testname);
  test_and_show(result == -1,verbose,"UNLINK");

  (void) fprintf(stdout,"PASSED\n");
  exit (EXIT_SUCCESS);
}
