xref: /netbsd-src/external/gpl2/rcs/dist/src/rcsutil.c (revision fa28c6faa16e0b00edee7acdcaf4899797043def)
1*fa28c6faSchristos /*	$NetBSD: rcsutil.c,v 1.2 2016/01/14 04:22:39 christos Exp $	*/
27bdc2678Schristos 
37bdc2678Schristos /* RCS utility functions */
47bdc2678Schristos 
57bdc2678Schristos /* Copyright 1982, 1988, 1989 Walter Tichy
67bdc2678Schristos    Copyright 1990, 1991, 1992, 1993, 1994, 1995 Paul Eggert
77bdc2678Schristos    Distributed under license by the Free Software Foundation, Inc.
87bdc2678Schristos 
97bdc2678Schristos This file is part of RCS.
107bdc2678Schristos 
117bdc2678Schristos RCS is free software; you can redistribute it and/or modify
127bdc2678Schristos it under the terms of the GNU General Public License as published by
137bdc2678Schristos the Free Software Foundation; either version 2, or (at your option)
147bdc2678Schristos any later version.
157bdc2678Schristos 
167bdc2678Schristos RCS is distributed in the hope that it will be useful,
177bdc2678Schristos but WITHOUT ANY WARRANTY; without even the implied warranty of
187bdc2678Schristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
197bdc2678Schristos GNU General Public License for more details.
207bdc2678Schristos 
217bdc2678Schristos You should have received a copy of the GNU General Public License
227bdc2678Schristos along with RCS; see the file COPYING.
237bdc2678Schristos If not, write to the Free Software Foundation,
247bdc2678Schristos 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
257bdc2678Schristos 
267bdc2678Schristos Report problems and direct all questions to:
277bdc2678Schristos 
287bdc2678Schristos     rcs-bugs@cs.purdue.edu
297bdc2678Schristos 
307bdc2678Schristos */
317bdc2678Schristos 
327bdc2678Schristos 
337bdc2678Schristos 
347bdc2678Schristos 
357bdc2678Schristos /*
367bdc2678Schristos  * Log: rcsutil.c,v
377bdc2678Schristos  * Revision 5.20  1995/06/16 06:19:24  eggert
387bdc2678Schristos  * (catchsig): Remove `return'.
397bdc2678Schristos  * Update FSF address.
407bdc2678Schristos  *
417bdc2678Schristos  * Revision 5.19  1995/06/02 18:19:00  eggert
427bdc2678Schristos  * (catchsigaction): New name for `catchsig', for sa_sigaction signature.
437bdc2678Schristos  * Use nRCS even if !has_psiginfo, to remove unused variable warning.
447bdc2678Schristos  * (setup_catchsig): Use sa_sigaction only if has_sa_sigaction.
457bdc2678Schristos  * Use ENOTSUP only if defined.
467bdc2678Schristos  *
477bdc2678Schristos  * Revision 5.18  1995/06/01 16:23:43  eggert
487bdc2678Schristos  * (catchsig, restoreints, setup_catchsig): Use SA_SIGINFO, not has_psiginfo,
497bdc2678Schristos  * to determine whether to use SA_SIGINFO feature,
507bdc2678Schristos  * but also check at runtime whether the feature works.
517bdc2678Schristos  * (catchsig): If an mmap_signal occurs, report the affected file name.
527bdc2678Schristos  * (unsupported_SA_SIGINFO, accessName): New variables.
537bdc2678Schristos  * (setup_catchsig): If using SA_SIGINFO, use sa_sigaction, not sa_handler.
547bdc2678Schristos  * If SA_SIGINFO fails, fall back on sa_handler method.
557bdc2678Schristos  *
567bdc2678Schristos  * (readAccessFilenameBuffer, dupSafer, fdSafer, fopenSafer): New functions.
577bdc2678Schristos  * (concatenate): Remove.
587bdc2678Schristos  *
597bdc2678Schristos  * (runv): Work around bad_wait_if_SIGCHLD_ignored bug.
607bdc2678Schristos  * Remove reference to OPEN_O_WORK.
617bdc2678Schristos  *
627bdc2678Schristos  * Revision 5.17  1994/03/20 04:52:58  eggert
637bdc2678Schristos  * Specify subprocess input via file descriptor, not file name.
647bdc2678Schristos  * Avoid messing with I/O buffers in the child process.
657bdc2678Schristos  * Define dup in terms of F_DUPFD if it exists.
667bdc2678Schristos  * Move setmtime to rcsedit.c.  Remove lint.
677bdc2678Schristos  *
687bdc2678Schristos  * Revision 5.16  1993/11/09 17:40:15  eggert
697bdc2678Schristos  * -V now prints version on stdout and exits.
707bdc2678Schristos  *
717bdc2678Schristos  * Revision 5.15  1993/11/03 17:42:27  eggert
727bdc2678Schristos  * Use psiginfo and setreuid if available.  Move date2str to maketime.c.
737bdc2678Schristos  *
747bdc2678Schristos  * Revision 5.14  1992/07/28  16:12:44  eggert
757bdc2678Schristos  * Add -V.  has_sigaction overrides sig_zaps_handler.  Fix -M bug.
767bdc2678Schristos  * Add mmap_signal, which minimizes signal handling for non-mmap hosts.
777bdc2678Schristos  *
787bdc2678Schristos  * Revision 5.13  1992/02/17  23:02:28  eggert
797bdc2678Schristos  * Work around NFS mmap SIGBUS problem.  Add -T support.
807bdc2678Schristos  *
817bdc2678Schristos  * Revision 5.12  1992/01/24  18:44:19  eggert
827bdc2678Schristos  * Work around NFS mmap bug that leads to SIGBUS core dumps.  lint -> RCS_lint
837bdc2678Schristos  *
847bdc2678Schristos  * Revision 5.11  1992/01/06  02:42:34  eggert
857bdc2678Schristos  * O_BINARY -> OPEN_O_WORK
867bdc2678Schristos  * while (E) ; -> while (E) continue;
877bdc2678Schristos  *
887bdc2678Schristos  * Revision 5.10  1991/10/07  17:32:46  eggert
897bdc2678Schristos  * Support piece tables even if !has_mmap.
907bdc2678Schristos  *
917bdc2678Schristos  * Revision 5.9  1991/08/19  03:13:55  eggert
927bdc2678Schristos  * Add spawn() support.  Explicate assumptions about getting invoker's name.
937bdc2678Schristos  * Standardize user-visible dates.  Tune.
947bdc2678Schristos  *
957bdc2678Schristos  * Revision 5.8  1991/04/21  11:58:30  eggert
967bdc2678Schristos  * Plug setuid security hole.
977bdc2678Schristos  *
987bdc2678Schristos  * Revision 5.6  1991/02/26  17:48:39  eggert
997bdc2678Schristos  * Fix setuid bug.  Use fread, fwrite more portably.
1007bdc2678Schristos  * Support waitpid.  Don't assume -1 is acceptable to W* macros.
1017bdc2678Schristos  * strsave -> str_save (DG/UX name clash)
1027bdc2678Schristos  *
1037bdc2678Schristos  * Revision 5.5  1990/12/04  05:18:49  eggert
1047bdc2678Schristos  * Don't output a blank line after a signal diagnostic.
1057bdc2678Schristos  * Use -I for prompts and -q for diagnostics.
1067bdc2678Schristos  *
1077bdc2678Schristos  * Revision 5.4  1990/11/01  05:03:53  eggert
1087bdc2678Schristos  * Remove unneeded setid check.  Add awrite(), fremember().
1097bdc2678Schristos  *
1107bdc2678Schristos  * Revision 5.3  1990/10/06  00:16:45  eggert
1117bdc2678Schristos  * Don't fread F if feof(F).
1127bdc2678Schristos  *
1137bdc2678Schristos  * Revision 5.2  1990/09/04  08:02:31  eggert
1147bdc2678Schristos  * Store fread()'s result in an fread_type object.
1157bdc2678Schristos  *
1167bdc2678Schristos  * Revision 5.1  1990/08/29  07:14:07  eggert
1177bdc2678Schristos  * Declare getpwuid() more carefully.
1187bdc2678Schristos  *
1197bdc2678Schristos  * Revision 5.0  1990/08/22  08:13:46  eggert
1207bdc2678Schristos  * Add setuid support.  Permit multiple locks per user.
1217bdc2678Schristos  * Remove compile-time limits; use malloc instead.
1227bdc2678Schristos  * Switch to GMT.  Permit dates past 1999/12/31.
1237bdc2678Schristos  * Add -V.  Remove snooping.  Ansify and Posixate.
1247bdc2678Schristos  * Tune.  Some USG hosts define NSIG but not sys_siglist.
1257bdc2678Schristos  * Don't run /bin/sh if it's hopeless.
1267bdc2678Schristos  * Don't leave garbage behind if the output is an empty pipe.
1277bdc2678Schristos  * Clean up after SIGXCPU or SIGXFSZ.  Print name of signal that caused cleanup.
1287bdc2678Schristos  *
1297bdc2678Schristos  * Revision 4.6  89/05/01  15:13:40  narten
1307bdc2678Schristos  * changed copyright header to reflect current distribution rules
1317bdc2678Schristos  *
1327bdc2678Schristos  * Revision 4.5  88/11/08  16:01:02  narten
1337bdc2678Schristos  * corrected use of varargs routines
1347bdc2678Schristos  *
1357bdc2678Schristos  * Revision 4.4  88/08/09  19:13:24  eggert
1367bdc2678Schristos  * Check for memory exhaustion.
1377bdc2678Schristos  * Permit signal handlers to yield either 'void' or 'int'; fix oldSIGINT botch.
1387bdc2678Schristos  * Use execv(), not system(); yield exit status like diff(1)'s.
1397bdc2678Schristos  *
1407bdc2678Schristos  * Revision 4.3  87/10/18  10:40:22  narten
1417bdc2678Schristos  * Updating version numbers. Changes relative to 1.1 actually
1427bdc2678Schristos  * relative to 4.1
1437bdc2678Schristos  *
1447bdc2678Schristos  * Revision 1.3  87/09/24  14:01:01  narten
1457bdc2678Schristos  * Sources now pass through lint (if you ignore printf/sprintf/fprintf
1467bdc2678Schristos  * warnings)
1477bdc2678Schristos  *
1487bdc2678Schristos  * Revision 1.2  87/03/27  14:22:43  jenkins
1497bdc2678Schristos  * Port to suns
1507bdc2678Schristos  *
1517bdc2678Schristos  * Revision 4.1  83/05/10  15:53:13  wft
1527bdc2678Schristos  * Added getcaller() and findlock().
1537bdc2678Schristos  * Changed catchints() to check SIGINT for SIG_IGN before setting up the signal
1547bdc2678Schristos  * (needed for background jobs in older shells). Added restoreints().
1557bdc2678Schristos  * Removed printing of full RCS path from logcommand().
1567bdc2678Schristos  *
1577bdc2678Schristos  * Revision 3.8  83/02/15  15:41:49  wft
1587bdc2678Schristos  * Added routine fastcopy() to copy remainder of a file in blocks.
1597bdc2678Schristos  *
1607bdc2678Schristos  * Revision 3.7  82/12/24  15:25:19  wft
1617bdc2678Schristos  * added catchints(), ignoreints() for catching and ingnoring interrupts;
1627bdc2678Schristos  * fixed catchsig().
1637bdc2678Schristos  *
1647bdc2678Schristos  * Revision 3.6  82/12/08  21:52:05  wft
1657bdc2678Schristos  * Using DATEFORM to format dates.
1667bdc2678Schristos  *
1677bdc2678Schristos  * Revision 3.5  82/12/04  18:20:49  wft
1687bdc2678Schristos  * Replaced SNOOPDIR with SNOOPFILE; changed addlock() to update
1697bdc2678Schristos  * lockedby-field.
1707bdc2678Schristos  *
1717bdc2678Schristos  * Revision 3.4  82/12/03  17:17:43  wft
1727bdc2678Schristos  * Added check to addlock() ensuring only one lock per person.
1737bdc2678Schristos  * Addlock also returns a pointer to the lock created. Deleted fancydate().
1747bdc2678Schristos  *
1757bdc2678Schristos  * Revision 3.3  82/11/27  12:24:37  wft
1767bdc2678Schristos  * moved rmsema(), trysema(), trydiraccess(), getfullRCSname() to rcsfnms.c.
1777bdc2678Schristos  * Introduced macro SNOOP so that snoop can be placed in directory other than
1787bdc2678Schristos  * TARGETDIR. Changed %02d to %.2d for compatibility reasons.
1797bdc2678Schristos  *
1807bdc2678Schristos  * Revision 3.2  82/10/18  21:15:11  wft
1817bdc2678Schristos  * added function getfullRCSname().
1827bdc2678Schristos  *
1837bdc2678Schristos  * Revision 3.1  82/10/13  16:17:37  wft
1847bdc2678Schristos  * Cleanup message is now suppressed in quiet mode.
1857bdc2678Schristos  */
1867bdc2678Schristos 
1877bdc2678Schristos 
1887bdc2678Schristos 
1897bdc2678Schristos 
1907bdc2678Schristos #include "rcsbase.h"
1917bdc2678Schristos 
1927bdc2678Schristos libId(utilId, "Id: rcsutil.c,v 5.20 1995/06/16 06:19:24 eggert Exp ")
1937bdc2678Schristos 
1947bdc2678Schristos #if !has_memcmp
1957bdc2678Schristos 	int
1967bdc2678Schristos memcmp(s1, s2, n)
1977bdc2678Schristos 	void const *s1, *s2;
1987bdc2678Schristos 	size_t n;
1997bdc2678Schristos {
2007bdc2678Schristos 	register unsigned char const
2017bdc2678Schristos 		*p1 = (unsigned char const*)s1,
2027bdc2678Schristos 		*p2 = (unsigned char const*)s2;
2037bdc2678Schristos 	register size_t i = n;
2047bdc2678Schristos 	register int r = 0;
2057bdc2678Schristos 	while (i--  &&  !(r = (*p1++ - *p2++)))
2067bdc2678Schristos 		;
2077bdc2678Schristos 	return r;
2087bdc2678Schristos }
2097bdc2678Schristos #endif
2107bdc2678Schristos 
2117bdc2678Schristos #if !has_memcpy
2127bdc2678Schristos 	void *
memcpy(s1,s2,n)2137bdc2678Schristos memcpy(s1, s2, n)
2147bdc2678Schristos 	void *s1;
2157bdc2678Schristos 	void const *s2;
2167bdc2678Schristos 	size_t n;
2177bdc2678Schristos {
2187bdc2678Schristos 	register char *p1 = (char*)s1;
2197bdc2678Schristos 	register char const *p2 = (char const*)s2;
2207bdc2678Schristos 	while (n--)
2217bdc2678Schristos 		*p1++ = *p2++;
2227bdc2678Schristos 	return s1;
2237bdc2678Schristos }
2247bdc2678Schristos #endif
2257bdc2678Schristos 
2267bdc2678Schristos #if RCS_lint
2277bdc2678Schristos 	malloc_type lintalloc;
2287bdc2678Schristos #endif
2297bdc2678Schristos 
2307bdc2678Schristos /*
2317bdc2678Schristos  * list of blocks allocated with ftestalloc()
2327bdc2678Schristos  * These blocks can be freed by ffree when we're done with the current file.
2337bdc2678Schristos  * We could put the free block inside struct alloclist, rather than a pointer
2347bdc2678Schristos  * to the free block, but that would be less portable.
2357bdc2678Schristos  */
2367bdc2678Schristos struct alloclist {
2377bdc2678Schristos 	malloc_type alloc;
2387bdc2678Schristos 	struct alloclist *nextalloc;
2397bdc2678Schristos };
2407bdc2678Schristos static struct alloclist *alloced;
2417bdc2678Schristos 
2427bdc2678Schristos 
2437bdc2678Schristos 	static malloc_type okalloc P((malloc_type));
2447bdc2678Schristos 	static malloc_type
okalloc(p)2457bdc2678Schristos okalloc(p)
2467bdc2678Schristos 	malloc_type p;
2477bdc2678Schristos {
2487bdc2678Schristos 	if (!p)
2497bdc2678Schristos 		faterror("out of memory");
2507bdc2678Schristos 	return p;
2517bdc2678Schristos }
2527bdc2678Schristos 
2537bdc2678Schristos 	malloc_type
testalloc(size)2547bdc2678Schristos testalloc(size)
2557bdc2678Schristos 	size_t size;
2567bdc2678Schristos /* Allocate a block, testing that the allocation succeeded.  */
2577bdc2678Schristos {
2587bdc2678Schristos 	return okalloc(malloc(size));
2597bdc2678Schristos }
2607bdc2678Schristos 
2617bdc2678Schristos 	malloc_type
testrealloc(ptr,size)2627bdc2678Schristos testrealloc(ptr, size)
2637bdc2678Schristos 	malloc_type ptr;
2647bdc2678Schristos 	size_t size;
2657bdc2678Schristos /* Reallocate a block, testing that the allocation succeeded.  */
2667bdc2678Schristos {
2677bdc2678Schristos 	return okalloc(realloc(ptr, size));
2687bdc2678Schristos }
2697bdc2678Schristos 
2707bdc2678Schristos 	malloc_type
fremember(ptr)2717bdc2678Schristos fremember(ptr)
2727bdc2678Schristos 	malloc_type ptr;
2737bdc2678Schristos /* Remember PTR in 'alloced' so that it can be freed later.  Yield PTR.  */
2747bdc2678Schristos {
2757bdc2678Schristos 	register struct alloclist *q = talloc(struct alloclist);
2767bdc2678Schristos 	q->nextalloc = alloced;
2777bdc2678Schristos 	alloced = q;
2787bdc2678Schristos 	return q->alloc = ptr;
2797bdc2678Schristos }
2807bdc2678Schristos 
2817bdc2678Schristos 	malloc_type
ftestalloc(size)2827bdc2678Schristos ftestalloc(size)
2837bdc2678Schristos 	size_t size;
2847bdc2678Schristos /* Allocate a block, putting it in 'alloced' so it can be freed later. */
2857bdc2678Schristos {
2867bdc2678Schristos 	return fremember(testalloc(size));
2877bdc2678Schristos }
2887bdc2678Schristos 
2897bdc2678Schristos 	void
ffree()2907bdc2678Schristos ffree()
2917bdc2678Schristos /* Free all blocks allocated with ftestalloc().  */
2927bdc2678Schristos {
2937bdc2678Schristos 	register struct alloclist *p, *q;
2947bdc2678Schristos 	for (p = alloced;  p;  p = q) {
2957bdc2678Schristos 		q = p->nextalloc;
2967bdc2678Schristos 		tfree(p->alloc);
2977bdc2678Schristos 		tfree(p);
2987bdc2678Schristos 	}
2997bdc2678Schristos 	alloced = 0;
3007bdc2678Schristos }
3017bdc2678Schristos 
3027bdc2678Schristos 	void
ffree1(f)3037bdc2678Schristos ffree1(f)
3047bdc2678Schristos 	register char const *f;
3057bdc2678Schristos /* Free the block f, which was allocated by ftestalloc.  */
3067bdc2678Schristos {
3077bdc2678Schristos 	register struct alloclist *p, **a = &alloced;
3087bdc2678Schristos 
3097bdc2678Schristos 	while ((p = *a)->alloc  !=  f)
3107bdc2678Schristos 		a = &p->nextalloc;
3117bdc2678Schristos 	*a = p->nextalloc;
3127bdc2678Schristos 	tfree(p->alloc);
3137bdc2678Schristos 	tfree(p);
3147bdc2678Schristos }
3157bdc2678Schristos 
3167bdc2678Schristos 	char *
str_save(s)3177bdc2678Schristos str_save(s)
3187bdc2678Schristos 	char const *s;
3197bdc2678Schristos /* Save s in permanently allocated storage. */
3207bdc2678Schristos {
3217bdc2678Schristos 	return strcpy(tnalloc(char, strlen(s)+1), s);
3227bdc2678Schristos }
3237bdc2678Schristos 
3247bdc2678Schristos 	char *
fstr_save(s)3257bdc2678Schristos fstr_save(s)
3267bdc2678Schristos 	char const *s;
3277bdc2678Schristos /* Save s in storage that will be deallocated when we're done with this file. */
3287bdc2678Schristos {
3297bdc2678Schristos 	return strcpy(ftnalloc(char, strlen(s)+1), s);
3307bdc2678Schristos }
3317bdc2678Schristos 
3327bdc2678Schristos 	char *
cgetenv(name)3337bdc2678Schristos cgetenv(name)
3347bdc2678Schristos 	char const *name;
3357bdc2678Schristos /* Like getenv(), but yield a copy; getenv() can overwrite old results. */
3367bdc2678Schristos {
3377bdc2678Schristos 	register char *p;
3387bdc2678Schristos 
3397bdc2678Schristos 	return (p=getenv(name)) ? str_save(p) : p;
3407bdc2678Schristos }
3417bdc2678Schristos 
3427bdc2678Schristos 	char const *
getusername(suspicious)3437bdc2678Schristos getusername(suspicious)
3447bdc2678Schristos 	int suspicious;
3457bdc2678Schristos /* Get the caller's login name.  Trust only getwpuid if SUSPICIOUS.  */
3467bdc2678Schristos {
3477bdc2678Schristos 	static char *name;
3487bdc2678Schristos 
3497bdc2678Schristos 	if (!name) {
3507bdc2678Schristos 		if (
3517bdc2678Schristos 		    /* Prefer getenv() unless suspicious; it's much faster.  */
3527bdc2678Schristos #		    if getlogin_is_secure
3537bdc2678Schristos 			    (suspicious
3547bdc2678Schristos 			    || (
3557bdc2678Schristos 				    !(name = cgetenv("LOGNAME"))
3567bdc2678Schristos 				&&  !(name = cgetenv("USER"))
3577bdc2678Schristos 			    ))
3587bdc2678Schristos 			&&  !(name = getlogin())
3597bdc2678Schristos #		    else
3607bdc2678Schristos 			suspicious
3617bdc2678Schristos 			|| (
3627bdc2678Schristos 				!(name = cgetenv("LOGNAME"))
3637bdc2678Schristos 			    &&  !(name = cgetenv("USER"))
3647bdc2678Schristos 			    &&  !(name = getlogin())
3657bdc2678Schristos 			)
3667bdc2678Schristos #		    endif
3677bdc2678Schristos 		) {
3687bdc2678Schristos #if has_getuid && has_getpwuid
3697bdc2678Schristos 			struct passwd const *pw = getpwuid(ruid());
3707bdc2678Schristos 			if (!pw)
3717bdc2678Schristos 			    faterror("no password entry for userid %lu",
3727bdc2678Schristos 				     (unsigned long)ruid()
3737bdc2678Schristos 			    );
374*fa28c6faSchristos 			name = strdup(pw->pw_name);
3757bdc2678Schristos #else
3767bdc2678Schristos #if has_setuid
3777bdc2678Schristos 			faterror("setuid not supported");
3787bdc2678Schristos #else
3797bdc2678Schristos 			faterror("Who are you?  Please setenv LOGNAME.");
3807bdc2678Schristos #endif
3817bdc2678Schristos #endif
3827bdc2678Schristos 		}
3837bdc2678Schristos 		checksid(name);
3847bdc2678Schristos 	}
3857bdc2678Schristos 	return name;
3867bdc2678Schristos }
3877bdc2678Schristos 
3887bdc2678Schristos 
3897bdc2678Schristos 
3907bdc2678Schristos 
3917bdc2678Schristos #if has_signal
3927bdc2678Schristos 
3937bdc2678Schristos /*
3947bdc2678Schristos  *	 Signal handling
3957bdc2678Schristos  *
3967bdc2678Schristos  * Standard C places too many restrictions on signal handlers.
3977bdc2678Schristos  * We obey as many of them as we can.
3987bdc2678Schristos  * Posix places fewer restrictions, and we are Posix-compatible here.
3997bdc2678Schristos  */
4007bdc2678Schristos 
4017bdc2678Schristos static sig_atomic_t volatile heldsignal, holdlevel;
4027bdc2678Schristos #ifdef SA_SIGINFO
4037bdc2678Schristos 	static int unsupported_SA_SIGINFO;
4047bdc2678Schristos 	static siginfo_t bufsiginfo;
4057bdc2678Schristos 	static siginfo_t *volatile heldsiginfo;
4067bdc2678Schristos #endif
4077bdc2678Schristos 
4087bdc2678Schristos 
4097bdc2678Schristos #if has_NFS && has_mmap && large_memory && mmap_signal
4107bdc2678Schristos     static char const *accessName;
4117bdc2678Schristos 
4127bdc2678Schristos 	  void
readAccessFilenameBuffer(filename,p)4137bdc2678Schristos     readAccessFilenameBuffer(filename, p)
4147bdc2678Schristos 	char const *filename;
4157bdc2678Schristos 	unsigned char const *p;
4167bdc2678Schristos     {
4177bdc2678Schristos 	unsigned char volatile t;
4187bdc2678Schristos 	accessName = filename;
4197bdc2678Schristos 	t = *p;
4207bdc2678Schristos 	accessName = 0;
4217bdc2678Schristos     }
4227bdc2678Schristos #else
4237bdc2678Schristos #   define accessName ((char const *) 0)
4247bdc2678Schristos #endif
4257bdc2678Schristos 
4267bdc2678Schristos 
4277bdc2678Schristos #if !has_psignal
4287bdc2678Schristos 
4297bdc2678Schristos # define psignal my_psignal
4307bdc2678Schristos 	static void my_psignal P((int,char const*));
4317bdc2678Schristos 	static void
my_psignal(sig,s)4327bdc2678Schristos my_psignal(sig, s)
4337bdc2678Schristos 	int sig;
4347bdc2678Schristos 	char const *s;
4357bdc2678Schristos {
4367bdc2678Schristos 	char const *sname = "Unknown signal";
4377bdc2678Schristos #	if has_sys_siglist && defined(NSIG)
4387bdc2678Schristos 	    if ((unsigned)sig < NSIG)
4397bdc2678Schristos 		sname = sys_siglist[sig];
4407bdc2678Schristos #	else
4417bdc2678Schristos 	    switch (sig) {
4427bdc2678Schristos #	       ifdef SIGHUP
4437bdc2678Schristos 		case SIGHUP:	sname = "Hangup";  break;
4447bdc2678Schristos #	       endif
4457bdc2678Schristos #	       ifdef SIGINT
4467bdc2678Schristos 		case SIGINT:	sname = "Interrupt";  break;
4477bdc2678Schristos #	       endif
4487bdc2678Schristos #	       ifdef SIGPIPE
4497bdc2678Schristos 		case SIGPIPE:	sname = "Broken pipe";  break;
4507bdc2678Schristos #	       endif
4517bdc2678Schristos #	       ifdef SIGQUIT
4527bdc2678Schristos 		case SIGQUIT:	sname = "Quit";  break;
4537bdc2678Schristos #	       endif
4547bdc2678Schristos #	       ifdef SIGTERM
4557bdc2678Schristos 		case SIGTERM:	sname = "Terminated";  break;
4567bdc2678Schristos #	       endif
4577bdc2678Schristos #	       ifdef SIGXCPU
4587bdc2678Schristos 		case SIGXCPU:	sname = "Cputime limit exceeded";  break;
4597bdc2678Schristos #	       endif
4607bdc2678Schristos #	       ifdef SIGXFSZ
4617bdc2678Schristos 		case SIGXFSZ:	sname = "Filesize limit exceeded";  break;
4627bdc2678Schristos #	       endif
4637bdc2678Schristos #	      if has_mmap && large_memory
4647bdc2678Schristos #	       if defined(SIGBUS) && mmap_signal==SIGBUS
4657bdc2678Schristos 		case SIGBUS:	sname = "Bus error";  break;
4667bdc2678Schristos #	       endif
4677bdc2678Schristos #	       if defined(SIGSEGV) && mmap_signal==SIGSEGV
4687bdc2678Schristos 		case SIGSEGV:	sname = "Segmentation fault";  break;
4697bdc2678Schristos #	       endif
4707bdc2678Schristos #	      endif
4717bdc2678Schristos 	    }
4727bdc2678Schristos #	endif
4737bdc2678Schristos 
4747bdc2678Schristos 	/* Avoid calling sprintf etc., in case they're not reentrant.  */
4757bdc2678Schristos 	{
4767bdc2678Schristos 	    char const *p;
4777bdc2678Schristos 	    char buf[BUFSIZ], *b = buf;
4787bdc2678Schristos 	    for (p = s;  *p;  *b++ = *p++)
4797bdc2678Schristos 		continue;
4807bdc2678Schristos 	    *b++ = ':';
4817bdc2678Schristos 	    *b++ = ' ';
4827bdc2678Schristos 	    for (p = sname;  *p;  *b++ = *p++)
4837bdc2678Schristos 		continue;
4847bdc2678Schristos 	    *b++ = '\n';
4857bdc2678Schristos 	    VOID write(STDERR_FILENO, buf, b - buf);
4867bdc2678Schristos 	}
4877bdc2678Schristos }
4887bdc2678Schristos #endif
4897bdc2678Schristos 
4907bdc2678Schristos static signal_type catchsig P((int));
4917bdc2678Schristos #ifdef SA_SIGINFO
4927bdc2678Schristos 	static signal_type catchsigaction P((int,siginfo_t*,void*));
4937bdc2678Schristos #endif
4947bdc2678Schristos 
4957bdc2678Schristos 	static signal_type
catchsig(s)4967bdc2678Schristos catchsig(s)
4977bdc2678Schristos 	int s;
4987bdc2678Schristos #ifdef SA_SIGINFO
4997bdc2678Schristos {
5007bdc2678Schristos 	catchsigaction(s, (siginfo_t *)0, (void *)0);
5017bdc2678Schristos }
5027bdc2678Schristos 	static signal_type
catchsigaction(s,i,c)5037bdc2678Schristos catchsigaction(s, i, c)
5047bdc2678Schristos 	int s;
5057bdc2678Schristos 	siginfo_t *i;
5067bdc2678Schristos 	void *c;
5077bdc2678Schristos #endif
5087bdc2678Schristos {
5097bdc2678Schristos #   if sig_zaps_handler
5107bdc2678Schristos 	/* If a signal arrives before we reset the handler, we lose. */
5117bdc2678Schristos 	VOID signal(s, SIG_IGN);
5127bdc2678Schristos #   endif
5137bdc2678Schristos 
5147bdc2678Schristos #   ifdef SA_SIGINFO
5157bdc2678Schristos 	if (!unsupported_SA_SIGINFO)
5167bdc2678Schristos 	    i = 0;
5177bdc2678Schristos #   endif
5187bdc2678Schristos 
5197bdc2678Schristos     if (holdlevel) {
5207bdc2678Schristos 	heldsignal = s;
5217bdc2678Schristos #	ifdef SA_SIGINFO
5227bdc2678Schristos 	    if (i) {
5237bdc2678Schristos 		bufsiginfo = *i;
5247bdc2678Schristos 		heldsiginfo = &bufsiginfo;
5257bdc2678Schristos 	    }
5267bdc2678Schristos #	endif
5277bdc2678Schristos 	return;
5287bdc2678Schristos     }
5297bdc2678Schristos 
5307bdc2678Schristos     ignoreints();
5317bdc2678Schristos     setrid();
5327bdc2678Schristos     if (!quietflag) {
5337bdc2678Schristos 	/* Avoid calling sprintf etc., in case they're not reentrant.  */
5347bdc2678Schristos 	char const *p;
5357bdc2678Schristos 	char buf[BUFSIZ], *b = buf;
5367bdc2678Schristos 
5377bdc2678Schristos 	if ( !	(
5387bdc2678Schristos #		if has_mmap && large_memory && mmap_signal
5397bdc2678Schristos 			/* Check whether this signal was planned.  */
5407bdc2678Schristos 			s == mmap_signal && accessName
5417bdc2678Schristos #		else
5427bdc2678Schristos 			0
5437bdc2678Schristos #		endif
5447bdc2678Schristos 	)) {
5457bdc2678Schristos 	    char const *nRCS = "\nRCS";
5467bdc2678Schristos #	    if defined(SA_SIGINFO) && has_si_errno && has_mmap && large_memory && mmap_signal
5477bdc2678Schristos 		if (s == mmap_signal  &&  i  &&  i->si_errno) {
5487bdc2678Schristos 		    errno = i->si_errno;
5497bdc2678Schristos 		    perror(nRCS++);
5507bdc2678Schristos 		}
5517bdc2678Schristos #	    endif
5527bdc2678Schristos #	    if defined(SA_SIGINFO) && has_psiginfo
5537bdc2678Schristos 		if (i)
5547bdc2678Schristos 		    psiginfo(i, nRCS);
5557bdc2678Schristos 		else
5567bdc2678Schristos 		    psignal(s, nRCS);
5577bdc2678Schristos #	    else
5587bdc2678Schristos 		psignal(s, nRCS);
5597bdc2678Schristos #	    endif
5607bdc2678Schristos 	}
5617bdc2678Schristos 
5627bdc2678Schristos 	for (p = "RCS: ";  *p;  *b++ = *p++)
5637bdc2678Schristos 	    continue;
5647bdc2678Schristos #	if has_mmap && large_memory && mmap_signal
5657bdc2678Schristos 	    if (s == mmap_signal) {
5667bdc2678Schristos 		p = accessName;
5677bdc2678Schristos 		if (!p)
5687bdc2678Schristos 		    p = "Was a file changed by some other process?  ";
5697bdc2678Schristos 		else {
5707bdc2678Schristos 		    char const *p1;
5717bdc2678Schristos 		    for (p1 = p;  *p1;  p1++)
5727bdc2678Schristos 			continue;
5737bdc2678Schristos 		    VOID write(STDERR_FILENO, buf, b - buf);
5747bdc2678Schristos 		    VOID write(STDERR_FILENO, p, p1 - p);
5757bdc2678Schristos 		    b = buf;
5767bdc2678Schristos 		    p = ": Permission denied.  ";
5777bdc2678Schristos 		}
5787bdc2678Schristos 		while (*p)
5797bdc2678Schristos 		    *b++ = *p++;
5807bdc2678Schristos 	    }
5817bdc2678Schristos #	endif
5827bdc2678Schristos 	for (p = "Cleaning up.\n";  *p;  *b++ = *p++)
5837bdc2678Schristos 	    continue;
5847bdc2678Schristos 	VOID write(STDERR_FILENO, buf, b - buf);
5857bdc2678Schristos     }
5867bdc2678Schristos     exiterr();
5877bdc2678Schristos }
5887bdc2678Schristos 
5897bdc2678Schristos 	void
ignoreints()5907bdc2678Schristos ignoreints()
5917bdc2678Schristos {
5927bdc2678Schristos 	++holdlevel;
5937bdc2678Schristos }
5947bdc2678Schristos 
5957bdc2678Schristos 	void
restoreints()5967bdc2678Schristos restoreints()
5977bdc2678Schristos {
5987bdc2678Schristos 	if (!--holdlevel && heldsignal)
5997bdc2678Schristos #	    ifdef SA_SIGINFO
6007bdc2678Schristos 		VOID catchsigaction(heldsignal, heldsiginfo, (void *)0);
6017bdc2678Schristos #	    else
6027bdc2678Schristos 		VOID catchsig(heldsignal);
6037bdc2678Schristos #	    endif
6047bdc2678Schristos }
6057bdc2678Schristos 
6067bdc2678Schristos 
6077bdc2678Schristos static void setup_catchsig P((int const*,int));
6087bdc2678Schristos 
6097bdc2678Schristos #if has_sigaction
6107bdc2678Schristos 
6117bdc2678Schristos 	static void check_sig P((int));
6127bdc2678Schristos 	static void
check_sig(r)6137bdc2678Schristos   check_sig(r)
6147bdc2678Schristos 	int r;
6157bdc2678Schristos   {
6167bdc2678Schristos 	if (r != 0)
6177bdc2678Schristos 		efaterror("signal handling");
6187bdc2678Schristos   }
6197bdc2678Schristos 
6207bdc2678Schristos 	static void
setup_catchsig(sig,sigs)6217bdc2678Schristos   setup_catchsig(sig, sigs)
6227bdc2678Schristos 	int const *sig;
6237bdc2678Schristos 	int sigs;
6247bdc2678Schristos   {
6257bdc2678Schristos 	register int i, j;
6267bdc2678Schristos 	struct sigaction act;
6277bdc2678Schristos 
6287bdc2678Schristos 	for (i=sigs; 0<=--i; ) {
6297bdc2678Schristos 	    check_sig(sigaction(sig[i], (struct sigaction*)0, &act));
6307bdc2678Schristos 	    if (act.sa_handler != SIG_IGN) {
6317bdc2678Schristos 		act.sa_handler = catchsig;
6327bdc2678Schristos #		ifdef SA_SIGINFO
6337bdc2678Schristos 		    if (!unsupported_SA_SIGINFO) {
6347bdc2678Schristos #			if has_sa_sigaction
6357bdc2678Schristos 			    act.sa_sigaction = catchsigaction;
6367bdc2678Schristos #			else
6377bdc2678Schristos 			    act.sa_handler = catchsigaction;
6387bdc2678Schristos #			endif
6397bdc2678Schristos 			act.sa_flags |= SA_SIGINFO;
6407bdc2678Schristos 		    }
6417bdc2678Schristos #		endif
6427bdc2678Schristos 		for (j=sigs; 0<=--j; )
6437bdc2678Schristos 		    check_sig(sigaddset(&act.sa_mask, sig[j]));
6447bdc2678Schristos 		if (sigaction(sig[i], &act, (struct sigaction*)0) != 0) {
6457bdc2678Schristos #		    if defined(SA_SIGINFO) && defined(ENOTSUP)
6467bdc2678Schristos 			if (errno == ENOTSUP  &&  !unsupported_SA_SIGINFO) {
6477bdc2678Schristos 			    /* Turn off use of SA_SIGINFO and try again.  */
6487bdc2678Schristos 			    unsupported_SA_SIGINFO = 1;
6497bdc2678Schristos 			    i++;
6507bdc2678Schristos 			    continue;
6517bdc2678Schristos 			}
6527bdc2678Schristos #		    endif
6537bdc2678Schristos 		    check_sig(-1);
6547bdc2678Schristos 		}
6557bdc2678Schristos 	    }
6567bdc2678Schristos 	}
6577bdc2678Schristos   }
6587bdc2678Schristos 
6597bdc2678Schristos #else
6607bdc2678Schristos #if has_sigblock
6617bdc2678Schristos 
6627bdc2678Schristos 	static void
setup_catchsig(sig,sigs)6637bdc2678Schristos   setup_catchsig(sig, sigs)
6647bdc2678Schristos 	int const *sig;
6657bdc2678Schristos 	int sigs;
6667bdc2678Schristos   {
6677bdc2678Schristos 	register int i;
6687bdc2678Schristos 	int mask;
6697bdc2678Schristos 
6707bdc2678Schristos 	mask = 0;
6717bdc2678Schristos 	for (i=sigs; 0<=--i; )
6727bdc2678Schristos 		mask |= sigmask(sig[i]);
6737bdc2678Schristos 	mask = sigblock(mask);
6747bdc2678Schristos 	for (i=sigs; 0<=--i; )
6757bdc2678Schristos 		if (
6767bdc2678Schristos 		    signal(sig[i], catchsig) == SIG_IGN  &&
6777bdc2678Schristos 		    signal(sig[i], SIG_IGN) != catchsig
6787bdc2678Schristos 		)
6797bdc2678Schristos 			faterror("signal catcher failure");
6807bdc2678Schristos 	VOID sigsetmask(mask);
6817bdc2678Schristos   }
6827bdc2678Schristos 
6837bdc2678Schristos #else
6847bdc2678Schristos 
6857bdc2678Schristos 	static void
setup_catchsig(sig,sigs)6867bdc2678Schristos   setup_catchsig(sig, sigs)
6877bdc2678Schristos 	int const *sig;
6887bdc2678Schristos 	int sigs;
6897bdc2678Schristos   {
6907bdc2678Schristos 	register i;
6917bdc2678Schristos 
6927bdc2678Schristos 	for (i=sigs; 0<=--i; )
6937bdc2678Schristos 		if (
6947bdc2678Schristos 		    signal(sig[i], SIG_IGN) != SIG_IGN  &&
6957bdc2678Schristos 		    signal(sig[i], catchsig) != SIG_IGN
6967bdc2678Schristos 		)
6977bdc2678Schristos 			faterror("signal catcher failure");
6987bdc2678Schristos   }
6997bdc2678Schristos 
7007bdc2678Schristos #endif
7017bdc2678Schristos #endif
7027bdc2678Schristos 
7037bdc2678Schristos 
7047bdc2678Schristos static int const regsigs[] = {
7057bdc2678Schristos # ifdef SIGHUP
7067bdc2678Schristos 	SIGHUP,
7077bdc2678Schristos # endif
7087bdc2678Schristos # ifdef SIGINT
7097bdc2678Schristos 	SIGINT,
7107bdc2678Schristos # endif
7117bdc2678Schristos # ifdef SIGPIPE
7127bdc2678Schristos 	SIGPIPE,
7137bdc2678Schristos # endif
7147bdc2678Schristos # ifdef SIGQUIT
7157bdc2678Schristos 	SIGQUIT,
7167bdc2678Schristos # endif
7177bdc2678Schristos # ifdef SIGTERM
7187bdc2678Schristos 	SIGTERM,
7197bdc2678Schristos # endif
7207bdc2678Schristos # ifdef SIGXCPU
7217bdc2678Schristos 	SIGXCPU,
7227bdc2678Schristos # endif
7237bdc2678Schristos # ifdef SIGXFSZ
7247bdc2678Schristos 	SIGXFSZ,
7257bdc2678Schristos # endif
7267bdc2678Schristos };
7277bdc2678Schristos 
7287bdc2678Schristos 	void
catchints()7297bdc2678Schristos catchints()
7307bdc2678Schristos {
7317bdc2678Schristos 	static int catching_ints;
7327bdc2678Schristos 	if (!catching_ints) {
7337bdc2678Schristos 	    catching_ints = true;
7347bdc2678Schristos 	    setup_catchsig(regsigs, (int) (sizeof(regsigs)/sizeof(*regsigs)));
7357bdc2678Schristos 	}
7367bdc2678Schristos }
7377bdc2678Schristos 
7387bdc2678Schristos #if has_mmap && large_memory && mmap_signal
7397bdc2678Schristos 
7407bdc2678Schristos     /*
7417bdc2678Schristos     * If you mmap an NFS file, and someone on another client removes the last
7427bdc2678Schristos     * link to that file, and you later reference an uncached part of that file,
7437bdc2678Schristos     * you'll get a SIGBUS or SIGSEGV (depending on the operating system).
7447bdc2678Schristos     * Catch the signal and report the problem to the user.
7457bdc2678Schristos     * Unfortunately, there's no portable way to differentiate between this
7467bdc2678Schristos     * problem and actual bugs in the program.
7477bdc2678Schristos     * This NFS problem is rare, thank goodness.
7487bdc2678Schristos     *
7497bdc2678Schristos     * This can also occur if someone truncates the file, even without NFS.
7507bdc2678Schristos     */
7517bdc2678Schristos 
7527bdc2678Schristos     static int const mmapsigs[] = { mmap_signal };
7537bdc2678Schristos 
7547bdc2678Schristos 	    void
catchmmapints()7557bdc2678Schristos     catchmmapints()
7567bdc2678Schristos     {
7577bdc2678Schristos 	static int catching_mmap_ints;
7587bdc2678Schristos 	if (!catching_mmap_ints) {
7597bdc2678Schristos 	    catching_mmap_ints = true;
7607bdc2678Schristos 	    setup_catchsig(mmapsigs, (int)(sizeof(mmapsigs)/sizeof(*mmapsigs)));
7617bdc2678Schristos 	}
7627bdc2678Schristos     }
7637bdc2678Schristos #endif
7647bdc2678Schristos 
7657bdc2678Schristos #endif /* has_signal */
7667bdc2678Schristos 
7677bdc2678Schristos 
7687bdc2678Schristos 	void
fastcopy(inf,outf)7697bdc2678Schristos fastcopy(inf,outf)
7707bdc2678Schristos 	register RILE *inf;
7717bdc2678Schristos 	FILE *outf;
7727bdc2678Schristos /* Function: copies the remainder of file inf to outf.
7737bdc2678Schristos  */
7747bdc2678Schristos {
7757bdc2678Schristos #if large_memory
7767bdc2678Schristos #	if maps_memory
7777bdc2678Schristos 	    awrite((char const*)inf->ptr, (size_t)(inf->lim - inf->ptr), outf);
7787bdc2678Schristos 	    inf->ptr = inf->lim;
7797bdc2678Schristos #	else
7807bdc2678Schristos 	    for (;;) {
7817bdc2678Schristos 		awrite((char const*)inf->ptr, (size_t)(inf->readlim - inf->ptr), outf);
7827bdc2678Schristos 		inf->ptr = inf->readlim;
7837bdc2678Schristos 		if (inf->ptr == inf->lim)
7847bdc2678Schristos 		    break;
7857bdc2678Schristos 		VOID Igetmore(inf);
7867bdc2678Schristos 	    }
7877bdc2678Schristos #	endif
7887bdc2678Schristos #else
7897bdc2678Schristos 	char buf[BUFSIZ*8];
7907bdc2678Schristos 	register fread_type rcount;
7917bdc2678Schristos 
7927bdc2678Schristos         /*now read the rest of the file in blocks*/
7937bdc2678Schristos 	while (!feof(inf)) {
7947bdc2678Schristos 		if (!(rcount = Fread(buf,sizeof(*buf),sizeof(buf),inf))) {
7957bdc2678Schristos 			testIerror(inf);
7967bdc2678Schristos 			return;
7977bdc2678Schristos 		}
7987bdc2678Schristos 		awrite(buf, (size_t)rcount, outf);
7997bdc2678Schristos         }
8007bdc2678Schristos #endif
8017bdc2678Schristos }
8027bdc2678Schristos 
8037bdc2678Schristos #ifndef SSIZE_MAX
8047bdc2678Schristos  /* This does not work in #ifs, but it's good enough for us.  */
8057bdc2678Schristos  /* Underestimating SSIZE_MAX may slow us down, but it won't break us.  */
8067bdc2678Schristos #	define SSIZE_MAX ((unsigned)-1 >> 1)
8077bdc2678Schristos #endif
8087bdc2678Schristos 
8097bdc2678Schristos 	void
awrite(buf,chars,f)8107bdc2678Schristos awrite(buf, chars, f)
8117bdc2678Schristos 	char const *buf;
8127bdc2678Schristos 	size_t chars;
8137bdc2678Schristos 	FILE *f;
8147bdc2678Schristos {
815*fa28c6faSchristos 	if (buf == NULL)
816*fa28c6faSchristos 		return;
817*fa28c6faSchristos 
8187bdc2678Schristos 	/* Posix 1003.1-1990 ssize_t hack */
8197bdc2678Schristos 	while (SSIZE_MAX < chars) {
8207bdc2678Schristos 		if (Fwrite(buf, sizeof(*buf), SSIZE_MAX, f)  !=  SSIZE_MAX)
8217bdc2678Schristos 			Oerror();
8227bdc2678Schristos 		buf += SSIZE_MAX;
8237bdc2678Schristos 		chars -= SSIZE_MAX;
8247bdc2678Schristos 	}
8257bdc2678Schristos 
8267bdc2678Schristos 	if (Fwrite(buf, sizeof(*buf), chars, f)  !=  chars)
8277bdc2678Schristos 		Oerror();
8287bdc2678Schristos }
8297bdc2678Schristos 
8307bdc2678Schristos /* dup a file descriptor; the result must not be stdin, stdout, or stderr.  */
8317bdc2678Schristos 	static int dupSafer P((int));
8327bdc2678Schristos 	static int
dupSafer(fd)8337bdc2678Schristos dupSafer(fd)
8347bdc2678Schristos 	int fd;
8357bdc2678Schristos {
8367bdc2678Schristos #	ifdef F_DUPFD
8377bdc2678Schristos 	    return fcntl(fd, F_DUPFD, STDERR_FILENO + 1);
8387bdc2678Schristos #	else
8397bdc2678Schristos 	    int e, f, i, used = 0;
8407bdc2678Schristos 	    while (STDIN_FILENO <= (f = dup(fd))  &&  f <= STDERR_FILENO)
8417bdc2678Schristos 		    used |= 1<<f;
8427bdc2678Schristos 	    e = errno;
8437bdc2678Schristos 	    for (i = STDIN_FILENO;  i <= STDERR_FILENO;  i++)
8447bdc2678Schristos 		    if (used & (1<<i))
8457bdc2678Schristos 			    VOID close(i);
8467bdc2678Schristos 	    errno = e;
8477bdc2678Schristos 	    return f;
8487bdc2678Schristos #	endif
8497bdc2678Schristos }
8507bdc2678Schristos 
8517bdc2678Schristos /* Renumber a file descriptor so that it's not stdin, stdout, or stderr.  */
8527bdc2678Schristos 	int
fdSafer(fd)8537bdc2678Schristos fdSafer(fd)
8547bdc2678Schristos 	int fd;
8557bdc2678Schristos {
8567bdc2678Schristos 	if (STDIN_FILENO <= fd  &&  fd <= STDERR_FILENO) {
8577bdc2678Schristos 		int f = dupSafer(fd);
8587bdc2678Schristos 		int e = errno;
8597bdc2678Schristos 		VOID close(fd);
8607bdc2678Schristos 		errno = e;
8617bdc2678Schristos 		fd = f;
8627bdc2678Schristos 	}
8637bdc2678Schristos 	return fd;
8647bdc2678Schristos }
8657bdc2678Schristos 
8667bdc2678Schristos /* Like fopen, except the result is never stdin, stdout, or stderr.  */
8677bdc2678Schristos 	FILE *
fopenSafer(filename,type)8687bdc2678Schristos fopenSafer(filename, type)
8697bdc2678Schristos 	char const *filename;
8707bdc2678Schristos 	char const *type;
8717bdc2678Schristos {
8727bdc2678Schristos 	FILE *stream = fopen(filename, type);
8737bdc2678Schristos 	if (stream) {
8747bdc2678Schristos 		int fd = fileno(stream);
8757bdc2678Schristos 		if (STDIN_FILENO <= fd  &&  fd <= STDERR_FILENO) {
8767bdc2678Schristos 			int f = dupSafer(fd);
8777bdc2678Schristos 			if (f < 0) {
8787bdc2678Schristos 				int e = errno;
8797bdc2678Schristos 				VOID fclose(stream);
8807bdc2678Schristos 				errno = e;
8817bdc2678Schristos 				return 0;
8827bdc2678Schristos 			}
8837bdc2678Schristos 			if (fclose(stream) != 0) {
8847bdc2678Schristos 				int e = errno;
8857bdc2678Schristos 				VOID close(f);
8867bdc2678Schristos 				errno = e;
8877bdc2678Schristos 				return 0;
8887bdc2678Schristos 			}
8897bdc2678Schristos 			stream = fdopen(f, type);
8907bdc2678Schristos 		}
8917bdc2678Schristos 	}
8927bdc2678Schristos 	return stream;
8937bdc2678Schristos }
8947bdc2678Schristos 
8957bdc2678Schristos 
8967bdc2678Schristos #ifdef F_DUPFD
8977bdc2678Schristos #	undef dup
8987bdc2678Schristos #	define dup(fd) fcntl(fd, F_DUPFD, 0)
8997bdc2678Schristos #endif
9007bdc2678Schristos 
9017bdc2678Schristos 
9027bdc2678Schristos #if has_fork || has_spawn
9037bdc2678Schristos 
9047bdc2678Schristos 	static int movefd P((int,int));
9057bdc2678Schristos 	static int
movefd(old,new)9067bdc2678Schristos movefd(old, new)
9077bdc2678Schristos 	int old, new;
9087bdc2678Schristos {
9097bdc2678Schristos 	if (old < 0  ||  old == new)
9107bdc2678Schristos 		return old;
9117bdc2678Schristos #	ifdef F_DUPFD
9127bdc2678Schristos 		new = fcntl(old, F_DUPFD, new);
9137bdc2678Schristos #	else
9147bdc2678Schristos 		new = dup2(old, new);
9157bdc2678Schristos #	endif
9167bdc2678Schristos 	return close(old)==0 ? new : -1;
9177bdc2678Schristos }
9187bdc2678Schristos 
9197bdc2678Schristos 	static int fdreopen P((int,char const*,int));
9207bdc2678Schristos 	static int
fdreopen(fd,file,flags)9217bdc2678Schristos fdreopen(fd, file, flags)
9227bdc2678Schristos 	int fd;
9237bdc2678Schristos 	char const *file;
9247bdc2678Schristos 	int flags;
9257bdc2678Schristos {
9267bdc2678Schristos 	int newfd;
9277bdc2678Schristos 	VOID close(fd);
9287bdc2678Schristos 	newfd =
9297bdc2678Schristos #if !open_can_creat
9307bdc2678Schristos 		flags&O_CREAT ? creat(file, S_IRUSR|S_IWUSR) :
9317bdc2678Schristos #endif
9327bdc2678Schristos 		open(file, flags, S_IRUSR|S_IWUSR);
9337bdc2678Schristos 	return movefd(newfd, fd);
9347bdc2678Schristos }
9357bdc2678Schristos 
9367bdc2678Schristos #if has_spawn
9377bdc2678Schristos 	static void redirect P((int,int));
9387bdc2678Schristos 	static void
redirect(old,new)9397bdc2678Schristos redirect(old, new)
9407bdc2678Schristos 	int old, new;
9417bdc2678Schristos /*
9427bdc2678Schristos * Move file descriptor OLD to NEW.
9437bdc2678Schristos * If OLD is -1, do nothing.
9447bdc2678Schristos * If OLD is -2, just close NEW.
9457bdc2678Schristos */
9467bdc2678Schristos {
9477bdc2678Schristos 	if ((old != -1 && close(new) != 0) || (0 <= old && movefd(old,new) < 0))
9487bdc2678Schristos 		efaterror("spawn I/O redirection");
9497bdc2678Schristos }
9507bdc2678Schristos #endif
9517bdc2678Schristos 
9527bdc2678Schristos 
9537bdc2678Schristos #else /* !has_fork && !has_spawn */
9547bdc2678Schristos 
9557bdc2678Schristos 	static void bufargcat P((struct buf*,int,char const*));
9567bdc2678Schristos 	static void
bufargcat(b,c,s)9577bdc2678Schristos bufargcat(b, c, s)
9587bdc2678Schristos 	register struct buf *b;
9597bdc2678Schristos 	int c;
9607bdc2678Schristos 	register char const *s;
9617bdc2678Schristos /* Append to B a copy of C, plus a quoted copy of S.  */
9627bdc2678Schristos {
9637bdc2678Schristos 	register char *p;
9647bdc2678Schristos 	register char const *t;
9657bdc2678Schristos 	size_t bl, sl;
9667bdc2678Schristos 
9677bdc2678Schristos 	for (t=s, sl=0;  *t;  )
9687bdc2678Schristos 		sl  +=  3*(*t++=='\'') + 1;
9697bdc2678Schristos 	bl = strlen(b->string);
9707bdc2678Schristos 	bufrealloc(b, bl + sl + 4);
9717bdc2678Schristos 	p = b->string + bl;
9727bdc2678Schristos 	*p++ = c;
9737bdc2678Schristos 	*p++ = '\'';
9747bdc2678Schristos 	while (*s) {
9757bdc2678Schristos 		if (*s == '\'') {
9767bdc2678Schristos 			*p++ = '\'';
9777bdc2678Schristos 			*p++ = '\\';
9787bdc2678Schristos 			*p++ = '\'';
9797bdc2678Schristos 		}
9807bdc2678Schristos 		*p++ = *s++;
9817bdc2678Schristos 	}
9827bdc2678Schristos 	*p++ = '\'';
9837bdc2678Schristos 	*p = 0;
9847bdc2678Schristos }
9857bdc2678Schristos 
9867bdc2678Schristos #endif
9877bdc2678Schristos 
9887bdc2678Schristos #if !has_spawn && has_fork
9897bdc2678Schristos /*
9907bdc2678Schristos * Output the string S to stderr, without touching any I/O buffers.
9917bdc2678Schristos * This is useful if you are a child process, whose buffers are usually wrong.
9927bdc2678Schristos * Exit immediately if the write does not completely succeed.
9937bdc2678Schristos */
9947bdc2678Schristos static void write_stderr P((char const *));
9957bdc2678Schristos 	static void
write_stderr(s)9967bdc2678Schristos write_stderr(s)
9977bdc2678Schristos 	char const *s;
9987bdc2678Schristos {
9997bdc2678Schristos 	size_t slen = strlen(s);
10007bdc2678Schristos 	if (write(STDERR_FILENO, s, slen) != slen)
10017bdc2678Schristos 		_exit(EXIT_TROUBLE);
10027bdc2678Schristos }
10037bdc2678Schristos #endif
10047bdc2678Schristos 
10057bdc2678Schristos /*
10067bdc2678Schristos * Run a command.
10077bdc2678Schristos * infd, if not -1, is the input file descriptor.
10087bdc2678Schristos * outname, if nonzero, is the name of the output file.
10097bdc2678Schristos * args[1..] form the command to be run; args[0] might be modified.
10107bdc2678Schristos */
10117bdc2678Schristos 	int
runv(infd,outname,args)10127bdc2678Schristos runv(infd, outname, args)
10137bdc2678Schristos 	int infd;
10147bdc2678Schristos 	char const *outname, **args;
10157bdc2678Schristos {
10167bdc2678Schristos 	int wstatus;
10177bdc2678Schristos 
10187bdc2678Schristos #if bad_wait_if_SIGCHLD_ignored
10197bdc2678Schristos 	static int fixed_SIGCHLD;
10207bdc2678Schristos 	if (!fixed_SIGCHLD) {
10217bdc2678Schristos 	    fixed_SIGCHLD = true;
10227bdc2678Schristos #	    ifndef SIGCHLD
10237bdc2678Schristos #	    define SIGCHLD SIGCLD
10247bdc2678Schristos #	    endif
10257bdc2678Schristos 	    VOID signal(SIGCHLD, SIG_DFL);
10267bdc2678Schristos 	}
10277bdc2678Schristos #endif
10287bdc2678Schristos 
10297bdc2678Schristos 	oflush();
10307bdc2678Schristos 	eflush();
10317bdc2678Schristos     {
10327bdc2678Schristos #if has_spawn
10337bdc2678Schristos 	int in, out;
10347bdc2678Schristos 	char const *file;
10357bdc2678Schristos 
10367bdc2678Schristos 	in = -1;
10377bdc2678Schristos 	if (infd != -1  &&  infd != STDIN_FILENO) {
10387bdc2678Schristos 	    if ((in = dup(STDIN_FILENO)) < 0) {
10397bdc2678Schristos 		if (errno != EBADF)
10407bdc2678Schristos 		    efaterror("spawn input setup");
10417bdc2678Schristos 		in = -2;
10427bdc2678Schristos 	    } else {
10437bdc2678Schristos #		ifdef F_DUPFD
10447bdc2678Schristos 		    if (close(STDIN_FILENO) != 0)
10457bdc2678Schristos 			efaterror("spawn input close");
10467bdc2678Schristos #		endif
10477bdc2678Schristos 	    }
10487bdc2678Schristos 	    if (
10497bdc2678Schristos #		ifdef F_DUPFD
10507bdc2678Schristos 		    fcntl(infd, F_DUPFD, STDIN_FILENO) != STDIN_FILENO
10517bdc2678Schristos #		else
10527bdc2678Schristos 		    dup2(infd, STDIN_FILENO) != STDIN_FILENO
10537bdc2678Schristos #		endif
10547bdc2678Schristos 	    )
10557bdc2678Schristos 		efaterror("spawn input redirection");
10567bdc2678Schristos 	}
10577bdc2678Schristos 
10587bdc2678Schristos 	out = -1;
10597bdc2678Schristos 	if (outname) {
10607bdc2678Schristos 	    if ((out = dup(STDOUT_FILENO)) < 0) {
10617bdc2678Schristos 		if (errno != EBADF)
10627bdc2678Schristos 		    efaterror("spawn output setup");
10637bdc2678Schristos 		out = -2;
10647bdc2678Schristos 	    }
10657bdc2678Schristos 	    if (fdreopen(
10667bdc2678Schristos 		STDOUT_FILENO, outname,
10677bdc2678Schristos 		O_CREAT | O_TRUNC | O_WRONLY
10687bdc2678Schristos 	    ) < 0)
10697bdc2678Schristos 		efaterror(outname);
10707bdc2678Schristos 	}
10717bdc2678Schristos 
10727bdc2678Schristos 	wstatus = spawn_RCS(0, args[1], (char**)(args + 1));
10737bdc2678Schristos #	ifdef RCS_SHELL
10747bdc2678Schristos 	    if (wstatus == -1  &&  errno == ENOEXEC) {
10757bdc2678Schristos 		args[0] = RCS_SHELL;
10767bdc2678Schristos 		wstatus = spawnv(0, args[0], (char**)args);
10777bdc2678Schristos 	    }
10787bdc2678Schristos #	endif
10797bdc2678Schristos 	redirect(in, STDIN_FILENO);
10807bdc2678Schristos 	redirect(out, STDOUT_FILENO);
10817bdc2678Schristos #else
10827bdc2678Schristos #if has_fork
10837bdc2678Schristos 	pid_t pid;
10847bdc2678Schristos 	if (!(pid = vfork())) {
10857bdc2678Schristos 		char const *notfound;
10867bdc2678Schristos 		if (infd != -1  &&  infd != STDIN_FILENO  &&  (
10877bdc2678Schristos #		    ifdef F_DUPFD
10887bdc2678Schristos 			(VOID close(STDIN_FILENO),
10897bdc2678Schristos 			fcntl(infd, F_DUPFD, STDIN_FILENO) != STDIN_FILENO)
10907bdc2678Schristos #		    else
10917bdc2678Schristos 			dup2(infd, STDIN_FILENO) != STDIN_FILENO
10927bdc2678Schristos #		    endif
10937bdc2678Schristos 		)) {
10947bdc2678Schristos 		    /* Avoid perror since it may misuse buffers.  */
10957bdc2678Schristos 		    write_stderr(args[1]);
10967bdc2678Schristos 		    write_stderr(": I/O redirection failed\n");
10977bdc2678Schristos 		    _exit(EXIT_TROUBLE);
10987bdc2678Schristos 		}
10997bdc2678Schristos 
11007bdc2678Schristos 		if (outname)
11017bdc2678Schristos 		    if (fdreopen(
11027bdc2678Schristos 			STDOUT_FILENO, outname,
11037bdc2678Schristos 			O_CREAT | O_TRUNC | O_WRONLY
11047bdc2678Schristos 		    ) < 0) {
11057bdc2678Schristos 			/* Avoid perror since it may misuse buffers.  */
11067bdc2678Schristos 			write_stderr(args[1]);
11077bdc2678Schristos 			write_stderr(": ");
11087bdc2678Schristos 			write_stderr(outname);
11097bdc2678Schristos 			write_stderr(": cannot create\n");
11107bdc2678Schristos 			_exit(EXIT_TROUBLE);
11117bdc2678Schristos 		    }
11127bdc2678Schristos 		VOID exec_RCS(args[1], (char**)(args + 1));
11137bdc2678Schristos 		notfound = args[1];
11147bdc2678Schristos #		ifdef RCS_SHELL
11157bdc2678Schristos 		    if (errno == ENOEXEC) {
11167bdc2678Schristos 			args[0] = notfound = RCS_SHELL;
11177bdc2678Schristos 			VOID execv(args[0], (char**)args);
11187bdc2678Schristos 		    }
11197bdc2678Schristos #		endif
11207bdc2678Schristos 
11217bdc2678Schristos 		/* Avoid perror since it may misuse buffers.  */
11227bdc2678Schristos 		write_stderr(notfound);
11237bdc2678Schristos 		write_stderr(": not found\n");
11247bdc2678Schristos 		_exit(EXIT_TROUBLE);
11257bdc2678Schristos 	}
11267bdc2678Schristos 	if (pid < 0)
11277bdc2678Schristos 		efaterror("fork");
11287bdc2678Schristos #	if has_waitpid
11297bdc2678Schristos 		if (waitpid(pid, &wstatus, 0) < 0)
11307bdc2678Schristos 			efaterror("waitpid");
11317bdc2678Schristos #	else
11327bdc2678Schristos 		{
11337bdc2678Schristos 			pid_t w;
11347bdc2678Schristos 			do {
11357bdc2678Schristos 				if ((w = wait(&wstatus)) < 0)
11367bdc2678Schristos 					efaterror("wait");
11377bdc2678Schristos 			} while (w != pid);
11387bdc2678Schristos 		}
11397bdc2678Schristos #	endif
11407bdc2678Schristos #else
11417bdc2678Schristos 	static struct buf b;
11427bdc2678Schristos 	char const *p;
11437bdc2678Schristos 
11447bdc2678Schristos 	/* Use system().  On many hosts system() discards signals.  Yuck!  */
11457bdc2678Schristos 	p = args + 1;
11467bdc2678Schristos 	bufscpy(&b, *p);
11477bdc2678Schristos 	while (*++p)
11487bdc2678Schristos 		bufargcat(&b, ' ', *p);
11497bdc2678Schristos 	if (infd != -1  &&  infd != STDIN_FILENO) {
11507bdc2678Schristos 		char redirection[32];
11517bdc2678Schristos 		VOID sprintf(redirection, "<&%d", infd);
11527bdc2678Schristos 		bufscat(&b, redirection);
11537bdc2678Schristos 	}
11547bdc2678Schristos 	if (outname)
11557bdc2678Schristos 		bufargcat(&b, '>', outname);
11567bdc2678Schristos 	wstatus = system(b.string);
11577bdc2678Schristos #endif
11587bdc2678Schristos #endif
11597bdc2678Schristos     }
11607bdc2678Schristos 	if (!WIFEXITED(wstatus)) {
11617bdc2678Schristos 		if (WIFSIGNALED(wstatus)) {
11627bdc2678Schristos 			psignal(WTERMSIG(wstatus), args[1]);
11637bdc2678Schristos 			fatcleanup(1);
11647bdc2678Schristos 		}
11657bdc2678Schristos 		faterror("%s failed for unknown reason", args[1]);
11667bdc2678Schristos 	}
11677bdc2678Schristos 	return WEXITSTATUS(wstatus);
11687bdc2678Schristos }
11697bdc2678Schristos 
11707bdc2678Schristos #define CARGSMAX 20
11717bdc2678Schristos /*
11727bdc2678Schristos * Run a command.
11737bdc2678Schristos * infd, if not -1, is the input file descriptor.
11747bdc2678Schristos * outname, if nonzero, is the name of the output file.
11757bdc2678Schristos * The remaining arguments specify the command and its arguments.
11767bdc2678Schristos */
11777bdc2678Schristos 	int
11787bdc2678Schristos #if has_prototypes
run(int infd,char const * outname,...)11797bdc2678Schristos run(int infd, char const *outname, ...)
11807bdc2678Schristos #else
11817bdc2678Schristos 	/*VARARGS2*/
11827bdc2678Schristos run(infd, outname, va_alist)
11837bdc2678Schristos 	int infd;
11847bdc2678Schristos 	char const *outname;
11857bdc2678Schristos 	va_dcl
11867bdc2678Schristos #endif
11877bdc2678Schristos {
11887bdc2678Schristos 	va_list ap;
11897bdc2678Schristos 	char const *rgargs[CARGSMAX];
11907bdc2678Schristos 	register int i;
11917bdc2678Schristos 	vararg_start(ap, outname);
11927bdc2678Schristos 	for (i = 1;  (rgargs[i++] = va_arg(ap, char const*));  )
11937bdc2678Schristos 		if (CARGSMAX <= i)
11947bdc2678Schristos 			faterror("too many command arguments");
11957bdc2678Schristos 	va_end(ap);
11967bdc2678Schristos 	return runv(infd, outname, rgargs);
11977bdc2678Schristos }
11987bdc2678Schristos 
11997bdc2678Schristos 
12007bdc2678Schristos int RCSversion;
12017bdc2678Schristos 
12027bdc2678Schristos 	void
setRCSversion(str)12037bdc2678Schristos setRCSversion(str)
12047bdc2678Schristos 	char const *str;
12057bdc2678Schristos {
12067bdc2678Schristos 	static int oldversion;
12077bdc2678Schristos 
12087bdc2678Schristos 	register char const *s = str + 2;
12097bdc2678Schristos 
12107bdc2678Schristos 	if (*s) {
12117bdc2678Schristos 		int v = VERSION_DEFAULT;
12127bdc2678Schristos 
12137bdc2678Schristos 		if (oldversion)
12147bdc2678Schristos 			redefined('V');
12157bdc2678Schristos 		oldversion = true;
12167bdc2678Schristos 		v = 0;
12177bdc2678Schristos 		while (isdigit(*s))
12187bdc2678Schristos 			v  =  10*v + *s++ - '0';
12197bdc2678Schristos 		if (*s)
12207bdc2678Schristos 			error("%s isn't a number", str);
12217bdc2678Schristos 		else if (v < VERSION_min  ||  VERSION_max < v)
12227bdc2678Schristos 			error("%s out of range %d..%d",
12237bdc2678Schristos 				str, VERSION_min, VERSION_max
12247bdc2678Schristos 			);
12257bdc2678Schristos 
12267bdc2678Schristos 		RCSversion = VERSION(v);
12277bdc2678Schristos 	} else {
12287bdc2678Schristos 		printf("RCS version %s\n", RCS_version_string);
12297bdc2678Schristos 		exit(0);
12307bdc2678Schristos 	}
12317bdc2678Schristos }
12327bdc2678Schristos 
12337bdc2678Schristos 	int
getRCSINIT(argc,argv,newargv)12347bdc2678Schristos getRCSINIT(argc, argv, newargv)
12357bdc2678Schristos 	int argc;
12367bdc2678Schristos 	char **argv, ***newargv;
12377bdc2678Schristos {
12387bdc2678Schristos 	register char *p, *q, **pp;
12397bdc2678Schristos 	size_t n;
12407bdc2678Schristos 
12417bdc2678Schristos 	if (!(q = cgetenv("RCSINIT")))
12427bdc2678Schristos 		*newargv = argv;
12437bdc2678Schristos 	else {
12447bdc2678Schristos 		n = argc + 2;
12457bdc2678Schristos 		/*
12467bdc2678Schristos 		 * Count spaces in RCSINIT to allocate a new arg vector.
12477bdc2678Schristos 		 * This is an upper bound, but it's OK even if too large.
12487bdc2678Schristos 		 */
12497bdc2678Schristos 		for (p = q;  ;  ) {
12507bdc2678Schristos 			switch (*p++) {
12517bdc2678Schristos 			    default:
12527bdc2678Schristos 				continue;
12537bdc2678Schristos 
12547bdc2678Schristos 			    case ' ':
12557bdc2678Schristos 			    case '\b': case '\f': case '\n':
12567bdc2678Schristos 			    case '\r': case '\t': case '\v':
12577bdc2678Schristos 				n++;
12587bdc2678Schristos 				continue;
12597bdc2678Schristos 
12607bdc2678Schristos 			    case '\0':
12617bdc2678Schristos 				break;
12627bdc2678Schristos 			}
12637bdc2678Schristos 			break;
12647bdc2678Schristos 		}
12657bdc2678Schristos 		*newargv = pp = tnalloc(char*, n);
12667bdc2678Schristos 		*pp++ = *argv++; /* copy program name */
12677bdc2678Schristos 		for (p = q;  ;  ) {
12687bdc2678Schristos 			for (;;) {
12697bdc2678Schristos 				switch (*q) {
12707bdc2678Schristos 				    case '\0':
12717bdc2678Schristos 					goto copyrest;
12727bdc2678Schristos 
12737bdc2678Schristos 				    case ' ':
12747bdc2678Schristos 				    case '\b': case '\f': case '\n':
12757bdc2678Schristos 				    case '\r': case '\t': case '\v':
12767bdc2678Schristos 					q++;
12777bdc2678Schristos 					continue;
12787bdc2678Schristos 				}
12797bdc2678Schristos 				break;
12807bdc2678Schristos 			}
12817bdc2678Schristos 			*pp++ = p;
12827bdc2678Schristos 			++argc;
12837bdc2678Schristos 			for (;;) {
12847bdc2678Schristos 				switch ((*p++ = *q++)) {
12857bdc2678Schristos 				    case '\0':
12867bdc2678Schristos 					goto copyrest;
12877bdc2678Schristos 
12887bdc2678Schristos 				    case '\\':
12897bdc2678Schristos 					if (!*q)
12907bdc2678Schristos 						goto copyrest;
12917bdc2678Schristos 					p[-1] = *q++;
12927bdc2678Schristos 					continue;
12937bdc2678Schristos 
12947bdc2678Schristos 				    default:
12957bdc2678Schristos 					continue;
12967bdc2678Schristos 
12977bdc2678Schristos 				    case ' ':
12987bdc2678Schristos 				    case '\b': case '\f': case '\n':
12997bdc2678Schristos 				    case '\r': case '\t': case '\v':
13007bdc2678Schristos 					break;
13017bdc2678Schristos 				}
13027bdc2678Schristos 				break;
13037bdc2678Schristos 			}
13047bdc2678Schristos 			p[-1] = '\0';
13057bdc2678Schristos 		}
13067bdc2678Schristos 	    copyrest:
13077bdc2678Schristos 		while ((*pp++ = *argv++))
13087bdc2678Schristos 			continue;
13097bdc2678Schristos 	}
13107bdc2678Schristos 	return argc;
13117bdc2678Schristos }
13127bdc2678Schristos 
13137bdc2678Schristos 
13147bdc2678Schristos #define cacheid(E) static uid_t i; static int s; if (!s){ s=1; i=(E); } return i
13157bdc2678Schristos 
13167bdc2678Schristos #if has_getuid
ruid()13177bdc2678Schristos 	uid_t ruid() { cacheid(getuid()); }
13187bdc2678Schristos #endif
13197bdc2678Schristos #if has_setuid
euid()13207bdc2678Schristos 	uid_t euid() { cacheid(geteuid()); }
13217bdc2678Schristos #endif
13227bdc2678Schristos 
13237bdc2678Schristos 
13247bdc2678Schristos #if has_setuid
13257bdc2678Schristos 
13267bdc2678Schristos /*
13277bdc2678Schristos  * Setuid execution really works only with Posix 1003.1a Draft 5 seteuid(),
13287bdc2678Schristos  * because it lets us switch back and forth between arbitrary users.
13297bdc2678Schristos  * If seteuid() doesn't work, we fall back on setuid(),
13307bdc2678Schristos  * which works if saved setuid is supported,
13317bdc2678Schristos  * unless the real or effective user is root.
13327bdc2678Schristos  * This area is such a mess that we always check switches at runtime.
13337bdc2678Schristos  */
13347bdc2678Schristos 
13357bdc2678Schristos 	static void
13367bdc2678Schristos #if has_prototypes
set_uid_to(uid_t u)13377bdc2678Schristos set_uid_to(uid_t u)
13387bdc2678Schristos #else
13397bdc2678Schristos  set_uid_to(u) uid_t u;
13407bdc2678Schristos #endif
13417bdc2678Schristos /* Become user u.  */
13427bdc2678Schristos {
13437bdc2678Schristos 	static int looping;
13447bdc2678Schristos 
13457bdc2678Schristos 	if (euid() == ruid())
13467bdc2678Schristos 		return;
13477bdc2678Schristos #if (has_fork||has_spawn) && DIFF_ABSOLUTE
13487bdc2678Schristos #	if has_setreuid
13497bdc2678Schristos 		if (setreuid(u==euid() ? ruid() : euid(), u) != 0)
13507bdc2678Schristos 			efaterror("setuid");
13517bdc2678Schristos #	else
13527bdc2678Schristos 		if (seteuid(u) != 0)
13537bdc2678Schristos 			efaterror("setuid");
13547bdc2678Schristos #	endif
13557bdc2678Schristos #endif
13567bdc2678Schristos 	if (geteuid() != u) {
13577bdc2678Schristos 		if (looping)
13587bdc2678Schristos 			return;
13597bdc2678Schristos 		looping = true;
13607bdc2678Schristos 		faterror("root setuid not supported" + (u?5:0));
13617bdc2678Schristos 	}
13627bdc2678Schristos }
13637bdc2678Schristos 
13647bdc2678Schristos static int stick_with_euid;
13657bdc2678Schristos 
13667bdc2678Schristos 	void
13677bdc2678Schristos /* Ignore all calls to seteid() and setrid().  */
nosetid()13687bdc2678Schristos nosetid()
13697bdc2678Schristos {
13707bdc2678Schristos 	stick_with_euid = true;
13717bdc2678Schristos }
13727bdc2678Schristos 
13737bdc2678Schristos 	void
seteid()13747bdc2678Schristos seteid()
13757bdc2678Schristos /* Become effective user.  */
13767bdc2678Schristos {
13777bdc2678Schristos 	if (!stick_with_euid)
13787bdc2678Schristos 		set_uid_to(euid());
13797bdc2678Schristos }
13807bdc2678Schristos 
13817bdc2678Schristos 	void
setrid()13827bdc2678Schristos setrid()
13837bdc2678Schristos /* Become real user.  */
13847bdc2678Schristos {
13857bdc2678Schristos 	if (!stick_with_euid)
13867bdc2678Schristos 		set_uid_to(ruid());
13877bdc2678Schristos }
13887bdc2678Schristos #endif
13897bdc2678Schristos 
13907bdc2678Schristos 	time_t
now()13917bdc2678Schristos now()
13927bdc2678Schristos {
13937bdc2678Schristos 	static time_t t;
13947bdc2678Schristos 	if (!t  &&  time(&t) == -1)
13957bdc2678Schristos 		efaterror("time");
13967bdc2678Schristos 	return t;
13977bdc2678Schristos }
1398