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 /* The name of the master lock dir. Usually CVSLCK. */
92 const char *lockdirname
;
94 /* The full path to the lock dir, if we are currently holding it.
96 * This will be LOCKDIRNAME catted onto REPOSITORY. We waste a little
97 * space by storing it, but save a later malloc/free.
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
;
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
);
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.
117 static char *readlock
;
118 /* Malloc'd array specifying name of a writelock within a directory.
120 static char *writelock
;
121 /* Malloc'd array specifying name of a promotablelock within a directory.
123 static char *promotablelock
;
124 static List
*locklist
;
126 #define L_OK 0 /* success */
127 #define L_ERROR 1 /* error condition */
128 #define L_LOCKED 2 /* lock owned by someone else */
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};
136 static struct lock global_history_lock
= {NULL
, NULL
, NULL
, CVSHISTORYLCK
,
138 static struct lock global_val_tags_lock
= {NULL
, NULL
, NULL
, CVSVALTAGSLCK
,
141 static struct lock global_readlock
= {NULL
, NULL
, CVSLCK
, NULL
, false};
142 static struct lock global_writelock
= {NULL
, NULL
, CVSLCK
, NULL
, false};
144 static struct lock global_history_lock
= {NULL
, NULL
, CVSHISTORYLCK
, NULL
,
146 static struct lock global_val_tags_lock
= {NULL
, NULL
, CVSVALTAGSLCK
, NULL
,
148 #endif /* LOCK_COMPATIBILITY */
150 /* List of locks set by lock_tree_for_write. This is redundant
151 with locklist, sort of. */
152 static List
*lock_tree_list
;
156 * Find the root directory in the repository directory
159 find_root (const char *repository
, char *rootdir
)
161 struct stat strep
, stroot
;
162 char *p
= NULL
, *q
= NULL
;
165 if (stat (rootdir
, &stroot
) == -1)
167 len
= strlen (repository
);
170 len
= p
- repository
;
175 if (stat(repository
, &strep
) == -1) {
180 if (strep
.st_dev
== stroot
.st_dev
&& strep
.st_ino
== stroot
.st_ino
) {
188 } while ((p
= strrchr (repository
, '/')) != NULL
);
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
199 lock_name (const char *repository
, const char *name
)
204 const char *short_repos
;
205 mode_t save_umask
= 0000;
206 int saved_umask
= 0, len
;
208 TRACE (TRACE_FLOW
, "lock_name (%s, %s)",
209 repository
? repository
: "(null)", name
? name
: "(null)");
211 if (!config
->lock_dir
)
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
);
224 /* The interesting part of the repository is the part relative
226 assert (current_parsed_root
!= NULL
);
227 assert (current_parsed_root
->directory
!= NULL
);
229 * Unfortunately, string comparisons are not enough because we
230 * might have symlinks present
232 len
= find_root(repository
, current_parsed_root
->directory
);
234 short_repos
= repository
+ len
+ 1;
236 if (strcmp (repository
, current_parsed_root
->directory
) == 0)
239 assert (short_repos
[-1] == '/');
241 retval
= xmalloc (strlen (config
->lock_dir
)
242 + strlen (short_repos
)
245 strcpy (retval
, config
->lock_dir
);
246 q
= retval
+ strlen (retval
);
249 strcpy (q
, short_repos
);
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)
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
);
262 if (S_ISDIR (sb
.st_mode
))
265 error (1, 0, "%s is not a directory", retval
);
268 /* Now add the directories one at a time, so we can create
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).
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. */
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);
293 while (!ISSLASH (*p
) && *p
!= '\0')
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)
302 int saved_errno
= errno
;
303 if (saved_errno
!= EEXIST
)
304 error (1, errno
, "cannot make directory %s", retval
);
307 if (stat (retval
, &sb
) < 0)
308 error (1, errno
, "cannot stat %s", retval
);
309 new_mode
= sb
.st_mode
;
316 strcpy (q
, short_repos
);
317 if (CVS_MKDIR (retval
, new_mode
) < 0
319 error (1, errno
, "cannot make directory %s", retval
);
325 strcat (retval
, "/");
326 strcat (retval
, name
);
330 assert (umask (save_umask
) == 0000);
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.
343 * lock The lock to remove.
344 * free True if this lock directory will not be reused (free
345 * lock->repository if necessary).
348 remove_lock_files (struct lock
*lock
, bool free_repository
)
350 TRACE (TRACE_FLOW
, "remove_lock_files (%s)", lock
->repository
);
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.
359 char *tmp
= lock
->file1
;
361 if (CVS_UNLINK (tmp
) < 0 && ! existence_error (errno
))
362 error (0, errno
, "failed to remove lock %s", tmp
);
365 #ifdef LOCK_COMPATIBILITY
368 char *tmp
= lock
->file2
;
370 if (CVS_UNLINK (tmp
) < 0 && ! existence_error (errno
))
371 error (0, errno
, "failed to remove lock %s", tmp
);
374 #endif /* LOCK_COMPATIBILITY */
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.
382 * Use SIG_beginCrSect since otherwise we might be interrupted between
383 * checking whether free_repository is set and freeing stuff.
388 if (lock
->free_repository
)
390 free ((char *)lock
->repository
);
391 lock
->free_repository
= false;
393 lock
->repository
= NULL
;
401 * Clean up outstanding read and write locks and free their storage.
404 Simple_Lock_Cleanup (void)
406 TRACE (TRACE_FUNCTION
, "Simple_Lock_Cleanup()");
408 /* Avoid interrupts while accessing globals the interrupt handlers might
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. */
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. */
429 /* clean up simple write locks (if any) */
430 if (global_history_lock
.repository
)
431 remove_lock_files (&global_history_lock
, true);
436 if (global_val_tags_lock
.repository
)
437 remove_lock_files (&global_val_tags_lock
, true);
438 /* See note in Lock_Cleanup() below. */
445 * Clean up all outstanding locks and free their storage.
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.
458 TRACE (TRACE_FUNCTION
, "Lock_Cleanup()");
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.
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.
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.
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.
489 * walklist proc for removing a list of locks
492 unlock_proc (Node
*p
, void *closure
)
494 remove_lock_files (p
->data
, false);
501 * Remove locks without discarding the lock information.
506 TRACE (TRACE_FLOW
, "remove_locks()");
508 Simple_Lock_Cleanup ();
510 /* clean up promotable locks (if any) */
512 if (locklist
!= NULL
)
514 /* Use a tmp var since any of these functions could call exit, causing
515 * us to be called a second time.
517 List
*tmp
= locklist
;
519 walklist (tmp
, unlock_proc
, NULL
);
527 * Set the global readlock variable if it isn't already.
530 set_readlock_name (void)
532 if (readlock
== NULL
)
534 readlock
= Xasprintf (
535 #ifdef HAVE_LONG_FILE_NAMES
536 "%s.%s.%ld", CVSRFL
, hostname
,
547 * Create a lock file for readers
550 Reader_Lock (char *xrepository
)
558 TRACE (TRACE_FUNCTION
, "Reader_Lock(%s)", xrepository
);
560 if (noexec
|| readonlyfs
)
563 /* we only do one directory at a time for read locks! */
564 if (global_readlock
.repository
!= NULL
)
566 error (0, 0, "Reader_Lock called while read locks set - Help!");
570 set_readlock_name ();
572 /* remember what we're locking (for Lock_Cleanup) */
573 global_readlock
.repository
= xstrdup (xrepository
);
574 global_readlock
.free_repository
= true;
576 /* get the lock dir for our own */
577 if (set_lock (&global_readlock
, 1) != L_OK
)
579 error (0, 0, "failed to obtain dir lock in repository `%s'",
581 if (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
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
)
595 error (0, errno
, "cannot create read lock in repository `%s'",
600 /* free the lock dir */
601 clear_lock (&global_readlock
);
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.
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.
619 * lockdir The lock dir external to the repository, if any.
622 * 0 No lock matching FILEPAT and not IGNORE exists.
623 * 1 Otherwise and on error.
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.
630 lock_exists (const char *repository
, const char *filepat
, const char *ignore
)
638 #ifdef CVS_FUDGELOCKS
643 TRACE (TRACE_FLOW
, "lock_exists (%s, %s, %s)",
644 repository
, filepat
, ignore
? ignore
: "(null)");
646 lockdir
= lock_name (repository
, "");
647 lockdir
[strlen (lockdir
) - 1] = '\0'; /* remove trailing slash */
650 if ((dirp
= CVS_OPENDIR (lockdir
)) == NULL
)
651 error (1, 0, "cannot open directory %s", lockdir
);
655 while ((dp
= CVS_READDIR (dirp
)) != NULL
)
657 if (CVS_FNMATCH (filepat
, dp
->d_name
, 0) == 0)
659 /* FIXME: the basename conversion below should be replaced with
660 * a call to the GNULIB basename function once it is imported.
662 /* ignore our plock, if any */
663 if (ignore
&& !fncmp (ignore
, dp
->d_name
))
666 line
= Xasprintf ("%s/%s", lockdir
, dp
->d_name
);
667 if (stat (line
, &sb
) != -1)
669 #ifdef CVS_FUDGELOCKS
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.
675 if (now
>= (sb
.st_ctime
+ CVSLCKAGE
) &&
676 CVS_UNLINK (line
) != -1)
683 set_lockers_name (&sb
);
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.
691 if (!existence_error (errno
))
692 error (0, errno
, "cannot stat %s", line
);
702 error (0, errno
, "error reading directory %s", repository
);
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.
719 * See lock_exists() for argument detail.
722 readers_exist (const char *repository
)
724 TRACE (TRACE_FLOW
, "readers_exist (%s)", repository
);
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.
732 return lock_exists (repository
, CVSRFLPAT
,
733 #ifdef LOCK_COMPATIBILITY
734 findnode (locklist
, repository
) ? readlock
:
735 #endif /* LOCK_COMPATIBILITY */
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.
746 * See lock_exists() for argument detail.
749 promotable_exists (const char *repository
)
751 TRACE (TRACE_FLOW
, "promotable_exists (%s)", repository
);
752 return lock_exists (repository
, CVSPFLPAT
, promotablelock
);
758 * Lock a list of directories for writing
760 static char *lock_error_repos
;
761 static int lock_error
;
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.
770 set_promotable_lock (struct lock
*lock
)
775 TRACE (TRACE_FUNCTION
, "set_promotable_lock(%s)",
776 lock
->repository
? lock
->repository
: "(null)");
778 if (promotablelock
== NULL
)
780 promotablelock
= Xasprintf (
781 #ifdef HAVE_LONG_FILE_NAMES
782 "%s.%s.%ld", CVSPFL
, hostname
,
789 /* make sure the lock dir is ours (not necessarily unique to us!) */
790 status
= set_lock (lock
, 0);
793 /* we now own a promotable lock - make sure there are no others */
794 if (promotable_exists (lock
->repository
))
796 /* clean up the lock dir */
799 /* indicate we failed due to read locks instead of error */
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
)
809 if (CVS_UNLINK (lock
->file1
) < 0 && ! existence_error (errno
))
810 error (0, errno
, "failed to remove lock %s", lock
->file1
);
812 /* free the lock dir */
815 /* return the error */
817 "cannot create promotable lock in repository `%s'",
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.
828 set_readlock_name ();
829 lock
->file2
= lock_name (lock
->repository
, readlock
);
830 if ((fp
= CVS_FOPEN (lock
->file2
, "w+")) == NULL
|| fclose (fp
) == EOF
)
834 if ( CVS_UNLINK (lock
->file2
) < 0 && ! existence_error (errno
))
835 error (0, errno
, "failed to remove lock %s", lock
->file2
);
837 /* free the lock dir */
840 /* Remove the promotable lock. */
842 remove_lock_files (lock
, false);
844 /* return the error */
846 "cannot create read lock in repository `%s'",
850 #endif /* LOCK_COMPATIBILITY */
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.
868 * p The current node, as determined by walklist().
872 * lock_error Any previous error encountered while attempting to get
876 * lock_error Set if we encounter an error attempting to get axi
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
886 set_promotablelock_proc (Node
*p
, void *closure
)
888 /* if some lock was not OK, just skip this one */
889 if (lock_error
!= L_OK
)
892 /* apply the write lock */
893 lock_error_repos
= p
->key
;
894 lock_error
= set_promotable_lock ((struct lock
*)p
->data
);
901 * Print out a message that the lock is still held, then sleep a while.
904 lock_wait (const char *repos
)
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
920 (void)sleep (CVSLCKSLEEP
);
926 * Print out a message when we obtain a lock.
929 lock_obtained (const char *repos
)
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
949 lock_list_promotably (List
*list
)
953 TRACE (TRACE_FLOW
, "lock_list_promotably ()");
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.");
968 /* We only know how to do one list at a time */
969 if (locklist
!= NULL
)
972 "lock_list_promotably called while promotable locks set - Help!");
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
)
985 lockers_name
= xstrdup ("unknown");
987 (void) walklist (list
, set_promotablelock_proc
, NULL
);
991 case L_ERROR
: /* Real Error */
992 if (wait_repos
!= NULL
)
994 Lock_Cleanup (); /* clean up any locks we set */
995 error (0, 0, "lock failed - giving up");
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
);
1004 case L_OK
: /* we got the locks set */
1005 if (wait_repos
!= NULL
)
1007 lock_obtained (wait_repos
);
1013 if (wait_repos
!= NULL
)
1015 error (0, 0, "unknown lock status %d in lock_list_promotably",
1025 * Set the static variable lockers_name appropriately, based on the stat
1026 * structure passed in.
1029 set_lockers_name (struct stat
*statp
)
1033 if (lockers_name
!= NULL
)
1034 free (lockers_name
);
1035 pw
= (struct passwd
*) getpwuid (statp
->st_uid
);
1037 lockers_name
= xstrdup (pw
->pw_name
);
1039 lockers_name
= Xasprintf ("uid%lu", (unsigned long) statp
->st_uid
);
1045 * Persistently tries to make the directory "lckdir", which serves as a
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.
1055 set_lock (struct lock
*lock
, int will_wait
)
1063 #ifdef CVS_FUDGELOCKS
1067 TRACE (TRACE_FLOW
, "set_lock (%s, %d)",
1068 lock
->repository
? lock
->repository
: "(null)", will_wait
);
1070 masterlock
= lock_name (lock
->repository
, lock
->lockdirname
);
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.
1082 omask
= umask (cvsumask
);
1084 if (CVS_MKDIR (masterlock
, 0777) == 0)
1086 lock
->lockdir
= masterlock
;
1090 lock_obtained (lock
->repository
);
1091 goto after_sig_unblock
;
1095 (void) umask (omask
);
1099 if (errno
!= EEXIST
)
1102 "failed to create lock directory for `%s' (%s)",
1103 lock
->repository
, masterlock
);
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)
1113 if (existence_error (errno
))
1116 error (0, errno
, "couldn't stat lock directory `%s'", masterlock
);
1121 #ifdef CVS_FUDGELOCKS
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.
1128 if (now
>= (sb
.st_ctime
+ CVSLCKAGE
))
1130 if (CVS_RMDIR (masterlock
) >= 0)
1135 /* set the lockers name */
1136 set_lockers_name (&sb
);
1138 /* if he wasn't willing to wait, return an error */
1145 /* if possible, try a very short sleep without a message */
1146 if (!waited
&& us
< 1000)
1152 ts
.tv_nsec
= us
* 1000;
1153 (void)nanosleep (&ts
, NULL
);
1158 lock_wait (lock
->repository
);
1171 * Clear master lock.
1174 * lock The lock information.
1177 * Sets LOCK->lockdir to NULL after removing the directory it names and
1178 * freeing the storage.
1181 * If we own the master lock directory, its name is stored in LOCK->lockdir.
1182 * We may free LOCK->lockdir.
1185 clear_lock (struct lock
*lock
)
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
;
1201 * Create a list of repositories to lock
1205 lock_filesdoneproc (void *callerdat
, int err
, const char *repository
,
1206 const char *update_dir
, List
*entries
)
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;
1223 /* FIXME-KRP: this error condition should not simply be passed by. */
1224 if (p
->key
== NULL
|| addnode (lock_tree_list
, p
) != 0)
1232 lock_tree_promotably (int argc
, char **argv
, int local
, int which
, int aflag
)
1234 TRACE (TRACE_FUNCTION
, "lock_tree_promotably (%d, argv, %d, %d, %d)",
1235 argc
, local
, which
, aflag
);
1238 * Run the recursion processor to find all the dirs to lock and lock all
1241 lock_tree_list
= getlist ();
1243 (NULL
, lock_filesdoneproc
,
1244 NULL
, NULL
, NULL
, argc
,
1245 argv
, local
, which
, aflag
, CVS_LOCK_NONE
,
1247 sortlist (lock_tree_list
, fsortcmp
);
1248 if (lock_list_promotably (lock_tree_list
) != 0)
1249 error (1, 0, "lock failed - giving up");
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.
1258 * We do not clear the dir lock after writing the lock file name since write
1259 * locks are exclusive to all other locks.
1262 lock_dir_for_write (const char *repository
)
1266 TRACE (TRACE_FLOW
, "lock_dir_for_write (%s)", repository
);
1268 if (repository
!= NULL
1269 && (global_writelock
.repository
== NULL
1270 || !strcmp (global_writelock
.repository
, repository
)))
1272 if (writelock
== NULL
)
1274 writelock
= Xasprintf (
1275 #ifdef HAVE_LONG_FILE_NAMES
1276 "%s.%s.%ld", CVSWFL
, hostname
,
1283 if (global_writelock
.repository
!= NULL
)
1284 remove_lock_files (&global_writelock
, true);
1286 global_writelock
.repository
= xstrdup (repository
);
1287 global_writelock
.free_repository
= true;
1293 if (set_lock (&global_writelock
, 1) != L_OK
)
1294 error (1, 0, "failed to obtain write lock in repository `%s'",
1297 /* check if readers exist */
1298 if (readers_exist (repository
)
1299 || promotable_exists (repository
))
1301 clear_lock (&global_writelock
);
1302 lock_wait (repository
); /* sleep a while and try again */
1308 lock_obtained (repository
);
1310 /* write the write-lock file */
1311 global_writelock
.file1
= lock_name (global_writelock
.repository
,
1313 if ((fp
= CVS_FOPEN (global_writelock
.file1
, "w+")) == NULL
1314 || fclose (fp
) == EOF
)
1318 if (CVS_UNLINK (global_writelock
.file1
) < 0
1319 && !existence_error (errno
))
1321 error (0, errno
, "failed to remove write lock %s",
1322 global_writelock
.file1
);
1325 /* free the lock dir */
1326 clear_lock (&global_writelock
);
1328 /* return the error */
1330 "cannot create write lock in repository `%s'",
1331 global_writelock
.repository
);
1334 /* If we upgraded from a promotable lock, remove it. */
1337 Node
*p
= findnode (locklist
, repository
);
1340 remove_lock_files (p
->data
, true);
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.
1360 internal_lock (struct lock
*lock
, const char *xrepository
)
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;
1367 /* get the lock dir for our own */
1368 if (set_lock (lock
, 1) != L_OK
)
1371 error (0, 0, "failed to obtain history lock in repository `%s'",
1382 /* Lock the CVSROOT/history file for write.
1385 history_lock (const char *xrepository
)
1387 return internal_lock (&global_history_lock
, xrepository
);
1392 /* Remove the CVSROOT/history lock, if it exists.
1395 clear_history_lock ()
1397 remove_lock_files (&global_history_lock
, true);
1402 /* Lock the CVSROOT/val-tags file for write.
1405 val_tags_lock (const char *xrepository
)
1407 return internal_lock (&global_val_tags_lock
, xrepository
);
1412 /* Remove the CVSROOT/val-tags lock, if it exists.
1415 clear_val_tags_lock ()
1417 remove_lock_files (&global_val_tags_lock
, true);