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 75 76 struct lock { 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; 84 85 /* The name of the lock files. */ 86 char *file1; 87 #ifdef LOCK_COMPATIBILITY 88 char *file2; 89 #endif /* LOCK_COMPATIBILITY */ 90 91 /* The name of the master lock dir. Usually CVSLCK. */ 92 const char *lockdirname; 93 94 /* The full path to the lock dir, if we are currently holding it. 95 * 96 * This will be LOCKDIRNAME catted onto REPOSITORY. We waste a little 97 * space by storing it, but save a later malloc/free. 98 */ 99 char *lockdir; 100 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; 105 }; 106 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); 111 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. 116 Or NULL if none. */ 117 static char *readlock; 118 /* Malloc'd array specifying name of a writelock within a directory. 119 Or NULL if none. */ 120 static char *writelock; 121 /* Malloc'd array specifying name of a promotablelock within a directory. 122 Or NULL if none. */ 123 static char *promotablelock; 124 static List *locklist; 125 126 #define L_OK 0 /* success */ 127 #define L_ERROR 1 /* error condition */ 128 #define L_LOCKED 2 /* lock owned by someone else */ 129 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}; 135 136 static struct lock global_history_lock = {NULL, NULL, NULL, CVSHISTORYLCK, 137 NULL, false}; 138 static struct lock global_val_tags_lock = {NULL, NULL, NULL, CVSVALTAGSLCK, 139 NULL, false}; 140 #else 141 static struct lock global_readlock = {NULL, NULL, CVSLCK, NULL, false}; 142 static struct lock global_writelock = {NULL, NULL, CVSLCK, NULL, false}; 143 144 static struct lock global_history_lock = {NULL, NULL, CVSHISTORYLCK, NULL, 145 false}; 146 static struct lock global_val_tags_lock = {NULL, NULL, CVSVALTAGSLCK, NULL, 147 false}; 148 #endif /* LOCK_COMPATIBILITY */ 149 150 /* List of locks set by lock_tree_for_write. This is redundant 151 with locklist, sort of. */ 152 static List *lock_tree_list; 153 154 155 /* 156 * Find the root directory in the repository directory 157 */ 158 static int 159 find_root (const char *repository, char *rootdir) 160 { 161 struct stat strep, stroot; 162 char *p = NULL, *q = NULL; 163 size_t len; 164 165 if (stat (rootdir, &stroot) == -1) 166 return -1; 167 len = strlen (repository); 168 do { 169 if (p != NULL) { 170 len = p - repository; 171 *p = '\0'; 172 } 173 if (q != NULL) 174 *q = '/'; 175 if (stat(repository, &strep) == -1) { 176 if (p != NULL) 177 *p = '/'; 178 return -1; 179 } 180 if (strep.st_dev == stroot.st_dev && strep.st_ino == stroot.st_ino) { 181 if (p != NULL) 182 *p = '/'; 183 if (q != NULL) 184 *q = '/'; 185 return len; 186 } 187 q = p; 188 } while ((p = strrchr (repository, '/')) != NULL); 189 return -1; 190 } 191 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 197 things simple). */ 198 static char * 199 lock_name (const char *repository, const char *name) 200 { 201 char *retval; 202 const char *p; 203 char *q; 204 const char *short_repos; 205 mode_t save_umask = 0000; 206 int saved_umask = 0, len; 207 208 TRACE (TRACE_FLOW, "lock_name (%s, %s)", 209 repository ? repository : "(null)", name ? name : "(null)"); 210 211 if (!config->lock_dir) 212 { 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); 218 } 219 else 220 { 221 struct stat sb; 222 mode_t new_mode = 0; 223 224 /* The interesting part of the repository is the part relative 225 to CVSROOT. */ 226 assert (current_parsed_root != NULL); 227 assert (current_parsed_root->directory != NULL); 228 /* 229 * Unfortunately, string comparisons are not enough because we 230 * might have symlinks present 231 */ 232 len = find_root(repository, current_parsed_root->directory); 233 assert(len != -1); 234 short_repos = repository + len + 1; 235 236 if (strcmp (repository, current_parsed_root->directory) == 0) 237 short_repos = "."; 238 else 239 assert (short_repos[-1] == '/'); 240 241 retval = xmalloc (strlen (config->lock_dir) 242 + strlen (short_repos) 243 + strlen (name) 244 + 10); 245 strcpy (retval, config->lock_dir); 246 q = retval + strlen (retval); 247 *q++ = '/'; 248 249 strcpy (q, short_repos); 250 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) 254 { 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); 259 } 260 else 261 { 262 if (S_ISDIR (sb.st_mode)) 263 goto created; 264 else 265 error (1, 0, "%s is not a directory", retval); 266 } 267 268 /* Now add the directories one at a time, so we can create 269 them if needed. 270 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). 278 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. */ 283 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); 288 saved_umask = 1; 289 290 p = short_repos; 291 while (1) 292 { 293 while (!ISSLASH (*p) && *p != '\0') 294 ++p; 295 if (ISSLASH (*p)) 296 { 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) 301 { 302 int saved_errno = errno; 303 if (saved_errno != EEXIST) 304 error (1, errno, "cannot make directory %s", retval); 305 else 306 { 307 if (stat (retval, &sb) < 0) 308 error (1, errno, "cannot stat %s", retval); 309 new_mode = sb.st_mode; 310 } 311 } 312 ++p; 313 } 314 else 315 { 316 strcpy (q, short_repos); 317 if (CVS_MKDIR (retval, new_mode) < 0 318 && errno != EEXIST) 319 error (1, errno, "cannot make directory %s", retval); 320 goto created; 321 } 322 } 323 created:; 324 325 strcat (retval, "/"); 326 strcat (retval, name); 327 328 if (saved_umask) 329 { 330 assert (umask (save_umask) == 0000); 331 saved_umask = 0; 332 } 333 } 334 return retval; 335 } 336 337 338 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. 341 * 342 * INPUTS 343 * lock The lock to remove. 344 * free True if this lock directory will not be reused (free 345 * lock->repository if necessary). 346 */ 347 static void 348 remove_lock_files (struct lock *lock, bool free_repository) 349 { 350 TRACE (TRACE_FLOW, "remove_lock_files (%s)", lock->repository); 351 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. 356 */ 357 if (lock->file1) 358 { 359 char *tmp = lock->file1; 360 lock->file1 = NULL; 361 if (CVS_UNLINK (tmp) < 0 && ! existence_error (errno)) 362 error (0, errno, "failed to remove lock %s", tmp); 363 free (tmp); 364 } 365 #ifdef LOCK_COMPATIBILITY 366 if (lock->file2) 367 { 368 char *tmp = lock->file2; 369 lock->file2 = NULL; 370 if (CVS_UNLINK (tmp) < 0 && ! existence_error (errno)) 371 error (0, errno, "failed to remove lock %s", tmp); 372 free (tmp); 373 } 374 #endif /* LOCK_COMPATIBILITY */ 375 376 clear_lock (lock); 377 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. 381 * 382 * Use SIG_beginCrSect since otherwise we might be interrupted between 383 * checking whether free_repository is set and freeing stuff. 384 */ 385 if (free_repository) 386 { 387 SIG_beginCrSect (); 388 if (lock->free_repository) 389 { 390 free ((char *)lock->repository); 391 lock->free_repository = false; 392 } 393 lock->repository = NULL; 394 SIG_endCrSect (); 395 } 396 } 397 398 399 400 /* 401 * Clean up outstanding read and write locks and free their storage. 402 */ 403 void 404 Simple_Lock_Cleanup (void) 405 { 406 TRACE (TRACE_FUNCTION, "Simple_Lock_Cleanup()"); 407 408 /* Avoid interrupts while accessing globals the interrupt handlers might 409 * make use of. 410 */ 411 SIG_beginCrSect(); 412 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. */ 417 SIG_endCrSect(); 418 419 SIG_beginCrSect(); 420 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. */ 425 SIG_endCrSect(); 426 427 SIG_beginCrSect(); 428 429 /* clean up simple write locks (if any) */ 430 if (global_history_lock.repository) 431 remove_lock_files (&global_history_lock, true); 432 SIG_endCrSect(); 433 434 SIG_beginCrSect(); 435 436 if (global_val_tags_lock.repository) 437 remove_lock_files (&global_val_tags_lock, true); 438 /* See note in Lock_Cleanup() below. */ 439 SIG_endCrSect(); 440 } 441 442 443 444 /* 445 * Clean up all outstanding locks and free their storage. 446 * 447 * NOTES 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. 451 * 452 * RETURNS 453 * Nothing. 454 */ 455 void 456 Lock_Cleanup (void) 457 { 458 TRACE (TRACE_FUNCTION, "Lock_Cleanup()"); 459 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. 465 */ 466 467 remove_locks (); 468 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. 472 * 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. 476 */ 477 SIG_beginCrSect(); 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. 482 */ 483 SIG_endCrSect(); 484 } 485 486 487 488 /* 489 * walklist proc for removing a list of locks 490 */ 491 static int 492 unlock_proc (Node *p, void *closure) 493 { 494 remove_lock_files (p->data, false); 495 return 0; 496 } 497 498 499 500 /* 501 * Remove locks without discarding the lock information. 502 */ 503 static void 504 remove_locks (void) 505 { 506 TRACE (TRACE_FLOW, "remove_locks()"); 507 508 Simple_Lock_Cleanup (); 509 510 /* clean up promotable locks (if any) */ 511 SIG_beginCrSect(); 512 if (locklist != NULL) 513 { 514 /* Use a tmp var since any of these functions could call exit, causing 515 * us to be called a second time. 516 */ 517 List *tmp = locklist; 518 locklist = NULL; 519 walklist (tmp, unlock_proc, NULL); 520 } 521 SIG_endCrSect(); 522 } 523 524 525 526 /* 527 * Set the global readlock variable if it isn't already. 528 */ 529 static void 530 set_readlock_name (void) 531 { 532 if (readlock == NULL) 533 { 534 readlock = Xasprintf ( 535 #ifdef HAVE_LONG_FILE_NAMES 536 "%s.%s.%ld", CVSRFL, hostname, 537 #else 538 "%s.%ld", CVSRFL, 539 #endif 540 (long) getpid ()); 541 } 542 } 543 544 545 546 /* 547 * Create a lock file for readers 548 */ 549 int 550 Reader_Lock (char *xrepository) 551 { 552 int err = 0; 553 FILE *fp; 554 555 if (nolock) 556 return (0); 557 558 TRACE (TRACE_FUNCTION, "Reader_Lock(%s)", xrepository); 559 560 if (noexec || readonlyfs) 561 return 0; 562 563 /* we only do one directory at a time for read locks! */ 564 if (global_readlock.repository != NULL) 565 { 566 error (0, 0, "Reader_Lock called while read locks set - Help!"); 567 return 1; 568 } 569 570 set_readlock_name (); 571 572 /* remember what we're locking (for Lock_Cleanup) */ 573 global_readlock.repository = xstrdup (xrepository); 574 global_readlock.free_repository = true; 575 576 /* get the lock dir for our own */ 577 if (set_lock (&global_readlock, 1) != L_OK) 578 { 579 error (0, 0, "failed to obtain dir lock in repository `%s'", 580 xrepository); 581 if (readlock != NULL) 582 free (readlock); 583 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 586 a nonzero value. */ 587 return 1; 588 } 589 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) 594 { 595 error (0, errno, "cannot create read lock in repository `%s'", 596 xrepository); 597 err = 1; 598 } 599 600 /* free the lock dir */ 601 clear_lock (&global_readlock); 602 603 return err; 604 } 605 606 607 608 /* 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. 612 * 613 * INPUTS 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. 617 * 618 * GLOBALS 619 * lockdir The lock dir external to the repository, if any. 620 * 621 * RETURNS 622 * 0 No lock matching FILEPAT and not IGNORE exists. 623 * 1 Otherwise and on error. 624 * 625 * ERRORS 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. 628 */ 629 static int 630 lock_exists (const char *repository, const char *filepat, const char *ignore) 631 { 632 char *lockdir; 633 char *line; 634 DIR *dirp; 635 struct dirent *dp; 636 struct stat sb; 637 int ret; 638 #ifdef CVS_FUDGELOCKS 639 time_t now; 640 (void)time (&now); 641 #endif 642 643 TRACE (TRACE_FLOW, "lock_exists (%s, %s, %s)", 644 repository, filepat, ignore ? ignore : "(null)"); 645 646 lockdir = lock_name (repository, ""); 647 lockdir[strlen (lockdir) - 1] = '\0'; /* remove trailing slash */ 648 649 do { 650 if ((dirp = CVS_OPENDIR (lockdir)) == NULL) 651 error (1, 0, "cannot open directory %s", lockdir); 652 653 ret = 0; 654 errno = 0; 655 while ((dp = CVS_READDIR (dirp)) != NULL) 656 { 657 if (CVS_FNMATCH (filepat, dp->d_name, 0) == 0) 658 { 659 /* FIXME: the basename conversion below should be replaced with 660 * a call to the GNULIB basename function once it is imported. 661 */ 662 /* ignore our plock, if any */ 663 if (ignore && !fncmp (ignore, dp->d_name)) 664 continue; 665 666 line = Xasprintf ("%s/%s", lockdir, dp->d_name); 667 if (stat (line, &sb) != -1) 668 { 669 #ifdef CVS_FUDGELOCKS 670 /* 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. 674 */ 675 if (now >= (sb.st_ctime + CVSLCKAGE) && 676 CVS_UNLINK (line) != -1) 677 { 678 free (line); 679 ret = -1; 680 break; 681 } 682 #endif 683 set_lockers_name (&sb); 684 } 685 else 686 { 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. 690 */ 691 if (!existence_error (errno)) 692 error (0, errno, "cannot stat %s", line); 693 } 694 errno = 0; 695 free (line); 696 ret = 1; 697 break; 698 } 699 errno = 0; 700 } 701 if (errno != 0) 702 error (0, errno, "error reading directory %s", repository); 703 704 CVS_CLOSEDIR (dirp); 705 } while (ret < 0); 706 707 if (lockdir != NULL) 708 free (lockdir); 709 return ret; 710 } 711 712 713 714 /* 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. 718 * 719 * See lock_exists() for argument detail. 720 */ 721 static int 722 readers_exist (const char *repository) 723 { 724 TRACE (TRACE_FLOW, "readers_exist (%s)", repository); 725 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. 731 */ 732 return lock_exists (repository, CVSRFLPAT, 733 #ifdef LOCK_COMPATIBILITY 734 findnode (locklist, repository) ? readlock : 735 #endif /* LOCK_COMPATIBILITY */ 736 NULL); 737 } 738 739 740 741 /* 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. 745 * 746 * See lock_exists() for argument detail. 747 */ 748 static int 749 promotable_exists (const char *repository) 750 { 751 TRACE (TRACE_FLOW, "promotable_exists (%s)", repository); 752 return lock_exists (repository, CVSPFLPAT, promotablelock); 753 } 754 755 756 757 /* 758 * Lock a list of directories for writing 759 */ 760 static char *lock_error_repos; 761 static int lock_error; 762 763 764 765 /* 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. 768 */ 769 static int 770 set_promotable_lock (struct lock *lock) 771 { 772 int status; 773 FILE *fp; 774 775 TRACE (TRACE_FUNCTION, "set_promotable_lock(%s)", 776 lock->repository ? lock->repository : "(null)"); 777 778 if (promotablelock == NULL) 779 { 780 promotablelock = Xasprintf ( 781 #ifdef HAVE_LONG_FILE_NAMES 782 "%s.%s.%ld", CVSPFL, hostname, 783 #else 784 "%s.%ld", CVSPFL, 785 #endif 786 (long) getpid()); 787 } 788 789 /* make sure the lock dir is ours (not necessarily unique to us!) */ 790 status = set_lock (lock, 0); 791 if (status == L_OK) 792 { 793 /* we now own a promotable lock - make sure there are no others */ 794 if (promotable_exists (lock->repository)) 795 { 796 /* clean up the lock dir */ 797 clear_lock (lock); 798 799 /* indicate we failed due to read locks instead of error */ 800 return L_LOCKED; 801 } 802 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) 806 { 807 int xerrno = errno; 808 809 if (CVS_UNLINK (lock->file1) < 0 && ! existence_error (errno)) 810 error (0, errno, "failed to remove lock %s", lock->file1); 811 812 /* free the lock dir */ 813 clear_lock (lock); 814 815 /* return the error */ 816 error (0, xerrno, 817 "cannot create promotable lock in repository `%s'", 818 lock->repository); 819 return L_ERROR; 820 } 821 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. 827 */ 828 set_readlock_name (); 829 lock->file2 = lock_name (lock->repository, readlock); 830 if ((fp = CVS_FOPEN (lock->file2, "w+")) == NULL || fclose (fp) == EOF) 831 { 832 int xerrno = errno; 833 834 if ( CVS_UNLINK (lock->file2) < 0 && ! existence_error (errno)) 835 error (0, errno, "failed to remove lock %s", lock->file2); 836 837 /* free the lock dir */ 838 clear_lock (lock); 839 840 /* Remove the promotable lock. */ 841 lock->file2 = NULL; 842 remove_lock_files (lock, false); 843 844 /* return the error */ 845 error (0, xerrno, 846 "cannot create read lock in repository `%s'", 847 lock->repository); 848 return L_ERROR; 849 } 850 #endif /* LOCK_COMPATIBILITY */ 851 852 clear_lock (lock); 853 854 return L_OK; 855 } 856 else 857 return status; 858 } 859 860 861 862 /* 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. 866 * 867 * INPUTS 868 * p The current node, as determined by walklist(). 869 * closure Not used. 870 * 871 * GLOBAL INPUTS 872 * lock_error Any previous error encountered while attempting to get 873 * a lock. 874 * 875 * GLOBAL OUTPUTS 876 * lock_error Set if we encounter an error attempting to get axi 877 * promotable lock. 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 880 * encountered. 881 * 882 * RETURNS 883 * 0 for no error. 884 */ 885 static int 886 set_promotablelock_proc (Node *p, void *closure) 887 { 888 /* if some lock was not OK, just skip this one */ 889 if (lock_error != L_OK) 890 return 0; 891 892 /* apply the write lock */ 893 lock_error_repos = p->key; 894 lock_error = set_promotable_lock ((struct lock *)p->data); 895 return 0; 896 } 897 898 899 900 /* 901 * Print out a message that the lock is still held, then sleep a while. 902 */ 903 static void 904 lock_wait (const char *repos) 905 { 906 time_t now; 907 char *msg; 908 struct tm *tm_p; 909 910 (void) time (&now); 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 917 soon as possible. */ 918 cvs_flusherr (); 919 free (msg); 920 (void)sleep (CVSLCKSLEEP); 921 } 922 923 924 925 /* 926 * Print out a message when we obtain a lock. 927 */ 928 static void 929 lock_obtained (const char *repos) 930 { 931 time_t now; 932 char *msg; 933 struct tm *tm_p; 934 935 (void) time (&now); 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 941 soon as possible. */ 942 cvs_flusherr (); 943 free (msg); 944 } 945 946 947 948 static int 949 lock_list_promotably (List *list) 950 { 951 char *wait_repos; 952 953 TRACE (TRACE_FLOW, "lock_list_promotably ()"); 954 955 if (nolock) 956 return (0); 957 if (noexec) 958 return 0; 959 960 if (readonlyfs) { 961 error (0, 0, 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."); 965 return 1; 966 } 967 968 /* We only know how to do one list at a time */ 969 if (locklist != NULL) 970 { 971 error (0, 0, 972 "lock_list_promotably called while promotable locks set - Help!"); 973 return 1; 974 } 975 976 wait_repos = NULL; 977 for (;;) 978 { 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) 984 free (lockers_name); 985 lockers_name = xstrdup ("unknown"); 986 987 (void) walklist (list, set_promotablelock_proc, NULL); 988 989 switch (lock_error) 990 { 991 case L_ERROR: /* Real Error */ 992 if (wait_repos != NULL) 993 free (wait_repos); 994 Lock_Cleanup (); /* clean up any locks we set */ 995 error (0, 0, "lock failed - giving up"); 996 return 1; 997 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); 1002 continue; 1003 1004 case L_OK: /* we got the locks set */ 1005 if (wait_repos != NULL) 1006 { 1007 lock_obtained (wait_repos); 1008 free (wait_repos); 1009 } 1010 return 0; 1011 1012 default: 1013 if (wait_repos != NULL) 1014 free (wait_repos); 1015 error (0, 0, "unknown lock status %d in lock_list_promotably", 1016 lock_error); 1017 return 1; 1018 } 1019 } 1020 } 1021 1022 1023 1024 /* 1025 * Set the static variable lockers_name appropriately, based on the stat 1026 * structure passed in. 1027 */ 1028 static void 1029 set_lockers_name (struct stat *statp) 1030 { 1031 struct passwd *pw; 1032 1033 if (lockers_name != NULL) 1034 free (lockers_name); 1035 pw = (struct passwd *) getpwuid (statp->st_uid); 1036 if (pw != NULL) 1037 lockers_name = xstrdup (pw->pw_name); 1038 else 1039 lockers_name = Xasprintf ("uid%lu", (unsigned long) statp->st_uid); 1040 } 1041 1042 1043 1044 /* 1045 * Persistently tries to make the directory "lckdir", which serves as a 1046 * lock. 1047 * 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. 1051 * #endif 1052 * 1053 */ 1054 static int 1055 set_lock (struct lock *lock, int will_wait) 1056 { 1057 int waited; 1058 long us; 1059 struct stat sb; 1060 mode_t omask; 1061 char *masterlock; 1062 int status; 1063 #ifdef CVS_FUDGELOCKS 1064 time_t now; 1065 #endif 1066 1067 TRACE (TRACE_FLOW, "set_lock (%s, %d)", 1068 lock->repository ? lock->repository : "(null)", will_wait); 1069 1070 masterlock = lock_name (lock->repository, lock->lockdirname); 1071 1072 /* 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. 1076 */ 1077 waited = 0; 1078 us = 1; 1079 for (;;) 1080 { 1081 status = -1; 1082 omask = umask (cvsumask); 1083 SIG_beginCrSect (); 1084 if (CVS_MKDIR (masterlock, 0777) == 0) 1085 { 1086 lock->lockdir = masterlock; 1087 SIG_endCrSect (); 1088 status = L_OK; 1089 if (waited) 1090 lock_obtained (lock->repository); 1091 goto after_sig_unblock; 1092 } 1093 SIG_endCrSect (); 1094 after_sig_unblock: 1095 (void) umask (omask); 1096 if (status != -1) 1097 goto done; 1098 1099 if (errno != EEXIST) 1100 { 1101 error (0, errno, 1102 "failed to create lock directory for `%s' (%s)", 1103 lock->repository, masterlock); 1104 status = L_ERROR; 1105 goto done; 1106 } 1107 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) 1112 { 1113 if (existence_error (errno)) 1114 continue; 1115 1116 error (0, errno, "couldn't stat lock directory `%s'", masterlock); 1117 status = L_ERROR; 1118 goto done; 1119 } 1120 1121 #ifdef CVS_FUDGELOCKS 1122 /* 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. 1126 */ 1127 (void) time (&now); 1128 if (now >= (sb.st_ctime + CVSLCKAGE)) 1129 { 1130 if (CVS_RMDIR (masterlock) >= 0) 1131 continue; 1132 } 1133 #endif 1134 1135 /* set the lockers name */ 1136 set_lockers_name (&sb); 1137 1138 /* if he wasn't willing to wait, return an error */ 1139 if (!will_wait) 1140 { 1141 status = L_LOCKED; 1142 goto done; 1143 } 1144 1145 /* if possible, try a very short sleep without a message */ 1146 if (!waited && us < 1000) 1147 { 1148 us += us; 1149 { 1150 struct timespec ts; 1151 ts.tv_sec = 0; 1152 ts.tv_nsec = us * 1000; 1153 (void)nanosleep (&ts, NULL); 1154 continue; 1155 } 1156 } 1157 1158 lock_wait (lock->repository); 1159 waited = 1; 1160 } 1161 1162 done: 1163 if (!lock->lockdir) 1164 free (masterlock); 1165 return status; 1166 } 1167 1168 1169 1170 /* 1171 * Clear master lock. 1172 * 1173 * INPUTS 1174 * lock The lock information. 1175 * 1176 * OUTPUTS 1177 * Sets LOCK->lockdir to NULL after removing the directory it names and 1178 * freeing the storage. 1179 * 1180 * ASSUMPTIONS 1181 * If we own the master lock directory, its name is stored in LOCK->lockdir. 1182 * We may free LOCK->lockdir. 1183 */ 1184 static void 1185 clear_lock (struct lock *lock) 1186 { 1187 SIG_beginCrSect (); 1188 if (lock->lockdir) 1189 { 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; 1194 } 1195 SIG_endCrSect (); 1196 } 1197 1198 1199 1200 /* 1201 * Create a list of repositories to lock 1202 */ 1203 /* ARGSUSED */ 1204 static int 1205 lock_filesdoneproc (void *callerdat, int err, const char *repository, 1206 const char *update_dir, List *entries) 1207 { 1208 Node *p; 1209 1210 p = getnode (); 1211 p->type = LOCK; 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; 1222 1223 /* FIXME-KRP: this error condition should not simply be passed by. */ 1224 if (p->key == NULL || addnode (lock_tree_list, p) != 0) 1225 freenode (p); 1226 return err; 1227 } 1228 1229 1230 1231 void 1232 lock_tree_promotably (int argc, char **argv, int local, int which, int aflag) 1233 { 1234 TRACE (TRACE_FUNCTION, "lock_tree_promotably (%d, argv, %d, %d, %d)", 1235 argc, local, which, aflag); 1236 1237 /* 1238 * Run the recursion processor to find all the dirs to lock and lock all 1239 * the dirs 1240 */ 1241 lock_tree_list = getlist (); 1242 start_recursion 1243 (NULL, lock_filesdoneproc, 1244 NULL, NULL, NULL, argc, 1245 argv, local, which, aflag, CVS_LOCK_NONE, 1246 NULL, 0, NULL ); 1247 sortlist (lock_tree_list, fsortcmp); 1248 if (lock_list_promotably (lock_tree_list) != 0) 1249 error (1, 0, "lock failed - giving up"); 1250 } 1251 1252 1253 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. 1257 * 1258 * We do not clear the dir lock after writing the lock file name since write 1259 * locks are exclusive to all other locks. 1260 */ 1261 void 1262 lock_dir_for_write (const char *repository) 1263 { 1264 int waiting = 0; 1265 1266 TRACE (TRACE_FLOW, "lock_dir_for_write (%s)", repository); 1267 1268 if (repository != NULL 1269 && (global_writelock.repository == NULL 1270 || !strcmp (global_writelock.repository, repository))) 1271 { 1272 if (writelock == NULL) 1273 { 1274 writelock = Xasprintf ( 1275 #ifdef HAVE_LONG_FILE_NAMES 1276 "%s.%s.%ld", CVSWFL, hostname, 1277 #else 1278 "%s.%ld", CVSWFL, 1279 #endif 1280 (long) getpid()); 1281 } 1282 1283 if (global_writelock.repository != NULL) 1284 remove_lock_files (&global_writelock, true); 1285 1286 global_writelock.repository = xstrdup (repository); 1287 global_writelock.free_repository = true; 1288 1289 for (;;) 1290 { 1291 FILE *fp; 1292 1293 if (set_lock (&global_writelock, 1) != L_OK) 1294 error (1, 0, "failed to obtain write lock in repository `%s'", 1295 repository); 1296 1297 /* check if readers exist */ 1298 if (readers_exist (repository) 1299 || promotable_exists (repository)) 1300 { 1301 clear_lock (&global_writelock); 1302 lock_wait (repository); /* sleep a while and try again */ 1303 waiting = 1; 1304 continue; 1305 } 1306 1307 if (waiting) 1308 lock_obtained (repository); 1309 1310 /* write the write-lock file */ 1311 global_writelock.file1 = lock_name (global_writelock.repository, 1312 writelock); 1313 if ((fp = CVS_FOPEN (global_writelock.file1, "w+")) == NULL 1314 || fclose (fp) == EOF) 1315 { 1316 int xerrno = errno; 1317 1318 if (CVS_UNLINK (global_writelock.file1) < 0 1319 && !existence_error (errno)) 1320 { 1321 error (0, errno, "failed to remove write lock %s", 1322 global_writelock.file1); 1323 } 1324 1325 /* free the lock dir */ 1326 clear_lock (&global_writelock); 1327 1328 /* return the error */ 1329 error (1, xerrno, 1330 "cannot create write lock in repository `%s'", 1331 global_writelock.repository); 1332 } 1333 1334 /* If we upgraded from a promotable lock, remove it. */ 1335 if (locklist) 1336 { 1337 Node *p = findnode (locklist, repository); 1338 if (p) 1339 { 1340 remove_lock_files (p->data, true); 1341 delnode (p); 1342 } 1343 } 1344 1345 break; 1346 } 1347 } 1348 } 1349 1350 1351 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. 1354 * 1355 * RETURNS 1356 * true, on success 1357 * false, on error 1358 */ 1359 static inline int 1360 internal_lock (struct lock *lock, const char *xrepository) 1361 { 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; 1366 1367 /* get the lock dir for our own */ 1368 if (set_lock (lock, 1) != L_OK) 1369 { 1370 if (!really_quiet) 1371 error (0, 0, "failed to obtain history lock in repository `%s'", 1372 xrepository); 1373 1374 return 0; 1375 } 1376 1377 return 1; 1378 } 1379 1380 1381 1382 /* Lock the CVSROOT/history file for write. 1383 */ 1384 int 1385 history_lock (const char *xrepository) 1386 { 1387 return internal_lock (&global_history_lock, xrepository); 1388 } 1389 1390 1391 1392 /* Remove the CVSROOT/history lock, if it exists. 1393 */ 1394 void 1395 clear_history_lock () 1396 { 1397 remove_lock_files (&global_history_lock, true); 1398 } 1399 1400 1401 1402 /* Lock the CVSROOT/val-tags file for write. 1403 */ 1404 int 1405 val_tags_lock (const char *xrepository) 1406 { 1407 return internal_lock (&global_val_tags_lock, xrepository); 1408 } 1409 1410 1411 1412 /* Remove the CVSROOT/val-tags lock, if it exists. 1413 */ 1414 void 1415 clear_val_tags_lock () 1416 { 1417 remove_lock_files (&global_val_tags_lock, true); 1418 } 1419