tc.os.c revision 69408
1/* $Header: /src/pub/tcsh/tc.os.c,v 3.52 2000/11/11 23:03:39 christos Exp $ */
2/*
3 * tc.os.c: OS Dependent builtin functions
4 */
5/*-
6 * Copyright (c) 1980, 1991 The Regents of the University of California.
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 *    must display the following acknowledgement:
19 *	This product includes software developed by the University of
20 *	California, Berkeley and its contributors.
21 * 4. Neither the name of the University nor the names of its contributors
22 *    may be used to endorse or promote products derived from this software
23 *    without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * SUCH DAMAGE.
36 */
37#include "sh.h"
38
39RCSID("$Id: tc.os.c,v 3.52 2000/11/11 23:03:39 christos Exp $")
40
41#include "tw.h"
42#include "ed.h"
43#include "ed.defns.h"		/* for the function names */
44#include "sh.decls.h"
45
46#ifdef _UWIN
47#define TIOCGPGRP TIOCGETPGRP
48#define TIOCSPGRP TIOCSETPGRP
49#endif
50
51/***
52 *** MACH
53 ***/
54
55#ifdef MACH
56/* dosetpath -- setpath built-in command
57 *
58 **********************************************************************
59 * HISTORY
60 * 08-May-88  Richard Draves (rpd) at Carnegie-Mellon University
61 *	Major changes to remove artificial limits on sizes and numbers
62 *	of paths.
63 *
64 **********************************************************************
65 */
66
67#ifdef MACH
68static Char STRCPATH[] = {'C', 'P', 'A', 'T', 'H', '\0'};
69static Char STRLPATH[] = {'L', 'P', 'A', 'T', 'H', '\0'};
70static Char STRMPATH[] = {'M', 'P', 'A', 'T', 'H', '\0'};
71# if EPATH
72static Char STREPATH[] = {'E', 'P', 'A', 'T', 'H', '\0'};
73# endif
74#endif /* MACH */
75static Char *syspaths[] = {STRKPATH, STRCPATH, STRLPATH, STRMPATH,
76
77#if EPATH
78	STREPATH,
79#endif
80	 0};
81#define LOCALSYSPATH	"/usr/local"
82
83/*ARGSUSED*/
84void
85dosetpath(arglist, c)
86    Char  **arglist;
87    struct command *c;
88{
89    extern char *getenv();
90    sigmask_t omask;
91    Char  **pathvars, **cmdargs;
92    char  **spaths, **cpaths, **cmds;
93    char   *tcp;
94    unsigned int npaths, ncmds;
95    int     i, sysflag;
96
97    omask = sigsetmask(sigmask(SIGINT));
98
99    /*
100     * setpath(3) uses stdio and we want 0, 1, 2 to work...
101     */
102    if (!didfds) {
103	(void) dcopy(SHIN, 0);
104	(void) dcopy(SHOUT, 1);
105	(void) dcopy(SHDIAG, 2);
106	didfds = 1;
107    }
108
109    for (i = 1; arglist[i] && (arglist[i][0] != '-'); i++);
110    npaths = i - 1;
111
112    cmdargs = &arglist[i];
113    for (; arglist[i]; i++);
114    ncmds = i - npaths - 1;
115
116    if (npaths) {
117	sysflag = 0;
118	pathvars = &arglist[1];
119    }
120    else {
121	sysflag = 1;
122	npaths = (sizeof syspaths / sizeof *syspaths) - 1;
123	pathvars = syspaths;
124    }
125
126    /* note that npaths != 0 */
127
128    spaths = (char **) xmalloc((size_t) npaths * sizeof *spaths);
129    setzero((char *) spaths, npaths * sizeof *spaths);
130    cpaths = (char **) xmalloc((size_t) (npaths + 1) * sizeof *cpaths);
131    setzero((char *) cpaths, (npaths + 1) * sizeof *cpaths);
132    cmds = (char **) xmalloc((size_t) (ncmds + 1) * sizeof *cmds);
133    setzero((char *) cmds, (ncmds + 1) * sizeof *cmds);
134    for (i = 0; i < npaths; i++) {
135	char   *val = getenv(short2str(pathvars[i]));
136
137	if (val == NULL)
138	    val = "";
139
140	spaths[i] = (char *) xmalloc((size_t) (Strlen(pathvars[i]) +
141				      strlen(val) + 2) * sizeof **spaths);
142	(void) strcpy(spaths[i], short2str(pathvars[i]));
143	(void) strcat(spaths[i], "=");
144	(void) strcat(spaths[i], val);
145	cpaths[i] = spaths[i];
146    }
147
148    for (i = 0; i < ncmds; i++) {
149	Char   *val = globone(cmdargs[i], G_ERROR);
150
151	if (val == NULL)
152	    goto abortpath;
153	cmds[i] = (char *) xmalloc((size_t) Strlen(val) + 1);
154	(void) strcpy(cmds[i], short2str(val));
155    }
156
157
158    if (setpath(cpaths, cmds, LOCALSYSPATH, sysflag, 1) < 0) {
159abortpath:
160	if (spaths) {
161	    for (i = 0; i < npaths; i++)
162		if (spaths[i])
163		    xfree((ptr_t) spaths[i]);
164	    xfree((ptr_t) spaths);
165	}
166	if (cpaths)
167	    xfree((ptr_t) cpaths);
168	if (cmds) {
169	    for (i = 0; i < ncmds; i++)
170		if (cmds[i])
171		    xfree((ptr_t) cmds[i]);
172	    xfree((ptr_t) cmds);
173	}
174
175	(void) sigsetmask(omask);
176	donefds();
177	return;
178    }
179
180    for (i = 0; i < npaths; i++) {
181	Char	*val, *name;
182
183	name = str2short(cpaths[i]);
184	for (val = str2short(cpaths[i]); val && *val && *val != '='; val++);
185	if (val && *val == '=') {
186	    *val++ = '\0';
187
188	    tsetenv(name, val);
189	    if (Strcmp(name, STRKPATH) == 0) {
190		importpath(val);
191		if (havhash)
192		    dohash(NULL, NULL);
193	    }
194	    *--val = '=';
195	}
196    }
197    (void) sigsetmask(omask);
198    donefds();
199}
200#endif /* MACH */
201
202/***
203 *** AIX
204 ***/
205#ifdef TCF
206/* ARGSUSED */
207void
208dogetxvers(v, c)
209    Char  **v;
210    struct command *c;
211{
212    char    xvers[MAXPATHLEN];
213
214    if (getxvers(xvers, MAXPATHLEN) == -1)
215	stderror(ERR_SYSTEM, "getxvers", strerror(errno));
216    xprintf("%s\n", xvers);
217    flush();
218}
219
220/*ARGSUSED*/
221void
222dosetxvers(v, c)
223    Char  **v;
224    struct command *c;
225{
226    char   *xvers;
227
228    ++v;
229    if (!*v || *v[0] == '\0')
230	xvers = "";
231    else
232	xvers = short2str(*v);
233    if (setxvers(xvers) == -1)
234	stderror(ERR_SYSTEM, "setxvers", strerror(errno));
235}
236
237#include <sf.h>
238#ifdef _AIXPS2
239# define XC_PDP11	0x01
240# define XC_23		0x02
241# define XC_Z8K		0x03
242# define XC_8086	0x04
243# define XC_68K		0x05
244# define XC_Z80		0x06
245# define XC_VAX		0x07
246# define XC_16032	0x08
247# define XC_286		0x09
248# define XC_386		0x0a
249# define XC_S370	0x0b
250#else
251# include <sys/x.out.h>
252#endif /* _AIXPS2 */
253
254static struct xc_cpu_t {
255    short   xc_id;
256    char   *xc_name;
257}       xcpu[] =
258{
259    { XC_PDP11,	"pdp11"   },
260    { XC_23,	"i370"    },
261    { XC_Z8K,	"z8000"   },
262    { XC_8086,	"i86"	  },
263    { XC_68K,	"mc68000" },
264    { XC_Z80,	"x80"	  },
265    { XC_VAX,	"vax"	  },
266    { XC_16032,	"ns16032" },
267    { XC_286,	"i286"	  },
268    { XC_386,	"i386"	  },
269    { XC_S370,	"xa370"	  },
270    { 0,	NULL      }
271};
272
273/*
274 * our local hack table, stolen from x.out.h
275 */
276static char *
277getxcode(xcid)
278    short   xcid;
279{
280    int     i;
281
282    for (i = 0; xcpu[i].xc_name != NULL; i++)
283	if (xcpu[i].xc_id == xcid)
284	    return (xcpu[i].xc_name);
285    return (NULL);
286}
287
288static short
289getxid(xcname)
290    char   *xcname;
291{
292    int     i;
293
294    for (i = 0; xcpu[i].xc_name != NULL; i++)
295	if (strcmp(xcpu[i].xc_name, xcname) == 0)
296	    return (xcpu[i].xc_id);
297    return ((short) -1);
298}
299
300
301/*ARGSUSED*/
302void
303dogetspath(v, c)
304    Char  **v;
305    struct command *c;
306{
307    int     i, j;
308    sitepath_t p[MAXSITE];
309    struct sf *st;
310    static char *local = "LOCAL ";
311
312    if ((j = getspath(p, MAXSITE)) == -1)
313	stderror(ERR_SYSTEM, "getspath", strerror(errno));
314    for (i = 0; i < j && (p[i] & SPATH_CPU) != NOSITE; i++) {
315	if (p[i] & SPATH_CPU) {
316	    if ((p[i] & SPATH_MASK) == NULLSITE)
317		xprintf(local);
318	    else if ((st = sfxcode((short) (p[i] & SPATH_MASK))) != NULL)
319		xprintf("%s ", st->sf_ctype);
320	    else {
321		char   *xc = getxcode(p[i] & SPATH_MASK);
322
323		if (xc != NULL)
324		    xprintf("%s ", xc);
325		else
326		    xprintf("*cpu %d* ", (int) (p[i] & SPATH_MASK));
327		/*
328		 * BUG in the aix code... needs that cause if
329		 * sfxcode fails once it fails for ever
330		 */
331		endsf();
332	    }
333	}
334	else {
335	    if (p[i] == NULLSITE)
336		xprintf(local);
337	    else if ((st = sfnum(p[i])) != NULL)
338		xprintf("%s ", st->sf_sname);
339	    else
340		xprintf("*site %d* ", (int) (p[i] & SPATH_MASK));
341	}
342    }
343    xputchar('\n');
344    flush();
345}
346
347/*ARGSUSED*/
348void
349dosetspath(v, c)
350    Char  **v;
351    struct command *c;
352{
353    int     i;
354    short   j;
355    char   *s;
356    sitepath_t p[MAXSITE];
357    struct sf *st;
358
359    /*
360     * sfname() on AIX G9.9 at least, mallocs too pointers p, q
361     * then does the equivalent of while (*p++ == *q++) continue;
362     * and then tries to free(p,q) them! Congrats to the wizard who
363     * wrote that one. I bet he tested it really well too.
364     * Sooo, we set dont_free :-)
365     */
366    dont_free = 1;
367    for (i = 0, v++; *v && *v[0] != '\0'; v++, i++) {
368	s = short2str(*v);
369	if (Isdigit(*s))
370	    p[i] = atoi(s);
371	else if (strcmp(s, "LOCAL") == 0)
372	    p[i] = NULLSITE;
373	else if ((st = sfctype(s)) != NULL)
374	    p[i] = SPATH_CPU | st->sf_ccode;
375	else if ((j = getxid(s)) != -1)
376	    p[i] = SPATH_CPU | j;
377	else if ((st = sfname(s)) != NULL)
378	    p[i] = st->sf_id;
379	else {
380	    setname(s);
381	    stderror(ERR_NAME | ERR_STRING, CGETS(23, 1, "Bad cpu/site name"));
382	}
383	if (i == MAXSITE - 1)
384	    stderror(ERR_NAME | ERR_STRING, CGETS(23, 2, "Site path too long"));
385    }
386    if (setspath(p, i) == -1)
387	stderror(ERR_SYSTEM, "setspath", strerror(errno));
388    dont_free = 0;
389}
390
391/* sitename():
392 *	Return the site name where the process is running
393 */
394char   *
395sitename(pid)
396    pid_t   pid;
397{
398    siteno_t ss;
399    struct sf *st;
400
401    if ((ss = site(pid)) == -1 || (st = sfnum(ss)) == NULL)
402	return CGETS(23, 3, "unknown");
403    else
404	return st->sf_sname;
405}
406
407static int
408migratepid(pid, new_site)
409    pid_t   pid;
410    siteno_t new_site;
411{
412    struct sf *st;
413    int     need_local;
414
415    need_local = (pid == 0) || (pid == getpid());
416
417    if (kill3((pid_t) pid, SIGMIGRATE, new_site) < 0) {
418	xprintf("%d: %s\n", pid, strerror(errno));
419	return (-1);
420    }
421
422    if (need_local) {
423	if ((new_site = site(0)) == -1) {
424	    xprintf(CGETS(23, 4, "site: %s\n"), strerror(errno));
425	    return (-1);
426	}
427	if ((st = sfnum(new_site)) == NULL) {
428	    xprintf(CGETS(23, 5, "%d: Site not found\n"), new_site);
429	    return (-1);
430	}
431	if (setlocal(st->sf_local, strlen(st->sf_local)) == -1) {
432	    xprintf(CGETS(23, 6, "setlocal: %s: %s\n"),
433			  st->sf_local, strerror(errno));
434	    return (-1);
435	}
436    }
437    return (0);
438}
439
440/*ARGSUSED*/
441void
442domigrate(v, c)
443    Char  **v;
444    struct command *c;
445{
446    struct sf *st;
447    char   *s;
448    Char   *cp;
449    struct process *pp;
450    int    err1 = 0;
451    int    pid = 0;
452    siteno_t new_site = 0;
453    sigmask_t omask;
454
455#ifdef BSDSIGS
456    omask = sigmask(SIGCHLD);
457    if (setintr)
458	omask |= sigmask(SIGINT);
459    omask = sigblock(omask) & ~omask;
460#else
461    if (setintr)
462	(void) sighold(SIGINT);
463    (void) sighold(SIGCHLD);
464#endif /* BSDSIGS */
465
466    ++v;
467    if (*v[0] == '-') {
468	/*
469	 * Do the -site.
470	 */
471	s = short2str(&v[0][1]);
472	/*
473	 * see comment in setspath()
474	 */
475	dont_free = 1;
476	if ((st = sfname(s)) == NULL) {
477	    setname(s);
478	    stderror(ERR_NAME | ERR_STRING, CGETS(23, 7, "Site not found"));
479	}
480	dont_free = 0;
481	new_site = st->sf_id;
482	++v;
483    }
484
485    if (!*v || *v[0] == '\0') {
486	if (migratepid(0, new_site) == -1)
487	    err1++;
488    }
489    else {
490	gflag = 0, tglob(v);
491	if (gflag) {
492	    v = globall(v);
493	    if (v == 0)
494		stderror(ERR_NAME | ERR_NOMATCH);
495	}
496	else {
497	    v = gargv = saveblk(v);
498	    trim(v);
499	}
500
501	while (v && (cp = *v)) {
502	    if (*cp == '%') {
503		pp = pfind(cp);
504		if (kill3((pid_t) - pp->p_jobid, SIGMIGRATE, new_site) < 0) {
505		    xprintf("%S: %s\n", cp, strerror(errno));
506		    err1++;
507		}
508	    }
509	    else if (!(Isdigit(*cp) || *cp == '-'))
510		stderror(ERR_NAME | ERR_JOBARGS);
511	    else {
512		pid = atoi(short2str(cp));
513		if (migratepid(pid, new_site) == -1)
514		    err1++;
515	    }
516	    v++;
517	}
518	if (gargv)
519	    blkfree(gargv), gargv = 0;
520    }
521
522done:
523#ifdef BSDSIGS
524    (void) sigsetmask(omask);
525#else
526    (void) sigrelse(SIGCHLD);
527    if (setintr)
528	(void) sigrelse(SIGINT);
529#endif /* BSDSIGS */
530    if (err1)
531	stderror(ERR_SILENT);
532}
533
534#endif /* TCF */
535
536/***
537 *** CRAY ddmode <velo@sesun3.epfl.ch> (Martin Ouwehand EPFL-SIC/SE)
538 ***/
539#if defined(_CRAY) && !defined(_CRAYMPP)
540void
541dodmmode(v, c)
542    Char  **v;
543    struct command *c;
544{
545    Char *cp = v[1];
546
547    USE(c);
548
549    if ( !cp ) {
550	int mode;
551
552	mode = dmmode(0);
553	dmmode(mode);
554	xprintf("%d\n",mode);
555    }
556    else {
557	if (cp[1] != '\0')
558	    stderror(ERR_NAME | ERR_STRING,
559		     CGETS(23, 30, "Too many arguments"));
560	else
561	    switch(*cp) {
562	    case '0':
563		dmmode(0);
564		break;
565	    case '1':
566		dmmode(1);
567		break;
568	    default:
569		stderror(ERR_NAME | ERR_STRING,
570			 CGETS(23, 31, "Invalid argument"));
571	    }
572    }
573}
574#endif /* _CRAY && !_CRAYMPP */
575
576
577/***
578 *** CONVEX Warps.
579 ***/
580
581#ifdef WARP
582/*
583 * handle the funky warping of symlinks
584 */
585#include <warpdb.h>
586#include <sys/warp.h>
587
588static jmp_buf sigsys_buf;
589
590static  sigret_t
591catch_sigsys()
592{
593    longjmp(sigsys_buf, 1);
594}
595
596
597/*ARGSUSED*/
598void
599dowarp(v, c)
600    Char  **v;
601    struct command *c;
602{
603    int     warp, oldwarp;
604    struct warpent *we;
605    void    (*old_sigsys_handler) () = 0;
606    char   *newwarp;
607
608    if (setjmp(sigsys_buf)) {
609	signal(SIGSYS, old_sigsys_handler);
610	stderror(ERR_NAME | ERR_STRING,
611		 CGETS(23, 8, "You're trapped in a universe you never made"));
612	return;
613    }
614    old_sigsys_handler = signal(SIGSYS, catch_sigsys);
615
616    warp = getwarp();
617
618    v++;
619    if (*v == 0) {		/* display warp value */
620	if (warp < 0)
621	    stderror(ERR_NAME | ERR_STRING, CGETS(23, 9, "Getwarp failed"));
622	we = getwarpbyvalue(warp);
623	if (we)
624	    printf("%s\n", we->w_name);
625	else
626	    printf("%d\n", warp);
627    }
628    else {			/* set warp value */
629	oldwarp = warp;
630	newwarp = short2str(*v);
631	if (Isdigit(*v[0]))
632	    warp = atoi(newwarp);
633	else {
634	    we = getwarpbyname(newwarp);
635	    if (we)
636		warp = we->w_value;
637	    else
638		warp = -1;
639	}
640	if ((warp < 0) || (warp >= WARP_MAXLINK))
641	    stderror(ERR_NAME | ERR_STRING, CGETS(23, 10, "Invalid warp"));
642	if ((setwarp(warp) < 0) || (getwarp() != warp)) {
643	    (void) setwarp(oldwarp);
644	    stderror(ERR_NAME | ERR_STRING, CGETS(23, 11, "Setwarp failed"));
645	}
646    }
647    signal(SIGSYS, old_sigsys_handler);
648    return;
649}
650#endif /* WARP */
651
652/***
653 *** Masscomp or HCX
654 ***/
655/* Added, DAS DEC-90. */
656#if defined(masscomp) || defined(_CX_UX)
657/*ARGSUSED*/
658void
659douniverse(v, c)
660    register Char **v;
661    struct command *c;
662{
663    register Char *cp = v[1];
664    register Char *cp2;		/* dunno how many elements v comes in with */
665    char    ubuf[100];
666#ifdef BSDSIGS
667    register sigmask_t omask = 0;
668#endif /* BSDSIGS */
669
670    if (cp == 0) {
671	(void) getuniverse(ubuf);
672	xprintf("%s\n", ubuf);
673    }
674    else {
675	cp2 = v[2];
676	if (cp2 == 0) {
677	    if (*cp == '\0' || setuniverse(short2str(cp)) != 0)
678		stderror(ERR_NAME | ERR_STRING, CGETS(23, 12, "Illegal universe"));
679	    }
680	else {
681	    (void) getuniverse(ubuf);
682	    if (*cp == '\0' || setuniverse(short2str(cp)) != 0)
683	stderror(ERR_NAME | ERR_STRING, CGETS(23, 12, "Illegal universe"));
684	    if (setintr)
685#ifdef BSDSIGS
686		omask = sigblock(sigmask(SIGINT)) & ~sigmask(SIGINT);
687#else /* !BSDSIGS */
688		(void) sighold(SIGINT);
689#endif /* BSDSIGS */
690	    lshift(v, 2);
691	    if (setintr)
692#ifdef BSDSIGS
693		(void) sigsetmask(omask);
694#else /* !BSDSIGS */
695		(void) sigrelse (SIGINT);
696#endif /* BSDSIGS */
697	    reexecute(c);
698	    (void) setuniverse(ubuf);
699	}
700    }
701}
702#endif /* masscomp || _CX_UX */
703
704#if defined(_CX_UX)
705/*ARGSUSED*/
706void
707doatt(v, c)
708    register Char **v;
709    struct command *c;
710{
711    register Char *cp = v[1];
712    char    ubuf[100];
713#ifdef BSDSIGS
714    register sigmask_t omask = 0;
715#endif /* BSDSIGS */
716
717    if (cp == 0)
718	(void) setuniverse("att");
719    else {
720	(void) getuniverse(ubuf);
721	(void) setuniverse("att");
722	if (setintr)
723#ifdef BSDSIGS
724	    omask = sigblock(sigmask(SIGINT)) & ~sigmask(SIGINT);
725#else /* !BSDSIGS */
726	    (void) sighold(SIGINT);
727#endif /* BSDSIGS */
728	lshift(v, 1);
729	if (setintr)
730#ifdef BSDSIGS
731	    (void) sigsetmask(omask);
732#else /* !BSDSIGS */
733	    (void) sigrelse (SIGINT);
734#endif /* BSDSIGS */
735	reexecute(c);
736	(void) setuniverse(ubuf);
737    }
738}
739
740/*ARGSUSED*/
741void
742doucb(v, c)
743    register Char **v;
744    struct command *c;
745{
746    register Char *cp = v[1];
747    char    ubuf[100];
748#ifdef BSDSIGS
749    register sigmask_t omask = 0;
750#endif /* BSDSIGS */
751
752    if (cp == 0)
753	(void) setuniverse("ucb");
754    else {
755	(void) getuniverse(ubuf);
756	(void) setuniverse("ucb");
757	if (setintr)
758#ifdef BSDSIGS
759	    omask = sigblock(sigmask(SIGINT)) & ~sigmask(SIGINT);
760#else /* !BSDSIGS */
761	    (void) sighold(SIGINT);
762#endif /* BSDSIGS */
763	lshift(v, 1);
764	if (setintr)
765#ifdef BSDSIGS
766	    (void) sigsetmask(omask);
767#else /* !BSDSIGS */
768	    (void) sigrelse (SIGINT);
769#endif /* BSDSIGS */
770	reexecute(c);
771	(void) setuniverse(ubuf);
772    }
773}
774#endif /* _CX_UX */
775
776#ifdef _SEQUENT_
777/*
778 * Compute the difference in process stats.
779 */
780void
781pr_stat_sub(p2, p1, pr)
782    struct process_stats *p2, *p1, *pr;
783{
784    pr->ps_utime.tv_sec = p2->ps_utime.tv_sec - p1->ps_utime.tv_sec;
785    pr->ps_utime.tv_usec = p2->ps_utime.tv_usec - p1->ps_utime.tv_usec;
786    if (pr->ps_utime.tv_usec < 0) {
787	pr->ps_utime.tv_sec -= 1;
788	pr->ps_utime.tv_usec += 1000000;
789    }
790    pr->ps_stime.tv_sec = p2->ps_stime.tv_sec - p1->ps_stime.tv_sec;
791    pr->ps_stime.tv_usec = p2->ps_stime.tv_usec - p1->ps_stime.tv_usec;
792    if (pr->ps_stime.tv_usec < 0) {
793	pr->ps_stime.tv_sec -= 1;
794	pr->ps_stime.tv_usec += 1000000;
795    }
796
797    pr->ps_maxrss = p2->ps_maxrss - p1->ps_maxrss;
798    pr->ps_pagein = p2->ps_pagein - p1->ps_pagein;
799    pr->ps_reclaim = p2->ps_reclaim - p1->ps_reclaim;
800    pr->ps_zerofill = p2->ps_zerofill - p1->ps_zerofill;
801    pr->ps_pffincr = p2->ps_pffincr - p1->ps_pffincr;
802    pr->ps_pffdecr = p2->ps_pffdecr - p1->ps_pffdecr;
803    pr->ps_swap = p2->ps_swap - p1->ps_swap;
804    pr->ps_syscall = p2->ps_syscall - p1->ps_syscall;
805    pr->ps_volcsw = p2->ps_volcsw - p1->ps_volcsw;
806    pr->ps_involcsw = p2->ps_involcsw - p1->ps_involcsw;
807    pr->ps_signal = p2->ps_signal - p1->ps_signal;
808    pr->ps_lread = p2->ps_lread - p1->ps_lread;
809    pr->ps_lwrite = p2->ps_lwrite - p1->ps_lwrite;
810    pr->ps_bread = p2->ps_bread - p1->ps_bread;
811    pr->ps_bwrite = p2->ps_bwrite - p1->ps_bwrite;
812    pr->ps_phread = p2->ps_phread - p1->ps_phread;
813    pr->ps_phwrite = p2->ps_phwrite - p1->ps_phwrite;
814}
815
816#endif /* _SEQUENT_ */
817
818
819#ifdef NEEDmemset
820/* This is a replacement for a missing memset function */
821ptr_t xmemset(loc, value, len)
822    ptr_t loc;
823    int len;
824    size_t value;
825{
826    char *ptr = (char *) loc;
827
828    while (len--)
829	*ptr++ = value;
830    return loc;
831}
832#endif /* NEEDmemset */
833
834
835#ifdef NEEDmemmove
836/* memmove():
837 * 	This is the ANSI form of bcopy() with the arguments backwards...
838 *	Unlike memcpy(), it handles overlaps between source and
839 *	destination memory
840 */
841ptr_t
842xmemmove(vdst, vsrc, len)
843    ptr_t vdst;
844    const ptr_t vsrc;
845    size_t len;
846{
847    const char *src = (const char *) vsrc;
848    char *dst = (char *) vdst;
849
850    if (src == dst)
851	return vdst;
852
853    if (src > dst) {
854	while (len--)
855	    *dst++ = *src++;
856    }
857    else {
858	src += len;
859	dst += len;
860	while (len--)
861	    *--dst = *--src;
862    }
863    return vdst;
864}
865#endif /* NEEDmemmove */
866
867
868#ifndef WINNT_NATIVE
869#ifdef tcgetpgrp
870int
871xtcgetpgrp(fd)
872    int     fd;
873{
874    int     pgrp;
875
876    /* ioctl will handle setting errno correctly. */
877    if (ioctl(fd, TIOCGPGRP, (ioctl_t) & pgrp) < 0)
878	return (-1);
879    return (pgrp);
880}
881
882/*
883 * XXX: tcsetpgrp is not a macro any more cause on some systems,
884 * pid_t is a short, but the ioctl() takes a pointer to int (pyr)
885 * Thanks to Simon Day (simon@pharaoh.cyborg.bt.co.uk) for pointing
886 * this out.
887 */
888int
889xtcsetpgrp(fd, pgrp)
890    int fd, pgrp;
891{
892    return ioctl(fd, TIOCSPGRP, (ioctl_t) &pgrp);
893}
894
895#endif	/* tcgetpgrp */
896#endif /* WINNT_NATIVE */
897
898
899#ifdef YPBUGS
900void
901fix_yp_bugs()
902{
903    char   *mydomain;
904
905    extern int yp_get_default_domain __P((char **));
906    /*
907     * PWP: The previous version assumed that yp domain was the same as the
908     * internet name domain.  This isn't allways true. (Thanks to Mat Landau
909     * <mlandau@bbn.com> for the original version of this.)
910     */
911    if (yp_get_default_domain(&mydomain) == 0) {	/* if we got a name */
912	extern void yp_unbind __P((const char *));
913
914	yp_unbind(mydomain);
915    }
916}
917
918#endif /* YPBUGS */
919
920#ifdef STRCOLLBUG
921void
922fix_strcoll_bug()
923{
924#if defined(NLS) && !defined(NOSTRCOLL)
925    /*
926     * SunOS4 checks the file descriptor from openlocale() for <= 0
927     * instead of == -1. Someone should tell sun that file descriptor 0
928     * is valid! Our portable hack: open one so we call it with 0 used...
929     * We have to call this routine every time the locale changes...
930     *
931     * Of course it also tries to free the constant locale "C" it initially
932     * had allocated, with the sequence
933     * > setenv LANG "fr"
934     * > ls^D
935     * > unsetenv LANG
936     * But we are smarter than that and just print a warning message.
937     */
938    int fd = -1;
939    static char *root = "/";
940
941    if (!didfds)
942	fd = open(root, O_RDONLY);
943
944    (void) strcoll(root, root);
945
946    if (fd != -1)
947	(void) close(fd);
948#endif
949}
950#endif /* STRCOLLBUG */
951
952
953#ifdef OREO
954#include <compat.h>
955#endif /* OREO */
956
957void
958osinit()
959{
960#ifdef OREO
961    set42sig();
962    setcompat(getcompat() & ~COMPAT_EXEC);
963    sigignore(SIGIO);		/* ignore SIGIO */
964#endif /* OREO */
965
966#ifdef aiws
967    {
968	struct sigstack inst;
969	inst.ss_sp = (char *) xmalloc((size_t) 4192) + 4192;
970	inst.ss_onstack = 0;
971	sigstack(&inst, NULL);
972    }
973#endif /* aiws */
974
975#ifdef apollo
976    (void) isapad();
977#endif
978
979#ifdef _SX
980    /*
981     * kill(SIGCONT) problems, don't know what this syscall does
982     * [schott@rzg.mpg.de]
983     */
984    syscall(151, getpid(), getpid());
985#endif /* _SX */
986}
987
988#ifdef strerror
989char *
990xstrerror(i)
991    int i;
992{
993    static char errbuf[128];
994
995    if (i >= 0 && i < sys_nerr) {
996	return sys_errlist[i];
997    } else {
998	(void) xsnprintf(errbuf, sizeof(errbuf),
999	    CGETS(23, 13, "Unknown Error: %d"), i);
1000	return errbuf;
1001    }
1002}
1003#endif /* strerror */
1004
1005#ifdef gethostname
1006# if !defined(_MINIX) && !defined(__EMX__) && !defined(WINNT_NATIVE)
1007#  include <sys/utsname.h>
1008# endif /* !_MINIX && !__EMX__ && !WINNT_NATIVE */
1009
1010int
1011xgethostname(name, namlen)
1012    char   *name;
1013    int     namlen;
1014{
1015# if !defined(_MINIX) && !defined(__EMX__) && !defined(WINNT_NATIVE)
1016    int     i, retval;
1017    struct utsname uts;
1018
1019    retval = uname(&uts);
1020
1021#  ifdef DEBUG
1022    xprintf(CGETS(23, 14, "sysname:  %s\n"), uts.sysname);
1023    xprintf(CGETS(23, 15, "nodename: %s\n"), uts.nodename);
1024    xprintf(CGETS(23, 16, "release:  %s\n"), uts.release);
1025    xprintf(CGETS(23, 17, "version:  %s\n"), uts.version);
1026    xprintf(CGETS(23, 18, "machine:  %s\n"), uts.machine);
1027#  endif /* DEBUG */
1028    i = strlen(uts.nodename) + 1;
1029    (void) strncpy(name, uts.nodename, i < namlen ? i : namlen);
1030
1031    return retval;
1032# else /* !_MINIX && !__EMX__ */
1033    if (namlen > 0) {
1034#  ifdef __EMX__
1035	(void) strncpy(name, "OS/2", namlen);
1036#  else /* _MINIX */
1037	(void) strncpy(name, "minix", namlen);
1038#  endif /* __EMX__ */
1039	name[namlen-1] = '\0';
1040    }
1041    return(0);
1042#endif /* _MINIX && !__EMX__ */
1043} /* end xgethostname */
1044#endif /* gethostname */
1045
1046#ifdef nice
1047# if defined(_MINIX) && defined(NICE)
1048#  undef _POSIX_SOURCE	/* redefined in <lib.h> */
1049#  undef _MINIX		/* redefined in <lib.h> */
1050#  undef HZ		/* redefined in <minix/const.h> */
1051#  include <lib.h>
1052# endif /* _MINIX && NICE */
1053int
1054xnice(incr)
1055    int incr;
1056{
1057#if defined(_MINIX) && defined(NICE)
1058    return callm1(MM, NICE, incr, 0, 0, NIL_PTR, NIL_PTR, NIL_PTR);
1059#else
1060    return /* incr ? 0 : */ 0;
1061#endif /* _MINIX && NICE */
1062} /* end xnice */
1063#endif /* nice */
1064
1065#ifdef NEEDgetcwd
1066static char *strnrcpy __P((char *, char *, size_t));
1067
1068/* xgetcwd():
1069 *	Return the pathname of the current directory, or return
1070 *	an error message in pathname.
1071 */
1072
1073# ifdef hp9000s500
1074/*
1075 *  From: Bernd Mohr <mohr@faui77.informatik.uni-erlangen.de>
1076 *  I also ported the tcsh to the HP9000 Series 500. This computer
1077 *  is a little bit different than the other HP 9000 computer. It has
1078 *  a HP Chip instead of a Motorola CPU and it is no "real" UNIX. It runs
1079 *  HP-UX which is emulated in top of a HP operating system. So, the last
1080 *  supported version of HP-UX is 5.2 on the HP9000s500. This has two
1081 *  consequences: it supports no job control and it has a filesystem
1082 *  without "." and ".." !!!
1083 */
1084char *
1085xgetcwd(pathname, pathlen)
1086    char *pathname;
1087    size_t pathlen;
1088{
1089    char pathbuf[MAXNAMLEN];	/* temporary pathname buffer */
1090    char *pnptr = &pathbuf[(sizeof pathbuf)-1]; /* pathname pointer */
1091    dev_t rdev;			/* root device number */
1092    DIR *dirp = NULL;		/* directory stream */
1093    ino_t rino;			/* root inode number */
1094    off_t rsize;		/* root size */
1095    struct direct *dir;		/* directory entry struct */
1096    struct stat d, dd;		/* file status struct */
1097    int serrno;
1098
1099    *pnptr = '\0';
1100    (void) stat("/.", &d);
1101    rdev = d.st_dev;
1102    rino = d.st_ino;
1103    rsize = d.st_size;
1104    for (;;) {
1105	if (stat(".", &d) == -1) {
1106	    (void) xsnprintf(pathname, pathlen, CGETS(23, 24,
1107		"getcwd: Cannot stat \".\" (%s)"), strerror(errno));
1108	    goto fail;
1109	}
1110	if (d.st_ino == rino && d.st_dev == rdev && d.st_size == rsize)
1111	    break;		/* reached root directory */
1112	if ((dirp = opendir("..")) == NULL) {
1113	    (void) xsnprintf(pathname, pathlen, CGETS(23, 19,
1114		"getcwd: Cannot open \"..\" (%s)"), strerror(errno));
1115	    goto fail;
1116	}
1117	if (chdir("..") == -1) {
1118	    (void) xsnprintf(pathname, pathlen, CGETS(23, 20,
1119		"getcwd: Cannot chdir to \"..\" (%s)"), strerror(errno));
1120	    goto fail;
1121	}
1122	do {
1123	    if ((dir = readdir(dirp)) == NULL) {
1124		(void) xsnprintf(pathname, pathlen,
1125		    CGETS(23, 21, "getcwd: Read error in \"..\" (%s)"),
1126		    strerror(errno));
1127		goto fail;
1128	    }
1129	    if (stat(dir->d_name, &dd) == -1) {
1130		(void) xsnprintf(pathname, pathlen,
1131		    CGETS(23, 25, "getcwd: Cannot stat directory \"%s\" (%s)"),
1132		    dir->d_name, strerror(errno));
1133		goto fail;
1134	    }
1135	} while (dd.st_ino  != d.st_ino  ||
1136		 dd.st_dev  != d.st_dev  ||
1137		 dd.st_size != d.st_size);
1138	(void) closedir(dirp);
1139	dirp = NULL;
1140	pnptr = strnrcpy(dirp->d_name, pnptr, pnptr - pathbuf);
1141	pnptr = strnrcpy("/", pnptr, pnptr - pathbuf);
1142    }
1143
1144    if (*pnptr == '\0')		/* current dir == root dir */
1145	(void) strncpy(pathname, "/", pathlen);
1146    else {
1147	(void) strncpy(pathname, pnptr, pathlen);
1148	pathname[pathlen - 1] = '\0';
1149	if (chdir(pnptr) == -1) {
1150	    (void) xsnprintf(pathname, MAXPATHLEN, CGETS(23, 22,
1151		    "getcwd: Cannot change back to \".\" (%s)"),
1152		    strerror(errno));
1153	    return NULL;
1154	}
1155    }
1156    return pathname;
1157
1158fail:
1159    serrno = errno;
1160    (void) chdir(strnrcpy(".", pnptr, pnptr - pathbuf));
1161    errno = serrno;
1162    return NULL;
1163}
1164
1165# else /* ! hp9000s500 */
1166
1167#  if (SYSVREL != 0 && !defined(d_fileno)) || defined(_VMS_POSIX) || defined(WINNT) || defined(_MINIX_VMD)
1168#   define d_fileno d_ino
1169#  endif
1170
1171char *
1172xgetcwd(pathname, pathlen)
1173    char   *pathname;
1174    size_t pathlen;
1175{
1176    DIR    *dp;
1177    struct dirent *d;
1178
1179    struct stat st_root, st_cur, st_next, st_dotdot;
1180    char    pathbuf[MAXPATHLEN], nextpathbuf[MAXPATHLEN * 2];
1181    char   *pathptr, *nextpathptr, *cur_name_add;
1182    int	   save_errno = 0;
1183
1184    /* find the inode of root */
1185    if (stat("/", &st_root) == -1) {
1186	(void) xsnprintf(pathname, pathlen, CGETS(23, 23,
1187			"getcwd: Cannot stat \"/\" (%s)"),
1188			strerror(errno));
1189	return NULL;
1190    }
1191    pathbuf[MAXPATHLEN - 1] = '\0';
1192    pathptr = &pathbuf[MAXPATHLEN - 1];
1193    nextpathbuf[MAXPATHLEN - 1] = '\0';
1194    cur_name_add = nextpathptr = &nextpathbuf[MAXPATHLEN - 1];
1195
1196    /* find the inode of the current directory */
1197    if (lstat(".", &st_cur) == -1) {
1198	(void) xsnprintf(pathname, pathlen, CGETS(23, 24,
1199			 "getcwd: Cannot stat \".\" (%s)"),
1200			 strerror(errno));
1201	return NULL;
1202    }
1203    nextpathptr = strnrcpy(nextpathptr, "../", nextpathptr - nextpathbuf);
1204
1205    /* Descend to root */
1206    for (;;) {
1207
1208	/* look if we found root yet */
1209	if (st_cur.st_ino == st_root.st_ino &&
1210	    DEV_DEV_COMPARE(st_cur.st_dev, st_root.st_dev)) {
1211	    (void) strncpy(pathname, *pathptr != '/' ? "/" : pathptr, pathlen);
1212	    pathname[pathlen - 1] = '\0';
1213	    return pathname;
1214	}
1215
1216	/* open the parent directory */
1217	if (stat(nextpathptr, &st_dotdot) == -1) {
1218	    (void) xsnprintf(pathname, pathlen, CGETS(23, 25,
1219			     "getcwd: Cannot stat directory \"%s\" (%s)"),
1220			     nextpathptr, strerror(errno));
1221	    return NULL;
1222	}
1223	if ((dp = opendir(nextpathptr)) == NULL) {
1224	    (void) xsnprintf(pathname, pathlen, CGETS(23, 26,
1225			     "getcwd: Cannot open directory \"%s\" (%s)"),
1226			     nextpathptr, strerror(errno));
1227	    return NULL;
1228	}
1229
1230	/* look in the parent for the entry with the same inode */
1231	if (DEV_DEV_COMPARE(st_dotdot.st_dev, st_cur.st_dev)) {
1232	    /* Parent has same device. No need to stat every member */
1233	    for (d = readdir(dp); d != NULL; d = readdir(dp)) {
1234#ifdef __clipper__
1235		if (((unsigned long)d->d_fileno & 0xffff) == st_cur.st_ino)
1236		    break;
1237#else
1238		if (d->d_fileno == st_cur.st_ino)
1239		    break;
1240#endif
1241	    }
1242	}
1243	else {
1244	    /*
1245	     * Parent has a different device. This is a mount point so we
1246	     * need to stat every member
1247	     */
1248	    for (d = readdir(dp); d != NULL; d = readdir(dp)) {
1249		if (ISDOT(d->d_name) || ISDOTDOT(d->d_name))
1250		    continue;
1251		(void)strncpy(cur_name_add, d->d_name,
1252		    (size_t) (&nextpathbuf[sizeof(nextpathbuf) - 1] - cur_name_add));
1253		if (lstat(nextpathptr, &st_next) == -1) {
1254		    /*
1255		     * We might not be able to stat() some path components
1256		     * if we are using afs, but this is not an error as
1257		     * long as we find the one we need; we also save the
1258		     * first error to report it if we don't finally succeed.
1259		     */
1260		    if (save_errno == 0)
1261			save_errno = errno;
1262		    continue;
1263		}
1264		/* check if we found it yet */
1265		if (st_next.st_ino == st_cur.st_ino &&
1266		    DEV_DEV_COMPARE(st_next.st_dev, st_cur.st_dev))
1267		    break;
1268	    }
1269	}
1270	if (d == NULL) {
1271	    (void) xsnprintf(pathname, pathlen, CGETS(23, 27,
1272			     "getcwd: Cannot find \".\" in \"..\" (%s)"),
1273			     strerror(save_errno ? save_errno : ENOENT));
1274	    (void) closedir(dp);
1275	    return NULL;
1276	}
1277	else
1278	    save_errno = 0;
1279	st_cur = st_dotdot;
1280	pathptr = strnrcpy(pathptr, d->d_name, pathptr - pathbuf);
1281	pathptr = strnrcpy(pathptr, "/", pathptr - pathbuf);
1282	nextpathptr = strnrcpy(nextpathptr, "../", nextpathptr - nextpathbuf);
1283	*cur_name_add = '\0';
1284	(void) closedir(dp);
1285    }
1286} /* end getcwd */
1287# endif /* hp9000s500 */
1288
1289/* strnrcpy():
1290 *	Like strncpy, going backwards and returning the new pointer
1291 */
1292static char *
1293strnrcpy(ptr, str, siz)
1294    register char *ptr, *str;
1295    size_t siz;
1296{
1297    register int len = strlen(str);
1298    if (siz == 0)
1299	return ptr;
1300
1301    while (len && siz--)
1302	*--ptr = str[--len];
1303
1304    return (ptr);
1305} /* end strnrcpy */
1306#endif /* getcwd */
1307
1308#ifdef apollo
1309/***
1310 *** Domain/OS
1311 ***/
1312#include <apollo/base.h>
1313#include <apollo/loader.h>
1314#include <apollo/error.h>
1315
1316
1317static char *
1318apperr(st)
1319    status_$t *st;
1320{
1321    static char buf[BUFSIZE];
1322    short e_subl, e_modl, e_codel;
1323    error_$string_t e_sub, e_mod, e_code;
1324
1325    error_$get_text(*st, e_sub, &e_subl, e_mod, &e_modl, e_code, &e_codel);
1326    e_sub[e_subl] = '\0';
1327    e_code[e_codel] = '\0';
1328    e_mod[e_modl] = '\0';
1329    (void) xsnprintf(buf, sizeof(buf), "%s (%s/%s)", e_code, e_sub, e_mod);
1330
1331    return(buf);
1332}
1333
1334static int
1335llib(s)
1336    Char *s;
1337{
1338    short len = Strlen(s);
1339    status_$t st;
1340    char *t;
1341
1342    loader_$inlib(t = short2str(s), len, &st);
1343    if (st.all != status_$ok)
1344	stderror(ERR_SYSTEM, t, apperr(&st));
1345}
1346
1347/*ARGSUSED*/
1348void
1349doinlib(v, c)
1350    Char **v;
1351    struct command *c;
1352{
1353    setname(short2str(*v++));
1354    gflag = 0, tglob(v);
1355    if (gflag) {
1356	v = globall(v);
1357	if (v == 0)
1358	    stderror(ERR_NAME | ERR_NOMATCH);
1359    }
1360    else {
1361	v = gargv = saveblk(v);
1362	trim(v);
1363    }
1364
1365    while (v && *v)
1366	llib(*v++);
1367    if (gargv)
1368	blkfree(gargv), gargv = 0;
1369}
1370
1371int
1372getv(v)
1373    Char *v;
1374{
1375    if (eq(v, STRbsd43))
1376	return(1);
1377    else if (eq(v, STRsys53))
1378	return(0);
1379    else
1380	stderror(ERR_NAME | ERR_SYSTEM, short2str(v),
1381		 CGETS(23, 28, "Invalid system type"));
1382    /*NOTREACHED*/
1383    return(0);
1384}
1385
1386/*ARGSUSED*/
1387void
1388dover(v, c)
1389    Char **v;
1390    struct command *c;
1391{
1392    Char *p;
1393
1394    setname(short2str(*v++));
1395    if (!*v) {
1396	if (!(p = tgetenv(STRSYSTYPE)))
1397	    stderror(ERR_NAME | ERR_STRING,
1398		     CGETS(23, 29, "System type is not set"));
1399	xprintf("%S\n", p);
1400    }
1401    else {
1402	tsetenv(STRSYSTYPE, getv(*v) ? STRbsd43 : STRsys53);
1403	dohash(NULL, NULL);
1404    }
1405}
1406
1407/*
1408 * Many thanks to rees@citi.umich.edu (Jim Rees) and
1409 *                mathys@ssdt-tempe.sps.mot.com (Yves Mathys)
1410 * For figuring out how to do this... I could have never done
1411 * it without their help.
1412 */
1413typedef short enum {
1414	name_$wdir_type,
1415	name_$ndir_type,
1416	name_$node_dir_type,
1417} name_$dir_type_t;
1418
1419/*ARGSUSED*/
1420void
1421dorootnode(v, c)
1422    Char **v;
1423    struct command *c;
1424{
1425    name_$dir_type_t dirtype = name_$node_dir_type;
1426    uid_$t uid;
1427    status_$t st;
1428    char *name;
1429    short namelen;
1430
1431    setname(short2str(*v++));
1432
1433    name = short2str(*v);
1434    namelen = strlen(name);
1435
1436    name_$resolve(name, &namelen, &uid, &st);
1437    if (st.all != status_$ok)
1438	stderror(ERR_SYSTEM, name, apperr(&st));
1439    namelen = 0;
1440    name_$set_diru(&uid, "", &namelen, &dirtype, &st);
1441    if (st.all != status_$ok)
1442	stderror(ERR_SYSTEM, name, apperr(&st));
1443    dohash(NULL, NULL);
1444}
1445
1446int
1447isapad()
1448{
1449    static int res = -1;
1450    static status_$t st;
1451
1452    if (res == -1) {
1453	int strm;
1454	if (isatty(0))
1455	    strm = 0;
1456	if (isatty(1))
1457	    strm = 1;
1458	if (isatty(2))
1459	    strm = 2;
1460	else {
1461	    res = 0;
1462	    st.all = status_$ok;
1463	    return(res);
1464	}
1465	res = stream_$isavt(&strm, &st);
1466	res = res ? 1 : 0;
1467    }
1468    else {
1469	if (st.all != status_$ok)
1470	    stderror(ERR_SYSTEM, "stream_$isavt", apperr(&st));
1471    }
1472    return(res);
1473}
1474#endif
1475