xref: /freebsd/contrib/tcsh/sh.misc.c (revision 1c05a6ea6b849ff95e539c31adea887c644a6a01)
1 /* $Header: /p/tcsh/cvsroot/tcsh/sh.misc.c,v 3.50 2015/06/06 21:19:08 christos Exp $ */
2 /*
3  * sh.misc.c: Miscelaneous functions
4  */
5 /*-
6  * Copyright (c) 1980, 1991 The Regents of the University of California.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33 #include "sh.h"
34 
35 RCSID("$tcsh: sh.misc.c,v 3.50 2015/06/06 21:19:08 christos Exp $")
36 
37 static	int	renum	(int, int);
38 static  Char  **blkend	(Char **);
39 static  Char  **blkcat	(Char **, Char **);
40 static	int	xdup2	(int, int);
41 
42 /*
43  * C Shell
44  */
45 
46 int
47 any(const char *s, Char c)
48 {
49     if (!s)
50 	return (0);		/* Check for nil pointer */
51     while (*s)
52 	if ((Char)*s++ == c)
53 	    return (1);
54     return (0);
55 }
56 
57 void
58 setzero(void *p, size_t size)
59 {
60     memset(p, 0, size);
61 }
62 
63 #ifndef SHORT_STRINGS
64 char *
65 strnsave(const char *s, size_t len)
66 {
67     char *r;
68 
69     r = xmalloc(len + 1);
70     memcpy(r, s, len);
71     r[len] = '\0';
72     return r;
73 }
74 #endif
75 
76 char   *
77 strsave(const char *s)
78 {
79     char   *r;
80     size_t size;
81 
82     if (s == NULL)
83 	s = "";
84     size = strlen(s) + 1;
85     r = xmalloc(size);
86     memcpy(r, s, size);
87     return (r);
88 }
89 
90 static Char  **
91 blkend(Char **up)
92 {
93 
94     while (*up)
95 	up++;
96     return (up);
97 }
98 
99 
100 void
101 blkpr(Char *const *av)
102 {
103 
104     for (; *av; av++) {
105 	xprintf("%S", *av);
106 	if (av[1])
107 	    xprintf(" ");
108     }
109 }
110 
111 Char *
112 blkexpand(Char *const *av)
113 {
114     struct Strbuf buf = Strbuf_INIT;
115 
116     for (; *av; av++) {
117 	Strbuf_append(&buf, *av);
118 	if (av[1])
119 	    Strbuf_append1(&buf, ' ');
120     }
121     return Strbuf_finish(&buf);
122 }
123 
124 int
125 blklen(Char **av)
126 {
127     int i = 0;
128 
129     while (*av++)
130 	i++;
131     return (i);
132 }
133 
134 Char  **
135 blkcpy(Char **oav, Char **bv)
136 {
137     Char **av = oav;
138 
139     while ((*av++ = *bv++) != NULL)
140 	continue;
141     return (oav);
142 }
143 
144 static Char  **
145 blkcat(Char **up, Char **vp)
146 {
147 
148     (void) blkcpy(blkend(up), vp);
149     return (up);
150 }
151 
152 void
153 blkfree(Char **av0)
154 {
155     Char **av = av0;
156 
157     if (!av0)
158 	return;
159     for (; *av; av++)
160 	xfree(*av);
161     xfree(av0);
162 }
163 
164 void
165 blk_cleanup(void *ptr)
166 {
167     blkfree(ptr);
168 }
169 
170 void
171 blk_indirect_cleanup(void *xptr)
172 {
173     Char ***ptr;
174 
175     ptr = xptr;
176     blkfree(*ptr);
177     xfree(ptr);
178 }
179 
180 Char  **
181 saveblk(Char **v)
182 {
183     Char **newv, **onewv;
184 
185     if (v == NULL)
186 	return NULL;
187 
188     onewv = newv = xcalloc(blklen(v) + 1, sizeof(Char **));
189 
190     while (*v)
191 	*newv++ = Strsave(*v++);
192     return (onewv);
193 }
194 
195 #ifndef HAVE_STRSTR
196 char   *
197 strstr(const char *s, const char *t)
198 {
199     do {
200 	const char *ss = s;
201 	const char *tt = t;
202 
203 	do
204 	    if (*tt == '\0')
205 		return (s);
206 	while (*ss++ == *tt++);
207     } while (*s++ != '\0');
208     return (NULL);
209 }
210 #endif /* !HAVE_STRSTR */
211 
212 char   *
213 strspl(const char *cp, const char *dp)
214 {
215     char   *ep;
216     size_t cl, dl;
217 
218     if (!cp)
219 	cp = "";
220     if (!dp)
221 	dp = "";
222     cl = strlen(cp);
223     dl = strlen(dp);
224     ep = xmalloc((cl + dl + 1) * sizeof(char));
225     memcpy(ep, cp, cl);
226     memcpy(ep + cl, dp, dl + 1);
227     return (ep);
228 }
229 
230 Char  **
231 blkspl(Char **up, Char **vp)
232 {
233     Char **wp = xcalloc(blklen(up) + blklen(vp) + 1, sizeof(Char **));
234 
235     (void) blkcpy(wp, up);
236     return (blkcat(wp, vp));
237 }
238 
239 Char
240 lastchr(Char *cp)
241 {
242 
243     if (!cp)
244 	return (0);
245     if (!*cp)
246 	return (0);
247     while (cp[1])
248 	cp++;
249     return (*cp);
250 }
251 
252 /*
253  * This routine is called after an error to close up
254  * any units which may have been left open accidentally.
255  */
256 void
257 closem(void)
258 {
259     int f, num_files;
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 	    )
278 	  {
279 	    xclose(f);
280 #ifdef NISPLUS
281 	    if(f < 3)
282 		(void) xopen(_PATH_DEVNULL, O_RDONLY|O_LARGEFILE);
283 #endif /* NISPLUS */
284 	  }
285 #ifdef NLS_BUGS
286 #ifdef NLS_CATALOGS
287     nlsinit();
288 #endif /* NLS_CATALOGS */
289 #endif /* NLS_BUGS */
290 }
291 
292 #ifndef CLOSE_ON_EXEC
293 /*
294  * Close files before executing a file.
295  * We could be MUCH more intelligent, since (on a version 7 system)
296  * we need only close files here during a source, the other
297  * shell fd's being in units 16-19 which are closed automatically!
298  */
299 void
300 closech(void)
301 {
302     int f, num_files;
303 
304     if (didcch)
305 	return;
306     didcch = 1;
307     SHIN = 0;
308     SHOUT = 1;
309     SHDIAG = 2;
310     OLDSTD = 0;
311     isoutatty = isatty(SHOUT);
312     isdiagatty = isatty(SHDIAG);
313     num_files = NOFILE;
314     for (f = 3; f < num_files; f++)
315 	xclose(f);
316 }
317 
318 #endif /* CLOSE_ON_EXEC */
319 
320 void
321 donefds(void)
322 {
323 
324     xclose(0);
325     xclose(1);
326     xclose(2);
327     didfds = 0;
328 #ifdef NISPLUS
329     {
330 	int fd = xopen(_PATH_DEVNULL, O_RDONLY|O_LARGEFILE);
331 	(void)dcopy(fd, 1);
332 	(void)dcopy(fd, 2);
333 	(void)dmove(fd, 0);
334     }
335 #endif /*NISPLUS*/
336 }
337 
338 /*
339  * Move descriptor i to j.
340  * If j is -1 then we just want to get i to a safe place,
341  * i.e. to a unit > FSAFE.  This also happens in dcopy.
342  */
343 int
344 dmove(int i, int j)
345 {
346 
347     if (i == j || i < 0)
348 	return (i);
349 #ifdef HAVE_DUP2
350     if (j >= 0) {
351 	(void) xdup2(i, j);
352 	if (j != i)
353 	    xclose(i);
354 	return (j);
355     }
356 #endif
357     j = dcopy(i, j);
358     if (j != i)
359 	xclose(i);
360     return (j);
361 }
362 
363 int
364 dcopy(int i, int j)
365 {
366 
367     if (i == j || i < 0 || (j < 0 && i > FSAFE))
368 	return (i);
369     if (j >= 0) {
370 #ifdef HAVE_DUP2
371 	(void) xdup2(i, j);
372 	return (j);
373 #else
374 	xclose(j);
375 #endif
376     }
377     return (renum(i, j));
378 }
379 
380 static int
381 renum(int i, int j)
382 {
383     int k = dup(i);
384 
385     if (k < 0)
386 	return (-1);
387     if (j == -1 && k > FSAFE)
388 	return (k);
389     if (k != j) {
390 	j = renum(k, j);
391 	xclose(k);
392 	return (j);
393     }
394     return (k);
395 }
396 
397 /*
398  * Left shift a command argument list, discarding
399  * the first c arguments.  Used in "shift" commands
400  * as well as by commands like "repeat".
401  */
402 void
403 lshift(Char **v, int c)
404 {
405     Char **u;
406 
407     for (u = v; *u && --c >= 0; u++)
408 	xfree(*u);
409     (void) blkcpy(v, u);
410 }
411 
412 int
413 number(Char *cp)
414 {
415     if (!cp)
416 	return (0);
417     if (*cp == '-') {
418 	cp++;
419 	if (!Isdigit(*cp))
420 	    return (0);
421 	cp++;
422     }
423     while (*cp && Isdigit(*cp))
424 	cp++;
425     return (*cp == 0);
426 }
427 
428 Char  **
429 copyblk(Char **v)
430 {
431     Char **nv = xcalloc(blklen(v) + 1, sizeof(Char **));
432 
433     return (blkcpy(nv, v));
434 }
435 
436 char   *
437 strend(const char *cp)
438 {
439     if (!cp)
440 	return ((char *)(intptr_t)cp);
441     while (*cp)
442 	cp++;
443     return ((char *)(intptr_t)cp);
444 }
445 
446 Char   *
447 strip(Char *cp)
448 {
449     Char *dp = cp;
450 
451     if (!cp)
452 	return (cp);
453     while (*dp != '\0') {
454 #if INVALID_BYTE != 0
455 	if ((*dp & INVALID_BYTE) != INVALID_BYTE)    /* *dp < INVALID_BYTE */
456 #endif
457 		*dp &= TRIM;
458 	dp++;
459     }
460     return (cp);
461 }
462 
463 Char   *
464 quote(Char *cp)
465 {
466     Char *dp = cp;
467 
468     if (!cp)
469 	return (cp);
470     while (*dp != '\0') {
471 #ifdef WIDE_STRINGS
472 	if ((*dp & 0xffffff80) == 0)	/* *dp < 0x80 */
473 #elif defined SHORT_STRINGS
474 	if ((*dp & 0xff80) == 0)	/* *dp < 0x80 */
475 #else
476 	if ((*dp & 0x80) == 0)		/* *dp < 0x80 */
477 #endif
478 	    *dp |= QUOTE;
479 	dp++;
480     }
481     return (cp);
482 }
483 
484 const Char *
485 quote_meta(struct Strbuf *buf, const Char *s)
486 {
487     buf->len = 0;
488     while (*s != '\0') {
489 	if (cmap(*s, _META | _DOL | _QF | _QB | _ESC | _GLOB))
490 	    Strbuf_append1(buf, '\\');
491 	Strbuf_append1(buf, *s++);
492     }
493     Strbuf_terminate(buf);
494     return buf->s;
495 }
496 
497 void
498 udvar(Char *name)
499 {
500     setname(short2str(name));
501     stderror(ERR_NAME | ERR_UNDVAR);
502 }
503 
504 int
505 prefix(const Char *sub, const Char *str)
506 {
507 
508     for (;;) {
509 	if (*sub == 0)
510 	    return (1);
511 	if (*str == 0)
512 	    return (0);
513 	if ((*sub++ & TRIM) != (*str++ & TRIM))
514 	    return (0);
515     }
516 }
517 #ifndef WINNT_NATIVE
518 char *
519 areadlink(const char *path)
520 {
521     char *buf;
522     size_t size;
523     ssize_t res;
524 
525     size = MAXPATHLEN + 1;
526     buf = xmalloc(size);
527     while ((size_t)(res = readlink(path, buf, size)) == size) {
528 	size *= 2;
529 	buf = xrealloc(buf, size);
530     }
531     if (res == -1) {
532 	int err;
533 
534 	err = errno;
535 	xfree(buf);
536 	errno = err;
537 	return NULL;
538     }
539     buf[res] = '\0';
540     return xrealloc(buf, res + 1);
541 }
542 #endif /*!WINNT_NATIVE*/
543 
544 void
545 xclose(int fildes)
546 {
547     if (fildes < 0)
548 	return;
549     while (close(fildes) == -1 && errno == EINTR)
550 	if (handle_pending_signals())
551 	    break;
552 }
553 
554 void
555 xclosedir(DIR *dirp)
556 {
557     while (closedir(dirp) == -1 && errno == EINTR)
558 	if (handle_pending_signals())
559 	    break;
560 }
561 
562 int
563 xcreat(const char *path, mode_t mode)
564 {
565     int res;
566 
567     while ((res = creat(path, mode)) == -1 && errno == EINTR)
568 	if (handle_pending_signals())
569 	    break;
570     return res;
571 }
572 
573 #ifdef HAVE_DUP2
574 static int
575 xdup2(int fildes, int fildes2)
576 {
577     int res;
578 
579     while ((res = dup2(fildes, fildes2)) == -1 && errno == EINTR)
580 	if (handle_pending_signals())
581 	    break;
582     return res;
583 }
584 #endif
585 
586 struct group *
587 xgetgrgid(gid_t xgid)
588 {
589     struct group *res;
590 
591     errno = 0;
592     while ((res = getgrgid(xgid)) == NULL && errno == EINTR) {
593 	if (handle_pending_signals())
594 	    break;
595 	errno = 0;
596     }
597     return res;
598 }
599 
600 struct passwd *
601 xgetpwnam(const char *name)
602 {
603     struct passwd *res;
604 
605     errno = 0;
606     while ((res = getpwnam(name)) == NULL && errno == EINTR) {
607 	if (handle_pending_signals())
608 	    break;
609 	errno = 0;
610     }
611     return res;
612 }
613 
614 struct passwd *
615 xgetpwuid(uid_t xuid)
616 {
617     struct passwd *res;
618 
619     errno = 0;
620     while ((res = getpwuid(xuid)) == NULL && errno == EINTR) {
621 	if (handle_pending_signals())
622 	    break;
623 	errno = 0;
624     }
625     return res;
626 }
627 
628 int
629 xopen(const char *path, int oflag, ...)
630 {
631     int res;
632 
633     if ((oflag & O_CREAT) == 0) {
634 	while ((res = open(path, oflag)) == -1 && errno == EINTR)
635 	    if (handle_pending_signals())
636 		break;
637     } else {
638 	va_list ap;
639 	mode_t mode;
640 
641 	va_start(ap, oflag);
642 	/* "int" should actually be "mode_t after default argument
643 	   promotions". "int" is the best guess we have, "mode_t" used to be
644 	   "unsigned short", which we obviously can't use. */
645 	mode = va_arg(ap, int);
646 	va_end(ap);
647 	while ((res = open(path, oflag, mode)) == -1 && errno == EINTR)
648 	    if (handle_pending_signals())
649 		break;
650     }
651     return res;
652 }
653 
654 ssize_t
655 xread(int fildes, void *buf, size_t nbyte)
656 {
657     ssize_t res;
658 
659     /* This is where we will be blocked most of the time, so handle signals
660        that didn't interrupt any system call. */
661     do
662       if (handle_pending_signals())
663 	  break;
664     while ((res = read(fildes, buf, nbyte)) == -1 && errno == EINTR);
665     return res;
666 }
667 
668 #ifdef POSIX
669 int
670 xtcsetattr(int fildes, int optional_actions, const struct termios *termios_p)
671 {
672     int res;
673 
674     while ((res = tcsetattr(fildes, optional_actions, termios_p)) == -1 &&
675 	   errno == EINTR)
676 	if (handle_pending_signals())
677 	    break;
678     return res;
679 }
680 #endif
681 
682 ssize_t
683 xwrite(int fildes, const void *buf, size_t nbyte)
684 {
685     ssize_t res;
686 
687     /* This is where we will be blocked most of the time, so handle signals
688        that didn't interrupt any system call. */
689     do
690       if (handle_pending_signals())
691 	  break;
692     while ((res = write(fildes, buf, nbyte)) == -1 && errno == EINTR);
693     return res;
694 }
695