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