2 * Copyright (c) 1992, Brian Berliner and Jeff Polk
3 * Copyright (c) 1989-1992, Brian Berliner
5 * You may distribute under the terms of the GNU General Public License as
6 * specified in the README file that comes with the CVS source distribution.
10 * Lock file support for CVS.
13 /* The node Concurrency in doc/cvs.texinfo has a brief introduction to
14 how CVS locks function, and some of the user-visible consequences of
15 their existence. Here is a summary of why they exist (and therefore,
16 the consequences of hacking CVS to read a repository without creating
19 There are two uses. One is the ability to prevent there from being
20 two writers at the same time. This is necessary for any number of
21 reasons (fileattr code, probably others). Commit needs to lock the
22 whole tree so that nothing happens between the up-to-date check and
25 The second use is the ability to ensure that there is not a writer
26 and a reader at the same time (several readers are allowed). Reasons
29 * Readlocks ensure that once CVS has found a collection of rcs
30 files using Find_Names, the files will still exist when it reads
31 them (they may have moved in or out of the attic).
33 * Readlocks provide some modicum of consistency, although this is
34 kind of limited--see the node Concurrency in cvs.texinfo.
36 * Readlocks ensure that the RCS file does not change between
37 RCS_parse and RCS_reparsercsfile time. This one strikes me as
38 important, although I haven't thought up what bad scenarios might
41 * Readlocks ensure that we won't find the file in the state in
42 which it is in between the calls to add_rcs_file and RCS_checkin in
43 commit.c (when a file is being added). This state is a state in
44 which the RCS file parsing routines in rcs.c cannot parse the file.
46 * Readlocks ensure that a reader won't try to look at a
47 half-written fileattr file (fileattr is not updated atomically).
49 (see also the description of anonymous read-only access in
50 "Password authentication security" node in doc/cvs.texinfo).
52 While I'm here, I'll try to summarize a few random suggestions
53 which periodically get made about how locks might be different:
55 1. Check for EROFS. Maybe useful, although in the presence of NFS
56 EROFS does *not* mean that the file system is unchanging.
58 2. Provide an option to disable locks for operations which only
59 read (see above for some of the consequences).
61 3. Have a server internally do the locking. Probably a good
62 long-term solution, and many people have been working hard on code
63 changes which would eventually make it possible to have a server
64 which can handle various connections in one process, but there is
65 much, much work still to be done before this is feasible. */
72 /* This is the directory in which we may have a lock named by the
73 readlock variable, a lock named by the writelock variable, and/or
74 a lock named CVSLCK. The storage is not allocated along with the
75 struct lock; it is allocated by the Reader_Lock caller or in the
76 case of promotablelocks, it is just a pointer to the storage allocated
77 for the ->key field. */
78 const char *repository;
80 /* The name of the lock files. */
82 #ifdef LOCK_COMPATIBILITY
84 #endif /* LOCK_COMPATIBILITY */
86 /* Do we have a lock named CVSLCK? */
88 /* Note there is no way of knowing whether the readlock and writelock
89 exist. The code which sets the locks doesn't use SIG_beginCrSect
90 to set a flag like we do for CVSLCK. */
94 static void remove_locks (void);
95 static int set_lock (struct lock *lock, int will_wait);
96 static void clear_lock (struct lock *lock);
97 static void set_lockers_name (struct stat *statp);
99 /* Malloc'd array containing the username of the whoever has the lock.
100 Will always be non-NULL in the cases where it is needed. */
101 static char *lockers_name;
102 /* Malloc'd array specifying name of a readlock within a directory.
104 static char *readlock;
105 /* Malloc'd array specifying name of a writelock within a directory.
107 static char *writelock;
108 /* Malloc'd array specifying name of a promotablelock within a directory.
110 static char *promotablelock;
111 /* Malloc'd array specifying the name of a CVSLCK file (absolute pathname).
112 Will always be non-NULL in the cases where it is used. */
113 static char *masterlock;
114 static List *locklist;
116 #define L_OK 0 /* success */
117 #define L_ERROR 1 /* error condition */
118 #define L_LOCKED 2 /* lock owned by someone else */
120 /* This is the (single) readlock which is set by Reader_Lock. The
121 repository field is NULL if there is no such lock. */
122 static struct lock global_readlock;
123 static struct lock global_writelock;
125 /* List of locks set by lock_tree_for_write. This is redundant
126 with locklist, sort of. */
127 static List *lock_tree_list;
131 /* Return a newly malloc'd string containing the name of the lock for the
132 repository REPOSITORY and the lock file name within that directory
133 NAME. Also create the directories in which to put the lock file
134 if needed (if we need to, could save system call(s) by doing
135 that only if the actual operation fails. But for now we'll keep
138 lock_name (const char *repository, const char *name)
143 const char *short_repos;
144 mode_t save_umask = 0000;
147 TRACE (TRACE_FLOW, "lock_name (%s, %s)",
148 repository ? repository : "(null)", name ? name : "(null)");
150 if (!config->lock_dir)
152 /* This is the easy case. Because the lock files go directly
153 in the repository, no need to create directories or anything. */
154 assert (name != NULL);
155 assert (repository != NULL);
156 retval = xmalloc (strlen (repository) + strlen (name) + 10);
157 (void) sprintf (retval, "%s/%s", repository, name);
164 /* The interesting part of the repository is the part relative
166 assert (current_parsed_root != NULL);
167 assert (current_parsed_root->directory != NULL);
168 assert (strncmp (repository, current_parsed_root->directory,
169 strlen (current_parsed_root->directory)) == 0);
170 short_repos = repository + strlen (current_parsed_root->directory) + 1;
172 if (strcmp (repository, current_parsed_root->directory) == 0)
175 assert (short_repos[-1] == '/');
177 retval = xmalloc (strlen (config->lock_dir)
178 + strlen (short_repos)
181 strcpy (retval, config->lock_dir);
182 q = retval + strlen (retval);
185 strcpy (q, short_repos);
187 /* In the common case, where the directory already exists, let's
188 keep it to one system call. */
189 if (CVS_STAT (retval, &sb) < 0)
191 /* If we need to be creating more than one directory, we'll
192 get the existence_error here. */
193 if (!existence_error (errno))
194 error (1, errno, "cannot stat directory %s", retval);
198 if (S_ISDIR (sb.st_mode))
201 error (1, 0, "%s is not a directory", retval);
204 /* Now add the directories one at a time, so we can create
207 The idea behind the new_mode stuff is that the directory we
208 end up creating will inherit permissions from its parent
209 directory (we re-set new_mode with each EEXIST). CVSUMASK
210 isn't right, because typically the reason for LockDir is to
211 use a different set of permissions. We probably want to
212 inherit group ownership also (but we don't try to deal with
213 that, some systems do it for us either always or when g+s is on).
215 We don't try to do anything about the permissions on the lock
216 files themselves. The permissions don't really matter so much
217 because the locks will generally be removed by the process
218 which created them. */
220 if (CVS_STAT (config->lock_dir, &sb) < 0)
221 error (1, errno, "cannot stat %s", config->lock_dir);
222 new_mode = sb.st_mode;
223 save_umask = umask (0000);
229 while (!ISSLASH (*p) && *p != '\0')
233 strncpy (q, short_repos, p - short_repos);
234 q[p - short_repos] = '\0';
235 if (!ISSLASH (q[p - short_repos - 1])
236 && CVS_MKDIR (retval, new_mode) < 0)
238 int saved_errno = errno;
239 if (saved_errno != EEXIST)
240 error (1, errno, "cannot make directory %s", retval);
243 if (CVS_STAT (retval, &sb) < 0)
244 error (1, errno, "cannot stat %s", retval);
245 new_mode = sb.st_mode;
252 strcpy (q, short_repos);
253 if (CVS_MKDIR (retval, new_mode) < 0
255 error (1, errno, "cannot make directory %s", retval);
261 strcat (retval, "/");
262 strcat (retval, name);
266 assert (umask (save_umask) == 0000);
275 /* Remove the lock files. For interrupt purposes, it can be assumed that the
276 * first thing this function does is set lock->repository to NULL.
279 * lock The lock to remove.
280 * free True if this lock directory will not5 be reused (free
281 * lock->repository if necessary).
284 remove_lock_files (struct lock *lock, int free_repository)
286 TRACE (TRACE_FLOW, "remove_lock_files (%s)", lock->repository);
288 /* If lock->file is set, the lock *might* have been created, but since
289 * Reader_Lock & lock_dir_for_write don't use SIG_beginCrSect the way that
290 * set_lock does, we don't know that. That is why we need to check for
291 * existence_error here.
295 char *tmp = lock->file1;
297 if (CVS_UNLINK (tmp) < 0 && ! existence_error (errno))
298 error (0, errno, "failed to remove lock %s", tmp);
301 #ifdef LOCK_COMPATIBILITY
304 char *tmp = lock->file2;
306 if (CVS_UNLINK (tmp) < 0 && ! existence_error (errno))
307 error (0, errno, "failed to remove lock %s", tmp);
310 #endif /* LOCK_COMPATIBILITY */
312 if (lock->have_lckdir)
314 char *tmp = lock_name (lock->repository, CVSLCK);
316 if (CVS_RMDIR (tmp) < 0)
317 error (0, errno, "failed to remove lock dir %s", tmp);
318 lock->have_lckdir = 0;
323 /* And free the repository string. We don't really have to set the
324 * repository string to NULL first since there is no harm in running any of
325 * the above code twice.
327 * Use SIG_beginCrSect since otherwise we might be interrupted between
328 * checking whether free_repository is set and freeing stuff.
333 if (lock->free_repository)
335 free ((char *)lock->repository);
336 lock->free_repository = 0;
338 lock->repository = NULL;
346 * Clean up outstanding read and write locks and free their storage.
349 Simple_Lock_Cleanup (void)
351 TRACE (TRACE_FUNCTION, "Simple_Lock_Cleanup()");
353 /* Avoid interrupts while accessing globals the interrupt handlers might
358 /* clean up simple read locks (if any) */
359 if (global_readlock.repository != NULL)
360 remove_lock_files (&global_readlock, 1);
361 /* See note in Lock_Cleanup() below. */
366 /* clean up simple write locks (if any) */
367 if (global_writelock.repository != NULL)
368 remove_lock_files (&global_writelock, 1);
369 /* See note in Lock_Cleanup() below. */
376 * Clean up all outstanding locks and free their storage.
379 * This function needs to be reentrant since a call to exit() can cause a
380 * call to this function, which can then be interrupted by a signal, which
381 * can cause a second call to this function.
389 TRACE (TRACE_FUNCTION, "Lock_Cleanup()");
391 /* FIXME: Do not perform buffered I/O from an interrupt handler like
392 * this (via error). However, I'm leaving the error-calling code there
393 * in the hope that on the rare occasion the error call is actually made
394 * (e.g., a fluky I/O error or permissions problem prevents the deletion
395 * of a just-created file) reentrancy won't be an issue.
400 /* Avoid being interrupted during calls which set globals to NULL. This
401 * avoids having interrupt handlers attempt to use these global variables
402 * in inconsistent states.
404 * This isn't always necessary, because sometimes we are called via exit()
405 * or the interrupt handler, in which case signals will already be blocked,
406 * but sometimes we might be called from elsewhere.
409 dellist (&lock_tree_list);
410 /* Unblocking allows any signal to be processed as soon as possible. This
411 * isn't really necessary, but since we know signals can cause us to be
412 * called, why not avoid having blocks of code run twice.
420 * walklist proc for removing a list of locks
423 unlock_proc (Node *p, void *closure)
425 remove_lock_files (p->data, 0);
432 * Remove locks without discarding the lock information.
437 TRACE (TRACE_FLOW, "remove_locks()");
439 Simple_Lock_Cleanup ();
441 /* clean up promotable locks (if any) */
443 if (locklist != NULL)
445 /* Use a tmp var since any of these functions could call exit, causing
446 * us to be called a second time.
448 List *tmp = locklist;
450 walklist (tmp, unlock_proc, NULL);
458 * Set the global readlock variable if it isn't already.
461 set_readlock_name (void)
463 if (readlock == NULL)
465 readlock = xmalloc (strlen (hostname) + sizeof (CVSRFL) + 40);
466 (void) sprintf (readlock,
467 #ifdef HAVE_LONG_FILE_NAMES
468 "%s.%s.%ld", CVSRFL, hostname,
479 * Create a lock file for readers
482 Reader_Lock (char *xrepository)
487 TRACE (TRACE_FUNCTION, "Reader_Lock(%s)", xrepository);
489 if (noexec || readonlyfs)
492 /* we only do one directory at a time for read locks! */
493 if (global_readlock.repository != NULL)
495 error (0, 0, "Reader_Lock called while read locks set - Help!");
499 set_readlock_name ();
501 /* remember what we're locking (for Lock_Cleanup) */
502 global_readlock.repository = xstrdup (xrepository);
503 global_readlock.free_repository = 1;
505 /* get the lock dir for our own */
506 if (set_lock (&global_readlock, 1) != L_OK)
508 error (0, 0, "failed to obtain dir lock in repository `%s'",
510 if (readlock != NULL)
513 /* We don't set global_readlock.repository to NULL. I think this
514 only works because recurse.c will give a fatal error if we return
519 /* write a read-lock */
520 global_readlock.file1 = lock_name (xrepository, readlock);
521 if ((fp = CVS_FOPEN (global_readlock.file1, "w+")) == NULL
522 || fclose (fp) == EOF)
524 error (0, errno, "cannot create read lock in repository `%s'",
529 /* free the lock dir */
530 clear_lock (&global_readlock);
538 * lock_exists() returns 0 if there is no lock file matching FILEPAT in
539 * the repository but not IGNORE; else 1 is returned, to indicate that the
540 * caller should sleep a while and try again.
543 * repository The repository directory to search for locks.
544 * filepat The file name pattern to search for.
545 * ignore The name of a single file which can be ignored.
548 * lockdir The lock dir external to the repository, if any.
551 * 0 No lock matching FILEPAT and not IGNORE exists.
552 * 1 Otherwise and on error.
555 * In the case where errors are encountered reading the directory, a warning
556 * message is printed, 1 is is returned and ERRNO is left set.
559 lock_exists (const char *repository, const char *filepat, const char *ignore)
567 #ifdef CVS_FUDGELOCKS
572 TRACE (TRACE_FLOW, "lock_exists (%s, %s, %s)",
573 repository, filepat, ignore ? ignore : "(null)");
575 lockdir = lock_name (repository, "");
576 lockdir[strlen (lockdir) - 1] = '\0'; /* remove trailing slash */
579 if ((dirp = CVS_OPENDIR (lockdir)) == NULL)
580 error (1, 0, "cannot open directory %s", lockdir);
584 while ((dp = CVS_READDIR (dirp)) != NULL)
586 if (CVS_FNMATCH (filepat, dp->d_name, 0) == 0)
588 /* FIXME: the basename conversion below should be replaced with
589 * a call to the GNULIB basename function once it is imported.
591 /* ignore our plock, if any */
592 if (ignore && !fncmp (ignore, dp->d_name))
595 line = xmalloc (strlen (lockdir) + 1 + strlen (dp->d_name) + 1);
596 (void)sprintf (line, "%s/%s", lockdir, dp->d_name);
597 if (CVS_STAT (line, &sb) != -1)
599 #ifdef CVS_FUDGELOCKS
601 * If the create time of the file is more than CVSLCKAGE
602 * seconds ago, try to clean-up the lock file, and if
603 * successful, re-open the directory and try again.
605 if (now >= (sb.st_ctime + CVSLCKAGE) &&
606 CVS_UNLINK (line) != -1)
613 set_lockers_name (&sb);
617 /* If the file doesn't exist, it just means that it
618 * disappeared between the time we did the readdir and the
619 * time we did the stat.
621 if (!existence_error (errno))
622 error (0, errno, "cannot stat %s", line);
632 error (0, errno, "error reading directory %s", repository);
645 * readers_exist() returns 0 if there are no reader lock files remaining in
646 * the repository; else 1 is returned, to indicate that the caller should
647 * sleep a while and try again.
649 * See lock_exists() for argument detail.
652 readers_exist (const char *repository)
654 TRACE (TRACE_FLOW, "readers_exist (%s)", repository);
656 /* It is only safe to ignore a readlock set by our process if it was set as
657 * a safety measure to prevent older CVS processes from ignoring our
658 * promotable locks. The code to ignore these readlocks can be removed
659 * once it is deemed unlikely that anyone will be using CVS servers earlier
660 * than version 1.12.4.
662 return lock_exists (repository, CVSRFLPAT,
663 #ifdef LOCK_COMPATIBILITY
664 findnode (locklist, repository) ? readlock :
665 #endif /* LOCK_COMPATIBILITY */
672 * promotable_exists() returns 0 if there is no promotable lock file in
673 * the repository; else 1 is returned, to indicate that the caller should
674 * sleep a while and try again.
676 * See lock_exists() for argument detail.
679 promotable_exists (const char *repository)
681 TRACE (TRACE_FLOW, "promotable_exists (%s)", repository);
682 return lock_exists (repository, CVSPFLPAT, promotablelock);
688 * Lock a list of directories for writing
690 static char *lock_error_repos;
691 static int lock_error;
696 * Create a lock file for potential writers returns L_OK if lock set ok,
697 * L_LOCKED if lock held by someone else or L_ERROR if an error occurred.
700 set_promotable_lock (struct lock *lock)
705 TRACE (TRACE_FUNCTION, "set_promotable_lock(%s)",
706 lock->repository ? lock->repository : "(null)");
708 if (promotablelock == NULL)
710 promotablelock = xmalloc (strlen (hostname) + sizeof (CVSPFL) + 40);
711 (void) sprintf (promotablelock,
712 #ifdef HAVE_LONG_FILE_NAMES
713 "%s.%s.%ld", CVSPFL, hostname,
720 /* make sure the lock dir is ours (not necessarily unique to us!) */
721 status = set_lock (lock, 0);
724 /* we now own a promotable lock - make sure there are no others */
725 if (promotable_exists (lock->repository))
727 /* clean up the lock dir */
730 /* indicate we failed due to read locks instead of error */
734 /* write the promotable-lock file */
735 lock->file1 = lock_name (lock->repository, promotablelock);
736 if ((fp = CVS_FOPEN (lock->file1, "w+")) == NULL || fclose (fp) == EOF)
740 if (CVS_UNLINK (lock->file1) < 0 && ! existence_error (errno))
741 error (0, errno, "failed to remove lock %s", lock->file1);
743 /* free the lock dir */
746 /* return the error */
748 "cannot create promotable lock in repository `%s'",
753 #ifdef LOCK_COMPATIBILITY
754 /* write the read-lock file. We only do this so that older versions of
755 * CVS will not think it is okay to create a write lock. When it is
756 * decided that versions of CVS earlier than 1.12.4 are not likely to
757 * be used, this code can be removed.
759 set_readlock_name ();
760 lock->file2 = lock_name (lock->repository, readlock);
761 if ((fp = CVS_FOPEN (lock->file2, "w+")) == NULL || fclose (fp) == EOF)
765 if ( CVS_UNLINK (lock->file2) < 0 && ! existence_error (errno))
766 error (0, errno, "failed to remove lock %s", lock->file2);
768 /* free the lock dir */
771 /* Remove the promotable lock. */
773 remove_lock_files (lock, 0);
775 /* return the error */
777 "cannot create read lock in repository `%s'",
781 #endif /* LOCK_COMPATIBILITY */
794 * walklist proc for setting write locks. Mostly just a wrapper for the
795 * set_promotable_lock function, which has a prettier API, but no other good
796 * reason for existing separately.
799 * p The current node, as determined by walklist().
803 * lock_error Any previous error encountered while attempting to get
807 * lock_error Set if we encounter an error attempting to get axi
809 * lock_error_repos Set so that if we set lock_error later functions will
810 * be able to report where the other process's lock was
817 set_promotablelock_proc (Node *p, void *closure)
819 /* if some lock was not OK, just skip this one */
820 if (lock_error != L_OK)
823 /* apply the write lock */
824 lock_error_repos = p->key;
825 lock_error = set_promotable_lock ((struct lock *)p->data);
832 * Print out a message that the lock is still held, then sleep a while.
835 lock_wait (const char *repos)
842 tm_p = gmtime (&now);
843 msg = xmalloc (100 + strlen (lockers_name) + strlen (repos));
844 sprintf (msg, "[%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 = xmalloc (100 + strlen (repos));
870 sprintf (msg, "[%8.8s] obtained lock in %s",
871 (tm_p ? asctime (tm_p) : ctime (&now)) + 11, repos);
872 error (0, 0, "%s", msg);
873 /* Call cvs_flusherr to ensure that the user sees this message as
882 lock_list_promotably (List *list)
886 TRACE (TRACE_FLOW, "lock_list_promotably ()");
893 "promotable lock failed.\n\
894 WARNING: Read-only repository access mode selected via `cvs -R'.\n\
895 Attempting to write to a read-only filesystem is not allowed.");
899 /* We only know how to do one list at a time */
900 if (locklist != (List *) NULL)
903 "lock_list_promotably called while promotable locks set - Help!");
910 /* try to lock everything on the list */
911 lock_error = L_OK; /* init for set_promotablelock_proc */
912 lock_error_repos = (char *) NULL; /* init for set_promotablelock_proc */
913 locklist = list; /* init for Lock_Cleanup */
914 if (lockers_name != NULL)
916 lockers_name = xstrdup ("unknown");
918 (void) walklist (list, set_promotablelock_proc, NULL);
922 case L_ERROR: /* Real Error */
923 if (wait_repos != NULL)
925 Lock_Cleanup (); /* clean up any locks we set */
926 error (0, 0, "lock failed - giving up");
929 case L_LOCKED: /* Someone already had a lock */
930 remove_locks (); /* clean up any locks we set */
931 lock_wait (lock_error_repos); /* sleep a while and try again */
932 wait_repos = xstrdup (lock_error_repos);
935 case L_OK: /* we got the locks set */
936 if (wait_repos != NULL)
938 lock_obtained (wait_repos);
944 if (wait_repos != NULL)
946 error (0, 0, "unknown lock status %d in lock_list_promotably",
956 * Set the static variable lockers_name appropriately, based on the stat
957 * structure passed in.
960 set_lockers_name (struct stat *statp)
964 if (lockers_name != NULL)
966 if ((pw = (struct passwd *)getpwuid (statp->st_uid)) !=
967 (struct passwd *)NULL)
969 lockers_name = xstrdup (pw->pw_name);
973 lockers_name = xmalloc (20);
974 (void)sprintf (lockers_name, "uid%lu", (unsigned long) statp->st_uid);
981 * Persistently tries to make the directory "lckdir", which serves as a
984 * #ifdef CVS_FUDGELOCKS
985 * If the create time on the directory is greater than CVSLCKAGE
986 * seconds old, just try to remove the directory.
991 set_lock (struct lock *lock, int will_wait)
997 #ifdef CVS_FUDGELOCKS
1001 TRACE (TRACE_FLOW, "set_lock (%s, %d)",
1002 lock->repository ? lock->repository : "(null)", will_wait);
1004 if (masterlock != NULL)
1006 masterlock = lock_name (lock->repository, CVSLCK);
1009 * Note that it is up to the callers of set_lock() to arrange for signal
1010 * handlers that do the appropriate things, like remove the lock
1011 * directory before they exit.
1015 lock->have_lckdir = 0;
1019 omask = umask (cvsumask);
1021 if (CVS_MKDIR (masterlock, 0777) == 0)
1023 lock->have_lckdir = 1;
1027 lock_obtained (lock->repository);
1032 (void) umask (omask);
1036 if (errno != EEXIST)
1039 "failed to create lock directory for `%s' (%s)",
1040 lock->repository, masterlock);
1044 /* Find out who owns the lock. If the lock directory is
1045 non-existent, re-try the loop since someone probably just
1046 removed it (thus releasing the lock). */
1047 if (CVS_STAT (masterlock, &sb) < 0)
1049 if (existence_error (errno))
1052 error (0, errno, "couldn't stat lock directory `%s'", masterlock);
1056 #ifdef CVS_FUDGELOCKS
1058 * If the create time of the directory is more than CVSLCKAGE seconds
1059 * ago, try to clean-up the lock directory, and if successful, just
1060 * quietly retry to make it.
1063 if (now >= (sb.st_ctime + CVSLCKAGE))
1065 if (CVS_RMDIR (masterlock) >= 0)
1070 /* set the lockers name */
1071 set_lockers_name (&sb);
1073 /* if he wasn't willing to wait, return an error */
1077 /* if possible, try a very short sleep without a message */
1078 if (!waited && us < 1000)
1084 ts.tv_nsec = us * 1000;
1085 (void)nanosleep (&ts, NULL);
1090 lock_wait (lock->repository);
1098 * Clear master lock. We don't have to recompute the lock name since
1099 * clear_lock is never called except after a successful set_lock().
1102 clear_lock (struct lock *lock)
1105 if (CVS_RMDIR (masterlock) < 0)
1106 error (0, errno, "failed to remove lock dir `%s'", masterlock);
1107 lock->have_lckdir = 0;
1114 * Create a list of repositories to lock
1118 lock_filesdoneproc (void *callerdat, int err, const char *repository,
1119 const char *update_dir, List *entries)
1125 p->key = xstrdup (repository);
1126 p->data = xmalloc (sizeof (struct lock));
1127 ((struct lock *)p->data)->repository = p->key;
1128 ((struct lock *)p->data)->file1 = NULL;
1129 #ifdef LOCK_COMPATIBILITY
1130 ((struct lock *)p->data)->file2 = NULL;
1131 #endif /* LOCK_COMPATIBILITY */
1132 ((struct lock *)p->data)->have_lckdir = 0;
1133 ((struct lock *)p->data)->free_repository = 0;
1135 /* FIXME-KRP: this error condition should not simply be passed by. */
1136 if (p->key == NULL || addnode (lock_tree_list, p) != 0)
1144 lock_tree_promotably (int argc, char **argv, int local, int which, int aflag)
1146 TRACE (TRACE_FUNCTION, "lock_tree_promotably (%d, argv, %d, %d, %d)",
1147 argc, local, which, aflag);
1150 * Run the recursion processor to find all the dirs to lock and lock all
1153 lock_tree_list = getlist ();
1155 (NULL, lock_filesdoneproc,
1156 NULL, NULL, NULL, argc,
1157 argv, local, which, aflag, CVS_LOCK_NONE,
1159 sortlist (lock_tree_list, fsortcmp);
1160 if (lock_list_promotably (lock_tree_list) != 0)
1161 error (1, 0, "lock failed - giving up");
1166 /* Lock a single directory in REPOSITORY. It is OK to call this if
1167 * a lock has been set with lock_dir_for_write; the new lock will replace
1168 * the old one. If REPOSITORY is NULL, don't do anything.
1170 * We do not clear the dir lock after writing the lock file name since write
1171 * locks are exclusive to all other locks.
1174 lock_dir_for_write (const char *repository)
1178 TRACE (TRACE_FLOW, "lock_dir_for_write (%s)", repository);
1180 if (repository != NULL
1181 && (global_writelock.repository == NULL
1182 || !strcmp (global_writelock.repository, repository)))
1184 if (writelock == NULL)
1186 writelock = xmalloc (strlen (hostname) + sizeof (CVSWFL) + 40);
1187 (void) sprintf (writelock,
1188 #ifdef HAVE_LONG_FILE_NAMES
1189 "%s.%s.%ld", CVSWFL, hostname,
1196 if (global_writelock.repository != NULL)
1197 remove_lock_files (&global_writelock, 1);
1199 global_writelock.repository = xstrdup (repository);
1200 global_writelock.free_repository = 1;
1206 if (set_lock (&global_writelock, 1) != L_OK)
1207 error (1, 0, "failed to obtain write lock in repository `%s'",
1210 /* check if readers exist */
1211 if (readers_exist (repository)
1212 || promotable_exists (repository))
1214 clear_lock (&global_writelock);
1215 lock_wait (repository); /* sleep a while and try again */
1221 lock_obtained (repository);
1223 /* write the write-lock file */
1224 global_writelock.file1 = lock_name (global_writelock.repository,
1226 if ((fp = CVS_FOPEN (global_writelock.file1, "w+")) == NULL
1227 || fclose (fp) == EOF)
1231 if (CVS_UNLINK (global_writelock.file1) < 0
1232 && !existence_error (errno))
1234 error (0, errno, "failed to remove write lock %s",
1235 global_writelock.file1);
1238 /* free the lock dir */
1239 clear_lock (&global_writelock);
1241 /* return the error */
1243 "cannot create write lock in repository `%s'",
1244 global_writelock.repository);
1247 /* If we upgraded from a promotable lock, remove it. */
1250 Node *p = findnode (locklist, repository);
1253 remove_lock_files (p->data, 1);