1/*
2 * sh.misc.c: Miscelaneous 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
34static	int	renum	(int, int);
35static  Char  **blkend	(Char **);
36static  Char  **blkcat	(Char **, Char **);
37static	int	xdup2	(int, int);
38
39/*
40 * C Shell
41 */
42
43int
44any(const char *s, Char c)
45{
46    if (!s)
47	return (0);		/* Check for nil pointer */
48    while (*s)
49	if ((Char)*s++ == c)
50	    return (1);
51    return (0);
52}
53
54void
55setzero(void *p, size_t size)
56{
57    memset(p, 0, size);
58}
59
60#ifndef SHORT_STRINGS
61char *
62strnsave(const char *s, size_t len)
63{
64    char *r;
65
66    r = xmalloc(len + 1);
67    memcpy(r, s, len);
68    r[len] = '\0';
69    return r;
70}
71#endif
72
73char   *
74strsave(const char *s)
75{
76    char   *r;
77    size_t size;
78
79    if (s == NULL)
80	s = "";
81    size = strlen(s) + 1;
82    r = xmalloc(size);
83    memcpy(r, s, size);
84    return (r);
85}
86
87static Char  **
88blkend(Char **up)
89{
90
91    while (*up)
92	up++;
93    return (up);
94}
95
96
97void
98blkpr(Char *const *av)
99{
100
101    for (; *av; av++) {
102	xprintf("%S", *av);
103	if (av[1])
104	    xprintf(" ");
105    }
106}
107
108Char *
109blkexpand(Char *const *av)
110{
111    struct Strbuf buf = Strbuf_INIT;
112
113    for (; *av; av++) {
114	Strbuf_append(&buf, *av);
115	if (av[1])
116	    Strbuf_append1(&buf, ' ');
117    }
118    return Strbuf_finish(&buf);
119}
120
121int
122blklen(Char **av)
123{
124    int i = 0;
125
126    while (*av++)
127	i++;
128    return (i);
129}
130
131Char  **
132blkcpy(Char **oav, Char **bv)
133{
134    Char **av = oav;
135
136    while ((*av++ = *bv++) != NULL)
137	continue;
138    return (oav);
139}
140
141static Char  **
142blkcat(Char **up, Char **vp)
143{
144
145    (void) blkcpy(blkend(up), vp);
146    return (up);
147}
148
149void
150blkfree(Char **av0)
151{
152    Char **av = av0;
153
154    if (!av0)
155	return;
156    for (; *av; av++)
157	xfree(*av);
158    xfree(av0);
159}
160
161void
162blk_cleanup(void *ptr)
163{
164    blkfree(ptr);
165}
166
167void
168blk_indirect_cleanup(void *xptr)
169{
170    Char ***ptr;
171
172    ptr = xptr;
173    blkfree(*ptr);
174    xfree(ptr);
175}
176
177Char  **
178saveblk(Char **v)
179{
180    Char **newv, **onewv;
181
182    if (v == NULL)
183	return NULL;
184
185    onewv = newv = xcalloc(blklen(v) + 1, sizeof(Char **));
186
187    while (*v)
188	*newv++ = Strsave(*v++);
189    return (onewv);
190}
191
192#ifndef HAVE_STRSTR
193char   *
194strstr(const char *s, const char *t)
195{
196    do {
197	const char *ss = s;
198	const char *tt = t;
199
200	do
201	    if (*tt == '\0')
202		return (s);
203	while (*ss++ == *tt++);
204    } while (*s++ != '\0');
205    return (NULL);
206}
207#endif /* !HAVE_STRSTR */
208
209char   *
210strspl(const char *cp, const char *dp)
211{
212    char   *ep;
213    size_t cl, dl;
214
215    if (!cp)
216	cp = "";
217    if (!dp)
218	dp = "";
219    cl = strlen(cp);
220    dl = strlen(dp);
221    ep = xmalloc((cl + dl + 1) * sizeof(char));
222    memcpy(ep, cp, cl);
223    memcpy(ep + cl, dp, dl + 1);
224    return (ep);
225}
226
227Char  **
228blkspl(Char **up, Char **vp)
229{
230    Char **wp = xcalloc(blklen(up) + blklen(vp) + 1, sizeof(Char **));
231
232    (void) blkcpy(wp, up);
233    return (blkcat(wp, vp));
234}
235
236Char
237lastchr(Char *cp)
238{
239
240    if (!cp)
241	return (0);
242    if (!*cp)
243	return (0);
244    while (cp[1])
245	cp++;
246    return (*cp);
247}
248
249/*
250 * This routine is called after an error to close up
251 * any units which may have been left open accidentally.
252 */
253void
254closem(void)
255{
256    int f, num_files;
257#ifdef S_ISSOCK
258    struct stat st;
259#endif /*S_ISSOCK*/
260
261#ifdef NLS_BUGS
262#ifdef NLS_CATALOGS
263    nlsclose();
264#endif /* NLS_CATALOGS */
265#endif /* NLS_BUGS */
266#ifdef YPBUGS
267    /* suggested by Justin Bur; thanks to Karl Kleinpaste */
268    fix_yp_bugs();
269#endif /* YPBUGS */
270    num_files = NOFILE;
271    for (f = 0; f < num_files; f++)
272	if (f != SHIN && f != SHOUT && f != SHDIAG && f != OLDSTD &&
273	    f != FSHTTY
274#ifdef MALLOC_TRACE
275	    && f != 25
276#endif /* MALLOC_TRACE */
277#ifdef S_ISSOCK
278	    /* NSS modules (e.g. Linux nss_ldap) might keep sockets open.
279	     * If we close such a socket, both the NSS module and tcsh think
280	     * they "own" the descriptor.
281	     *
282	     * Not closing sockets does not make the cleanup use of closem()
283	     * less reliable because tcsh never creates sockets.
284	     */
285	    && fstat(f, &st) == 0 && !S_ISSOCK(st.st_mode)
286#endif
287	    )
288	  {
289	    xclose(f);
290#ifdef NISPLUS
291	    if (f < 3)
292		(void) xopen(_PATH_DEVNULL, O_RDONLY|O_LARGEFILE);
293#endif /* NISPLUS */
294	  }
295#ifdef NLS_BUGS
296#ifdef NLS_CATALOGS
297    nlsinit();
298#endif /* NLS_CATALOGS */
299#endif /* NLS_BUGS */
300}
301
302#ifndef CLOSE_ON_EXEC
303/*
304 * Close files before executing a file.
305 * We could be MUCH more intelligent, since (on a version 7 system)
306 * we need only close files here during a source, the other
307 * shell fd's being in units 16-19 which are closed automatically!
308 */
309void
310closech(void)
311{
312    int f, num_files;
313
314    if (didcch)
315	return;
316    didcch = 1;
317    SHIN = 0;
318    SHOUT = 1;
319    SHDIAG = 2;
320    OLDSTD = 0;
321    isoutatty = isatty(SHOUT);
322    isdiagatty = isatty(SHDIAG);
323    num_files = NOFILE;
324    for (f = 3; f < num_files; f++)
325	xclose(f);
326}
327
328#endif /* CLOSE_ON_EXEC */
329
330void
331donefds(void)
332{
333
334    xclose(0);
335    xclose(1);
336    xclose(2);
337    didfds = 0;
338#ifdef NISPLUS
339    {
340	int fd = xopen(_PATH_DEVNULL, O_RDONLY|O_LARGEFILE);
341	(void)dcopy(fd, 1);
342	(void)dcopy(fd, 2);
343	(void)dmove(fd, 0);
344    }
345#endif /*NISPLUS*/
346}
347
348/*
349 * Move descriptor i to j.
350 * If j is -1 then we just want to get i to a safe place,
351 * i.e. to a unit > FSAFE.  This also happens in dcopy.
352 */
353int
354dmove(int i, int j)
355{
356
357    if (i == j || i < 0)
358	return (i);
359#ifdef HAVE_DUP2
360    if (j >= 0) {
361	(void) xdup2(i, j);
362	if (j != i)
363	    xclose(i);
364	return (j);
365    }
366#endif
367    j = dcopy(i, j);
368    if (j != i)
369	xclose(i);
370    return (j);
371}
372
373int
374dcopy(int i, int j)
375{
376
377    if (i == j || i < 0 || (j < 0 && i > FSAFE))
378	return (i);
379    if (j >= 0) {
380#ifdef HAVE_DUP2
381	(void) xdup2(i, j);
382	return (j);
383#else
384	xclose(j);
385#endif
386    }
387    return (renum(i, j));
388}
389
390static int
391renum(int i, int j)
392{
393    int k = dup(i);
394
395    if (k < 0)
396	return (-1);
397    if (j == -1 && k > FSAFE)
398	return (k);
399    if (k != j) {
400	j = renum(k, j);
401	xclose(k);
402	return (j);
403    }
404    return (k);
405}
406
407/*
408 * Left shift a command argument list, discarding
409 * the first c arguments.  Used in "shift" commands
410 * as well as by commands like "repeat".
411 */
412void
413lshift(Char **v, int c)
414{
415    Char **u;
416
417    for (u = v; *u && --c >= 0; u++)
418	xfree(*u);
419    (void) blkcpy(v, u);
420}
421
422int
423number(Char *cp)
424{
425    if (!cp)
426	return (0);
427    if (*cp == '-') {
428	cp++;
429	if (!Isdigit(*cp))
430	    return (0);
431	cp++;
432    }
433    while (*cp && Isdigit(*cp))
434	cp++;
435    return (*cp == 0);
436}
437
438Char  **
439copyblk(Char **v)
440{
441    Char **nv = xcalloc(blklen(v) + 1, sizeof(Char **));
442
443    return (blkcpy(nv, v));
444}
445
446char   *
447strend(const char *cp)
448{
449    if (!cp)
450	return ((char *)(intptr_t)cp);
451    while (*cp)
452	cp++;
453    return ((char *)(intptr_t)cp);
454}
455
456Char   *
457strip(Char *cp)
458{
459    Char *dp = cp;
460
461    if (!cp)
462	return (cp);
463    while (*dp != '\0') {
464#if INVALID_BYTE != 0
465	if ((*dp & INVALID_BYTE) != INVALID_BYTE)    /* *dp < INVALID_BYTE */
466#endif
467		*dp &= TRIM;
468	dp++;
469    }
470    return (cp);
471}
472
473Char   *
474quote(Char *cp)
475{
476    Char *dp = cp;
477
478    if (!cp)
479	return (cp);
480    while (*dp != '\0') {
481#ifdef WIDE_STRINGS
482	if ((*dp & 0xffffff80) == 0)	/* *dp < 0x80 */
483#elif defined SHORT_STRINGS
484	if ((*dp & 0xff80) == 0)	/* *dp < 0x80 */
485#else
486	if ((*dp & 0x80) == 0)		/* *dp < 0x80 */
487#endif
488	    *dp |= QUOTE;
489	dp++;
490    }
491    return (cp);
492}
493
494const Char *
495quote_meta(struct Strbuf *buf, const Char *s)
496{
497    buf->len = 0;
498    while (*s != '\0') {
499	if (cmap(*s, _META | _DOL | _QF | _QB | _ESC | _GLOB))
500	    Strbuf_append1(buf, '\\');
501	Strbuf_append1(buf, *s++);
502    }
503    Strbuf_terminate(buf);
504    return buf->s;
505}
506
507void
508udvar(Char *name)
509{
510    setname(short2str(name));
511    stderror(ERR_NAME | ERR_UNDVAR);
512}
513
514int
515prefix(const Char *sub, const Char *str)
516{
517
518    for (;;) {
519	if (*sub == 0)
520	    return (1);
521	if (*str == 0)
522	    return (0);
523	if ((*sub++ & TRIM) != (*str++ & TRIM))
524	    return (0);
525    }
526}
527#ifndef WINNT_NATIVE
528char *
529areadlink(const char *path)
530{
531    char *buf;
532    size_t size;
533    ssize_t res;
534#ifdef __IBMC__
535    /*
536     * Prevent infinite recursion. Someone should tell me how to expand
537     * these...
538     */
539    size_t i;
540    static const char *vars[] = {
541	"/$VERSION",
542	"/$SYSNAME",
543	"/$SYSSYMR",
544	"/$SYSSYMA",
545    };
546    for (i = 0; i < sizeof(vars) / sizeof(vars[0]); i++) {
547	if (strcmp(vars[i], path) == 0) {
548	    return NULL;
549	}
550    }
551#endif
552
553
554    size = MAXPATHLEN + 1;
555    buf = xmalloc(size);
556    while ((size_t)(res = readlink(path, buf, size)) == size) {
557	size *= 2;
558	buf = xrealloc(buf, size);
559    }
560    if (res == -1) {
561	int err;
562
563	err = errno;
564	xfree(buf);
565	errno = err;
566	return NULL;
567    }
568    buf[res] = '\0';
569    return xrealloc(buf, res + 1);
570}
571#endif /*!WINNT_NATIVE*/
572
573void
574xclose(int fildes)
575{
576    if (fildes < 0)
577	return;
578    while (close(fildes) == -1 && errno == EINTR)
579	if (handle_pending_signals())
580	    break;
581}
582
583void
584xclosedir(DIR *dirp)
585{
586    while (closedir(dirp) == -1 && errno == EINTR)
587	if (handle_pending_signals())
588	    break;
589}
590
591int
592xcreat(const char *path, mode_t mode)
593{
594    int res;
595
596    while ((res = creat(path, mode)) == -1 && errno == EINTR)
597	if (handle_pending_signals())
598	    break;
599    return res;
600}
601
602#ifdef HAVE_DUP2
603static int
604xdup2(int fildes, int fildes2)
605{
606    int res;
607
608    while ((res = dup2(fildes, fildes2)) == -1 && errno == EINTR)
609	if (handle_pending_signals())
610	    break;
611    return res;
612}
613#endif
614
615struct group *
616xgetgrgid(gid_t xgid)
617{
618    struct group *res;
619
620    errno = 0;
621    while ((res = getgrgid(xgid)) == NULL && errno == EINTR) {
622	if (handle_pending_signals())
623	    break;
624	errno = 0;
625    }
626    return res;
627}
628
629struct passwd *
630xgetpwnam(const char *name)
631{
632    struct passwd *res;
633
634    errno = 0;
635    while ((res = getpwnam(name)) == NULL && errno == EINTR) {
636	if (handle_pending_signals())
637	    break;
638	errno = 0;
639    }
640    return res;
641}
642
643struct passwd *
644xgetpwuid(uid_t xuid)
645{
646    struct passwd *res;
647
648    errno = 0;
649    while ((res = getpwuid(xuid)) == NULL && errno == EINTR) {
650	if (handle_pending_signals())
651	    break;
652	errno = 0;
653    }
654    return res;
655}
656
657int
658xopen(const char *path, int oflag, ...)
659{
660    int res;
661
662    if ((oflag & O_CREAT) == 0) {
663	while ((res = open(path, oflag)) == -1 && errno == EINTR)
664	    if (handle_pending_signals())
665		break;
666    } else {
667	va_list ap;
668	mode_t mode;
669
670	va_start(ap, oflag);
671	/* "int" should actually be "mode_t after default argument
672	   promotions". "int" is the best guess we have, "mode_t" used to be
673	   "unsigned short", which we obviously can't use. */
674	mode = va_arg(ap, int);
675	va_end(ap);
676	while ((res = open(path, oflag, mode)) == -1 && errno == EINTR)
677	    if (handle_pending_signals())
678		break;
679    }
680    return res;
681}
682
683ssize_t
684xread(int fildes, void *buf, size_t nbyte)
685{
686    ssize_t res = -1;
687
688    /* This is where we will be blocked most of the time, so handle signals
689       that didn't interrupt any system call. */
690    do
691      if (handle_pending_signals())
692	  break;
693    while ((res = read(fildes, buf, nbyte)) == -1 && errno == EINTR);
694    return res;
695}
696
697#ifdef POSIX
698int
699xtcsetattr(int fildes, int optional_actions, const struct termios *termios_p)
700{
701    int res;
702
703    while ((res = tcsetattr(fildes, optional_actions, termios_p)) == -1 &&
704	   errno == EINTR)
705	if (handle_pending_signals())
706	    break;
707    return res;
708}
709#endif
710
711ssize_t
712xwrite(int fildes, const void *buf, size_t nbyte)
713{
714    ssize_t res = -1;
715
716    /* This is where we will be blocked most of the time, so handle signals
717       that didn't interrupt any system call. */
718    do
719      if (handle_pending_signals())
720	  break;
721    while ((res = write(fildes, buf, nbyte)) == -1 && errno == EINTR);
722    return res;
723}
724