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 34 static int renum (int, int); 35 static Char **blkend (Char **); 36 static Char **blkcat (Char **, Char **); 37 static int xdup2 (int, int); 38 39 /* 40 * C Shell 41 */ 42 43 int 44 any(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 54 void 55 setzero(void *p, size_t size) 56 { 57 memset(p, 0, size); 58 } 59 60 #ifndef SHORT_STRINGS 61 char * 62 strnsave(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 73 char * 74 strsave(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 87 static Char ** 88 blkend(Char **up) 89 { 90 91 while (*up) 92 up++; 93 return (up); 94 } 95 96 97 void 98 blkpr(Char *const *av) 99 { 100 101 for (; *av; av++) { 102 xprintf("%S", *av); 103 if (av[1]) 104 xprintf(" "); 105 } 106 } 107 108 Char * 109 blkexpand(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 121 int 122 blklen(Char **av) 123 { 124 int i = 0; 125 126 while (*av++) 127 i++; 128 return (i); 129 } 130 131 Char ** 132 blkcpy(Char **oav, Char **bv) 133 { 134 Char **av = oav; 135 136 while ((*av++ = *bv++) != NULL) 137 continue; 138 return (oav); 139 } 140 141 static Char ** 142 blkcat(Char **up, Char **vp) 143 { 144 145 (void) blkcpy(blkend(up), vp); 146 return (up); 147 } 148 149 void 150 blkfree(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 161 void 162 blk_cleanup(void *ptr) 163 { 164 blkfree(ptr); 165 } 166 167 void 168 blk_indirect_cleanup(void *xptr) 169 { 170 Char ***ptr; 171 172 ptr = xptr; 173 blkfree(*ptr); 174 xfree(ptr); 175 } 176 177 Char ** 178 saveblk(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 193 char * 194 strstr(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 209 char * 210 strspl(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 227 Char ** 228 blkspl(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 236 Char 237 lastchr(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 */ 253 void 254 closem(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 */ 309 void 310 closech(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 330 void 331 donefds(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 */ 353 int 354 dmove(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 373 int 374 dcopy(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 390 static int 391 renum(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 */ 412 void 413 lshift(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 422 int 423 number(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 438 Char ** 439 copyblk(Char **v) 440 { 441 Char **nv = xcalloc(blklen(v) + 1, sizeof(Char **)); 442 443 return (blkcpy(nv, v)); 444 } 445 446 char * 447 strend(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 456 Char * 457 strip(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 473 Char * 474 quote(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 494 const Char * 495 quote_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 507 void 508 udvar(Char *name) 509 { 510 setname(short2str(name)); 511 stderror(ERR_NAME | ERR_UNDVAR); 512 } 513 514 int 515 prefix(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 528 char * 529 areadlink(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 573 void 574 xclose(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 583 void 584 xclosedir(DIR *dirp) 585 { 586 while (closedir(dirp) == -1 && errno == EINTR) 587 if (handle_pending_signals()) 588 break; 589 } 590 591 int 592 xcreat(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 603 static int 604 xdup2(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 615 struct group * 616 xgetgrgid(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 629 struct passwd * 630 xgetpwnam(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 643 struct passwd * 644 xgetpwuid(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 657 int 658 xopen(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 683 ssize_t 684 xread(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 698 int 699 xtcsetattr(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 711 ssize_t 712 xwrite(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