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