tc.os.c revision 131962
1/* $Header: /src/pub/tcsh/tc.os.c,v 3.55 2004/02/21 20:34:25 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("$Id: tc.os.c,v 3.55 2004/02/21 20:34:25 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(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) {
155abortpath:
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 */
203void
204dogetxvers(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*/
217void
218dosetxvers(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
250static 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 */
272static char *
273getxcode(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
284static short
285getxid(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*/
298void
299dogetspath(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*/
344void
345dosetspath(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 */
390char   *
391sitename(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
403static int
404migratepid(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*/
437void
438domigrate(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
518done:
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)
536void
537dodmmode(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
584static jmp_buf sigsys_buf;
585
586static  sigret_t
587catch_sigsys()
588{
589    longjmp(sigsys_buf, 1);
590}
591
592
593/*ARGSUSED*/
594void
595dowarp(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*/
654void
655douniverse(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/***
701 *** BS2000/OSD POSIX (Fujitsu Siemens Computers)
702 ***/
703#if defined(_OSD_POSIX)
704static int
705bs2upcase(char *str)
706{
707    enum { outside = ' ', singlequote='\'', doublequote='"'} string = outside;
708
709    char *white;
710
711    for (white = str + strlen(str) - 1; isspace(*white) && white > str; --white)
712        *white = '\0';
713
714    for (; *str != '\0'; ++str)
715    {
716        if (string == outside)
717        {
718            *str = toupper (*str);
719        }
720        if (*str == '\'')
721        {
722            if (string == outside)
723                string = singlequote;
724            else if (string != doublequote)
725                string = outside;
726        }
727        else if (*str == '"')
728        {
729            if (string == outside)
730                string = doublequote;
731            else if (string != singlequote)
732                string = outside;
733        }
734    }
735    if (string != outside)
736    {
737        stderror(ERR_NAME | ERR_UNMATCHED, (Char) string);
738        return 1;
739    }
740    return 0;
741}
742static int
743bs2cmdlist(char *str)
744{
745    char *str_beg = NULL;
746    int ret = 0;
747
748    enum { outside = ' ', singlequote='\'', doublequote='"'} string = outside;
749
750    while (*str != '\0')
751    {
752        while (isspace(*str))
753            ++str;
754
755        if (*str == '\0')
756            break;
757
758        str_beg = str;
759
760        for (; *str != '\0'; ++str)
761        {
762            if (string == outside && *str == ';') /* End of command */
763            {
764                *str++ = '\0';
765                break;    /* continue with next command */
766            }
767            if (*str == '\'')
768            {
769                if (string == outside)
770                    string = singlequote;
771                else if (string != doublequote)
772                    string = outside;
773            }
774            else if (*str == '"')
775            {
776                if (string == outside)
777                    string = doublequote;
778                else if (string != singlequote)
779                    string = outside;
780            }
781        }
782        if (strlen(str_beg) != 0)
783        {
784            ret = bs2system(str_beg);
785	    flush();
786            if (ret != 0 /*&& !option.err_ignore*/)
787                break; /* do not continue after errors */
788        }
789    }
790
791    if (string != outside)
792    {
793        stderror(ERR_NAME | ERR_UNMATCHED, (Char) string);
794        return -1;
795    }
796
797    return ret;
798}
799/*ARGSUSED*/
800void
801dobs2cmd(v, c)
802    register Char **v;
803    struct command *c;
804{
805    register Char *cp;
806    register int  i = 0, len = 0;
807    char *cmd = NULL;
808    int     pvec[2];
809    struct command faket;
810    Char   *fakecom[2];
811    char    tibuf[BUFSIZE];
812    int     icnt;
813    static const Char STRbs2cmd[] = { 'b','s','2','c','m','d','\0' };
814
815    if (setintr)
816#ifdef BSDSIGS
817	(void) sigsetmask(sigblock((sigmask_t) 0) & ~sigmask(SIGINT));
818#else /* !BSDSIGS */
819	(void) sigrelse (SIGINT);
820#endif /* BSDSIGS */
821    v++;
822    gflag = 0, tglob(v);
823    if (gflag) {
824	v = globall(v);
825	if (v == 0)
826	    stderror(ERR_NAME | ERR_NOMATCH);
827    }
828    else {
829	v = gargv = saveblk(v);
830	trim(v);
831    }
832
833    /* First round: count the string lengths */
834    for (i=0; v[i]; ++i) {
835	len += s_strlen(v[i]) + (v[i+1] != NULL);
836    }
837
838    cmd = xmalloc(len+1); /* 1 for the final '\0' */
839
840    /* 2nd round: fill cmd buffer */
841    i = 0;
842    while ((cp = *v++) != 0) {
843	register int c;
844	while (c = *cp++)
845	    cmd[i++] = (char)c;
846        if (*v)
847	    cmd[i++] = ' ';
848    }
849    cmd[i] = '\0';
850
851    /* Make upper case */
852    bs2upcase(cmd);
853
854    faket.t_dtyp = NODE_COMMAND;
855    faket.t_dflg = F_BACKQ|F_STDERR;
856    faket.t_dlef = 0;
857    faket.t_drit = 0;
858    faket.t_dspr = 0;
859    faket.t_dcom = fakecom;
860    fakecom[0] = STRbs2cmd;
861    fakecom[1] = 0;
862
863    mypipe(pvec);
864    if (pfork(&faket, -1) == 0) {
865        /* child */
866        (void) close(pvec[0]);
867        (void) dmove(pvec[1], 1);
868        (void) dmove(SHDIAG,  2);
869        initdesc();
870/*        closem();*/
871#ifdef SIGTSTP
872        (void) sigignore(SIGTSTP);
873#endif
874#ifdef SIGTTIN
875        (void) sigignore(SIGTTIN);
876#endif
877#ifdef SIGTTOU
878        (void) sigignore(SIGTTOU);
879#endif
880        xexit(bs2cmdlist(cmd));
881    }
882    (void) close(pvec[1]);
883    for(;;) {
884        do
885            icnt = read(pvec[0], tibuf, BUFSIZE);
886        while (icnt == -1 && errno == EINTR);
887        if (icnt <= 0)
888            break;
889        for (i = 0; i < icnt; i++)
890            xputchar((unsigned char) tibuf[i]);
891    }
892    (void) close(pvec[0]);
893    pwait();
894
895    flush();
896
897    if (setintr)
898#ifdef BSDSIGS
899	(void) sigblock(sigmask(SIGINT));
900#else /* !BSDSIGS */
901	(void) sighold(SIGINT);
902#endif /* BSDSIGS */
903    if (gargv)
904	blkfree(gargv), gargv = 0;
905}
906#endif /* _OSD_POSIX */
907
908#if defined(_CX_UX)
909/*ARGSUSED*/
910void
911doatt(v, c)
912    register Char **v;
913    struct command *c;
914{
915    register Char *cp = v[1];
916    char    ubuf[100];
917#ifdef BSDSIGS
918    register sigmask_t omask = 0;
919#endif /* BSDSIGS */
920
921    if (cp == 0)
922	(void) setuniverse("att");
923    else {
924	(void) getuniverse(ubuf);
925	(void) setuniverse("att");
926	if (setintr)
927#ifdef BSDSIGS
928	    omask = sigblock(sigmask(SIGINT)) & ~sigmask(SIGINT);
929#else /* !BSDSIGS */
930	    (void) sighold(SIGINT);
931#endif /* BSDSIGS */
932	lshift(v, 1);
933	if (setintr)
934#ifdef BSDSIGS
935	    (void) sigsetmask(omask);
936#else /* !BSDSIGS */
937	    (void) sigrelse (SIGINT);
938#endif /* BSDSIGS */
939	reexecute(c);
940	(void) setuniverse(ubuf);
941    }
942}
943
944/*ARGSUSED*/
945void
946doucb(v, c)
947    register Char **v;
948    struct command *c;
949{
950    register Char *cp = v[1];
951    char    ubuf[100];
952#ifdef BSDSIGS
953    register sigmask_t omask = 0;
954#endif /* BSDSIGS */
955
956    if (cp == 0)
957	(void) setuniverse("ucb");
958    else {
959	(void) getuniverse(ubuf);
960	(void) setuniverse("ucb");
961	if (setintr)
962#ifdef BSDSIGS
963	    omask = sigblock(sigmask(SIGINT)) & ~sigmask(SIGINT);
964#else /* !BSDSIGS */
965	    (void) sighold(SIGINT);
966#endif /* BSDSIGS */
967	lshift(v, 1);
968	if (setintr)
969#ifdef BSDSIGS
970	    (void) sigsetmask(omask);
971#else /* !BSDSIGS */
972	    (void) sigrelse (SIGINT);
973#endif /* BSDSIGS */
974	reexecute(c);
975	(void) setuniverse(ubuf);
976    }
977}
978#endif /* _CX_UX */
979
980#ifdef _SEQUENT_
981/*
982 * Compute the difference in process stats.
983 */
984void
985pr_stat_sub(p2, p1, pr)
986    struct process_stats *p2, *p1, *pr;
987{
988    pr->ps_utime.tv_sec = p2->ps_utime.tv_sec - p1->ps_utime.tv_sec;
989    pr->ps_utime.tv_usec = p2->ps_utime.tv_usec - p1->ps_utime.tv_usec;
990    if (pr->ps_utime.tv_usec < 0) {
991	pr->ps_utime.tv_sec -= 1;
992	pr->ps_utime.tv_usec += 1000000;
993    }
994    pr->ps_stime.tv_sec = p2->ps_stime.tv_sec - p1->ps_stime.tv_sec;
995    pr->ps_stime.tv_usec = p2->ps_stime.tv_usec - p1->ps_stime.tv_usec;
996    if (pr->ps_stime.tv_usec < 0) {
997	pr->ps_stime.tv_sec -= 1;
998	pr->ps_stime.tv_usec += 1000000;
999    }
1000
1001    pr->ps_maxrss = p2->ps_maxrss - p1->ps_maxrss;
1002    pr->ps_pagein = p2->ps_pagein - p1->ps_pagein;
1003    pr->ps_reclaim = p2->ps_reclaim - p1->ps_reclaim;
1004    pr->ps_zerofill = p2->ps_zerofill - p1->ps_zerofill;
1005    pr->ps_pffincr = p2->ps_pffincr - p1->ps_pffincr;
1006    pr->ps_pffdecr = p2->ps_pffdecr - p1->ps_pffdecr;
1007    pr->ps_swap = p2->ps_swap - p1->ps_swap;
1008    pr->ps_syscall = p2->ps_syscall - p1->ps_syscall;
1009    pr->ps_volcsw = p2->ps_volcsw - p1->ps_volcsw;
1010    pr->ps_involcsw = p2->ps_involcsw - p1->ps_involcsw;
1011    pr->ps_signal = p2->ps_signal - p1->ps_signal;
1012    pr->ps_lread = p2->ps_lread - p1->ps_lread;
1013    pr->ps_lwrite = p2->ps_lwrite - p1->ps_lwrite;
1014    pr->ps_bread = p2->ps_bread - p1->ps_bread;
1015    pr->ps_bwrite = p2->ps_bwrite - p1->ps_bwrite;
1016    pr->ps_phread = p2->ps_phread - p1->ps_phread;
1017    pr->ps_phwrite = p2->ps_phwrite - p1->ps_phwrite;
1018}
1019
1020#endif /* _SEQUENT_ */
1021
1022
1023#ifdef NEEDmemset
1024/* This is a replacement for a missing memset function */
1025ptr_t xmemset(loc, value, len)
1026    ptr_t loc;
1027    int len;
1028    size_t value;
1029{
1030    char *ptr = (char *) loc;
1031
1032    while (len--)
1033	*ptr++ = value;
1034    return loc;
1035}
1036#endif /* NEEDmemset */
1037
1038
1039#ifdef NEEDmemmove
1040/* memmove():
1041 * 	This is the ANSI form of bcopy() with the arguments backwards...
1042 *	Unlike memcpy(), it handles overlaps between source and
1043 *	destination memory
1044 */
1045ptr_t
1046xmemmove(vdst, vsrc, len)
1047    ptr_t vdst;
1048    const ptr_t vsrc;
1049    size_t len;
1050{
1051    const char *src = (const char *) vsrc;
1052    char *dst = (char *) vdst;
1053
1054    if (src == dst)
1055	return vdst;
1056
1057    if (src > dst) {
1058	while (len--)
1059	    *dst++ = *src++;
1060    }
1061    else {
1062	src += len;
1063	dst += len;
1064	while (len--)
1065	    *--dst = *--src;
1066    }
1067    return vdst;
1068}
1069#endif /* NEEDmemmove */
1070
1071
1072#ifndef WINNT_NATIVE
1073#ifdef tcgetpgrp
1074int
1075xtcgetpgrp(fd)
1076    int     fd;
1077{
1078    int     pgrp;
1079
1080    /* ioctl will handle setting errno correctly. */
1081    if (ioctl(fd, TIOCGPGRP, (ioctl_t) & pgrp) < 0)
1082	return (-1);
1083    return (pgrp);
1084}
1085
1086/*
1087 * XXX: tcsetpgrp is not a macro any more cause on some systems,
1088 * pid_t is a short, but the ioctl() takes a pointer to int (pyr)
1089 * Thanks to Simon Day (simon@pharaoh.cyborg.bt.co.uk) for pointing
1090 * this out.
1091 */
1092int
1093xtcsetpgrp(fd, pgrp)
1094    int fd, pgrp;
1095{
1096    return ioctl(fd, TIOCSPGRP, (ioctl_t) &pgrp);
1097}
1098
1099#endif	/* tcgetpgrp */
1100#endif /* WINNT_NATIVE */
1101
1102
1103#ifdef YPBUGS
1104void
1105fix_yp_bugs()
1106{
1107    char   *mydomain;
1108
1109    extern int yp_get_default_domain __P((char **));
1110    /*
1111     * PWP: The previous version assumed that yp domain was the same as the
1112     * internet name domain.  This isn't allways true. (Thanks to Mat Landau
1113     * <mlandau@bbn.com> for the original version of this.)
1114     */
1115    if (yp_get_default_domain(&mydomain) == 0) {	/* if we got a name */
1116	extern void yp_unbind __P((const char *));
1117
1118	yp_unbind(mydomain);
1119    }
1120}
1121
1122#endif /* YPBUGS */
1123
1124#ifdef STRCOLLBUG
1125void
1126fix_strcoll_bug()
1127{
1128#if defined(NLS) && !defined(NOSTRCOLL)
1129    /*
1130     * SunOS4 checks the file descriptor from openlocale() for <= 0
1131     * instead of == -1. Someone should tell sun that file descriptor 0
1132     * is valid! Our portable hack: open one so we call it with 0 used...
1133     * We have to call this routine every time the locale changes...
1134     *
1135     * Of course it also tries to free the constant locale "C" it initially
1136     * had allocated, with the sequence
1137     * > setenv LANG "fr"
1138     * > ls^D
1139     * > unsetenv LANG
1140     * But we are smarter than that and just print a warning message.
1141     */
1142    int fd = -1;
1143    static char *root = "/";
1144
1145    if (!didfds)
1146	fd = open(root, O_RDONLY|O_LARGEFILE);
1147
1148    (void) strcoll(root, root);
1149
1150    if (fd != -1)
1151	(void) close(fd);
1152#endif
1153}
1154#endif /* STRCOLLBUG */
1155
1156
1157#ifdef OREO
1158#include <compat.h>
1159#endif /* OREO */
1160
1161void
1162osinit()
1163{
1164#ifdef OREO
1165    set42sig();
1166    setcompat(getcompat() & ~COMPAT_EXEC);
1167    sigignore(SIGIO);		/* ignore SIGIO */
1168#endif /* OREO */
1169
1170#ifdef aiws
1171    {
1172	struct sigstack inst;
1173	inst.ss_sp = (char *) xmalloc((size_t) 4192) + 4192;
1174	inst.ss_onstack = 0;
1175	sigstack(&inst, NULL);
1176    }
1177#endif /* aiws */
1178
1179#ifdef apollo
1180    (void) isapad();
1181#endif
1182
1183#ifdef _SX
1184    /*
1185     * kill(SIGCONT) problems, don't know what this syscall does
1186     * [schott@rzg.mpg.de]
1187     */
1188    syscall(151, getpid(), getpid());
1189#endif /* _SX */
1190}
1191
1192#ifdef strerror
1193char *
1194xstrerror(i)
1195    int i;
1196{
1197    static char errbuf[128];
1198
1199    if (i >= 0 && i < sys_nerr) {
1200	return sys_errlist[i];
1201    } else {
1202	(void) xsnprintf(errbuf, sizeof(errbuf),
1203	    CGETS(23, 13, "Unknown Error: %d"), i);
1204	return errbuf;
1205    }
1206}
1207#endif /* strerror */
1208
1209#ifdef gethostname
1210# if !defined(_MINIX) && !defined(__EMX__) && !defined(WINNT_NATIVE)
1211#  include <sys/utsname.h>
1212# endif /* !_MINIX && !__EMX__ && !WINNT_NATIVE */
1213
1214int
1215xgethostname(name, namlen)
1216    char   *name;
1217    int     namlen;
1218{
1219# if !defined(_MINIX) && !defined(__EMX__) && !defined(WINNT_NATIVE)
1220    int     i, retval;
1221    struct utsname uts;
1222
1223    retval = uname(&uts);
1224
1225#  ifdef DEBUG
1226    xprintf(CGETS(23, 14, "sysname:  %s\n"), uts.sysname);
1227    xprintf(CGETS(23, 15, "nodename: %s\n"), uts.nodename);
1228    xprintf(CGETS(23, 16, "release:  %s\n"), uts.release);
1229    xprintf(CGETS(23, 17, "version:  %s\n"), uts.version);
1230    xprintf(CGETS(23, 18, "machine:  %s\n"), uts.machine);
1231#  endif /* DEBUG */
1232    i = strlen(uts.nodename) + 1;
1233    (void) strncpy(name, uts.nodename, i < namlen ? i : namlen);
1234
1235    return retval;
1236# else /* !_MINIX && !__EMX__ */
1237    if (namlen > 0) {
1238#  ifdef __EMX__
1239	(void) strncpy(name, "OS/2", namlen);
1240#  else /* _MINIX */
1241	(void) strncpy(name, "minix", namlen);
1242#  endif /* __EMX__ */
1243	name[namlen-1] = '\0';
1244    }
1245    return(0);
1246#endif /* _MINIX && !__EMX__ */
1247} /* end xgethostname */
1248#endif /* gethostname */
1249
1250#ifdef nice
1251# if defined(_MINIX) && defined(NICE)
1252#  undef _POSIX_SOURCE	/* redefined in <lib.h> */
1253#  undef _MINIX		/* redefined in <lib.h> */
1254#  undef HZ		/* redefined in <minix/const.h> */
1255#  include <lib.h>
1256# endif /* _MINIX && NICE */
1257int
1258xnice(incr)
1259    int incr;
1260{
1261#if defined(_MINIX) && defined(NICE)
1262    return callm1(MM, NICE, incr, 0, 0, NIL_PTR, NIL_PTR, NIL_PTR);
1263#else
1264    return /* incr ? 0 : */ 0;
1265#endif /* _MINIX && NICE */
1266} /* end xnice */
1267#endif /* nice */
1268
1269#ifdef NEEDgetcwd
1270static char *strnrcpy __P((char *, char *, size_t));
1271
1272/* xgetcwd():
1273 *	Return the pathname of the current directory, or return
1274 *	an error message in pathname.
1275 */
1276
1277# ifdef hp9000s500
1278/*
1279 *  From: Bernd Mohr <mohr@faui77.informatik.uni-erlangen.de>
1280 *  I also ported the tcsh to the HP9000 Series 500. This computer
1281 *  is a little bit different than the other HP 9000 computer. It has
1282 *  a HP Chip instead of a Motorola CPU and it is no "real" UNIX. It runs
1283 *  HP-UX which is emulated in top of a HP operating system. So, the last
1284 *  supported version of HP-UX is 5.2 on the HP9000s500. This has two
1285 *  consequences: it supports no job control and it has a filesystem
1286 *  without "." and ".." !!!
1287 */
1288char *
1289xgetcwd(pathname, pathlen)
1290    char *pathname;
1291    size_t pathlen;
1292{
1293    char pathbuf[MAXNAMLEN];	/* temporary pathname buffer */
1294    char *pnptr = &pathbuf[(sizeof pathbuf)-1]; /* pathname pointer */
1295    dev_t rdev;			/* root device number */
1296    DIR *dirp = NULL;		/* directory stream */
1297    ino_t rino;			/* root inode number */
1298    off_t rsize;		/* root size */
1299    struct direct *dir;		/* directory entry struct */
1300    struct stat d, dd;		/* file status struct */
1301    int serrno;
1302
1303    *pnptr = '\0';
1304    (void) stat("/.", &d);
1305    rdev = d.st_dev;
1306    rino = d.st_ino;
1307    rsize = d.st_size;
1308    for (;;) {
1309	if (stat(".", &d) == -1) {
1310	    (void) xsnprintf(pathname, pathlen, CGETS(23, 24,
1311		"getcwd: Cannot stat \".\" (%s)"), strerror(errno));
1312	    goto fail;
1313	}
1314	if (d.st_ino == rino && d.st_dev == rdev && d.st_size == rsize)
1315	    break;		/* reached root directory */
1316	if ((dirp = opendir("..")) == NULL) {
1317	    (void) xsnprintf(pathname, pathlen, CGETS(23, 19,
1318		"getcwd: Cannot open \"..\" (%s)"), strerror(errno));
1319	    goto fail;
1320	}
1321	if (chdir("..") == -1) {
1322	    (void) xsnprintf(pathname, pathlen, CGETS(23, 20,
1323		"getcwd: Cannot chdir to \"..\" (%s)"), strerror(errno));
1324	    goto fail;
1325	}
1326	do {
1327	    if ((dir = readdir(dirp)) == NULL) {
1328		(void) xsnprintf(pathname, pathlen,
1329		    CGETS(23, 21, "getcwd: Read error in \"..\" (%s)"),
1330		    strerror(errno));
1331		goto fail;
1332	    }
1333	    if (stat(dir->d_name, &dd) == -1) {
1334		(void) xsnprintf(pathname, pathlen,
1335		    CGETS(23, 25, "getcwd: Cannot stat directory \"%s\" (%s)"),
1336		    dir->d_name, strerror(errno));
1337		goto fail;
1338	    }
1339	} while (dd.st_ino  != d.st_ino  ||
1340		 dd.st_dev  != d.st_dev  ||
1341		 dd.st_size != d.st_size);
1342	(void) closedir(dirp);
1343	dirp = NULL;
1344	pnptr = strnrcpy(dirp->d_name, pnptr, pnptr - pathbuf);
1345	pnptr = strnrcpy("/", pnptr, pnptr - pathbuf);
1346    }
1347
1348    if (*pnptr == '\0')		/* current dir == root dir */
1349	(void) strncpy(pathname, "/", pathlen);
1350    else {
1351	(void) strncpy(pathname, pnptr, pathlen);
1352	pathname[pathlen - 1] = '\0';
1353	if (chdir(pnptr) == -1) {
1354	    (void) xsnprintf(pathname, MAXPATHLEN, CGETS(23, 22,
1355		    "getcwd: Cannot change back to \".\" (%s)"),
1356		    strerror(errno));
1357	    return NULL;
1358	}
1359    }
1360    return pathname;
1361
1362fail:
1363    serrno = errno;
1364    (void) chdir(strnrcpy(".", pnptr, pnptr - pathbuf));
1365    errno = serrno;
1366    return NULL;
1367}
1368
1369# else /* ! hp9000s500 */
1370
1371#  if (SYSVREL != 0 && !defined(d_fileno)) || defined(_VMS_POSIX) || defined(WINNT) || defined(_MINIX_VMD)
1372#   define d_fileno d_ino
1373#  endif
1374
1375char *
1376xgetcwd(pathname, pathlen)
1377    char   *pathname;
1378    size_t pathlen;
1379{
1380    DIR    *dp;
1381    struct dirent *d;
1382
1383    struct stat st_root, st_cur, st_next, st_dotdot;
1384    char    pathbuf[MAXPATHLEN], nextpathbuf[MAXPATHLEN * 2];
1385    char   *pathptr, *nextpathptr, *cur_name_add;
1386    int	   save_errno = 0;
1387
1388    /* find the inode of root */
1389    if (stat("/", &st_root) == -1) {
1390	(void) xsnprintf(pathname, pathlen, CGETS(23, 23,
1391			"getcwd: Cannot stat \"/\" (%s)"),
1392			strerror(errno));
1393	return NULL;
1394    }
1395    pathbuf[MAXPATHLEN - 1] = '\0';
1396    pathptr = &pathbuf[MAXPATHLEN - 1];
1397    nextpathbuf[MAXPATHLEN - 1] = '\0';
1398    cur_name_add = nextpathptr = &nextpathbuf[MAXPATHLEN - 1];
1399
1400    /* find the inode of the current directory */
1401    if (lstat(".", &st_cur) == -1) {
1402	(void) xsnprintf(pathname, pathlen, CGETS(23, 24,
1403			 "getcwd: Cannot stat \".\" (%s)"),
1404			 strerror(errno));
1405	return NULL;
1406    }
1407    nextpathptr = strnrcpy(nextpathptr, "../", nextpathptr - nextpathbuf);
1408
1409    /* Descend to root */
1410    for (;;) {
1411
1412	/* look if we found root yet */
1413	if (st_cur.st_ino == st_root.st_ino &&
1414	    DEV_DEV_COMPARE(st_cur.st_dev, st_root.st_dev)) {
1415	    (void) strncpy(pathname, *pathptr != '/' ? "/" : pathptr, pathlen);
1416	    pathname[pathlen - 1] = '\0';
1417	    return pathname;
1418	}
1419
1420	/* open the parent directory */
1421	if (stat(nextpathptr, &st_dotdot) == -1) {
1422	    (void) xsnprintf(pathname, pathlen, CGETS(23, 25,
1423			     "getcwd: Cannot stat directory \"%s\" (%s)"),
1424			     nextpathptr, strerror(errno));
1425	    return NULL;
1426	}
1427	if ((dp = opendir(nextpathptr)) == NULL) {
1428	    (void) xsnprintf(pathname, pathlen, CGETS(23, 26,
1429			     "getcwd: Cannot open directory \"%s\" (%s)"),
1430			     nextpathptr, strerror(errno));
1431	    return NULL;
1432	}
1433
1434	/* look in the parent for the entry with the same inode */
1435	if (DEV_DEV_COMPARE(st_dotdot.st_dev, st_cur.st_dev)) {
1436	    /* Parent has same device. No need to stat every member */
1437	    for (d = readdir(dp); d != NULL; d = readdir(dp)) {
1438#ifdef __clipper__
1439		if (((unsigned long)d->d_fileno & 0xffff) == st_cur.st_ino)
1440		    break;
1441#else
1442		if (d->d_fileno == st_cur.st_ino)
1443		    break;
1444#endif
1445	    }
1446	}
1447	else {
1448	    /*
1449	     * Parent has a different device. This is a mount point so we
1450	     * need to stat every member
1451	     */
1452	    for (d = readdir(dp); d != NULL; d = readdir(dp)) {
1453		if (ISDOT(d->d_name) || ISDOTDOT(d->d_name))
1454		    continue;
1455		(void)strncpy(cur_name_add, d->d_name,
1456		    (size_t) (&nextpathbuf[sizeof(nextpathbuf) - 1] - cur_name_add));
1457		if (lstat(nextpathptr, &st_next) == -1) {
1458		    /*
1459		     * We might not be able to stat() some path components
1460		     * if we are using afs, but this is not an error as
1461		     * long as we find the one we need; we also save the
1462		     * first error to report it if we don't finally succeed.
1463		     */
1464		    if (save_errno == 0)
1465			save_errno = errno;
1466		    continue;
1467		}
1468		/* check if we found it yet */
1469		if (st_next.st_ino == st_cur.st_ino &&
1470		    DEV_DEV_COMPARE(st_next.st_dev, st_cur.st_dev))
1471		    break;
1472	    }
1473	}
1474	if (d == NULL) {
1475	    (void) xsnprintf(pathname, pathlen, CGETS(23, 27,
1476			     "getcwd: Cannot find \".\" in \"..\" (%s)"),
1477			     strerror(save_errno ? save_errno : ENOENT));
1478	    (void) closedir(dp);
1479	    return NULL;
1480	}
1481	else
1482	    save_errno = 0;
1483	st_cur = st_dotdot;
1484	pathptr = strnrcpy(pathptr, d->d_name, pathptr - pathbuf);
1485	pathptr = strnrcpy(pathptr, "/", pathptr - pathbuf);
1486	nextpathptr = strnrcpy(nextpathptr, "../", nextpathptr - nextpathbuf);
1487	*cur_name_add = '\0';
1488	(void) closedir(dp);
1489    }
1490} /* end getcwd */
1491# endif /* hp9000s500 */
1492
1493/* strnrcpy():
1494 *	Like strncpy, going backwards and returning the new pointer
1495 */
1496static char *
1497strnrcpy(ptr, str, siz)
1498    register char *ptr, *str;
1499    size_t siz;
1500{
1501    register int len = strlen(str);
1502    if (siz == 0)
1503	return ptr;
1504
1505    while (len && siz--)
1506	*--ptr = str[--len];
1507
1508    return (ptr);
1509} /* end strnrcpy */
1510#endif /* getcwd */
1511
1512#ifdef apollo
1513/***
1514 *** Domain/OS
1515 ***/
1516#include <apollo/base.h>
1517#include <apollo/loader.h>
1518#include <apollo/error.h>
1519
1520
1521static char *
1522apperr(st)
1523    status_$t *st;
1524{
1525    static char buf[BUFSIZE];
1526    short e_subl, e_modl, e_codel;
1527    error_$string_t e_sub, e_mod, e_code;
1528
1529    error_$get_text(*st, e_sub, &e_subl, e_mod, &e_modl, e_code, &e_codel);
1530    e_sub[e_subl] = '\0';
1531    e_code[e_codel] = '\0';
1532    e_mod[e_modl] = '\0';
1533    (void) xsnprintf(buf, sizeof(buf), "%s (%s/%s)", e_code, e_sub, e_mod);
1534
1535    return(buf);
1536}
1537
1538static int
1539llib(s)
1540    Char *s;
1541{
1542    short len = Strlen(s);
1543    status_$t st;
1544    char *t;
1545
1546    loader_$inlib(t = short2str(s), len, &st);
1547    if (st.all != status_$ok)
1548	stderror(ERR_SYSTEM, t, apperr(&st));
1549}
1550
1551/*ARGSUSED*/
1552void
1553doinlib(v, c)
1554    Char **v;
1555    struct command *c;
1556{
1557    setname(short2str(*v++));
1558    gflag = 0, tglob(v);
1559    if (gflag) {
1560	v = globall(v);
1561	if (v == 0)
1562	    stderror(ERR_NAME | ERR_NOMATCH);
1563    }
1564    else {
1565	v = gargv = saveblk(v);
1566	trim(v);
1567    }
1568
1569    while (v && *v)
1570	llib(*v++);
1571    if (gargv)
1572	blkfree(gargv), gargv = 0;
1573}
1574
1575int
1576getv(v)
1577    Char *v;
1578{
1579    if (eq(v, STRbsd43))
1580	return(1);
1581    else if (eq(v, STRsys53))
1582	return(0);
1583    else
1584	stderror(ERR_NAME | ERR_SYSTEM, short2str(v),
1585		 CGETS(23, 28, "Invalid system type"));
1586    /*NOTREACHED*/
1587    return(0);
1588}
1589
1590/*ARGSUSED*/
1591void
1592dover(v, c)
1593    Char **v;
1594    struct command *c;
1595{
1596    Char *p;
1597
1598    setname(short2str(*v++));
1599    if (!*v) {
1600	if (!(p = tgetenv(STRSYSTYPE)))
1601	    stderror(ERR_NAME | ERR_STRING,
1602		     CGETS(23, 29, "System type is not set"));
1603	xprintf("%S\n", p);
1604    }
1605    else {
1606	tsetenv(STRSYSTYPE, getv(*v) ? STRbsd43 : STRsys53);
1607	dohash(NULL, NULL);
1608    }
1609}
1610
1611/*
1612 * Many thanks to rees@citi.umich.edu (Jim Rees) and
1613 *                mathys@ssdt-tempe.sps.mot.com (Yves Mathys)
1614 * For figuring out how to do this... I could have never done
1615 * it without their help.
1616 */
1617typedef short enum {
1618	name_$wdir_type,
1619	name_$ndir_type,
1620	name_$node_dir_type,
1621} name_$dir_type_t;
1622
1623/*ARGSUSED*/
1624void
1625dorootnode(v, c)
1626    Char **v;
1627    struct command *c;
1628{
1629    name_$dir_type_t dirtype = name_$node_dir_type;
1630    uid_$t uid;
1631    status_$t st;
1632    char *name;
1633    short namelen;
1634
1635    setname(short2str(*v++));
1636
1637    name = short2str(*v);
1638    namelen = strlen(name);
1639
1640    name_$resolve(name, &namelen, &uid, &st);
1641    if (st.all != status_$ok)
1642	stderror(ERR_SYSTEM, name, apperr(&st));
1643    namelen = 0;
1644    name_$set_diru(&uid, "", &namelen, &dirtype, &st);
1645    if (st.all != status_$ok)
1646	stderror(ERR_SYSTEM, name, apperr(&st));
1647    dohash(NULL, NULL);
1648}
1649
1650int
1651isapad()
1652{
1653    static int res = -1;
1654    static status_$t st;
1655
1656    if (res == -1) {
1657	int strm;
1658	if (isatty(0))
1659	    strm = 0;
1660	if (isatty(1))
1661	    strm = 1;
1662	if (isatty(2))
1663	    strm = 2;
1664	else {
1665	    res = 0;
1666	    st.all = status_$ok;
1667	    return(res);
1668	}
1669	res = stream_$isavt(&strm, &st);
1670	res = res ? 1 : 0;
1671    }
1672    else {
1673	if (st.all != status_$ok)
1674	    stderror(ERR_SYSTEM, "stream_$isavt", apperr(&st));
1675    }
1676    return(res);
1677}
1678#endif
1679