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