Changeset 3621 in MondoRescue for branches/3.3/mindi-busybox/shell/hush.c
- Timestamp:
- Dec 20, 2016, 4:07:32 PM (7 years ago)
- Location:
- branches/3.3
- Files:
-
- 1 edited
- 1 copied
Legend:
- Unmodified
- Added
- Removed
-
branches/3.3/mindi-busybox/shell/hush.c
r3232 r3621 92 92 # include <fnmatch.h> 93 93 #endif 94 #include <sys/utsname.h> /* for setting $HOSTNAME */ 94 95 95 96 #include "busybox.h" /* for APPLET_IS_NOFORK/NOEXEC */ … … 442 443 DEFINITELY_ASSIGNMENT = 1, 443 444 NOT_ASSIGNMENT = 2, 444 /* Not an assig ment, but next word may be: "if v=xyz cmd;" */445 /* Not an assignment, but next word may be: "if v=xyz cmd;" */ 445 446 WORD_IS_KEYWORD = 3, 446 447 }; … … 851 852 static int builtin_help(char **argv) FAST_FUNC; 852 853 #endif 854 #if MAX_HISTORY && ENABLE_FEATURE_EDITING 855 static int builtin_history(char **argv) FAST_FUNC; 856 #endif 853 857 #if ENABLE_HUSH_LOCAL 854 858 static int builtin_local(char **argv) FAST_FUNC; … … 920 924 BLTIN("help" , builtin_help , NULL), 921 925 #endif 926 #if MAX_HISTORY && ENABLE_FEATURE_EDITING 927 BLTIN("history" , builtin_history , "Show command history"), 928 #endif 922 929 #if ENABLE_HUSH_JOB 923 930 BLTIN("jobs" , builtin_jobs , "List jobs"), … … 939 946 #endif 940 947 BLTIN("trap" , builtin_trap , "Trap signals"), 948 BLTIN("true" , builtin_true , NULL), 941 949 BLTIN("type" , builtin_type , "Show command type"), 942 950 BLTIN("ulimit" , shell_builtin_ulimit , "Control resource limits"), … … 1305 1313 * pipe. 1306 1314 * 1307 * Wait builtin i ninterruptible by signals for which user trap is set1315 * Wait builtin is interruptible by signals for which user trap is set 1308 1316 * or by SIGINT in interactive shell. 1309 1317 * … … 1384 1392 * 1385 1393 * Problem: the above approach makes it unwieldy to catch signals while 1386 * we are in read builtin, o fwhile we read commands from stdin:1394 * we are in read builtin, or while we read commands from stdin: 1387 1395 * masked signals are not visible! 1388 1396 * … … 1393 1401 * We are interested in: signals which need to have special handling 1394 1402 * as described above, and all signals which have traps set. 1395 * Signals are r ocorded in pending_set.1403 * Signals are recorded in pending_set. 1396 1404 * After each pipe execution, we extract any pending signals 1397 1405 * and act on them. … … 1470 1478 } 1471 1479 1480 static void hush_exit(int exitcode) NORETURN; 1481 static void fflush_and__exit(void) NORETURN; 1482 static void restore_ttypgrp_and__exit(void) NORETURN; 1483 1484 static void restore_ttypgrp_and__exit(void) 1485 { 1486 /* xfunc has failed! die die die */ 1487 /* no EXIT traps, this is an escape hatch! */ 1488 G.exiting = 1; 1489 hush_exit(xfunc_error_retval); 1490 } 1491 1492 /* Needed only on some libc: 1493 * It was observed that on exit(), fgetc'ed buffered data 1494 * gets "unwound" via lseek(fd, -NUM, SEEK_CUR). 1495 * With the net effect that even after fork(), not vfork(), 1496 * exit() in NOEXECed applet in "sh SCRIPT": 1497 * noexec_applet_here 1498 * echo END_OF_SCRIPT 1499 * lseeks fd in input FILE object from EOF to "e" in "echo END_OF_SCRIPT". 1500 * This makes "echo END_OF_SCRIPT" executed twice. 1501 * Similar problems can be seen with die_if_script() -> xfunc_die() 1502 * and in `cmd` handling. 1503 * If set as die_func(), this makes xfunc_die() exit via _exit(), not exit(): 1504 */ 1505 static void fflush_and__exit(void) 1506 { 1507 fflush_all(); 1508 _exit(xfunc_error_retval); 1509 } 1510 1472 1511 #if ENABLE_HUSH_JOB 1473 1512 1474 1513 /* After [v]fork, in child: do not restore tty pgrp on xfunc death */ 1475 # define disable_restore_tty_pgrp_on_exit() (die_ sleep = 0)1514 # define disable_restore_tty_pgrp_on_exit() (die_func = fflush_and__exit) 1476 1515 /* After [v]fork, in parent: restore tty pgrp on xfunc death */ 1477 # define enable_restore_tty_pgrp_on_exit() (die_ sleep = -1)1516 # define enable_restore_tty_pgrp_on_exit() (die_func = restore_ttypgrp_and__exit) 1478 1517 1479 1518 /* Restores tty foreground process group, and exits. … … 1481 1520 * (will resend signal to itself, producing correct exit state) 1482 1521 * or called directly with -EXITCODE. 1483 * We also call it if xfunc is exiting. */ 1522 * We also call it if xfunc is exiting. 1523 */ 1484 1524 static void sigexit(int sig) NORETURN; 1485 1525 static void sigexit(int sig) … … 1536 1576 1537 1577 /* Restores tty foreground process group, and exits. */ 1538 static void hush_exit(int exitcode) NORETURN;1539 1578 static void hush_exit(int exitcode) 1540 1579 { … … 1572 1611 #endif 1573 1612 1613 fflush_all(); 1574 1614 #if ENABLE_HUSH_JOB 1575 fflush_all();1576 1615 sigexit(- (exitcode & 0xff)); 1577 1616 #else 1578 exit(exitcode);1617 _exit(exitcode); 1579 1618 #endif 1580 1619 } … … 1749 1788 struct variable **var_pp; 1750 1789 struct variable *cur; 1790 char *free_me = NULL; 1751 1791 char *eq_sign; 1752 1792 int name_len; … … 1765 1805 continue; 1766 1806 } 1807 1767 1808 /* We found an existing var with this name */ 1768 1809 if (cur->flg_read_only) { … … 1813 1854 goto free_and_exp; 1814 1855 } 1815 } else { 1816 /* max_len == 0 signifies "malloced" var, which we can 1817 * (and has to) free */ 1818 free(cur->varstr); 1819 } 1820 cur->max_len = 0; 1856 /* Can't reuse */ 1857 cur->max_len = 0; 1858 goto set_str_and_exp; 1859 } 1860 /* max_len == 0 signifies "malloced" var, which we can 1861 * (and have to) free. But we can't free(cur->varstr) here: 1862 * if cur->flg_export is 1, it is in the environment. 1863 * We should either unsetenv+free, or wait until putenv, 1864 * then putenv(new)+free(old). 1865 */ 1866 free_me = cur->varstr; 1821 1867 goto set_str_and_exp; 1822 1868 } … … 1845 1891 /* unsetenv was already done */ 1846 1892 } else { 1893 int i; 1847 1894 debug_printf_env("%s: putenv '%s'\n", __func__, cur->varstr); 1848 return putenv(cur->varstr); 1849 } 1850 } 1895 i = putenv(cur->varstr); 1896 /* only now we can free old exported malloced string */ 1897 free(free_me); 1898 return i; 1899 } 1900 } 1901 free(free_me); 1851 1902 return 0; 1852 1903 } … … 1966 2017 } 1967 2018 return old; 2019 } 2020 2021 2022 /* 2023 * Unicode helper 2024 */ 2025 static void reinit_unicode_for_hush(void) 2026 { 2027 /* Unicode support should be activated even if LANG is set 2028 * _during_ shell execution, not only if it was set when 2029 * shell was started. Therefore, re-check LANG every time: 2030 */ 2031 if (ENABLE_FEATURE_CHECK_UNICODE_IN_ENV 2032 || ENABLE_UNICODE_USING_LOCALE 2033 ) { 2034 const char *s = get_local_var_value("LC_ALL"); 2035 if (!s) s = get_local_var_value("LC_CTYPE"); 2036 if (!s) s = get_local_var_value("LANG"); 2037 reinit_unicode(s); 2038 } 1968 2039 } 1969 2040 … … 2035 2106 * is actually being read */ 2036 2107 do { 2037 /* Unicode support should be activated even if LANG is set 2038 * _during_ shell execution, not only if it was set when 2039 * shell was started. Therefore, re-check LANG every time: 2040 */ 2041 reinit_unicode(get_local_var_value("LANG")); 2042 2108 reinit_unicode_for_hush(); 2043 2109 G.flag_SIGINT = 0; 2044 2110 /* buglet: SIGINT will not make new prompt to appear _at once_, … … 3139 3205 old->command->cmd_type = CMD_NORMAL; 3140 3206 # if !BB_MMU 3141 o_addstr(&old->as_string, ctx->as_string.data); 3142 o_free_unsafe(&ctx->as_string); 3143 old->command->group_as_string = xstrdup(old->as_string.data); 3144 debug_printf_parse("pop, remembering as:'%s'\n", 3145 old->command->group_as_string); 3207 /* At this point, the compound command's string is in 3208 * ctx->as_string... except for the leading keyword! 3209 * Consider this example: "echo a | if true; then echo a; fi" 3210 * ctx->as_string will contain "true; then echo a; fi", 3211 * with "if " remaining in old->as_string! 3212 */ 3213 { 3214 char *str; 3215 int len = old->as_string.length; 3216 /* Concatenate halves */ 3217 o_addstr(&old->as_string, ctx->as_string.data); 3218 o_free_unsafe(&ctx->as_string); 3219 /* Find where leading keyword starts in first half */ 3220 str = old->as_string.data + len; 3221 if (str > old->as_string.data) 3222 str--; /* skip whitespace after keyword */ 3223 while (str > old->as_string.data && isalpha(str[-1])) 3224 str--; 3225 /* Ugh, we're done with this horrid hack */ 3226 old->command->group_as_string = xstrdup(str); 3227 debug_printf_parse("pop, remembering as:'%s'\n", 3228 old->command->group_as_string); 3229 } 3146 3230 # endif 3147 3231 *ctx = *old; /* physical copy */ … … 4226 4310 } 4227 4311 #if !BB_MMU 4228 debug_printf_parse("as_string '%s'\n", ctx.as_string.data);4312 debug_printf_parse("as_string1 '%s'\n", ctx.as_string.data); 4229 4313 if (pstring) 4230 4314 *pstring = ctx.as_string.data; … … 4377 4461 o_free(&dest); 4378 4462 #if !BB_MMU 4379 debug_printf_parse("as_string '%s'\n", ctx.as_string.data);4463 debug_printf_parse("as_string2 '%s'\n", ctx.as_string.data); 4380 4464 if (pstring) 4381 4465 *pstring = ctx.as_string.data; … … 4617 4701 * "echo foo 2| cat" yields "foo 2". */ 4618 4702 done_command(&ctx); 4619 #if !BB_MMU4620 o_reset_to_empty_unquoted(&ctx.as_string);4621 #endif4622 4703 } 4623 4704 goto new_cmd; … … 5018 5099 /* Handle any expansions */ 5019 5100 if (exp_op == 'L') { 5101 reinit_unicode_for_hush(); 5020 5102 debug_printf_expand("expand: length(%s)=", val); 5021 val = utoa(val ? strlen(val) : 0);5103 val = utoa(val ? unicode_strlen(val) : 0); 5022 5104 debug_printf_expand("%s\n", val); 5023 5105 } else if (exp_op) { … … 5367 5449 } 5368 5450 break; 5369 5370 5451 } /* switch (char after <SPECIAL_VAR_SYMBOL>) */ 5371 5452 … … 5861 5942 */ 5862 5943 s = skip_whitespace(s); 5863 if ( strncmp(s, "trap", 4) == 05944 if (is_prefixed_with(s, "trap") 5864 5945 && skip_whitespace(s + 4)[0] == '\0' 5865 5946 ) { 5866 5947 static const char *const argv[] = { NULL, NULL }; 5867 5948 builtin_trap((char**)argv); 5868 exit(0); /* not _exit() - we need to fflush */ 5949 fflush_all(); /* important */ 5950 _exit(0); 5869 5951 } 5870 5952 # if BB_MMU … … 6419 6501 * Don't exit() here. If you don't exec, use _exit instead. 6420 6502 * The at_exit handlers apparently confuse the calling process, 6421 * in particular stdin handling. Not sure why? -- because of vfork! (vda) */ 6503 * in particular stdin handling. Not sure why? -- because of vfork! (vda) 6504 */ 6422 6505 static void pseudo_exec_argv(nommu_save_t *nommu_save, 6423 6506 char **argv, int assignment_cnt, … … 6757 6840 if (i == fg_pipe->num_cmds-1) 6758 6841 /* TODO: use strsignal() instead for bash compat? but that's bloat... */ 6759 p rintf("%s\n",sig == SIGINT || sig == SIGPIPE ? "" : get_signame(sig));6842 puts(sig == SIGINT || sig == SIGPIPE ? "" : get_signame(sig)); 6760 6843 /* TODO: if (WCOREDUMP(status)) + " (core dumped)"; */ 6761 6844 /* TODO: MIPS has 128 sigs (1..128), what if sig==128 here? … … 7355 7438 debug_printf_exec("skipped cmd because of || or &&\n"); 7356 7439 last_followup = pi->followup; 7357 continue;7440 goto dont_check_jobs_but_continue; 7358 7441 } 7359 7442 } … … 7494 7577 /* else: e.g. "continue 2" should *break* once, *then* continue */ 7495 7578 } /* else: "while... do... { we are here (innermost list is not a loop!) };...done" */ 7496 if (G.depth_break_continue != 0 || fbc == BC_BREAK) 7497 goto check_jobs_and_break; 7579 if (G.depth_break_continue != 0 || fbc == BC_BREAK) { 7580 checkjobs(NULL); 7581 break; 7582 } 7498 7583 /* "continue": simulate end of loop */ 7499 7584 rword = RES_DONE; … … 7503 7588 #if ENABLE_HUSH_FUNCTIONS 7504 7589 if (G.flag_return_in_progress == 1) { 7505 /* same as "goto check_jobs_and_break" */7506 7590 checkjobs(NULL); 7507 7591 break; … … 7545 7629 cond_code = rcode; 7546 7630 #endif 7631 check_jobs_and_continue: 7632 checkjobs(NULL); 7633 dont_check_jobs_but_continue: ; 7547 7634 #if ENABLE_HUSH_LOOPS 7548 7635 /* Beware of "while false; true; do ..."! */ … … 7556 7643 G.last_exitcode = rcode = EXIT_SUCCESS; 7557 7644 debug_printf_exec(": while expr is false: breaking (exitcode:EXIT_SUCCESS)\n"); 7558 goto check_jobs_and_break;7645 break; 7559 7646 } 7560 7647 } … … 7562 7649 if (!rcode) { 7563 7650 debug_printf_exec(": until expr is true: breaking\n"); 7564 check_jobs_and_break:7565 checkjobs(NULL);7566 7651 break; 7567 7652 } … … 7569 7654 } 7570 7655 #endif 7571 7572 check_jobs_and_continue:7573 checkjobs(NULL);7574 7656 } /* for (pi) */ 7575 7657 … … 7741 7823 if (EXIT_SUCCESS != 0) /* if EXIT_SUCCESS == 0, it is already done */ 7742 7824 G.last_exitcode = EXIT_SUCCESS; 7825 7743 7826 #if ENABLE_HUSH_FAST 7744 7827 G.count_SIGCHLD++; /* ensure it is != G.handled_SIGCHLD */ … … 7778 7861 /* Export PWD */ 7779 7862 set_pwd_var(/*exp:*/ 1); 7863 7864 #if ENABLE_HUSH_BASH_COMPAT 7865 /* Set (but not export) HOSTNAME unless already set */ 7866 if (!get_local_var_value("HOSTNAME")) { 7867 struct utsname uts; 7868 uname(&uts); 7869 set_local_var_from_halves("HOSTNAME", uts.nodename); 7870 } 7780 7871 /* bash also exports SHLVL and _, 7781 7872 * and sets (but doesn't export) the following variables: … … 7786 7877 * MACHTYPE=i386-pc-linux-gnu 7787 7878 * OSTYPE=linux-gnu 7788 * HOSTNAME=<xxxxxxxxxx>7789 7879 * PPID=<NNNNN> - we also do it elsewhere 7790 7880 * EUID=<NNNNN> … … 7814 7904 * PS4='+ ' 7815 7905 */ 7906 #endif 7816 7907 7817 7908 #if ENABLE_FEATURE_EDITING … … 7822 7913 cmdedit_update_prompt(); 7823 7914 7824 if (setjmp(die_jmp)) { 7825 /* xfunc has failed! die die die */ 7826 /* no EXIT traps, this is an escape hatch! */ 7827 G.exiting = 1; 7828 hush_exit(xfunc_error_retval); 7829 } 7915 die_func = restore_ttypgrp_and__exit; 7830 7916 7831 7917 /* Shell is non-interactive at first. We need to call … … 8085 8171 tcsetpgrp(G_interactive_fd, getpid()); 8086 8172 } 8087 /* -1 is special - makes xfuncs longjmp, not exit 8088 * (we reset die_sleep = 0 whereever we [v]fork) */ 8089 enable_restore_tty_pgrp_on_exit(); /* sets die_sleep = -1 */ 8173 enable_restore_tty_pgrp_on_exit(); 8090 8174 8091 8175 # if ENABLE_HUSH_SAVEHISTORY && MAX_HISTORY > 0 … … 8625 8709 } 8626 8710 bb_putchar('\n'); 8711 return EXIT_SUCCESS; 8712 } 8713 #endif 8714 8715 #if MAX_HISTORY && ENABLE_FEATURE_EDITING 8716 static int FAST_FUNC builtin_history(char **argv UNUSED_PARAM) 8717 { 8718 show_history(G.line_input_state); 8627 8719 return EXIT_SUCCESS; 8628 8720 } … … 8881 8973 if (!input) { 8882 8974 /* bb_perror_msg("%s", *argv); - done by fopen_or_warn */ 8975 /* POSIX: non-interactive shell should abort here, 8976 * not merely fail. So far no one complained :) 8977 */ 8883 8978 return EXIT_FAILURE; 8884 8979 } … … 8890 8985 G.flag_return_in_progress = -1; 8891 8986 #endif 8892 save_and_replace_G_args(&sv, argv); 8987 if (argv[1]) 8988 save_and_replace_G_args(&sv, argv); 8893 8989 8894 8990 parse_and_run_file(input); 8895 8991 fclose(input); 8896 8992 8897 restore_G_args(&sv, argv); 8993 if (argv[1]) 8994 restore_G_args(&sv, argv); 8898 8995 #if ENABLE_HUSH_FUNCTIONS 8899 8996 G.flag_return_in_progress = sv_flg; … … 8908 9005 mode_t mask; 8909 9006 9007 rc = 1; 8910 9008 mask = umask(0); 8911 9009 argv = skip_dash_dash(argv); … … 8913 9011 mode_t old_mask = mask; 8914 9012 8915 mask ^= 0777; 8916 rc = bb_parse_mode(argv[0], &mask); 8917 mask ^= 0777; 8918 if (rc == 0) { 9013 /* numeric umasks are taken as-is */ 9014 /* symbolic umasks are inverted: "umask a=rx" calls umask(222) */ 9015 if (!isdigit(argv[0][0])) 9016 mask ^= 0777; 9017 mask = bb_parse_mode(argv[0], mask); 9018 if (!isdigit(argv[0][0])) 9019 mask ^= 0777; 9020 if ((unsigned)mask > 0777) { 8919 9021 mask = old_mask; 8920 9022 /* bash messages: … … 8923 9025 */ 8924 9026 bb_error_msg("%s: invalid mode '%s'", "umask", argv[0]); 9027 rc = 0; 8925 9028 } 8926 9029 } else { 8927 rc = 1;8928 9030 /* Mimic bash */ 8929 9031 printf("%04o\n", (unsigned) mask); … … 9055 9157 } 9056 9158 if (waitpid(pid, &status, 0) == pid) { 9159 ret = WEXITSTATUS(status); 9057 9160 if (WIFSIGNALED(status)) 9058 9161 ret = 128 + WTERMSIG(status); 9059 else if (WIFEXITED(status))9060 ret = WEXITSTATUS(status);9061 else /* wtf? */9062 ret = EXIT_FAILURE;9063 9162 } else { 9064 9163 bb_perror_msg("wait %s", *argv);
Note:
See TracChangeset
for help on using the changeset viewer.