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