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