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