Changeset 3232 in MondoRescue for branches/3.2/mindi-busybox/shell/ash.c
- Timestamp:
- Jan 1, 2014, 12:47:38 AM (10 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/3.2/mindi-busybox/shell/ash.c
r2725 r3232 24 24 * define DEBUG=2 to compile in and turn on debugging. 25 25 * 26 * When debugging is on, debugging info will be written to ./trace and 27 * a quit signal will generate a core dump. 26 * When debugging is on (DEBUG is 1 and "set -o debug" was executed), 27 * debugging info will be written to ./trace and a quit signal 28 * will generate a core dump. 28 29 */ 29 30 #define DEBUG 0 … … 37 38 #define JOBS ENABLE_ASH_JOB_CONTROL 38 39 39 #include "busybox.h" /* for applet_names */40 40 #include <paths.h> 41 41 #include <setjmp.h> 42 42 #include <fnmatch.h> 43 43 #include <sys/times.h> 44 45 #include "busybox.h" /* for applet_names */ 46 #include "unicode.h" 44 47 45 48 #include "shell_common.h" … … 72 75 # error "Do not even bother, ash will not run on NOMMU machine" 73 76 #endif 74 75 //applet:IF_ASH(APPLET(ash, _BB_DIR_BIN, _BB_SUID_DROP))76 //applet:IF_FEATURE_SH_IS_ASH(APPLET_ODDNAME(sh, ash, _BB_DIR_BIN, _BB_SUID_DROP, sh))77 //applet:IF_FEATURE_BASH_IS_ASH(APPLET_ODDNAME(bash, ash, _BB_DIR_BIN, _BB_SUID_DROP, bash))78 79 //kbuild:lib-$(CONFIG_ASH) += ash.o ash_ptr_hack.o shell_common.o80 //kbuild:lib-$(CONFIG_ASH_RANDOM_SUPPORT) += random.o81 77 82 78 //config:config ASH … … 98 94 //config: Enable bash-compatible extensions. 99 95 //config: 96 //config:config ASH_IDLE_TIMEOUT 97 //config: bool "Idle timeout variable" 98 //config: default n 99 //config: depends on ASH 100 //config: help 101 //config: Enables bash-like auto-logout after $TMOUT seconds of idle time. 102 //config: 100 103 //config:config ASH_JOB_CONTROL 101 104 //config: bool "Job control" … … 106 109 //config: 107 110 //config:config ASH_ALIAS 108 //config: bool " alias support"111 //config: bool "Alias support" 109 112 //config: default y 110 113 //config: depends on ASH … … 117 120 //config: depends on ASH 118 121 //config: help 119 //config: Enable getopts builtin in the ash shell.122 //config: Enable support for getopts builtin in ash. 120 123 //config: 121 124 //config:config ASH_BUILTIN_ECHO … … 124 127 //config: depends on ASH 125 128 //config: help 126 //config: Enable support for echo , builtin toash.129 //config: Enable support for echo builtin in ash. 127 130 //config: 128 131 //config:config ASH_BUILTIN_PRINTF … … 131 134 //config: depends on ASH 132 135 //config: help 133 //config: Enable support for printf , builtin toash.136 //config: Enable support for printf builtin in ash. 134 137 //config: 135 138 //config:config ASH_BUILTIN_TEST … … 138 141 //config: depends on ASH 139 142 //config: help 140 //config: Enable support for test , builtin toash.143 //config: Enable support for test builtin in ash. 141 144 //config: 142 145 //config:config ASH_CMDCMD … … 154 157 //config: depends on ASH 155 158 //config: help 156 //config: Enable "check for new mail" in the ash shell.159 //config: Enable "check for new mail" function in the ash shell. 157 160 //config: 158 161 //config:config ASH_OPTIMIZE_FOR_SIZE … … 184 187 //config: 185 188 186 // usage:#define ash_trivial_usage NOUSAGE_STR187 // usage:#define ash_full_usage ""188 // usage:#define sh_trivial_usage NOUSAGE_STR189 //usage:#define sh_full_usage "" 190 // usage:#define bash_trivial_usage NOUSAGE_STR191 // usage:#define bash_full_usage ""189 //applet:IF_ASH(APPLET(ash, BB_DIR_BIN, BB_SUID_DROP)) 190 //applet:IF_FEATURE_SH_IS_ASH(APPLET_ODDNAME(sh, ash, BB_DIR_BIN, BB_SUID_DROP, sh)) 191 //applet:IF_FEATURE_BASH_IS_ASH(APPLET_ODDNAME(bash, ash, BB_DIR_BIN, BB_SUID_DROP, bash)) 192 193 //kbuild:lib-$(CONFIG_ASH) += ash.o ash_ptr_hack.o shell_common.o 194 //kbuild:lib-$(CONFIG_ASH_RANDOM_SUPPORT) += random.o 192 195 193 196 … … 401 404 402 405 /* ============ Interrupts / exceptions */ 406 407 static void exitshell(void) NORETURN; 408 403 409 /* 404 410 * These macros allow the user to suspend the handling of interrupt signals … … 1881 1887 #if ENABLE_ASH_MAIL 1882 1888 static void chkmail(void); 1883 static void changemail(const char *) FAST_FUNC; 1889 static void changemail(const char *var_value) FAST_FUNC; 1890 #else 1891 # define chkmail() ((void)0) 1884 1892 #endif 1885 1893 static void changepath(const char *) FAST_FUNC; … … 1893 1901 void (*var_func)(const char *) FAST_FUNC; 1894 1902 } varinit_data[] = { 1903 /* 1904 * Note: VEXPORT would not work correctly here for NOFORK applets: 1905 * some environment strings may be constant. 1906 */ 1895 1907 { VSTRFIXED|VTEXTFIXED , defifsvar , NULL }, 1896 1908 #if ENABLE_ASH_MAIL … … 3485 3497 case S_CATCH: 3486 3498 act.sa_handler = signal_handler; 3487 act.sa_flags = 0; /* matters only if !DFL and !IGN */3488 sigfillset(&act.sa_mask); /* ditto */3489 3499 break; 3490 3500 case S_IGN: … … 3492 3502 break; 3493 3503 } 3504 3505 /* flags and mask matter only if !DFL and !IGN, but we do it 3506 * for all cases for more deterministic behavior: 3507 */ 3508 act.sa_flags = 0; 3509 sigfillset(&act.sa_mask); 3510 3494 3511 sigaction_set(signo, &act); 3495 3512 … … 3528 3545 /* first remove from list */ 3529 3546 jpp = curp = &curjob; 3530 do{3547 while (1) { 3531 3548 jp1 = *jpp; 3532 3549 if (jp1 == jp) 3533 3550 break; 3534 3551 jpp = &jp1->prev_job; 3535 } while (1);3552 } 3536 3553 *jpp = jp1->prev_job; 3537 3554 … … 3548 3565 case CUR_RUNNING: 3549 3566 /* newly created job or backgrounded job, 3550 put after all stopped jobs. */ 3551 do { 3567 * put after all stopped jobs. 3568 */ 3569 while (1) { 3552 3570 jp1 = *jpp; 3553 3571 #if JOBS … … 3556 3574 break; 3557 3575 jpp = &jp1->prev_job; 3558 } while (1);3576 } 3559 3577 /* FALLTHROUGH */ 3560 3578 #if JOBS … … 3729 3747 /* fd is a tty at this point */ 3730 3748 close_on_exec_on(fd); 3731 do{ /* while we are in the background */3749 while (1) { /* while we are in the background */ 3732 3750 pgrp = tcgetpgrp(fd); 3733 3751 if (pgrp < 0) { … … 3740 3758 break; 3741 3759 killpg(0, SIGTTIN); 3742 } while (1);3760 } 3743 3761 initialpgrp = pgrp; 3744 3762 … … 3772 3790 killcmd(int argc, char **argv) 3773 3791 { 3774 int i = 1;3775 3792 if (argv[1] && strcmp(argv[1], "-l") != 0) { 3793 int i = 1; 3776 3794 do { 3777 3795 if (argv[i][0] == '%') { 3778 struct job *jp = getjob(argv[i], 0); 3779 unsigned pid = jp->ps[0].ps_pid; 3780 /* Enough space for ' -NNN<nul>' */ 3781 argv[i] = alloca(sizeof(int)*3 + 3); 3782 /* kill_main has matching code to expect 3783 * leading space. Needed to not confuse 3784 * negative pids with "kill -SIGNAL_NO" syntax */ 3785 sprintf(argv[i], " -%u", pid); 3796 /* 3797 * "kill %N" - job kill 3798 * Converting to pgrp / pid kill 3799 */ 3800 struct job *jp; 3801 char *dst; 3802 int j, n; 3803 3804 jp = getjob(argv[i], 0); 3805 /* 3806 * In jobs started under job control, we signal 3807 * entire process group by kill -PGRP_ID. 3808 * This happens, f.e., in interactive shell. 3809 * 3810 * Otherwise, we signal each child via 3811 * kill PID1 PID2 PID3. 3812 * Testcases: 3813 * sh -c 'sleep 1|sleep 1 & kill %1' 3814 * sh -c 'true|sleep 2 & sleep 1; kill %1' 3815 * sh -c 'true|sleep 1 & sleep 2; kill %1' 3816 */ 3817 n = jp->nprocs; /* can't be 0 (I hope) */ 3818 if (jp->jobctl) 3819 n = 1; 3820 dst = alloca(n * sizeof(int)*4); 3821 argv[i] = dst; 3822 for (j = 0; j < n; j++) { 3823 struct procstat *ps = &jp->ps[j]; 3824 /* Skip non-running and not-stopped members 3825 * (i.e. dead members) of the job 3826 */ 3827 if (ps->ps_status != -1 && !WIFSTOPPED(ps->ps_status)) 3828 continue; 3829 /* 3830 * kill_main has matching code to expect 3831 * leading space. Needed to not confuse 3832 * negative pids with "kill -SIGNAL_NO" syntax 3833 */ 3834 dst += sprintf(dst, jp->jobctl ? " -%u" : " %u", (int)ps->ps_pid); 3835 } 3836 *dst = '\0'; 3786 3837 } 3787 3838 } while (argv[++i]); … … 3881 3932 } 3882 3933 st &= 0x7f; 3934 //TODO: use bbox's get_signame? strsignal adds ~600 bytes to text+rodata 3883 3935 col = fmtstr(s, 32, strsignal(st)); 3884 3936 if (WCOREDUMP(status)) { … … 4215 4267 job = job->prev_job; 4216 4268 } 4217 } else 4269 } else { 4218 4270 job = getjob(*argv, 0); 4271 } 4219 4272 /* loop until process terminated or stopped */ 4220 4273 while (job->state == JOBRUNNING) … … 4712 4765 /* do job control only in root shell */ 4713 4766 doing_jobctl = 0; 4714 if (mode != FORK_NOJOB && jp->jobctl && !oldlvl) {4767 if (mode != FORK_NOJOB && jp->jobctl && oldlvl == 0) { 4715 4768 pid_t pgrp; 4716 4769 … … 4738 4791 } 4739 4792 } 4740 if ( !oldlvl) {4793 if (oldlvl == 0) { 4741 4794 if (iflag) { /* why if iflag only? */ 4742 4795 setsignal(SIGINT); … … 4945 4998 */ 4946 4999 5000 #undef EMPTY 5001 #undef CLOSED 4947 5002 #define EMPTY -2 /* marks an unused slot in redirtab */ 4948 5003 #define CLOSED -3 /* marks a slot of previously-closed fd */ … … 5057 5112 int f; 5058 5113 5114 fname = redir->nfile.expfname; 5059 5115 switch (redir->nfile.type) { 5060 5116 case NFROM: 5061 fname = redir->nfile.expfname;5062 5117 f = open(fname, O_RDONLY); 5063 5118 if (f < 0) … … 5065 5120 break; 5066 5121 case NFROMTO: 5067 fname = redir->nfile.expfname;5068 5122 f = open(fname, O_RDWR|O_CREAT, 0666); 5069 5123 if (f < 0) … … 5076 5130 /* Take care of noclobber mode. */ 5077 5131 if (Cflag) { 5078 fname = redir->nfile.expfname;5079 5132 f = noclobberopen(fname); 5080 5133 if (f < 0) … … 5084 5137 /* FALLTHROUGH */ 5085 5138 case NCLOBBER: 5086 fname = redir->nfile.expfname;5087 5139 f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666); 5088 5140 if (f < 0) … … 5090 5142 break; 5091 5143 case NAPPEND: 5092 fname = redir->nfile.expfname;5093 5144 f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666); 5094 5145 if (f < 0) … … 5870 5921 if (in.fd < 0) 5871 5922 break; 5872 i = nonblock_ safe_read(in.fd, buf, sizeof(buf));5923 i = nonblock_immune_read(in.fd, buf, sizeof(buf), /*loop_on_EINTR:*/ 1); 5873 5924 TRACE(("expbackq: read returns %d\n", i)); 5874 5925 if (i <= 0) … … 5922 5973 *p = '\0'; 5923 5974 p--; 5924 do{5975 while (1) { 5925 5976 int esc; 5926 5977 … … 5940 5991 5941 5992 p -= esc + 1; 5942 } while (1);5993 } 5943 5994 5944 5995 begoff = p - start; … … 6090 6141 goto addquote; 6091 6142 case CTLVAR: 6143 TRACE(("argstr: evalvar('%s')\n", p)); 6092 6144 p = evalvar(p, flags, var_str_list); 6145 TRACE(("argstr: evalvar:'%s'\n", (char *)stackblock())); 6093 6146 goto start; 6094 6147 case CTLBACKQ: … … 6287 6340 IF_ASH_BASH_COMPAT(int pos, len, orig_len;) 6288 6341 int saveherefd = herefd; 6289 int amount, workloc, resetloc; 6342 int amount, resetloc; 6343 IF_ASH_BASH_COMPAT(int workloc;) 6290 6344 int zero; 6291 6345 char *(*scan)(char*, char*, char*, char*, int, int); … … 6400 6454 str = (char *)stackblock() + strloc; 6401 6455 preglob(str, varflags & VSQUOTE, 0); 6456 6457 #if ENABLE_ASH_BASH_COMPAT 6402 6458 workloc = expdest - (char *)stackblock(); 6403 6404 #if ENABLE_ASH_BASH_COMPAT6405 6459 if (subtype == VSREPLACE || subtype == VSREPLACEALL) { 6406 6460 char *idx, *end; … … 6798 6852 if (NULL == subevalvar(p, /* varname: */ NULL, patloc, subtype, 6799 6853 startloc, varflags, 6800 //TODO: | EXP_REDIR too? All other such places do it too 6801 /* quotes: */ flags & (EXP_FULL | EXP_CASE), 6854 /* quotes: */ flags & (EXP_FULL | EXP_CASE | EXP_REDIR), 6802 6855 var_str_list) 6803 6856 ) { … … 7201 7254 ifsfirst.next = NULL; 7202 7255 ifslastp = NULL; 7256 TRACE(("expandarg: argstr('%s',flags:%x)\n", arg->narg.text, flag)); 7203 7257 argstr(arg->narg.text, flag, 7204 7258 /* var_str_list: */ arglist ? arglist->list : NULL); … … 7209 7263 } 7210 7264 p = grabstackstr(p); 7265 TRACE(("expandarg: p:'%s'\n", p)); 7211 7266 exparg.lastp = &exparg.list; 7212 7267 /* … … 7219 7274 expandmeta(exparg.list /*, flag*/); 7220 7275 } else { 7221 if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */7276 if (flag & EXP_REDIR) { /*XXX - for now, just remove escapes */ 7222 7277 rmescapes(p, 0); 7278 TRACE(("expandarg: rmescapes:'%s'\n", p)); 7279 } 7223 7280 sp = stzalloc(sizeof(*sp)); 7224 7281 sp->text = p; … … 7348 7405 tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) char *cmd, char **argv, char **envp) 7349 7406 { 7350 int repeated = 0;7351 7352 7407 #if ENABLE_FEATURE_SH_STANDALONE 7353 7408 if (applet_no >= 0) { … … 7373 7428 execve(cmd, argv, envp); 7374 7429 #endif 7375 if (repeated) { 7430 if (cmd == (char*) bb_busybox_exec_path) { 7431 /* We already visited ENOEXEC branch below, don't do it again */ 7432 //TODO: try execve(initial_argv0_of_shell, argv, envp) before giving up? 7376 7433 free(argv); 7377 7434 return; 7378 7435 } 7379 7436 if (errno == ENOEXEC) { 7437 /* Run "cmd" as a shell script: 7438 * http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html 7439 * "If the execve() function fails with ENOEXEC, the shell 7440 * shall execute a command equivalent to having a shell invoked 7441 * with the command name as its first operand, 7442 * with any remaining arguments passed to the new shell" 7443 * 7444 * That is, do not use $SHELL, user's shell, or /bin/sh; 7445 * just call ourselves. 7446 * 7447 * Note that bash reads ~80 chars of the file, and if it sees 7448 * a zero byte before it sees newline, it doesn't try to 7449 * interpret it, but fails with "cannot execute binary file" 7450 * message and exit code 126. For one, this prevents attempts 7451 * to interpret foreign ELF binaries as shell scripts. 7452 */ 7380 7453 char **ap; 7381 7454 char **new; … … 7383 7456 for (ap = argv; *ap; ap++) 7384 7457 continue; 7385 ap = new = ckmalloc((ap - argv + 2) * sizeof(ap[0])); 7386 ap[1] = cmd; 7387 ap[0] = cmd = (char *)DEFAULT_SHELL; 7388 ap += 2; 7389 argv++; 7390 while ((*ap++ = *argv++) != NULL) 7458 new = ckmalloc((ap - argv + 2) * sizeof(new[0])); 7459 new[0] = (char*) "ash"; 7460 new[1] = cmd; 7461 ap = new + 2; 7462 while ((*ap++ = *++argv) != NULL) 7391 7463 continue; 7464 cmd = (char*) bb_busybox_exec_path; 7392 7465 argv = new; 7393 repeated++;7394 7466 goto repeat; 7395 7467 } … … 7408 7480 char **envp; 7409 7481 int exerrno; 7410 #if ENABLE_FEATURE_SH_STANDALONE 7411 int applet_no = -1; 7412 #endif 7482 int applet_no = -1; /* used only by FEATURE_SH_STANDALONE */ 7413 7483 7414 7484 clearredir(/*drop:*/ 1); … … 7420 7490 ) { 7421 7491 tryexec(IF_FEATURE_SH_STANDALONE(applet_no,) argv[0], argv, envp); 7492 if (applet_no >= 0) { 7493 /* We tried execing ourself, but it didn't work. 7494 * Maybe /proc/self/exe doesn't exist? 7495 * Try $PATH search. 7496 */ 7497 goto try_PATH; 7498 } 7422 7499 e = errno; 7423 7500 } else { 7501 try_PATH: 7424 7502 e = ENOENT; 7425 7503 while ((cmdname = path_advance(&path, argv[0])) != NULL) { … … 8596 8674 case NAPPEND: 8597 8675 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR); 8676 TRACE(("expredir expanded to '%s'\n", fn.list->text)); 8598 8677 #if ENABLE_ASH_BASH_COMPAT 8599 8678 store_expfname: 8679 #endif 8680 #if 0 8681 // By the design of stack allocator, the loop of this kind: 8682 // while true; do while true; do break; done </dev/null; done 8683 // will look like a memory leak: ash plans to free expfname's 8684 // of "/dev/null" as soon as it finishes running the loop 8685 // (in this case, never). 8686 // This "fix" is wrong: 8687 if (redir->nfile.expfname) 8688 stunalloc(redir->nfile.expfname); 8689 // It results in corrupted state of stacked allocations. 8600 8690 #endif 8601 8691 redir->nfile.expfname = fn.list->text; … … 9234 9324 /* Now locate the command. */ 9235 9325 if (argc) { 9236 const char *oldpath;9237 9326 int cmd_flag = DO_ERR; 9238 9327 #if ENABLE_ASH_CMDCMD 9328 const char *oldpath = path + 5; 9329 #endif 9239 9330 path += 5; 9240 oldpath = path;9241 9331 for (;;) { 9242 9332 find_command(argv[0], &cmdentry, cmd_flag, path); … … 9560 9650 retry: 9561 9651 if (!iflag || g_parsefile->pf_fd != STDIN_FILENO) 9562 nr = nonblock_ safe_read(g_parsefile->pf_fd, buf, IBUFSIZ -1);9652 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1, /*loop_on_EINTR:*/ 1); 9563 9653 else { 9564 #if ENABLE_FEATURE_TAB_COMPLETION 9654 int timeout = -1; 9655 # if ENABLE_ASH_IDLE_TIMEOUT 9656 if (iflag) { 9657 const char *tmout_var = lookupvar("TMOUT"); 9658 if (tmout_var) { 9659 timeout = atoi(tmout_var) * 1000; 9660 if (timeout <= 0) 9661 timeout = -1; 9662 } 9663 } 9664 # endif 9665 # if ENABLE_FEATURE_TAB_COMPLETION 9565 9666 line_input_state->path_lookup = pathval(); 9566 #endif 9567 nr = read_line_input(cmdedit_prompt, buf, IBUFSIZ, line_input_state); 9667 # endif 9668 /* Unicode support should be activated even if LANG is set 9669 * _during_ shell execution, not only if it was set when 9670 * shell was started. Therefore, re-check LANG every time: 9671 */ 9672 reinit_unicode(lookupvar("LANG")); 9673 nr = read_line_input(line_input_state, cmdedit_prompt, buf, IBUFSIZ, timeout); 9568 9674 if (nr == 0) { 9569 9675 /* Ctrl+C pressed */ … … 9576 9682 goto retry; 9577 9683 } 9578 if (nr < 0 && errno == 0) { 9579 /* Ctrl+D pressed */ 9580 nr = 0; 9684 if (nr < 0) { 9685 if (errno == 0) { 9686 /* Ctrl+D pressed */ 9687 nr = 0; 9688 } 9689 # if ENABLE_ASH_IDLE_TIMEOUT 9690 else if (errno == EAGAIN && timeout > 0) { 9691 printf("\007timed out waiting for input: auto-logout\n"); 9692 exitshell(); 9693 } 9694 # endif 9581 9695 } 9582 9696 } 9583 9697 #else 9584 nr = nonblock_safe_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1); 9585 #endif 9586 9587 #if 0 9588 /* nonblock_safe_read() handles this problem */ 9698 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1, /*loop_on_EINTR:*/ 1); 9699 #endif 9700 9701 #if 0 /* disabled: nonblock_immune_read() handles this problem */ 9589 9702 if (nr < 0) { 9590 9703 if (parsefile->fd == 0 && errno == EWOULDBLOCK) { … … 10105 10218 setparam(argptr); 10106 10219 } 10107 break; /* "-" or 10220 break; /* "-" or "--" terminates options */ 10108 10221 } 10109 10222 } … … 10207 10320 if (!argv[1]) 10208 10321 return showvars(nullstr, 0, VUNSET); 10322 10209 10323 INT_OFF; 10210 retval = 1; 10211 if (!options(0)) { /* if no parse error... */ 10212 retval = 0; 10324 retval = options(/*cmdline:*/ 0); 10325 if (retval == 0) { /* if no parse error... */ 10213 10326 optschanged(); 10214 10327 if (*argptr != NULL) { … … 11538 11651 if (oldstyle) { 11539 11652 /* We must read until the closing backquote, giving special 11540 treatment to some slashes, and then push the string and 11541 reread it as input, interpreting it normally. */ 11653 * treatment to some slashes, and then push the string and 11654 * reread it as input, interpreting it normally. 11655 */ 11542 11656 char *pout; 11543 11657 size_t psavelen; … … 12071 12185 if (iflag && top) { 12072 12186 inter++; 12073 #if ENABLE_ASH_MAIL12074 12187 chkmail(); 12075 #endif12076 12188 } 12077 12189 n = parsecmd(inter); … … 12532 12644 const char *p; 12533 12645 char **aptr; 12534 int flag = argv[0][0] == 'r' ? VREADONLY : VEXPORT; 12535 12536 if (nextopt("p") != 'p') { 12646 char opt; 12647 int flag; 12648 int flag_off; 12649 12650 /* "readonly" in bash accepts, but ignores -n. 12651 * We do the same: it saves a conditional in nextopt's param. 12652 */ 12653 flag_off = 0; 12654 while ((opt = nextopt("np")) != '\0') { 12655 if (opt == 'n') 12656 flag_off = VEXPORT; 12657 } 12658 flag = VEXPORT; 12659 if (argv[0][0] == 'r') { 12660 flag = VREADONLY; 12661 flag_off = 0; /* readonly ignores -n */ 12662 } 12663 flag_off = ~flag_off; 12664 12665 /*if (opt_p_not_specified) - bash doesnt check this. Try "export -p NAME" */ 12666 { 12537 12667 aptr = argptr; 12538 12668 name = *aptr; … … 12545 12675 vp = *findvar(hashvar(name), name); 12546 12676 if (vp) { 12547 vp->flags |= flag;12677 vp->flags = ((vp->flags | flag) & flag_off); 12548 12678 continue; 12549 12679 } 12550 12680 } 12551 setvar(name, p, flag);12681 setvar(name, p, (flag & flag_off)); 12552 12682 } while ((name = *++aptr) != NULL); 12553 12683 return 0; 12554 12684 } 12555 12685 } 12686 12687 /* No arguments. Show the list of exported or readonly vars. 12688 * -n is ignored. 12689 */ 12556 12690 showvars(argv[0], flag, 0); 12557 12691 return 0; … … 12706 12840 } 12707 12841 12842 /* "read -s" needs to save/restore termios, can't allow ^C 12843 * to jump out of it. 12844 */ 12845 INT_OFF; 12708 12846 r = shell_builtin_read(setvar2, 12709 12847 argptr, … … 12715 12853 opt_u 12716 12854 ); 12855 INT_ON; 12717 12856 12718 12857 if ((uintptr_t)r > 1) … … 12803 12942 * Called to exit the shell. 12804 12943 */ 12805 static void exitshell(void) NORETURN;12806 12944 static void 12807 12945 exitshell(void) … … 12810 12948 char *p; 12811 12949 int status; 12950 12951 #if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT 12952 save_history(line_input_state); 12953 #endif 12812 12954 12813 12955 status = exitstatus; … … 12866 13008 12867 13009 p = lookupvar("PWD"); 12868 if (p) 13010 if (p) { 12869 13011 if (*p != '/' || stat(p, &st1) || stat(".", &st2) 12870 || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino) 13012 || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino 13013 ) { 12871 13014 p = '\0'; 13015 } 13016 } 12872 13017 setpwd(p, 0); 12873 13018 } 12874 13019 } 13020 13021 13022 //usage:#define ash_trivial_usage 13023 //usage: "[-/+OPTIONS] [-/+o OPT]... [-c 'SCRIPT' [ARG0 [ARGS]] / FILE [ARGS]]" 13024 //usage:#define ash_full_usage "\n\n" 13025 //usage: "Unix shell interpreter" 13026 13027 //usage:#if ENABLE_FEATURE_SH_IS_ASH 13028 //usage:# define sh_trivial_usage ash_trivial_usage 13029 //usage:# define sh_full_usage ash_full_usage 13030 //usage:#endif 13031 //usage:#if ENABLE_FEATURE_BASH_IS_ASH 13032 //usage:# define bash_trivial_usage ash_trivial_usage 13033 //usage:# define bash_full_usage ash_full_usage 13034 //usage:#endif 12875 13035 12876 13036 /* … … 12891 13051 optlist[i] = 2; 12892 13052 argptr = xargv; 12893 if (options( 1)) {13053 if (options(/*cmdline:*/ 1)) { 12894 13054 /* it already printed err message */ 12895 13055 raise_exception(EXERROR); … … 13053 13213 if (iflag) { 13054 13214 const char *hp = lookupvar("HISTFILE"); 13055 13056 if (hp == NULL) { 13215 if (!hp) { 13057 13216 hp = lookupvar("HOME"); 13058 if (hp != NULL) {13217 if (hp) { 13059 13218 char *defhp = concat_path_file(hp, ".ash_history"); 13060 13219 setvar("HISTFILE", defhp, 0); … … 13064 13223 } 13065 13224 #endif 13066 if ( /* argv[0] && */argv[0][0] == '-')13225 if (argv[0] && argv[0][0] == '-') 13067 13226 isloginsh = 1; 13068 13227 if (isloginsh) { … … 13100 13259 13101 13260 if (sflag || minusc == NULL) { 13102 #if defined MAX_HISTORY &&MAX_HISTORY > 0 && ENABLE_FEATURE_EDITING_SAVEHISTORY13261 #if MAX_HISTORY > 0 && ENABLE_FEATURE_EDITING_SAVEHISTORY 13103 13262 if (iflag) { 13104 13263 const char *hp = lookupvar("HISTFILE"); 13105 13264 if (hp) 13106 13265 line_input_state->hist_file = hp; 13266 # if ENABLE_FEATURE_SH_HISTFILESIZE 13267 hp = lookupvar("HISTFILESIZE"); 13268 line_input_state->max_history = size_from_HISTFILESIZE(hp); 13269 # endif 13107 13270 } 13108 13271 #endif
Note:
See TracChangeset
for help on using the changeset viewer.