1 /* $OpenBSD: history.c,v 1.39 2010/05/19 17:36:08 jasper Exp $ */ 2 /* $OpenBSD: trap.c,v 1.23 2010/05/19 17:36:08 jasper Exp $ */ 3 4 /*- 5 * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 6 * 2011, 2012, 2014 7 * Thorsten Glaser <tg (at) mirbsd.org> 8 * 9 * Provided that these terms and disclaimer and all copyright notices 10 * are retained or reproduced in an accompanying document, permission 11 * is granted to deal in this work without restriction, including un- 12 * limited rights to use, publicly perform, distribute, sell, modify, 13 * merge, give away, or sublicence. 14 * 15 * This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to 16 * the utmost extent permitted by applicable law, neither express nor 17 * implied; without malicious intent or gross negligence. In no event 18 * may a licensor, author or contributor be held liable for indirect, 19 * direct, other damage, loss, or other issues arising in any way out 20 * of dealing in the work, even if advised of the possibility of such 21 * damage or existence of a defect, except proven that it results out 22 * of said person's immediate fault when using the work as intended. 23 */ 24 25 #include "sh.h" 26 #if HAVE_SYS_FILE_H 27 #include <sys/file.h> 28 #endif 29 30 __RCSID("$MirOS: src/bin/mksh/histrap.c,v 1.134 2014/06/09 13:25:53 tg Exp $"); 31 32 Trap sigtraps[NSIG + 1]; 33 static struct sigaction Sigact_ign; 34 35 #if HAVE_PERSISTENT_HISTORY 36 static int histload(Source *, unsigned char *, size_t); 37 static int writehistline(int, int, const char *); 38 static void writehistfile(int, const char *); 39 #endif 40 41 static int hist_execute(char *); 42 static char **hist_get(const char *, bool, bool); 43 static char **hist_get_oldest(void); 44 45 static bool hstarted; /* set after hist_init() called */ 46 static Source *hist_source; 47 48 #if HAVE_PERSISTENT_HISTORY 49 /*XXX imake style */ 50 #if defined(__linux) 51 #define caddr_cast(x) ((void *)(x)) 52 #else 53 #define caddr_cast(x) ((caddr_t)(x)) 54 #endif 55 56 /* several OEs do not have these constants */ 57 #ifndef MAP_FAILED 58 #define MAP_FAILED caddr_cast(-1) 59 #endif 60 61 /* some OEs need the default mapping type specified */ 62 #ifndef MAP_FILE 63 #define MAP_FILE 0 64 #endif 65 66 /* current history file: name, fd, size */ 67 static char *hname; 68 static int histfd = -1; 69 static off_t histfsize; 70 #endif 71 72 static const char Tnot_in_history[] = "not in history"; 73 #define Thistory (Tnot_in_history + 7) 74 75 static const char TFCEDIT_dollaru[] = "${FCEDIT:-/bin/ed} $_"; 76 #define Tspdollaru (TFCEDIT_dollaru + 18) 77 78 /* HISTSIZE default: size of saved history, persistent or standard */ 79 #ifdef MKSH_SMALL 80 #define MKSH_DEFHISTSIZE 255 81 #else 82 #define MKSH_DEFHISTSIZE 2047 83 #endif 84 /* maximum considered size of persistent history file */ 85 #define MKSH_MAXHISTFSIZE ((off_t)1048576 * 96) 86 87 int 88 c_fc(const char **wp) 89 { 90 struct shf *shf; 91 struct temp *tf; 92 bool gflag = false, lflag = false, nflag = false, rflag = false, 93 sflag = false; 94 int optc; 95 const char *p, *first = NULL, *last = NULL; 96 char **hfirst, **hlast, **hp, *editor = NULL; 97 98 if (!Flag(FTALKING_I)) { 99 bi_errorf("history %ss not available", Tfunction); 100 return (1); 101 } 102 103 while ((optc = ksh_getopt(wp, &builtin_opt, 104 "e:glnrs0,1,2,3,4,5,6,7,8,9,")) != -1) 105 switch (optc) { 106 107 case 'e': 108 p = builtin_opt.optarg; 109 if (ksh_isdash(p)) 110 sflag = true; 111 else { 112 size_t len = strlen(p); 113 114 /* almost certainly not overflowing */ 115 editor = alloc(len + 4, ATEMP); 116 memcpy(editor, p, len); 117 memcpy(editor + len, Tspdollaru, 4); 118 } 119 break; 120 121 /* non-AT&T ksh */ 122 case 'g': 123 gflag = true; 124 break; 125 126 case 'l': 127 lflag = true; 128 break; 129 130 case 'n': 131 nflag = true; 132 break; 133 134 case 'r': 135 rflag = true; 136 break; 137 138 /* POSIX version of -e - */ 139 case 's': 140 sflag = true; 141 break; 142 143 /* kludge city - accept -num as -- -num (kind of) */ 144 case '0': case '1': case '2': case '3': case '4': 145 case '5': case '6': case '7': case '8': case '9': 146 p = shf_smprintf("-%c%s", 147 optc, builtin_opt.optarg); 148 if (!first) 149 first = p; 150 else if (!last) 151 last = p; 152 else { 153 bi_errorf("too many arguments"); 154 return (1); 155 } 156 break; 157 158 case '?': 159 return (1); 160 } 161 wp += builtin_opt.optind; 162 163 /* Substitute and execute command */ 164 if (sflag) { 165 char *pat = NULL, *rep = NULL, *line; 166 167 if (editor || lflag || nflag || rflag) { 168 bi_errorf("can't use -e, -l, -n, -r with -s (-e -)"); 169 return (1); 170 } 171 172 /* Check for pattern replacement argument */ 173 if (*wp && **wp && (p = cstrchr(*wp + 1, '='))) { 174 strdupx(pat, *wp, ATEMP); 175 rep = pat + (p - *wp); 176 *rep++ = '\0'; 177 wp++; 178 } 179 /* Check for search prefix */ 180 if (!first && (first = *wp)) 181 wp++; 182 if (last || *wp) { 183 bi_errorf("too many arguments"); 184 return (1); 185 } 186 187 hp = first ? hist_get(first, false, false) : 188 hist_get_newest(false); 189 if (!hp) 190 return (1); 191 /* hist_replace */ 192 if (!pat) 193 strdupx(line, *hp, ATEMP); 194 else { 195 char *s, *s1; 196 size_t len, pat_len, rep_len; 197 XString xs; 198 char *xp; 199 bool any_subst = false; 200 201 pat_len = strlen(pat); 202 rep_len = strlen(rep); 203 Xinit(xs, xp, 128, ATEMP); 204 for (s = *hp; (s1 = strstr(s, pat)) && 205 (!any_subst || gflag); s = s1 + pat_len) { 206 any_subst = true; 207 len = s1 - s; 208 XcheckN(xs, xp, len + rep_len); 209 /*; first part */ 210 memcpy(xp, s, len); 211 xp += len; 212 /* replacement */ 213 memcpy(xp, rep, rep_len); 214 xp += rep_len; 215 } 216 if (!any_subst) { 217 bi_errorf("bad substitution"); 218 return (1); 219 } 220 len = strlen(s) + 1; 221 XcheckN(xs, xp, len); 222 memcpy(xp, s, len); 223 xp += len; 224 line = Xclose(xs, xp); 225 } 226 return (hist_execute(line)); 227 } 228 229 if (editor && (lflag || nflag)) { 230 bi_errorf("can't use -l, -n with -e"); 231 return (1); 232 } 233 234 if (!first && (first = *wp)) 235 wp++; 236 if (!last && (last = *wp)) 237 wp++; 238 if (*wp) { 239 bi_errorf("too many arguments"); 240 return (1); 241 } 242 if (!first) { 243 hfirst = lflag ? hist_get("-16", true, true) : 244 hist_get_newest(false); 245 if (!hfirst) 246 return (1); 247 /* can't fail if hfirst didn't fail */ 248 hlast = hist_get_newest(false); 249 } else { 250 /* 251 * POSIX says not an error if first/last out of bounds 252 * when range is specified; AT&T ksh and pdksh allow out 253 * of bounds for -l as well. 254 */ 255 hfirst = hist_get(first, tobool(lflag || last), lflag); 256 if (!hfirst) 257 return (1); 258 hlast = last ? hist_get(last, true, lflag) : 259 (lflag ? hist_get_newest(false) : hfirst); 260 if (!hlast) 261 return (1); 262 } 263 if (hfirst > hlast) { 264 char **temp; 265 266 temp = hfirst; hfirst = hlast; hlast = temp; 267 /* POSIX */ 268 rflag = !rflag; 269 } 270 271 /* List history */ 272 if (lflag) { 273 char *s, *t; 274 275 for (hp = rflag ? hlast : hfirst; 276 hp >= hfirst && hp <= hlast; hp += rflag ? -1 : 1) { 277 if (!nflag) 278 shf_fprintf(shl_stdout, "%d", 279 hist_source->line - (int)(histptr - hp)); 280 shf_putc('\t', shl_stdout); 281 /* print multi-line commands correctly */ 282 s = *hp; 283 while ((t = strchr(s, '\n'))) { 284 *t = '\0'; 285 shf_fprintf(shl_stdout, "%s\n\t", s); 286 *t++ = '\n'; 287 s = t; 288 } 289 shf_fprintf(shl_stdout, "%s\n", s); 290 } 291 shf_flush(shl_stdout); 292 return (0); 293 } 294 295 /* Run editor on selected lines, then run resulting commands */ 296 297 tf = maketemp(ATEMP, TT_HIST_EDIT, &e->temps); 298 if (!(shf = tf->shf)) { 299 bi_errorf("can't %s temporary file %s: %s", 300 "create", tf->tffn, cstrerror(errno)); 301 return (1); 302 } 303 for (hp = rflag ? hlast : hfirst; 304 hp >= hfirst && hp <= hlast; hp += rflag ? -1 : 1) 305 shf_fprintf(shf, "%s\n", *hp); 306 if (shf_close(shf) == EOF) { 307 bi_errorf("can't %s temporary file %s: %s", 308 "write", tf->tffn, cstrerror(errno)); 309 return (1); 310 } 311 312 /* Ignore setstr errors here (arbitrary) */ 313 setstr(local("_", false), tf->tffn, KSH_RETURN_ERROR); 314 315 /* XXX: source should not get trashed by this.. */ 316 { 317 Source *sold = source; 318 int ret; 319 320 ret = command(editor ? editor : TFCEDIT_dollaru, 0); 321 source = sold; 322 if (ret) 323 return (ret); 324 } 325 326 { 327 struct stat statb; 328 XString xs; 329 char *xp; 330 ssize_t n; 331 332 if (!(shf = shf_open(tf->tffn, O_RDONLY, 0, 0))) { 333 bi_errorf("can't %s temporary file %s: %s", 334 "open", tf->tffn, cstrerror(errno)); 335 return (1); 336 } 337 338 if (stat(tf->tffn, &statb) < 0) 339 n = 128; 340 else if ((off_t)statb.st_size > MKSH_MAXHISTFSIZE) { 341 bi_errorf("%s %s too large: %lu", Thistory, 342 "file", (unsigned long)statb.st_size); 343 goto errout; 344 } else 345 n = (size_t)statb.st_size + 1; 346 Xinit(xs, xp, n, hist_source->areap); 347 while ((n = shf_read(xp, Xnleft(xs, xp), shf)) > 0) { 348 xp += n; 349 if (Xnleft(xs, xp) <= 0) 350 XcheckN(xs, xp, Xlength(xs, xp)); 351 } 352 if (n < 0) { 353 bi_errorf("can't %s temporary file %s: %s", 354 "read", tf->tffn, cstrerror(shf_errno(shf))); 355 errout: 356 shf_close(shf); 357 return (1); 358 } 359 shf_close(shf); 360 *xp = '\0'; 361 strip_nuls(Xstring(xs, xp), Xlength(xs, xp)); 362 return (hist_execute(Xstring(xs, xp))); 363 } 364 } 365 366 /* Save cmd in history, execute cmd (cmd gets trashed) */ 367 static int 368 hist_execute(char *cmd) 369 { 370 static int last_line = -1; 371 Source *sold; 372 int ret; 373 char *p, *q; 374 375 /* Back up over last histsave */ 376 if (histptr >= history && last_line != hist_source->line) { 377 hist_source->line--; 378 afree(*histptr, APERM); 379 histptr--; 380 last_line = hist_source->line; 381 } 382 383 for (p = cmd; p; p = q) { 384 if ((q = strchr(p, '\n'))) { 385 /* kill the newline */ 386 *q++ = '\0'; 387 if (!*q) 388 /* ignore trailing newline */ 389 q = NULL; 390 } 391 histsave(&hist_source->line, p, true, true); 392 393 /* POSIX doesn't say this is done... */ 394 shellf("%s\n", p); 395 if (q) 396 /* restore \n (trailing \n not restored) */ 397 q[-1] = '\n'; 398 } 399 400 /*- 401 * Commands are executed here instead of pushing them onto the 402 * input 'cause POSIX says the redirection and variable assignments 403 * in 404 * X=y fc -e - 42 2> /dev/null 405 * are to effect the repeated commands environment. 406 */ 407 /* XXX: source should not get trashed by this.. */ 408 sold = source; 409 ret = command(cmd, 0); 410 source = sold; 411 return (ret); 412 } 413 414 /* 415 * get pointer to history given pattern 416 * pattern is a number or string 417 */ 418 static char ** 419 hist_get(const char *str, bool approx, bool allow_cur) 420 { 421 char **hp = NULL; 422 int n; 423 424 if (getn(str, &n)) { 425 hp = histptr + (n < 0 ? n : (n - hist_source->line)); 426 if ((ptrdiff_t)hp < (ptrdiff_t)history) { 427 if (approx) 428 hp = hist_get_oldest(); 429 else { 430 bi_errorf("%s: %s", str, Tnot_in_history); 431 hp = NULL; 432 } 433 } else if ((ptrdiff_t)hp > (ptrdiff_t)histptr) { 434 if (approx) 435 hp = hist_get_newest(allow_cur); 436 else { 437 bi_errorf("%s: %s", str, Tnot_in_history); 438 hp = NULL; 439 } 440 } else if (!allow_cur && hp == histptr) { 441 bi_errorf("%s: %s", str, "invalid range"); 442 hp = NULL; 443 } 444 } else { 445 bool anchored = *str == '?' ? (++str, false) : true; 446 447 /* the -1 is to avoid the current fc command */ 448 if ((n = findhist(histptr - history - 1, 0, str, anchored)) < 0) 449 bi_errorf("%s: %s", str, Tnot_in_history); 450 else 451 hp = &history[n]; 452 } 453 return (hp); 454 } 455 456 /* Return a pointer to the newest command in the history */ 457 char ** 458 hist_get_newest(bool allow_cur) 459 { 460 if (histptr < history || (!allow_cur && histptr == history)) { 461 bi_errorf("no history (yet)"); 462 return (NULL); 463 } 464 return (allow_cur ? histptr : histptr - 1); 465 } 466 467 /* Return a pointer to the oldest command in the history */ 468 static char ** 469 hist_get_oldest(void) 470 { 471 if (histptr <= history) { 472 bi_errorf("no history (yet)"); 473 return (NULL); 474 } 475 return (history); 476 } 477 478 #if !defined(MKSH_NO_CMDLINE_EDITING) && !MKSH_S_NOVI 479 /* current position in history[] */ 480 static char **current; 481 482 /* 483 * Return the current position. 484 */ 485 char ** 486 histpos(void) 487 { 488 return (current); 489 } 490 491 int 492 histnum(int n) 493 { 494 int last = histptr - history; 495 496 if (n < 0 || n >= last) { 497 current = histptr; 498 return (last); 499 } else { 500 current = &history[n]; 501 return (n); 502 } 503 } 504 #endif 505 506 /* 507 * This will become unnecessary if hist_get is modified to allow 508 * searching from positions other than the end, and in either 509 * direction. 510 */ 511 int 512 findhist(int start, int fwd, const char *str, bool anchored) 513 { 514 char **hp; 515 int maxhist = histptr - history; 516 int incr = fwd ? 1 : -1; 517 size_t len = strlen(str); 518 519 if (start < 0 || start >= maxhist) 520 start = maxhist; 521 522 hp = &history[start]; 523 for (; hp >= history && hp <= histptr; hp += incr) 524 if ((anchored && strncmp(*hp, str, len) == 0) || 525 (!anchored && strstr(*hp, str))) 526 return (hp - history); 527 528 return (-1); 529 } 530 531 /* 532 * set history; this means reallocating the dataspace 533 */ 534 void 535 sethistsize(mksh_ari_t n) 536 { 537 if (n > 0 && n != histsize) { 538 int cursize = histptr - history; 539 540 /* save most recent history */ 541 if (n < cursize) { 542 memmove(history, histptr - n + 1, n * sizeof(char *)); 543 cursize = n - 1; 544 } 545 546 history = aresize2(history, n, sizeof(char *), APERM); 547 548 histsize = n; 549 histptr = history + cursize; 550 } 551 } 552 553 #if HAVE_PERSISTENT_HISTORY 554 /* 555 * set history file; this can mean reloading/resetting/starting 556 * history file maintenance 557 */ 558 void 559 sethistfile(const char *name) 560 { 561 /* if not started then nothing to do */ 562 if (hstarted == false) 563 return; 564 565 /* if the name is the same as the name we have */ 566 if (hname && strcmp(hname, name) == 0) 567 return; 568 569 /* 570 * it's a new name - possibly 571 */ 572 if (histfd != -1) { 573 /* yes the file is open */ 574 (void)close(histfd); 575 histfd = -1; 576 histfsize = 0; 577 afree(hname, APERM); 578 hname = NULL; 579 /* let's reset the history */ 580 histptr = history - 1; 581 hist_source->line = 0; 582 } 583 584 hist_init(hist_source); 585 } 586 #endif 587 588 /* 589 * initialise the history vector 590 */ 591 void 592 init_histvec(void) 593 { 594 if (history == (char **)NULL) { 595 histsize = MKSH_DEFHISTSIZE; 596 history = alloc2(histsize, sizeof(char *), APERM); 597 histptr = history - 1; 598 } 599 } 600 601 602 /* 603 * It turns out that there is a lot of ghastly hackery here 604 */ 605 606 #if !defined(MKSH_SMALL) && HAVE_PERSISTENT_HISTORY 607 /* do not save command in history but possibly sync */ 608 bool 609 histsync(void) 610 { 611 bool changed = false; 612 613 if (histfd != -1) { 614 int lno = hist_source->line; 615 616 hist_source->line++; 617 writehistfile(0, NULL); 618 hist_source->line--; 619 620 if (lno != hist_source->line) 621 changed = true; 622 } 623 624 return (changed); 625 } 626 #endif 627 628 /* 629 * save command in history 630 */ 631 void 632 histsave(int *lnp, const char *cmd, bool dowrite MKSH_A_UNUSED, bool ignoredups) 633 { 634 char **hp; 635 char *c, *cp; 636 637 mkssert(cmd != NULL); 638 strdupx(c, cmd, APERM); 639 if ((cp = strchr(c, '\n')) != NULL) 640 *cp = '\0'; 641 642 if (ignoredups && !strcmp(c, *histptr) 643 #if !defined(MKSH_SMALL) && HAVE_PERSISTENT_HISTORY 644 && !histsync() 645 #endif 646 ) { 647 afree(c, APERM); 648 return; 649 } 650 ++*lnp; 651 652 #if HAVE_PERSISTENT_HISTORY 653 if (dowrite && histfd != -1) 654 writehistfile(*lnp, c); 655 #endif 656 657 hp = histptr; 658 659 if (++hp >= history + histsize) { 660 /* remove oldest command */ 661 afree(*history, APERM); 662 for (hp = history; hp < history + histsize - 1; hp++) 663 hp[0] = hp[1]; 664 } 665 *hp = c; 666 histptr = hp; 667 } 668 669 /* 670 * Write history data to a file nominated by HISTFILE; 671 * if HISTFILE is unset then history still happens, but 672 * the data is not written to a file. All copies of ksh 673 * looking at the file will maintain the same history. 674 * This is ksh behaviour. 675 * 676 * This stuff uses mmap() 677 * 678 * This stuff is so totally broken it must eventually be 679 * redesigned, without mmap, better checks, support for 680 * larger files, etc. and handle partially corrupted files 681 */ 682 683 /*- 684 * Open a history file 685 * Format is: 686 * Bytes 1, 2: 687 * HMAGIC - just to check that we are dealing with the correct object 688 * Then follows a number of stored commands 689 * Each command is 690 * <command byte><command number(4 octets, big endian)><bytes><NUL> 691 */ 692 #define HMAGIC1 0xAB 693 #define HMAGIC2 0xCD 694 #define COMMAND 0xFF 695 696 #if HAVE_PERSISTENT_HISTORY 697 static const unsigned char sprinkle[2] = { HMAGIC1, HMAGIC2 }; 698 #endif 699 700 void 701 hist_init(Source *s) 702 { 703 #if HAVE_PERSISTENT_HISTORY 704 unsigned char *base; 705 int lines, fd; 706 enum { hist_init_first, hist_init_retry, hist_init_restore } hs; 707 #endif 708 709 if (Flag(FTALKING) == 0) 710 return; 711 712 hstarted = true; 713 hist_source = s; 714 715 #if HAVE_PERSISTENT_HISTORY 716 if ((hname = str_val(global("HISTFILE"))) == NULL) 717 return; 718 strdupx(hname, hname, APERM); 719 hs = hist_init_first; 720 721 retry: 722 /* we have a file and are interactive */ 723 if ((fd = open(hname, O_RDWR | O_CREAT | O_APPEND | O_BINARY, 724 0600)) < 0) 725 return; 726 727 histfd = savefd(fd); 728 if (histfd != fd) 729 close(fd); 730 731 mksh_lockfd(histfd); 732 733 histfsize = lseek(histfd, (off_t)0, SEEK_END); 734 if (histfsize > MKSH_MAXHISTFSIZE || hs == hist_init_restore) { 735 /* we ignore too large files but still append to them */ 736 /* we also don't need to re-read after truncation */ 737 goto hist_init_tail; 738 } else if (histfsize > 2) { 739 /* we have some data, check its validity */ 740 base = (void *)mmap(NULL, (size_t)histfsize, PROT_READ, 741 MAP_FILE | MAP_PRIVATE, histfd, (off_t)0); 742 if (base == (unsigned char *)MAP_FAILED) 743 goto hist_init_fail; 744 if (base[0] != HMAGIC1 || base[1] != HMAGIC2) { 745 munmap(caddr_cast(base), (size_t)histfsize); 746 goto hist_init_fail; 747 } 748 /* load _all_ data */ 749 lines = histload(hist_source, base + 2, (size_t)histfsize - 2); 750 munmap(caddr_cast(base), (size_t)histfsize); 751 /* check if the file needs to be truncated */ 752 if (lines > histsize && histptr >= history) { 753 /* you're fucked up with the current code, trust me */ 754 char *nhname, **hp; 755 struct stat sb; 756 757 /* create temporary file */ 758 nhname = shf_smprintf("%s.%d", hname, (int)procpid); 759 if ((fd = open(nhname, O_RDWR | O_CREAT | O_TRUNC | 760 O_EXCL | O_BINARY, 0600)) < 0) { 761 /* just don't truncate then, meh. */ 762 goto hist_trunc_dont; 763 } 764 if (fstat(histfd, &sb) >= 0 && 765 chown(nhname, sb.st_uid, sb.st_gid)) { 766 /* abort the truncation then, meh. */ 767 goto hist_trunc_abort; 768 } 769 /* we definitively want some magic in that file */ 770 if (write(fd, sprinkle, 2) != 2) 771 goto hist_trunc_abort; 772 /* and of course the entries */ 773 hp = history; 774 while (hp < histptr) { 775 if (!writehistline(fd, 776 s->line - (histptr - hp), *hp)) 777 goto hist_trunc_abort; 778 ++hp; 779 } 780 /* now unlock, close both, rename, rinse, repeat */ 781 close(fd); 782 fd = -1; 783 hist_finish(); 784 if (rename(nhname, hname) < 0) { 785 hist_trunc_abort: 786 if (fd != -1) 787 close(fd); 788 unlink(nhname); 789 if (fd != -1) 790 goto hist_trunc_dont; 791 /* darn! restore histfd and pray */ 792 } 793 hs = hist_init_restore; 794 hist_trunc_dont: 795 afree(nhname, ATEMP); 796 if (hs == hist_init_restore) 797 goto retry; 798 } 799 } else if (histfsize != 0) { 800 /* negative or too small... */ 801 hist_init_fail: 802 /* ... or mmap failed or illegal */ 803 hist_finish(); 804 /* nuke the bogus file then retry, at most once */ 805 if (!unlink(hname) && hs != hist_init_retry) { 806 hs = hist_init_retry; 807 goto retry; 808 } 809 if (hs != hist_init_retry) 810 bi_errorf("can't %s %s: %s", 811 "unlink HISTFILE", hname, cstrerror(errno)); 812 histfsize = 0; 813 return; 814 } else { 815 /* size 0, add magic to the history file */ 816 if (write(histfd, sprinkle, 2) != 2) { 817 hist_finish(); 818 return; 819 } 820 } 821 histfsize = lseek(histfd, (off_t)0, SEEK_END); 822 hist_init_tail: 823 mksh_unlkfd(histfd); 824 #endif 825 } 826 827 #if HAVE_PERSISTENT_HISTORY 828 /* 829 * load the history structure from the stored data 830 */ 831 static int 832 histload(Source *s, unsigned char *base, size_t bytes) 833 { 834 int lno = 0, lines = 0; 835 unsigned char *cp; 836 837 histload_loop: 838 /* !bytes check as some systems (older FreeBSDs) have buggy memchr */ 839 if (!bytes || (cp = memchr(base, COMMAND, bytes)) == NULL) 840 return (lines); 841 /* advance base pointer past COMMAND byte */ 842 bytes -= ++cp - base; 843 base = cp; 844 /* if there is no full string left, don't bother with the rest */ 845 if (bytes < 5 || (cp = memchr(base + 4, '\0', bytes - 4)) == NULL) 846 return (lines); 847 /* load the stored line number */ 848 lno = ((base[0] & 0xFF) << 24) | ((base[1] & 0xFF) << 16) | 849 ((base[2] & 0xFF) << 8) | (base[3] & 0xFF); 850 /* store away the found line (@base[4]) */ 851 ++lines; 852 if (histptr >= history && lno - 1 != s->line) { 853 /* a replacement? */ 854 char **hp; 855 856 if (lno >= s->line - (histptr - history) && lno <= s->line) { 857 hp = &histptr[lno - s->line]; 858 if (*hp) 859 afree(*hp, APERM); 860 strdupx(*hp, (char *)(base + 4), APERM); 861 } 862 } else { 863 s->line = lno--; 864 histsave(&lno, (char *)(base + 4), false, false); 865 } 866 /* advance base pointer past NUL */ 867 bytes -= ++cp - base; 868 base = cp; 869 /* repeat until no more */ 870 goto histload_loop; 871 } 872 873 /* 874 * write a command to the end of the history file 875 * 876 * This *MAY* seem easy but it's also necessary to check 877 * that the history file has not changed in size. 878 * If it has - then some other shell has written to it and 879 * we should (re)read those commands to update our history 880 */ 881 static void 882 writehistfile(int lno, const char *cmd) 883 { 884 off_t sizenow; 885 size_t bytes; 886 unsigned char *base, *news; 887 888 mksh_lockfd(histfd); 889 sizenow = lseek(histfd, (off_t)0, SEEK_END); 890 if (sizenow < histfsize) { 891 /* the file has shrunk; give up */ 892 goto bad; 893 } 894 if ( 895 /* ignore changes when the file is too large */ 896 sizenow <= MKSH_MAXHISTFSIZE 897 && 898 /* the size has changed, we need to do read updates */ 899 sizenow > histfsize 900 ) { 901 /* both sizenow and histfsize are <= MKSH_MAXHISTFSIZE */ 902 bytes = (size_t)(sizenow - histfsize); 903 base = (void *)mmap(NULL, (size_t)sizenow, PROT_READ, 904 MAP_FILE | MAP_PRIVATE, histfd, (off_t)0); 905 if (base == (unsigned char *)MAP_FAILED) 906 goto bad; 907 news = base + (size_t)histfsize; 908 if (*news == COMMAND) { 909 hist_source->line--; 910 histload(hist_source, news, bytes); 911 hist_source->line++; 912 lno = hist_source->line; 913 } else 914 bytes = 0; 915 munmap(caddr_cast(base), (size_t)sizenow); 916 if (!bytes) 917 goto bad; 918 } 919 if (cmd && !writehistline(histfd, lno, cmd)) { 920 bad: 921 hist_finish(); 922 return; 923 } 924 histfsize = lseek(histfd, (off_t)0, SEEK_END); 925 mksh_unlkfd(histfd); 926 } 927 928 static int 929 writehistline(int fd, int lno, const char *cmd) 930 { 931 ssize_t n; 932 unsigned char hdr[5]; 933 934 hdr[0] = COMMAND; 935 hdr[1] = (lno >> 24) & 0xFF; 936 hdr[2] = (lno >> 16) & 0xFF; 937 hdr[3] = (lno >> 8) & 0xFF; 938 hdr[4] = lno & 0xFF; 939 n = strlen(cmd) + 1; 940 return (write(fd, hdr, 5) == 5 && write(fd, cmd, n) == n); 941 } 942 943 void 944 hist_finish(void) 945 { 946 if (histfd >= 0) { 947 mksh_unlkfd(histfd); 948 (void)close(histfd); 949 } 950 histfd = -1; 951 } 952 #endif 953 954 955 #if !HAVE_SYS_SIGNAME 956 static const struct mksh_sigpair { 957 const char * const name; 958 int nr; 959 } mksh_sigpairs[] = { 960 #include "signames.inc" 961 { NULL, 0 } 962 }; 963 #endif 964 965 #if HAVE_SYS_SIGLIST 966 #if !HAVE_SYS_SIGLIST_DECL 967 extern const char * const sys_siglist[]; 968 #endif 969 #endif 970 971 void 972 inittraps(void) 973 { 974 int i; 975 const char *cs; 976 977 trap_exstat = -1; 978 979 /* Populate sigtraps based on sys_signame and sys_siglist. */ 980 /*XXX this is idiotic, use a multi-key/value hashtable! */ 981 for (i = 0; i <= NSIG; i++) { 982 sigtraps[i].signal = i; 983 if (i == ksh_SIGERR) { 984 sigtraps[i].name = "ERR"; 985 sigtraps[i].mess = "Error handler"; 986 } else { 987 #if HAVE_SYS_SIGNAME 988 cs = sys_signame[i]; 989 #else 990 const struct mksh_sigpair *pair = mksh_sigpairs; 991 while ((pair->nr != i) && (pair->name != NULL)) 992 ++pair; 993 cs = pair->name; 994 #endif 995 if ((cs == NULL) || 996 (cs[0] == '\0')) 997 sigtraps[i].name = shf_smprintf("%d", i); 998 else { 999 char *s; 1000 1001 /* this is not optimal, what about SIGSIG1? */ 1002 if ((cs[0] & 0xDF) == 'S' && 1003 (cs[1] & 0xDF) == 'I' && 1004 (cs[2] & 0xDF) == 'G' && 1005 cs[3] != '\0') { 1006 /* skip leading "SIG" */ 1007 cs += 3; 1008 } 1009 strdupx(s, cs, APERM); 1010 sigtraps[i].name = s; 1011 while ((*s = ksh_toupper(*s))) 1012 ++s; 1013 } 1014 #if HAVE_SYS_SIGLIST 1015 sigtraps[i].mess = sys_siglist[i]; 1016 #elif HAVE_STRSIGNAL 1017 sigtraps[i].mess = strsignal(i); 1018 #else 1019 sigtraps[i].mess = NULL; 1020 #endif 1021 if ((sigtraps[i].mess == NULL) || 1022 (sigtraps[i].mess[0] == '\0')) 1023 sigtraps[i].mess = shf_smprintf("%s %d", 1024 "Signal", i); 1025 } 1026 } 1027 /* our name for signal 0 */ 1028 sigtraps[ksh_SIGEXIT].name = "EXIT"; 1029 1030 (void)sigemptyset(&Sigact_ign.sa_mask); 1031 Sigact_ign.sa_flags = 0; /* interruptible */ 1032 Sigact_ign.sa_handler = SIG_IGN; 1033 1034 sigtraps[SIGINT].flags |= TF_DFL_INTR | TF_TTY_INTR; 1035 sigtraps[SIGQUIT].flags |= TF_DFL_INTR | TF_TTY_INTR; 1036 /* SIGTERM is not fatal for interactive */ 1037 sigtraps[SIGTERM].flags |= TF_DFL_INTR; 1038 sigtraps[SIGHUP].flags |= TF_FATAL; 1039 sigtraps[SIGCHLD].flags |= TF_SHELL_USES; 1040 1041 /* these are always caught so we can clean up any temporary files. */ 1042 setsig(&sigtraps[SIGINT], trapsig, SS_RESTORE_ORIG); 1043 setsig(&sigtraps[SIGQUIT], trapsig, SS_RESTORE_ORIG); 1044 setsig(&sigtraps[SIGTERM], trapsig, SS_RESTORE_ORIG); 1045 setsig(&sigtraps[SIGHUP], trapsig, SS_RESTORE_ORIG); 1046 } 1047 1048 static void alarm_catcher(int sig); 1049 1050 void 1051 alarm_init(void) 1052 { 1053 sigtraps[SIGALRM].flags |= TF_SHELL_USES; 1054 setsig(&sigtraps[SIGALRM], alarm_catcher, 1055 SS_RESTORE_ORIG|SS_FORCE|SS_SHTRAP); 1056 } 1057 1058 /* ARGSUSED */ 1059 static void 1060 alarm_catcher(int sig MKSH_A_UNUSED) 1061 { 1062 /* this runs inside interrupt context, with errno saved */ 1063 1064 if (ksh_tmout_state == TMOUT_READING) { 1065 int left = alarm(0); 1066 1067 if (left == 0) { 1068 ksh_tmout_state = TMOUT_LEAVING; 1069 intrsig = 1; 1070 } else 1071 alarm(left); 1072 } 1073 } 1074 1075 Trap * 1076 gettrap(const char *cs, bool igncase) 1077 { 1078 int i; 1079 Trap *p; 1080 char *as; 1081 1082 if (ksh_isdigit(*cs)) { 1083 return ((getn(cs, &i) && 0 <= i && i < NSIG) ? 1084 (&sigtraps[i]) : NULL); 1085 } 1086 1087 /* this breaks SIGSIG1, but we do that above anyway */ 1088 if ((cs[0] & 0xDF) == 'S' && 1089 (cs[1] & 0xDF) == 'I' && 1090 (cs[2] & 0xDF) == 'G' && 1091 cs[3] != '\0') { 1092 /* skip leading "SIG" */ 1093 cs += 3; 1094 } 1095 if (igncase) { 1096 char *s; 1097 1098 strdupx(as, cs, ATEMP); 1099 cs = s = as; 1100 while ((*s = ksh_toupper(*s))) 1101 ++s; 1102 } else 1103 as = NULL; 1104 1105 p = sigtraps; 1106 for (i = 0; i <= NSIG; i++) { 1107 if (!strcmp(p->name, cs)) 1108 goto found; 1109 ++p; 1110 } 1111 p = NULL; 1112 found: 1113 afree(as, ATEMP); 1114 return (p); 1115 } 1116 1117 /* 1118 * trap signal handler 1119 */ 1120 void 1121 trapsig(int i) 1122 { 1123 Trap *p = &sigtraps[i]; 1124 int eno = errno; 1125 1126 trap = p->set = 1; 1127 if (p->flags & TF_DFL_INTR) 1128 intrsig = 1; 1129 if ((p->flags & TF_FATAL) && !p->trap) { 1130 fatal_trap = 1; 1131 intrsig = 1; 1132 } 1133 if (p->shtrap) 1134 (*p->shtrap)(i); 1135 errno = eno; 1136 } 1137 1138 /* 1139 * called when we want to allow the user to ^C out of something - won't 1140 * work if user has trapped SIGINT. 1141 */ 1142 void 1143 intrcheck(void) 1144 { 1145 if (intrsig) 1146 runtraps(TF_DFL_INTR|TF_FATAL); 1147 } 1148 1149 /* 1150 * called after EINTR to check if a signal with normally causes process 1151 * termination has been received. 1152 */ 1153 int 1154 fatal_trap_check(void) 1155 { 1156 int i; 1157 Trap *p; 1158 1159 /* todo: should check if signal is fatal, not the TF_DFL_INTR flag */ 1160 for (p = sigtraps, i = NSIG+1; --i >= 0; p++) 1161 if (p->set && (p->flags & (TF_DFL_INTR|TF_FATAL))) 1162 /* return value is used as an exit code */ 1163 return (128 + p->signal); 1164 return (0); 1165 } 1166 1167 /* 1168 * Returns the signal number of any pending traps: ie, a signal which has 1169 * occurred for which a trap has been set or for which the TF_DFL_INTR flag 1170 * is set. 1171 */ 1172 int 1173 trap_pending(void) 1174 { 1175 int i; 1176 Trap *p; 1177 1178 for (p = sigtraps, i = NSIG+1; --i >= 0; p++) 1179 if (p->set && ((p->trap && p->trap[0]) || 1180 ((p->flags & (TF_DFL_INTR|TF_FATAL)) && !p->trap))) 1181 return (p->signal); 1182 return (0); 1183 } 1184 1185 /* 1186 * run any pending traps. If intr is set, only run traps that 1187 * can interrupt commands. 1188 */ 1189 void 1190 runtraps(int flag) 1191 { 1192 int i; 1193 Trap *p; 1194 1195 if (ksh_tmout_state == TMOUT_LEAVING) { 1196 ksh_tmout_state = TMOUT_EXECUTING; 1197 warningf(false, "timed out waiting for input"); 1198 unwind(LEXIT); 1199 } else 1200 /* 1201 * XXX: this means the alarm will have no effect if a trap 1202 * is caught after the alarm() was started...not good. 1203 */ 1204 ksh_tmout_state = TMOUT_EXECUTING; 1205 if (!flag) 1206 trap = 0; 1207 if (flag & TF_DFL_INTR) 1208 intrsig = 0; 1209 if (flag & TF_FATAL) 1210 fatal_trap = 0; 1211 ++trap_nested; 1212 for (p = sigtraps, i = NSIG+1; --i >= 0; p++) 1213 if (p->set && (!flag || 1214 ((p->flags & flag) && p->trap == NULL))) 1215 runtrap(p, false); 1216 if (!--trap_nested) 1217 runtrap(NULL, true); 1218 } 1219 1220 void 1221 runtrap(Trap *p, bool is_last) 1222 { 1223 int old_changed = 0, i; 1224 char *trapstr; 1225 1226 if (p == NULL) 1227 /* just clean up, see runtraps() above */ 1228 goto donetrap; 1229 i = p->signal; 1230 trapstr = p->trap; 1231 p->set = 0; 1232 if (trapstr == NULL) { 1233 /* SIG_DFL */ 1234 if (p->flags & TF_FATAL) { 1235 /* eg, SIGHUP */ 1236 exstat = (int)ksh_min(128U + (unsigned)i, 255U); 1237 unwind(LLEAVE); 1238 } 1239 if (p->flags & TF_DFL_INTR) { 1240 /* eg, SIGINT, SIGQUIT, SIGTERM, etc. */ 1241 exstat = (int)ksh_min(128U + (unsigned)i, 255U); 1242 unwind(LINTR); 1243 } 1244 goto donetrap; 1245 } 1246 if (trapstr[0] == '\0') 1247 /* SIG_IGN */ 1248 goto donetrap; 1249 if (i == ksh_SIGEXIT || i == ksh_SIGERR) { 1250 /* avoid recursion on these */ 1251 old_changed = p->flags & TF_CHANGED; 1252 p->flags &= ~TF_CHANGED; 1253 p->trap = NULL; 1254 } 1255 if (trap_exstat == -1) 1256 trap_exstat = exstat & 0xFF; 1257 /* 1258 * Note: trapstr is fully parsed before anything is executed, thus 1259 * no problem with afree(p->trap) in settrap() while still in use. 1260 */ 1261 command(trapstr, current_lineno); 1262 if (i == ksh_SIGEXIT || i == ksh_SIGERR) { 1263 if (p->flags & TF_CHANGED) 1264 /* don't clear TF_CHANGED */ 1265 afree(trapstr, APERM); 1266 else 1267 p->trap = trapstr; 1268 p->flags |= old_changed; 1269 } 1270 1271 donetrap: 1272 /* we're the last trap of a sequence executed */ 1273 if (is_last && trap_exstat != -1) { 1274 exstat = trap_exstat; 1275 trap_exstat = -1; 1276 } 1277 } 1278 1279 /* clear pending traps and reset user's trap handlers; used after fork(2) */ 1280 void 1281 cleartraps(void) 1282 { 1283 int i; 1284 Trap *p; 1285 1286 trap = 0; 1287 intrsig = 0; 1288 fatal_trap = 0; 1289 for (i = NSIG+1, p = sigtraps; --i >= 0; p++) { 1290 p->set = 0; 1291 if ((p->flags & TF_USER_SET) && (p->trap && p->trap[0])) 1292 settrap(p, NULL); 1293 } 1294 } 1295 1296 /* restore signals just before an exec(2) */ 1297 void 1298 restoresigs(void) 1299 { 1300 int i; 1301 Trap *p; 1302 1303 for (i = NSIG+1, p = sigtraps; --i >= 0; p++) 1304 if (p->flags & (TF_EXEC_IGN|TF_EXEC_DFL)) 1305 setsig(p, (p->flags & TF_EXEC_IGN) ? SIG_IGN : SIG_DFL, 1306 SS_RESTORE_CURR|SS_FORCE); 1307 } 1308 1309 void 1310 settrap(Trap *p, const char *s) 1311 { 1312 sig_t f; 1313 1314 if (p->trap) 1315 afree(p->trap, APERM); 1316 /* handles s == NULL */ 1317 strdupx(p->trap, s, APERM); 1318 p->flags |= TF_CHANGED; 1319 f = !s ? SIG_DFL : s[0] ? trapsig : SIG_IGN; 1320 1321 p->flags |= TF_USER_SET; 1322 if ((p->flags & (TF_DFL_INTR|TF_FATAL)) && f == SIG_DFL) 1323 f = trapsig; 1324 else if (p->flags & TF_SHELL_USES) { 1325 if (!(p->flags & TF_ORIG_IGN) || Flag(FTALKING)) { 1326 /* do what user wants at exec time */ 1327 p->flags &= ~(TF_EXEC_IGN|TF_EXEC_DFL); 1328 if (f == SIG_IGN) 1329 p->flags |= TF_EXEC_IGN; 1330 else 1331 p->flags |= TF_EXEC_DFL; 1332 } 1333 1334 /* 1335 * assumes handler already set to what shell wants it 1336 * (normally trapsig, but could be j_sigchld() or SIG_IGN) 1337 */ 1338 return; 1339 } 1340 1341 /* todo: should we let user know signal is ignored? how? */ 1342 setsig(p, f, SS_RESTORE_CURR|SS_USER); 1343 } 1344 1345 /* 1346 * Called by c_print() when writing to a co-process to ensure SIGPIPE won't 1347 * kill shell (unless user catches it and exits) 1348 */ 1349 int 1350 block_pipe(void) 1351 { 1352 int restore_dfl = 0; 1353 Trap *p = &sigtraps[SIGPIPE]; 1354 1355 if (!(p->flags & (TF_ORIG_IGN|TF_ORIG_DFL))) { 1356 setsig(p, SIG_IGN, SS_RESTORE_CURR); 1357 if (p->flags & TF_ORIG_DFL) 1358 restore_dfl = 1; 1359 } else if (p->cursig == SIG_DFL) { 1360 setsig(p, SIG_IGN, SS_RESTORE_CURR); 1361 /* restore to SIG_DFL */ 1362 restore_dfl = 1; 1363 } 1364 return (restore_dfl); 1365 } 1366 1367 /* Called by c_print() to undo whatever block_pipe() did */ 1368 void 1369 restore_pipe(int restore_dfl) 1370 { 1371 if (restore_dfl) 1372 setsig(&sigtraps[SIGPIPE], SIG_DFL, SS_RESTORE_CURR); 1373 } 1374 1375 /* 1376 * Set action for a signal. Action may not be set if original 1377 * action was SIG_IGN, depending on the value of flags and FTALKING. 1378 */ 1379 int 1380 setsig(Trap *p, sig_t f, int flags) 1381 { 1382 struct sigaction sigact; 1383 1384 if (p->signal == ksh_SIGEXIT || p->signal == ksh_SIGERR) 1385 return (1); 1386 1387 memset(&sigact, 0, sizeof(sigact)); 1388 1389 /* 1390 * First time setting this signal? If so, get and note the current 1391 * setting. 1392 */ 1393 if (!(p->flags & (TF_ORIG_IGN|TF_ORIG_DFL))) { 1394 sigaction(p->signal, &Sigact_ign, &sigact); 1395 p->flags |= sigact.sa_handler == SIG_IGN ? 1396 TF_ORIG_IGN : TF_ORIG_DFL; 1397 p->cursig = SIG_IGN; 1398 } 1399 1400 /*- 1401 * Generally, an ignored signal stays ignored, except if 1402 * - the user of an interactive shell wants to change it 1403 * - the shell wants for force a change 1404 */ 1405 if ((p->flags & TF_ORIG_IGN) && !(flags & SS_FORCE) && 1406 (!(flags & SS_USER) || !Flag(FTALKING))) 1407 return (0); 1408 1409 setexecsig(p, flags & SS_RESTORE_MASK); 1410 1411 /* 1412 * This is here 'cause there should be a way of clearing 1413 * shtraps, but don't know if this is a sane way of doing 1414 * it. At the moment, all users of shtrap are lifetime 1415 * users (SIGALRM, SIGCHLD, SIGWINCH). 1416 */ 1417 if (!(flags & SS_USER)) 1418 p->shtrap = (sig_t)NULL; 1419 if (flags & SS_SHTRAP) { 1420 p->shtrap = f; 1421 f = trapsig; 1422 } 1423 1424 if (p->cursig != f) { 1425 p->cursig = f; 1426 (void)sigemptyset(&sigact.sa_mask); 1427 /* interruptible */ 1428 sigact.sa_flags = 0; 1429 sigact.sa_handler = f; 1430 sigaction(p->signal, &sigact, NULL); 1431 } 1432 1433 return (1); 1434 } 1435 1436 /* control what signal is set to before an exec() */ 1437 void 1438 setexecsig(Trap *p, int restore) 1439 { 1440 /* XXX debugging */ 1441 if (!(p->flags & (TF_ORIG_IGN|TF_ORIG_DFL))) 1442 internal_errorf("setexecsig: unset signal %d(%s)", 1443 p->signal, p->name); 1444 1445 /* restore original value for exec'd kids */ 1446 p->flags &= ~(TF_EXEC_IGN|TF_EXEC_DFL); 1447 switch (restore & SS_RESTORE_MASK) { 1448 case SS_RESTORE_CURR: 1449 /* leave things as they currently are */ 1450 break; 1451 case SS_RESTORE_ORIG: 1452 p->flags |= p->flags & TF_ORIG_IGN ? TF_EXEC_IGN : TF_EXEC_DFL; 1453 break; 1454 case SS_RESTORE_DFL: 1455 p->flags |= TF_EXEC_DFL; 1456 break; 1457 case SS_RESTORE_IGN: 1458 p->flags |= TF_EXEC_IGN; 1459 break; 1460 } 1461 } 1462 1463 #if HAVE_PERSISTENT_HISTORY || defined(DF) 1464 /* 1465 * File descriptor locking and unlocking functions. 1466 * Could use some error handling, but hey, this is only 1467 * advisory locking anyway, will often not work over NFS, 1468 * and you are SOL if this fails... 1469 */ 1470 1471 void 1472 mksh_lockfd(int fd) 1473 { 1474 #if defined(__OpenBSD__) 1475 /* flock is not interrupted by signals */ 1476 (void)flock(fd, LOCK_EX); 1477 #elif HAVE_FLOCK 1478 int rv; 1479 1480 /* e.g. on Linux */ 1481 do { 1482 rv = flock(fd, LOCK_EX); 1483 } while (rv == 1 && errno == EINTR); 1484 #elif HAVE_LOCK_FCNTL 1485 int rv; 1486 struct flock lks; 1487 1488 memset(&lks, 0, sizeof(lks)); 1489 lks.l_type = F_WRLCK; 1490 do { 1491 rv = fcntl(fd, F_SETLKW, &lks); 1492 } while (rv == 1 && errno == EINTR); 1493 #endif 1494 } 1495 1496 /* designed to not define mksh_unlkfd if none triggered */ 1497 #if HAVE_FLOCK 1498 void 1499 mksh_unlkfd(int fd) 1500 { 1501 (void)flock(fd, LOCK_UN); 1502 } 1503 #elif HAVE_LOCK_FCNTL 1504 void 1505 mksh_unlkfd(int fd) 1506 { 1507 struct flock lks; 1508 1509 memset(&lks, 0, sizeof(lks)); 1510 lks.l_type = F_UNLCK; 1511 (void)fcntl(fd, F_SETLKW, &lks); 1512 } 1513 #endif 1514 #endif 1515