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