1 /* 2 * Copyright (c) 1992, Brian Berliner and Jeff Polk 3 * Copyright (c) 1989-1992, Brian Berliner 4 * 5 * You may distribute under the terms of the GNU General Public License as 6 * specified in the README file that comes with the CVS source distribution. 7 * 8 * Set Lock 9 * 10 * Lock file support for CVS. 11 */ 12 13 /* The node Concurrency in doc/cvs.texinfo has a brief introduction to 14 how CVS locks function, and some of the user-visible consequences of 15 their existence. Here is a summary of why they exist (and therefore, 16 the consequences of hacking CVS to read a repository without creating 17 locks): 18 19 There are two uses. One is the ability to prevent there from being 20 two writers at the same time. This is necessary for any number of 21 reasons (fileattr code, probably others). Commit needs to lock the 22 whole tree so that nothing happens between the up-to-date check and 23 the actual checkin. 24 25 The second use is the ability to ensure that there is not a writer 26 and a reader at the same time (several readers are allowed). Reasons 27 for this are: 28 29 * Readlocks ensure that once CVS has found a collection of rcs 30 files using Find_Names, the files will still exist when it reads 31 them (they may have moved in or out of the attic). 32 33 * Readlocks provide some modicum of consistency, although this is 34 kind of limited--see the node Concurrency in cvs.texinfo. 35 36 * Readlocks ensure that the RCS file does not change between 37 RCS_parse and RCS_reparsercsfile time. This one strikes me as 38 important, although I haven't thought up what bad scenarios might 39 be. 40 41 * Readlocks ensure that we won't find the file in the state in 42 which it is in between the calls to add_rcs_file and RCS_checkin in 43 commit.c (when a file is being added). This state is a state in 44 which the RCS file parsing routines in rcs.c cannot parse the file. 45 46 * Readlocks ensure that a reader won't try to look at a 47 half-written fileattr file (fileattr is not updated atomically). 48 49 (see also the description of anonymous read-only access in 50 "Password authentication security" node in doc/cvs.texinfo). 51 52 While I'm here, I'll try to summarize a few random suggestions 53 which periodically get made about how locks might be different: 54 55 1. Check for EROFS. Maybe useful, although in the presence of NFS 56 EROFS does *not* mean that the file system is unchanging. 57 58 2. Provide a means to put the cvs locks in some directory apart from 59 the repository (CVSROOT/locks; a -l option in modules; etc.). 60 61 3. Provide an option to disable locks for operations which only 62 read (see above for some of the consequences). 63 64 4. Have a server internally do the locking. Probably a good 65 long-term solution, and many people have been working hard on code 66 changes which would eventually make it possible to have a server 67 which can handle various connections in one process, but there is 68 much, much work still to be done before this is feasible. 69 70 5. Like #4 but use shared memory or something so that the servers 71 merely need to all be on the same machine. This is a much smaller 72 change to CVS (it functions much like #2; shared memory might be an 73 unneeded complication although it presumably would be faster). */ 74 75 #include "cvs.h" 76 #include <assert.h> 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 writelocks, it is just a pointer to the storage allocated 84 for the ->key field. */ 85 char *repository; 86 /* Do we have a lock named CVSLCK? */ 87 int have_lckdir; 88 /* Note there is no way of knowing whether the readlock and writelock 89 exist. The code which sets the locks doesn't use SIG_beginCrSect 90 to set a flag like we do for CVSLCK. */ 91 }; 92 93 static void remove_locks PROTO((void)); 94 static int readers_exist PROTO((char *repository)); 95 static int set_lock PROTO ((struct lock *lock, int will_wait)); 96 static void clear_lock PROTO ((struct lock *lock)); 97 static void set_lockers_name PROTO((struct stat *statp)); 98 static int set_writelock_proc PROTO((Node * p, void *closure)); 99 static int unlock_proc PROTO((Node * p, void *closure)); 100 static int write_lock PROTO ((struct lock *lock)); 101 static void lock_simple_remove PROTO ((struct lock *lock)); 102 static void lock_wait PROTO((char *repository)); 103 static void lock_obtained PROTO((char *repository)); 104 105 /* Malloc'd array containing the username of the whoever has the lock. 106 Will always be non-NULL in the cases where it is needed. */ 107 static char *lockers_name; 108 /* Malloc'd array specifying name of a readlock within a directory. 109 Or NULL if none. */ 110 static char *readlock; 111 /* Malloc'd array specifying name of a writelock within a directory. 112 Or NULL if none. */ 113 static char *writelock; 114 /* Malloc'd array specifying the name of a CVSLCK file (absolute pathname). 115 Will always be non-NULL in the cases where it is used. */ 116 static char *masterlock; 117 static List *locklist; 118 119 #define L_OK 0 /* success */ 120 #define L_ERROR 1 /* error condition */ 121 #define L_LOCKED 2 /* lock owned by someone else */ 122 123 /* This is the (single) readlock which is set by Reader_Lock. The 124 repository field is NULL if there is no such lock. */ 125 static struct lock global_readlock; 126 127 /* List of locks set by lock_tree_for_write. This is redundant 128 with locklist, sort of. */ 129 static List *lock_tree_list; 130 131 /* If we set locks with lock_dir_for_write, then locked_dir contains 132 the malloc'd name of the repository directory which we have locked. 133 locked_list is the same thing packaged into a list and is redundant 134 with locklist the same way that lock_tree_list is. */ 135 static char *locked_dir; 136 static List *locked_list; 137 138 /* LockDir from CVSROOT/config. */ 139 char *lock_dir; 140 141 static char *lock_name PROTO ((char *repository, char *name)); 142 143 /* Return a newly malloc'd string containing the name of the lock for the 144 repository REPOSITORY and the lock file name within that directory 145 NAME. Also create the directories in which to put the lock file 146 if needed (if we need to, could save system call(s) by doing 147 that only if the actual operation fails. But for now we'll keep 148 things simple). */ 149 static char * 150 lock_name (repository, name) 151 char *repository; 152 char *name; 153 { 154 char *retval; 155 char *p; 156 char *q; 157 char *short_repos; 158 mode_t save_umask; 159 int saved_umask = 0; 160 161 if (lock_dir == NULL) 162 { 163 /* This is the easy case. Because the lock files go directly 164 in the repository, no need to create directories or anything. */ 165 retval = xmalloc (strlen (repository) + strlen (name) + 10); 166 (void) sprintf (retval, "%s/%s", repository, name); 167 } 168 else 169 { 170 struct stat sb; 171 mode_t new_mode = 0; 172 173 /* The interesting part of the repository is the part relative 174 to CVSROOT. */ 175 assert (current_parsed_root != NULL); 176 assert (current_parsed_root->directory != NULL); 177 assert (strncmp (repository, current_parsed_root->directory, 178 strlen (current_parsed_root->directory)) == 0); 179 short_repos = repository + strlen (current_parsed_root->directory) + 1; 180 181 if (strcmp (repository, current_parsed_root->directory) == 0) 182 short_repos = "."; 183 else 184 assert (short_repos[-1] == '/'); 185 186 retval = xmalloc (strlen (lock_dir) 187 + strlen (short_repos) 188 + strlen (name) 189 + 10); 190 strcpy (retval, lock_dir); 191 q = retval + strlen (retval); 192 *q++ = '/'; 193 194 strcpy (q, short_repos); 195 196 /* In the common case, where the directory already exists, let's 197 keep it to one system call. */ 198 if (CVS_STAT (retval, &sb) < 0) 199 { 200 /* If we need to be creating more than one directory, we'll 201 get the existence_error here. */ 202 if (!existence_error (errno)) 203 error (1, errno, "cannot stat directory %s", retval); 204 } 205 else 206 { 207 if (S_ISDIR (sb.st_mode)) 208 goto created; 209 else 210 error (1, 0, "%s is not a directory", retval); 211 } 212 213 /* Now add the directories one at a time, so we can create 214 them if needed. 215 216 The idea behind the new_mode stuff is that the directory we 217 end up creating will inherit permissions from its parent 218 directory (we re-set new_mode with each EEXIST). CVSUMASK 219 isn't right, because typically the reason for LockDir is to 220 use a different set of permissions. We probably want to 221 inherit group ownership also (but we don't try to deal with 222 that, some systems do it for us either always or when g+s is on). 223 224 We don't try to do anything about the permissions on the lock 225 files themselves. The permissions don't really matter so much 226 because the locks will generally be removed by the process 227 which created them. */ 228 229 if (CVS_STAT (lock_dir, &sb) < 0) 230 error (1, errno, "cannot stat %s", lock_dir); 231 new_mode = sb.st_mode; 232 save_umask = umask (0000); 233 saved_umask = 1; 234 235 p = short_repos; 236 while (1) 237 { 238 while (!ISDIRSEP (*p) && *p != '\0') 239 ++p; 240 if (ISDIRSEP (*p)) 241 { 242 strncpy (q, short_repos, p - short_repos); 243 q[p - short_repos] = '\0'; 244 if (!ISDIRSEP (q[p - short_repos - 1]) 245 && CVS_MKDIR (retval, new_mode) < 0) 246 { 247 int saved_errno = errno; 248 if (saved_errno != EEXIST) 249 error (1, errno, "cannot make directory %s", retval); 250 else 251 { 252 if (CVS_STAT (retval, &sb) < 0) 253 error (1, errno, "cannot stat %s", retval); 254 new_mode = sb.st_mode; 255 } 256 } 257 ++p; 258 } 259 else 260 { 261 strcpy (q, short_repos); 262 if (CVS_MKDIR (retval, new_mode) < 0 263 && errno != EEXIST) 264 error (1, errno, "cannot make directory %s", retval); 265 goto created; 266 } 267 } 268 created:; 269 270 strcat (retval, "/"); 271 strcat (retval, name); 272 273 if (saved_umask) 274 { 275 assert (umask (save_umask) == 0000); 276 saved_umask = 0; 277 } 278 } 279 return retval; 280 } 281 282 /* 283 * Clean up all outstanding locks 284 */ 285 void 286 Lock_Cleanup () 287 { 288 /* FIXME: error handling here is kind of bogus; we sometimes will call 289 error, which in turn can call us again. For the moment work around 290 this by refusing to reenter this function (this is a kludge). */ 291 /* FIXME-reentrancy: the workaround isn't reentrant. */ 292 static int in_lock_cleanup = 0; 293 294 if (in_lock_cleanup) 295 return; 296 in_lock_cleanup = 1; 297 298 remove_locks (); 299 300 dellist (&lock_tree_list); 301 302 if (locked_dir != NULL) 303 { 304 dellist (&locked_list); 305 free (locked_dir); 306 locked_dir = NULL; 307 locked_list = NULL; 308 } 309 in_lock_cleanup = 0; 310 } 311 312 /* 313 * Remove locks without discarding the lock information 314 */ 315 static void 316 remove_locks () 317 { 318 /* clean up simple locks (if any) */ 319 if (global_readlock.repository != NULL) 320 { 321 lock_simple_remove (&global_readlock); 322 global_readlock.repository = NULL; 323 } 324 325 /* clean up multiple locks (if any) */ 326 if (locklist != (List *) NULL) 327 { 328 (void) walklist (locklist, unlock_proc, NULL); 329 locklist = (List *) NULL; 330 } 331 } 332 333 /* 334 * walklist proc for removing a list of locks 335 */ 336 static int 337 unlock_proc (p, closure) 338 Node *p; 339 void *closure; 340 { 341 lock_simple_remove ((struct lock *)p->data); 342 return (0); 343 } 344 345 /* Remove the lock files. */ 346 static void 347 lock_simple_remove (lock) 348 struct lock *lock; 349 { 350 char *tmp; 351 352 /* If readlock is set, the lock directory *might* have been created, but 353 since Reader_Lock doesn't use SIG_beginCrSect the way that set_lock 354 does, we don't know that. That is why we need to check for 355 existence_error here. */ 356 if (readlock != NULL) 357 { 358 tmp = lock_name (lock->repository, readlock); 359 if ( CVS_UNLINK (tmp) < 0 && ! existence_error (errno)) 360 error (0, errno, "failed to remove lock %s", tmp); 361 free (tmp); 362 } 363 364 /* If writelock is set, the lock directory *might* have been created, but 365 since write_lock doesn't use SIG_beginCrSect the way that set_lock 366 does, we don't know that. That is why we need to check for 367 existence_error here. */ 368 if (writelock != NULL) 369 { 370 tmp = lock_name (lock->repository, writelock); 371 if ( CVS_UNLINK (tmp) < 0 && ! existence_error (errno)) 372 error (0, errno, "failed to remove lock %s", tmp); 373 free (tmp); 374 } 375 376 if (lock->have_lckdir) 377 { 378 tmp = lock_name (lock->repository, CVSLCK); 379 SIG_beginCrSect (); 380 if (CVS_RMDIR (tmp) < 0) 381 error (0, errno, "failed to remove lock dir %s", tmp); 382 lock->have_lckdir = 0; 383 SIG_endCrSect (); 384 free (tmp); 385 } 386 } 387 388 /* 389 * Create a lock file for readers 390 */ 391 int 392 Reader_Lock (xrepository) 393 char *xrepository; 394 { 395 int err = 0; 396 FILE *fp; 397 char *tmp; 398 399 if (noexec || readonlyfs) 400 return (0); 401 402 /* we only do one directory at a time for read locks! */ 403 if (global_readlock.repository != NULL) 404 { 405 error (0, 0, "Reader_Lock called while read locks set - Help!"); 406 return (1); 407 } 408 409 if (readlock == NULL) 410 { 411 readlock = xmalloc (strlen (hostname) + sizeof (CVSRFL) + 40); 412 (void) sprintf (readlock, 413 #ifdef HAVE_LONG_FILE_NAMES 414 "%s.%s.%ld", CVSRFL, hostname, 415 #else 416 "%s.%ld", CVSRFL, 417 #endif 418 (long) getpid ()); 419 } 420 421 /* remember what we're locking (for Lock_Cleanup) */ 422 global_readlock.repository = xrepository; 423 424 /* get the lock dir for our own */ 425 if (set_lock (&global_readlock, 1) != L_OK) 426 { 427 error (0, 0, "failed to obtain dir lock in repository `%s'", 428 xrepository); 429 if (readlock != NULL) 430 free (readlock); 431 readlock = NULL; 432 /* We don't set global_readlock.repository to NULL. I think this 433 only works because recurse.c will give a fatal error if we return 434 a nonzero value. */ 435 return (1); 436 } 437 438 /* write a read-lock */ 439 tmp = lock_name (xrepository, readlock); 440 if ((fp = CVS_FOPEN (tmp, "w+")) == NULL || fclose (fp) == EOF) 441 { 442 error (0, errno, "cannot create read lock in repository `%s'", 443 xrepository); 444 if (readlock != NULL) 445 free (readlock); 446 readlock = NULL; 447 err = 1; 448 } 449 free (tmp); 450 451 /* free the lock dir */ 452 clear_lock (&global_readlock); 453 454 return (err); 455 } 456 457 /* 458 * Lock a list of directories for writing 459 */ 460 static char *lock_error_repos; 461 static int lock_error; 462 463 static int Writer_Lock PROTO ((List * list)); 464 465 static int 466 Writer_Lock (list) 467 List *list; 468 { 469 char *wait_repos; 470 471 if (noexec) 472 return (0); 473 474 /* We only know how to do one list at a time */ 475 if (locklist != (List *) NULL) 476 { 477 error (0, 0, "Writer_Lock called while write locks set - Help!"); 478 return (1); 479 } 480 481 wait_repos = NULL; 482 for (;;) 483 { 484 /* try to lock everything on the list */ 485 lock_error = L_OK; /* init for set_writelock_proc */ 486 lock_error_repos = (char *) NULL; /* init for set_writelock_proc */ 487 locklist = list; /* init for Lock_Cleanup */ 488 if (lockers_name != NULL) 489 free (lockers_name); 490 lockers_name = xstrdup ("unknown"); 491 492 (void) walklist (list, set_writelock_proc, NULL); 493 494 switch (lock_error) 495 { 496 case L_ERROR: /* Real Error */ 497 if (wait_repos != NULL) 498 free (wait_repos); 499 Lock_Cleanup (); /* clean up any locks we set */ 500 error (0, 0, "lock failed - giving up"); 501 return (1); 502 503 case L_LOCKED: /* Someone already had a lock */ 504 remove_locks (); /* clean up any locks we set */ 505 lock_wait (lock_error_repos); /* sleep a while and try again */ 506 wait_repos = xstrdup (lock_error_repos); 507 continue; 508 509 case L_OK: /* we got the locks set */ 510 if (wait_repos != NULL) 511 { 512 lock_obtained (wait_repos); 513 free (wait_repos); 514 } 515 return (0); 516 517 default: 518 if (wait_repos != NULL) 519 free (wait_repos); 520 error (0, 0, "unknown lock status %d in Writer_Lock", 521 lock_error); 522 return (1); 523 } 524 } 525 } 526 527 /* 528 * walklist proc for setting write locks 529 */ 530 static int 531 set_writelock_proc (p, closure) 532 Node *p; 533 void *closure; 534 { 535 /* if some lock was not OK, just skip this one */ 536 if (lock_error != L_OK) 537 return (0); 538 539 /* apply the write lock */ 540 lock_error_repos = p->key; 541 lock_error = write_lock ((struct lock *)p->data); 542 return (0); 543 } 544 545 /* 546 * Create a lock file for writers returns L_OK if lock set ok, L_LOCKED if 547 * lock held by someone else or L_ERROR if an error occurred 548 */ 549 static int 550 write_lock (lock) 551 struct lock *lock; 552 { 553 int status; 554 FILE *fp; 555 char *tmp; 556 557 if (writelock == NULL) 558 { 559 writelock = xmalloc (strlen (hostname) + sizeof (CVSWFL) + 40); 560 (void) sprintf (writelock, 561 #ifdef HAVE_LONG_FILE_NAMES 562 "%s.%s.%ld", CVSWFL, hostname, 563 #else 564 "%s.%ld", CVSWFL, 565 #endif 566 (long) getpid()); 567 } 568 569 /* make sure the lock dir is ours (not necessarily unique to us!) */ 570 status = set_lock (lock, 0); 571 if (status == L_OK) 572 { 573 /* we now own a writer - make sure there are no readers */ 574 if (readers_exist (lock->repository)) 575 { 576 /* clean up the lock dir if we created it */ 577 if (status == L_OK) 578 { 579 clear_lock (lock); 580 } 581 582 /* indicate we failed due to read locks instead of error */ 583 return (L_LOCKED); 584 } 585 586 /* write the write-lock file */ 587 tmp = lock_name (lock->repository, writelock); 588 if ((fp = CVS_FOPEN (tmp, "w+")) == NULL || fclose (fp) == EOF) 589 { 590 int xerrno = errno; 591 592 if ( CVS_UNLINK (tmp) < 0 && ! existence_error (errno)) 593 error (0, errno, "failed to remove lock %s", tmp); 594 595 /* free the lock dir if we created it */ 596 if (status == L_OK) 597 { 598 clear_lock (lock); 599 } 600 601 /* return the error */ 602 error (0, xerrno, "cannot create write lock in repository `%s'", 603 lock->repository); 604 free (tmp); 605 return (L_ERROR); 606 } 607 free (tmp); 608 return (L_OK); 609 } 610 else 611 return (status); 612 } 613 614 /* 615 * readers_exist() returns 0 if there are no reader lock files remaining in 616 * the repository; else 1 is returned, to indicate that the caller should 617 * sleep a while and try again. 618 */ 619 static int 620 readers_exist (repository) 621 char *repository; 622 { 623 char *line; 624 DIR *dirp; 625 struct dirent *dp; 626 struct stat sb; 627 int ret = 0; 628 629 #ifdef CVS_FUDGELOCKS 630 again: 631 #endif 632 633 if ((dirp = CVS_OPENDIR (repository)) == NULL) 634 error (1, 0, "cannot open directory %s", repository); 635 636 errno = 0; 637 while ((dp = CVS_READDIR (dirp)) != NULL) 638 { 639 if (CVS_FNMATCH (CVSRFLPAT, dp->d_name, 0) == 0) 640 { 641 #ifdef CVS_FUDGELOCKS 642 time_t now; 643 (void) time (&now); 644 #endif 645 646 line = xmalloc (strlen (repository) + strlen (dp->d_name) + 5); 647 (void) sprintf (line, "%s/%s", repository, dp->d_name); 648 if ( CVS_STAT (line, &sb) != -1) 649 { 650 #ifdef CVS_FUDGELOCKS 651 /* 652 * If the create time of the file is more than CVSLCKAGE 653 * seconds ago, try to clean-up the lock file, and if 654 * successful, re-open the directory and try again. 655 */ 656 if (now >= (sb.st_ctime + CVSLCKAGE) && CVS_UNLINK (line) != -1) 657 { 658 (void) CVS_CLOSEDIR (dirp); 659 free (line); 660 goto again; 661 } 662 #endif 663 set_lockers_name (&sb); 664 } 665 else 666 { 667 /* If the file doesn't exist, it just means that it disappeared 668 between the time we did the readdir and the time we did 669 the stat. */ 670 if (!existence_error (errno)) 671 error (0, errno, "cannot stat %s", line); 672 } 673 errno = 0; 674 free (line); 675 676 ret = 1; 677 break; 678 } 679 errno = 0; 680 } 681 if (errno != 0) 682 error (0, errno, "error reading directory %s", repository); 683 684 CVS_CLOSEDIR (dirp); 685 return (ret); 686 } 687 688 /* 689 * Set the static variable lockers_name appropriately, based on the stat 690 * structure passed in. 691 */ 692 static void 693 set_lockers_name (statp) 694 struct stat *statp; 695 { 696 struct passwd *pw; 697 698 if (lockers_name != NULL) 699 free (lockers_name); 700 if ((pw = (struct passwd *) getpwuid (statp->st_uid)) != 701 (struct passwd *) NULL) 702 { 703 lockers_name = xstrdup (pw->pw_name); 704 } 705 else 706 { 707 lockers_name = xmalloc (20); 708 (void) sprintf (lockers_name, "uid%lu", (unsigned long) statp->st_uid); 709 } 710 } 711 712 /* 713 * Persistently tries to make the directory "lckdir",, which serves as a 714 * lock. If the create time on the directory is greater than CVSLCKAGE 715 * seconds old, just try to remove the directory. 716 */ 717 static int 718 set_lock (lock, will_wait) 719 struct lock *lock; 720 int will_wait; 721 { 722 int waited; 723 struct stat sb; 724 mode_t omask; 725 #ifdef CVS_FUDGELOCKS 726 time_t now; 727 #endif 728 729 if (masterlock != NULL) 730 free (masterlock); 731 masterlock = lock_name (lock->repository, CVSLCK); 732 733 /* 734 * Note that it is up to the callers of set_lock() to arrange for signal 735 * handlers that do the appropriate things, like remove the lock 736 * directory before they exit. 737 */ 738 waited = 0; 739 lock->have_lckdir = 0; 740 for (;;) 741 { 742 int status = -1; 743 omask = umask (cvsumask); 744 SIG_beginCrSect (); 745 if (CVS_MKDIR (masterlock, 0777) == 0) 746 { 747 lock->have_lckdir = 1; 748 SIG_endCrSect (); 749 status = L_OK; 750 if (waited) 751 lock_obtained (lock->repository); 752 goto out; 753 } 754 SIG_endCrSect (); 755 out: 756 (void) umask (omask); 757 if (status != -1) 758 return status; 759 760 if (errno != EEXIST) 761 { 762 error (0, errno, 763 "failed to create lock directory for `%s' (%s)", 764 lock->repository, masterlock); 765 return (L_ERROR); 766 } 767 768 /* Find out who owns the lock. If the lock directory is 769 non-existent, re-try the loop since someone probably just 770 removed it (thus releasing the lock). */ 771 if (CVS_STAT (masterlock, &sb) < 0) 772 { 773 if (existence_error (errno)) 774 continue; 775 776 error (0, errno, "couldn't stat lock directory `%s'", masterlock); 777 return (L_ERROR); 778 } 779 780 #ifdef CVS_FUDGELOCKS 781 /* 782 * If the create time of the directory is more than CVSLCKAGE seconds 783 * ago, try to clean-up the lock directory, and if successful, just 784 * quietly retry to make it. 785 */ 786 (void) time (&now); 787 if (now >= (sb.st_ctime + CVSLCKAGE)) 788 { 789 if (CVS_RMDIR (masterlock) >= 0) 790 continue; 791 } 792 #endif 793 794 /* set the lockers name */ 795 set_lockers_name (&sb); 796 797 /* if he wasn't willing to wait, return an error */ 798 if (!will_wait) 799 return (L_LOCKED); 800 lock_wait (lock->repository); 801 waited = 1; 802 } 803 } 804 805 /* 806 * Clear master lock. We don't have to recompute the lock name since 807 * clear_lock is never called except after a successful set_lock(). 808 */ 809 static void 810 clear_lock (lock) 811 struct lock *lock; 812 { 813 SIG_beginCrSect (); 814 if (CVS_RMDIR (masterlock) < 0) 815 error (0, errno, "failed to remove lock dir `%s'", masterlock); 816 lock->have_lckdir = 0; 817 SIG_endCrSect (); 818 } 819 820 /* 821 * Print out a message that the lock is still held, then sleep a while. 822 */ 823 static void 824 lock_wait (repos) 825 char *repos; 826 { 827 time_t now; 828 char *msg; 829 830 (void) time (&now); 831 msg = xmalloc (100 + strlen (lockers_name) + strlen (repos)); 832 sprintf (msg, "[%8.8s] waiting for %s's lock in %s", ctime (&now) + 11, 833 lockers_name, repos); 834 error (0, 0, "%s", msg); 835 /* Call cvs_flusherr to ensure that the user sees this message as 836 soon as possible. */ 837 cvs_flusherr (); 838 free (msg); 839 (void) sleep (CVSLCKSLEEP); 840 } 841 842 /* 843 * Print out a message when we obtain a lock. 844 */ 845 static void 846 lock_obtained (repos) 847 char *repos; 848 { 849 time_t now; 850 char *msg; 851 852 (void) time (&now); 853 msg = xmalloc (100 + strlen (repos)); 854 sprintf (msg, "[%8.8s] obtained lock in %s", ctime (&now) + 11, repos); 855 error (0, 0, "%s", msg); 856 /* Call cvs_flusherr to ensure that the user sees this message as 857 soon as possible. */ 858 cvs_flusherr (); 859 free (msg); 860 } 861 862 static int lock_filesdoneproc PROTO ((void *callerdat, int err, 863 char *repository, char *update_dir, 864 List *entries)); 865 866 /* 867 * Create a list of repositories to lock 868 */ 869 /* ARGSUSED */ 870 static int 871 lock_filesdoneproc (callerdat, err, repository, update_dir, entries) 872 void *callerdat; 873 int err; 874 char *repository; 875 char *update_dir; 876 List *entries; 877 { 878 Node *p; 879 880 p = getnode (); 881 p->type = LOCK; 882 p->key = xstrdup (repository); 883 p->data = xmalloc (sizeof (struct lock)); 884 ((struct lock *)p->data)->repository = p->key; 885 ((struct lock *)p->data)->have_lckdir = 0; 886 887 /* FIXME-KRP: this error condition should not simply be passed by. */ 888 if (p->key == NULL || addnode (lock_tree_list, p) != 0) 889 freenode (p); 890 return (err); 891 } 892 893 void 894 lock_tree_for_write (argc, argv, local, which, aflag) 895 int argc; 896 char **argv; 897 int local; 898 int which; 899 int aflag; 900 { 901 int err; 902 /* 903 * Run the recursion processor to find all the dirs to lock and lock all 904 * the dirs 905 */ 906 lock_tree_list = getlist (); 907 err = start_recursion ((FILEPROC) NULL, lock_filesdoneproc, 908 (DIRENTPROC) NULL, (DIRLEAVEPROC) NULL, NULL, argc, 909 argv, local, which, aflag, 0, (char *) NULL, 0); 910 sortlist (lock_tree_list, fsortcmp); 911 if (Writer_Lock (lock_tree_list) != 0) 912 error (1, 0, "lock failed - giving up"); 913 } 914 915 /* Lock a single directory in REPOSITORY. It is OK to call this if 916 a lock has been set with lock_dir_for_write; the new lock will replace 917 the old one. If REPOSITORY is NULL, don't do anything. */ 918 void 919 lock_dir_for_write (repository) 920 char *repository; 921 { 922 if (repository != NULL 923 && (locked_dir == NULL 924 || strcmp (locked_dir, repository) != 0)) 925 { 926 Node *node; 927 928 if (locked_dir != NULL) 929 Lock_Cleanup (); 930 931 locked_dir = xstrdup (repository); 932 locked_list = getlist (); 933 node = getnode (); 934 node->type = LOCK; 935 node->key = xstrdup (repository); 936 node->data = xmalloc (sizeof (struct lock)); 937 ((struct lock *)node->data)->repository = node->key; 938 ((struct lock *)node->data)->have_lckdir = 0; 939 940 (void) addnode (locked_list, node); 941 Writer_Lock (locked_list); 942 } 943 } 944