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