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