1 /* RCS utility functions */ 2 3 /* Copyright 1982, 1988, 1989 Walter Tichy 4 Copyright 1990, 1991, 1992, 1993, 1994, 1995 Paul Eggert 5 Distributed under license by the Free Software Foundation, Inc. 6 7 This file is part of RCS. 8 9 RCS is free software; you can redistribute it and/or modify 10 it under the terms of the GNU General Public License as published by 11 the Free Software Foundation; either version 2, or (at your option) 12 any later version. 13 14 RCS is distributed in the hope that it will be useful, 15 but WITHOUT ANY WARRANTY; without even the implied warranty of 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 GNU General Public License for more details. 18 19 You should have received a copy of the GNU General Public License 20 along with RCS; see the file COPYING. 21 If not, write to the Free Software Foundation, 22 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 23 24 Report problems and direct all questions to: 25 26 rcs-bugs@cs.purdue.edu 27 28 */ 29 30 31 32 33 /* 34 * $FreeBSD: src/gnu/usr.bin/rcs/lib/rcsutil.c,v 1.8 1999/08/27 23:36:49 peter Exp $ 35 * 36 * Revision 5.20 1995/06/16 06:19:24 eggert 37 * (catchsig): Remove `return'. 38 * Update FSF address. 39 * 40 * Revision 5.19 1995/06/02 18:19:00 eggert 41 * (catchsigaction): New name for `catchsig', for sa_sigaction signature. 42 * Use nRCS even if !has_psiginfo, to remove unused variable warning. 43 * (setup_catchsig): Use sa_sigaction only if has_sa_sigaction. 44 * Use ENOTSUP only if defined. 45 * 46 * Revision 5.18 1995/06/01 16:23:43 eggert 47 * (catchsig, restoreints, setup_catchsig): Use SA_SIGINFO, not has_psiginfo, 48 * to determine whether to use SA_SIGINFO feature, 49 * but also check at runtime whether the feature works. 50 * (catchsig): If an mmap_signal occurs, report the affected file name. 51 * (unsupported_SA_SIGINFO, accessName): New variables. 52 * (setup_catchsig): If using SA_SIGINFO, use sa_sigaction, not sa_handler. 53 * If SA_SIGINFO fails, fall back on sa_handler method. 54 * 55 * (readAccessFilenameBuffer, dupSafer, fdSafer, fopenSafer): New functions. 56 * (concatenate): Remove. 57 * 58 * (runv): Work around bad_wait_if_SIGCHLD_ignored bug. 59 * Remove reference to OPEN_O_WORK. 60 * 61 * Revision 5.17 1994/03/20 04:52:58 eggert 62 * Specify subprocess input via file descriptor, not file name. 63 * Avoid messing with I/O buffers in the child process. 64 * Define dup in terms of F_DUPFD if it exists. 65 * Move setmtime to rcsedit.c. Remove lint. 66 * 67 * Revision 5.16 1993/11/09 17:40:15 eggert 68 * -V now prints version on stdout and exits. 69 * 70 * Revision 5.15 1993/11/03 17:42:27 eggert 71 * Use psiginfo and setreuid if available. Move date2str to maketime.c. 72 * 73 * Revision 5.14 1992/07/28 16:12:44 eggert 74 * Add -V. has_sigaction overrides sig_zaps_handler. Fix -M bug. 75 * Add mmap_signal, which minimizes signal handling for non-mmap hosts. 76 * 77 * Revision 5.13 1992/02/17 23:02:28 eggert 78 * Work around NFS mmap SIGBUS problem. Add -T support. 79 * 80 * Revision 5.12 1992/01/24 18:44:19 eggert 81 * Work around NFS mmap bug that leads to SIGBUS core dumps. lint -> RCS_lint 82 * 83 * Revision 5.11 1992/01/06 02:42:34 eggert 84 * O_BINARY -> OPEN_O_WORK 85 * while (E) ; -> while (E) continue; 86 * 87 * Revision 5.10 1991/10/07 17:32:46 eggert 88 * Support piece tables even if !has_mmap. 89 * 90 * Revision 5.9 1991/08/19 03:13:55 eggert 91 * Add spawn() support. Explicate assumptions about getting invoker's name. 92 * Standardize user-visible dates. Tune. 93 * 94 * Revision 5.8 1991/04/21 11:58:30 eggert 95 * Plug setuid security hole. 96 * 97 * Revision 5.6 1991/02/26 17:48:39 eggert 98 * Fix setuid bug. Use fread, fwrite more portably. 99 * Support waitpid. Don't assume -1 is acceptable to W* macros. 100 * strsave -> str_save (DG/UX name clash) 101 * 102 * Revision 5.5 1990/12/04 05:18:49 eggert 103 * Don't output a blank line after a signal diagnostic. 104 * Use -I for prompts and -q for diagnostics. 105 * 106 * Revision 5.4 1990/11/01 05:03:53 eggert 107 * Remove unneeded setid check. Add awrite(), fremember(). 108 * 109 * Revision 5.3 1990/10/06 00:16:45 eggert 110 * Don't fread F if feof(F). 111 * 112 * Revision 5.2 1990/09/04 08:02:31 eggert 113 * Store fread()'s result in an fread_type object. 114 * 115 * Revision 5.1 1990/08/29 07:14:07 eggert 116 * Declare getpwuid() more carefully. 117 * 118 * Revision 5.0 1990/08/22 08:13:46 eggert 119 * Add setuid support. Permit multiple locks per user. 120 * Remove compile-time limits; use malloc instead. 121 * Switch to GMT. Permit dates past 1999/12/31. 122 * Add -V. Remove snooping. Ansify and Posixate. 123 * Tune. Some USG hosts define NSIG but not sys_siglist. 124 * Don't run /bin/sh if it's hopeless. 125 * Don't leave garbage behind if the output is an empty pipe. 126 * Clean up after SIGXCPU or SIGXFSZ. Print name of signal that caused cleanup. 127 * 128 * Revision 4.6 89/05/01 15:13:40 narten 129 * changed copyright header to reflect current distribution rules 130 * 131 * Revision 4.5 88/11/08 16:01:02 narten 132 * corrected use of varargs routines 133 * 134 * Revision 4.4 88/08/09 19:13:24 eggert 135 * Check for memory exhaustion. 136 * Permit signal handlers to yield either 'void' or 'int'; fix oldSIGINT botch. 137 * Use execv(), not system(); yield exit status like diff(1)'s. 138 * 139 * Revision 4.3 87/10/18 10:40:22 narten 140 * Updating version numbers. Changes relative to 1.1 actually 141 * relative to 4.1 142 * 143 * Revision 1.3 87/09/24 14:01:01 narten 144 * Sources now pass through lint (if you ignore printf/sprintf/fprintf 145 * warnings) 146 * 147 * Revision 1.2 87/03/27 14:22:43 jenkins 148 * Port to suns 149 * 150 * Revision 4.1 83/05/10 15:53:13 wft 151 * Added getcaller() and findlock(). 152 * Changed catchints() to check SIGINT for SIG_IGN before setting up the signal 153 * (needed for background jobs in older shells). Added restoreints(). 154 * Removed printing of full RCS path from logcommand(). 155 * 156 * Revision 3.8 83/02/15 15:41:49 wft 157 * Added routine fastcopy() to copy remainder of a file in blocks. 158 * 159 * Revision 3.7 82/12/24 15:25:19 wft 160 * added catchints(), ignoreints() for catching and ingnoring interrupts; 161 * fixed catchsig(). 162 * 163 * Revision 3.6 82/12/08 21:52:05 wft 164 * Using DATEFORM to format dates. 165 * 166 * Revision 3.5 82/12/04 18:20:49 wft 167 * Replaced SNOOPDIR with SNOOPFILE; changed addlock() to update 168 * lockedby-field. 169 * 170 * Revision 3.4 82/12/03 17:17:43 wft 171 * Added check to addlock() ensuring only one lock per person. 172 * Addlock also returns a pointer to the lock created. Deleted fancydate(). 173 * 174 * Revision 3.3 82/11/27 12:24:37 wft 175 * moved rmsema(), trysema(), trydiraccess(), getfullRCSname() to rcsfnms.c. 176 * Introduced macro SNOOP so that snoop can be placed in directory other than 177 * TARGETDIR. Changed %02d to %.2d for compatibility reasons. 178 * 179 * Revision 3.2 82/10/18 21:15:11 wft 180 * added function getfullRCSname(). 181 * 182 * Revision 3.1 82/10/13 16:17:37 wft 183 * Cleanup message is now suppressed in quiet mode. 184 */ 185 186 187 188 189 #include "rcsbase.h" 190 191 libId(utilId, "$DragonFly: src/gnu/usr.bin/rcs/lib/rcsutil.c,v 1.2 2003/06/17 04:25:47 dillon Exp $") 192 193 #if !has_memcmp 194 int 195 memcmp(s1, s2, n) 196 void const *s1, *s2; 197 size_t n; 198 { 199 register unsigned char const 200 *p1 = (unsigned char const*)s1, 201 *p2 = (unsigned char const*)s2; 202 register size_t i = n; 203 register int r = 0; 204 while (i-- && !(r = (*p1++ - *p2++))) 205 ; 206 return r; 207 } 208 #endif 209 210 #if !has_memcpy 211 void * 212 memcpy(s1, s2, n) 213 void *s1; 214 void const *s2; 215 size_t n; 216 { 217 register char *p1 = (char*)s1; 218 register char const *p2 = (char const*)s2; 219 while (n--) 220 *p1++ = *p2++; 221 return s1; 222 } 223 #endif 224 225 #if RCS_lint 226 malloc_type lintalloc; 227 #endif 228 229 /* 230 * list of blocks allocated with ftestalloc() 231 * These blocks can be freed by ffree when we're done with the current file. 232 * We could put the free block inside struct alloclist, rather than a pointer 233 * to the free block, but that would be less portable. 234 */ 235 struct alloclist { 236 malloc_type alloc; 237 struct alloclist *nextalloc; 238 }; 239 static struct alloclist *alloced; 240 241 242 static malloc_type okalloc P((malloc_type)); 243 static malloc_type 244 okalloc(p) 245 malloc_type p; 246 { 247 if (!p) 248 faterror("out of memory"); 249 return p; 250 } 251 252 malloc_type 253 testalloc(size) 254 size_t size; 255 /* Allocate a block, testing that the allocation succeeded. */ 256 { 257 return okalloc(malloc(size)); 258 } 259 260 malloc_type 261 testrealloc(ptr, size) 262 malloc_type ptr; 263 size_t size; 264 /* Reallocate a block, testing that the allocation succeeded. */ 265 { 266 return okalloc(realloc(ptr, size)); 267 } 268 269 malloc_type 270 fremember(ptr) 271 malloc_type ptr; 272 /* Remember PTR in 'alloced' so that it can be freed later. Yield PTR. */ 273 { 274 register struct alloclist *q = talloc(struct alloclist); 275 q->nextalloc = alloced; 276 alloced = q; 277 return q->alloc = ptr; 278 } 279 280 malloc_type 281 ftestalloc(size) 282 size_t size; 283 /* Allocate a block, putting it in 'alloced' so it can be freed later. */ 284 { 285 return fremember(testalloc(size)); 286 } 287 288 void 289 ffree() 290 /* Free all blocks allocated with ftestalloc(). */ 291 { 292 register struct alloclist *p, *q; 293 for (p = alloced; p; p = q) { 294 q = p->nextalloc; 295 tfree(p->alloc); 296 tfree(p); 297 } 298 alloced = 0; 299 } 300 301 void 302 ffree1(f) 303 register char const *f; 304 /* Free the block f, which was allocated by ftestalloc. */ 305 { 306 register struct alloclist *p, **a = &alloced; 307 308 while ((p = *a)->alloc != f) 309 a = &p->nextalloc; 310 *a = p->nextalloc; 311 tfree(p->alloc); 312 tfree(p); 313 } 314 315 char * 316 str_save(s) 317 char const *s; 318 /* Save s in permanently allocated storage. */ 319 { 320 return strcpy(tnalloc(char, strlen(s)+1), s); 321 } 322 323 char * 324 fstr_save(s) 325 char const *s; 326 /* Save s in storage that will be deallocated when we're done with this file. */ 327 { 328 return strcpy(ftnalloc(char, strlen(s)+1), s); 329 } 330 331 char * 332 cgetenv(name) 333 char const *name; 334 /* Like getenv(), but yield a copy; getenv() can overwrite old results. */ 335 { 336 register char *p; 337 338 return (p=getenv(name)) ? str_save(p) : p; 339 } 340 341 char const * 342 getusername(suspicious) 343 int suspicious; 344 /* Get the caller's login name. Trust only getwpuid if SUSPICIOUS. */ 345 { 346 static char *name; 347 348 if (!name) { 349 if ( 350 /* Prefer getenv() unless suspicious; it's much faster. */ 351 # if getlogin_is_secure 352 (suspicious 353 || ( 354 !(name = cgetenv("LOGNAME")) 355 && !(name = cgetenv("USER")) 356 )) 357 && !(name = getlogin()) 358 # else 359 suspicious 360 || ( 361 !(name = cgetenv("LOGNAME")) 362 && !(name = cgetenv("USER")) 363 && !(name = getlogin()) 364 ) 365 # endif 366 ) { 367 #if has_getuid && has_getpwuid 368 struct passwd const *pw = getpwuid(ruid()); 369 if (!pw) 370 faterror("no password entry for userid %lu", 371 (unsigned long)ruid() 372 ); 373 name = pw->pw_name; 374 #else 375 #if has_setuid 376 faterror("setuid not supported"); 377 #else 378 faterror("Who are you? Please setenv LOGNAME."); 379 #endif 380 #endif 381 } 382 checksid(name); 383 } 384 return name; 385 } 386 387 388 389 390 #if has_signal 391 392 /* 393 * Signal handling 394 * 395 * Standard C places too many restrictions on signal handlers. 396 * We obey as many of them as we can. 397 * Posix places fewer restrictions, and we are Posix-compatible here. 398 */ 399 400 static sig_atomic_t volatile heldsignal, holdlevel; 401 #ifdef SA_SIGINFO 402 static int unsupported_SA_SIGINFO; 403 static siginfo_t bufsiginfo; 404 static siginfo_t *volatile heldsiginfo; 405 #endif 406 407 408 #if has_NFS && has_mmap && large_memory && mmap_signal 409 static char const *accessName; 410 411 void 412 readAccessFilenameBuffer(filename, p) 413 char const *filename; 414 unsigned char const *p; 415 { 416 accessName = 0; 417 } 418 #else 419 # define accessName ((char const *) 0) 420 #endif 421 422 423 #if !has_psignal 424 425 # define psignal my_psignal 426 static void my_psignal P((int,char const*)); 427 static void 428 my_psignal(sig, s) 429 int sig; 430 char const *s; 431 { 432 char const *sname = "Unknown signal"; 433 # if has_sys_siglist && defined(NSIG) 434 if ((unsigned)sig < NSIG) 435 sname = sys_siglist[sig]; 436 # else 437 switch (sig) { 438 # ifdef SIGHUP 439 case SIGHUP: sname = "Hangup"; break; 440 # endif 441 # ifdef SIGINT 442 case SIGINT: sname = "Interrupt"; break; 443 # endif 444 # ifdef SIGPIPE 445 case SIGPIPE: sname = "Broken pipe"; break; 446 # endif 447 # ifdef SIGQUIT 448 case SIGQUIT: sname = "Quit"; break; 449 # endif 450 # ifdef SIGTERM 451 case SIGTERM: sname = "Terminated"; break; 452 # endif 453 # ifdef SIGXCPU 454 case SIGXCPU: sname = "Cputime limit exceeded"; break; 455 # endif 456 # ifdef SIGXFSZ 457 case SIGXFSZ: sname = "Filesize limit exceeded"; break; 458 # endif 459 # if has_mmap && large_memory 460 # if defined(SIGBUS) && mmap_signal==SIGBUS 461 case SIGBUS: sname = "Bus error"; break; 462 # endif 463 # if defined(SIGSEGV) && mmap_signal==SIGSEGV 464 case SIGSEGV: sname = "Segmentation fault"; break; 465 # endif 466 # endif 467 } 468 # endif 469 470 /* Avoid calling sprintf etc., in case they're not reentrant. */ 471 { 472 char const *p; 473 char buf[BUFSIZ], *b = buf; 474 for (p = s; *p; *b++ = *p++) 475 continue; 476 *b++ = ':'; 477 *b++ = ' '; 478 for (p = sname; *p; *b++ = *p++) 479 continue; 480 *b++ = '\n'; 481 VOID write(STDERR_FILENO, buf, b - buf); 482 } 483 } 484 #endif 485 486 static signal_type catchsig P((int)); 487 #ifdef SA_SIGINFO 488 static signal_type catchsigaction P((int,siginfo_t*,void*)); 489 #endif 490 491 static signal_type 492 catchsig(s) 493 int s; 494 #ifdef SA_SIGINFO 495 { 496 catchsigaction(s, (siginfo_t *)0, (void *)0); 497 } 498 static signal_type 499 catchsigaction(s, i, c) 500 int s; 501 siginfo_t *i; 502 void *c; 503 #endif 504 { 505 # if sig_zaps_handler 506 /* If a signal arrives before we reset the handler, we lose. */ 507 VOID signal(s, SIG_IGN); 508 # endif 509 510 # ifdef SA_SIGINFO 511 if (!unsupported_SA_SIGINFO) 512 i = 0; 513 # endif 514 515 if (holdlevel) { 516 heldsignal = s; 517 # ifdef SA_SIGINFO 518 if (i) { 519 bufsiginfo = *i; 520 heldsiginfo = &bufsiginfo; 521 } 522 # endif 523 return; 524 } 525 526 ignoreints(); 527 setrid(); 528 if (!quietflag) { 529 /* Avoid calling sprintf etc., in case they're not reentrant. */ 530 char const *p; 531 char buf[BUFSIZ], *b = buf; 532 533 if ( ! ( 534 # if has_mmap && large_memory && mmap_signal 535 /* Check whether this signal was planned. */ 536 s == mmap_signal && accessName 537 # else 538 0 539 # endif 540 )) { 541 char const *nRCS = "\nRCS"; 542 # if defined(SA_SIGINFO) && has_si_errno && has_mmap && large_memory && mmap_signal 543 if (s == mmap_signal && i && i->si_errno) { 544 errno = i->si_errno; 545 perror(nRCS++); 546 } 547 # endif 548 # if defined(SA_SIGINFO) && has_psiginfo 549 if (i) 550 psiginfo(i, nRCS); 551 else 552 psignal(s, nRCS); 553 # else 554 psignal(s, nRCS); 555 # endif 556 } 557 558 for (p = "RCS: "; *p; *b++ = *p++) 559 continue; 560 # if has_mmap && large_memory && mmap_signal 561 if (s == mmap_signal) { 562 p = accessName; 563 if (!p) 564 p = "Was a file changed by some other process? "; 565 else { 566 char const *p1; 567 for (p1 = p; *p1; p1++) 568 continue; 569 VOID write(STDERR_FILENO, buf, b - buf); 570 VOID write(STDERR_FILENO, p, p1 - p); 571 b = buf; 572 p = ": Permission denied. "; 573 } 574 while (*p) 575 *b++ = *p++; 576 } 577 # endif 578 for (p = "Cleaning up.\n"; *p; *b++ = *p++) 579 continue; 580 VOID write(STDERR_FILENO, buf, b - buf); 581 } 582 exiterr(); 583 } 584 585 void 586 ignoreints() 587 { 588 ++holdlevel; 589 } 590 591 void 592 restoreints() 593 { 594 if (!--holdlevel && heldsignal) 595 # ifdef SA_SIGINFO 596 VOID catchsigaction(heldsignal, heldsiginfo, (void *)0); 597 # else 598 VOID catchsig(heldsignal); 599 # endif 600 } 601 602 603 static void setup_catchsig P((int const*,int)); 604 605 #if has_sigaction 606 607 static void check_sig P((int)); 608 static void 609 check_sig(r) 610 int r; 611 { 612 if (r != 0) 613 efaterror("signal handling"); 614 } 615 616 static void 617 setup_catchsig(sig, sigs) 618 int const *sig; 619 int sigs; 620 { 621 register int i, j; 622 struct sigaction act; 623 624 for (i=sigs; 0<=--i; ) { 625 check_sig(sigaction(sig[i], (struct sigaction*)0, &act)); 626 if (act.sa_handler != SIG_IGN) { 627 act.sa_handler = catchsig; 628 # ifdef SA_SIGINFO 629 if (!unsupported_SA_SIGINFO) { 630 # if has_sa_sigaction 631 act.sa_sigaction = catchsigaction; 632 # else 633 act.sa_handler = catchsig; 634 # endif 635 act.sa_flags |= SA_SIGINFO; 636 } 637 # endif 638 for (j=sigs; 0<=--j; ) 639 check_sig(sigaddset(&act.sa_mask, sig[j])); 640 if (sigaction(sig[i], &act, (struct sigaction*)0) != 0) { 641 # if defined(SA_SIGINFO) && defined(ENOTSUP) 642 if (errno == ENOTSUP && !unsupported_SA_SIGINFO) { 643 /* Turn off use of SA_SIGINFO and try again. */ 644 unsupported_SA_SIGINFO = 1; 645 i++; 646 continue; 647 } 648 # endif 649 check_sig(-1); 650 } 651 } 652 } 653 } 654 655 #else 656 #if has_sigblock 657 658 static void 659 setup_catchsig(sig, sigs) 660 int const *sig; 661 int sigs; 662 { 663 register int i; 664 int mask; 665 666 mask = 0; 667 for (i=sigs; 0<=--i; ) 668 mask |= sigmask(sig[i]); 669 mask = sigblock(mask); 670 for (i=sigs; 0<=--i; ) 671 if ( 672 signal(sig[i], catchsig) == SIG_IGN && 673 signal(sig[i], SIG_IGN) != catchsig 674 ) 675 faterror("signal catcher failure"); 676 VOID sigsetmask(mask); 677 } 678 679 #else 680 681 static void 682 setup_catchsig(sig, sigs) 683 int const *sig; 684 int sigs; 685 { 686 register i; 687 688 for (i=sigs; 0<=--i; ) 689 if ( 690 signal(sig[i], SIG_IGN) != SIG_IGN && 691 signal(sig[i], catchsig) != SIG_IGN 692 ) 693 faterror("signal catcher failure"); 694 } 695 696 #endif 697 #endif 698 699 700 static int const regsigs[] = { 701 # ifdef SIGHUP 702 SIGHUP, 703 # endif 704 # ifdef SIGINT 705 SIGINT, 706 # endif 707 # ifdef SIGPIPE 708 SIGPIPE, 709 # endif 710 # ifdef SIGQUIT 711 SIGQUIT, 712 # endif 713 # ifdef SIGTERM 714 SIGTERM, 715 # endif 716 # ifdef SIGXCPU 717 SIGXCPU, 718 # endif 719 # ifdef SIGXFSZ 720 SIGXFSZ, 721 # endif 722 }; 723 724 void 725 catchints() 726 { 727 static int catching_ints; 728 if (!catching_ints) { 729 catching_ints = true; 730 setup_catchsig(regsigs, (int) (sizeof(regsigs)/sizeof(*regsigs))); 731 } 732 } 733 734 #if has_mmap && large_memory && mmap_signal 735 736 /* 737 * If you mmap an NFS file, and someone on another client removes the last 738 * link to that file, and you later reference an uncached part of that file, 739 * you'll get a SIGBUS or SIGSEGV (depending on the operating system). 740 * Catch the signal and report the problem to the user. 741 * Unfortunately, there's no portable way to differentiate between this 742 * problem and actual bugs in the program. 743 * This NFS problem is rare, thank goodness. 744 * 745 * This can also occur if someone truncates the file, even without NFS. 746 */ 747 748 static int const mmapsigs[] = { mmap_signal }; 749 750 void 751 catchmmapints() 752 { 753 static int catching_mmap_ints; 754 if (!catching_mmap_ints) { 755 catching_mmap_ints = true; 756 setup_catchsig(mmapsigs, (int)(sizeof(mmapsigs)/sizeof(*mmapsigs))); 757 } 758 } 759 #endif 760 761 #endif /* has_signal */ 762 763 764 void 765 fastcopy(inf,outf) 766 register RILE *inf; 767 FILE *outf; 768 /* Function: copies the remainder of file inf to outf. 769 */ 770 { 771 #if large_memory 772 # if maps_memory 773 awrite((char const*)inf->ptr, (size_t)(inf->lim - inf->ptr), outf); 774 inf->ptr = inf->lim; 775 # else 776 for (;;) { 777 awrite((char const*)inf->ptr, (size_t)(inf->readlim - inf->ptr), outf); 778 inf->ptr = inf->readlim; 779 if (inf->ptr == inf->lim) 780 break; 781 VOID Igetmore(inf); 782 } 783 # endif 784 #else 785 char buf[BUFSIZ*8]; 786 register fread_type rcount; 787 788 /*now read the rest of the file in blocks*/ 789 while (!feof(inf)) { 790 if (!(rcount = Fread(buf,sizeof(*buf),sizeof(buf),inf))) { 791 testIerror(inf); 792 return; 793 } 794 awrite(buf, (size_t)rcount, outf); 795 } 796 #endif 797 } 798 799 #ifndef SSIZE_MAX 800 /* This does not work in #ifs, but it's good enough for us. */ 801 /* Underestimating SSIZE_MAX may slow us down, but it won't break us. */ 802 # define SSIZE_MAX ((unsigned)-1 >> 1) 803 #endif 804 805 void 806 awrite(buf, chars, f) 807 char const *buf; 808 size_t chars; 809 FILE *f; 810 { 811 /* Posix 1003.1-1990 ssize_t hack */ 812 while (SSIZE_MAX < chars) { 813 if (Fwrite(buf, sizeof(*buf), SSIZE_MAX, f) != SSIZE_MAX) 814 Oerror(); 815 buf += SSIZE_MAX; 816 chars -= SSIZE_MAX; 817 } 818 819 if (Fwrite(buf, sizeof(*buf), chars, f) != chars) 820 Oerror(); 821 } 822 823 /* dup a file descriptor; the result must not be stdin, stdout, or stderr. */ 824 static int dupSafer P((int)); 825 static int 826 dupSafer(fd) 827 int fd; 828 { 829 # ifdef F_DUPFD 830 return fcntl(fd, F_DUPFD, STDERR_FILENO + 1); 831 # else 832 int e, f, i, used = 0; 833 while (STDIN_FILENO <= (f = dup(fd)) && f <= STDERR_FILENO) 834 used |= 1<<f; 835 e = errno; 836 for (i = STDIN_FILENO; i <= STDERR_FILENO; i++) 837 if (used & (1<<i)) 838 VOID close(i); 839 errno = e; 840 return f; 841 # endif 842 } 843 844 /* Renumber a file descriptor so that it's not stdin, stdout, or stderr. */ 845 int 846 fdSafer(fd) 847 int fd; 848 { 849 if (STDIN_FILENO <= fd && fd <= STDERR_FILENO) { 850 int f = dupSafer(fd); 851 int e = errno; 852 VOID close(fd); 853 errno = e; 854 fd = f; 855 } 856 return fd; 857 } 858 859 /* Like fopen, except the result is never stdin, stdout, or stderr. */ 860 FILE * 861 fopenSafer(filename, type) 862 char const *filename; 863 char const *type; 864 { 865 FILE *stream = fopen(filename, type); 866 if (stream) { 867 int fd = fileno(stream); 868 if (STDIN_FILENO <= fd && fd <= STDERR_FILENO) { 869 int f = dupSafer(fd); 870 if (f < 0) { 871 int e = errno; 872 VOID fclose(stream); 873 errno = e; 874 return 0; 875 } 876 if (fclose(stream) != 0) { 877 int e = errno; 878 VOID close(f); 879 errno = e; 880 return 0; 881 } 882 stream = fdopen(f, type); 883 } 884 } 885 return stream; 886 } 887 888 889 #ifdef F_DUPFD 890 # undef dup 891 # define dup(fd) fcntl(fd, F_DUPFD, 0) 892 #endif 893 894 895 #if has_fork || has_spawn 896 897 static int movefd P((int,int)); 898 static int 899 movefd(old, new) 900 int old, new; 901 { 902 if (old < 0 || old == new) 903 return old; 904 # ifdef F_DUPFD 905 new = fcntl(old, F_DUPFD, new); 906 # else 907 new = dup2(old, new); 908 # endif 909 return close(old)==0 ? new : -1; 910 } 911 912 static int fdreopen P((int,char const*,int)); 913 static int 914 fdreopen(fd, file, flags) 915 int fd; 916 char const *file; 917 int flags; 918 { 919 int newfd; 920 VOID close(fd); 921 newfd = 922 #if !open_can_creat 923 flags&O_CREAT ? creat(file, S_IRUSR|S_IWUSR) : 924 #endif 925 open(file, flags, S_IRUSR|S_IWUSR); 926 return movefd(newfd, fd); 927 } 928 929 #if has_spawn 930 static void redirect P((int,int)); 931 static void 932 redirect(old, new) 933 int old, new; 934 /* 935 * Move file descriptor OLD to NEW. 936 * If OLD is -1, do nothing. 937 * If OLD is -2, just close NEW. 938 */ 939 { 940 if ((old != -1 && close(new) != 0) || (0 <= old && movefd(old,new) < 0)) 941 efaterror("spawn I/O redirection"); 942 } 943 #endif 944 945 946 #else /* !has_fork && !has_spawn */ 947 948 static void bufargcat P((struct buf*,int,char const*)); 949 static void 950 bufargcat(b, c, s) 951 register struct buf *b; 952 int c; 953 register char const *s; 954 /* Append to B a copy of C, plus a quoted copy of S. */ 955 { 956 register char *p; 957 register char const *t; 958 size_t bl, sl; 959 960 for (t=s, sl=0; *t; ) 961 sl += 3*(*t++=='\'') + 1; 962 bl = strlen(b->string); 963 bufrealloc(b, bl + sl + 4); 964 p = b->string + bl; 965 *p++ = c; 966 *p++ = '\''; 967 while (*s) { 968 if (*s == '\'') { 969 *p++ = '\''; 970 *p++ = '\\'; 971 *p++ = '\''; 972 } 973 *p++ = *s++; 974 } 975 *p++ = '\''; 976 *p = 0; 977 } 978 979 #endif 980 981 #if !has_spawn && has_fork 982 /* 983 * Output the string S to stderr, without touching any I/O buffers. 984 * This is useful if you are a child process, whose buffers are usually wrong. 985 * Exit immediately if the write does not completely succeed. 986 */ 987 static void write_stderr P((char const *)); 988 static void 989 write_stderr(s) 990 char const *s; 991 { 992 size_t slen = strlen(s); 993 if (write(STDERR_FILENO, s, slen) != slen) 994 _exit(EXIT_TROUBLE); 995 } 996 #endif 997 998 /* 999 * Run a command. 1000 * infd, if not -1, is the input file descriptor. 1001 * outname, if nonzero, is the name of the output file. 1002 * args[1..] form the command to be run; args[0] might be modified. 1003 */ 1004 int 1005 runv(infd, outname, args) 1006 int infd; 1007 char const *outname, **args; 1008 { 1009 int wstatus; 1010 1011 #if bad_wait_if_SIGCHLD_ignored 1012 static int fixed_SIGCHLD; 1013 if (!fixed_SIGCHLD) { 1014 fixed_SIGCHLD = true; 1015 # ifndef SIGCHLD 1016 # define SIGCHLD SIGCLD 1017 # endif 1018 VOID signal(SIGCHLD, SIG_DFL); 1019 } 1020 #endif 1021 1022 oflush(); 1023 eflush(); 1024 { 1025 #if has_spawn 1026 int in, out; 1027 char const *file; 1028 1029 in = -1; 1030 if (infd != -1 && infd != STDIN_FILENO) { 1031 if ((in = dup(STDIN_FILENO)) < 0) { 1032 if (errno != EBADF) 1033 efaterror("spawn input setup"); 1034 in = -2; 1035 } else { 1036 # ifdef F_DUPFD 1037 if (close(STDIN_FILENO) != 0) 1038 efaterror("spawn input close"); 1039 # endif 1040 } 1041 if ( 1042 # ifdef F_DUPFD 1043 fcntl(infd, F_DUPFD, STDIN_FILENO) != STDIN_FILENO 1044 # else 1045 dup2(infd, STDIN_FILENO) != STDIN_FILENO 1046 # endif 1047 ) 1048 efaterror("spawn input redirection"); 1049 } 1050 1051 out = -1; 1052 if (outname) { 1053 if ((out = dup(STDOUT_FILENO)) < 0) { 1054 if (errno != EBADF) 1055 efaterror("spawn output setup"); 1056 out = -2; 1057 } 1058 if (fdreopen( 1059 STDOUT_FILENO, outname, 1060 O_CREAT | O_TRUNC | O_WRONLY 1061 ) < 0) 1062 efaterror(outname); 1063 } 1064 1065 wstatus = spawn_RCS(0, args[1], (char**)(args + 1)); 1066 # ifdef RCS_SHELL 1067 if (wstatus == -1 && errno == ENOEXEC) { 1068 args[0] = RCS_SHELL; 1069 wstatus = spawnv(0, args[0], (char**)args); 1070 } 1071 # endif 1072 redirect(in, STDIN_FILENO); 1073 redirect(out, STDOUT_FILENO); 1074 #else 1075 #if has_fork 1076 pid_t pid; 1077 if (!(pid = vfork())) { 1078 char const *notfound; 1079 if (infd != -1 && infd != STDIN_FILENO && ( 1080 # ifdef F_DUPFD 1081 (VOID close(STDIN_FILENO), 1082 fcntl(infd, F_DUPFD, STDIN_FILENO) != STDIN_FILENO) 1083 # else 1084 dup2(infd, STDIN_FILENO) != STDIN_FILENO 1085 # endif 1086 )) { 1087 /* Avoid perror since it may misuse buffers. */ 1088 write_stderr(args[1]); 1089 write_stderr(": I/O redirection failed\n"); 1090 _exit(EXIT_TROUBLE); 1091 } 1092 1093 if (outname) 1094 if (fdreopen( 1095 STDOUT_FILENO, outname, 1096 O_CREAT | O_TRUNC | O_WRONLY 1097 ) < 0) { 1098 /* Avoid perror since it may misuse buffers. */ 1099 write_stderr(args[1]); 1100 write_stderr(": "); 1101 write_stderr(outname); 1102 write_stderr(": cannot create\n"); 1103 _exit(EXIT_TROUBLE); 1104 } 1105 VOID exec_RCS(args[1], (char**)(args + 1)); 1106 notfound = args[1]; 1107 # ifdef RCS_SHELL 1108 if (errno == ENOEXEC) { 1109 args[0] = notfound = RCS_SHELL; 1110 VOID execv(args[0], (char**)args); 1111 } 1112 # endif 1113 1114 /* Avoid perror since it may misuse buffers. */ 1115 write_stderr(notfound); 1116 write_stderr(": not found\n"); 1117 _exit(EXIT_TROUBLE); 1118 } 1119 if (pid < 0) 1120 efaterror("fork"); 1121 # if has_waitpid 1122 if (waitpid(pid, &wstatus, 0) < 0) 1123 efaterror("waitpid"); 1124 # else 1125 { 1126 pid_t w; 1127 do { 1128 if ((w = wait(&wstatus)) < 0) 1129 efaterror("wait"); 1130 } while (w != pid); 1131 } 1132 # endif 1133 #else 1134 static struct buf b; 1135 char const *p; 1136 1137 /* Use system(). On many hosts system() discards signals. Yuck! */ 1138 p = args + 1; 1139 bufscpy(&b, *p); 1140 while (*++p) 1141 bufargcat(&b, ' ', *p); 1142 if (infd != -1 && infd != STDIN_FILENO) { 1143 char redirection[32]; 1144 VOID sprintf(redirection, "<&%d", infd); 1145 bufscat(&b, redirection); 1146 } 1147 if (outname) 1148 bufargcat(&b, '>', outname); 1149 wstatus = system(b.string); 1150 #endif 1151 #endif 1152 } 1153 if (!WIFEXITED(wstatus)) { 1154 if (WIFSIGNALED(wstatus)) { 1155 psignal(WTERMSIG(wstatus), args[1]); 1156 fatcleanup(1); 1157 } 1158 faterror("%s failed for unknown reason", args[1]); 1159 } 1160 return WEXITSTATUS(wstatus); 1161 } 1162 1163 #define CARGSMAX 20 1164 /* 1165 * Run a command. 1166 * infd, if not -1, is the input file descriptor. 1167 * outname, if nonzero, is the name of the output file. 1168 * The remaining arguments specify the command and its arguments. 1169 */ 1170 int 1171 #if has_prototypes 1172 run(int infd, char const *outname, ...) 1173 #else 1174 /*VARARGS2*/ 1175 run(infd, outname, va_alist) 1176 int infd; 1177 char const *outname; 1178 va_dcl 1179 #endif 1180 { 1181 va_list ap; 1182 char const *rgargs[CARGSMAX]; 1183 register int i; 1184 vararg_start(ap, outname); 1185 for (i = 1; (rgargs[i++] = va_arg(ap, char const*)); ) 1186 if (CARGSMAX <= i) 1187 faterror("too many command arguments"); 1188 va_end(ap); 1189 return runv(infd, outname, rgargs); 1190 } 1191 1192 1193 int RCSversion; 1194 1195 void 1196 setRCSversion(str) 1197 char const *str; 1198 { 1199 static int oldversion; 1200 1201 register char const *s = str + 2; 1202 1203 if (*s) { 1204 int v = VERSION_DEFAULT; 1205 1206 if (oldversion) 1207 redefined('V'); 1208 oldversion = true; 1209 v = 0; 1210 while (isdigit(*s)) 1211 v = 10*v + *s++ - '0'; 1212 if (*s) 1213 error("%s isn't a number", str); 1214 else if (v < VERSION_min || VERSION_max < v) 1215 error("%s out of range %d..%d", 1216 str, VERSION_min, VERSION_max 1217 ); 1218 1219 RCSversion = VERSION(v); 1220 } else { 1221 printf("RCS version %s\n", RCS_version_string); 1222 exit(0); 1223 } 1224 } 1225 1226 int 1227 getRCSINIT(argc, argv, newargv) 1228 int argc; 1229 char **argv, ***newargv; 1230 { 1231 register char *p, *q, **pp; 1232 char const *ev; 1233 size_t n; 1234 1235 if ((ev = cgetenv("RCSLOCALID"))) 1236 setRCSLocalId(ev); 1237 1238 if ((ev = cgetenv("RCSINCEXC"))) 1239 setIncExc(ev); 1240 1241 if (!(q = cgetenv("RCSINIT"))) 1242 *newargv = argv; 1243 else { 1244 n = argc + 2; 1245 /* 1246 * Count spaces in RCSINIT to allocate a new arg vector. 1247 * This is an upper bound, but it's OK even if too large. 1248 */ 1249 for (p = q; ; ) { 1250 switch (*p++) { 1251 default: 1252 continue; 1253 1254 case ' ': 1255 case '\b': case '\f': case '\n': 1256 case '\r': case '\t': case '\v': 1257 n++; 1258 continue; 1259 1260 case '\0': 1261 break; 1262 } 1263 break; 1264 } 1265 *newargv = pp = tnalloc(char*, n); 1266 *pp++ = *argv++; /* copy program name */ 1267 for (p = q; ; ) { 1268 for (;;) { 1269 switch (*q) { 1270 case '\0': 1271 goto copyrest; 1272 1273 case ' ': 1274 case '\b': case '\f': case '\n': 1275 case '\r': case '\t': case '\v': 1276 q++; 1277 continue; 1278 } 1279 break; 1280 } 1281 *pp++ = p; 1282 ++argc; 1283 for (;;) { 1284 switch ((*p++ = *q++)) { 1285 case '\0': 1286 goto copyrest; 1287 1288 case '\\': 1289 if (!*q) 1290 goto copyrest; 1291 p[-1] = *q++; 1292 continue; 1293 1294 default: 1295 continue; 1296 1297 case ' ': 1298 case '\b': case '\f': case '\n': 1299 case '\r': case '\t': case '\v': 1300 break; 1301 } 1302 break; 1303 } 1304 p[-1] = '\0'; 1305 } 1306 copyrest: 1307 while ((*pp++ = *argv++)) 1308 continue; 1309 } 1310 return argc; 1311 } 1312 1313 1314 #define cacheid(E) static uid_t i; static int s; if (!s){ s=1; i=(E); } return i 1315 1316 #if has_getuid 1317 uid_t ruid() { cacheid(getuid()); } 1318 #endif 1319 #if has_setuid 1320 uid_t euid() { cacheid(geteuid()); } 1321 #endif 1322 1323 1324 #if has_setuid 1325 1326 /* 1327 * Setuid execution really works only with Posix 1003.1a Draft 5 seteuid(), 1328 * because it lets us switch back and forth between arbitrary users. 1329 * If seteuid() doesn't work, we fall back on setuid(), 1330 * which works if saved setuid is supported, 1331 * unless the real or effective user is root. 1332 * This area is such a mess that we always check switches at runtime. 1333 */ 1334 1335 static void 1336 #if has_prototypes 1337 set_uid_to(uid_t u) 1338 #else 1339 set_uid_to(u) uid_t u; 1340 #endif 1341 /* Become user u. */ 1342 { 1343 static int looping; 1344 1345 if (euid() == ruid()) 1346 return; 1347 #if (has_fork||has_spawn) && DIFF_ABSOLUTE 1348 # if has_setreuid 1349 if (setreuid(u==euid() ? ruid() : euid(), u) != 0) 1350 efaterror("setuid"); 1351 # else 1352 if (seteuid(u) != 0) 1353 efaterror("setuid"); 1354 # endif 1355 #endif 1356 if (geteuid() != u) { 1357 if (looping) 1358 return; 1359 looping = true; 1360 faterror("root setuid not supported" + (u?5:0)); 1361 } 1362 } 1363 1364 static int stick_with_euid; 1365 1366 void 1367 /* Ignore all calls to seteid() and setrid(). */ 1368 nosetid() 1369 { 1370 stick_with_euid = true; 1371 } 1372 1373 void 1374 seteid() 1375 /* Become effective user. */ 1376 { 1377 if (!stick_with_euid) 1378 set_uid_to(euid()); 1379 } 1380 1381 void 1382 setrid() 1383 /* Become real user. */ 1384 { 1385 if (!stick_with_euid) 1386 set_uid_to(ruid()); 1387 } 1388 #endif 1389 1390 time_t 1391 now() 1392 { 1393 static time_t t; 1394 if (!t && time(&t) == -1) 1395 efaterror("time"); 1396 return t; 1397 } 1398