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
60static Char STRCPATH[] = {'C', 'P', 'A', 'T', 'H', '\0'};
61static Char STRLPATH[] = {'L', 'P', 'A', 'T', 'H', '\0'};
62static Char STRMPATH[] = {'M', 'P', 'A', 'T', 'H', '\0'};
63# if EPATH
64static Char STREPATH[] = {'E', 'P', 'A', 'T', 'H', '\0'};
65# endif
66#endif /* MACH */
67static Char *syspaths[] = {STRKPATH, STRCPATH, STRLPATH, STRMPATH,
68
69#if EPATH
70	STREPATH,
71#endif
72	 0};
73#define LOCALSYSPATH	"/usr/local"
74
75/*ARGSUSED*/
76void
77dosetpath(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) {
148abortpath:
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 */
193void
194dogetxvers(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*/
205void
206dosetxvers(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
236static 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 */
258static char *
259getxcode(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
269static short
270getxid(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*/
282void
283dogetspath(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*/
326void
327dosetspath(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 */
370char   *
371sitename(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
382static int
383migratepid(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*/
414void
415domigrate(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
483done:
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)
495void
496dodmmode(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
541static jmp_buf sigsys_buf;
542
543static void
544catch_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*/
554void
555dowarp(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)
611static void
612setuniverse_cleanup(void *xbuf)
613{
614    char *buf;
615
616    buf = xbuf;
617    setuniverse(buf);
618}
619
620/*ARGSUSED*/
621void
622douniverse(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)
661static int
662bs2upcase(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}
699static int
700bs2cmdlist(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*/
757void
758dobs2cmd(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)
857static void
858setuniverse_cleanup(void *xbuf)
859{
860    char *buf;
861
862    buf = xbuf;
863    setuniverse(buf);
864}
865
866/*ARGSUSED*/
867void
868doatt(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*/
892void
893doucb(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 */
921void
922pr_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 */
962void *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 */
979void *
980xmemmove(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
1005pid_t
1006xtcgetpgrp(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 */
1022int
1023xtcsetpgrp(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
1033void
1034fix_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
1054void
1055fix_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
1090void
1091osinit(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
1122extern int sys_nerr;
1123extern char *sys_errlist[];
1124char *
1125xstrerror(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
1144int
1145xgethostname(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 */
1185int
1186xnice(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
1197static 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 */
1215char *
1216xgetcwd(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
1287fail:
1288    serrno = errno;
1289    (void) chdir(strnrcpy(".", pnptr, pnptr - pathbuf));
1290    errno = serrno;
1291    return NULL;
1292}
1293
1294# else /* ! hp9000s500 */
1295
1296
1297char *
1298xgetcwd(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 */
1416static char *
1417strnrcpy(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
1439static char *
1440apperr(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
1456static int
1457llib(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*/
1469void
1470doinlib(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
1484int
1485getv(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*/
1499void
1500dover(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 */
1523typedef short enum {
1524	name_$wdir_type,
1525	name_$ndir_type,
1526	name_$node_dir_type,
1527} name_$dir_type_t;
1528
1529/*ARGSUSED*/
1530void
1531dorootnode(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
1554int
1555isapad(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>
1589char *
1590cygwin_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