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 (CVSroot_directory != NULL); 176 assert (strncmp (repository, CVSroot_directory, 177 strlen (CVSroot_directory)) == 0); 178 short_repos = repository + strlen (CVSroot_directory) + 1; 179 180 if (strcmp (repository, CVSroot_directory) == 0) 181 short_repos = "."; 182 else 183 assert (short_repos[-1] == '/'); 184 185 retval = xmalloc (strlen (lock_dir) 186 + strlen (short_repos) 187 + strlen (name) 188 + 10); 189 strcpy (retval, lock_dir); 190 q = retval + strlen (retval); 191 *q++ = '/'; 192 193 strcpy (q, short_repos); 194 195 /* In the common case, where the directory already exists, let's 196 keep it to one system call. */ 197 if (CVS_STAT (retval, &sb) < 0) 198 { 199 /* If we need to be creating more than one directory, we'll 200 get the existence_error here. */ 201 if (!existence_error (errno)) 202 error (1, errno, "cannot stat directory %s", retval); 203 } 204 else 205 { 206 if (S_ISDIR (sb.st_mode)) 207 goto created; 208 else 209 error (1, 0, "%s is not a directory", retval); 210 } 211 212 /* Now add the directories one at a time, so we can create 213 them if needed. 214 215 The idea behind the new_mode stuff is that the directory we 216 end up creating will inherit permissions from its parent 217 directory (we re-set new_mode with each EEXIST). CVSUMASK 218 isn't right, because typically the reason for LockDir is to 219 use a different set of permissions. We probably want to 220 inherit group ownership also (but we don't try to deal with 221 that, some systems do it for us either always or when g+s is on). 222 223 We don't try to do anything about the permissions on the lock 224 files themselves. The permissions don't really matter so much 225 because the locks will generally be removed by the process 226 which created them. */ 227 228 if (CVS_STAT (lock_dir, &sb) < 0) 229 error (1, errno, "cannot stat %s", lock_dir); 230 new_mode = sb.st_mode; 231 save_umask = umask (0000); 232 saved_umask = 1; 233 234 p = short_repos; 235 while (1) 236 { 237 while (!ISDIRSEP (*p) && *p != '\0') 238 ++p; 239 if (ISDIRSEP (*p)) 240 { 241 strncpy (q, short_repos, p - short_repos); 242 q[p - short_repos] = '\0'; 243 if (!ISDIRSEP (q[p - short_repos - 1]) 244 && CVS_MKDIR (retval, new_mode) < 0) 245 { 246 int saved_errno = errno; 247 if (saved_errno != EEXIST) 248 error (1, errno, "cannot make directory %s", retval); 249 else 250 { 251 if (CVS_STAT (retval, &sb) < 0) 252 error (1, errno, "cannot stat %s", retval); 253 new_mode = sb.st_mode; 254 } 255 } 256 ++p; 257 } 258 else 259 { 260 strcpy (q, short_repos); 261 if (CVS_MKDIR (retval, new_mode) < 0 262 && errno != EEXIST) 263 error (1, errno, "cannot make directory %s", retval); 264 goto created; 265 } 266 } 267 created:; 268 269 strcat (retval, "/"); 270 strcat (retval, name); 271 272 if (saved_umask) 273 { 274 assert (umask (save_umask) == 0000); 275 saved_umask = 0; 276 } 277 } 278 return retval; 279 } 280 281 /* 282 * Clean up all outstanding locks 283 */ 284 void 285 Lock_Cleanup () 286 { 287 /* FIXME: error handling here is kind of bogus; we sometimes will call 288 error, which in turn can call us again. For the moment work around 289 this by refusing to reenter this function (this is a kludge). */ 290 /* FIXME-reentrancy: the workaround isn't reentrant. */ 291 static int in_lock_cleanup = 0; 292 293 if (in_lock_cleanup) 294 return; 295 in_lock_cleanup = 1; 296 297 remove_locks (); 298 299 dellist (&lock_tree_list); 300 301 if (locked_dir != NULL) 302 { 303 dellist (&locked_list); 304 free (locked_dir); 305 locked_dir = NULL; 306 locked_list = NULL; 307 } 308 in_lock_cleanup = 0; 309 } 310 311 /* 312 * Remove locks without discarding the lock information 313 */ 314 static void 315 remove_locks () 316 { 317 /* clean up simple locks (if any) */ 318 if (global_readlock.repository != NULL) 319 { 320 lock_simple_remove (&global_readlock); 321 global_readlock.repository = NULL; 322 } 323 324 /* clean up multiple locks (if any) */ 325 if (locklist != (List *) NULL) 326 { 327 (void) walklist (locklist, unlock_proc, NULL); 328 locklist = (List *) NULL; 329 } 330 } 331 332 /* 333 * walklist proc for removing a list of locks 334 */ 335 static int 336 unlock_proc (p, closure) 337 Node *p; 338 void *closure; 339 { 340 lock_simple_remove ((struct lock *)p->data); 341 return (0); 342 } 343 344 /* Remove the lock files. */ 345 static void 346 lock_simple_remove (lock) 347 struct lock *lock; 348 { 349 char *tmp; 350 351 /* If readlock is set, the lock directory *might* have been created, but 352 since Reader_Lock doesn't use SIG_beginCrSect the way that set_lock 353 does, we don't know that. That is why we need to check for 354 existence_error here. */ 355 if (readlock != NULL) 356 { 357 tmp = lock_name (lock->repository, readlock); 358 if ( CVS_UNLINK (tmp) < 0 && ! existence_error (errno)) 359 error (0, errno, "failed to remove lock %s", tmp); 360 free (tmp); 361 } 362 363 /* If writelock is set, the lock directory *might* have been created, but 364 since write_lock doesn't use SIG_beginCrSect the way that set_lock 365 does, we don't know that. That is why we need to check for 366 existence_error here. */ 367 if (writelock != NULL) 368 { 369 tmp = lock_name (lock->repository, writelock); 370 if ( CVS_UNLINK (tmp) < 0 && ! existence_error (errno)) 371 error (0, errno, "failed to remove lock %s", tmp); 372 free (tmp); 373 } 374 375 if (lock->have_lckdir) 376 { 377 tmp = lock_name (lock->repository, CVSLCK); 378 SIG_beginCrSect (); 379 if (CVS_RMDIR (tmp) < 0) 380 error (0, errno, "failed to remove lock dir %s", tmp); 381 lock->have_lckdir = 0; 382 SIG_endCrSect (); 383 free (tmp); 384 } 385 } 386 387 /* 388 * Create a lock file for readers 389 */ 390 int 391 Reader_Lock (xrepository) 392 char *xrepository; 393 { 394 int err = 0; 395 FILE *fp; 396 char *tmp; 397 398 if (noexec || readonlyfs) 399 return (0); 400 401 /* we only do one directory at a time for read locks! */ 402 if (global_readlock.repository != NULL) 403 { 404 error (0, 0, "Reader_Lock called while read locks set - Help!"); 405 return (1); 406 } 407 408 if (readlock == NULL) 409 { 410 readlock = xmalloc (strlen (hostname) + sizeof (CVSRFL) + 40); 411 (void) sprintf (readlock, 412 #ifdef HAVE_LONG_FILE_NAMES 413 "%s.%s.%ld", CVSRFL, hostname, 414 #else 415 "%s.%ld", CVSRFL, 416 #endif 417 (long) getpid ()); 418 } 419 420 /* remember what we're locking (for Lock_Cleanup) */ 421 global_readlock.repository = xrepository; 422 423 /* get the lock dir for our own */ 424 if (set_lock (&global_readlock, 1) != L_OK) 425 { 426 error (0, 0, "failed to obtain dir lock in repository `%s'", 427 xrepository); 428 if (readlock != NULL) 429 free (readlock); 430 readlock = NULL; 431 /* We don't set global_readlock.repository to NULL. I think this 432 only works because recurse.c will give a fatal error if we return 433 a nonzero value. */ 434 return (1); 435 } 436 437 /* write a read-lock */ 438 tmp = lock_name (xrepository, readlock); 439 if ((fp = CVS_FOPEN (tmp, "w+")) == NULL || fclose (fp) == EOF) 440 { 441 error (0, errno, "cannot create read lock in repository `%s'", 442 xrepository); 443 if (readlock != NULL) 444 free (readlock); 445 readlock = NULL; 446 err = 1; 447 } 448 free (tmp); 449 450 /* free the lock dir */ 451 clear_lock (&global_readlock); 452 453 return (err); 454 } 455 456 /* 457 * Lock a list of directories for writing 458 */ 459 static char *lock_error_repos; 460 static int lock_error; 461 462 static int Writer_Lock PROTO ((List * list)); 463 464 static int 465 Writer_Lock (list) 466 List *list; 467 { 468 char *wait_repos; 469 470 if (noexec) 471 return (0); 472 473 /* We only know how to do one list at a time */ 474 if (locklist != (List *) NULL) 475 { 476 error (0, 0, "Writer_Lock called while write locks set - Help!"); 477 return (1); 478 } 479 480 wait_repos = NULL; 481 for (;;) 482 { 483 /* try to lock everything on the list */ 484 lock_error = L_OK; /* init for set_writelock_proc */ 485 lock_error_repos = (char *) NULL; /* init for set_writelock_proc */ 486 locklist = list; /* init for Lock_Cleanup */ 487 if (lockers_name != NULL) 488 free (lockers_name); 489 lockers_name = xstrdup ("unknown"); 490 491 (void) walklist (list, set_writelock_proc, NULL); 492 493 switch (lock_error) 494 { 495 case L_ERROR: /* Real Error */ 496 if (wait_repos != NULL) 497 free (wait_repos); 498 Lock_Cleanup (); /* clean up any locks we set */ 499 error (0, 0, "lock failed - giving up"); 500 return (1); 501 502 case L_LOCKED: /* Someone already had a lock */ 503 remove_locks (); /* clean up any locks we set */ 504 lock_wait (lock_error_repos); /* sleep a while and try again */ 505 wait_repos = xstrdup (lock_error_repos); 506 continue; 507 508 case L_OK: /* we got the locks set */ 509 if (wait_repos != NULL) 510 { 511 lock_obtained (wait_repos); 512 free (wait_repos); 513 } 514 return (0); 515 516 default: 517 if (wait_repos != NULL) 518 free (wait_repos); 519 error (0, 0, "unknown lock status %d in Writer_Lock", 520 lock_error); 521 return (1); 522 } 523 } 524 } 525 526 /* 527 * walklist proc for setting write locks 528 */ 529 static int 530 set_writelock_proc (p, closure) 531 Node *p; 532 void *closure; 533 { 534 /* if some lock was not OK, just skip this one */ 535 if (lock_error != L_OK) 536 return (0); 537 538 /* apply the write lock */ 539 lock_error_repos = p->key; 540 lock_error = write_lock ((struct lock *)p->data); 541 return (0); 542 } 543 544 /* 545 * Create a lock file for writers returns L_OK if lock set ok, L_LOCKED if 546 * lock held by someone else or L_ERROR if an error occurred 547 */ 548 static int 549 write_lock (lock) 550 struct lock *lock; 551 { 552 int status; 553 FILE *fp; 554 char *tmp; 555 556 if (writelock == NULL) 557 { 558 writelock = xmalloc (strlen (hostname) + sizeof (CVSWFL) + 40); 559 (void) sprintf (writelock, 560 #ifdef HAVE_LONG_FILE_NAMES 561 "%s.%s.%ld", CVSWFL, hostname, 562 #else 563 "%s.%ld", CVSWFL, 564 #endif 565 (long) getpid()); 566 } 567 568 /* make sure the lock dir is ours (not necessarily unique to us!) */ 569 status = set_lock (lock, 0); 570 if (status == L_OK) 571 { 572 /* we now own a writer - make sure there are no readers */ 573 if (readers_exist (lock->repository)) 574 { 575 /* clean up the lock dir if we created it */ 576 if (status == L_OK) 577 { 578 clear_lock (lock); 579 } 580 581 /* indicate we failed due to read locks instead of error */ 582 return (L_LOCKED); 583 } 584 585 /* write the write-lock file */ 586 tmp = lock_name (lock->repository, writelock); 587 if ((fp = CVS_FOPEN (tmp, "w+")) == NULL || fclose (fp) == EOF) 588 { 589 int xerrno = errno; 590 591 if ( CVS_UNLINK (tmp) < 0 && ! existence_error (errno)) 592 error (0, errno, "failed to remove lock %s", tmp); 593 594 /* free the lock dir if we created it */ 595 if (status == L_OK) 596 { 597 clear_lock (lock); 598 } 599 600 /* return the error */ 601 error (0, xerrno, "cannot create write lock in repository `%s'", 602 lock->repository); 603 free (tmp); 604 return (L_ERROR); 605 } 606 free (tmp); 607 return (L_OK); 608 } 609 else 610 return (status); 611 } 612 613 /* 614 * readers_exist() returns 0 if there are no reader lock files remaining in 615 * the repository; else 1 is returned, to indicate that the caller should 616 * sleep a while and try again. 617 */ 618 static int 619 readers_exist (repository) 620 char *repository; 621 { 622 char *line; 623 DIR *dirp; 624 struct dirent *dp; 625 struct stat sb; 626 int ret = 0; 627 628 #ifdef CVS_FUDGELOCKS 629 again: 630 #endif 631 632 if ((dirp = CVS_OPENDIR (repository)) == NULL) 633 error (1, 0, "cannot open directory %s", repository); 634 635 errno = 0; 636 while ((dp = readdir (dirp)) != NULL) 637 { 638 if (CVS_FNMATCH (CVSRFLPAT, dp->d_name, 0) == 0) 639 { 640 #ifdef CVS_FUDGELOCKS 641 time_t now; 642 (void) time (&now); 643 #endif 644 645 line = xmalloc (strlen (repository) + strlen (dp->d_name) + 5); 646 (void) sprintf (line, "%s/%s", repository, dp->d_name); 647 if ( CVS_STAT (line, &sb) != -1) 648 { 649 #ifdef CVS_FUDGELOCKS 650 /* 651 * If the create time of the file is more than CVSLCKAGE 652 * seconds ago, try to clean-up the lock file, and if 653 * successful, re-open the directory and try again. 654 */ 655 if (now >= (sb.st_ctime + CVSLCKAGE) && CVS_UNLINK (line) != -1) 656 { 657 (void) closedir (dirp); 658 free (line); 659 goto again; 660 } 661 #endif 662 set_lockers_name (&sb); 663 } 664 else 665 { 666 /* If the file doesn't exist, it just means that it disappeared 667 between the time we did the readdir and the time we did 668 the stat. */ 669 if (!existence_error (errno)) 670 error (0, errno, "cannot stat %s", line); 671 } 672 errno = 0; 673 free (line); 674 675 ret = 1; 676 break; 677 } 678 errno = 0; 679 } 680 if (errno != 0) 681 error (0, errno, "error reading directory %s", repository); 682 683 closedir (dirp); 684 return (ret); 685 } 686 687 /* 688 * Set the static variable lockers_name appropriately, based on the stat 689 * structure passed in. 690 */ 691 static void 692 set_lockers_name (statp) 693 struct stat *statp; 694 { 695 struct passwd *pw; 696 697 if (lockers_name != NULL) 698 free (lockers_name); 699 if ((pw = (struct passwd *) getpwuid (statp->st_uid)) != 700 (struct passwd *) NULL) 701 { 702 lockers_name = xstrdup (pw->pw_name); 703 } 704 else 705 { 706 lockers_name = xmalloc (20); 707 (void) sprintf (lockers_name, "uid%lu", (unsigned long) statp->st_uid); 708 } 709 } 710 711 /* 712 * Persistently tries to make the directory "lckdir",, which serves as a 713 * lock. If the create time on the directory is greater than CVSLCKAGE 714 * seconds old, just try to remove the directory. 715 */ 716 static int 717 set_lock (lock, will_wait) 718 struct lock *lock; 719 int will_wait; 720 { 721 int waited; 722 struct stat sb; 723 mode_t omask; 724 #ifdef CVS_FUDGELOCKS 725 time_t now; 726 #endif 727 728 if (masterlock != NULL) 729 free (masterlock); 730 masterlock = lock_name (lock->repository, CVSLCK); 731 732 /* 733 * Note that it is up to the callers of set_lock() to arrange for signal 734 * handlers that do the appropriate things, like remove the lock 735 * directory before they exit. 736 */ 737 waited = 0; 738 lock->have_lckdir = 0; 739 for (;;) 740 { 741 int status = -1; 742 omask = umask (cvsumask); 743 SIG_beginCrSect (); 744 if (CVS_MKDIR (masterlock, 0777) == 0) 745 { 746 lock->have_lckdir = 1; 747 SIG_endCrSect (); 748 status = L_OK; 749 if (waited) 750 lock_obtained (lock->repository); 751 goto out; 752 } 753 SIG_endCrSect (); 754 out: 755 (void) umask (omask); 756 if (status != -1) 757 return status; 758 759 if (errno != EEXIST) 760 { 761 error (0, errno, 762 "failed to create lock directory for `%s' (%s)", 763 lock->repository, masterlock); 764 return (L_ERROR); 765 } 766 767 /* Find out who owns the lock. If the lock directory is 768 non-existent, re-try the loop since someone probably just 769 removed it (thus releasing the lock). */ 770 if (CVS_STAT (masterlock, &sb) < 0) 771 { 772 if (existence_error (errno)) 773 continue; 774 775 error (0, errno, "couldn't stat lock directory `%s'", masterlock); 776 return (L_ERROR); 777 } 778 779 #ifdef CVS_FUDGELOCKS 780 /* 781 * If the create time of the directory is more than CVSLCKAGE seconds 782 * ago, try to clean-up the lock directory, and if successful, just 783 * quietly retry to make it. 784 */ 785 (void) time (&now); 786 if (now >= (sb.st_ctime + CVSLCKAGE)) 787 { 788 if (CVS_RMDIR (masterlock) >= 0) 789 continue; 790 } 791 #endif 792 793 /* set the lockers name */ 794 set_lockers_name (&sb); 795 796 /* if he wasn't willing to wait, return an error */ 797 if (!will_wait) 798 return (L_LOCKED); 799 lock_wait (lock->repository); 800 waited = 1; 801 } 802 } 803 804 /* 805 * Clear master lock. We don't have to recompute the lock name since 806 * clear_lock is never called except after a successful set_lock(). 807 */ 808 static void 809 clear_lock (lock) 810 struct lock *lock; 811 { 812 SIG_beginCrSect (); 813 if (CVS_RMDIR (masterlock) < 0) 814 error (0, errno, "failed to remove lock dir `%s'", masterlock); 815 lock->have_lckdir = 0; 816 SIG_endCrSect (); 817 } 818 819 /* 820 * Print out a message that the lock is still held, then sleep a while. 821 */ 822 static void 823 lock_wait (repos) 824 char *repos; 825 { 826 time_t now; 827 char *msg; 828 829 (void) time (&now); 830 msg = xmalloc (100 + strlen (lockers_name) + strlen (repos)); 831 sprintf (msg, "[%8.8s] waiting for %s's lock in %s", ctime (&now) + 11, 832 lockers_name, repos); 833 error (0, 0, "%s", msg); 834 /* Call cvs_flusherr to ensure that the user sees this message as 835 soon as possible. */ 836 cvs_flusherr (); 837 free (msg); 838 (void) sleep (CVSLCKSLEEP); 839 } 840 841 /* 842 * Print out a message when we obtain a lock. 843 */ 844 static void 845 lock_obtained (repos) 846 char *repos; 847 { 848 time_t now; 849 char *msg; 850 851 (void) time (&now); 852 msg = xmalloc (100 + strlen (repos)); 853 sprintf (msg, "[%8.8s] obtained lock in %s", ctime (&now) + 11, repos); 854 error (0, 0, "%s", msg); 855 /* Call cvs_flusherr to ensure that the user sees this message as 856 soon as possible. */ 857 cvs_flusherr (); 858 free (msg); 859 } 860 861 static int lock_filesdoneproc PROTO ((void *callerdat, int err, 862 char *repository, char *update_dir, 863 List *entries)); 864 865 /* 866 * Create a list of repositories to lock 867 */ 868 /* ARGSUSED */ 869 static int 870 lock_filesdoneproc (callerdat, err, repository, update_dir, entries) 871 void *callerdat; 872 int err; 873 char *repository; 874 char *update_dir; 875 List *entries; 876 { 877 Node *p; 878 879 p = getnode (); 880 p->type = LOCK; 881 p->key = xstrdup (repository); 882 p->data = xmalloc (sizeof (struct lock)); 883 ((struct lock *)p->data)->repository = p->key; 884 ((struct lock *)p->data)->have_lckdir = 0; 885 886 /* FIXME-KRP: this error condition should not simply be passed by. */ 887 if (p->key == NULL || addnode (lock_tree_list, p) != 0) 888 freenode (p); 889 return (err); 890 } 891 892 void 893 lock_tree_for_write (argc, argv, local, aflag) 894 int argc; 895 char **argv; 896 int local; 897 int aflag; 898 { 899 int err; 900 /* 901 * Run the recursion processor to find all the dirs to lock and lock all 902 * the dirs 903 */ 904 lock_tree_list = getlist (); 905 err = start_recursion ((FILEPROC) NULL, lock_filesdoneproc, 906 (DIRENTPROC) NULL, (DIRLEAVEPROC) NULL, NULL, argc, 907 argv, local, W_LOCAL, aflag, 0, (char *) NULL, 0); 908 sortlist (lock_tree_list, fsortcmp); 909 if (Writer_Lock (lock_tree_list) != 0) 910 error (1, 0, "lock failed - giving up"); 911 } 912 913 /* Lock a single directory in REPOSITORY. It is OK to call this if 914 a lock has been set with lock_dir_for_write; the new lock will replace 915 the old one. If REPOSITORY is NULL, don't do anything. */ 916 void 917 lock_dir_for_write (repository) 918 char *repository; 919 { 920 if (repository != NULL 921 && (locked_dir == NULL 922 || strcmp (locked_dir, repository) != 0)) 923 { 924 Node *node; 925 926 if (locked_dir != NULL) 927 Lock_Cleanup (); 928 929 locked_dir = xstrdup (repository); 930 locked_list = getlist (); 931 node = getnode (); 932 node->type = LOCK; 933 node->key = xstrdup (repository); 934 node->data = xmalloc (sizeof (struct lock)); 935 ((struct lock *)node->data)->repository = node->key; 936 ((struct lock *)node->data)->have_lckdir = 0; 937 938 (void) addnode (locked_list, node); 939 Writer_Lock (locked_list); 940 } 941 } 942