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