1 /*- 2 * Copyright (c) 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Kenneth Almquist. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the name of the University nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33 #include <sys/param.h> 34 #include <sys/stat.h> 35 #include <dirent.h> 36 #include <errno.h> 37 #include <fcntl.h> 38 #include <limits.h> 39 #include <paths.h> 40 #include <stdbool.h> 41 #include <stdio.h> 42 #include <stdlib.h> 43 #include <unistd.h> 44 /* 45 * Editline and history functions (and glue). 46 */ 47 #include "alias.h" 48 #include "exec.h" 49 #include "shell.h" 50 #include "parser.h" 51 #include "var.h" 52 #include "options.h" 53 #include "main.h" 54 #include "output.h" 55 #include "mystring.h" 56 #include "builtins.h" 57 #ifndef NO_HISTORY 58 #include "myhistedit.h" 59 #include "error.h" 60 #include "eval.h" 61 #include "memalloc.h" 62 63 #define MAXHISTLOOPS 4 /* max recursions through fc */ 64 #define DEFEDITOR "ed" /* default editor *should* be $EDITOR */ 65 66 History *hist; /* history cookie */ 67 EditLine *el; /* editline cookie */ 68 int displayhist; 69 static int savehist; 70 static FILE *el_in, *el_out; 71 static bool in_command_completion; 72 73 static char *fc_replace(const char *, char *, char *); 74 static int not_fcnumber(const char *); 75 static int str_to_event(const char *, int); 76 static int comparator(const void *, const void *, void *); 77 static char **sh_matches(const char *, int, int); 78 static const char *append_char_function(const char *); 79 static unsigned char sh_complete(EditLine *, int); 80 81 static const char * 82 get_histfile(void) 83 { 84 const char *histfile; 85 86 /* don't try to save if the history size is 0 */ 87 if (hist == NULL || !strcmp(histsizeval(), "0")) 88 return (NULL); 89 histfile = expandstr("${HISTFILE-${HOME-}/.sh_history}"); 90 91 if (histfile[0] == '\0') 92 return (NULL); 93 return (histfile); 94 } 95 96 void 97 histsave(void) 98 { 99 HistEvent he; 100 char *histtmpname = NULL; 101 const char *histfile; 102 int fd; 103 FILE *f; 104 105 if (!savehist || (histfile = get_histfile()) == NULL) 106 return; 107 INTOFF; 108 asprintf(&histtmpname, "%s.XXXXXXXXXX", histfile); 109 if (histtmpname == NULL) { 110 INTON; 111 return; 112 } 113 fd = mkstemp(histtmpname); 114 if (fd == -1 || (f = fdopen(fd, "w")) == NULL) { 115 free(histtmpname); 116 INTON; 117 return; 118 } 119 if (history(hist, &he, H_SAVE_FP, f) < 1 || 120 rename(histtmpname, histfile) == -1) 121 unlink(histtmpname); 122 fclose(f); 123 free(histtmpname); 124 INTON; 125 126 } 127 128 void 129 histload(void) 130 { 131 const char *histfile; 132 HistEvent he; 133 134 if ((histfile = get_histfile()) == NULL) 135 return; 136 errno = 0; 137 if (history(hist, &he, H_LOAD, histfile) != -1 || errno == ENOENT) 138 savehist = 1; 139 } 140 141 /* 142 * Set history and editing status. Called whenever the status may 143 * have changed (figures out what to do). 144 */ 145 void 146 histedit(void) 147 { 148 149 #define editing (Eflag || Vflag) 150 151 if (iflag) { 152 if (!hist) { 153 /* 154 * turn history on 155 */ 156 INTOFF; 157 hist = history_init(); 158 INTON; 159 160 if (hist != NULL) 161 sethistsize(histsizeval()); 162 else 163 out2fmt_flush("sh: can't initialize history\n"); 164 } 165 if (editing && !el && isatty(0)) { /* && isatty(2) ??? */ 166 /* 167 * turn editing on 168 */ 169 char *term; 170 171 INTOFF; 172 if (el_in == NULL) 173 el_in = fdopen(0, "r"); 174 if (el_out == NULL) 175 el_out = fdopen(2, "w"); 176 if (el_in == NULL || el_out == NULL) 177 goto bad; 178 term = lookupvar("TERM"); 179 if (term) 180 setenv("TERM", term, 1); 181 else 182 unsetenv("TERM"); 183 el = el_init(arg0, el_in, el_out, el_out); 184 if (el != NULL) { 185 if (hist) 186 el_set(el, EL_HIST, history, hist); 187 el_set(el, EL_PROMPT_ESC, getprompt, '\001'); 188 el_set(el, EL_ADDFN, "sh-complete", 189 "Filename completion", 190 sh_complete); 191 } else { 192 bad: 193 out2fmt_flush("sh: can't initialize editing\n"); 194 } 195 INTON; 196 } else if (!editing && el) { 197 INTOFF; 198 el_end(el); 199 el = NULL; 200 INTON; 201 } 202 if (el) { 203 if (Vflag) 204 el_set(el, EL_EDITOR, "vi"); 205 else if (Eflag) { 206 el_set(el, EL_EDITOR, "emacs"); 207 } 208 el_set(el, EL_BIND, "^I", "sh-complete", NULL); 209 el_source(el, NULL); 210 } 211 } else { 212 INTOFF; 213 if (el) { /* no editing if not interactive */ 214 el_end(el); 215 el = NULL; 216 } 217 if (hist) { 218 history_end(hist); 219 hist = NULL; 220 } 221 INTON; 222 } 223 } 224 225 226 void 227 sethistsize(const char *hs) 228 { 229 int histsize; 230 HistEvent he; 231 232 if (hist != NULL) { 233 if (hs == NULL || !is_number(hs)) 234 histsize = 100; 235 else 236 histsize = atoi(hs); 237 history(hist, &he, H_SETSIZE, histsize); 238 history(hist, &he, H_SETUNIQUE, 1); 239 } 240 } 241 242 void 243 setterm(const char *term) 244 { 245 if (rootshell && el != NULL && term != NULL) 246 el_set(el, EL_TERMINAL, term); 247 } 248 249 int 250 histcmd(int argc, char **argv __unused) 251 { 252 const char *editor = NULL; 253 HistEvent he; 254 int lflg = 0, nflg = 0, rflg = 0, sflg = 0; 255 int i, retval; 256 const char *firststr, *laststr; 257 int first, last, direction; 258 char *pat = NULL, *repl = NULL; 259 static int active = 0; 260 struct jmploc jmploc; 261 struct jmploc *savehandler; 262 char editfilestr[PATH_MAX]; 263 char *volatile editfile; 264 FILE *efp = NULL; 265 int oldhistnum; 266 267 if (hist == NULL) 268 error("history not active"); 269 270 if (argc == 1) 271 error("missing history argument"); 272 273 while (not_fcnumber(*argptr)) 274 do { 275 switch (nextopt("e:lnrs")) { 276 case 'e': 277 editor = shoptarg; 278 break; 279 case 'l': 280 lflg = 1; 281 break; 282 case 'n': 283 nflg = 1; 284 break; 285 case 'r': 286 rflg = 1; 287 break; 288 case 's': 289 sflg = 1; 290 break; 291 case '\0': 292 goto operands; 293 } 294 } while (nextopt_optptr != NULL); 295 operands: 296 savehandler = handler; 297 /* 298 * If executing... 299 */ 300 if (lflg == 0 || editor || sflg) { 301 lflg = 0; /* ignore */ 302 editfile = NULL; 303 /* 304 * Catch interrupts to reset active counter and 305 * cleanup temp files. 306 */ 307 if (setjmp(jmploc.loc)) { 308 active = 0; 309 if (editfile) 310 unlink(editfile); 311 handler = savehandler; 312 longjmp(handler->loc, 1); 313 } 314 handler = &jmploc; 315 if (++active > MAXHISTLOOPS) { 316 active = 0; 317 displayhist = 0; 318 error("called recursively too many times"); 319 } 320 /* 321 * Set editor. 322 */ 323 if (sflg == 0) { 324 if (editor == NULL && 325 (editor = bltinlookup("FCEDIT", 1)) == NULL && 326 (editor = bltinlookup("EDITOR", 1)) == NULL) 327 editor = DEFEDITOR; 328 if (editor[0] == '-' && editor[1] == '\0') { 329 sflg = 1; /* no edit */ 330 editor = NULL; 331 } 332 } 333 } 334 335 /* 336 * If executing, parse [old=new] now 337 */ 338 if (lflg == 0 && *argptr != NULL && 339 ((repl = strchr(*argptr, '=')) != NULL)) { 340 pat = *argptr; 341 *repl++ = '\0'; 342 argptr++; 343 } 344 /* 345 * determine [first] and [last] 346 */ 347 if (*argptr == NULL) { 348 firststr = lflg ? "-16" : "-1"; 349 laststr = "-1"; 350 } else if (argptr[1] == NULL) { 351 firststr = argptr[0]; 352 laststr = lflg ? "-1" : argptr[0]; 353 } else if (argptr[2] == NULL) { 354 firststr = argptr[0]; 355 laststr = argptr[1]; 356 } else 357 error("too many arguments"); 358 /* 359 * Turn into event numbers. 360 */ 361 first = str_to_event(firststr, 0); 362 last = str_to_event(laststr, 1); 363 364 if (rflg) { 365 i = last; 366 last = first; 367 first = i; 368 } 369 /* 370 * XXX - this should not depend on the event numbers 371 * always increasing. Add sequence numbers or offset 372 * to the history element in next (diskbased) release. 373 */ 374 direction = first < last ? H_PREV : H_NEXT; 375 376 /* 377 * If editing, grab a temp file. 378 */ 379 if (editor) { 380 int fd; 381 INTOFF; /* easier */ 382 sprintf(editfilestr, "%s/_shXXXXXX", _PATH_TMP); 383 if ((fd = mkstemp(editfilestr)) < 0) 384 error("can't create temporary file %s", editfile); 385 editfile = editfilestr; 386 if ((efp = fdopen(fd, "w")) == NULL) { 387 close(fd); 388 error("Out of space"); 389 } 390 } 391 392 /* 393 * Loop through selected history events. If listing or executing, 394 * do it now. Otherwise, put into temp file and call the editor 395 * after. 396 * 397 * The history interface needs rethinking, as the following 398 * convolutions will demonstrate. 399 */ 400 history(hist, &he, H_FIRST); 401 retval = history(hist, &he, H_NEXT_EVENT, first); 402 for (;retval != -1; retval = history(hist, &he, direction)) { 403 if (lflg) { 404 if (!nflg) 405 out1fmt("%5d ", he.num); 406 out1str(he.str); 407 } else { 408 const char *s = pat ? 409 fc_replace(he.str, pat, repl) : he.str; 410 411 if (sflg) { 412 if (displayhist) { 413 out2str(s); 414 flushout(out2); 415 } 416 evalstring(s, 0); 417 if (displayhist && hist) { 418 /* 419 * XXX what about recursive and 420 * relative histnums. 421 */ 422 oldhistnum = he.num; 423 history(hist, &he, H_ENTER, s); 424 /* 425 * XXX H_ENTER moves the internal 426 * cursor, set it back to the current 427 * entry. 428 */ 429 history(hist, &he, 430 H_NEXT_EVENT, oldhistnum); 431 } 432 } else 433 fputs(s, efp); 434 } 435 /* 436 * At end? (if we were to lose last, we'd sure be 437 * messed up). 438 */ 439 if (he.num == last) 440 break; 441 } 442 if (editor) { 443 char *editcmd; 444 445 fclose(efp); 446 INTON; 447 editcmd = stalloc(strlen(editor) + strlen(editfile) + 2); 448 sprintf(editcmd, "%s %s", editor, editfile); 449 evalstring(editcmd, 0); /* XXX - should use no JC command */ 450 readcmdfile(editfile, 0 /* verify */); /* XXX - should read back - quick tst */ 451 unlink(editfile); 452 } 453 454 if (lflg == 0 && active > 0) 455 --active; 456 if (displayhist) 457 displayhist = 0; 458 handler = savehandler; 459 return 0; 460 } 461 462 static char * 463 fc_replace(const char *s, char *p, char *r) 464 { 465 char *dest; 466 int plen = strlen(p); 467 468 STARTSTACKSTR(dest); 469 while (*s) { 470 if (*s == *p && strncmp(s, p, plen) == 0) { 471 STPUTS(r, dest); 472 s += plen; 473 *p = '\0'; /* so no more matches */ 474 } else 475 STPUTC(*s++, dest); 476 } 477 STPUTC('\0', dest); 478 dest = grabstackstr(dest); 479 480 return (dest); 481 } 482 483 static int 484 not_fcnumber(const char *s) 485 { 486 if (s == NULL) 487 return (0); 488 if (*s == '-') 489 s++; 490 return (!is_number(s)); 491 } 492 493 static int 494 str_to_event(const char *str, int last) 495 { 496 HistEvent he; 497 const char *s = str; 498 int relative = 0; 499 int i, retval; 500 501 retval = history(hist, &he, H_FIRST); 502 switch (*s) { 503 case '-': 504 relative = 1; 505 /*FALLTHROUGH*/ 506 case '+': 507 s++; 508 } 509 if (is_number(s)) { 510 i = atoi(s); 511 if (relative) { 512 while (retval != -1 && i--) { 513 retval = history(hist, &he, H_NEXT); 514 } 515 if (retval == -1) 516 retval = history(hist, &he, H_LAST); 517 } else { 518 retval = history(hist, &he, H_NEXT_EVENT, i); 519 if (retval == -1) { 520 /* 521 * the notion of first and last is 522 * backwards to that of the history package 523 */ 524 retval = history(hist, &he, last ? H_FIRST : H_LAST); 525 } 526 } 527 if (retval == -1) 528 error("history number %s not found (internal error)", 529 str); 530 } else { 531 /* 532 * pattern 533 */ 534 retval = history(hist, &he, H_PREV_STR, str); 535 if (retval == -1) 536 error("history pattern not found: %s", str); 537 } 538 return (he.num); 539 } 540 541 int 542 bindcmd(int argc, char **argv) 543 { 544 int ret; 545 FILE *old; 546 FILE *out; 547 548 if (el == NULL) 549 error("line editing is disabled"); 550 551 INTOFF; 552 553 out = out1fp(); 554 if (out == NULL) 555 error("Out of space"); 556 557 el_get(el, EL_GETFP, 1, &old); 558 el_set(el, EL_SETFP, 1, out); 559 560 ret = el_parse(el, argc, __DECONST(const char **, argv)); 561 562 el_set(el, EL_SETFP, 1, old); 563 564 fclose(out); 565 566 if (argc > 1 && argv[1][0] == '-' && 567 memchr("ve", argv[1][1], 2) != NULL) { 568 Vflag = argv[1][1] == 'v'; 569 Eflag = !Vflag; 570 histedit(); 571 } 572 573 INTON; 574 575 return ret; 576 } 577 578 /* 579 * Comparator function for qsort(). The use of curpos here is to skip 580 * characters that we already know to compare equal (common prefix). 581 */ 582 static int 583 comparator(const void *a, const void *b, void *thunk) 584 { 585 size_t curpos = (intptr_t)thunk; 586 587 return (strcmp(*(char *const *)a + curpos, 588 *(char *const *)b + curpos)); 589 } 590 591 static char 592 **add_match(char **matches, size_t i, size_t *size, char *match_copy) 593 { 594 if (match_copy == NULL) 595 return (NULL); 596 matches[i] = match_copy; 597 if (i >= *size - 1) { 598 *size *= 2; 599 matches = reallocarray(matches, *size, sizeof(matches[0])); 600 } 601 602 return (matches); 603 } 604 605 /* 606 * This function is passed to libedit's fn_complete2(). The library will use 607 * it instead of its standard function that finds matching files in current 608 * directory. If we're at the start of the line, we want to look for 609 * available commands from all paths in $PATH. 610 */ 611 static char 612 **sh_matches(const char *text, int start, int end) 613 { 614 char *free_path = NULL, *path; 615 const char *dirname; 616 char **matches = NULL, **rmatches; 617 size_t i = 0, size = 16, uniq; 618 size_t curpos = end - start, lcstring = -1; 619 struct cmdentry e; 620 621 in_command_completion = false; 622 if (start > 0 || memchr("/.~", text[0], 3) != NULL) 623 return (NULL); 624 in_command_completion = true; 625 if ((free_path = path = strdup(pathval())) == NULL) 626 goto out; 627 if ((matches = malloc(size * sizeof(matches[0]))) == NULL) 628 goto out; 629 while ((dirname = strsep(&path, ":")) != NULL) { 630 struct dirent *entry; 631 DIR *dir; 632 int dfd; 633 634 dir = opendir(dirname[0] == '\0' ? "." : dirname); 635 if (dir == NULL) 636 continue; 637 if ((dfd = dirfd(dir)) == -1) { 638 closedir(dir); 639 continue; 640 } 641 while ((entry = readdir(dir)) != NULL) { 642 struct stat statb; 643 644 if (strncmp(entry->d_name, text, curpos) != 0) 645 continue; 646 if (entry->d_type == DT_UNKNOWN || entry->d_type == DT_LNK) { 647 if (fstatat(dfd, entry->d_name, &statb, 0) == -1) 648 continue; 649 if (!S_ISREG(statb.st_mode)) 650 continue; 651 } else if (entry->d_type != DT_REG) 652 continue; 653 rmatches = add_match(matches, ++i, &size, 654 strdup(entry->d_name)); 655 if (rmatches == NULL) { 656 closedir(dir); 657 goto out; 658 } 659 matches = rmatches; 660 } 661 closedir(dir); 662 } 663 for (const unsigned char *bp = builtincmd; *bp != 0; bp += 2 + bp[0]) { 664 if (curpos > bp[0] || memcmp(bp + 2, text, curpos) != 0) 665 continue; 666 rmatches = add_match(matches, ++i, &size, strndup(bp + 2, bp[0])); 667 if (rmatches == NULL) 668 goto out; 669 matches = rmatches; 670 } 671 for (const struct alias *ap = NULL; (ap = iteralias(ap)) != NULL;) { 672 if (strncmp(ap->name, text, curpos) != 0) 673 continue; 674 rmatches = add_match(matches, ++i, &size, strdup(ap->name)); 675 if (rmatches == NULL) 676 goto out; 677 matches = rmatches; 678 } 679 for (const void *a = NULL; (a = itercmd(a, &e)) != NULL;) { 680 if (e.cmdtype != CMDFUNCTION) 681 continue; 682 if (strncmp(e.cmdname, text, curpos) != 0) 683 continue; 684 rmatches = add_match(matches, ++i, &size, strdup(e.cmdname)); 685 if (rmatches == NULL) 686 goto out; 687 matches = rmatches; 688 } 689 out: 690 free(free_path); 691 if (i == 0) { 692 free(matches); 693 return (NULL); 694 } 695 uniq = 1; 696 if (i > 1) { 697 qsort_s(matches + 1, i, sizeof(matches[0]), comparator, 698 (void *)(intptr_t)curpos); 699 for (size_t k = 2; k <= i; k++) { 700 const char *l = matches[uniq] + curpos; 701 const char *r = matches[k] + curpos; 702 size_t common = 0; 703 704 while (*l != '\0' && *r != '\0' && *l == *r) 705 (void)l++, r++, common++; 706 if (common < lcstring) 707 lcstring = common; 708 if (*l == *r) 709 free(matches[k]); 710 else 711 matches[++uniq] = matches[k]; 712 } 713 } 714 matches[uniq + 1] = NULL; 715 /* 716 * matches[0] is special: it's not a real matching file name but 717 * a common prefix for all matching names. It can't be null, unlike 718 * any other element of the array. When strings matches[0] and 719 * matches[1] compare equal and matches[2] is null that means to 720 * libedit that there is only a single match. It will then replace 721 * user input with possibly escaped string in matches[0] which is the 722 * reason to copy the full name of the only match. 723 */ 724 if (uniq == 1) 725 matches[0] = strdup(matches[1]); 726 else if (lcstring != (size_t)-1) 727 matches[0] = strndup(matches[1], curpos + lcstring); 728 else 729 matches[0] = strdup(text); 730 if (matches[0] == NULL) { 731 for (size_t k = 1; k <= uniq; k++) 732 free(matches[k]); 733 free(matches); 734 return (NULL); 735 } 736 return (matches); 737 } 738 739 /* 740 * If we don't specify this function as app_func in the call to fn_complete2, 741 * libedit will use the default one, which adds a " " to plain files and 742 * a "/" to directories regardless of whether it's a command name or a plain 743 * path (relative or absolute). We never want to add "/" to commands. 744 * 745 * For example, after I did "mkdir rmdir", "rmdi" would be autocompleted to 746 * "rmdir/" instead of "rmdir ". 747 */ 748 static const char * 749 append_char_function(const char *name) 750 { 751 struct stat stbuf; 752 char *expname = name[0] == '~' ? fn_tilde_expand(name) : NULL; 753 const char *rs; 754 755 if (!in_command_completion && 756 stat(expname ? expname : name, &stbuf) == 0 && 757 S_ISDIR(stbuf.st_mode)) 758 rs = "/"; 759 else 760 rs = " "; 761 free(expname); 762 return (rs); 763 } 764 765 /* 766 * This is passed to el_set(el, EL_ADDFN, ...) so that it's possible to 767 * bind a key (tab by default) to execute the function. 768 */ 769 unsigned char 770 sh_complete(EditLine *sel, int ch __unused) 771 { 772 return (unsigned char)fn_complete2(sel, NULL, sh_matches, 773 L" \t\n\"\\'`@$><=;|&{(", NULL, append_char_function, 774 (size_t)100, NULL, &((int) {0}), NULL, NULL, FN_QUOTE_MATCH); 775 } 776 777 #else 778 #include "error.h" 779 780 int 781 histcmd(int argc __unused, char **argv __unused) 782 { 783 784 error("not compiled with history support"); 785 /*NOTREACHED*/ 786 return (0); 787 } 788 789 int 790 bindcmd(int argc __unused, char **argv __unused) 791 { 792 793 error("not compiled with line editing support"); 794 return (0); 795 } 796 #endif 797