sh.misc.c revision 316958
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 35RCSID("$tcsh: sh.misc.c,v 3.50 2015/06/06 21:19:08 christos Exp $") 36 37static int renum (int, int); 38static Char **blkend (Char **); 39static Char **blkcat (Char **, Char **); 40static int xdup2 (int, int); 41 42/* 43 * C Shell 44 */ 45 46int 47any(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 57void 58setzero(void *p, size_t size) 59{ 60 memset(p, 0, size); 61} 62 63#ifndef SHORT_STRINGS 64char * 65strnsave(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 76char * 77strsave(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 90static Char ** 91blkend(Char **up) 92{ 93 94 while (*up) 95 up++; 96 return (up); 97} 98 99 100void 101blkpr(Char *const *av) 102{ 103 104 for (; *av; av++) { 105 xprintf("%S", *av); 106 if (av[1]) 107 xprintf(" "); 108 } 109} 110 111Char * 112blkexpand(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 124int 125blklen(Char **av) 126{ 127 int i = 0; 128 129 while (*av++) 130 i++; 131 return (i); 132} 133 134Char ** 135blkcpy(Char **oav, Char **bv) 136{ 137 Char **av = oav; 138 139 while ((*av++ = *bv++) != NULL) 140 continue; 141 return (oav); 142} 143 144static Char ** 145blkcat(Char **up, Char **vp) 146{ 147 148 (void) blkcpy(blkend(up), vp); 149 return (up); 150} 151 152void 153blkfree(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 164void 165blk_cleanup(void *ptr) 166{ 167 blkfree(ptr); 168} 169 170void 171blk_indirect_cleanup(void *xptr) 172{ 173 Char ***ptr; 174 175 ptr = xptr; 176 blkfree(*ptr); 177 xfree(ptr); 178} 179 180Char ** 181saveblk(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 196char * 197strstr(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 212char * 213strspl(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 230Char ** 231blkspl(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 239Char 240lastchr(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 */ 256void 257closem(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 */ 299void 300closech(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 320void 321donefds(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 */ 343int 344dmove(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 363int 364dcopy(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 380static int 381renum(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 */ 402void 403lshift(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 412int 413number(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 428Char ** 429copyblk(Char **v) 430{ 431 Char **nv = xcalloc(blklen(v) + 1, sizeof(Char **)); 432 433 return (blkcpy(nv, v)); 434} 435 436char * 437strend(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 446Char * 447strip(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 463Char * 464quote(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 484const Char * 485quote_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 497void 498udvar(Char *name) 499{ 500 setname(short2str(name)); 501 stderror(ERR_NAME | ERR_UNDVAR); 502} 503 504int 505prefix(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 518char * 519areadlink(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 544void 545xclose(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 554void 555xclosedir(DIR *dirp) 556{ 557 while (closedir(dirp) == -1 && errno == EINTR) 558 if (handle_pending_signals()) 559 break; 560} 561 562int 563xcreat(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 574static int 575xdup2(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 586struct group * 587xgetgrgid(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 600struct passwd * 601xgetpwnam(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 614struct passwd * 615xgetpwuid(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 628int 629xopen(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 654ssize_t 655xread(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 669int 670xtcsetattr(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 682ssize_t 683xwrite(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