home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume16 / deliver / part02 / lock.c < prev   
C/C++ Source or Header  |  1988-11-14  |  7KB  |  360 lines

  1. /* $Header: lock.c,v 1.2 88/08/30 16:13:14 network Exp $
  2.  *
  3.  * Mailbox locking.
  4.  * Local hacks for mailbox access should be grafted here.
  5.  *
  6.  * $Log:    lock.c,v $
  7.  * Revision 1.2  88/08/30  16:13:14  network
  8.  * Portability fixes from Ronald Karr <tron@uts.amdahl.com>.
  9.  * 
  10.  * Revision 1.1  88/06/06  09:38:48  chip
  11.  * Initial revision
  12.  * 
  13.  */
  14.  
  15. #include "deliver.h"
  16.  
  17. /*
  18.  * Validate the locking configuration.
  19.  */
  20.  
  21. #if (defined(ML_FCNTL) + defined(ML_LOCKF) + defined(ML_LOCKING)) > 1
  22.   lose! "Only one of ML_FCNTL, ML_LOCKF and ML_LOCKING may be defined.";
  23. #endif
  24.  
  25. /*
  26.  * Support for the lockf() system call.
  27.  */
  28.  
  29. #ifdef ML_LOCKF
  30. #include <unistd.h>
  31. #define SIMPLE_LOCK "lockf"
  32. #define LOCKFD(fd, size)    lockf(fd, F_LOCK, size)
  33. #define UNLOCKFD(fd, size)  lockf(fd, F_ULOCK, size)
  34. #endif /* ML_LOCKF */
  35.  
  36. /*
  37.  * Setup for the locking() system call.
  38.  */
  39.  
  40. #ifdef ML_LOCKING
  41. #include <sys/types.h>
  42. #include <sys/locking.h>
  43. #define SIMPLE_LOCK "locking"
  44. #define LOCKFD(fd, size)    locking(fd, LK_LOCK, size)
  45. #define UNLOCKFD(fd, size)  locking(fd, LK_UNLOCK, size)
  46. #endif
  47.  
  48. /*
  49.  * Local functions.
  50.  */
  51.  
  52. #ifdef ML_DOTLOCK
  53. static  char    *dotlock_name();
  54. #endif
  55. #ifdef ML_DOTMLK
  56. static  char    *dotmlk_name();
  57. #endif
  58.  
  59. /*----------------------------------------------------------------------
  60.  * Lock a mailbox by name.
  61.  *
  62.  * This code looks quite hairy with all the ifdefs.  In fact, the only
  63.  * somewhat strange thing here is that neither, either, or both of
  64.  * ML_DOTLOCK and ML_DOTMLK may be defined, and we have to allow for it.
  65.  */
  66.  
  67. int
  68. lock_name(name)
  69. char    *name;
  70. {
  71. #ifdef ML_DOTLOCK
  72.     char    *dotlock;
  73. #endif
  74. #ifdef ML_DOTMLK
  75.     char    *dotmlk;
  76. #endif
  77.  
  78. #ifdef ML_DOTLOCK
  79.     if ((dotlock = dotlock_name(name)) == NULL
  80.      || create_lockfile(dotlock) < 0)
  81.         return -1;
  82. #endif /* ML_DOTLOCK */
  83.  
  84. #ifdef ML_DOTMLK
  85.     if ((dotmlk = dotmlk_name(name)) == NULL
  86.      || create_lockfile(dotmlk) < 0)
  87.     {
  88. #ifdef ML_DOTLOCK
  89.         (void) remove_lockfile(dotlock); /* don't leave me hanging */
  90. #endif
  91.         return -1;
  92.     }
  93. #endif /* ML_DOTMLK */
  94.  
  95.     return 0;
  96. }
  97.  
  98. /*----------------------------------------------------------------------
  99.  * Unlock a mailbox by name.
  100.  */
  101.  
  102. int
  103. unlock_name(name)
  104. char    *name;
  105. {
  106.     int     ret = 0;
  107.  
  108. #ifdef ML_DOTLOCK
  109.     char    *dotlock;
  110. #endif
  111. #ifdef ML_DOTMLK
  112.     char    *dotmlk;
  113. #endif
  114.  
  115. #ifdef ML_DOTLOCK
  116.     if ((dotlock = dotlock_name(name)) == NULL
  117.      || remove_lockfile(dotlock) < 0)
  118.         ret = -1;
  119. #endif /* ML_DOTLOCK */
  120.  
  121. #ifdef ML_DOTMLK
  122.     if ((dotmlk = dotmlk_name(name)) == NULL
  123.      || remove_lockfile(dotmlk) < 0)
  124.         ret = -1;
  125. #endif /* ML_DOTMLK */
  126.  
  127.     return ret;
  128. }
  129.  
  130. /*----------------------------------------------------------------------
  131.  * Lock a file descriptor.
  132.  */
  133.  
  134. int
  135. lock_fd(fd)
  136. int     fd;
  137. {
  138. #ifdef ML_FCNTL
  139.     struct flock fl;
  140.  
  141.     fl.l_type = F_WRLCK;
  142.     fl.l_whence = 0;
  143.     fl.l_start = 0L;
  144.     fl.l_len = 0L;
  145.  
  146.     if (fcntl(fd, F_SETLKW, &fl) == -1)
  147.     {
  148.         syserr("can't lock with fcntl()");
  149.         return -1;
  150.     }
  151.  
  152.     if (verbose)
  153.         message("locked mailbox with fcntl()\n");
  154. #endif /* ML_FCNTL */
  155.  
  156. #ifdef SIMPLE_LOCK
  157.     long    pos;
  158.  
  159.     if ((pos = lseek(fd, 0L, 0)) == -1)
  160.     {
  161.         syserr("can't seek in mailbox");
  162.         return -1;
  163.     }
  164.     if (LOCKFD(fd, 0L) == -1)
  165.     {
  166.         syserr("can't lock with %s()", SIMPLE_LOCK);
  167.         return -1;
  168.     }
  169.     if (lseek(fd, pos, 0) == -1)
  170.     {
  171.         syserr("can't seek in mailbox");
  172.         return -1;
  173.     }
  174.  
  175.     if (verbose)
  176.         message("locked mailbox with %s()\n", SIMPLE_LOCK);
  177. #endif /* SIMPLE_LOCK */
  178.  
  179.     /* Default: success */
  180.     return 0;
  181. }
  182.  
  183. /*----------------------------------------------------------------------
  184.  * Unlock a file descriptor.
  185.  */
  186.  
  187. int
  188. unlock_fd(fd)
  189. int     fd;
  190. {
  191. #ifdef ML_FCNTL
  192.     struct flock fl;
  193.  
  194.     fl.l_type = F_UNLCK;
  195.     fl.l_whence = 0;
  196.     fl.l_start = 0L;
  197.     fl.l_len = 0L;
  198.  
  199.     if (fcntl(fd, F_SETLKW, &fl) == -1)
  200.     {
  201.         syserr("can't unlock with fcntl()");
  202.         return -1;
  203.     }
  204.  
  205.     if (verbose)
  206.         message("unlocked mailbox with fcntl()\n");
  207. #endif /* ML_FCNTL */
  208.  
  209. #ifdef SIMPLE_LOCK
  210.     long    pos;
  211.  
  212.     if ((pos = lseek(fd, 0L, 0)) == -1)
  213.     {
  214.         syserr("can't seek in mailbox");
  215.         return -1;
  216.     }
  217.     if (LOCKFD(fd, 0L) == -1)
  218.     {
  219.         syserr("can't unlock with %s()", SIMPLE_LOCK);
  220.         return -1;
  221.     }
  222.     if (lseek(fd, pos, 0) == -1)
  223.     {
  224.         syserr("can't seek in mailbox");
  225.         return -1;
  226.     }
  227.  
  228.     if (verbose)
  229.         message("unlocked mailbox with %s()\n", SIMPLE_LOCK);
  230. #endif /* SIMPLE_LOCK */
  231.  
  232.     /* Default: success */
  233.     return 0;
  234. }
  235.  
  236. /*----------------------------------------------------------------------
  237.  * Return the name of the appropriate ".lock" file for a mailbox.
  238.  */
  239.  
  240. #ifdef ML_DOTLOCK
  241.  
  242. static char *
  243. dotlock_name(name)
  244. char    *name;
  245. {
  246.     static char *lname = NULL;
  247.     static int lsize = 0;
  248.     char    *p;
  249.     int     n, i;
  250.  
  251.     n = strlen(name);
  252.     if (lsize < n + 8)
  253.     {
  254.         if (lname)
  255.             free(lname);
  256.         lsize = n + 32;
  257.         lname = zalloc(lsize);
  258.     }
  259.  
  260.     (void) strcpy(lname, name);
  261.  
  262.     /*
  263.      * We want as much of `basename.lock' as will fit in a string
  264.      * MAX_NAMESIZE long.
  265.      */
  266.     for (i = 0, p = basename(lname); (i < MAX_NAMESIZE - 5) && (*p); ++i)
  267.         ++p;
  268.     (void) strcpy(p, ".lock");
  269.  
  270.     return lname;
  271. }
  272.  
  273. #endif /* ML_DOTLOCK */
  274.  
  275. /*----------------------------------------------------------------------
  276.  * Return the name of the appropriate ".mlk" file for a mailbox.
  277.  */
  278.  
  279. #ifdef ML_DOTMLK
  280.  
  281. static char *
  282. dotmlk_name(name)
  283. char    *name;
  284. {
  285.     static char lname[MAX_NAMESIZE + 16];
  286.     char    *p, *d;
  287.     int     i;
  288.  
  289.     /*
  290.      * To explain the below:  If we ass_u_me that MAX_NAMESIZE is 14,
  291.      * then this code is like `printf(lname, "/tmp/%.10s.mlk", ...)'.
  292.      * In other words, we want as much of `basename.mlk' as will fit
  293.      * in a string MAX_NAMESIZE long.
  294.      */
  295.     d = lname;
  296.     for (p = "/tmp/"; *p; )
  297.         *d++ = *p++;
  298.     for (i = 0, p = basename(name); (i < MAX_NAMESIZE - 4) && (*p); ++i)
  299.         *d++ = *p++;
  300.     (void) strcpy(d, ".mlk");
  301.  
  302.     return lname;
  303. }
  304.  
  305. #endif /* ML_DOTMLK */
  306.  
  307. /*----------------------------------------------------------------------
  308.  * Create a lockfile.
  309.  */
  310.  
  311. int
  312. create_lockfile(name)
  313. char    *name;
  314. {
  315.     int     tries, fd;
  316.  
  317.     for (tries = 0; tries < 10; ++tries)
  318.     {
  319.         if (tries)
  320.             snooze(3);
  321.  
  322.         if ((fd = open(name, O_RDWR|O_CREAT|O_EXCL, 0)) >= 0)
  323.         {
  324.             (void) close(fd);
  325.             if (verbose)
  326.                 message("created lockfile %s\n", name);
  327.             return 0;
  328.         }
  329.  
  330.         if (verbose && (tries == 0))
  331.         {
  332.             message("Waiting to create %s (try #%d)\n",
  333.                 name, tries + 1);
  334.         }
  335.     }
  336.  
  337.     syserr("can't create lockfile %s", name);
  338.     return -1;
  339. }
  340.  
  341. /*----------------------------------------------------------------------
  342.  * Remove a lockfile.
  343.  */
  344.  
  345. int
  346. remove_lockfile(name)
  347. char    *name;
  348. {
  349.     if (unlink(name) == -1)
  350.     {
  351.         syserr("can't remove lockfile %s", name);
  352.         return -1;
  353.     }
  354.  
  355.     if (verbose)
  356.         message("removed lockfile %s\n", name);
  357.  
  358.     return 0;
  359. }
  360.