1 /* $Header: /p/tcsh/cvsroot/tcsh/sh.misc.c,v 3.46 2010/05/08 00:41:58 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.46 2010/05/08 00:41:58 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++ &= TRIM) != '\0') 454 continue; 455 return (cp); 456 } 457 458 Char * 459 quote(Char *cp) 460 { 461 Char *dp = cp; 462 463 if (!cp) 464 return (cp); 465 while (*dp != '\0') 466 *dp++ |= QUOTE; 467 return (cp); 468 } 469 470 const Char * 471 quote_meta(struct Strbuf *buf, const Char *s) 472 { 473 buf->len = 0; 474 while (*s != '\0') { 475 if (cmap(*s, _META | _DOL | _QF | _QB | _ESC | _GLOB)) 476 Strbuf_append1(buf, '\\'); 477 Strbuf_append1(buf, *s++); 478 } 479 Strbuf_terminate(buf); 480 return buf->s; 481 } 482 483 void 484 udvar(Char *name) 485 { 486 setname(short2str(name)); 487 stderror(ERR_NAME | ERR_UNDVAR); 488 } 489 490 int 491 prefix(const Char *sub, const Char *str) 492 { 493 494 for (;;) { 495 if (*sub == 0) 496 return (1); 497 if (*str == 0) 498 return (0); 499 if ((*sub++ & TRIM) != (*str++ & TRIM)) 500 return (0); 501 } 502 } 503 #ifndef WINNT_NATIVE 504 char * 505 areadlink(const char *path) 506 { 507 char *buf; 508 size_t size; 509 ssize_t res; 510 511 size = MAXPATHLEN + 1; 512 buf = xmalloc(size); 513 while ((size_t)(res = readlink(path, buf, size)) == size) { 514 size *= 2; 515 buf = xrealloc(buf, size); 516 } 517 if (res == -1) { 518 int err; 519 520 err = errno; 521 xfree(buf); 522 errno = err; 523 return NULL; 524 } 525 buf[res] = '\0'; 526 return xrealloc(buf, res + 1); 527 } 528 #endif /*!WINNT_NATIVE*/ 529 530 void 531 xclose(int fildes) 532 { 533 if (fildes < 0) 534 return; 535 while (close(fildes) == -1 && errno == EINTR) 536 handle_pending_signals(); 537 } 538 539 void 540 xclosedir(DIR *dirp) 541 { 542 while (closedir(dirp) == -1 && errno == EINTR) 543 handle_pending_signals(); 544 } 545 546 int 547 xcreat(const char *path, mode_t mode) 548 { 549 int res; 550 551 while ((res = creat(path, mode)) == -1 && errno == EINTR) 552 handle_pending_signals(); 553 return res; 554 } 555 556 #ifdef HAVE_DUP2 557 static int 558 xdup2(int fildes, int fildes2) 559 { 560 int res; 561 562 while ((res = dup2(fildes, fildes2)) == -1 && errno == EINTR) 563 handle_pending_signals(); 564 return res; 565 } 566 #endif 567 568 struct group * 569 xgetgrgid(gid_t xgid) 570 { 571 struct group *res; 572 573 errno = 0; 574 while ((res = getgrgid(xgid)) == NULL && errno == EINTR) { 575 handle_pending_signals(); 576 errno = 0; 577 } 578 return res; 579 } 580 581 struct passwd * 582 xgetpwnam(const char *name) 583 { 584 struct passwd *res; 585 586 errno = 0; 587 while ((res = getpwnam(name)) == NULL && errno == EINTR) { 588 handle_pending_signals(); 589 errno = 0; 590 } 591 return res; 592 } 593 594 struct passwd * 595 xgetpwuid(uid_t xuid) 596 { 597 struct passwd *res; 598 599 errno = 0; 600 while ((res = getpwuid(xuid)) == NULL && errno == EINTR) { 601 handle_pending_signals(); 602 errno = 0; 603 } 604 return res; 605 } 606 607 int 608 xopen(const char *path, int oflag, ...) 609 { 610 int res; 611 612 if ((oflag & O_CREAT) == 0) { 613 while ((res = open(path, oflag)) == -1 && errno == EINTR) 614 handle_pending_signals(); 615 } else { 616 va_list ap; 617 mode_t mode; 618 619 va_start(ap, oflag); 620 /* "int" should actually be "mode_t after default argument 621 promotions". "int" is the best guess we have, "mode_t" used to be 622 "unsigned short", which we obviously can't use. */ 623 mode = va_arg(ap, int); 624 va_end(ap); 625 while ((res = open(path, oflag, mode)) == -1 && errno == EINTR) 626 handle_pending_signals(); 627 } 628 return res; 629 } 630 631 ssize_t 632 xread(int fildes, void *buf, size_t nbyte) 633 { 634 ssize_t res; 635 636 /* This is where we will be blocked most of the time, so handle signals 637 that didn't interrupt any system call. */ 638 do 639 handle_pending_signals(); 640 while ((res = read(fildes, buf, nbyte)) == -1 && errno == EINTR); 641 return res; 642 } 643 644 #ifdef POSIX 645 int 646 xtcsetattr(int fildes, int optional_actions, const struct termios *termios_p) 647 { 648 int res; 649 650 while ((res = tcsetattr(fildes, optional_actions, termios_p)) == -1 && 651 errno == EINTR) 652 handle_pending_signals(); 653 return res; 654 } 655 #endif 656 657 ssize_t 658 xwrite(int fildes, const void *buf, size_t nbyte) 659 { 660 ssize_t res; 661 662 /* This is where we will be blocked most of the time, so handle signals 663 that didn't interrupt any system call. */ 664 do 665 handle_pending_signals(); 666 while ((res = write(fildes, buf, nbyte)) == -1 && errno == EINTR); 667 return res; 668 } 669