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