📄 rcsutil.c
字号:
/* * RCS utilities *//* Copyright (C) 1982, 1988, 1989 Walter Tichy Copyright 1990, 1991 by Paul Eggert Distributed under license by the Free Software Foundation, Inc.This file is part of RCS.RCS is free software; you can redistribute it and/or modifyit under the terms of the GNU General Public License as published bythe Free Software Foundation; either version 2, or (at your option)any later version.RCS is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See theGNU General Public License for more details.You should have received a copy of the GNU General Public Licensealong with RCS; see the file COPYING. If not, write tothe Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.Report problems and direct all questions to: rcs-bugs@cs.purdue.edu*//* $Log: rcsutil.c,v $ * Revision 5.10 1991/10/07 17:32:46 eggert * Support piece tables even if !has_mmap. * * Revision 5.9 1991/08/19 03:13:55 eggert * Add spawn() support. Explicate assumptions about getting invoker's name. * Standardize user-visible dates. Tune. * * Revision 5.8 1991/04/21 11:58:30 eggert * Plug setuid security hole. * * Revision 5.6 1991/02/26 17:48:39 eggert * Fix setuid bug. Use fread, fwrite more portably. * Support waitpid. Don't assume -1 is acceptable to W* macros. * strsave -> str_save (DG/UX name clash) * * Revision 5.5 1990/12/04 05:18:49 eggert * Don't output a blank line after a signal diagnostic. * Use -I for prompts and -q for diagnostics. * * Revision 5.4 1990/11/01 05:03:53 eggert * Remove unneeded setid check. Add awrite(), fremember(). * * Revision 5.3 1990/10/06 00:16:45 eggert * Don't fread F if feof(F). * * Revision 5.2 1990/09/04 08:02:31 eggert * Store fread()'s result in an fread_type object. * * Revision 5.1 1990/08/29 07:14:07 eggert * Declare getpwuid() more carefully. * * Revision 5.0 1990/08/22 08:13:46 eggert * Add setuid support. Permit multiple locks per user. * Remove compile-time limits; use malloc instead. * Switch to GMT. Permit dates past 1999/12/31. * Add -V. Remove snooping. Ansify and Posixate. * Tune. Some USG hosts define NSIG but not sys_siglist. * Don't run /bin/sh if it's hopeless. * Don't leave garbage behind if the output is an empty pipe. * Clean up after SIGXCPU or SIGXFSZ. Print name of signal that caused cleanup. * * Revision 4.6 89/05/01 15:13:40 narten * changed copyright header to reflect current distribution rules * * Revision 4.5 88/11/08 16:01:02 narten * corrected use of varargs routines * * Revision 4.4 88/08/09 19:13:24 eggert * Check for memory exhaustion. * Permit signal handlers to yield either 'void' or 'int'; fix oldSIGINT botch. * Use execv(), not system(); yield exit status like diff(1)'s. * * Revision 4.3 87/10/18 10:40:22 narten * Updating version numbers. Changes relative to 1.1 actually * relative to 4.1 * * Revision 1.3 87/09/24 14:01:01 narten * Sources now pass through lint (if you ignore printf/sprintf/fprintf * warnings) * * Revision 1.2 87/03/27 14:22:43 jenkins * Port to suns * * Revision 4.1 83/05/10 15:53:13 wft * Added getcaller() and findlock(). * Changed catchints() to check SIGINT for SIG_IGN before setting up the signal * (needed for background jobs in older shells). Added restoreints(). * Removed printing of full RCS path from logcommand(). * * Revision 3.8 83/02/15 15:41:49 wft * Added routine fastcopy() to copy remainder of a file in blocks. * * Revision 3.7 82/12/24 15:25:19 wft * added catchints(), ignoreints() for catching and ingnoring interrupts; * fixed catchsig(). * * Revision 3.6 82/12/08 21:52:05 wft * Using DATEFORM to format dates. * * Revision 3.5 82/12/04 18:20:49 wft * Replaced SNOOPDIR with SNOOPFILE; changed addlock() to update * lockedby-field. * * Revision 3.4 82/12/03 17:17:43 wft * Added check to addlock() ensuring only one lock per person. * Addlock also returns a pointer to the lock created. Deleted fancydate(). * * Revision 3.3 82/11/27 12:24:37 wft * moved rmsema(), trysema(), trydiraccess(), getfullRCSname() to rcsfnms.c. * Introduced macro SNOOP so that snoop can be placed in directory other than * TARGETDIR. Changed %02d to %.2d for compatibility reasons. * * Revision 3.2 82/10/18 21:15:11 wft * added function getfullRCSname(). * * Revision 3.1 82/10/13 16:17:37 wft * Cleanup message is now suppressed in quiet mode. */#include "rcsbase.h"libId(utilId, "$Id: rcsutil.c,v 5.10 1991/10/07 17:32:46 eggert Exp $")#if !has_memcmp intmemcmp(s1, s2, n) void const *s1, *s2; size_t n;{ register unsigned char const *p1 = (unsigned char const*)s1, *p2 = (unsigned char const*)s2; register size_t i = n; register int r = 0; while (i-- && !(r = (*p1++ - *p2++))) ; return r;}#endif#if !has_memcpy void *memcpy(s1, s2, n) void *s1; void const *s2; size_t n;{ register char *p1 = (char*)s1; register char const *p2 = (char const*)s2; while (n--) *p1++ = *p2++; return s1;}#endif#if lint malloc_type lintalloc;#endif/* * list of blocks allocated with ftestalloc() * These blocks can be freed by ffree when we're done with the current file. * We could put the free block inside struct alloclist, rather than a pointer * to the free block, but that would be less portable. */struct alloclist { malloc_type alloc; struct alloclist *nextalloc;};static struct alloclist *alloced; static malloc_typeokalloc(p) malloc_type p;{ if (!p) faterror("out of memory"); return p;} malloc_typetestalloc(size) size_t size;/* Allocate a block, testing that the allocation succeeded. */{ return okalloc(malloc(size));} malloc_typetestrealloc(ptr, size) malloc_type ptr; size_t size;/* Reallocate a block, testing that the allocation succeeded. */{ return okalloc(realloc(ptr, size));} malloc_typefremember(ptr) malloc_type ptr;/* Remember PTR in 'alloced' so that it can be freed later. Yield PTR. */{ register struct alloclist *q = talloc(struct alloclist); q->nextalloc = alloced; alloced = q; return q->alloc = ptr;} malloc_typeftestalloc(size) size_t size;/* Allocate a block, putting it in 'alloced' so it can be freed later. */{ return fremember(testalloc(size));} voidffree()/* Free all blocks allocated with ftestalloc(). */{ register struct alloclist *p, *q; for (p = alloced; p; p = q) { q = p->nextalloc; tfree(p->alloc); tfree(p); } alloced = nil;} voidffree1(f) register char const *f;/* Free the block f, which was allocated by ftestalloc. */{ register struct alloclist *p, **a = &alloced; while ((p = *a)->alloc != f) a = &p->nextalloc; *a = p->nextalloc; tfree(p->alloc); tfree(p);} char *str_save(s) char const *s;/* Save s in permanently allocated storage. */{ return strcpy(tnalloc(char, strlen(s)+1), s);} char *fstr_save(s) char const *s;/* Save s in storage that will be deallocated when we're done with this file. */{ return strcpy(ftnalloc(char, strlen(s)+1), s);} char *cgetenv(name) char const *name;/* Like getenv(), but yield a copy; getenv() can overwrite old results. */{ register char *p; return (p=getenv(name)) ? str_save(p) : p;} char const *getusername(suspicious) int suspicious;/* Get the caller's login name. Trust only getwpuid if SUSPICIOUS. */{ static char *name; if (!name) { if ( /* Prefer getenv() unless suspicious; it's much faster. */# if getlogin_is_secure (suspicious || !(name = cgetenv("LOGNAME")) && !(name = cgetenv("USER"))) && !(name = getlogin())# else suspicious || !(name = cgetenv("LOGNAME")) && !(name = cgetenv("USER")) && !(name = getlogin())# endif ) {#if has_getuid && has_getpwuid struct passwd const *pw = getpwuid(ruid()); if (!pw) faterror("no password entry for userid %lu", (unsigned long)ruid() ); name = pw->pw_name;#else#if has_setuid faterror("setuid not supported");#else faterror("Who are you? Please set LOGNAME.");#endif#endif } checksid(name); } return name;}#if has_signal/* * Signal handling * * Standard C places too many restrictions on signal handlers. * We obey as many of them as we can. * Posix places fewer restrictions, and we are Posix-compatible here. */static sig_atomic_t volatile heldsignal, holdlevel; static signal_typecatchsig(s) int s;{ char const *sname; char buf[BUFSIZ];#if sig_zaps_handler /* If a signal arrives before we reset the signal handler, we lose. */ VOID signal(s, SIG_IGN);#endif if (holdlevel) { heldsignal = s; return; } ignoreints(); setrid(); if (!quietflag) { sname = nil;#if has_sys_siglist && defined(NSIG) if ((unsigned)s < NSIG) {# ifndef sys_siglist extern char const *sys_siglist[];# endif sname = sys_siglist[s]; }#else switch (s) {#ifdef SIGHUP case SIGHUP: sname = "Hangup"; break;#endif#ifdef SIGINT case SIGINT: sname = "Interrupt"; break;#endif#ifdef SIGPIPE case SIGPIPE: sname = "Broken pipe"; break;#endif#ifdef SIGQUIT case SIGQUIT: sname = "Quit"; break;#endif#ifdef SIGTERM case SIGTERM: sname = "Terminated"; break;#endif#ifdef SIGXCPU case SIGXCPU: sname = "Cputime limit exceeded"; break;#endif#ifdef SIGXFSZ case SIGXFSZ: sname = "Filesize limit exceeded"; break;#endif }#endif if (sname) VOID sprintf(buf, "\nRCS: %s. Cleaning up.\n", sname); else VOID sprintf(buf, "\nRCS: Signal %d. Cleaning up.\n", s); VOID write(STDERR_FILENO, buf, strlen(buf)); } exiterr();} voidignoreints(){ ++holdlevel;} voidrestoreints(){ if (!--holdlevel && heldsignal) VOID catchsig(heldsignal);}static int const sig[] = {#ifdef SIGHUP SIGHUP,#endif#ifdef SIGINT SIGINT,#endif#ifdef SIGPIPE SIGPIPE,#endif#ifdef SIGQUIT SIGQUIT,#endif#ifdef SIGTERM SIGTERM,#endif#ifdef SIGXCPU SIGXCPU,#endif#ifdef SIGXFSZ SIGXFSZ,#endif};#define SIGS (sizeof(sig)/sizeof(*sig))#if has_sigaction static void check_sig(r) int r; { if (r != 0) efaterror("signal"); } static void setup_catchsig() { register int i; sigset_t blocked; struct sigaction act; check_sig(sigemptyset(&blocked)); for (i=SIGS; 0<=--i; ) check_sig(sigaddset(&blocked, sig[i])); for (i=SIGS; 0<=--i; ) { check_sig(sigaction(sig[i], (struct sigaction*)nil, &act)); if (act.sa_handler != SIG_IGN) { act.sa_handler = catchsig; act.sa_mask = blocked; check_sig(sigaction(sig[i], &act, (struct sigaction*)nil)); } } }#else#if has_sigblock static void setup_catchsig() { register int i; int mask; mask = 0; for (i=SIGS; 0<=--i; ) mask |= sigmask(sig[i]); mask = sigblock(mask); for (i=SIGS; 0<=--i; ) if ( signal(sig[i], catchsig) == SIG_IGN && signal(sig[i], SIG_IGN) != catchsig ) faterror("signal catcher failure"); VOID sigsetmask(mask); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -