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