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