xref: /freebsd/contrib/tcsh/tc.os.c (revision d056fa046c6a91b90cd98165face0e42a33a5173)
1 /* $Header: /src/pub/tcsh/tc.os.c,v 3.58 2005/01/18 20:24:51 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.58 2005/01/18 20:24:51 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 RETSIGTYPE
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     Char **v;
657     struct command *c;
658 {
659     Char *cp = v[1];
660     Char *cp2;		/* dunno how many elements v comes in with */
661     char    ubuf[100];
662 #ifdef BSDSIGS
663     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)
704 static int
705 bs2upcase(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 }
742 static int
743 bs2cmdlist(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*/
800 void
801 dobs2cmd(v, c)
802     Char **v;
803     struct command *c;
804 {
805     Char *cp;
806     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 	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*/
910 void
911 doatt(v, c)
912     Char **v;
913     struct command *c;
914 {
915     Char *cp = v[1];
916     char    ubuf[100];
917 #ifdef BSDSIGS
918     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*/
945 void
946 doucb(v, c)
947     Char **v;
948     struct command *c;
949 {
950     Char *cp = v[1];
951     char    ubuf[100];
952 #ifdef BSDSIGS
953     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  */
984 void
985 pr_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 #ifndef HAVE_MEMSET
1024 /* This is a replacement for a missing memset function */
1025 ptr_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 /* !HAVE_MEMSET */
1037 
1038 
1039 #ifndef HAVE_MEMMOVE
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  */
1045 ptr_t
1046 xmemmove(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 /* HAVE_MEMMOVE */
1070 
1071 
1072 #ifndef WINNT_NATIVE
1073 #ifdef NEEDtcgetpgrp
1074 int
1075 xtcgetpgrp(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  */
1092 int
1093 xtcsetpgrp(fd, pgrp)
1094     int fd, pgrp;
1095 {
1096     return ioctl(fd, TIOCSPGRP, (ioctl_t) &pgrp);
1097 }
1098 
1099 #endif	/* NEEDtcgetpgrp */
1100 #endif /* WINNT_NATIVE */
1101 
1102 
1103 #ifdef YPBUGS
1104 void
1105 fix_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
1125 void
1126 fix_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 
1161 void
1162 osinit()
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 #ifndef HAVE_STRERROR
1193 char *
1194 xstrerror(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 /* !HAVE_STRERROR */
1208 
1209 #ifndef HAVE_GETHOSTNAME
1210 # if !defined(_MINIX) && !defined(__EMX__) && !defined(WINNT_NATIVE)
1211 #  include <sys/utsname.h>
1212 # endif /* !_MINIX && !__EMX__ && !WINNT_NATIVE */
1213 
1214 int
1215 xgethostname(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 /* !HAVE_GETHOSTNAME */
1249 
1250 #ifndef HAVE_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 */
1257 int
1258 xnice(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 /* !HAVE_NICE */
1268 
1269 #ifndef HAVE_GETCWD
1270 static 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  */
1288 char *
1289 xgetcwd(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 
1362 fail:
1363     serrno = errno;
1364     (void) chdir(strnrcpy(".", pnptr, pnptr - pathbuf));
1365     errno = serrno;
1366     return NULL;
1367 }
1368 
1369 # else /* ! hp9000s500 */
1370 
1371 
1372 char *
1373 xgetcwd(pathname, pathlen)
1374     char   *pathname;
1375     size_t pathlen;
1376 {
1377     DIR    *dp;
1378     struct dirent *d;
1379 
1380     struct stat st_root, st_cur, st_next, st_dotdot;
1381     char    pathbuf[MAXPATHLEN], nextpathbuf[MAXPATHLEN * 2];
1382     char   *pathptr, *nextpathptr, *cur_name_add;
1383     int	   save_errno = 0;
1384 
1385     /* find the inode of root */
1386     if (stat("/", &st_root) == -1) {
1387 	(void) xsnprintf(pathname, pathlen, CGETS(23, 23,
1388 			"getcwd: Cannot stat \"/\" (%s)"),
1389 			strerror(errno));
1390 	return NULL;
1391     }
1392     pathbuf[MAXPATHLEN - 1] = '\0';
1393     pathptr = &pathbuf[MAXPATHLEN - 1];
1394     nextpathbuf[MAXPATHLEN - 1] = '\0';
1395     cur_name_add = nextpathptr = &nextpathbuf[MAXPATHLEN - 1];
1396 
1397     /* find the inode of the current directory */
1398     if (lstat(".", &st_cur) == -1) {
1399 	(void) xsnprintf(pathname, pathlen, CGETS(23, 24,
1400 			 "getcwd: Cannot stat \".\" (%s)"),
1401 			 strerror(errno));
1402 	return NULL;
1403     }
1404     nextpathptr = strnrcpy(nextpathptr, "../", nextpathptr - nextpathbuf);
1405 
1406     /* Descend to root */
1407     for (;;) {
1408 
1409 	/* look if we found root yet */
1410 	if (st_cur.st_ino == st_root.st_ino &&
1411 	    DEV_DEV_COMPARE(st_cur.st_dev, st_root.st_dev)) {
1412 	    (void) strncpy(pathname, *pathptr != '/' ? "/" : pathptr, pathlen);
1413 	    pathname[pathlen - 1] = '\0';
1414 	    return pathname;
1415 	}
1416 
1417 	/* open the parent directory */
1418 	if (stat(nextpathptr, &st_dotdot) == -1) {
1419 	    (void) xsnprintf(pathname, pathlen, CGETS(23, 25,
1420 			     "getcwd: Cannot stat directory \"%s\" (%s)"),
1421 			     nextpathptr, strerror(errno));
1422 	    return NULL;
1423 	}
1424 	if ((dp = opendir(nextpathptr)) == NULL) {
1425 	    (void) xsnprintf(pathname, pathlen, CGETS(23, 26,
1426 			     "getcwd: Cannot open directory \"%s\" (%s)"),
1427 			     nextpathptr, strerror(errno));
1428 	    return NULL;
1429 	}
1430 
1431 	/* look in the parent for the entry with the same inode */
1432 	if (DEV_DEV_COMPARE(st_dotdot.st_dev, st_cur.st_dev)) {
1433 	    /* Parent has same device. No need to stat every member */
1434 	    for (d = readdir(dp); d != NULL; d = readdir(dp)) {
1435 #ifdef __clipper__
1436 		if (((unsigned long)d->d_ino & 0xffff) == st_cur.st_ino)
1437 		    break;
1438 #else
1439 		if (d->d_ino == st_cur.st_ino)
1440 		    break;
1441 #endif
1442 	    }
1443 	}
1444 	else {
1445 	    /*
1446 	     * Parent has a different device. This is a mount point so we
1447 	     * need to stat every member
1448 	     */
1449 	    for (d = readdir(dp); d != NULL; d = readdir(dp)) {
1450 		if (ISDOT(d->d_name) || ISDOTDOT(d->d_name))
1451 		    continue;
1452 		(void)strncpy(cur_name_add, d->d_name,
1453 		    (size_t) (&nextpathbuf[sizeof(nextpathbuf) - 1] - cur_name_add));
1454 		if (lstat(nextpathptr, &st_next) == -1) {
1455 		    /*
1456 		     * We might not be able to stat() some path components
1457 		     * if we are using afs, but this is not an error as
1458 		     * long as we find the one we need; we also save the
1459 		     * first error to report it if we don't finally succeed.
1460 		     */
1461 		    if (save_errno == 0)
1462 			save_errno = errno;
1463 		    continue;
1464 		}
1465 		/* check if we found it yet */
1466 		if (st_next.st_ino == st_cur.st_ino &&
1467 		    DEV_DEV_COMPARE(st_next.st_dev, st_cur.st_dev))
1468 		    break;
1469 	    }
1470 	}
1471 	if (d == NULL) {
1472 	    (void) xsnprintf(pathname, pathlen, CGETS(23, 27,
1473 			     "getcwd: Cannot find \".\" in \"..\" (%s)"),
1474 			     strerror(save_errno ? save_errno : ENOENT));
1475 	    (void) closedir(dp);
1476 	    return NULL;
1477 	}
1478 	else
1479 	    save_errno = 0;
1480 	st_cur = st_dotdot;
1481 	pathptr = strnrcpy(pathptr, d->d_name, pathptr - pathbuf);
1482 	pathptr = strnrcpy(pathptr, "/", pathptr - pathbuf);
1483 	nextpathptr = strnrcpy(nextpathptr, "../", nextpathptr - nextpathbuf);
1484 	*cur_name_add = '\0';
1485 	(void) closedir(dp);
1486     }
1487 } /* end getcwd */
1488 # endif /* hp9000s500 */
1489 
1490 /* strnrcpy():
1491  *	Like strncpy, going backwards and returning the new pointer
1492  */
1493 static char *
1494 strnrcpy(ptr, str, siz)
1495     char *ptr, *str;
1496     size_t siz;
1497 {
1498     int len = strlen(str);
1499     if (siz == 0)
1500 	return ptr;
1501 
1502     while (len && siz--)
1503 	*--ptr = str[--len];
1504 
1505     return (ptr);
1506 } /* end strnrcpy */
1507 #endif /* !HAVE_GETCWD */
1508 
1509 #ifdef apollo
1510 /***
1511  *** Domain/OS
1512  ***/
1513 #include <apollo/base.h>
1514 #include <apollo/loader.h>
1515 #include <apollo/error.h>
1516 
1517 
1518 static char *
1519 apperr(st)
1520     status_$t *st;
1521 {
1522     static char buf[BUFSIZE];
1523     short e_subl, e_modl, e_codel;
1524     error_$string_t e_sub, e_mod, e_code;
1525 
1526     error_$get_text(*st, e_sub, &e_subl, e_mod, &e_modl, e_code, &e_codel);
1527     e_sub[e_subl] = '\0';
1528     e_code[e_codel] = '\0';
1529     e_mod[e_modl] = '\0';
1530     (void) xsnprintf(buf, sizeof(buf), "%s (%s/%s)", e_code, e_sub, e_mod);
1531 
1532     return(buf);
1533 }
1534 
1535 static int
1536 llib(s)
1537     Char *s;
1538 {
1539     short len = Strlen(s);
1540     status_$t st;
1541     char *t;
1542 
1543     loader_$inlib(t = short2str(s), len, &st);
1544     if (st.all != status_$ok)
1545 	stderror(ERR_SYSTEM, t, apperr(&st));
1546 }
1547 
1548 /*ARGSUSED*/
1549 void
1550 doinlib(v, c)
1551     Char **v;
1552     struct command *c;
1553 {
1554     setname(short2str(*v++));
1555     gflag = 0, tglob(v);
1556     if (gflag) {
1557 	v = globall(v);
1558 	if (v == 0)
1559 	    stderror(ERR_NAME | ERR_NOMATCH);
1560     }
1561     else {
1562 	v = gargv = saveblk(v);
1563 	trim(v);
1564     }
1565 
1566     while (v && *v)
1567 	llib(*v++);
1568     if (gargv)
1569 	blkfree(gargv), gargv = 0;
1570 }
1571 
1572 int
1573 getv(v)
1574     Char *v;
1575 {
1576     if (eq(v, STRbsd43))
1577 	return(1);
1578     else if (eq(v, STRsys53))
1579 	return(0);
1580     else
1581 	stderror(ERR_NAME | ERR_SYSTEM, short2str(v),
1582 		 CGETS(23, 28, "Invalid system type"));
1583     /*NOTREACHED*/
1584     return(0);
1585 }
1586 
1587 /*ARGSUSED*/
1588 void
1589 dover(v, c)
1590     Char **v;
1591     struct command *c;
1592 {
1593     Char *p;
1594 
1595     setname(short2str(*v++));
1596     if (!*v) {
1597 	if (!(p = tgetenv(STRSYSTYPE)))
1598 	    stderror(ERR_NAME | ERR_STRING,
1599 		     CGETS(23, 29, "System type is not set"));
1600 	xprintf("%S\n", p);
1601     }
1602     else {
1603 	tsetenv(STRSYSTYPE, getv(*v) ? STRbsd43 : STRsys53);
1604 	dohash(NULL, NULL);
1605     }
1606 }
1607 
1608 /*
1609  * Many thanks to rees@citi.umich.edu (Jim Rees) and
1610  *                mathys@ssdt-tempe.sps.mot.com (Yves Mathys)
1611  * For figuring out how to do this... I could have never done
1612  * it without their help.
1613  */
1614 typedef short enum {
1615 	name_$wdir_type,
1616 	name_$ndir_type,
1617 	name_$node_dir_type,
1618 } name_$dir_type_t;
1619 
1620 /*ARGSUSED*/
1621 void
1622 dorootnode(v, c)
1623     Char **v;
1624     struct command *c;
1625 {
1626     name_$dir_type_t dirtype = name_$node_dir_type;
1627     uid_$t uid;
1628     status_$t st;
1629     char *name;
1630     short namelen;
1631 
1632     setname(short2str(*v++));
1633 
1634     name = short2str(*v);
1635     namelen = strlen(name);
1636 
1637     name_$resolve(name, &namelen, &uid, &st);
1638     if (st.all != status_$ok)
1639 	stderror(ERR_SYSTEM, name, apperr(&st));
1640     namelen = 0;
1641     name_$set_diru(&uid, "", &namelen, &dirtype, &st);
1642     if (st.all != status_$ok)
1643 	stderror(ERR_SYSTEM, name, apperr(&st));
1644     dohash(NULL, NULL);
1645 }
1646 
1647 int
1648 isapad()
1649 {
1650     static int res = -1;
1651     static status_$t st;
1652 
1653     if (res == -1) {
1654 	int strm;
1655 	if (isatty(0))
1656 	    strm = 0;
1657 	if (isatty(1))
1658 	    strm = 1;
1659 	if (isatty(2))
1660 	    strm = 2;
1661 	else {
1662 	    res = 0;
1663 	    st.all = status_$ok;
1664 	    return(res);
1665 	}
1666 	res = stream_$isavt(&strm, &st);
1667 	res = res ? 1 : 0;
1668     }
1669     else {
1670 	if (st.all != status_$ok)
1671 	    stderror(ERR_SYSTEM, "stream_$isavt", apperr(&st));
1672     }
1673     return(res);
1674 }
1675 #endif
1676