home *** CD-ROM | disk | FTP | other *** search
/ PC-Online 1996 May / PCOnline_05_1996.bin / linux / source / n / tcpip / nntp-1.5 / nntp-1 / nntp.1.5.11t / xmit / shlock.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-10-17  |  7.0 KB  |  317 lines

  1. #ifndef lint
  2. static char * rcsid = "@(#)$Header: shlock.c,v 1.3 91/01/12 01:04:24 sob Exp $";
  3. #endif
  4. /*
  5. ** Program to produce reliable locks for shell scripts.
  6. ** Algorithmn suggested by Peter Honeyman, January 1984,
  7. ** in connection with HoneyDanBer UUCP.
  8. **
  9. ** I tried extending this to handle shared locks in November 1987,
  10. ** and ran into to some fundamental problems:
  11. **
  12. **    Neither 4.3 BSD nor System V have an open(2) with locking,
  13. **    so that you can open a file and have it locked as soon as
  14. **    it's real; you have to make two system calls, and there's
  15. **    a race...
  16. **
  17. **    When removing dead process id's from a list in a file,
  18. **    you need to truncate the file (you don't want to create a
  19. **    new one; see above); unfortunately for the portability of
  20. **    this program, only 4.3 BSD has ftruncate(2).
  21. **
  22. ** Erik E. Fair <fair@ucbarpa.berkeley.edu>, November 8, 1987
  23. **
  24. ** Extensions for UUCP style locks (i.e. pid is an int in the file,
  25. ** rather than an ASCII string). Also fix long standing bug with
  26. ** full file systems and temporary files.
  27. **
  28. ** Erik E. Fair <fair@apple.com>, November 12, 1989
  29. */
  30.  
  31. #include <stdio.h>
  32. #include <sys/types.h>
  33. #include <fcntl.h>            /* Needed on hpux */
  34. #include <sys/file.h>
  35. #include <errno.h>
  36. #ifdef NNTPSRC
  37. #include "../common/conf.h"
  38. #endif
  39.  
  40. #define    LOCK_SET    0
  41. #define    LOCK_FAIL    1
  42.  
  43. #define    FAIL        (-1)
  44.  
  45. #define    TRUE    1
  46. #define    FALSE    0
  47.  
  48. #ifdef USG
  49. #define    index    strchr
  50. #define    rindex    strrchr
  51. #endif
  52.  
  53. int    Debug = FALSE;
  54. char    *Pname;
  55. char    *USAGE = "%s: USAGE: shlock -f file -p pid [-d][-u]\n";
  56. char    *E_unlk = "%s: unlink(%s): %s\n";
  57. char    *E_open = "%s: open(%s): %s\n";
  58.  
  59. char    *errmsg();
  60. char    *xtmpfile();
  61.  
  62. #define    dprintf    if (Debug) printf
  63.  
  64. extern    int    errno;
  65. extern    char    *rindex();
  66. extern    char    *strcpy();
  67. extern    char    *strcat();
  68.  
  69. main(ac, av)
  70. int    ac;
  71. char    *av[];
  72. {
  73.     register int    x;
  74.     char    *file;
  75.     int    pid;
  76.     int    uucpstyle = FALSE;    /* indicating UUCP style locks */
  77.  
  78.     Pname = ((Pname = rindex(av[0], '/')) ? Pname + 1 : av[0]);
  79.  
  80.     for(x = 1; x < ac; x++) {
  81.         if (av[x][0] == '-') {
  82.             switch(av[x][1]) {
  83.             case 'u':
  84.                 uucpstyle = TRUE;
  85.                 break;
  86.             case 'd':
  87.                 Debug = TRUE;
  88.                 break;
  89.             case 'p':
  90.                 if (strlen(av[x]) > 2) {
  91.                     pid = atoi(&av[x][2]);
  92.                 } else {
  93.                     pid = atoi(av[++x]);
  94.                 }
  95.                 break;
  96.             case 'f':
  97.                 if (strlen(av[x]) > 2) {
  98.                     file = &av[x][2];
  99.                 } else {
  100.                     file = av[++x];
  101.                 }
  102.                 break;
  103.             default:
  104.                 fprintf(stderr, USAGE, Pname);
  105.                 exit(LOCK_FAIL);
  106.             }
  107.         }
  108.     }
  109.     if (pid == 0 || file == (char *)NULL) {
  110.         fprintf(stderr, USAGE, Pname);
  111.         exit(LOCK_FAIL);
  112.     }
  113.  
  114.     exit(mklock(file, pid, uucpstyle) ? LOCK_SET : LOCK_FAIL);
  115. }
  116.  
  117. char *
  118. errmsg(n)
  119. register int    n;
  120. {
  121.     extern    int    sys_nerr;
  122.     extern     char    *sys_errlist[];
  123.  
  124.     return((n >= 0 && n < sys_nerr) ? sys_errlist[n] : "unknown error");
  125. }
  126.  
  127. mklock(file, pid, uucpstyle)
  128. char    *file;
  129. int    pid;
  130. {
  131.     register char    *tmp;
  132.     register int    retcode = FALSE;
  133.  
  134.     dprintf("%s: trying lock <%s> for process %d\n", Pname, file, pid);
  135.     if ((tmp = xtmpfile(file, pid, uucpstyle)) == (char *)NULL)
  136.         return(FALSE);
  137.  
  138. linkloop:
  139.     if (link(tmp, file) < 0) {
  140.         switch(errno) {
  141.         case EEXIST:
  142.             dprintf("%s: lock <%s> already exists\n", Pname, file);
  143.             if (cklock(file, uucpstyle)) {
  144.                 dprintf("%s: extant lock is valid\n", Pname);
  145.                 break;
  146.             } else {
  147.                 dprintf("%s: lock is invalid, removing\n",
  148.                     Pname);
  149.                 if (unlink(file) < 0) {
  150.                     fprintf(stderr, E_unlk,
  151.                         Pname, file, errmsg(errno));
  152.                     break;
  153.                 }
  154.             }
  155.             /*
  156.             ** I hereby profane the god of structured programming,
  157.             ** Edsgar Dijkstra
  158.             */
  159.             goto linkloop;
  160.         default:
  161.             fprintf(stderr, "%s: link(%s, %s): %s\n",
  162.                 Pname, tmp, file, errmsg(errno));
  163.             break;
  164.         }
  165.     } else {
  166.         dprintf("%s: got lock <%s>\n", Pname, file);
  167.         retcode = TRUE;
  168.     }
  169.     if (unlink(tmp) < 0) {
  170.         fprintf(stderr, E_unlk, Pname, tmp, errmsg(errno));
  171.     }
  172.     return(retcode);
  173. }
  174.  
  175. /*
  176. ** Does the PID exist?
  177. ** Send null signal to find out.
  178. */
  179. p_exists(pid)
  180. int    pid;
  181. {
  182.     dprintf("%s: process %d is ", Pname, pid);
  183.     if (pid <= 0) {
  184.         dprintf("invalid\n");
  185.         return(FALSE);
  186.     }
  187.     if (kill(pid, 0) < 0) {
  188.         switch(errno) {
  189.         case ESRCH:
  190.             dprintf("dead\n");
  191.             return(FALSE);    /* pid does not exist */
  192.         case EPERM:
  193.             dprintf("alive\n");
  194.             return(TRUE);    /* pid exists */
  195.         default:
  196.             dprintf("state unknown: %s\n", errmsg(errno));
  197.             return(TRUE);    /* be conservative */
  198.         }
  199.     }
  200.     dprintf("alive\n");
  201.     return(TRUE);    /* pid exists */
  202. }
  203.  
  204. /*
  205. ** Check the validity of an existing lock file.
  206. **
  207. **    Read the PID out of the lock
  208. **    Send a null signal to determine whether that PID still exists
  209. **    Existence (or not) determines the validity of the lock.
  210. **
  211. **    Two bigs wins to this algorithmn:
  212. **
  213. **    o    Locks do not survive crashes of either the system or the
  214. **            application by any appreciable period of time.
  215. **
  216. **    o    No clean up to do if the system or application crashes.
  217. **
  218. */
  219.  
  220. cklock(file, uucpstyle)
  221. char    *file;
  222. int    uucpstyle;
  223. {
  224.     register int    fd = open(file, O_RDONLY);
  225.     register int    len;
  226.     int    pid;
  227.     char    buf[BUFSIZ];
  228.  
  229.     dprintf("%s: checking extant lock <%s>\n", Pname, file);
  230.     if (fd < 0) {
  231.         fprintf(stderr, E_open, Pname, file, errmsg(errno));
  232.         return(TRUE);    /* might or might not; conservatism */
  233.     }
  234.  
  235.     if (uucpstyle ?
  236.         ((len = read(fd, &pid, sizeof(pid))) != sizeof(pid)) :
  237.         ((len = read(fd, buf, sizeof(buf))) <= 0))
  238.     {
  239.         close(fd);
  240.         dprintf("%s: lock file format error\n", Pname);
  241.         return(FALSE);
  242.     }
  243.     close(fd);
  244.     buf[len + 1] = '\0';
  245.     return(p_exists(uucpstyle ? pid : atoi(buf)));
  246. }
  247.  
  248. /*
  249. ** Create a temporary file, all ready to lock with.
  250. ** The file arg is so we get the filename right, if he
  251. ** gave us a full path, instead of using the current directory
  252. ** which might not be in the same filesystem.
  253. */
  254. char *
  255. xtmpfile(file, pid, uucpstyle)
  256. char    *file;
  257. int    pid, uucpstyle;
  258. {
  259.     register int    fd;
  260.     register int    len;
  261.     char    *cp, buf[BUFSIZ];
  262.     static char    tempname[BUFSIZ];
  263.  
  264.     sprintf(buf, "shlock%d", getpid());
  265.     if ((cp = rindex(strcpy(tempname, file), '/')) != (char *)NULL) {
  266.         *++cp = '\0';
  267.         (void) strcat(tempname, buf);
  268.     } else
  269.         (void) strcpy(tempname, buf);
  270.     dprintf("%s: temporary filename: %s\n", Pname, tempname);
  271.  
  272.     sprintf(buf, "%d\n", pid);
  273.     len = strlen(buf);
  274. openloop:
  275.     if ((fd = open(tempname, O_RDWR|O_CREAT|O_EXCL, 0644)) < 0) {
  276.         switch(errno) {
  277.         case EEXIST:
  278.             dprintf("%s: file %s exists already.\n",
  279.                 Pname, tempname);
  280.             if (unlink(tempname) < 0) {
  281.                 fprintf(stderr, E_unlk,
  282.                     Pname, tempname, errmsg(errno));
  283.                 return((char *)NULL);
  284.             }
  285.             /*
  286.             ** Further profanity
  287.             */
  288.             goto openloop;
  289.         default:
  290.             fprintf(stderr, E_open,
  291.                 Pname, tempname, errmsg(errno));
  292.             return((char *)NULL);
  293.         }
  294.     }
  295.  
  296.     /*
  297.     ** Write the PID into the temporary file before attempting to link
  298.     ** to the actual lock file. That way we have a valid lock the instant
  299.     ** the link succeeds.
  300.     */
  301.     if (uucpstyle ?
  302.         (write(fd, &pid, sizeof(pid)) != sizeof(pid)) :
  303.         (write(fd, buf, len) < 0))
  304.     {
  305.         fprintf(stderr, "%s: write(%s,%d): %s\n",
  306.             Pname, tempname, pid, errmsg(errno));
  307.         (void) close(fd);
  308.         if (unlink(tempname) < 0) {
  309.             fprintf(stderr, E_unlk,
  310.                 Pname, tempname, errmsg(errno));
  311.         }
  312.         return((char *)NULL);
  313.     }
  314.     (void) close(fd);
  315.     return(tempname);
  316. }
  317.