]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - contrib/cvs/src/lock.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / contrib / cvs / src / lock.c
1 /*
2  * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
3  *
4  * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
5  *                                  and others.
6  *
7  * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk
8  * Portions Copyright (C) 1989-1992, Brian Berliner
9  * 
10  * You may distribute under the terms of the GNU General Public License as
11  * specified in the README file that comes with the CVS source distribution.
12  * 
13  * Set Lock
14  * 
15  * Lock file support for CVS.
16  *
17  * $FreeBSD$
18  */
19
20 /* The node Concurrency in doc/cvs.texinfo has a brief introduction to
21    how CVS locks function, and some of the user-visible consequences of
22    their existence.  Here is a summary of why they exist (and therefore,
23    the consequences of hacking CVS to read a repository without creating
24    locks):
25
26    There are two uses.  One is the ability to prevent there from being
27    two writers at the same time.  This is necessary for any number of
28    reasons (fileattr code, probably others).  Commit needs to lock the
29    whole tree so that nothing happens between the up-to-date check and
30    the actual checkin.
31
32    The second use is the ability to ensure that there is not a writer
33    and a reader at the same time (several readers are allowed).  Reasons
34    for this are:
35
36    * Readlocks ensure that once CVS has found a collection of rcs
37    files using Find_Names, the files will still exist when it reads
38    them (they may have moved in or out of the attic).
39
40    * Readlocks provide some modicum of consistency, although this is
41    kind of limited--see the node Concurrency in cvs.texinfo.
42
43    * Readlocks ensure that the RCS file does not change between
44    RCS_parse and RCS_reparsercsfile time.  This one strikes me as
45    important, although I haven't thought up what bad scenarios might
46    be.
47
48    * Readlocks ensure that we won't find the file in the state in
49    which it is in between the calls to add_rcs_file and RCS_checkin in
50    commit.c (when a file is being added).  This state is a state in
51    which the RCS file parsing routines in rcs.c cannot parse the file.
52
53    * Readlocks ensure that a reader won't try to look at a
54    half-written fileattr file (fileattr is not updated atomically).
55
56    (see also the description of anonymous read-only access in
57    "Password authentication security" node in doc/cvs.texinfo).
58
59    While I'm here, I'll try to summarize a few random suggestions
60    which periodically get made about how locks might be different:
61
62    1.  Check for EROFS.  Maybe useful, although in the presence of NFS
63    EROFS does *not* mean that the file system is unchanging.
64
65    2.  Provide an option to disable locks for operations which only
66    read (see above for some of the consequences).
67
68    3.  Have a server internally do the locking.  Probably a good
69    long-term solution, and many people have been working hard on code
70    changes which would eventually make it possible to have a server
71    which can handle various connections in one process, but there is
72    much, much work still to be done before this is feasible.  */
73
74 #include "cvs.h"
75 #include <assert.h>
76
77 #ifdef HAVE_NANOSLEEP
78 # include "xtime.h"
79 #else /* HAVE_NANOSLEEP */
80 # if !defined HAVE_USLEEP && defined HAVE_SELECT
81     /* use select as a workaround */
82 #   include "xselect.h"
83 # endif /* !defined HAVE_USLEEP && defined HAVE_SELECT */
84 #endif /* !HAVE_NANOSLEEP */
85
86
87 struct lock {
88     /* This is the directory in which we may have a lock named by the
89        readlock variable, a lock named by the writelock variable, and/or
90        a lock named CVSLCK.  The storage is not allocated along with the
91        struct lock; it is allocated by the Reader_Lock caller or in the
92        case of writelocks, it is just a pointer to the storage allocated
93        for the ->key field.  */
94     char *repository;
95
96     /* The name of the master lock dir.  Usually CVSLCK.  */
97     const char *lockdirname;
98
99     /* The full path to the lock dir, if we are currently holding it.
100      *
101      * This will be LOCKDIRNAME catted onto REPOSITORY.  We waste a little
102      * space by storing it, but save a later malloc/free.
103      */
104     char *lockdir;
105
106     /* Note there is no way of knowing whether the readlock and writelock
107        exist.  The code which sets the locks doesn't use SIG_beginCrSect
108        to set a flag like we do for CVSLCK.  */
109 };
110
111 static void remove_locks PROTO((void));
112 static int readers_exist PROTO((char *repository));
113 static int set_lock PROTO ((struct lock *lock, int will_wait));
114 static void clear_lock PROTO ((struct lock *lock));
115 static void set_lockers_name PROTO((struct stat *statp));
116 static int set_writelock_proc PROTO((Node * p, void *closure));
117 static int unlock_proc PROTO((Node * p, void *closure));
118 static int write_lock PROTO ((struct lock *lock));
119 static void lock_simple_remove PROTO ((struct lock *lock));
120 static void lock_wait PROTO((char *repository));
121 static void lock_obtained PROTO((char *repository));
122
123 /* Malloc'd array containing the username of the whoever has the lock.
124    Will always be non-NULL in the cases where it is needed.  */
125 static char *lockers_name;
126 /* Malloc'd array specifying name of a readlock within a directory.
127    Or NULL if none.  */
128 static char *readlock;
129 /* Malloc'd array specifying name of a writelock within a directory.
130    Or NULL if none.  */
131 static char *writelock;
132 /* Malloc'd array specifying the name of a CVSLCK file (absolute pathname).
133    Will always be non-NULL in the cases where it is used.  */
134 static List *locklist;
135
136 #define L_OK            0               /* success */
137 #define L_ERROR         1               /* error condition */
138 #define L_LOCKED        2               /* lock owned by someone else */
139
140 /* This is the (single) readlock which is set by Reader_Lock.  The
141    repository field is NULL if there is no such lock.  */
142 static struct lock global_readlock = {NULL, CVSLCK, NULL};
143
144 static struct lock global_history_lock = {NULL, CVSHISTORYLCK, NULL};
145 static struct lock global_val_tags_lock = {NULL, CVSVALTAGSLCK, NULL};
146
147 /* List of locks set by lock_tree_for_write.  This is redundant
148    with locklist, sort of.  */
149 static List *lock_tree_list;
150
151 /* If we set locks with lock_dir_for_write, then locked_dir contains
152    the malloc'd name of the repository directory which we have locked.
153    locked_list is the same thing packaged into a list and is redundant
154    with locklist the same way that lock_tree_list is.  */
155 static char *locked_dir;
156 static List *locked_list;
157
158 /* LockDir from CVSROOT/config.  */
159 char *lock_dir;
160
161 static char *lock_name PROTO ((const char *repository, const char *name));
162
163 /* Return a newly malloc'd string containing the name of the lock for the
164    repository REPOSITORY and the lock file name within that directory
165    NAME.  Also create the directories in which to put the lock file
166    if needed (if we need to, could save system call(s) by doing
167    that only if the actual operation fails.  But for now we'll keep
168    things simple).  */
169 static char *
170 lock_name (repository, name)
171     const char *repository;
172     const char *name;
173 {
174     char *retval;
175     const char *p;
176     char *q;
177     const char *short_repos;
178     mode_t save_umask = 0;
179     int saved_umask = 0;
180
181     if (lock_dir == NULL)
182     {
183         /* This is the easy case.  Because the lock files go directly
184            in the repository, no need to create directories or anything.  */
185         retval = xmalloc (strlen (repository) + strlen (name) + 10);
186         (void) sprintf (retval, "%s/%s", repository, name);
187     }
188     else
189     {
190         struct stat sb;
191         mode_t new_mode = 0;
192
193         /* The interesting part of the repository is the part relative
194            to CVSROOT.  */
195         assert (current_parsed_root != NULL);
196         assert (current_parsed_root->directory != NULL);
197         assert (strncmp (repository, current_parsed_root->directory,
198                          strlen (current_parsed_root->directory)) == 0);
199         short_repos = repository + strlen (current_parsed_root->directory) + 1;
200
201         if (strcmp (repository, current_parsed_root->directory) == 0)
202             short_repos = ".";
203         else
204             assert (short_repos[-1] == '/');
205
206         retval = xmalloc (strlen (lock_dir)
207                           + strlen (short_repos)
208                           + strlen (name)
209                           + 10);
210         strcpy (retval, lock_dir);
211         q = retval + strlen (retval);
212         *q++ = '/';
213
214         strcpy (q, short_repos);
215
216         /* In the common case, where the directory already exists, let's
217            keep it to one system call.  */
218         if (CVS_STAT (retval, &sb) < 0)
219         {
220             /* If we need to be creating more than one directory, we'll
221                get the existence_error here.  */
222             if (!existence_error (errno))
223                 error (1, errno, "cannot stat directory %s", retval);
224         }
225         else
226         {
227             if (S_ISDIR (sb.st_mode))
228                 goto created;
229             else
230                 error (1, 0, "%s is not a directory", retval);
231         }
232
233         /* Now add the directories one at a time, so we can create
234            them if needed.
235
236            The idea behind the new_mode stuff is that the directory we
237            end up creating will inherit permissions from its parent
238            directory (we re-set new_mode with each EEXIST).  CVSUMASK
239            isn't right, because typically the reason for LockDir is to
240            use a different set of permissions.  We probably want to
241            inherit group ownership also (but we don't try to deal with
242            that, some systems do it for us either always or when g+s is on).
243
244            We don't try to do anything about the permissions on the lock
245            files themselves.  The permissions don't really matter so much
246            because the locks will generally be removed by the process
247            which created them.  */
248
249         if (CVS_STAT (lock_dir, &sb) < 0)
250             error (1, errno, "cannot stat %s", lock_dir);
251         new_mode = sb.st_mode;
252         save_umask = umask (0000);
253         saved_umask = 1;
254
255         p = short_repos;
256         while (1)
257         {
258             while (!ISDIRSEP (*p) && *p != '\0')
259                 ++p;
260             if (ISDIRSEP (*p))
261             {
262                 strncpy (q, short_repos, p - short_repos);
263                 q[p - short_repos] = '\0';
264                 if (!ISDIRSEP (q[p - short_repos - 1])
265                     && CVS_MKDIR (retval, new_mode) < 0)
266                 {
267                     int saved_errno = errno;
268                     if (saved_errno != EEXIST)
269                         error (1, errno, "cannot make directory %s", retval);
270                     else
271                     {
272                         if (CVS_STAT (retval, &sb) < 0)
273                             error (1, errno, "cannot stat %s", retval);
274                         new_mode = sb.st_mode;
275                     }
276                 }
277                 ++p;
278             }
279             else
280             {
281                 strcpy (q, short_repos);
282                 if (CVS_MKDIR (retval, new_mode) < 0
283                     && errno != EEXIST)
284                     error (1, errno, "cannot make directory %s", retval);
285                 goto created;
286             }
287         }
288     created:;
289
290         strcat (retval, "/");
291         strcat (retval, name);
292
293         if (saved_umask)
294         {
295             assert (umask (save_umask) == 0000);
296             saved_umask = 0;
297         }
298     }
299     return retval;
300 }
301
302 /*
303  * Clean up all outstanding locks
304  */
305 void
306 Lock_Cleanup ()
307 {
308     /* FIXME: error handling here is kind of bogus; we sometimes will call
309        error, which in turn can call us again.  For the moment work around
310        this by refusing to reenter this function (this is a kludge).  */
311     /* FIXME-reentrancy: the workaround isn't reentrant.  */
312     static int in_lock_cleanup = 0;
313
314     if (trace)
315         (void) fprintf (stderr, "%s-> Lock_Cleanup()\n", CLIENT_SERVER_STR);
316
317     if (in_lock_cleanup)
318         return;
319     in_lock_cleanup = 1;
320
321     remove_locks ();
322
323     dellist (&lock_tree_list);
324
325     if (locked_dir != NULL)
326     {
327         dellist (&locked_list);
328         free (locked_dir);
329         locked_dir = NULL;
330         locked_list = NULL;
331     }
332
333     if (global_history_lock.repository) clear_history_lock ();
334     if (global_val_tags_lock.repository) clear_val_tags_lock ();
335
336     in_lock_cleanup = 0;
337 }
338
339 /*
340  * Remove locks without discarding the lock information
341  */
342 static void
343 remove_locks ()
344 {
345     /* clean up simple locks (if any) */
346     if (global_readlock.repository != NULL)
347     {
348         lock_simple_remove (&global_readlock);
349         global_readlock.repository = NULL;
350     }
351
352     /* clean up multiple locks (if any) */
353     if (locklist != (List *) NULL)
354     {
355         (void) walklist (locklist, unlock_proc, NULL);
356         locklist = (List *) NULL;
357     }
358 }
359
360 /*
361  * walklist proc for removing a list of locks
362  */
363 static int
364 unlock_proc (p, closure)
365     Node *p;
366     void *closure;
367 {
368     lock_simple_remove (p->data);
369     return (0);
370 }
371
372
373
374 /* Remove the lock files.  */
375 static void
376 lock_simple_remove (lock)
377     struct lock *lock;
378 {
379     char *tmp;
380
381     /* If readlock is set, the lock directory *might* have been created, but
382        since Reader_Lock doesn't use SIG_beginCrSect the way that set_lock
383        does, we don't know that.  That is why we need to check for
384        existence_error here.  */
385     if (readlock != NULL)
386     {
387         tmp = lock_name (lock->repository, readlock);
388         if (CVS_UNLINK (tmp) < 0 && ! existence_error (errno))
389             error (0, errno, "failed to remove lock %s", tmp);
390         free (tmp);
391     }
392
393     /* If writelock is set, the lock directory *might* have been created, but
394        since write_lock doesn't use SIG_beginCrSect the way that set_lock
395        does, we don't know that.  That is why we need to check for
396        existence_error here.  */
397     if (writelock != NULL)
398     {
399         tmp = lock_name (lock->repository, writelock);
400         if (CVS_UNLINK (tmp) < 0 && ! existence_error (errno))
401             error (0, errno, "failed to remove lock %s", tmp);
402         free (tmp);
403     }
404
405     clear_lock (lock);
406 }
407
408
409
410 /*
411  * Create a lock file for readers
412  */
413 int
414 Reader_Lock (xrepository)
415     char *xrepository;
416 {
417     int err = 0;
418     FILE *fp;
419     char *tmp;
420
421     if (trace)
422         (void) fprintf (stderr, "%s-> Reader_Lock(%s)\n", CLIENT_SERVER_STR,
423                         xrepository);
424
425     if (noexec || readonlyfs)
426         return 0;
427
428     /* we only do one directory at a time for read locks! */
429     if (global_readlock.repository != NULL)
430     {
431         error (0, 0, "Reader_Lock called while read locks set - Help!");
432         return 1;
433     }
434
435     if (readlock == NULL)
436     {
437         readlock = xmalloc (strlen (hostname) + sizeof (CVSRFL) + 40);
438         (void) sprintf (readlock, 
439 #ifdef HAVE_LONG_FILE_NAMES
440                         "%s.%s.%ld", CVSRFL, hostname,
441 #else
442                         "%s.%ld", CVSRFL,
443 #endif
444                         (long) getpid ());
445     }
446
447     /* remember what we're locking (for Lock_Cleanup) */
448     global_readlock.repository = xrepository;
449
450     /* get the lock dir for our own */
451     if (set_lock (&global_readlock, 1) != L_OK)
452     {
453         error (0, 0, "failed to obtain dir lock in repository `%s'",
454                xrepository);
455         if (readlock != NULL)
456             free (readlock);
457         readlock = NULL;
458         /* We don't set global_readlock.repository to NULL.  I think this
459            only works because recurse.c will give a fatal error if we return
460            a nonzero value.  */
461         return 1;
462     }
463
464     /* write a read-lock */
465     tmp = lock_name (xrepository, readlock);
466     if ((fp = CVS_FOPEN (tmp, "w+")) == NULL || fclose (fp) == EOF)
467     {
468         error (0, errno, "cannot create read lock in repository `%s'",
469                xrepository);
470         if (readlock != NULL)
471             free (readlock);
472         readlock = NULL;
473         err = 1;
474     }
475     free (tmp);
476
477     /* free the lock dir */
478     clear_lock (&global_readlock);
479
480     return err;
481 }
482
483
484
485 /*
486  * Lock a list of directories for writing
487  */
488 static char *lock_error_repos;
489 static int lock_error;
490
491 static int Writer_Lock PROTO ((List * list));
492
493 static int
494 Writer_Lock (list)
495     List *list;
496 {
497     char *wait_repos;
498
499     if (noexec)
500         return 0;
501
502     if (readonlyfs) {
503         error (0, 0, "write lock failed - read-only repository");
504         return (1);
505     }
506
507     /* We only know how to do one list at a time */
508     if (locklist != (List *) NULL)
509     {
510         error (0, 0, "Writer_Lock called while write locks set - Help!");
511         return 1;
512     }
513
514     wait_repos = NULL;
515     for (;;)
516     {
517         /* try to lock everything on the list */
518         lock_error = L_OK;              /* init for set_writelock_proc */
519         lock_error_repos = (char *) NULL; /* init for set_writelock_proc */
520         locklist = list;                /* init for Lock_Cleanup */
521         if (lockers_name != NULL)
522             free (lockers_name);
523         lockers_name = xstrdup ("unknown");
524
525         (void) walklist (list, set_writelock_proc, NULL);
526
527         switch (lock_error)
528         {
529             case L_ERROR:               /* Real Error */
530                 if (wait_repos != NULL)
531                     free (wait_repos);
532                 Lock_Cleanup ();        /* clean up any locks we set */
533                 error (0, 0, "lock failed - giving up");
534                 return 1;
535
536             case L_LOCKED:              /* Someone already had a lock */
537                 remove_locks ();        /* clean up any locks we set */
538                 lock_wait (lock_error_repos); /* sleep a while and try again */
539                 wait_repos = xstrdup (lock_error_repos);
540                 continue;
541
542             case L_OK:                  /* we got the locks set */
543                 if (wait_repos != NULL)
544                 {
545                     lock_obtained (wait_repos);
546                     free (wait_repos);
547                 }
548                 return 0;
549
550             default:
551                 if (wait_repos != NULL)
552                     free (wait_repos);
553                 error (0, 0, "unknown lock status %d in Writer_Lock",
554                        lock_error);
555                 return 1;
556         }
557     }
558 }
559
560
561
562 /*
563  * walklist proc for setting write locks
564  */
565 static int
566 set_writelock_proc (p, closure)
567     Node *p;
568     void *closure;
569 {
570     /* if some lock was not OK, just skip this one */
571     if (lock_error != L_OK)
572         return 0;
573
574     /* apply the write lock */
575     lock_error_repos = p->key;
576     lock_error = write_lock (p->data);
577     return 0;
578 }
579
580
581
582 /*
583  * Create a lock file for writers returns L_OK if lock set ok, L_LOCKED if
584  * lock held by someone else or L_ERROR if an error occurred
585  */
586 static int
587 write_lock (lock)
588     struct lock *lock;
589 {
590     int status;
591     FILE *fp;
592     char *tmp;
593
594     if (trace)
595         (void) fprintf (stderr, "%s-> write_lock(%s)\n",
596                         CLIENT_SERVER_STR, lock->repository);
597
598     if (writelock == NULL)
599     {
600         writelock = xmalloc (strlen (hostname) + sizeof (CVSWFL) + 40);
601         (void) sprintf (writelock,
602 #ifdef HAVE_LONG_FILE_NAMES
603                         "%s.%s.%ld", CVSWFL, hostname,
604 #else
605                         "%s.%ld", CVSWFL,
606 #endif
607                         (long) getpid());
608     }
609
610     /* make sure the lock dir is ours (not necessarily unique to us!) */
611     status = set_lock (lock, 0);
612     if (status == L_OK)
613     {
614         /* we now own a writer - make sure there are no readers */
615         if (readers_exist (lock->repository))
616         {
617             /* clean up the lock dir if we created it */
618             if (status == L_OK)
619             {
620                 clear_lock (lock);
621             }
622
623             /* indicate we failed due to read locks instead of error */
624             return L_LOCKED;
625         }
626
627         /* write the write-lock file */
628         tmp = lock_name (lock->repository, writelock);
629         if ((fp = CVS_FOPEN (tmp, "w+")) == NULL || fclose (fp) == EOF)
630         {
631             int xerrno = errno;
632
633             if ( CVS_UNLINK (tmp) < 0 && ! existence_error (errno))
634                 error (0, errno, "failed to remove lock %s", tmp);
635
636             /* free the lock dir if we created it */
637             if (status == L_OK)
638             {
639                 clear_lock (lock);
640             }
641
642             /* return the error */
643             error (0, xerrno, "cannot create write lock in repository `%s'",
644                    lock->repository);
645             free (tmp);
646             return L_ERROR;
647         }
648         free (tmp);
649         return L_OK;
650     }
651     else
652         return status;
653 }
654
655
656
657 /*
658  * readers_exist() returns 0 if there are no reader lock files remaining in
659  * the repository; else 1 is returned, to indicate that the caller should
660  * sleep a while and try again.
661  */
662 static int
663 readers_exist (repository)
664     char *repository;
665 {
666     char *lockdir;
667     char *line;
668     DIR *dirp;
669     struct dirent *dp;
670     struct stat sb;
671     int ret;
672 #ifdef CVS_FUDGELOCKS
673     time_t now;
674     (void)time (&now);
675 #endif
676
677     lockdir = lock_name (repository, "");
678
679     assert (lockdir != NULL);
680
681     lockdir[strlen (lockdir) - 1] = '\0';   /* remove trailing slash */
682
683     do {
684         if ((dirp = CVS_OPENDIR (lockdir)) == NULL)
685             error (1, 0, "cannot open directory %s", lockdir);
686
687         ret = 0;
688         errno = 0;
689         while ((dp = CVS_READDIR (dirp)) != NULL)
690         {
691             if (CVS_FNMATCH (CVSRFLPAT, dp->d_name, 0) == 0)
692             {
693                 line = xmalloc (strlen (lockdir) + 1 + strlen (dp->d_name) + 1);
694                 (void)sprintf (line, "%s/%s", lockdir, dp->d_name);
695                 if (CVS_STAT (line, &sb) != -1)
696                 {
697 #ifdef CVS_FUDGELOCKS
698                     /*
699                      * If the create time of the file is more than CVSLCKAGE 
700                      * seconds ago, try to clean-up the lock file, and if
701                      * successful, re-open the directory and try again.
702                      */
703                     if (now >= (sb.st_ctime + CVSLCKAGE) &&
704                         CVS_UNLINK (line) != -1)
705                     {
706                         free (line);
707                         ret = -1;
708                         break;
709                     }
710 #endif
711                     set_lockers_name (&sb);
712                 }
713                 else
714                 {
715                     /* If the file doesn't exist, it just means that it
716                      * disappeared between the time we did the readdir and the
717                      * time we did the stat.
718                      */
719                     if (!existence_error (errno))
720                         error (0, errno, "cannot stat %s", line);
721                 }
722                 errno = 0;
723                 free (line);
724                 ret = 1;
725                 break;
726             }
727             errno = 0;
728         }
729         if (errno != 0)
730             error (0, errno, "error reading directory %s", repository);
731
732         CVS_CLOSEDIR (dirp);
733     } while (ret < 0);
734
735     if (lockdir != NULL)
736         free (lockdir);
737     return ret;
738 }
739
740
741
742 /*
743  * Set the static variable lockers_name appropriately, based on the stat
744  * structure passed in.
745  */
746 static void
747 set_lockers_name (statp)
748     struct stat *statp;
749 {
750     struct passwd *pw;
751
752     if (lockers_name != NULL)
753         free (lockers_name);
754     if ((pw = (struct passwd *)getpwuid (statp->st_uid)) !=
755         (struct passwd *)NULL)
756     {
757         lockers_name = xstrdup (pw->pw_name);
758     }
759     else
760     {
761         lockers_name = xmalloc (20);
762         (void)sprintf (lockers_name, "uid%lu", (unsigned long) statp->st_uid);
763     }
764 }
765
766
767
768 /*
769  * Persistently tries to make the directory "lckdir", which serves as a
770  * lock.
771  *
772  * #ifdef CVS_FUDGELOCKS
773  * If the create time on the directory is greater than CVSLCKAGE
774  * seconds old, just try to remove the directory.
775  * #endif
776  *
777  */
778 static int
779 set_lock (lock, will_wait)
780     struct lock *lock;
781     int will_wait;
782 {
783     int waited;
784     long us;
785     struct stat sb;
786     mode_t omask;
787     char *masterlock;
788     int status;
789 #ifdef CVS_FUDGELOCKS
790     time_t now;
791 #endif
792
793     masterlock = lock_name (lock->repository, lock->lockdirname);
794
795     /*
796      * Note that it is up to the callers of set_lock() to arrange for signal
797      * handlers that do the appropriate things, like remove the lock
798      * directory before they exit.
799      */
800     waited = 0;
801     us = 1;
802     for (;;)
803     {
804         status = -1;
805         omask = umask (cvsumask);
806         SIG_beginCrSect ();
807         if (CVS_MKDIR (masterlock, 0777) == 0)
808         {
809             lock->lockdir = masterlock;
810             SIG_endCrSect ();
811             status = L_OK;
812             if (waited)
813                 lock_obtained (lock->repository);
814             goto after_sig_unblock;
815         }
816         SIG_endCrSect ();
817     after_sig_unblock:
818         (void) umask (omask);
819         if (status != -1)
820             goto done;
821
822         if (errno != EEXIST)
823         {
824             error (0, errno,
825                    "failed to create lock directory for `%s' (%s)",
826                    lock->repository, masterlock);
827             status = L_ERROR;
828             goto done;
829         }
830
831         /* Find out who owns the lock.  If the lock directory is
832            non-existent, re-try the loop since someone probably just
833            removed it (thus releasing the lock).  */
834         if (CVS_STAT (masterlock, &sb) < 0)
835         {
836             if (existence_error (errno))
837                 continue;
838
839             error (0, errno, "couldn't stat lock directory `%s'", masterlock);
840             status = L_ERROR;
841             goto done;
842         }
843
844 #ifdef CVS_FUDGELOCKS
845         /*
846          * If the create time of the directory is more than CVSLCKAGE seconds
847          * ago, try to clean-up the lock directory, and if successful, just
848          * quietly retry to make it.
849          */
850         (void) time (&now);
851         if (now >= (sb.st_ctime + CVSLCKAGE))
852         {
853             if (CVS_RMDIR (masterlock) >= 0)
854                 continue;
855         }
856 #endif
857
858         /* set the lockers name */
859         set_lockers_name (&sb);
860
861         /* if he wasn't willing to wait, return an error */
862         if (!will_wait)
863         {
864             status = L_LOCKED;
865             goto done;
866         }
867
868         /* if possible, try a very short sleep without a message */
869         if (!waited && us < 1000)
870         {
871             us += us;
872 #if defined HAVE_NANOSLEEP
873             {
874                 struct timespec ts;
875                 ts.tv_sec = 0;
876                 ts.tv_nsec = us * 1000;
877                 (void)nanosleep (&ts, NULL);
878                 continue;
879             }
880 #elif defined HAVE_USLEEP
881             (void)usleep (us);
882             continue;
883 #elif defined HAVE_SELECT
884             {
885                 struct timeval tv;
886                 tv.tv_sec = 0;
887                 tv.tv_usec = us;
888                 (void)select (0, (fd_set *)NULL, (fd_set *)NULL, (fd_set *)NULL, &tv);
889                 continue;
890             }
891 #endif
892         }
893
894         lock_wait (lock->repository);
895         waited = 1;
896     }
897 done:
898     if (!lock->lockdir) free (masterlock);
899     return status;
900 }
901
902
903
904 /*
905  * Clear master lock.
906  *
907  * INPUTS
908  *   lock       The lock information.
909  *
910  * OUTPUTS
911  *   Sets LOCK->lockdir to NULL after removing the directory it names and
912  *   freeing the storage.
913  *
914  * ASSUMPTIONS
915  *   If we own the master lock directory, its name is stored in LOCK->lockdir.
916  *   We may free LOCK->lockdir.
917  *
918  */
919 static void
920 clear_lock (lock)
921     struct lock *lock;
922 {
923     SIG_beginCrSect ();
924     if (lock->lockdir)
925     {
926         if (CVS_RMDIR (lock->lockdir) < 0)
927             error (0, errno, "failed to remove lock dir `%s'", lock->lockdir);
928         free (lock->lockdir);
929         lock->lockdir = NULL;
930     }
931     SIG_endCrSect ();
932 }
933
934
935
936 /*
937  * Print out a message that the lock is still held, then sleep a while.
938  */
939 static void
940 lock_wait (repos)
941     char *repos;
942 {
943     time_t now;
944     char *msg;
945     struct tm *tm_p;
946
947     (void) time (&now);
948     tm_p = gmtime (&now);
949     msg = xmalloc (100 + strlen (lockers_name) + strlen (repos));
950     sprintf (msg, "[%8.8s] waiting for %s's lock in %s",
951              (tm_p ? asctime (tm_p) : ctime (&now)) + 11,
952              lockers_name, repos);
953     error (0, 0, "%s", msg);
954     /* Call cvs_flusherr to ensure that the user sees this message as
955        soon as possible.  */
956     cvs_flusherr ();
957     free (msg);
958     (void) sleep (CVSLCKSLEEP);
959 }
960
961 /*
962  * Print out a message when we obtain a lock.
963  */
964 static void
965 lock_obtained (repos)
966      char *repos;
967 {
968     time_t now;
969     char *msg;
970     struct tm *tm_p;
971
972     (void) time (&now);
973     tm_p = gmtime (&now);
974     msg = xmalloc (100 + strlen (repos));
975     sprintf (msg, "[%8.8s] obtained lock in %s",
976              (tm_p ? asctime (tm_p) : ctime (&now)) + 11, repos);
977     error (0, 0, "%s", msg);
978     /* Call cvs_flusherr to ensure that the user sees this message as
979        soon as possible.  */
980     cvs_flusherr ();
981     free (msg);
982 }
983
984
985
986 static int lock_filesdoneproc PROTO ((void *callerdat, int err,
987                                       const char *repository,
988                                       const char *update_dir,
989                                       List *entries));
990
991 /*
992  * Create a list of repositories to lock
993  */
994 /* ARGSUSED */
995 static int
996 lock_filesdoneproc (callerdat, err, repository, update_dir, entries)
997     void *callerdat;
998     int err;
999     const char *repository;
1000     const char *update_dir;
1001     List *entries;
1002 {
1003     Node *p;
1004
1005     p = getnode ();
1006     p->type = LOCK;
1007     p->key = xstrdup (repository);
1008     p->data = xmalloc (sizeof (struct lock));
1009     ((struct lock *)p->data)->repository = p->key;
1010     ((struct lock *)p->data)->lockdirname = CVSLCK;
1011     ((struct lock *)p->data)->lockdir = NULL;
1012
1013     /* FIXME-KRP: this error condition should not simply be passed by. */
1014     if (p->key == NULL || addnode (lock_tree_list, p) != 0)
1015         freenode (p);
1016     return (err);
1017 }
1018
1019 void
1020 lock_tree_for_write (argc, argv, local, which, aflag)
1021     int argc;
1022     char **argv;
1023     int local;
1024     int which;
1025     int aflag;
1026 {
1027     /*
1028      * Run the recursion processor to find all the dirs to lock and lock all
1029      * the dirs
1030      */
1031     lock_tree_list = getlist ();
1032     start_recursion ((FILEPROC) NULL, lock_filesdoneproc,
1033                      (DIRENTPROC) NULL, (DIRLEAVEPROC) NULL, NULL, argc,
1034                      argv, local, which, aflag, CVS_LOCK_NONE,
1035                      (char *) NULL, 0, (char *) NULL);
1036     sortlist (lock_tree_list, fsortcmp);
1037     if (Writer_Lock (lock_tree_list) != 0)
1038         error (1, 0, "lock failed - giving up");
1039 }
1040 \f
1041 /* Lock a single directory in REPOSITORY.  It is OK to call this if
1042    a lock has been set with lock_dir_for_write; the new lock will replace
1043    the old one.  If REPOSITORY is NULL, don't do anything.  */
1044 void
1045 lock_dir_for_write (repository)
1046      char *repository;
1047 {
1048     if (repository != NULL
1049         && (locked_dir == NULL
1050             || strcmp (locked_dir, repository) != 0))
1051     {
1052         Node *node;
1053
1054         if (locked_dir != NULL)
1055             Lock_Cleanup ();
1056
1057         locked_dir = xstrdup (repository);
1058         locked_list = getlist ();
1059         node = getnode ();
1060         node->type = LOCK;
1061         node->key = xstrdup (repository);
1062         node->data = xmalloc (sizeof (struct lock));
1063         ((struct lock *)node->data)->repository = node->key;
1064         ((struct lock *)node->data)->lockdirname = CVSLCK;
1065         ((struct lock *)node->data)->lockdir = NULL;
1066
1067         (void) addnode (locked_list, node);
1068         Writer_Lock (locked_list);
1069     }
1070 }
1071
1072
1073
1074 /* This is the internal implementation behind history_lock & val_tags_lock.  It
1075  * gets a write lock for the history or val-tags file.
1076  *
1077  * RETURNS
1078  *   true, on success
1079  *   false, on error
1080  */
1081 static int internal_lock PROTO ((struct lock *lock, const char *xrepository));
1082 static int
1083 internal_lock (lock, xrepository)
1084     struct lock *lock;
1085     const char *xrepository;
1086 {
1087     /* remember what we're locking (for Lock_Cleanup) */
1088     assert (!lock->repository);
1089     lock->repository = xmalloc (strlen (xrepository) + sizeof (CVSROOTADM) + 2);
1090     sprintf (lock->repository, "%s/%s", xrepository, CVSROOTADM);
1091
1092     /* get the lock dir for our own */
1093     if (set_lock (lock, 1) != L_OK)
1094     {
1095         if (!really_quiet)
1096             error (0, 0, "failed to obtain history lock in repository `%s'",
1097                    xrepository);
1098
1099         return 0;
1100     }
1101
1102     return 1;
1103 }
1104
1105
1106
1107 /* This is the internal implementation behind history_lock & val_tags_lock.  It
1108  * removes the write lock for the history or val-tags file, when it exists.
1109  */
1110 static void internal_clear_lock PROTO((struct lock *lock));
1111 static void
1112 internal_clear_lock (lock)
1113     struct lock *lock;
1114 {
1115     SIG_beginCrSect ();
1116     if (lock->repository)
1117     {
1118         free (lock->repository);
1119         lock->repository = NULL;
1120     }
1121     SIG_endCrSect ();
1122
1123     clear_lock (lock);
1124 }
1125
1126
1127
1128 /* Lock the CVSROOT/history file for write.
1129  */
1130 int
1131 history_lock (xrepository)
1132     const char *xrepository;
1133 {
1134     return internal_lock (&global_history_lock, xrepository);
1135 }
1136
1137
1138
1139 /* Remove the CVSROOT/history lock, if it exists.
1140  */
1141 void
1142 clear_history_lock ()
1143 {
1144     internal_clear_lock (&global_history_lock);
1145 }
1146
1147
1148
1149 /* Lock the CVSROOT/val-tags file for write.
1150  */
1151 int
1152 val_tags_lock (xrepository)
1153     const char *xrepository;
1154 {
1155     return internal_lock (&global_val_tags_lock, xrepository);
1156 }
1157
1158
1159
1160 /* Remove the CVSROOT/val-tags lock, if it exists.
1161  */
1162 void
1163 clear_val_tags_lock ()
1164 {
1165     internal_clear_lock (&global_val_tags_lock);
1166 }