- Add lwkt_serialize_adaptive_enter(9), it is same as lwkt_serialize_enter(9)
[dfdiff.git] / contrib / tcsh-6 / tc.os.c
blob7738321b4b6ac6ac752674a1a91de3e5f94402ba
1 /* $Header: /p/tcsh/cvsroot/tcsh/tc.os.c,v 3.69 2006/08/24 20:56:31 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.
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. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
33 #include "sh.h"
35 RCSID("$tcsh: tc.os.c,v 3.69 2006/08/24 20:56:31 christos Exp $")
37 #include "tw.h"
38 #include "ed.h"
39 #include "ed.defns.h" /* for the function names */
40 #include "sh.decls.h"
42 #ifdef _UWIN
43 #define TIOCGPGRP TIOCGETPGRP
44 #define TIOCSPGRP TIOCSETPGRP
45 #endif
47 /***
48 *** MACH
49 ***/
51 #ifdef MACH
52 /* dosetpath -- setpath built-in command
54 **********************************************************************
55 * HISTORY
56 * 08-May-88 Richard Draves (rpd) at Carnegie-Mellon University
57 * Major changes to remove artificial limits on sizes and numbers
58 * of paths.
60 **********************************************************************
63 #ifdef MACH
64 static Char STRCPATH[] = {'C', 'P', 'A', 'T', 'H', '\0'};
65 static Char STRLPATH[] = {'L', 'P', 'A', 'T', 'H', '\0'};
66 static Char STRMPATH[] = {'M', 'P', 'A', 'T', 'H', '\0'};
67 # if EPATH
68 static Char STREPATH[] = {'E', 'P', 'A', 'T', 'H', '\0'};
69 # endif
70 #endif /* MACH */
71 static Char *syspaths[] = {STRKPATH, STRCPATH, STRLPATH, STRMPATH,
73 #if EPATH
74 STREPATH,
75 #endif
76 0};
77 #define LOCALSYSPATH "/usr/local"
79 /*ARGSUSED*/
80 void
81 dosetpath(Char **arglist, struct command *c)
83 extern char *getenv();
84 Char **pathvars, **cmdargs;
85 char **spaths, **cpaths, **cmds;
86 char *tcp;
87 unsigned int npaths, ncmds;
88 int i, sysflag;
90 pintr_disabled++;
91 cleanup_push(&pintr_disabled, disabled_cleanup);
94 * setpath(3) uses stdio and we want 0, 1, 2 to work...
96 if (!didfds) {
97 (void) dcopy(SHIN, 0);
98 (void) dcopy(SHOUT, 1);
99 (void) dcopy(SHDIAG, 2);
100 didfds = 1;
103 for (i = 1; arglist[i] && (arglist[i][0] != '-'); i++);
104 npaths = i - 1;
106 cmdargs = &arglist[i];
107 for (; arglist[i]; i++);
108 ncmds = i - npaths - 1;
110 if (npaths) {
111 sysflag = 0;
112 pathvars = &arglist[1];
114 else {
115 sysflag = 1;
116 npaths = (sizeof syspaths / sizeof *syspaths) - 1;
117 pathvars = syspaths;
120 /* note that npaths != 0 */
122 spaths = xmalloc(npaths * sizeof *spaths);
123 setzero(spaths, npaths * sizeof *spaths);
124 cpaths = xmalloc((npaths + 1) * sizeof *cpaths);
125 setzero(cpaths, (npaths + 1) * sizeof *cpaths);
126 cmds = xmalloc((ncmds + 1) * sizeof *cmds);
127 setzero(cmds, (ncmds + 1) * sizeof *cmds);
128 for (i = 0; i < npaths; i++) {
129 char *val = getenv(short2str(pathvars[i]));
131 if (val == NULL)
132 val = "";
134 spaths[i] = xmalloc((Strlen(pathvars[i]) + strlen(val) + 2) *
135 sizeof **spaths);
136 (void) strcpy(spaths[i], short2str(pathvars[i]));
137 (void) strcat(spaths[i], "=");
138 (void) strcat(spaths[i], val);
139 cpaths[i] = spaths[i];
142 for (i = 0; i < ncmds; i++) {
143 Char *val = globone(cmdargs[i], G_ERROR);/*FIXRESET*/
145 if (val == NULL)
146 goto abortpath;
147 cmds[i] = strsave(short2str(val));
151 if (setpath(cpaths, cmds, LOCALSYSPATH, sysflag, 1) < 0) {
152 abortpath:
153 if (spaths) {
154 for (i = 0; i < npaths; i++)
155 xfree(spaths[i]);
156 xfree(spaths);
158 xfree(cpaths);
159 if (cmds) {
160 for (i = 0; i < ncmds; i++)
161 xfree(cmds[i]);
162 xfree(cmds);
165 cleanup_until(&pintr_disabled);
166 donefds();
167 return;
170 for (i = 0; i < npaths; i++) {
171 Char *val, *name;
173 name = str2short(cpaths[i]);
174 for (val = str2short(cpaths[i]); val && *val && *val != '='; val++);
175 if (val && *val == '=') {
176 *val++ = '\0';
178 tsetenv(name, val);/*FIXRESET*/
179 if (Strcmp(name, STRKPATH) == 0) {
180 importpath(val);/*FIXRESET*/
181 if (havhash)
182 dohash(NULL, NULL);/*FIXRESET*/
184 *--val = '=';
187 cleanup_until(&pintr_disabled);
188 donefds();
190 #endif /* MACH */
192 /***
193 *** AIX
194 ***/
195 #ifdef TCF
196 /* ARGSUSED */
197 void
198 dogetxvers(Char **v, struct command *c)
200 char xvers[MAXPATHLEN];
202 if (getxvers(xvers, MAXPATHLEN) == -1)
203 stderror(ERR_SYSTEM, "getxvers", strerror(errno));
204 xprintf("%s\n", xvers);
205 flush();
208 /*ARGSUSED*/
209 void
210 dosetxvers(Char **v, struct command *c)
212 char *xvers;
214 ++v;
215 if (!*v || *v[0] == '\0')
216 xvers = "";
217 else
218 xvers = short2str(*v);
219 if (setxvers(xvers) == -1)
220 stderror(ERR_SYSTEM, "setxvers", strerror(errno));
223 #include <sf.h>
224 #ifdef _AIXPS2
225 # define XC_PDP11 0x01
226 # define XC_23 0x02
227 # define XC_Z8K 0x03
228 # define XC_8086 0x04
229 # define XC_68K 0x05
230 # define XC_Z80 0x06
231 # define XC_VAX 0x07
232 # define XC_16032 0x08
233 # define XC_286 0x09
234 # define XC_386 0x0a
235 # define XC_S370 0x0b
236 #else
237 # include <sys/x.out.h>
238 #endif /* _AIXPS2 */
240 static struct xc_cpu_t {
241 short xc_id;
242 char *xc_name;
243 } xcpu[] =
245 { XC_PDP11, "pdp11" },
246 { XC_23, "i370" },
247 { XC_Z8K, "z8000" },
248 { XC_8086, "i86" },
249 { XC_68K, "mc68000" },
250 { XC_Z80, "x80" },
251 { XC_VAX, "vax" },
252 { XC_16032, "ns16032" },
253 { XC_286, "i286" },
254 { XC_386, "i386" },
255 { XC_S370, "xa370" },
256 { 0, NULL }
260 * our local hack table, stolen from x.out.h
262 static char *
263 getxcode(short xcid)
265 int i;
267 for (i = 0; xcpu[i].xc_name != NULL; i++)
268 if (xcpu[i].xc_id == xcid)
269 return (xcpu[i].xc_name);
270 return (NULL);
273 static short
274 getxid(char *xcname)
276 int i;
278 for (i = 0; xcpu[i].xc_name != NULL; i++)
279 if (strcmp(xcpu[i].xc_name, xcname) == 0)
280 return (xcpu[i].xc_id);
281 return ((short) -1);
285 /*ARGSUSED*/
286 void
287 dogetspath(Char **v, struct command *c)
289 int i, j;
290 sitepath_t p[MAXSITE];
291 struct sf *st;
292 static char *local = "LOCAL ";
294 if ((j = getspath(p, MAXSITE)) == -1)
295 stderror(ERR_SYSTEM, "getspath", strerror(errno));
296 for (i = 0; i < j && (p[i] & SPATH_CPU) != NOSITE; i++) {
297 if (p[i] & SPATH_CPU) {
298 if ((p[i] & SPATH_MASK) == NULLSITE)
299 xprintf(local);
300 else if ((st = sfxcode((short) (p[i] & SPATH_MASK))) != NULL)
301 xprintf("%s ", st->sf_ctype);
302 else {
303 char *xc = getxcode(p[i] & SPATH_MASK);
305 if (xc != NULL)
306 xprintf("%s ", xc);
307 else
308 xprintf("*cpu %d* ", (int) (p[i] & SPATH_MASK));
310 * BUG in the aix code... needs that cause if
311 * sfxcode fails once it fails for ever
313 endsf();
316 else {
317 if (p[i] == NULLSITE)
318 xprintf(local);
319 else if ((st = sfnum(p[i])) != NULL)
320 xprintf("%s ", st->sf_sname);
321 else
322 xprintf("*site %d* ", (int) (p[i] & SPATH_MASK));
325 xputchar('\n');
326 flush();
329 /*ARGSUSED*/
330 void
331 dosetspath(Char **v, struct command *c)
333 int i;
334 short j;
335 char *s;
336 sitepath_t p[MAXSITE];
337 struct sf *st;
340 * sfname() on AIX G9.9 at least, mallocs too pointers p, q
341 * then does the equivalent of while (*p++ == *q++) continue;
342 * and then tries to free(p,q) them! Congrats to the wizard who
343 * wrote that one. I bet he tested it really well too.
344 * Sooo, we set dont_free :-)
346 dont_free = 1;
347 for (i = 0, v++; *v && *v[0] != '\0'; v++, i++) {
348 s = short2str(*v);
349 if (isdigit(*s))
350 p[i] = atoi(s);
351 else if (strcmp(s, "LOCAL") == 0)
352 p[i] = NULLSITE;
353 else if ((st = sfctype(s)) != NULL)
354 p[i] = SPATH_CPU | st->sf_ccode;
355 else if ((j = getxid(s)) != -1)
356 p[i] = SPATH_CPU | j;
357 else if ((st = sfname(s)) != NULL)
358 p[i] = st->sf_id;
359 else {
360 setname(s);
361 stderror(ERR_NAME | ERR_STRING, CGETS(23, 1, "Bad cpu/site name"));
363 if (i == MAXSITE - 1)
364 stderror(ERR_NAME | ERR_STRING, CGETS(23, 2, "Site path too long"));
366 if (setspath(p, i) == -1)
367 stderror(ERR_SYSTEM, "setspath", strerror(errno));
368 dont_free = 0;
371 /* sitename():
372 * Return the site name where the process is running
374 char *
375 sitename(pid_t pid)
377 siteno_t ss;
378 struct sf *st;
380 if ((ss = site(pid)) == -1 || (st = sfnum(ss)) == NULL)
381 return CGETS(23, 3, "unknown");
382 else
383 return st->sf_sname;
386 static int
387 migratepid(pit_t pid, siteno_t new_site)
389 struct sf *st;
390 int need_local;
392 need_local = (pid == 0) || (pid == getpid());
394 if (kill3(pid, SIGMIGRATE, new_site) < 0) {
395 xprintf("%d: %s\n", pid, strerror(errno));
396 return (-1);
399 if (need_local) {
400 if ((new_site = site(0)) == -1) {
401 xprintf(CGETS(23, 4, "site: %s\n"), strerror(errno));
402 return (-1);
404 if ((st = sfnum(new_site)) == NULL) {
405 xprintf(CGETS(23, 5, "%d: Site not found\n"), new_site);
406 return (-1);
408 if (setlocal(st->sf_local, strlen(st->sf_local)) == -1) {
409 xprintf(CGETS(23, 6, "setlocal: %s: %s\n"),
410 st->sf_local, strerror(errno));
411 return (-1);
414 return (0);
417 /*ARGSUSED*/
418 void
419 domigrate(Char **v, struct command *c)
421 struct sf *st;
422 char *s;
423 Char *cp;
424 struct process *pp;
425 int err1 = 0;
426 int pid = 0;
427 siteno_t new_site = 0;
429 pchild_disabled++;
430 cleanup_push(&pchild_disabled, disabled_cleanup);
431 if (setintr) {
432 pintr_disabled++;
433 cleanup_push(&pintr_disabled, disabled_cleanup);
436 ++v;
437 if (*v[0] == '-') {
439 * Do the -site.
441 s = short2str(&v[0][1]);
443 * see comment in setspath()
445 dont_free = 1;
446 if ((st = sfname(s)) == NULL) {
447 dont_free = 0;
448 setname(s);
449 stderror(ERR_NAME | ERR_STRING, CGETS(23, 7, "Site not found"));
451 dont_free = 0;
452 new_site = st->sf_id;
453 ++v;
456 if (!*v || *v[0] == '\0') {
457 if (migratepid(0, new_site) == -1)
458 err1++;
460 else {
461 Char **globbed;
463 v = glob_all_or_error(v);
464 globbed = v;
465 cleanup_push(globbed, blk_cleanup);
467 while (v && (cp = *v)) {
468 if (*cp == '%') {
469 pp = pfind(cp);
470 if (kill3(- pp->p_jobid, SIGMIGRATE, new_site) < 0) {
471 xprintf("%S: %s\n", cp, strerror(errno));
472 err1++;
475 else if (!(Isdigit(*cp) || *cp == '-'))
476 stderror(ERR_NAME | ERR_JOBARGS);
477 else {
478 pid = atoi(short2str(cp));
479 if (migratepid(pid, new_site) == -1)
480 err1++;
482 v++;
484 cleanup_until(globbed);
487 done:
488 cleanup_until(&pchild_disabled);
489 if (err1)
490 stderror(ERR_SILENT);
493 #endif /* TCF */
495 /***
496 *** CRAY ddmode <velo@sesun3.epfl.ch> (Martin Ouwehand EPFL-SIC/SE)
497 ***/
498 #if defined(_CRAY) && !defined(_CRAYMPP)
499 void
500 dodmmode(Char **v, struct command *c)
502 Char *cp = v[1];
504 USE(c);
506 if ( !cp ) {
507 int mode;
509 mode = dmmode(0);
510 dmmode(mode);
511 xprintf("%d\n",mode);
513 else {
514 if (cp[1] != '\0')
515 stderror(ERR_NAME | ERR_STRING,
516 CGETS(23, 30, "Too many arguments"));
517 else
518 switch(*cp) {
519 case '0':
520 dmmode(0);
521 break;
522 case '1':
523 dmmode(1);
524 break;
525 default:
526 stderror(ERR_NAME | ERR_STRING,
527 CGETS(23, 31, "Invalid argument"));
531 #endif /* _CRAY && !_CRAYMPP */
534 /***
535 *** CONVEX Warps.
536 ***/
538 #ifdef WARP
540 * handle the funky warping of symlinks
542 #include <warpdb.h>
543 #include <sys/warp.h>
545 static jmp_buf sigsys_buf;
547 static void
548 catch_sigsys(void)
550 sigset_t set;
551 sigemptyset(&set, SIGSYS);
552 (void)sigprocmask(SIG_UNBLOCK, &set, NULL);
553 longjmp(sigsys_buf, 1);
557 /*ARGSUSED*/
558 void
559 dowarp(Char **v, struct command *c)
561 int warp, oldwarp;
562 struct warpent *we;
563 volatile struct sigaction old_sigsys_handler;
564 char *newwarp;
566 if (setjmp(sigsys_buf)) {
567 sigaction(SIGSYS, &old_sigsys_handler, NULL);
568 stderror(ERR_NAME | ERR_STRING,
569 CGETS(23, 8, "You're trapped in a universe you never made"));
570 return;
572 sigaction(SIGSYS, NULL, &old_sigsys_handler);
573 signal(SIGSYS, catch_sigsys);
575 warp = getwarp();
577 v++;
578 if (*v == 0) { /* display warp value */
579 if (warp < 0)
580 stderror(ERR_NAME | ERR_STRING, CGETS(23, 9, "Getwarp failed"));
581 we = getwarpbyvalue(warp);
582 if (we)
583 printf("%s\n", we->w_name);
584 else
585 printf("%d\n", warp);
587 else { /* set warp value */
588 oldwarp = warp;
589 newwarp = short2str(*v);
590 if (Isdigit(*v[0]))
591 warp = atoi(newwarp);
592 else {
593 we = getwarpbyname(newwarp);
594 if (we)
595 warp = we->w_value;
596 else
597 warp = -1;
599 if ((warp < 0) || (warp >= WARP_MAXLINK))
600 stderror(ERR_NAME | ERR_STRING, CGETS(23, 10, "Invalid warp"));
601 if ((setwarp(warp) < 0) || (getwarp() != warp)) {
602 (void) setwarp(oldwarp);
603 stderror(ERR_NAME | ERR_STRING, CGETS(23, 11, "Setwarp failed"));
606 sigaction(SIGSYS, &old_sigsys_handler, NULL);
608 #endif /* WARP */
610 /***
611 *** Masscomp or HCX
612 ***/
613 /* Added, DAS DEC-90. */
614 #if defined(masscomp) || defined(_CX_UX)
615 static void
616 setuniverse_cleanup(void *xbuf)
618 char *buf;
620 buf = xbuf;
621 setuniverse(buf);
624 /*ARGSUSED*/
625 void
626 douniverse(Char **v, struct command *c)
628 Char *cp = v[1];
629 Char *cp2; /* dunno how many elements v comes in with */
630 char ubuf[100];
632 if (cp == 0) {
633 (void) getuniverse(ubuf);
634 xprintf("%s\n", ubuf);
636 else {
637 cp2 = v[2];
638 if (cp2 == 0) {
639 if (*cp == '\0' || setuniverse(short2str(cp)) != 0)
640 stderror(ERR_NAME | ERR_STRING, CGETS(23, 12, "Illegal universe"));
642 else {
643 (void) getuniverse(ubuf);
644 if (*cp == '\0' || setuniverse(short2str(cp)) != 0)
645 stderror(ERR_NAME | ERR_STRING, CGETS(23, 12, "Illegal universe"));
646 cleanup_push(ubuf, setuniverse_cleanup);
647 if (setintr) {
648 pintr_disabled++;
649 cleanup_push(&pintr_disabled, disabled_cleanup);
651 lshift(v, 2);
652 if (setintr)
653 cleanup_until(&pintr_disabled);
654 reexecute(c);
655 cleanup_until(ubuf);
659 #endif /* masscomp || _CX_UX */
661 /***
662 *** BS2000/OSD POSIX (Fujitsu Siemens Computers)
663 ***/
664 #if defined(_OSD_POSIX)
665 static int
666 bs2upcase(char *str)
668 enum { outside = ' ', singlequote='\'', doublequote='"'} string = outside;
670 char *white;
672 for (white = str + strlen(str) - 1; isspace(*white) && white > str; --white)
673 *white = '\0';
675 for (; *str != '\0'; ++str)
677 if (string == outside)
679 *str = toupper (*str);
681 if (*str == '\'')
683 if (string == outside)
684 string = singlequote;
685 else if (string != doublequote)
686 string = outside;
688 else if (*str == '"')
690 if (string == outside)
691 string = doublequote;
692 else if (string != singlequote)
693 string = outside;
696 if (string != outside)
698 stderror(ERR_NAME | ERR_UNMATCHED, (Char) string);
699 return 1;
701 return 0;
703 static int
704 bs2cmdlist(char *str)
706 char *str_beg = NULL;
707 int ret = 0;
709 enum { outside = ' ', singlequote='\'', doublequote='"'} string = outside;
711 while (*str != '\0')
713 while (isspace(*str))
714 ++str;
716 if (*str == '\0')
717 break;
719 str_beg = str;
721 for (; *str != '\0'; ++str)
723 if (string == outside && *str == ';') /* End of command */
725 *str++ = '\0';
726 break; /* continue with next command */
728 if (*str == '\'')
730 if (string == outside)
731 string = singlequote;
732 else if (string != doublequote)
733 string = outside;
735 else if (*str == '"')
737 if (string == outside)
738 string = doublequote;
739 else if (string != singlequote)
740 string = outside;
743 if (strlen(str_beg) != 0)
745 ret = bs2system(str_beg);
746 flush();
747 if (ret != 0 /*&& !option.err_ignore*/)
748 break; /* do not continue after errors */
752 if (string != outside)
754 stderror(ERR_NAME | ERR_UNMATCHED, (Char) string);
755 return -1;
758 return ret;
760 /*ARGSUSED*/
761 void
762 dobs2cmd(Char **v, struct command *c)
764 Char *cp, **globbed;
765 int i = 0, len = 0;
766 char *cmd = NULL;
767 int pvec[2];
768 struct command faket;
769 Char *fakecom[2];
770 char tibuf[BUFSIZE];
771 int icnt, old_pintr_disabled;
772 static const Char STRbs2cmd[] = { 'b','s','2','c','m','d','\0' };
774 v++;
775 if (setintr)
776 pintr_push_enable(&old_pintr_disabled);
777 v = glob_all_or_error(v);
778 if (setintr)
779 cleanup_until(&old_pintr_disabled);
780 globbed = v;
781 cleanup_push(globbed, blk_cleanup);
783 /* First round: count the string lengths */
784 for (i=0; v[i]; ++i) {
785 len += Strlen(v[i]) + (v[i+1] != NULL);
788 cmd = xmalloc(len+1); /* 1 for the final '\0' *//* FIXME: memory leak? */
790 /* 2nd round: fill cmd buffer */
791 i = 0;
792 while ((cp = *v++) != 0) {
793 int c;
794 while (c = *cp++)
795 cmd[i++] = (char)c;
796 if (*v)
797 cmd[i++] = ' ';
799 cmd[i] = '\0';
801 /* Make upper case */
802 bs2upcase(cmd);
804 faket.t_dtyp = NODE_COMMAND;
805 faket.t_dflg = F_BACKQ|F_STDERR;
806 faket.t_dlef = 0;
807 faket.t_drit = 0;
808 faket.t_dspr = 0;
809 faket.t_dcom = fakecom;
810 fakecom[0] = (Char *)STRbs2cmd;
811 fakecom[1] = 0;
813 mypipe(pvec);
814 cleanup_push(&pvec[0], open_cleanup);
815 cleanup_push(&pvec[1], open_cleanup);
816 if (pfork(&faket, -1) == 0) {
817 sigset_t set;
818 /* child */
819 xclose(pvec[0]);
820 (void) dmove(pvec[1], 1);
821 (void) dmove(SHDIAG, 2);
822 initdesc();
823 sigemptyset(&set);
824 sigaddset(&set, SIGINT);
825 (void)sigprocmask(SIG_UNBLOCK, &set, NULL);
826 #ifdef SIGTSTP
827 signal(SIGTSTP, SIG_IGN);
828 #endif
829 #ifdef SIGTTIN
830 signal(SIGTTIN, SIG_IGN);
831 #endif
832 #ifdef SIGTTOU
833 signal(SIGTTOU, SIG_IGN);
834 #endif
835 xexit(bs2cmdlist(cmd));
837 cleanup_until(&pvec[1]);
838 for(;;) {
839 int old_pintr_disabled;
841 if (setintr)
842 pintr_push_enable(&old_pintr_disabled);
843 icnt = xread(pvec[0], tibuf, sizeof(tibuf));
844 if (setintr)
845 cleanup_until(&old_pintr_disabled);
846 if (icnt <= 0)
847 break;
848 for (i = 0; i < icnt; i++)
849 xputchar((unsigned char) tibuf[i]);
851 cleanup_until(&pvec[0]);
852 pwait();
854 flush();
856 cleanup_until(globbed);
858 #endif /* _OSD_POSIX */
860 #if defined(_CX_UX)
861 static void
862 setuniverse_cleanup(void *xbuf)
864 char *buf;
866 buf = xbuf;
867 setuniverse(buf);
870 /*ARGSUSED*/
871 void
872 doatt(Char **v, struct command *c)
874 Char *cp = v[1];
875 char ubuf[100];
877 if (cp == 0)
878 (void) setuniverse("att");
879 else {
880 (void) getuniverse(ubuf);
881 (void) setuniverse("att");
882 cleanup_push(ubuf, setuniverse_cleanup);
883 if (setintr) {
884 pintr_disabled++;
885 cleanup_push(&pintr_disabled, disabled_cleanup);
887 lshift(v, 1);
888 if (setintr)
889 cleanup_until(&pintr_disabled);
890 reexecute(c);
891 cleanup_until(ubuf);
895 /*ARGSUSED*/
896 void
897 doucb(Char **v, struct command *c)
899 Char *cp = v[1];
900 char ubuf[100];
902 if (cp == 0)
903 (void) setuniverse("ucb");
904 else {
905 (void) getuniverse(ubuf);
906 (void) setuniverse("ucb");
907 cleanup_push(ubuf, setuniverse_cleanup);
908 if (setintr) {
909 pintr_disabled++;
910 cleanup_push(&pintr_disabled, disabled_cleanup);
912 lshift(v, 1);
913 if (setintr)
914 cleanup_until(&pintr_disabled);
915 reexecute(c);
916 cleanup_until(ubuf);
919 #endif /* _CX_UX */
921 #ifdef _SEQUENT_
923 * Compute the difference in process stats.
925 void
926 pr_stat_sub(struct process_stats *p2, struct process_stats *p1,
927 struct process_stats *pr)
929 pr->ps_utime.tv_sec = p2->ps_utime.tv_sec - p1->ps_utime.tv_sec;
930 pr->ps_utime.tv_usec = p2->ps_utime.tv_usec - p1->ps_utime.tv_usec;
931 if (pr->ps_utime.tv_usec < 0) {
932 pr->ps_utime.tv_sec -= 1;
933 pr->ps_utime.tv_usec += 1000000;
935 pr->ps_stime.tv_sec = p2->ps_stime.tv_sec - p1->ps_stime.tv_sec;
936 pr->ps_stime.tv_usec = p2->ps_stime.tv_usec - p1->ps_stime.tv_usec;
937 if (pr->ps_stime.tv_usec < 0) {
938 pr->ps_stime.tv_sec -= 1;
939 pr->ps_stime.tv_usec += 1000000;
942 pr->ps_maxrss = p2->ps_maxrss - p1->ps_maxrss;
943 pr->ps_pagein = p2->ps_pagein - p1->ps_pagein;
944 pr->ps_reclaim = p2->ps_reclaim - p1->ps_reclaim;
945 pr->ps_zerofill = p2->ps_zerofill - p1->ps_zerofill;
946 pr->ps_pffincr = p2->ps_pffincr - p1->ps_pffincr;
947 pr->ps_pffdecr = p2->ps_pffdecr - p1->ps_pffdecr;
948 pr->ps_swap = p2->ps_swap - p1->ps_swap;
949 pr->ps_syscall = p2->ps_syscall - p1->ps_syscall;
950 pr->ps_volcsw = p2->ps_volcsw - p1->ps_volcsw;
951 pr->ps_involcsw = p2->ps_involcsw - p1->ps_involcsw;
952 pr->ps_signal = p2->ps_signal - p1->ps_signal;
953 pr->ps_lread = p2->ps_lread - p1->ps_lread;
954 pr->ps_lwrite = p2->ps_lwrite - p1->ps_lwrite;
955 pr->ps_bread = p2->ps_bread - p1->ps_bread;
956 pr->ps_bwrite = p2->ps_bwrite - p1->ps_bwrite;
957 pr->ps_phread = p2->ps_phread - p1->ps_phread;
958 pr->ps_phwrite = p2->ps_phwrite - p1->ps_phwrite;
961 #endif /* _SEQUENT_ */
964 #ifndef HAVE_MEMSET
965 /* This is a replacement for a missing memset function */
966 void *xmemset(void *loc, int value, size_t len)
968 char *ptr = loc;
970 while (len--)
971 *ptr++ = value;
972 return loc;
974 #endif /* !HAVE_MEMSET */
977 #ifndef HAVE_MEMMOVE
978 /* memmove():
979 * This is the ANSI form of bcopy() with the arguments backwards...
980 * Unlike memcpy(), it handles overlaps between source and
981 * destination memory
983 void *
984 xmemmove(void *vdst, const void *vsrc, size_t len)
986 const char *src = vsrc;
987 char *dst = vdst;
989 if (src == dst)
990 return vdst;
992 if (src > dst) {
993 while (len--)
994 *dst++ = *src++;
996 else {
997 src += len;
998 dst += len;
999 while (len--)
1000 *--dst = *--src;
1002 return vdst;
1004 #endif /* HAVE_MEMMOVE */
1007 #ifndef WINNT_NATIVE
1008 #ifdef NEEDtcgetpgrp
1009 pid_t
1010 xtcgetpgrp(int fd)
1012 int pgrp;
1014 /* ioctl will handle setting errno correctly. */
1015 if (ioctl(fd, TIOCGPGRP, (ioctl_t) & pgrp) < 0)
1016 return (-1);
1017 return (pgrp);
1021 * XXX: tcsetpgrp is not a macro any more cause on some systems,
1022 * pid_t is a short, but the ioctl() takes a pointer to int (pyr)
1023 * Thanks to Simon Day (simon@pharaoh.cyborg.bt.co.uk) for pointing
1024 * this out.
1027 xtcsetpgrp(int fd, int pgrp)
1029 return ioctl(fd, TIOCSPGRP, (ioctl_t) &pgrp);
1032 #endif /* NEEDtcgetpgrp */
1033 #endif /* WINNT_NATIVE */
1036 #ifdef YPBUGS
1037 void
1038 fix_yp_bugs(void)
1040 char *mydomain;
1042 extern int yp_get_default_domain (char **);
1044 * PWP: The previous version assumed that yp domain was the same as the
1045 * internet name domain. This isn't allways true. (Thanks to Mat Landau
1046 * <mlandau@bbn.com> for the original version of this.)
1048 if (yp_get_default_domain(&mydomain) == 0) { /* if we got a name */
1049 extern void yp_unbind (const char *);
1051 yp_unbind(mydomain);
1055 #endif /* YPBUGS */
1057 #ifdef STRCOLLBUG
1058 void
1059 fix_strcoll_bug(void)
1061 #if defined(NLS) && defined(HAVE_STRCOLL)
1063 * SunOS4 checks the file descriptor from openlocale() for <= 0
1064 * instead of == -1. Someone should tell sun that file descriptor 0
1065 * is valid! Our portable hack: open one so we call it with 0 used...
1066 * We have to call this routine every time the locale changes...
1068 * Of course it also tries to free the constant locale "C" it initially
1069 * had allocated, with the sequence
1070 * > setenv LANG "fr"
1071 * > ls^D
1072 * > unsetenv LANG
1073 * But we are smarter than that and just print a warning message.
1075 int fd = -1;
1076 static char *root = "/";
1078 if (!didfds)
1079 fd = xopen(root, O_RDONLY|O_LARGEFILE);
1081 (void) strcoll(root, root);
1083 if (fd != -1)
1084 xclose(fd);
1085 #endif
1087 #endif /* STRCOLLBUG */
1090 #ifdef OREO
1091 #include <compat.h>
1092 #endif /* OREO */
1094 void
1095 osinit(void)
1097 #ifdef OREO
1098 set42sig();
1099 setcompat(getcompat() & ~COMPAT_EXEC);
1100 signal(SIGIO, SIG_IGN); /* ignore SIGIO */
1101 #endif /* OREO */
1103 #ifdef aiws
1105 struct sigstack inst;
1106 inst.ss_sp = xmalloc(4192) + 4192;
1107 inst.ss_onstack = 0;
1108 sigstack(&inst, NULL);
1110 #endif /* aiws */
1112 #ifdef apollo
1113 (void) isapad();
1114 #endif
1116 #ifdef _SX
1118 * kill(SIGCONT) problems, don't know what this syscall does
1119 * [schott@rzg.mpg.de]
1121 syscall(151, getpid(), getpid());
1122 #endif /* _SX */
1125 #ifndef HAVE_STRERROR
1126 extern int sys_nerr;
1127 extern char *sys_errlist[];
1128 char *
1129 xstrerror(int i)
1131 if (i >= 0 && i < sys_nerr) {
1132 return sys_errlist[i];
1133 } else {
1134 static char *errbuf; /* = NULL; */
1136 xfree(errbuf);
1137 errbuf = xasprintf(CGETS(23, 13, "Unknown Error: %d"), i);
1138 return errbuf;
1141 #endif /* !HAVE_STRERROR */
1143 #ifndef HAVE_GETHOSTNAME
1144 # if !defined(_MINIX) && !defined(__EMX__) && !defined(WINNT_NATIVE)
1145 # include <sys/utsname.h>
1146 # endif /* !_MINIX && !__EMX__ && !WINNT_NATIVE */
1149 xgethostname(char *name, int namlen)
1151 # if !defined(_MINIX) && !defined(__EMX__) && !defined(WINNT_NATIVE)
1152 int i, retval;
1153 struct utsname uts;
1155 retval = uname(&uts);
1157 # ifdef DEBUG
1158 xprintf(CGETS(23, 14, "sysname: %s\n"), uts.sysname);
1159 xprintf(CGETS(23, 15, "nodename: %s\n"), uts.nodename);
1160 xprintf(CGETS(23, 16, "release: %s\n"), uts.release);
1161 xprintf(CGETS(23, 17, "version: %s\n"), uts.version);
1162 xprintf(CGETS(23, 18, "machine: %s\n"), uts.machine);
1163 # endif /* DEBUG */
1164 i = strlen(uts.nodename) + 1;
1165 (void) strncpy(name, uts.nodename, i < namlen ? i : namlen);
1167 return retval;
1168 # else /* !_MINIX && !__EMX__ */
1169 if (namlen > 0) {
1170 # ifdef __EMX__
1171 (void) strncpy(name, "OS/2", namlen);
1172 # else /* _MINIX */
1173 (void) strncpy(name, "minix", namlen);
1174 # endif /* __EMX__ */
1175 name[namlen-1] = '\0';
1177 return(0);
1178 #endif /* _MINIX && !__EMX__ */
1179 } /* end xgethostname */
1180 #endif /* !HAVE_GETHOSTNAME */
1182 #ifndef HAVE_NICE
1183 # if defined(_MINIX) && defined(NICE)
1184 # undef _POSIX_SOURCE /* redefined in <lib.h> */
1185 # undef _MINIX /* redefined in <lib.h> */
1186 # undef HZ /* redefined in <minix/const.h> */
1187 # include <lib.h>
1188 # endif /* _MINIX && NICE */
1189 int
1190 xnice(int incr)
1192 #if defined(_MINIX) && defined(NICE)
1193 return callm1(MM, NICE, incr, 0, 0, NIL_PTR, NIL_PTR, NIL_PTR);
1194 #else
1195 return /* incr ? 0 : */ 0;
1196 #endif /* _MINIX && NICE */
1197 } /* end xnice */
1198 #endif /* !HAVE_NICE */
1200 #ifndef HAVE_GETCWD
1201 static char *strnrcpy (char *, char *, size_t);
1203 /* xgetcwd():
1204 * Return the pathname of the current directory, or return
1205 * an error message in pathname.
1208 # ifdef hp9000s500
1210 * From: Bernd Mohr <mohr@faui77.informatik.uni-erlangen.de>
1211 * I also ported the tcsh to the HP9000 Series 500. This computer
1212 * is a little bit different than the other HP 9000 computer. It has
1213 * a HP Chip instead of a Motorola CPU and it is no "real" UNIX. It runs
1214 * HP-UX which is emulated in top of a HP operating system. So, the last
1215 * supported version of HP-UX is 5.2 on the HP9000s500. This has two
1216 * consequences: it supports no job control and it has a filesystem
1217 * without "." and ".." !!!
1219 char *
1220 xgetcwd(char *pathname, size_t pathlen)
1222 char pathbuf[MAXPATHLEN]; /* temporary pathname buffer */
1223 char *pnptr = &pathbuf[(sizeof pathbuf)-1]; /* pathname pointer */
1224 dev_t rdev; /* root device number */
1225 DIR *dirp = NULL; /* directory stream */
1226 ino_t rino; /* root inode number */
1227 off_t rsize; /* root size */
1228 struct direct *dir; /* directory entry struct */
1229 struct stat d, dd; /* file status struct */
1230 int serrno;
1232 *pnptr = '\0';
1233 (void) stat("/.", &d);
1234 rdev = d.st_dev;
1235 rino = d.st_ino;
1236 rsize = d.st_size;
1237 for (;;) {
1238 if (stat(".", &d) == -1) {
1239 (void) xsnprintf(pathname, pathlen, CGETS(23, 24,
1240 "getcwd: Cannot stat \".\" (%s)"), strerror(errno));
1241 goto fail;
1243 if (d.st_ino == rino && d.st_dev == rdev && d.st_size == rsize)
1244 break; /* reached root directory */
1245 if ((dirp = opendir("..")) == NULL) {
1246 (void) xsnprintf(pathname, pathlen, CGETS(23, 19,
1247 "getcwd: Cannot open \"..\" (%s)"), strerror(errno));
1248 goto fail;
1250 if (chdir("..") == -1) {
1251 (void) xsnprintf(pathname, pathlen, CGETS(23, 20,
1252 "getcwd: Cannot chdir to \"..\" (%s)"), strerror(errno));
1253 goto fail;
1255 do {
1256 if ((dir = readdir(dirp)) == NULL) {
1257 (void) xsnprintf(pathname, pathlen,
1258 CGETS(23, 21, "getcwd: Read error in \"..\" (%s)"),
1259 strerror(errno));
1260 goto fail;
1262 if (stat(dir->d_name, &dd) == -1) {
1263 (void) xsnprintf(pathname, pathlen,
1264 CGETS(23, 25, "getcwd: Cannot stat directory \"%s\" (%s)"),
1265 dir->d_name, strerror(errno));
1266 goto fail;
1268 } while (dd.st_ino != d.st_ino ||
1269 dd.st_dev != d.st_dev ||
1270 dd.st_size != d.st_size);
1271 closedir(dirp);
1272 dirp = NULL;
1273 pnptr = strnrcpy(dirp->d_name, pnptr, pnptr - pathbuf);
1274 pnptr = strnrcpy("/", pnptr, pnptr - pathbuf);
1277 if (*pnptr == '\0') /* current dir == root dir */
1278 (void) strncpy(pathname, "/", pathlen);
1279 else {
1280 (void) strncpy(pathname, pnptr, pathlen);
1281 pathname[pathlen - 1] = '\0';
1282 if (chdir(pnptr) == -1) {
1283 (void) xsnprintf(pathname, MAXPATHLEN, CGETS(23, 22,
1284 "getcwd: Cannot change back to \".\" (%s)"),
1285 strerror(errno));
1286 return NULL;
1289 return pathname;
1291 fail:
1292 serrno = errno;
1293 (void) chdir(strnrcpy(".", pnptr, pnptr - pathbuf));
1294 errno = serrno;
1295 return NULL;
1298 # else /* ! hp9000s500 */
1301 char *
1302 xgetcwd(char *pathname, size_t pathlen)
1304 DIR *dp;
1305 struct dirent *d;
1307 struct stat st_root, st_cur, st_next, st_dotdot;
1308 char pathbuf[MAXPATHLEN], nextpathbuf[MAXPATHLEN * 2];
1309 char *pathptr, *nextpathptr, *cur_name_add;
1310 int save_errno = 0;
1312 /* find the inode of root */
1313 if (stat("/", &st_root) == -1) {
1314 (void) xsnprintf(pathname, pathlen, CGETS(23, 23,
1315 "getcwd: Cannot stat \"/\" (%s)"),
1316 strerror(errno));
1317 return NULL;
1319 pathbuf[MAXPATHLEN - 1] = '\0';
1320 pathptr = &pathbuf[MAXPATHLEN - 1];
1321 nextpathbuf[MAXPATHLEN - 1] = '\0';
1322 cur_name_add = nextpathptr = &nextpathbuf[MAXPATHLEN - 1];
1324 /* find the inode of the current directory */
1325 if (lstat(".", &st_cur) == -1) {
1326 (void) xsnprintf(pathname, pathlen, CGETS(23, 24,
1327 "getcwd: Cannot stat \".\" (%s)"),
1328 strerror(errno));
1329 return NULL;
1331 nextpathptr = strnrcpy(nextpathptr, "../", nextpathptr - nextpathbuf);
1333 /* Descend to root */
1334 for (;;) {
1336 /* look if we found root yet */
1337 if (st_cur.st_ino == st_root.st_ino &&
1338 DEV_DEV_COMPARE(st_cur.st_dev, st_root.st_dev)) {
1339 (void) strncpy(pathname, *pathptr != '/' ? "/" : pathptr, pathlen);
1340 pathname[pathlen - 1] = '\0';
1341 return pathname;
1344 /* open the parent directory */
1345 if (stat(nextpathptr, &st_dotdot) == -1) {
1346 (void) xsnprintf(pathname, pathlen, CGETS(23, 25,
1347 "getcwd: Cannot stat directory \"%s\" (%s)"),
1348 nextpathptr, strerror(errno));
1349 return NULL;
1351 if ((dp = opendir(nextpathptr)) == NULL) {
1352 (void) xsnprintf(pathname, pathlen, CGETS(23, 26,
1353 "getcwd: Cannot open directory \"%s\" (%s)"),
1354 nextpathptr, strerror(errno));
1355 return NULL;
1358 /* look in the parent for the entry with the same inode */
1359 if (DEV_DEV_COMPARE(st_dotdot.st_dev, st_cur.st_dev)) {
1360 /* Parent has same device. No need to stat every member */
1361 for (d = readdir(dp); d != NULL; d = readdir(dp)) {
1362 #ifdef __clipper__
1363 if (((unsigned long)d->d_ino & 0xffff) == st_cur.st_ino)
1364 break;
1365 #else
1366 if (d->d_ino == st_cur.st_ino)
1367 break;
1368 #endif
1371 else {
1373 * Parent has a different device. This is a mount point so we
1374 * need to stat every member
1376 for (d = readdir(dp); d != NULL; d = readdir(dp)) {
1377 if (ISDOT(d->d_name) || ISDOTDOT(d->d_name))
1378 continue;
1379 (void)strncpy(cur_name_add, d->d_name,
1380 (size_t) (&nextpathbuf[sizeof(nextpathbuf) - 1] - cur_name_add));
1381 if (lstat(nextpathptr, &st_next) == -1) {
1383 * We might not be able to stat() some path components
1384 * if we are using afs, but this is not an error as
1385 * long as we find the one we need; we also save the
1386 * first error to report it if we don't finally succeed.
1388 if (save_errno == 0)
1389 save_errno = errno;
1390 continue;
1392 /* check if we found it yet */
1393 if (st_next.st_ino == st_cur.st_ino &&
1394 DEV_DEV_COMPARE(st_next.st_dev, st_cur.st_dev))
1395 break;
1398 if (d == NULL) {
1399 (void) xsnprintf(pathname, pathlen, CGETS(23, 27,
1400 "getcwd: Cannot find \".\" in \"..\" (%s)"),
1401 strerror(save_errno ? save_errno : ENOENT));
1402 closedir(dp);
1403 return NULL;
1405 else
1406 save_errno = 0;
1407 st_cur = st_dotdot;
1408 pathptr = strnrcpy(pathptr, d->d_name, pathptr - pathbuf);
1409 pathptr = strnrcpy(pathptr, "/", pathptr - pathbuf);
1410 nextpathptr = strnrcpy(nextpathptr, "../", nextpathptr - nextpathbuf);
1411 *cur_name_add = '\0';
1412 closedir(dp);
1414 } /* end getcwd */
1415 # endif /* hp9000s500 */
1417 /* strnrcpy():
1418 * Like strncpy, going backwards and returning the new pointer
1420 static char *
1421 strnrcpy(char *ptr, char *str, size_t siz)
1423 int len = strlen(str);
1424 if (siz == 0)
1425 return ptr;
1427 while (len && siz--)
1428 *--ptr = str[--len];
1430 return (ptr);
1431 } /* end strnrcpy */
1432 #endif /* !HAVE_GETCWD */
1434 #ifdef apollo
1435 /***
1436 *** Domain/OS
1437 ***/
1438 #include <apollo/base.h>
1439 #include <apollo/loader.h>
1440 #include <apollo/error.h>
1443 static char *
1444 apperr(status_$t *st)
1446 static char *buf; /* = NULL */
1447 short e_subl, e_modl, e_codel;
1448 error_$string_t e_sub, e_mod, e_code;
1450 error_$get_text(*st, e_sub, &e_subl, e_mod, &e_modl, e_code, &e_codel);
1451 e_sub[e_subl] = '\0';
1452 e_code[e_codel] = '\0';
1453 e_mod[e_modl] = '\0';
1454 xfree(buf);
1455 buf = xasprintf("%s (%s/%s)", e_code, e_sub, e_mod);
1457 return(buf);
1460 static int
1461 llib(Char *s)
1463 short len = Strlen(s);
1464 status_$t st;
1465 char *t;
1467 loader_$inlib(t = short2str(s), len, &st);
1468 if (st.all != status_$ok)
1469 stderror(ERR_SYSTEM, t, apperr(&st));
1472 /*ARGSUSED*/
1473 void
1474 doinlib(Char **v, struct command *c)
1476 Char **globbed;
1478 setname(short2str(*v++));
1479 v = glob_all_or_error(v);
1480 globbed = v;
1481 cleanup_push(globbed, blk_cleanup);
1483 while (v && *v)
1484 llib(*v++);
1485 cleanup_until(globbed);
1489 getv(Char *v)
1491 if (eq(v, STRbsd43))
1492 return(1);
1493 else if (eq(v, STRsys53))
1494 return(0);
1495 else
1496 stderror(ERR_NAME | ERR_SYSTEM, short2str(v),
1497 CGETS(23, 28, "Invalid system type"));
1498 /*NOTREACHED*/
1499 return(0);
1502 /*ARGSUSED*/
1503 void
1504 dover(Char **v, struct command *c)
1506 Char *p;
1508 setname(short2str(*v++));
1509 if (!*v) {
1510 if (!(p = tgetenv(STRSYSTYPE)))
1511 stderror(ERR_NAME | ERR_STRING,
1512 CGETS(23, 29, "System type is not set"));
1513 xprintf("%S\n", p);
1515 else {
1516 tsetenv(STRSYSTYPE, getv(*v) ? STRbsd43 : STRsys53);
1517 dohash(NULL, NULL);
1522 * Many thanks to rees@citi.umich.edu (Jim Rees) and
1523 * mathys@ssdt-tempe.sps.mot.com (Yves Mathys)
1524 * For figuring out how to do this... I could have never done
1525 * it without their help.
1527 typedef short enum {
1528 name_$wdir_type,
1529 name_$ndir_type,
1530 name_$node_dir_type,
1531 } name_$dir_type_t;
1533 /*ARGSUSED*/
1534 void
1535 dorootnode(Char **v, struct command *c)
1537 name_$dir_type_t dirtype = name_$node_dir_type;
1538 uid_$t uid;
1539 status_$t st;
1540 char *name;
1541 short namelen;
1543 setname(short2str(*v++));
1545 name = short2str(*v);
1546 namelen = strlen(name);
1548 name_$resolve(name, &namelen, &uid, &st);
1549 if (st.all != status_$ok)
1550 stderror(ERR_SYSTEM, name, apperr(&st));
1551 namelen = 0;
1552 name_$set_diru(&uid, "", &namelen, &dirtype, &st);
1553 if (st.all != status_$ok)
1554 stderror(ERR_SYSTEM, name, apperr(&st));
1555 dohash(NULL, NULL);
1559 isapad(void)
1561 static int res = -1;
1562 static status_$t st;
1564 if (res == -1) {
1565 int strm;
1566 if (isatty(0))
1567 strm = 0;
1568 if (isatty(1))
1569 strm = 1;
1570 if (isatty(2))
1571 strm = 2;
1572 else {
1573 res = 0;
1574 st.all = status_$ok;
1575 return(res);
1577 res = stream_$isavt(&strm, &st);
1578 res = res ? 1 : 0;
1580 else {
1581 if (st.all != status_$ok)
1582 stderror(ERR_SYSTEM, "stream_$isavt", apperr(&st));
1584 return(res);
1586 #endif