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