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