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