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
any(const char * s,Char c)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
setzero(void * p,size_t size)58 setzero(void *p, size_t size)
59 {
60 memset(p, 0, size);
61 }
62
63 #ifndef SHORT_STRINGS
64 char *
strnsave(const char * s,size_t len)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 *
strsave(const char * s)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 **
blkend(Char ** up)91 blkend(Char **up)
92 {
93
94 while (*up)
95 up++;
96 return (up);
97 }
98
99
100 void
blkpr(Char * const * av)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 *
blkexpand(Char * const * av)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
blklen(Char ** av)125 blklen(Char **av)
126 {
127 int i = 0;
128
129 while (*av++)
130 i++;
131 return (i);
132 }
133
134 Char **
blkcpy(Char ** oav,Char ** bv)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 **
blkcat(Char ** up,Char ** vp)145 blkcat(Char **up, Char **vp)
146 {
147
148 (void) blkcpy(blkend(up), vp);
149 return (up);
150 }
151
152 void
blkfree(Char ** av0)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
blk_cleanup(void * ptr)165 blk_cleanup(void *ptr)
166 {
167 blkfree(ptr);
168 }
169
170 void
blk_indirect_cleanup(void * xptr)171 blk_indirect_cleanup(void *xptr)
172 {
173 Char ***ptr;
174
175 ptr = xptr;
176 blkfree(*ptr);
177 xfree(ptr);
178 }
179
180 Char **
saveblk(Char ** v)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 *
strstr(const char * s,const char * t)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 *
strspl(const char * cp,const char * dp)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 **
blkspl(Char ** up,Char ** vp)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
lastchr(Char * cp)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
closem(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
closech(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
donefds(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
dmove(int i,int j)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
dcopy(int i,int j)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
renum(int i,int j)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
lshift(Char ** v,int c)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
number(Char * cp)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 **
copyblk(Char ** v)429 copyblk(Char **v)
430 {
431 Char **nv = xcalloc(blklen(v) + 1, sizeof(Char **));
432
433 return (blkcpy(nv, v));
434 }
435
436 char *
strend(const char * cp)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 *
strip(Char * cp)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 *
quote(Char * cp)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 *
quote_meta(struct Strbuf * buf,const Char * s)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
udvar(Char * name)498 udvar(Char *name)
499 {
500 setname(short2str(name));
501 stderror(ERR_NAME | ERR_UNDVAR);
502 }
503
504 int
prefix(const Char * sub,const Char * str)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 *
areadlink(const char * path)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
xclose(int fildes)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
xclosedir(DIR * dirp)555 xclosedir(DIR *dirp)
556 {
557 while (closedir(dirp) == -1 && errno == EINTR)
558 if (handle_pending_signals())
559 break;
560 }
561
562 int
xcreat(const char * path,mode_t mode)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
xdup2(int fildes,int fildes2)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 *
xgetgrgid(gid_t xgid)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 *
xgetpwnam(const char * name)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 *
xgetpwuid(uid_t xuid)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
xopen(const char * path,int oflag,...)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
xread(int fildes,void * buf,size_t nbyte)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
xtcsetattr(int fildes,int optional_actions,const struct termios * termios_p)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
xwrite(int fildes,const void * buf,size_t nbyte)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