PageRenderTime 120ms CodeModel.GetById 42ms app.highlight 67ms RepoModel.GetById 1ms app.codeStats 0ms

/contrib/tcsh/tc.os.c

https://bitbucket.org/freebsd/freebsd-head/
C | 1625 lines | 1258 code | 174 blank | 193 comment | 329 complexity | a2e35aff151242cb121a62121c7d4c32 MD5 | raw file
   1/* $Header: /p/tcsh/cvsroot/tcsh/tc.os.c,v 3.72 2011/01/25 13:58:19 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
  35RCSID("$tcsh: tc.os.c,v 3.72 2011/01/25 13:58:19 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
  64static Char STRCPATH[] = {'C', 'P', 'A', 'T', 'H', '\0'};
  65static Char STRLPATH[] = {'L', 'P', 'A', 'T', 'H', '\0'};
  66static Char STRMPATH[] = {'M', 'P', 'A', 'T', 'H', '\0'};
  67# if EPATH
  68static Char STREPATH[] = {'E', 'P', 'A', 'T', 'H', '\0'};
  69# endif
  70#endif /* MACH */
  71static Char *syspaths[] = {STRKPATH, STRCPATH, STRLPATH, STRMPATH, 
  72
  73#if EPATH
  74	STREPATH,
  75#endif
  76	 0};
  77#define LOCALSYSPATH	"/usr/local"
  78
  79/*ARGSUSED*/
  80void
  81dosetpath(Char **arglist, struct command *c)
  82{
  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;
  89
  90    pintr_disabled++;
  91    cleanup_push(&pintr_disabled, disabled_cleanup);
  92
  93    /*
  94     * setpath(3) uses stdio and we want 0, 1, 2 to work...
  95     */
  96    if (!didfds) {
  97	(void) dcopy(SHIN, 0);
  98	(void) dcopy(SHOUT, 1);
  99	(void) dcopy(SHDIAG, 2);
 100	didfds = 1;
 101    }
 102
 103    for (i = 1; arglist[i] && (arglist[i][0] != '-'); i++);
 104    npaths = i - 1;
 105
 106    cmdargs = &arglist[i];
 107    for (; arglist[i]; i++);
 108    ncmds = i - npaths - 1;
 109
 110    if (npaths) {
 111	sysflag = 0;
 112	pathvars = &arglist[1];
 113    }
 114    else {
 115	sysflag = 1;
 116	npaths = (sizeof syspaths / sizeof *syspaths) - 1;
 117	pathvars = syspaths;
 118    }
 119
 120    /* note that npaths != 0 */
 121
 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]));
 130
 131	if (val == NULL)
 132	    val = "";
 133
 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];
 140    }
 141
 142    for (i = 0; i < ncmds; i++) {
 143	Char   *val = globone(cmdargs[i], G_ERROR);/*FIXRESET*/
 144
 145	if (val == NULL)
 146	    goto abortpath;
 147	cmds[i] = strsave(short2str(val));
 148    }
 149
 150
 151    if (setpath(cpaths, cmds, LOCALSYSPATH, sysflag, 1) < 0) {
 152abortpath:
 153	if (spaths) {
 154	    for (i = 0; i < npaths; i++)
 155		xfree(spaths[i]);
 156	    xfree(spaths);
 157	}
 158	xfree(cpaths);
 159	if (cmds) {
 160	    for (i = 0; i < ncmds; i++)
 161		xfree(cmds[i]);
 162	    xfree(cmds);
 163	}
 164
 165	cleanup_until(&pintr_disabled);
 166	donefds();
 167	return;
 168    }
 169
 170    for (i = 0; i < npaths; i++) {
 171	Char	*val, *name;
 172
 173	name = str2short(cpaths[i]);
 174	for (val = str2short(cpaths[i]); val && *val && *val != '='; val++);
 175	if (val && *val == '=') {
 176	    *val++ = '\0';
 177
 178	    tsetenv(name, val);/*FIXRESET*/
 179	    if (Strcmp(name, STRKPATH) == 0) {
 180		importpath(val);/*FIXRESET*/
 181		if (havhash)
 182		    dohash(NULL, NULL);/*FIXRESET*/
 183	    }
 184	    *--val = '=';
 185	}
 186    }
 187    cleanup_until(&pintr_disabled);
 188    donefds();
 189}
 190#endif /* MACH */
 191
 192/***
 193 *** AIX
 194 ***/
 195#ifdef TCF
 196/* ARGSUSED */
 197void
 198dogetxvers(Char **v, struct command *c)
 199{
 200    char    xvers[MAXPATHLEN];
 201
 202    if (getxvers(xvers, MAXPATHLEN) == -1)
 203	stderror(ERR_SYSTEM, "getxvers", strerror(errno));
 204    xprintf("%s\n", xvers);
 205    flush();
 206}
 207
 208/*ARGSUSED*/
 209void
 210dosetxvers(Char **v, struct command *c)
 211{
 212    char   *xvers;
 213
 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));
 221}
 222
 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 */
 239
 240static struct xc_cpu_t {
 241    short   xc_id;
 242    char   *xc_name;
 243}       xcpu[] =
 244{
 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      }
 257};
 258
 259/*
 260 * our local hack table, stolen from x.out.h
 261 */
 262static char *
 263getxcode(short xcid)
 264{
 265    int     i;
 266
 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);
 271}
 272
 273static short
 274getxid(char *xcname)
 275{
 276    int     i;
 277
 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);
 282}
 283
 284
 285/*ARGSUSED*/
 286void
 287dogetspath(Char **v, struct command *c)
 288{
 289    int     i, j;
 290    sitepath_t p[MAXSITE];
 291    struct sf *st;
 292    static char *local = "LOCAL ";
 293
 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);
 304
 305		if (xc != NULL)
 306		    xprintf("%s ", xc);
 307		else
 308		    xprintf("*cpu %d* ", (int) (p[i] & SPATH_MASK));
 309		/* 
 310		 * BUG in the aix code... needs that cause if
 311		 * sfxcode fails once it fails for ever 
 312		 */
 313		endsf();	
 314	    }
 315	}
 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));
 323	}
 324    }
 325    xputchar('\n');
 326    flush();
 327}
 328
 329/*ARGSUSED*/
 330void
 331dosetspath(Char **v, struct command *c)
 332{
 333    int     i;
 334    short   j;
 335    char   *s;
 336    sitepath_t p[MAXSITE];
 337    struct sf *st;
 338
 339    /*
 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 :-)
 345     */
 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"));
 362	}
 363	if (i == MAXSITE - 1)
 364	    stderror(ERR_NAME | ERR_STRING, CGETS(23, 2, "Site path too long"));
 365    }
 366    if (setspath(p, i) == -1)
 367	stderror(ERR_SYSTEM, "setspath", strerror(errno));
 368    dont_free = 0;
 369}
 370
 371/* sitename():
 372 *	Return the site name where the process is running
 373 */
 374char   *
 375sitename(pid_t pid)
 376{
 377    siteno_t ss;
 378    struct sf *st;
 379
 380    if ((ss = site(pid)) == -1 || (st = sfnum(ss)) == NULL)
 381	return CGETS(23, 3, "unknown");
 382    else
 383	return st->sf_sname;
 384}
 385
 386static int
 387migratepid(pit_t pid, siteno_t new_site)
 388{
 389    struct sf *st;
 390    int     need_local;
 391
 392    need_local = (pid == 0) || (pid == getpid());
 393
 394    if (kill3(pid, SIGMIGRATE, new_site) < 0) {
 395	xprintf("%d: %s\n", pid, strerror(errno));
 396	return (-1);
 397    }
 398
 399    if (need_local) {
 400	if ((new_site = site(0)) == -1) {
 401	    xprintf(CGETS(23, 4, "site: %s\n"), strerror(errno));
 402	    return (-1);
 403	}
 404	if ((st = sfnum(new_site)) == NULL) {
 405	    xprintf(CGETS(23, 5, "%d: Site not found\n"), new_site);
 406	    return (-1);
 407	}
 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);
 412	}
 413    }
 414    return (0);
 415}
 416
 417/*ARGSUSED*/
 418void
 419domigrate(Char **v, struct command *c)
 420{
 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;
 428
 429    pchild_disabled++;
 430    cleanup_push(&pchild_disabled, disabled_cleanup);
 431    if (setintr) {
 432	pintr_disabled++;
 433	cleanup_push(&pintr_disabled, disabled_cleanup);
 434    }
 435
 436    ++v;
 437    if (*v[0] == '-') {
 438	/*
 439	 * Do the -site.
 440	 */
 441	s = short2str(&v[0][1]);
 442	/*
 443	 * see comment in setspath()
 444	 */
 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"));
 450	}
 451	dont_free = 0;
 452	new_site = st->sf_id;
 453	++v;
 454    }
 455
 456    if (!*v || *v[0] == '\0') {
 457	if (migratepid(0, new_site) == -1)
 458	    err1++;
 459    }
 460    else {
 461	Char **globbed;
 462
 463	v = glob_all_or_error(v);
 464	globbed = v;
 465	cleanup_push(globbed, blk_cleanup);
 466
 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++;
 473		}
 474	    }
 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++;
 481	    }
 482	    v++;
 483	}
 484	cleanup_until(globbed);
 485    }
 486
 487done:
 488    cleanup_until(&pchild_disabled);
 489    if (err1)
 490	stderror(ERR_SILENT);
 491}
 492
 493#endif /* TCF */
 494
 495/***
 496 *** CRAY ddmode <velo@sesun3.epfl.ch> (Martin Ouwehand EPFL-SIC/SE)
 497 ***/
 498#if defined(_CRAY) && !defined(_CRAYMPP)
 499void
 500dodmmode(Char **v, struct command *c)
 501{
 502    Char *cp = v[1];
 503
 504    USE(c);
 505
 506    if ( !cp ) {
 507	int mode;
 508
 509	mode = dmmode(0);
 510	dmmode(mode);
 511	xprintf("%d\n",mode);
 512    }
 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"));
 528	    }
 529    }
 530}
 531#endif /* _CRAY && !_CRAYMPP */
 532
 533
 534/***
 535 *** CONVEX Warps.
 536 ***/
 537
 538#ifdef WARP
 539/*
 540 * handle the funky warping of symlinks
 541 */
 542#include <warpdb.h>
 543#include <sys/warp.h>
 544
 545static jmp_buf sigsys_buf;
 546
 547static void
 548catch_sigsys(void)
 549{
 550    sigset_t set;
 551    sigemptyset(&set, SIGSYS);
 552    (void)sigprocmask(SIG_UNBLOCK, &set, NULL);
 553    longjmp(sigsys_buf, 1);
 554}
 555
 556
 557/*ARGSUSED*/
 558void
 559dowarp(Char **v, struct command *c) 
 560{
 561    int     warp, oldwarp;
 562    struct warpent *we;
 563    volatile struct sigaction old_sigsys_handler;
 564    char   *newwarp;
 565
 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;
 571    }
 572    sigaction(SIGSYS, NULL, &old_sigsys_handler);
 573    signal(SIGSYS, catch_sigsys);
 574
 575    warp = getwarp();
 576
 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);
 586    }
 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;
 598	}
 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"));
 604	}
 605    }
 606    sigaction(SIGSYS, &old_sigsys_handler, NULL);
 607}
 608#endif /* WARP */
 609
 610/***
 611 *** Masscomp or HCX
 612 ***/
 613/* Added, DAS DEC-90. */
 614#if defined(masscomp) || defined(_CX_UX)
 615static void
 616setuniverse_cleanup(void *xbuf)
 617{
 618    char *buf;
 619
 620    buf = xbuf;
 621    setuniverse(buf);
 622}
 623
 624/*ARGSUSED*/
 625void
 626douniverse(Char **v, struct command *c) 
 627{
 628    Char *cp = v[1];
 629    Char *cp2;		/* dunno how many elements v comes in with */
 630    char    ubuf[100];
 631
 632    if (cp == 0) {
 633	(void) getuniverse(ubuf);
 634	xprintf("%s\n", ubuf);
 635    }
 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"));
 641	    }
 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);
 650	    }
 651	    lshift(v, 2);
 652	    if (setintr)
 653		cleanup_until(&pintr_disabled);
 654	    reexecute(c);
 655	    cleanup_until(ubuf);
 656	}
 657    }
 658}
 659#endif /* masscomp || _CX_UX */
 660
 661/***
 662 *** BS2000/OSD POSIX (Fujitsu Siemens Computers)
 663 ***/
 664#if defined(_OSD_POSIX)
 665static int
 666bs2upcase(char *str)
 667{
 668    enum { outside = ' ', singlequote='\'', doublequote='"'} string = outside;
 669
 670    char *white;
 671
 672    for (white = str + strlen(str) - 1; isspace(*white) && white > str; --white)
 673        *white = '\0';
 674
 675    for (; *str != '\0'; ++str)
 676    {
 677        if (string == outside)
 678        {
 679            *str = toupper (*str);
 680        }
 681        if (*str == '\'')
 682        {
 683            if (string == outside)
 684                string = singlequote;
 685            else if (string != doublequote)
 686                string = outside;
 687        }
 688        else if (*str == '"')
 689        {
 690            if (string == outside)
 691                string = doublequote;
 692            else if (string != singlequote)
 693                string = outside;
 694        }
 695    }
 696    if (string != outside)
 697    {
 698        stderror(ERR_NAME | ERR_UNMATCHED, (Char) string);
 699        return 1;
 700    }
 701    return 0;
 702}
 703static int
 704bs2cmdlist(char *str)
 705{
 706    char *str_beg = NULL;
 707    int ret = 0;
 708
 709    enum { outside = ' ', singlequote='\'', doublequote='"'} string = outside;
 710
 711    while (*str != '\0')
 712    {
 713        while (isspace(*str))
 714            ++str;
 715
 716        if (*str == '\0')
 717            break;
 718
 719        str_beg = str;
 720        
 721        for (; *str != '\0'; ++str)
 722        {
 723            if (string == outside && *str == ';') /* End of command */
 724            {
 725                *str++ = '\0';
 726                break;    /* continue with next command */
 727            }
 728            if (*str == '\'')
 729            {
 730                if (string == outside)
 731                    string = singlequote;
 732                else if (string != doublequote)
 733                    string = outside;
 734            }
 735            else if (*str == '"')
 736            {
 737                if (string == outside)
 738                    string = doublequote;
 739                else if (string != singlequote)
 740                    string = outside;
 741            }
 742        }
 743        if (strlen(str_beg) != 0)
 744        {
 745            ret = bs2system(str_beg);
 746	    flush();
 747            if (ret != 0 /*&& !option.err_ignore*/)
 748                break; /* do not continue after errors */
 749        }
 750    }
 751
 752    if (string != outside)
 753    {
 754        stderror(ERR_NAME | ERR_UNMATCHED, (Char) string);
 755        return -1;
 756    }
 757
 758    return ret;
 759}
 760/*ARGSUSED*/
 761void
 762dobs2cmd(Char **v, struct command *c)
 763{
 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' };
 773
 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);
 782
 783    /* First round: count the string lengths */
 784    for (i=0; v[i]; ++i) {
 785	len += Strlen(v[i]) + (v[i+1] != NULL);
 786    }
 787
 788    cmd = xmalloc(len+1); /* 1 for the final '\0' *//* FIXME: memory leak? */
 789
 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++] = ' ';
 798    }
 799    cmd[i] = '\0';
 800
 801    /* Make upper case */
 802    bs2upcase(cmd);
 803
 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;
 812
 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));
 836    }
 837    cleanup_until(&pvec[1]);
 838    for(;;) {
 839	int old_pintr_disabled;
 840
 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]);
 850    }
 851    cleanup_until(&pvec[0]);
 852    pwait();
 853
 854    flush();
 855
 856    cleanup_until(globbed);
 857}
 858#endif /* _OSD_POSIX */
 859
 860#if defined(_CX_UX)
 861static void
 862setuniverse_cleanup(void *xbuf)
 863{
 864    char *buf;
 865
 866    buf = xbuf;
 867    setuniverse(buf);
 868}
 869
 870/*ARGSUSED*/
 871void
 872doatt(Char **v, struct command *c)
 873{
 874    Char *cp = v[1];
 875    char    ubuf[100];
 876
 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);
 886	}
 887	lshift(v, 1);
 888	if (setintr)
 889	    cleanup_until(&pintr_disabled);
 890	reexecute(c);
 891	cleanup_until(ubuf);
 892    }
 893}
 894
 895/*ARGSUSED*/
 896void
 897doucb(Char **v, struct command *c)
 898{
 899    Char *cp = v[1];
 900    char    ubuf[100];
 901
 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);
 911	}
 912	lshift(v, 1);
 913	if (setintr)
 914	    cleanup_until(&pintr_disabled);
 915	reexecute(c);
 916	cleanup_until(ubuf);
 917    }
 918}
 919#endif /* _CX_UX */
 920
 921#ifdef _SEQUENT_
 922/*
 923 * Compute the difference in process stats.
 924 */
 925void
 926pr_stat_sub(struct process_stats *p2, struct process_stats *p1,
 927	    struct process_stats *pr)
 928{
 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;
 934    }
 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;
 940    }
 941
 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;
 959}
 960
 961#endif /* _SEQUENT_ */
 962
 963
 964#ifndef HAVE_MEMSET
 965/* This is a replacement for a missing memset function */
 966void *xmemset(void *loc, int value, size_t len)
 967{
 968    char *ptr = loc;
 969
 970    while (len--)
 971	*ptr++ = value;
 972    return loc;
 973}
 974#endif /* !HAVE_MEMSET */
 975
 976
 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
 982 */
 983void *
 984xmemmove(void *vdst, const void *vsrc, size_t len)
 985{
 986    const char *src = vsrc;
 987    char *dst = vdst;
 988
 989    if (src == dst)
 990	return vdst;
 991
 992    if (src > dst) {
 993	while (len--) 
 994	    *dst++ = *src++;
 995    }
 996    else {
 997	src += len;
 998	dst += len;
 999	while (len--) 
1000	    *--dst = *--src;
1001    }
1002    return vdst;
1003}
1004#endif /* HAVE_MEMMOVE */
1005
1006
1007#ifndef WINNT_NATIVE
1008#ifdef NEEDtcgetpgrp
1009pid_t
1010xtcgetpgrp(int fd)
1011{
1012    int     pgrp;
1013
1014    /* ioctl will handle setting errno correctly. */
1015    if (ioctl(fd, TIOCGPGRP, (ioctl_t) & pgrp) < 0)
1016	return (-1);
1017    return (pgrp);
1018}
1019
1020/*
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.
1025 */
1026int
1027xtcsetpgrp(int fd, int pgrp)
1028{
1029    return ioctl(fd, TIOCSPGRP, (ioctl_t) &pgrp);
1030}
1031
1032#endif	/* NEEDtcgetpgrp */
1033#endif /* WINNT_NATIVE */
1034
1035
1036#ifdef YPBUGS
1037void
1038fix_yp_bugs(void)
1039{
1040    char   *mydomain;
1041
1042    extern int yp_get_default_domain (char **);
1043    /*
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.)
1047     */
1048    if (yp_get_default_domain(&mydomain) == 0) {	/* if we got a name */
1049	extern void yp_unbind (const char *);
1050
1051	yp_unbind(mydomain);
1052    }
1053}
1054
1055#endif /* YPBUGS */
1056
1057#ifdef STRCOLLBUG
1058void
1059fix_strcoll_bug(void)
1060{
1061#if defined(NLS) && defined(HAVE_STRCOLL)
1062    /*
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...
1067     *
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.
1074     */
1075    int fd = -1;
1076    static char *root = "/";
1077
1078    if (!didfds)
1079	fd = xopen(root, O_RDONLY|O_LARGEFILE);
1080
1081    (void) strcoll(root, root);
1082
1083    if (fd != -1)
1084	xclose(fd);
1085#endif
1086}
1087#endif /* STRCOLLBUG */
1088
1089
1090#ifdef OREO
1091#include <compat.h>
1092#endif /* OREO */
1093
1094void
1095osinit(void)
1096{
1097#ifdef OREO
1098    set42sig();
1099    setcompat(getcompat() & ~COMPAT_EXEC);
1100    signal(SIGIO, SIG_IGN);		/* ignore SIGIO */
1101#endif /* OREO */
1102
1103#ifdef aiws
1104    {
1105	struct sigstack inst;
1106	inst.ss_sp = xmalloc(4192) + 4192;
1107	inst.ss_onstack = 0;
1108	sigstack(&inst, NULL);
1109    }
1110#endif /* aiws */
1111
1112#ifdef apollo
1113    (void) isapad();
1114#endif
1115
1116#ifdef _SX
1117    /* 
1118     * kill(SIGCONT) problems, don't know what this syscall does
1119     * [schott@rzg.mpg.de]
1120     */
1121    syscall(151, getpid(), getpid());
1122#endif /* _SX */
1123}
1124
1125#ifndef HAVE_STRERROR
1126extern int sys_nerr;
1127extern char *sys_errlist[];
1128char *
1129xstrerror(int i)
1130{
1131    if (i >= 0 && i < sys_nerr) {
1132	return sys_errlist[i];
1133    } else {
1134	static char *errbuf; /* = NULL; */
1135
1136	xfree(errbuf);
1137	errbuf = xasprintf(CGETS(23, 13, "Unknown Error: %d"), i);
1138	return errbuf;
1139    }
1140}
1141#endif /* !HAVE_STRERROR */
1142    
1143#ifndef HAVE_GETHOSTNAME
1144# if !defined(_MINIX) && !defined(__EMX__) && !defined(WINNT_NATIVE)
1145#  include <sys/utsname.h>
1146# endif /* !_MINIX && !__EMX__ && !WINNT_NATIVE */
1147
1148int
1149xgethostname(char *name, int namlen)
1150{
1151# if !defined(_MINIX) && !defined(__EMX__) && !defined(WINNT_NATIVE)
1152    int     i, retval;
1153    struct utsname uts;
1154
1155    retval = uname(&uts);
1156
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);
1166
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';
1176    }
1177    return(0);
1178#endif /* _MINIX && !__EMX__ */
1179} /* end xgethostname */
1180#endif /* !HAVE_GETHOSTNAME */
1181
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 */
1189int 
1190xnice(int incr)
1191{
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 */
1199
1200#ifndef HAVE_GETCWD
1201static char *strnrcpy (char *, char *, size_t);
1202
1203/* xgetcwd():
1204 *	Return the pathname of the current directory, or return
1205 *	an error message in pathname.
1206 */
1207
1208# ifdef hp9000s500
1209/*
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 ".." !!!
1218 */
1219char *
1220xgetcwd(char *pathname, size_t pathlen)
1221{
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;
1231
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;
1242	}
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;
1249	}
1250	if (chdir("..") == -1) {
1251	    (void) xsnprintf(pathname, pathlen, CGETS(23, 20,
1252		"getcwd: Cannot chdir to \"..\" (%s)"), strerror(errno));
1253	    goto fail;
1254	}
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;
1261	    }
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;
1267	    }
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);
1275    }
1276
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;
1287	}
1288    }
1289    return pathname;
1290
1291fail:
1292    serrno = errno;
1293    (void) chdir(strnrcpy(".", pnptr, pnptr - pathbuf));
1294    errno = serrno;
1295    return NULL;
1296}
1297
1298# else /* ! hp9000s500 */
1299
1300
1301char *
1302xgetcwd(char *pathname, size_t pathlen)
1303{
1304    DIR    *dp;
1305    struct dirent *d;
1306
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;
1311
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;
1318    }
1319    pathbuf[MAXPATHLEN - 1] = '\0';
1320    pathptr = &pathbuf[MAXPATHLEN - 1];
1321    nextpathbuf[MAXPATHLEN - 1] = '\0';
1322    cur_name_add = nextpathptr = &nextpathbuf[MAXPATHLEN - 1];
1323
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;
1330    }
1331    nextpathptr = strnrcpy(nextpathptr, "../", nextpathptr - nextpathbuf);
1332
1333    /* Descend to root */
1334    for (;;) {
1335
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;
1342	}
1343
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;
1350	}
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;
1356	}
1357
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
1369	    }
1370	}
1371	else {
1372	    /* 
1373	     * Parent has a different device. This is a mount point so we 
1374	     * need to stat every member 
1375	     */
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) {
1382		    /*
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.
1387		     */
1388		    if (save_errno == 0)
1389			save_errno = errno;
1390		    continue;
1391		}
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;
1396	    }
1397	}
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;
1404	}
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);
1413    }
1414} /* end getcwd */
1415# endif /* hp9000s500 */
1416
1417/* strnrcpy():
1418 *	Like strncpy, going backwards and returning the new pointer
1419 */
1420static char *
1421strnrcpy(char *ptr, char *str, size_t siz)
1422{
1423    int len = strlen(str);
1424    if (siz == 0)
1425	return ptr;
1426
1427    while (len && siz--)
1428	*--ptr = str[--len];
1429
1430    return (ptr);
1431} /* end strnrcpy */
1432#endif /* !HAVE_GETCWD */
1433
1434#ifdef apollo
1435/***
1436 *** Domain/OS
1437 ***/
1438#include <apollo/base.h>
1439#include <apollo/loader.h>
1440#include <apollo/error.h>
1441
1442
1443static char *
1444apperr(status_$t *st)
1445{
1446    static char *buf; /* = NULL */
1447    short e_subl, e_modl, e_codel;
1448    error_$string_t e_sub, e_mod, e_code;
1449
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);
1456
1457    return(buf);
1458}
1459
1460static int
1461llib(Char *s)
1462{
1463    short len = Strlen(s);
1464    status_$t st;
1465    char *t;
1466
1467    loader_$inlib(t = short2str(s), len, &st);
1468    if (st.all != status_$ok) 
1469	stderror(ERR_SYSTEM, t, apperr(&st));
1470}
1471
1472/*ARGSUSED*/
1473void
1474doinlib(Char **v, struct command *c)
1475{
1476    Char **globbed;
1477
1478    setname(short2str(*v++));
1479    v = glob_all_or_error(v);
1480    globbed = v;
1481    cleanup_push(globbed, blk_cleanup);
1482
1483    while (v && *v) 
1484	llib(*v++);
1485    cleanup_until(globbed);
1486}
1487
1488int
1489getv(Char *v)
1490{
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);
1500}
1501
1502/*ARGSUSED*/
1503void
1504dover(Char **v, struct command *c)
1505{
1506    Char *p;
1507
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);
1514    }
1515    else {
1516	tsetenv(STRSYSTYPE, getv(*v) ? STRbsd43 : STRsys53);
1517	dohash(NULL, NULL);
1518    }
1519}
1520
1521/*
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.
1526 */
1527typedef short enum {
1528	name_$wdir_type,
1529	name_$ndir_type,
1530	name_$node_dir_type,
1531} name_$dir_type_t;
1532
1533/*ARGSUSED*/
1534void
1535dorootnode(Char **v, struct command *c)
1536{
1537    name_$dir_type_t dirtype = name_$node_dir_type;
1538    uid_$t uid;
1539    status_$t st;
1540    char *name;
1541    short namelen;
1542
1543    setname(short2str(*v++));
1544
1545    name = short2str(*v);
1546    namelen = strlen(name);
1547
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);
1556}
1557
1558int
1559isapad(void)
1560{
1561    static int res = -1;
1562    static status_$t st;
1563
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);
1576	}
1577	res = stream_$isavt(&strm, &st);
1578	res = res ? 1 : 0;
1579    }
1580    else {
1581	if (st.all != status_$ok) 
1582	    stderror(ERR_SYSTEM, "stream_$isavt", apperr(&st));
1583    }
1584    return(res);
1585}
1586#endif
1587
1588#ifdef __ANDROID__
1589#include <stdio.h>
1590/* Android (<= 2.1?) has an incomplete ttyname implementation. */
1591char *
1592ttyname(int fd)
1593{
1594    char path[64];
1595    ssize_t siz;
1596    static char ttyname[32];
1597
1598    if (!isatty(fd))
1599	return NULL;
1600
1601    (void)snprintf(path, sizeof(path), "/proc/self/fd/%d", fd);
1602    siz = readlink(path, ttyname, sizeof(ttyname));
1603    if (siz < 0 || siz == sizeof(ttyname))
1604	return NULL;
1605    ttyname[siz] = '\0';
1606    return ttyname;
1607}
1608#endif /* __ANDROID__ */
1609
1610#if defined(__CYGWIN__) && !defined(NO_CRYPT)
1611#undef CHAR		/* Collides with Win32 API */
1612#define WIN32_LEAN_AND_MEAN
1613#include <windows.h>
1614#include <sys/cygwin.h>
1615char *
1616cygwin_xcrypt(struct passwd *pw, const char *password, const char *expected_pwd)
1617{
1618    static char invalid_password[] = "\377";
1619    HANDLE token = cygwin_logon_user(pw, password);
1620    if (token == INVALID_HANDLE_VALUE)
1621	return invalid_password;
1622    CloseHandle(token);
1623    return (char *) expected_pwd;
1624}
1625#endif /* __CYGWIN__ && !NO_CRYPT */