1 /* $Header: /p/tcsh/cvsroot/tcsh/sh.misc.c,v 3.45 2006/10/14 17:57:21 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.45 2006/10/14 17:57:21 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 char * 64 strnsave(const char *s, size_t len) 65 { 66 char *r; 67 68 r = xmalloc(len + 1); 69 memcpy(r, s, len); 70 r[len] = '\0'; 71 return r; 72 } 73 74 char * 75 strsave(const char *s) 76 { 77 char *r; 78 size_t size; 79 80 if (s == NULL) 81 s = ""; 82 size = strlen(s) + 1; 83 r = xmalloc(size); 84 memcpy(r, s, size); 85 return (r); 86 } 87 88 static Char ** 89 blkend(Char **up) 90 { 91 92 while (*up) 93 up++; 94 return (up); 95 } 96 97 98 void 99 blkpr(Char *const *av) 100 { 101 102 for (; *av; av++) { 103 xprintf("%S", *av); 104 if (av[1]) 105 xprintf(" "); 106 } 107 } 108 109 Char * 110 blkexpand(Char *const *av) 111 { 112 struct Strbuf buf = Strbuf_INIT; 113 114 for (; *av; av++) { 115 Strbuf_append(&buf, *av); 116 if (av[1]) 117 Strbuf_append1(&buf, ' '); 118 } 119 return Strbuf_finish(&buf); 120 } 121 122 int 123 blklen(Char **av) 124 { 125 int i = 0; 126 127 while (*av++) 128 i++; 129 return (i); 130 } 131 132 Char ** 133 blkcpy(Char **oav, Char **bv) 134 { 135 Char **av = oav; 136 137 while ((*av++ = *bv++) != NULL) 138 continue; 139 return (oav); 140 } 141 142 static Char ** 143 blkcat(Char **up, Char **vp) 144 { 145 146 (void) blkcpy(blkend(up), vp); 147 return (up); 148 } 149 150 void 151 blkfree(Char **av0) 152 { 153 Char **av = av0; 154 155 if (!av0) 156 return; 157 for (; *av; av++) 158 xfree(*av); 159 xfree(av0); 160 } 161 162 void 163 blk_cleanup(void *ptr) 164 { 165 blkfree(ptr); 166 } 167 168 void 169 blk_indirect_cleanup(void *xptr) 170 { 171 Char ***ptr; 172 173 ptr = xptr; 174 blkfree(*ptr); 175 xfree(ptr); 176 } 177 178 Char ** 179 saveblk(Char **v) 180 { 181 Char **newv, **onewv; 182 183 if (v == NULL) 184 return NULL; 185 186 onewv = newv = xcalloc(blklen(v) + 1, sizeof(Char **)); 187 188 while (*v) 189 *newv++ = Strsave(*v++); 190 return (onewv); 191 } 192 193 #ifndef HAVE_STRSTR 194 char * 195 strstr(const char *s, const char *t) 196 { 197 do { 198 const char *ss = s; 199 const char *tt = t; 200 201 do 202 if (*tt == '\0') 203 return (s); 204 while (*ss++ == *tt++); 205 } while (*s++ != '\0'); 206 return (NULL); 207 } 208 #endif /* !HAVE_STRSTR */ 209 210 char * 211 strspl(const char *cp, const char *dp) 212 { 213 char *ep; 214 size_t cl, dl; 215 216 if (!cp) 217 cp = ""; 218 if (!dp) 219 dp = ""; 220 cl = strlen(cp); 221 dl = strlen(dp); 222 ep = xmalloc((cl + dl + 1) * sizeof(char)); 223 memcpy(ep, cp, cl); 224 memcpy(ep + cl, dp, dl + 1); 225 return (ep); 226 } 227 228 Char ** 229 blkspl(Char **up, Char **vp) 230 { 231 Char **wp = xcalloc(blklen(up) + blklen(vp) + 1, sizeof(Char **)); 232 233 (void) blkcpy(wp, up); 234 return (blkcat(wp, vp)); 235 } 236 237 Char 238 lastchr(Char *cp) 239 { 240 241 if (!cp) 242 return (0); 243 if (!*cp) 244 return (0); 245 while (cp[1]) 246 cp++; 247 return (*cp); 248 } 249 250 /* 251 * This routine is called after an error to close up 252 * any units which may have been left open accidentally. 253 */ 254 void 255 closem(void) 256 { 257 int f, num_files; 258 259 #ifdef NLS_BUGS 260 #ifdef NLS_CATALOGS 261 nlsclose(); 262 #endif /* NLS_CATALOGS */ 263 #endif /* NLS_BUGS */ 264 #ifdef YPBUGS 265 /* suggested by Justin Bur; thanks to Karl Kleinpaste */ 266 fix_yp_bugs(); 267 #endif /* YPBUGS */ 268 num_files = NOFILE; 269 for (f = 0; f < num_files; f++) 270 if (f != SHIN && f != SHOUT && f != SHDIAG && f != OLDSTD && 271 f != FSHTTY 272 #ifdef MALLOC_TRACE 273 && f != 25 274 #endif /* MALLOC_TRACE */ 275 ) 276 { 277 xclose(f); 278 #ifdef NISPLUS 279 if(f < 3) 280 (void) xopen(_PATH_DEVNULL, O_RDONLY|O_LARGEFILE); 281 #endif /* NISPLUS */ 282 } 283 #ifdef NLS_BUGS 284 #ifdef NLS_CATALOGS 285 nlsinit(); 286 #endif /* NLS_CATALOGS */ 287 #endif /* NLS_BUGS */ 288 } 289 290 #ifndef CLOSE_ON_EXEC 291 /* 292 * Close files before executing a file. 293 * We could be MUCH more intelligent, since (on a version 7 system) 294 * we need only close files here during a source, the other 295 * shell fd's being in units 16-19 which are closed automatically! 296 */ 297 void 298 closech(void) 299 { 300 int f, num_files; 301 302 if (didcch) 303 return; 304 didcch = 1; 305 SHIN = 0; 306 SHOUT = 1; 307 SHDIAG = 2; 308 OLDSTD = 0; 309 isoutatty = isatty(SHOUT); 310 isdiagatty = isatty(SHDIAG); 311 num_files = NOFILE; 312 for (f = 3; f < num_files; f++) 313 xclose(f); 314 } 315 316 #endif /* CLOSE_ON_EXEC */ 317 318 void 319 donefds(void) 320 { 321 322 xclose(0); 323 xclose(1); 324 xclose(2); 325 didfds = 0; 326 #ifdef NISPLUS 327 { 328 int fd = xopen(_PATH_DEVNULL, O_RDONLY|O_LARGEFILE); 329 (void)dcopy(fd, 1); 330 (void)dcopy(fd, 2); 331 (void)dmove(fd, 0); 332 } 333 #endif /*NISPLUS*/ 334 } 335 336 /* 337 * Move descriptor i to j. 338 * If j is -1 then we just want to get i to a safe place, 339 * i.e. to a unit > FSAFE. This also happens in dcopy. 340 */ 341 int 342 dmove(int i, int j) 343 { 344 345 if (i == j || i < 0) 346 return (i); 347 #ifdef HAVE_DUP2 348 if (j >= 0) { 349 (void) xdup2(i, j); 350 if (j != i) 351 xclose(i); 352 return (j); 353 } 354 #endif 355 j = dcopy(i, j); 356 if (j != i) 357 xclose(i); 358 return (j); 359 } 360 361 int 362 dcopy(int i, int j) 363 { 364 365 if (i == j || i < 0 || (j < 0 && i > FSAFE)) 366 return (i); 367 if (j >= 0) { 368 #ifdef HAVE_DUP2 369 (void) xdup2(i, j); 370 return (j); 371 #else 372 xclose(j); 373 #endif 374 } 375 return (renum(i, j)); 376 } 377 378 static int 379 renum(int i, int j) 380 { 381 int k = dup(i); 382 383 if (k < 0) 384 return (-1); 385 if (j == -1 && k > FSAFE) 386 return (k); 387 if (k != j) { 388 j = renum(k, j); 389 xclose(k); 390 return (j); 391 } 392 return (k); 393 } 394 395 /* 396 * Left shift a command argument list, discarding 397 * the first c arguments. Used in "shift" commands 398 * as well as by commands like "repeat". 399 */ 400 void 401 lshift(Char **v, int c) 402 { 403 Char **u; 404 405 for (u = v; *u && --c >= 0; u++) 406 xfree(*u); 407 (void) blkcpy(v, u); 408 } 409 410 int 411 number(Char *cp) 412 { 413 if (!cp) 414 return (0); 415 if (*cp == '-') { 416 cp++; 417 if (!Isdigit(*cp)) 418 return (0); 419 cp++; 420 } 421 while (*cp && Isdigit(*cp)) 422 cp++; 423 return (*cp == 0); 424 } 425 426 Char ** 427 copyblk(Char **v) 428 { 429 Char **nv = xcalloc(blklen(v) + 1, sizeof(Char **)); 430 431 return (blkcpy(nv, v)); 432 } 433 434 char * 435 strend(const char *cp) 436 { 437 if (!cp) 438 return ((char *)(intptr_t)cp); 439 while (*cp) 440 cp++; 441 return ((char *)(intptr_t)cp); 442 } 443 444 Char * 445 strip(Char *cp) 446 { 447 Char *dp = cp; 448 449 if (!cp) 450 return (cp); 451 while ((*dp++ &= TRIM) != '\0') 452 continue; 453 return (cp); 454 } 455 456 Char * 457 quote(Char *cp) 458 { 459 Char *dp = cp; 460 461 if (!cp) 462 return (cp); 463 while (*dp != '\0') 464 *dp++ |= QUOTE; 465 return (cp); 466 } 467 468 const Char * 469 quote_meta(struct Strbuf *buf, const Char *s) 470 { 471 buf->len = 0; 472 while (*s != '\0') { 473 if (cmap(*s, _META | _DOL | _QF | _QB | _ESC | _GLOB)) 474 Strbuf_append1(buf, '\\'); 475 Strbuf_append1(buf, *s++); 476 } 477 Strbuf_terminate(buf); 478 return buf->s; 479 } 480 481 void 482 udvar(Char *name) 483 { 484 setname(short2str(name)); 485 stderror(ERR_NAME | ERR_UNDVAR); 486 } 487 488 int 489 prefix(const Char *sub, const Char *str) 490 { 491 492 for (;;) { 493 if (*sub == 0) 494 return (1); 495 if (*str == 0) 496 return (0); 497 if ((*sub++ & TRIM) != (*str++ & TRIM)) 498 return (0); 499 } 500 } 501 #ifndef WINNT_NATIVE 502 char * 503 areadlink(const char *path) 504 { 505 char *buf; 506 size_t size; 507 ssize_t res; 508 509 size = MAXPATHLEN + 1; 510 buf = xmalloc(size); 511 while ((size_t)(res = readlink(path, buf, size)) == size) { 512 size *= 2; 513 buf = xrealloc(buf, size); 514 } 515 if (res == -1) { 516 int err; 517 518 err = errno; 519 xfree(buf); 520 errno = err; 521 return NULL; 522 } 523 buf[res] = '\0'; 524 return xrealloc(buf, res + 1); 525 } 526 #endif /*!WINNT_NATIVE*/ 527 528 void 529 xclose(int fildes) 530 { 531 if (fildes < 0) 532 return; 533 while (close(fildes) == -1 && errno == EINTR) 534 handle_pending_signals(); 535 } 536 537 void 538 xclosedir(DIR *dirp) 539 { 540 while (closedir(dirp) == -1 && errno == EINTR) 541 handle_pending_signals(); 542 } 543 544 int 545 xcreat(const char *path, mode_t mode) 546 { 547 int res; 548 549 while ((res = creat(path, mode)) == -1 && errno == EINTR) 550 handle_pending_signals(); 551 return res; 552 } 553 554 #ifdef HAVE_DUP2 555 static int 556 xdup2(int fildes, int fildes2) 557 { 558 int res; 559 560 while ((res = dup2(fildes, fildes2)) == -1 && errno == EINTR) 561 handle_pending_signals(); 562 return res; 563 } 564 #endif 565 566 struct group * 567 xgetgrgid(gid_t xgid) 568 { 569 struct group *res; 570 571 errno = 0; 572 while ((res = getgrgid(xgid)) == NULL && errno == EINTR) { 573 handle_pending_signals(); 574 errno = 0; 575 } 576 return res; 577 } 578 579 struct passwd * 580 xgetpwnam(const char *name) 581 { 582 struct passwd *res; 583 584 errno = 0; 585 while ((res = getpwnam(name)) == NULL && errno == EINTR) { 586 handle_pending_signals(); 587 errno = 0; 588 } 589 return res; 590 } 591 592 struct passwd * 593 xgetpwuid(uid_t xuid) 594 { 595 struct passwd *res; 596 597 errno = 0; 598 while ((res = getpwuid(xuid)) == NULL && errno == EINTR) { 599 handle_pending_signals(); 600 errno = 0; 601 } 602 return res; 603 } 604 605 int 606 xopen(const char *path, int oflag, ...) 607 { 608 int res; 609 610 if ((oflag & O_CREAT) == 0) { 611 while ((res = open(path, oflag)) == -1 && errno == EINTR) 612 handle_pending_signals(); 613 } else { 614 va_list ap; 615 mode_t mode; 616 617 va_start(ap, oflag); 618 /* "int" should actually be "mode_t after default argument 619 promotions". "int" is the best guess we have, "mode_t" used to be 620 "unsigned short", which we obviously can't use. */ 621 mode = va_arg(ap, int); 622 va_end(ap); 623 while ((res = open(path, oflag, mode)) == -1 && errno == EINTR) 624 handle_pending_signals(); 625 } 626 return res; 627 } 628 629 ssize_t 630 xread(int fildes, void *buf, size_t nbyte) 631 { 632 ssize_t res; 633 634 /* This is where we will be blocked most of the time, so handle signals 635 that didn't interrupt any system call. */ 636 do 637 handle_pending_signals(); 638 while ((res = read(fildes, buf, nbyte)) == -1 && errno == EINTR); 639 return res; 640 } 641 642 #ifdef POSIX 643 int 644 xtcsetattr(int fildes, int optional_actions, const struct termios *termios_p) 645 { 646 int res; 647 648 while ((res = tcsetattr(fildes, optional_actions, termios_p)) == -1 && 649 errno == EINTR) 650 handle_pending_signals(); 651 return res; 652 } 653 #endif 654 655 ssize_t 656 xwrite(int fildes, const void *buf, size_t nbyte) 657 { 658 ssize_t res; 659 660 /* This is where we will be blocked most of the time, so handle signals 661 that didn't interrupt any system call. */ 662 do 663 handle_pending_signals(); 664 while ((res = write(fildes, buf, nbyte)) == -1 && errno == EINTR); 665 return res; 666 } 667