home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Professional / OS2PRO194.ISO / os2 / prgramer / rcs / sources / set_lock.c < prev    next >
C/C++ Source or Header  |  1992-02-23  |  6KB  |  233 lines

  1. #ifndef lint
  2. static char rcsid[] = "$Id: set_lock.c,v 1.8 89/11/19 23:20:26 berliner Exp $";
  3. #endif 
  4.  
  5. /*
  6.  *    Copyright (c) 1989, Brian Berliner
  7.  *
  8.  *    You may distribute under the terms of the GNU General Public License
  9.  *    as specified in the README file that comes with the CVS 1.0 kit.
  10.  *
  11.  * Set Lock
  12.  *
  13.  * Lock file support for CVS.  Currently, only "update" and "commit"
  14.  * (and by extension, "checkout") adhere to this locking protocol.
  15.  * Maybe some day, others will too.
  16.  */
  17.  
  18. #include <sys/types.h>
  19. #include <sys/stat.h>
  20. #include <signal.h>
  21. #include "dir.h"
  22. #include "cvs.h"
  23.  
  24. static char lckdir[MAXPATHLEN], lckrfl[MAXPATHLEN], lckwfl[MAXPATHLEN];
  25.  
  26. /*
  27.  * Remove the lock files (without complaining if they are not there),
  28.  * and do a quick check to see if the Entries file is missing, but
  29.  * the Entries.Backup file is there.
  30.  */
  31. void
  32. Lock_Cleanup(sig)
  33.     int sig;
  34. {
  35.     struct stat sb;
  36.  
  37.     if (lckrfl[0] != '\0')
  38.     (void) unlink(lckrfl);
  39.     if (lckwfl[0] != '\0')
  40.     (void) unlink(lckwfl);
  41.     if (lckdir[0] != '\0') {
  42.     /*
  43.      * Only remove the lock directory if it is ours, note that this does
  44.      * lead to the limitation that one user ID should not be committing
  45.      * files into the same Repository directory at the same time.
  46.      * Oh well.
  47.      */
  48.     if (stat(lckdir, &sb) != -1 && sb.st_uid == geteuid())
  49.         (void) rmdir(lckdir);
  50.     }
  51.     if (!isfile(CVSADM_ENT) && isfile(CVSADM_ENTBAK)) {
  52.     warn(0, "warning: restoring %s to %s", CVSADM_ENTBAK, CVSADM_ENT);
  53.     rename_file(CVSADM_ENTBAK, CVSADM_ENT);
  54.     }
  55.     if (sig != 0)
  56.     exit(1);
  57. }
  58.  
  59. /*
  60.  * Create a lock file for readers (like "update" is)
  61.  */
  62. Reader_Lock()
  63. {
  64.     extern char *ctime();
  65.     extern time_t time();
  66.     char *cp;
  67.     time_t now;
  68.     FILE *fp;
  69.  
  70.     (void) sprintf(lckdir, "%s%c%s", Repository, DIRSEP, CVSLCK);
  71.     (void) sprintf(lckrfl, "%s%c%s%04x", Repository, DIRSEP, CVSTFL, getpid());
  72.     (void) signal(SIGINT, Lock_Cleanup);
  73.     (void) signal(SIGTERM, Lock_Cleanup);
  74.     (void) signal(SIGBREAK, Lock_Cleanup);
  75.     if ((fp = fopen(lckrfl, "w+")) != NULL) {
  76.     (void) fclose(fp);
  77.     (void) unlink(lckrfl);
  78.     set_lock(lckdir);
  79.     (void) sprintf(lckrfl, "%s%c%s%04x", Repository, DIRSEP, CVSRFL, getpid());
  80.     if ((fp = fopen(lckrfl, "w+")) == NULL)
  81.         warn(1, "cannot create read lock file %s", lckrfl);
  82.     else
  83.         (void) fclose(fp);
  84.     if (rmdir(lckdir) < 0)
  85.         warn(1, "failed to remove lock dir %s", lckdir);
  86.     } else {
  87.     while (isfile(lckdir)) {
  88.         struct stat sb;
  89.  
  90.         (void) time(&now);
  91.         /*
  92.          * If the create time of the directory is more than CVSLCKAGE
  93.          * seconds ago, try to clean-up the lock directory, and if
  94.          * successful, we are (somewhat) free and clear.
  95.          */
  96.         if (stat(lckdir, &sb) != -1 && now >= (sb.st_ctime + CVSLCKAGE)) {
  97.         if (rmdir(lckdir) != -1)
  98.             break;
  99.         }
  100.         cp = ctime(&now);
  101.         warn(0, "%s: waiting for the lock directory to go away", cp);
  102.         sleep(CVSLCKSLEEP);
  103.     }
  104.     }
  105. }
  106.  
  107. /*
  108.  * Create a lock file for writers (like "commit" is)
  109.  */
  110. Writer_Lock()
  111. {
  112.     FILE *fp;
  113.  
  114.     (void) sprintf(lckdir, "%s%c%s", Repository, DIRSEP, CVSLCK);
  115.     (void) sprintf(lckrfl, "%s%c%s%04x", Repository, DIRSEP, CVSTFL, getpid());
  116.     (void) sprintf(lckwfl, "%s%c%s%04x", Repository, DIRSEP, CVSWFL, getpid());
  117.     (void) signal(SIGINT, Lock_Cleanup);
  118.     (void) signal(SIGTERM, Lock_Cleanup);
  119.     (void) signal(SIGBREAK, Lock_Cleanup);
  120.     if ((fp = fopen(lckrfl, "w+")) == NULL)
  121.     error(1, "you have no write permission in %s", Repository);
  122.     (void) fclose(fp);
  123.     (void) unlink(lckrfl);
  124.     (void) sprintf(lckrfl, "%s%c%s%04x", Repository, DIRSEP, CVSRFL, getpid());
  125.     set_lock(lckdir);
  126.     if ((fp = fopen(lckwfl, "w+")) == NULL)
  127.     warn(1, "cannot create write lock file %s", lckwfl);
  128.     else
  129.     (void) fclose(fp);
  130.     while (readers_exist()) {
  131.     extern char *ctime();
  132.     extern time_t time();
  133.     char *cp;
  134.     time_t now;
  135.  
  136.     (void) time(&now);
  137.     cp = ctime(&now);
  138.     cp[24] = ' ';
  139.     warn(0, "%s: waiting for readers to go away", cp);
  140.     sleep(CVSLCKSLEEP);
  141.     }
  142. }
  143.  
  144. /*
  145.  * readers_exist() returns 0 if there are no reader lock files
  146.  * remaining in the repository; else 1 is returned, to indicate that the
  147.  * caller should sleep a while and try again.
  148.  */
  149. static
  150. readers_exist()
  151. {
  152.     char line[MAXLINELEN];
  153.     DIR *dirp;
  154.     struct dirent *dp;
  155.     char *cp;
  156.     int ret = 0;
  157.  
  158. again:
  159.     if ((dirp = opendir(Repository)) == NULL)
  160.     error(0, "cannot open directory %s", Repository);
  161.     (void) sprintf(line, "^%s.*", CVSRFL);
  162.     if ((cp = re_comp(line)) != NULL)
  163.     error(0, "%s", cp);
  164.     while ((dp = readdir(dirp)) != NULL) {
  165.     if (re_exec(dp->d_name)) {
  166.         struct stat sb;
  167.         long now;
  168.  
  169.         (void) time(&now);
  170.         /*
  171.          * If the create time of the file is more than CVSLCKAGE
  172.          * seconds ago, try to clean-up the lock file, and if
  173.          * successful, re-open the directory and try again.
  174.          */
  175.         (void) sprintf(line, "%s%c%s", Repository, DIRSEP, dp->d_name);
  176.         if (stat(line, &sb) != -1 && now >= (sb.st_ctime + CVSLCKAGE)) {
  177.         if (unlink(line) != -1) {
  178.             (void) closedir(dirp);
  179.             goto again;
  180.         }
  181.         }
  182.         ret = 1;
  183.         break;
  184.     }
  185.     }
  186.     (void) closedir(dirp);
  187.     return (ret);
  188. }
  189.  
  190. /*
  191.  * Persistently tries to make the directory "lckdir",, which serves as a lock.
  192.  * If the create time on the directory is greater than CVSLCKAGE seconds
  193.  * old, just try to remove the directory.
  194.  */
  195. static
  196. set_lock(lckdir)
  197.     char *lckdir;
  198. {
  199.     extern char *ctime();
  200.     extern time_t time();
  201.     struct stat sb;
  202.     char *cp;
  203.     time_t now;
  204.  
  205.     /*
  206.      * Note that it is up to the callers of Set_Lock() to
  207.      * arrange for signal handlers that do the appropriate things,
  208.      * like remove the lock directory before they exit.
  209.      */
  210.     for (;;) {
  211.     if (mkdir(lckdir, 0777) < 0) {
  212.         (void) time(&now);
  213.         /*
  214.          * If the create time of the directory is more than CVSLCKAGE
  215.          * seconds ago, try to clean-up the lock directory, and if
  216.          * successful, just quietly retry to make it.
  217.          */
  218.         if (stat(lckdir, &sb) != -1 && now >= (sb.st_ctime + CVSLCKAGE)) {
  219.         if (rmdir(lckdir) != -1)
  220.             continue;
  221.         }
  222.         cp = ctime(&now);
  223.         cp[24] = ' ';
  224.         warn(0, "%s: waiting for the lock to go away", cp);
  225.         sleep(CVSLCKSLEEP);
  226.     } else {
  227.         break;
  228.     }
  229.     }
  230. }
  231.  
  232.  
  233.