aboutsummaryrefslogtreecommitdiff
path: root/shell/ash.c
diff options
context:
space:
mode:
Diffstat (limited to 'shell/ash.c')
-rw-r--r--shell/ash.c122
1 files changed, 92 insertions, 30 deletions
diff --git a/shell/ash.c b/shell/ash.c
index 28f988698..fd9141661 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -111,6 +111,13 @@
111//config: help 111//config: help
112//config: Enable bash-compatible extensions. 112//config: Enable bash-compatible extensions.
113//config: 113//config:
114//config:config ASH_IDLE_TIMEOUT
115//config: bool "Idle timeout variable"
116//config: default n
117//config: depends on ASH
118//config: help
119//config: Enables bash-like auto-logout after $TMOUT seconds of idle time.
120//config:
114//config:config ASH_JOB_CONTROL 121//config:config ASH_JOB_CONTROL
115//config: bool "Job control" 122//config: bool "Job control"
116//config: default y 123//config: default y
@@ -119,7 +126,7 @@
119//config: Enable job control in the ash shell. 126//config: Enable job control in the ash shell.
120//config: 127//config:
121//config:config ASH_ALIAS 128//config:config ASH_ALIAS
122//config: bool "alias support" 129//config: bool "Alias support"
123//config: default y 130//config: default y
124//config: depends on ASH 131//config: depends on ASH
125//config: help 132//config: help
@@ -130,28 +137,28 @@
130//config: default y 137//config: default y
131//config: depends on ASH 138//config: depends on ASH
132//config: help 139//config: help
133//config: Enable getopts builtin in the ash shell. 140//config: Enable support for getopts builtin in ash.
134//config: 141//config:
135//config:config ASH_BUILTIN_ECHO 142//config:config ASH_BUILTIN_ECHO
136//config: bool "Builtin version of 'echo'" 143//config: bool "Builtin version of 'echo'"
137//config: default y 144//config: default y
138//config: depends on ASH 145//config: depends on ASH
139//config: help 146//config: help
140//config: Enable support for echo, builtin to ash. 147//config: Enable support for echo builtin in ash.
141//config: 148//config:
142//config:config ASH_BUILTIN_PRINTF 149//config:config ASH_BUILTIN_PRINTF
143//config: bool "Builtin version of 'printf'" 150//config: bool "Builtin version of 'printf'"
144//config: default y 151//config: default y
145//config: depends on ASH 152//config: depends on ASH
146//config: help 153//config: help
147//config: Enable support for printf, builtin to ash. 154//config: Enable support for printf builtin in ash.
148//config: 155//config:
149//config:config ASH_BUILTIN_TEST 156//config:config ASH_BUILTIN_TEST
150//config: bool "Builtin version of 'test'" 157//config: bool "Builtin version of 'test'"
151//config: default y 158//config: default y
152//config: depends on ASH 159//config: depends on ASH
153//config: help 160//config: help
154//config: Enable support for test, builtin to ash. 161//config: Enable support for test builtin in ash.
155//config: 162//config:
156//config:config ASH_CMDCMD 163//config:config ASH_CMDCMD
157//config: bool "'command' command to override shell builtins" 164//config: bool "'command' command to override shell builtins"
@@ -167,7 +174,7 @@
167//config: default n 174//config: default n
168//config: depends on ASH 175//config: depends on ASH
169//config: help 176//config: help
170//config: Enable "check for new mail" in the ash shell. 177//config: Enable "check for new mail" function in the ash shell.
171//config: 178//config:
172//config:config ASH_OPTIMIZE_FOR_SIZE 179//config:config ASH_OPTIMIZE_FOR_SIZE
173//config: bool "Optimize for size instead of speed" 180//config: bool "Optimize for size instead of speed"
@@ -449,6 +456,9 @@ static const char *var_end(const char *var)
449 456
450 457
451/* ============ Interrupts / exceptions */ 458/* ============ Interrupts / exceptions */
459
460static void exitshell(void) NORETURN;
461
452/* 462/*
453 * These macros allow the user to suspend the handling of interrupt signals 463 * These macros allow the user to suspend the handling of interrupt signals
454 * over a period of time. This is similar to SIGHOLD or to sigblock, but 464 * over a period of time. This is similar to SIGHOLD or to sigblock, but
@@ -1929,7 +1939,9 @@ change_lc_ctype(const char *value)
1929#endif 1939#endif
1930#if ENABLE_ASH_MAIL 1940#if ENABLE_ASH_MAIL
1931static void chkmail(void); 1941static void chkmail(void);
1932static void changemail(const char *) FAST_FUNC; 1942static void changemail(const char *var_value) FAST_FUNC;
1943#else
1944# define chkmail() ((void)0)
1933#endif 1945#endif
1934static void changepath(const char *) FAST_FUNC; 1946static void changepath(const char *) FAST_FUNC;
1935#if ENABLE_ASH_RANDOM_SUPPORT 1947#if ENABLE_ASH_RANDOM_SUPPORT
@@ -3937,18 +3949,51 @@ setjobctl(int on)
3937static int FAST_FUNC 3949static int FAST_FUNC
3938killcmd(int argc, char **argv) 3950killcmd(int argc, char **argv)
3939{ 3951{
3940 int i = 1;
3941 if (argv[1] && strcmp(argv[1], "-l") != 0) { 3952 if (argv[1] && strcmp(argv[1], "-l") != 0) {
3953 int i = 1;
3942 do { 3954 do {
3943 if (argv[i][0] == '%') { 3955 if (argv[i][0] == '%') {
3944 struct job *jp = getjob(argv[i], 0); 3956 /*
3945 unsigned pid = jp->ps[0].ps_pid; 3957 * "kill %N" - job kill
3946 /* Enough space for ' -NNN<nul>' */ 3958 * Converting to pgrp / pid kill
3947 argv[i] = alloca(sizeof(int)*3 + 3); 3959 */
3948 /* kill_main has matching code to expect 3960 struct job *jp;
3949 * leading space. Needed to not confuse 3961 char *dst;
3950 * negative pids with "kill -SIGNAL_NO" syntax */ 3962 int j, n;
3951 sprintf(argv[i], " -%u", pid); 3963
3964 jp = getjob(argv[i], 0);
3965 /*
3966 * In jobs started under job control, we signal
3967 * entire process group by kill -PGRP_ID.
3968 * This happens, f.e., in interactive shell.
3969 *
3970 * Otherwise, we signal each child via
3971 * kill PID1 PID2 PID3.
3972 * Testcases:
3973 * sh -c 'sleep 1|sleep 1 & kill %1'
3974 * sh -c 'true|sleep 2 & sleep 1; kill %1'
3975 * sh -c 'true|sleep 1 & sleep 2; kill %1'
3976 */
3977 n = jp->nprocs; /* can't be 0 (I hope) */
3978 if (jp->jobctl)
3979 n = 1;
3980 dst = alloca(n * sizeof(int)*4);
3981 argv[i] = dst;
3982 for (j = 0; j < n; j++) {
3983 struct procstat *ps = &jp->ps[j];
3984 /* Skip non-running and not-stopped members
3985 * (i.e. dead members) of the job
3986 */
3987 if (ps->ps_status != -1 && !WIFSTOPPED(ps->ps_status))
3988 continue;
3989 /*
3990 * kill_main has matching code to expect
3991 * leading space. Needed to not confuse
3992 * negative pids with "kill -SIGNAL_NO" syntax
3993 */
3994 dst += sprintf(dst, jp->jobctl ? " -%u" : " %u", (int)ps->ps_pid);
3995 }
3996 *dst = '\0';
3952 } 3997 }
3953 } while (argv[++i]); 3998 } while (argv[++i]);
3954 } 3999 }
@@ -4046,6 +4091,7 @@ sprint_status(char *s, int status, int sigonly)
4046#endif 4091#endif
4047 } 4092 }
4048 st &= 0x7f; 4093 st &= 0x7f;
4094//TODO: use bbox's get_signame? strsignal adds ~600 bytes to text+rodata
4049 col = fmtstr(s, 32, strsignal(st)); 4095 col = fmtstr(s, 32, strsignal(st));
4050 if (WCOREDUMP(status)) { 4096 if (WCOREDUMP(status)) {
4051 col += fmtstr(s + col, 16, " (core dumped)"); 4097 col += fmtstr(s + col, 16, " (core dumped)");
@@ -4462,8 +4508,9 @@ waitcmd(int argc UNUSED_PARAM, char **argv)
4462 break; 4508 break;
4463 job = job->prev_job; 4509 job = job->prev_job;
4464 } 4510 }
4465 } else 4511 } else {
4466 job = getjob(*argv, 0); 4512 job = getjob(*argv, 0);
4513 }
4467 /* loop until process terminated or stopped */ 4514 /* loop until process terminated or stopped */
4468 while (job->state == JOBRUNNING) 4515 while (job->state == JOBRUNNING)
4469 blocking_wait_with_raise_on_sig(); 4516 blocking_wait_with_raise_on_sig();
@@ -4959,7 +5006,7 @@ forkchild(struct job *jp, union node *n, int mode)
4959#if JOBS 5006#if JOBS
4960 /* do job control only in root shell */ 5007 /* do job control only in root shell */
4961 doing_jobctl = 0; 5008 doing_jobctl = 0;
4962 if (mode != FORK_NOJOB && jp->jobctl && !oldlvl) { 5009 if (mode != FORK_NOJOB && jp->jobctl && oldlvl == 0) {
4963 pid_t pgrp; 5010 pid_t pgrp;
4964 5011
4965 if (jp->nprocs == 0) 5012 if (jp->nprocs == 0)
@@ -4985,7 +5032,7 @@ forkchild(struct job *jp, union node *n, int mode)
4985 ash_msg_and_raise_error("can't open '%s'", bb_dev_null); 5032 ash_msg_and_raise_error("can't open '%s'", bb_dev_null);
4986 } 5033 }
4987 } 5034 }
4988 if (!oldlvl) { 5035 if (oldlvl == 0) {
4989 if (iflag) { /* why if iflag only? */ 5036 if (iflag) { /* why if iflag only? */
4990 setsignal(SIGINT); 5037 setsignal(SIGINT);
4991 setsignal(SIGTERM); 5038 setsignal(SIGTERM);
@@ -10065,10 +10112,21 @@ preadfd(void)
10065 if (!iflag || g_parsefile->pf_fd != STDIN_FILENO) 10112 if (!iflag || g_parsefile->pf_fd != STDIN_FILENO)
10066 nr = nonblock_safe_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1); 10113 nr = nonblock_safe_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
10067 else { 10114 else {
10068#if ENABLE_FEATURE_TAB_COMPLETION 10115 int timeout = -1;
10116# if ENABLE_ASH_IDLE_TIMEOUT
10117 if (iflag) {
10118 const char *tmout_var = lookupvar("TMOUT");
10119 if (tmout_var) {
10120 timeout = atoi(tmout_var) * 1000;
10121 if (timeout <= 0)
10122 timeout = -1;
10123 }
10124 }
10125# endif
10126# if ENABLE_FEATURE_TAB_COMPLETION
10069 line_input_state->path_lookup = pathval(); 10127 line_input_state->path_lookup = pathval();
10070#endif 10128# endif
10071 nr = read_line_input(cmdedit_prompt, buf, IBUFSIZ, line_input_state); 10129 nr = read_line_input(line_input_state, cmdedit_prompt, buf, IBUFSIZ, timeout);
10072 if (nr == 0) { 10130 if (nr == 0) {
10073 /* Ctrl+C pressed */ 10131 /* Ctrl+C pressed */
10074 if (trap[SIGINT]) { 10132 if (trap[SIGINT]) {
@@ -10079,17 +10137,24 @@ preadfd(void)
10079 } 10137 }
10080 goto retry; 10138 goto retry;
10081 } 10139 }
10082 if (nr < 0 && errno == 0) { 10140 if (nr < 0) {
10083 /* Ctrl+D pressed */ 10141 if (errno == 0) {
10084 nr = 0; 10142 /* Ctrl+D pressed */
10143 nr = 0;
10144 }
10145# if ENABLE_ASH_IDLE_TIMEOUT
10146 else if (errno == EAGAIN && timeout > 0) {
10147 printf("\007timed out waiting for input: auto-logout\n");
10148 exitshell();
10149 }
10150# endif
10085 } 10151 }
10086 } 10152 }
10087#else 10153#else
10088 nr = nonblock_safe_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1); 10154 nr = nonblock_safe_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
10089#endif 10155#endif
10090 10156
10091#if 0 10157#if 0 /* disabled: nonblock_safe_read() handles this problem */
10092/* nonblock_safe_read() handles this problem */
10093 if (nr < 0) { 10158 if (nr < 0) {
10094 if (parsefile->fd == 0 && errno == EWOULDBLOCK) { 10159 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
10095 int flags = fcntl(0, F_GETFL); 10160 int flags = fcntl(0, F_GETFL);
@@ -12574,9 +12639,7 @@ cmdloop(int top)
12574 inter = 0; 12639 inter = 0;
12575 if (iflag && top) { 12640 if (iflag && top) {
12576 inter++; 12641 inter++;
12577#if ENABLE_ASH_MAIL
12578 chkmail(); 12642 chkmail();
12579#endif
12580 } 12643 }
12581 n = parsecmd(inter); 12644 n = parsecmd(inter);
12582#if DEBUG 12645#if DEBUG
@@ -13346,7 +13409,6 @@ ulimitcmd(int argc UNUSED_PARAM, char **argv)
13346/* 13409/*
13347 * Called to exit the shell. 13410 * Called to exit the shell.
13348 */ 13411 */
13349static void exitshell(void) NORETURN;
13350static void 13412static void
13351exitshell(void) 13413exitshell(void)
13352{ 13414{