2 * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
4 * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
7 * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk
8 * Portions Copyright (C) 1989-1992, Brian Berliner
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.
15 * Lock file support for CVS.
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
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
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
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).
38 * Readlocks provide some modicum of consistency, although this is
39 kind of limited--see the node Concurrency in cvs.texinfo.
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
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.
51 * Readlocks ensure that a reader won't try to look at a
52 half-written fileattr file (fileattr is not updated atomically).
54 (see also the description of anonymous read-only access in
55 "Password authentication security" node in doc/cvs.texinfo).
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:
60 1. Check for EROFS. Maybe useful, although in the presence of NFS
61 EROFS does *not* mean that the file system is unchanging.
63 2. Provide an option to disable locks for operations which only
64 read (see above for some of the consequences).
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. */
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;
85 /* The name of the lock files. */
87 #ifdef LOCK_COMPATIBILITY
89 #endif /* LOCK_COMPATIBILITY */
91 /* Do we have a lock named CVSLCK? */
93 /* Note there is no way of knowing whether the readlock and writelock
94 exist. The code which sets the locks doesn't use SIG_beginCrSect
95 to set a flag like we do for CVSLCK. */
99 static void remove_locks (void);
100 static int set_lock (struct lock *lock, int will_wait);
101 static void clear_lock (struct lock *lock);
102 static void set_lockers_name (struct stat *statp);
104 /* Malloc'd array containing the username of the whoever has the lock.
105 Will always be non-NULL in the cases where it is needed. */
106 static char *lockers_name;
107 /* Malloc'd array specifying name of a readlock within a directory.
109 static char *readlock;
110 /* Malloc'd array specifying name of a writelock within a directory.
112 static char *writelock;
113 /* Malloc'd array specifying name of a promotablelock within a directory.
115 static char *promotablelock;
116 /* Malloc'd array specifying the name of a CVSLCK file (absolute pathname).
117 Will always be non-NULL in the cases where it is used. */
118 static char *masterlock;
119 static List *locklist;
121 #define L_OK 0 /* success */
122 #define L_ERROR 1 /* error condition */
123 #define L_LOCKED 2 /* lock owned by someone else */
125 /* This is the (single) readlock which is set by Reader_Lock. The
126 repository field is NULL if there is no such lock. */
127 static struct lock global_readlock;
128 static struct lock global_writelock;
130 /* List of locks set by lock_tree_for_write. This is redundant
131 with locklist, sort of. */
132 static List *lock_tree_list;
136 /* Return a newly malloc'd string containing the name of the lock for the
137 repository REPOSITORY and the lock file name within that directory
138 NAME. Also create the directories in which to put the lock file
139 if needed (if we need to, could save system call(s) by doing
140 that only if the actual operation fails. But for now we'll keep
143 lock_name (const char *repository, const char *name)
148 const char *short_repos;
149 mode_t save_umask = 0000;
152 TRACE (TRACE_FLOW, "lock_name (%s, %s)",
153 repository ? repository : "(null)", name ? name : "(null)");
155 if (!config->lock_dir)
157 /* This is the easy case. Because the lock files go directly
158 in the repository, no need to create directories or anything. */
159 assert (name != NULL);
160 assert (repository != NULL);
161 retval = Xasprintf ("%s/%s", repository, name);
168 /* The interesting part of the repository is the part relative
170 assert (current_parsed_root != NULL);
171 assert (current_parsed_root->directory != NULL);
172 assert (strncmp (repository, current_parsed_root->directory,
173 strlen (current_parsed_root->directory)) == 0);
174 short_repos = repository + strlen (current_parsed_root->directory) + 1;
176 if (strcmp (repository, current_parsed_root->directory) == 0)
179 assert (short_repos[-1] == '/');
181 retval = xmalloc (strlen (config->lock_dir)
182 + strlen (short_repos)
185 strcpy (retval, config->lock_dir);
186 q = retval + strlen (retval);
189 strcpy (q, short_repos);
191 /* In the common case, where the directory already exists, let's
192 keep it to one system call. */
193 if (CVS_STAT (retval, &sb) < 0)
195 /* If we need to be creating more than one directory, we'll
196 get the existence_error here. */
197 if (!existence_error (errno))
198 error (1, errno, "cannot stat directory %s", retval);
202 if (S_ISDIR (sb.st_mode))
205 error (1, 0, "%s is not a directory", retval);
208 /* Now add the directories one at a time, so we can create
211 The idea behind the new_mode stuff is that the directory we
212 end up creating will inherit permissions from its parent
213 directory (we re-set new_mode with each EEXIST). CVSUMASK
214 isn't right, because typically the reason for LockDir is to
215 use a different set of permissions. We probably want to
216 inherit group ownership also (but we don't try to deal with
217 that, some systems do it for us either always or when g+s is on).
219 We don't try to do anything about the permissions on the lock
220 files themselves. The permissions don't really matter so much
221 because the locks will generally be removed by the process
222 which created them. */
224 if (CVS_STAT (config->lock_dir, &sb) < 0)
225 error (1, errno, "cannot stat %s", config->lock_dir);
226 new_mode = sb.st_mode;
227 save_umask = umask (0000);
233 while (!ISSLASH (*p) && *p != '\0')
237 strncpy (q, short_repos, p - short_repos);
238 q[p - short_repos] = '\0';
239 if (!ISSLASH (q[p - short_repos - 1])
240 && CVS_MKDIR (retval, new_mode) < 0)
242 int saved_errno = errno;
243 if (saved_errno != EEXIST)
244 error (1, errno, "cannot make directory %s", retval);
247 if (CVS_STAT (retval, &sb) < 0)
248 error (1, errno, "cannot stat %s", retval);
249 new_mode = sb.st_mode;
256 strcpy (q, short_repos);
257 if (CVS_MKDIR (retval, new_mode) < 0
259 error (1, errno, "cannot make directory %s", retval);
265 strcat (retval, "/");
266 strcat (retval, name);
270 assert (umask (save_umask) == 0000);
279 /* Remove the lock files. For interrupt purposes, it can be assumed that the
280 * first thing this function does is set lock->repository to NULL.
283 * lock The lock to remove.
284 * free True if this lock directory will not5 be reused (free
285 * lock->repository if necessary).
288 remove_lock_files (struct lock *lock, int free_repository)
290 TRACE (TRACE_FLOW, "remove_lock_files (%s)", lock->repository);
292 /* If lock->file is set, the lock *might* have been created, but since
293 * Reader_Lock & lock_dir_for_write don't use SIG_beginCrSect the way that
294 * set_lock does, we don't know that. That is why we need to check for
295 * existence_error here.
299 char *tmp = lock->file1;
301 if (CVS_UNLINK (tmp) < 0 && ! existence_error (errno))
302 error (0, errno, "failed to remove lock %s", tmp);
305 #ifdef LOCK_COMPATIBILITY
308 char *tmp = lock->file2;
310 if (CVS_UNLINK (tmp) < 0 && ! existence_error (errno))
311 error (0, errno, "failed to remove lock %s", tmp);
314 #endif /* LOCK_COMPATIBILITY */
316 if (lock->have_lckdir)
318 char *tmp = lock_name (lock->repository, CVSLCK);
320 if (CVS_RMDIR (tmp) < 0)
321 error (0, errno, "failed to remove lock dir %s", tmp);
322 lock->have_lckdir = 0;
327 /* And free the repository string. We don't really have to set the
328 * repository string to NULL first since there is no harm in running any of
329 * the above code twice.
331 * Use SIG_beginCrSect since otherwise we might be interrupted between
332 * checking whether free_repository is set and freeing stuff.
337 if (lock->free_repository)
339 free ((char *)lock->repository);
340 lock->free_repository = 0;
342 lock->repository = NULL;
350 * Clean up outstanding read and write locks and free their storage.
353 Simple_Lock_Cleanup (void)
355 TRACE (TRACE_FUNCTION, "Simple_Lock_Cleanup()");
357 /* Avoid interrupts while accessing globals the interrupt handlers might
362 /* clean up simple read locks (if any) */
363 if (global_readlock.repository != NULL)
364 remove_lock_files (&global_readlock, 1);
365 /* See note in Lock_Cleanup() below. */
370 /* clean up simple write locks (if any) */
371 if (global_writelock.repository != NULL)
372 remove_lock_files (&global_writelock, 1);
373 /* See note in Lock_Cleanup() below. */
380 * Clean up all outstanding locks and free their storage.
383 * This function needs to be reentrant since a call to exit() can cause a
384 * call to this function, which can then be interrupted by a signal, which
385 * can cause a second call to this function.
393 TRACE (TRACE_FUNCTION, "Lock_Cleanup()");
395 /* FIXME: Do not perform buffered I/O from an interrupt handler like
396 * this (via error). However, I'm leaving the error-calling code there
397 * in the hope that on the rare occasion the error call is actually made
398 * (e.g., a fluky I/O error or permissions problem prevents the deletion
399 * of a just-created file) reentrancy won't be an issue.
404 /* Avoid being interrupted during calls which set globals to NULL. This
405 * avoids having interrupt handlers attempt to use these global variables
406 * in inconsistent states.
408 * This isn't always necessary, because sometimes we are called via exit()
409 * or the interrupt handler, in which case signals will already be blocked,
410 * but sometimes we might be called from elsewhere.
413 dellist (&lock_tree_list);
414 /* Unblocking allows any signal to be processed as soon as possible. This
415 * isn't really necessary, but since we know signals can cause us to be
416 * called, why not avoid having blocks of code run twice.
424 * walklist proc for removing a list of locks
427 unlock_proc (Node *p, void *closure)
429 remove_lock_files (p->data, 0);
436 * Remove locks without discarding the lock information.
441 TRACE (TRACE_FLOW, "remove_locks()");
443 Simple_Lock_Cleanup ();
445 /* clean up promotable locks (if any) */
447 if (locklist != NULL)
449 /* Use a tmp var since any of these functions could call exit, causing
450 * us to be called a second time.
452 List *tmp = locklist;
454 walklist (tmp, unlock_proc, NULL);
462 * Set the global readlock variable if it isn't already.
465 set_readlock_name (void)
467 if (readlock == NULL)
469 readlock = Xasprintf (
470 #ifdef HAVE_LONG_FILE_NAMES
471 "%s.%s.%ld", CVSRFL, hostname,
482 * Create a lock file for readers
485 Reader_Lock (char *xrepository)
490 TRACE (TRACE_FUNCTION, "Reader_Lock(%s)", xrepository);
492 if (noexec || readonlyfs)
495 /* we only do one directory at a time for read locks! */
496 if (global_readlock.repository != NULL)
498 error (0, 0, "Reader_Lock called while read locks set - Help!");
502 set_readlock_name ();
504 /* remember what we're locking (for Lock_Cleanup) */
505 global_readlock.repository = xstrdup (xrepository);
506 global_readlock.free_repository = 1;
508 /* get the lock dir for our own */
509 if (set_lock (&global_readlock, 1) != L_OK)
511 error (0, 0, "failed to obtain dir lock in repository `%s'",
513 if (readlock != NULL)
516 /* We don't set global_readlock.repository to NULL. I think this
517 only works because recurse.c will give a fatal error if we return
522 /* write a read-lock */
523 global_readlock.file1 = lock_name (xrepository, readlock);
524 if ((fp = CVS_FOPEN (global_readlock.file1, "w+")) == NULL
525 || fclose (fp) == EOF)
527 error (0, errno, "cannot create read lock in repository `%s'",
532 /* free the lock dir */
533 clear_lock (&global_readlock);
541 * lock_exists() returns 0 if there is no lock file matching FILEPAT in
542 * the repository but not IGNORE; else 1 is returned, to indicate that the
543 * caller should sleep a while and try again.
546 * repository The repository directory to search for locks.
547 * filepat The file name pattern to search for.
548 * ignore The name of a single file which can be ignored.
551 * lockdir The lock dir external to the repository, if any.
554 * 0 No lock matching FILEPAT and not IGNORE exists.
555 * 1 Otherwise and on error.
558 * In the case where errors are encountered reading the directory, a warning
559 * message is printed, 1 is is returned and ERRNO is left set.
562 lock_exists (const char *repository, const char *filepat, const char *ignore)
570 #ifdef CVS_FUDGELOCKS
575 TRACE (TRACE_FLOW, "lock_exists (%s, %s, %s)",
576 repository, filepat, ignore ? ignore : "(null)");
578 lockdir = lock_name (repository, "");
579 lockdir[strlen (lockdir) - 1] = '\0'; /* remove trailing slash */
582 if ((dirp = CVS_OPENDIR (lockdir)) == NULL)
583 error (1, 0, "cannot open directory %s", lockdir);
587 while ((dp = CVS_READDIR (dirp)) != NULL)
589 if (CVS_FNMATCH (filepat, dp->d_name, 0) == 0)
591 /* FIXME: the basename conversion below should be replaced with
592 * a call to the GNULIB basename function once it is imported.
594 /* ignore our plock, if any */
595 if (ignore && !fncmp (ignore, dp->d_name))
598 line = Xasprintf ("%s/%s", lockdir, dp->d_name);
599 if (CVS_STAT (line, &sb) != -1)
601 #ifdef CVS_FUDGELOCKS
603 * If the create time of the file is more than CVSLCKAGE
604 * seconds ago, try to clean-up the lock file, and if
605 * successful, re-open the directory and try again.
607 if (now >= (sb.st_ctime + CVSLCKAGE) &&
608 CVS_UNLINK (line) != -1)
615 set_lockers_name (&sb);
619 /* If the file doesn't exist, it just means that it
620 * disappeared between the time we did the readdir and the
621 * time we did the stat.
623 if (!existence_error (errno))
624 error (0, errno, "cannot stat %s", line);
634 error (0, errno, "error reading directory %s", repository);
647 * readers_exist() returns 0 if there are no reader lock files remaining in
648 * the repository; else 1 is returned, to indicate that the caller should
649 * sleep a while and try again.
651 * See lock_exists() for argument detail.
654 readers_exist (const char *repository)
656 TRACE (TRACE_FLOW, "readers_exist (%s)", repository);
658 /* It is only safe to ignore a readlock set by our process if it was set as
659 * a safety measure to prevent older CVS processes from ignoring our
660 * promotable locks. The code to ignore these readlocks can be removed
661 * once it is deemed unlikely that anyone will be using CVS servers earlier
662 * than version 1.12.4.
664 return lock_exists (repository, CVSRFLPAT,
665 #ifdef LOCK_COMPATIBILITY
666 findnode (locklist, repository) ? readlock :
667 #endif /* LOCK_COMPATIBILITY */
674 * promotable_exists() returns 0 if there is no promotable lock file in
675 * the repository; else 1 is returned, to indicate that the caller should
676 * sleep a while and try again.
678 * See lock_exists() for argument detail.
681 promotable_exists (const char *repository)
683 TRACE (TRACE_FLOW, "promotable_exists (%s)", repository);
684 return lock_exists (repository, CVSPFLPAT, promotablelock);
690 * Lock a list of directories for writing
692 static char *lock_error_repos;
693 static int lock_error;
698 * Create a lock file for potential writers returns L_OK if lock set ok,
699 * L_LOCKED if lock held by someone else or L_ERROR if an error occurred.
702 set_promotable_lock (struct lock *lock)
707 TRACE (TRACE_FUNCTION, "set_promotable_lock(%s)",
708 lock->repository ? lock->repository : "(null)");
710 if (promotablelock == NULL)
712 promotablelock = Xasprintf (
713 #ifdef HAVE_LONG_FILE_NAMES
714 "%s.%s.%ld", CVSPFL, hostname,
721 /* make sure the lock dir is ours (not necessarily unique to us!) */
722 status = set_lock (lock, 0);
725 /* we now own a promotable lock - make sure there are no others */
726 if (promotable_exists (lock->repository))
728 /* clean up the lock dir */
731 /* indicate we failed due to read locks instead of error */
735 /* write the promotable-lock file */
736 lock->file1 = lock_name (lock->repository, promotablelock);
737 if ((fp = CVS_FOPEN (lock->file1, "w+")) == NULL || fclose (fp) == EOF)
741 if (CVS_UNLINK (lock->file1) < 0 && ! existence_error (errno))
742 error (0, errno, "failed to remove lock %s", lock->file1);
744 /* free the lock dir */
747 /* return the error */
749 "cannot create promotable lock in repository `%s'",
754 #ifdef LOCK_COMPATIBILITY
755 /* write the read-lock file. We only do this so that older versions of
756 * CVS will not think it is okay to create a write lock. When it is
757 * decided that versions of CVS earlier than 1.12.4 are not likely to
758 * be used, this code can be removed.
760 set_readlock_name ();
761 lock->file2 = lock_name (lock->repository, readlock);
762 if ((fp = CVS_FOPEN (lock->file2, "w+")) == NULL || fclose (fp) == EOF)
766 if ( CVS_UNLINK (lock->file2) < 0 && ! existence_error (errno))
767 error (0, errno, "failed to remove lock %s", lock->file2);
769 /* free the lock dir */
772 /* Remove the promotable lock. */
774 remove_lock_files (lock, 0);
776 /* return the error */
778 "cannot create read lock in repository `%s'",
782 #endif /* LOCK_COMPATIBILITY */
795 * walklist proc for setting write locks. Mostly just a wrapper for the
796 * set_promotable_lock function, which has a prettier API, but no other good
797 * reason for existing separately.
800 * p The current node, as determined by walklist().
804 * lock_error Any previous error encountered while attempting to get
808 * lock_error Set if we encounter an error attempting to get axi
810 * lock_error_repos Set so that if we set lock_error later functions will
811 * be able to report where the other process's lock was
818 set_promotablelock_proc (Node *p, void *closure)
820 /* if some lock was not OK, just skip this one */
821 if (lock_error != L_OK)
824 /* apply the write lock */
825 lock_error_repos = p->key;
826 lock_error = set_promotable_lock ((struct lock *)p->data);
833 * Print out a message that the lock is still held, then sleep a while.
836 lock_wait (const char *repos)
843 tm_p = gmtime (&now);
844 msg = Xasprintf ("[%8.8s] waiting for %s's lock in %s",
845 (tm_p ? asctime (tm_p) : ctime (&now)) + 11,
846 lockers_name, repos);
847 error (0, 0, "%s", msg);
848 /* Call cvs_flusherr to ensure that the user sees this message as
852 (void)sleep (CVSLCKSLEEP);
858 * Print out a message when we obtain a lock.
861 lock_obtained (const char *repos)
868 tm_p = gmtime (&now);
869 msg = Xasprintf ("[%8.8s] obtained lock in %s",
870 (tm_p ? asctime (tm_p) : ctime (&now)) + 11, repos);
871 error (0, 0, "%s", msg);
872 /* Call cvs_flusherr to ensure that the user sees this message as
881 lock_list_promotably (List *list)
885 TRACE (TRACE_FLOW, "lock_list_promotably ()");
892 "promotable lock failed.\n\
893 WARNING: Read-only repository access mode selected via `cvs -R'.\n\
894 Attempting to write to a read-only filesystem is not allowed.");
898 /* We only know how to do one list at a time */
899 if (locklist != NULL)
902 "lock_list_promotably called while promotable locks set - Help!");
909 /* try to lock everything on the list */
910 lock_error = L_OK; /* init for set_promotablelock_proc */
911 lock_error_repos = NULL; /* init for set_promotablelock_proc */
912 locklist = list; /* init for Lock_Cleanup */
913 if (lockers_name != NULL)
915 lockers_name = xstrdup ("unknown");
917 (void) walklist (list, set_promotablelock_proc, NULL);
921 case L_ERROR: /* Real Error */
922 if (wait_repos != NULL)
924 Lock_Cleanup (); /* clean up any locks we set */
925 error (0, 0, "lock failed - giving up");
928 case L_LOCKED: /* Someone already had a lock */
929 remove_locks (); /* clean up any locks we set */
930 lock_wait (lock_error_repos); /* sleep a while and try again */
931 wait_repos = xstrdup (lock_error_repos);
934 case L_OK: /* we got the locks set */
935 if (wait_repos != NULL)
937 lock_obtained (wait_repos);
943 if (wait_repos != NULL)
945 error (0, 0, "unknown lock status %d in lock_list_promotably",
955 * Set the static variable lockers_name appropriately, based on the stat
956 * structure passed in.
959 set_lockers_name (struct stat *statp)
963 if (lockers_name != NULL)
965 pw = (struct passwd *) getpwuid (statp->st_uid);
967 lockers_name = xstrdup (pw->pw_name);
969 lockers_name = Xasprintf ("uid%lu", (unsigned long) statp->st_uid);
975 * Persistently tries to make the directory "lckdir", which serves as a
978 * #ifdef CVS_FUDGELOCKS
979 * If the create time on the directory is greater than CVSLCKAGE
980 * seconds old, just try to remove the directory.
985 set_lock (struct lock *lock, int will_wait)
991 #ifdef CVS_FUDGELOCKS
995 TRACE (TRACE_FLOW, "set_lock (%s, %d)",
996 lock->repository ? lock->repository : "(null)", will_wait);
998 if (masterlock != NULL)
1000 masterlock = lock_name (lock->repository, CVSLCK);
1003 * Note that it is up to the callers of set_lock() to arrange for signal
1004 * handlers that do the appropriate things, like remove the lock
1005 * directory before they exit.
1009 lock->have_lckdir = 0;
1013 omask = umask (cvsumask);
1015 if (CVS_MKDIR (masterlock, 0777) == 0)
1017 lock->have_lckdir = 1;
1021 lock_obtained (lock->repository);
1026 (void) umask (omask);
1030 if (errno != EEXIST)
1033 "failed to create lock directory for `%s' (%s)",
1034 lock->repository, masterlock);
1038 /* Find out who owns the lock. If the lock directory is
1039 non-existent, re-try the loop since someone probably just
1040 removed it (thus releasing the lock). */
1041 if (CVS_STAT (masterlock, &sb) < 0)
1043 if (existence_error (errno))
1046 error (0, errno, "couldn't stat lock directory `%s'", masterlock);
1050 #ifdef CVS_FUDGELOCKS
1052 * If the create time of the directory is more than CVSLCKAGE seconds
1053 * ago, try to clean-up the lock directory, and if successful, just
1054 * quietly retry to make it.
1057 if (now >= (sb.st_ctime + CVSLCKAGE))
1059 if (CVS_RMDIR (masterlock) >= 0)
1064 /* set the lockers name */
1065 set_lockers_name (&sb);
1067 /* if he wasn't willing to wait, return an error */
1071 /* if possible, try a very short sleep without a message */
1072 if (!waited && us < 1000)
1078 ts.tv_nsec = us * 1000;
1079 (void)nanosleep (&ts, NULL);
1084 lock_wait (lock->repository);
1092 * Clear master lock. We don't have to recompute the lock name since
1093 * clear_lock is never called except after a successful set_lock().
1096 clear_lock (struct lock *lock)
1099 if (CVS_RMDIR (masterlock) < 0)
1100 error (0, errno, "failed to remove lock dir `%s'", masterlock);
1101 lock->have_lckdir = 0;
1108 * Create a list of repositories to lock
1112 lock_filesdoneproc (void *callerdat, int err, const char *repository,
1113 const char *update_dir, List *entries)
1119 p->key = xstrdup (repository);
1120 p->data = xmalloc (sizeof (struct lock));
1121 ((struct lock *)p->data)->repository = p->key;
1122 ((struct lock *)p->data)->file1 = NULL;
1123 #ifdef LOCK_COMPATIBILITY
1124 ((struct lock *)p->data)->file2 = NULL;
1125 #endif /* LOCK_COMPATIBILITY */
1126 ((struct lock *)p->data)->have_lckdir = 0;
1127 ((struct lock *)p->data)->free_repository = 0;
1129 /* FIXME-KRP: this error condition should not simply be passed by. */
1130 if (p->key == NULL || addnode (lock_tree_list, p) != 0)
1138 lock_tree_promotably (int argc, char **argv, int local, int which, int aflag)
1140 TRACE (TRACE_FUNCTION, "lock_tree_promotably (%d, argv, %d, %d, %d)",
1141 argc, local, which, aflag);
1144 * Run the recursion processor to find all the dirs to lock and lock all
1147 lock_tree_list = getlist ();
1149 (NULL, lock_filesdoneproc,
1150 NULL, NULL, NULL, argc,
1151 argv, local, which, aflag, CVS_LOCK_NONE,
1153 sortlist (lock_tree_list, fsortcmp);
1154 if (lock_list_promotably (lock_tree_list) != 0)
1155 error (1, 0, "lock failed - giving up");
1160 /* Lock a single directory in REPOSITORY. It is OK to call this if
1161 * a lock has been set with lock_dir_for_write; the new lock will replace
1162 * the old one. If REPOSITORY is NULL, don't do anything.
1164 * We do not clear the dir lock after writing the lock file name since write
1165 * locks are exclusive to all other locks.
1168 lock_dir_for_write (const char *repository)
1172 TRACE (TRACE_FLOW, "lock_dir_for_write (%s)", repository);
1174 if (repository != NULL
1175 && (global_writelock.repository == NULL
1176 || !strcmp (global_writelock.repository, repository)))
1178 if (writelock == NULL)
1180 writelock = Xasprintf (
1181 #ifdef HAVE_LONG_FILE_NAMES
1182 "%s.%s.%ld", CVSWFL, hostname,
1189 if (global_writelock.repository != NULL)
1190 remove_lock_files (&global_writelock, 1);
1192 global_writelock.repository = xstrdup (repository);
1193 global_writelock.free_repository = 1;
1199 if (set_lock (&global_writelock, 1) != L_OK)
1200 error (1, 0, "failed to obtain write lock in repository `%s'",
1203 /* check if readers exist */
1204 if (readers_exist (repository)
1205 || promotable_exists (repository))
1207 clear_lock (&global_writelock);
1208 lock_wait (repository); /* sleep a while and try again */
1214 lock_obtained (repository);
1216 /* write the write-lock file */
1217 global_writelock.file1 = lock_name (global_writelock.repository,
1219 if ((fp = CVS_FOPEN (global_writelock.file1, "w+")) == NULL
1220 || fclose (fp) == EOF)
1224 if (CVS_UNLINK (global_writelock.file1) < 0
1225 && !existence_error (errno))
1227 error (0, errno, "failed to remove write lock %s",
1228 global_writelock.file1);
1231 /* free the lock dir */
1232 clear_lock (&global_writelock);
1234 /* return the error */
1236 "cannot create write lock in repository `%s'",
1237 global_writelock.repository);
1240 /* If we upgraded from a promotable lock, remove it. */
1243 Node *p = findnode (locklist, repository);
1246 remove_lock_files (p->data, 1);