Lines Matching +full:- +full:- +full:enable +full:- +full:safe +full:- +full:stack

1 // SPDX-License-Identifier: GPL-2.0+
3 * sh.c -- a prototype Bourne shell grammar parser
14 * support has been adapted from busybox-0.49pre's lash,
21 * b_addchr() derived from similar w_addchar function in glibc-2.2
54 * to-do:
55 * port selected bugfixes from post-0.49 busybox lash - done?
63 * control-C handling, probably with longjmp
65 * figure out what to do with backslash-newline
68 * continuation lines, both explicit and implicit - done?
69 * memory leak finding and plugging - done?
72 * maybe change map[] to use 2-bit entries
133 #define EOF -1
153 { O_RDONLY, -1, "<<" },
206 struct p_context *stack; member
215 int dup; /* -1, or file descriptor being duplicated */
231 struct pipe *group; /* if non-NULL, first in group or subshell */
233 int subshell; /* flag, non-zero if group must be forked */
341 #define b_getch(input) ((input)->get(input))
342 #define b_peek(input) ((input)->peek(input))
345 #define JOB_STATUS_FORMAT "[%d] %-22s %.40s\n"
354 /* define DEBUG_SHELL for debugging output (obviously ;-)) */
498 /* Table of built-in functions. They can be forked or not, depending on
500 * When used in non-forking context, they can change global variables
526 {".", "Source-in and run commands in a file", builtin_source},
527 {"help", "List shell built-in commands", builtin_help},
541 /* built-in 'eval' handler */
547 if (child->argv[1]) { in builtin_eval()
548 str = make_string(child->argv + 1); in builtin_eval()
557 /* built-in 'cd <path>' handler */
561 if (child->argv[1] == NULL) in builtin_cd()
564 newdir = child->argv[1]; in builtin_cd()
573 /* built-in 'env' handler */
584 /* built-in 'exec' handler */
587 if (child->argv[1] == NULL) in builtin_exec()
589 child->argv++; in builtin_exec()
594 /* built-in 'exit' handler */
597 if (child->argv[1] == NULL) in builtin_exit()
599 exit (atoi(child->argv[1])); in builtin_exit()
602 /* built-in 'export VAR=value' handler */
606 char *name = child->argv[1]; in builtin_export()
627 res = -1; in builtin_export()
649 /* built-in 'fg' and 'bg' handler */
658 if (!child->argv[1]) { in builtin_fg_bg()
659 for (pi = job_list; pi; pi = pi->next) { in builtin_fg_bg()
660 if (pi->jobid == last_jobid) { in builtin_fg_bg()
665 error_msg("%s: no current job", child->argv[0]); in builtin_fg_bg()
669 if (sscanf(child->argv[1], "%%%d", &jobnum) != 1) { in builtin_fg_bg()
670 error_msg("%s: bad argument '%s'", child->argv[0], child->argv[1]); in builtin_fg_bg()
673 for (pi = job_list; pi; pi = pi->next) { in builtin_fg_bg()
674 if (pi->jobid == jobnum) { in builtin_fg_bg()
679 error_msg("%s: %d: no such job", child->argv[0], jobnum); in builtin_fg_bg()
684 if (*child->argv[0] == 'f') { in builtin_fg_bg()
686 tcsetpgrp(shell_terminal, pi->pgrp); in builtin_fg_bg()
690 for (i = 0; i < pi->num_progs; i++) in builtin_fg_bg()
691 pi->progs[i].is_stopped = 0; in builtin_fg_bg()
693 if ( (i=kill(- pi->pgrp, SIGCONT)) < 0) { in builtin_fg_bg()
701 pi->stopped_progs = 0; in builtin_fg_bg()
705 /* built-in 'help' handler */
710 printf("\nBuilt-in commands:\n"); in builtin_help()
711 printf("-------------------\n"); in builtin_help()
712 for (x = bltins; x->cmd; x++) { in builtin_help()
713 if (x->descr==NULL) in builtin_help()
715 printf("%s\t%s\n", x->cmd, x->descr); in builtin_help()
721 /* built-in 'jobs' handler */
727 for (job = job_list; job; job = job->next) { in builtin_jobs()
728 if (job->running_progs == job->stopped_progs) in builtin_jobs()
733 printf(JOB_STATUS_FORMAT, job->jobid, status_string, job->text); in builtin_jobs()
739 /* built-in 'pwd' handler */
746 /* built-in 'read VAR' handler */
751 if (child->argv[1]) { in builtin_read()
759 var = malloc(strlen(child->argv[1])+strlen(string)+2); in builtin_read()
761 sprintf(var, "%s=%s", child->argv[1], string); in builtin_read()
764 res = -1; in builtin_read()
775 /* built-in 'set VAR=value' handler */
778 char *temp = child->argv[1]; in builtin_set()
782 for(e = top_vars; e; e=e->next) in builtin_set()
783 printf("%s=%s\n", e->name, e->value); in builtin_set()
791 /* Built-in 'shift' handler */
795 if (child->argv[1]) { in builtin_shift()
796 n=atoi(child->argv[1]); in builtin_shift()
800 global_argc -= n; in builtin_shift()
808 /* Built-in '.' handler (read-in and execute commands from file) */
814 if (child->argv[1] == NULL) in builtin_source()
818 input = fopen(child->argv[1], "r"); in builtin_source()
820 error_msg("Couldn't open file '%s'", child->argv[1]); in builtin_source()
826 * (pointer only is OK!) on this stack frame, in builtin_source()
827 * set global_argv=child->argv+1, recurse, and restore. */ in builtin_source()
838 const char *arg = child->argv[1]; in builtin_umask()
852 /* built-in 'unset VAR' handler */
856 unset_local_var(child->argv[1]); in builtin_unset()
862 printf("builtin_%s not written\n",child->argv[0]); in builtin_not_written()
871 if (o->length + len > o->maxlen) { in b_check_space()
872 char *old_data = o->data; in b_check_space()
873 /* assert (data == NULL || o->maxlen != 0); */ in b_check_space()
874 o->maxlen += max(2*len, B_CHUNK); in b_check_space()
875 o->data = realloc(o->data, 1 + o->maxlen); in b_check_space()
876 if (o->data == NULL) { in b_check_space()
880 return o->data == NULL; in b_check_space()
885 debug_printf("b_addchr: %c %d %p\n", ch, o->length, o); in b_addchr()
887 o->data[o->length] = ch; in b_addchr()
888 o->length++; in b_addchr()
889 o->data[o->length] = '\0'; in b_addchr()
895 o->length = 0; in b_reset()
896 o->nonnull = 0; in b_reset()
897 if (o->data != NULL) *o->data = '\0'; in b_reset()
903 free(o->data); in b_free()
904 o->data = NULL; in b_free()
905 o->maxlen = 0; in b_free()
934 int ch = *i->p++; in static_get()
941 return *i->p; in static_peek()
982 if (i->promptmode == 1) in uboot_cli_readline()
988 if (i->promptmode == 1) in uboot_cli_readline()
1006 setup_prompt_string(i->promptmode, &prompt_str); in get_user_input()
1009 ** enable command line editing only while a command line in get_user_input()
1018 the_command[0]=fgetc(i->file); in get_user_input()
1022 i->p = the_command; in get_user_input()
1028 i->__promptme = 1; in get_user_input()
1032 if (n == -2) { in get_user_input()
1041 if (n == -1 ) { in get_user_input()
1043 i->__promptme = 0; in get_user_input()
1051 if (i->promptmode == 1) { in get_user_input()
1064 i->p = the_command; in get_user_input()
1071 the_command[n-1] = ' '; in get_user_input()
1080 if (i->__promptme == 0) { in get_user_input()
1084 i->p = console_buffer; in get_user_input()
1097 if (i->p && *i->p) {
1098 ch = *i->p++;
1100 /* need to double check i->file because we might be doing something
1103 if (i->__promptme && interactive && i->file == stdin) {
1104 while(! i->p || (interactive && strlen(i->p)==0) ) {
1106 while(! i->p || strlen(i->p)==0 ) {
1110 i->promptmode=2;
1112 i->__promptme = 0;
1114 if (i->p && *i->p) {
1115 ch = *i->p++;
1119 ch = fgetc(i->file);
1126 if (ch == '\n') i->__promptme=1;
1137 if (i->p && *i->p) {
1139 return *i->p;
1142 i->peek_buf[0] = fgetc(i->file);
1143 i->peek_buf[1] = '\0';
1144 i->p = i->peek_buf;
1145 debug_printf("b_peek: got a %d\n", *i->p);
1146 return *i->p;
1157 i->peek = file_peek;
1158 i->get = file_get;
1159 i->__promptme=1;
1160 i->promptmode=1;
1162 i->file = f;
1164 i->p = NULL;
1169 i->peek = static_peek;
1170 i->get = static_get;
1171 i->__promptme=1;
1172 i->promptmode=1;
1173 i->p = s;
1180 new->fd = fd;
1181 new->next = close_me_head;
1188 if (close_me_head == NULL || close_me_head->fd != fd)
1191 close_me_head = close_me_head->next;
1198 for (c=close_me_head; c; c=c->next) {
1199 close(c->fd);
1211 for (redir=prog->redirects; redir; redir=redir->next) {
1212 if (redir->dup == -1 && redir->word.gl_pathv == NULL) {
1216 if (redir->dup == -1) {
1217 mode=redir_table[redir->type].mode;
1218 openfd = open(redir->word.gl_pathv[0], mode, 0666);
1222 perror_msg("error opening %s", redir->word.gl_pathv[0]);
1226 openfd = redir->dup;
1229 if (openfd != redir->fd) {
1230 if (squirrel && redir->fd < 3) {
1231 squirrel[redir->fd] = dup(redir->fd);
1233 if (openfd == -3) {
1236 dup2(openfd, redir->fd);
1237 if (redir->dup == -1)
1250 if (fd != -1) {
1268 if (child->argv) {
1269 for (i=0; is_assignment(child->argv[i]); i++) {
1270 debug_printf("pid %d environment modification: %s\n",getpid(),child->argv[i]);
1271 p = insert_var_value(child->argv[i]);
1273 if (p != child->argv[i]) free(p);
1275 child->argv+=i; /* XXX this hack isn't so horrible, since we are about
1281 if (child->argv[0] == NULL) {
1291 for (x = bltins; x->cmd; x++) {
1292 if (strcmp(child->argv[0], x->cmd) == 0 ) {
1293 debug_printf("builtin exec %s\n", child->argv[0]);
1294 rcode = x->function(child);
1302 * FIXME: This feature is not 100% safe, since
1312 char** argv_l=child->argv;
1313 char *name = child->argv[0];
1320 * If you enable CONFIG_FEATURE_SH_APPLETS_ALWAYS_WIN then applets
1331 run_applet_by_name(name, argc_l, child->argv);
1334 debug_printf("exec of %s\n",child->argv[0]);
1335 execvp(child->argv[0],child->argv);
1336 perror_msg("couldn't exec: %s",child->argv[0]);
1338 } else if (child->group) {
1341 rcode = run_list_real(child->group);
1357 pi->jobid = 1;
1358 for (thejob = job_list; thejob; thejob = thejob->next)
1359 if (thejob->jobid >= pi->jobid)
1360 pi->jobid = thejob->jobid + 1;
1366 for (thejob = job_list; thejob->next; thejob = thejob->next) /* nothing */;
1367 thejob->next = xmalloc(sizeof(*thejob));
1368 thejob = thejob->next;
1373 thejob->next = NULL;
1374 thejob->running_progs = thejob->num_progs;
1375 thejob->stopped_progs = 0;
1376 thejob->text = xmalloc(BUFSIZ); /* cmdedit buffer size */
1378 /*if (pi->progs[0] && pi->progs[0].argv && pi->progs[0].argv[0]) */
1380 char *bar=thejob->text;
1381 char **foo=pi->progs[0].argv;
1387 /* we don't wait for background thejobs to return -- append it
1389 printf("[%d] %d\n", thejob->jobid, thejob->progs[0].pid);
1390 last_bg_pid = thejob->progs[0].pid;
1391 last_jobid = thejob->jobid;
1400 job_list = pi->next;
1403 while (prev_pipe->next != pi)
1404 prev_pipe = prev_pipe->next;
1405 prev_pipe->next = pi->next;
1408 last_jobid = job_list->jobid;
1412 pi->stopped_progs = 0;
1417 /* Checks to see if any processes have exited -- if they
1432 while ((childpid = waitpid(-1, &status, attributes)) > 0) {
1435 for (i=0; i < fg_pipe->num_progs; i++) {
1436 if (fg_pipe->progs[i].pid == childpid) {
1437 if (i==fg_pipe->num_progs-1)
1439 (fg_pipe->num_progs)--;
1445 for (pi = job_list; pi; pi = pi->next) {
1447 while (prognum < pi->num_progs && pi->progs[prognum].pid != childpid) {
1450 if (prognum < pi->num_progs)
1461 pi->running_progs--;
1462 pi->progs[prognum].pid = 0;
1464 if (!pi->running_progs) {
1465 printf(JOB_STATUS_FORMAT, pi->jobid, "Done", pi->text);
1470 pi->stopped_progs++;
1471 pi->progs[prognum].is_stopped = 1;
1477 if (pi->stopped_progs == pi->num_progs) {
1478 printf("\n"JOB_STATUS_FORMAT, pi->jobid, "Stopped", pi->text);
1484 if (childpid == -1 && errno != ECHILD)
1489 /* perror_msg("tcsetpgrp-2"); */
1490 return -1;
1513 shell_terminal = -1;
1521 * return code is normally -1, when the caller has to wait for children
1528 * stdout. The outpipe[] mechanism in BusyBox-0.48 lash is bogus,
1565 pi->pgrp = -1;
1572 if (pi->num_progs == 1) child = & (pi->progs[0]);
1574 if (pi->num_progs == 1 && child->group && child->subshell == 0) {
1575 int squirrel[] = {-1, -1, -1};
1577 debug_printf("non-subshell grouping\n");
1581 rcode = run_list_real(child->group);
1584 if (pi->num_progs == 1 && child->group) {
1586 debug_printf("non-subshell grouping\n");
1587 rcode = run_list_real(child->group);
1590 } else if (pi->num_progs == 1 && pi->progs[0].argv != NULL) {
1591 for (i=0; is_assignment(child->argv[i]); i++) { /* nothing */ }
1592 if (i!=0 && child->argv[i]==NULL) {
1594 for (i=0; child->argv[i]!=NULL; i++) {
1604 name = xstrdup(child->argv[i]);
1615 p = insert_var_value(child->argv[i]);
1617 if (p != child->argv[i]) free(p);
1621 for (i = 0; is_assignment(child->argv[i]); i++) {
1622 p = insert_var_value(child->argv[i]);
1628 if (p != child->argv[i]) {
1629 child->sp--;
1633 if (child->sp) {
1636 str = make_string(child->argv + i,
1637 child->argv_nonnull + i);
1643 for (x = bltins; x->cmd; x++) {
1644 if (strcmp(child->argv[i], x->cmd) == 0 ) {
1645 int squirrel[] = {-1, -1, -1};
1647 if (x->function == builtin_exec && child->argv[i+1]==NULL) {
1652 debug_printf("builtin inline %s\n", child->argv[0]);
1655 * Is it really safe for inline use? Experimentally,
1659 child->argv += i; /* XXX horrible hack */
1660 rcode = x->function(child);
1662 child->argv -= i;
1671 if (strchr(child->argv[i], ';')) {
1672 printf("Unknown command '%s' - try 'help' or use "
1673 "'run' command\n", child->argv[i]);
1674 return -1;
1677 return cmd_process(flag, child->argc, child->argv,
1683 for (i = 0; i < pi->num_progs; i++) {
1684 child = & (pi->progs[i]);
1687 if ((i + 1) < pi->num_progs) {
1692 pipefds[0] = -1;
1696 if (!(child->pid = fork())) {
1716 if (pipefds[0]!=-1) {
1724 if (interactive && pi->followup!=PIPE_BG) {
1727 if (pi->pgrp < 0) {
1728 pi->pgrp = getpid();
1730 if (setpgid(0, pi->pgrp) == 0) {
1731 tcsetpgrp(2, pi->pgrp);
1741 if (pi->pgrp < 0) {
1742 pi->pgrp = child->pid;
1746 setpgid(child->pid, pi->pgrp);
1758 return -1;
1773 int if_code=0, next_if_code=0; /* need double-buffer to handle elif */
1776 for (rpipe = pi; rpipe; rpipe = rpipe->next) {
1777 if ((rpipe->r_mode == RES_IN ||
1778 rpipe->r_mode == RES_FOR) &&
1779 (rpipe->next == NULL)) {
1786 if ((rpipe->r_mode == RES_IN &&
1787 (rpipe->next->r_mode == RES_IN &&
1788 rpipe->next->progs->argv != NULL))||
1789 (rpipe->r_mode == RES_FOR &&
1790 rpipe->next->r_mode != RES_IN)) {
1798 for (; pi; pi = (flag_restore != 0) ? rpipe : pi->next) {
1799 if (pi->r_mode == RES_WHILE || pi->r_mode == RES_UNTIL ||
1800 pi->r_mode == RES_FOR) {
1802 /* check Ctrl-C */
1814 rmode = pi->r_mode;
1817 if (pi->followup == PIPE_SEQ) flag_skip=0;
1826 if (rmode == RES_FOR && pi->num_progs) {
1829 if (!pi->next->progs->argv) continue;
1831 list = make_list_in(pi->next->progs->argv,
1832 pi->progs->argv[0]);
1834 save_name = pi->progs->argv[0];
1835 pi->progs->argv[0] = NULL;
1839 free(pi->progs->argv[0]);
1843 pi->progs->argv[0] = save_name;
1845 pi->progs->glob_result.gl_pathv[0] =
1846 pi->progs->argv[0];
1851 if (pi->progs->argv[0])
1852 free(pi->progs->argv[0]);
1853 pi->progs->argv[0] = *list++;
1855 pi->progs->glob_result.gl_pathv[0] =
1856 pi->progs->argv[0];
1871 if (pi->num_progs == 0) continue;
1873 save_num_progs = pi->num_progs; /* save number of programs */
1878 if (rcode!=-1) {
1881 } else if (pi->followup==PIPE_BG) {
1890 if (tcsetpgrp(shell_terminal, pi->pgrp) && errno != ENOTTY)
1891 perror_msg("tcsetpgrp-3");
1895 perror_msg("tcsetpgrp-4");
1903 if (rcode < -1) {
1904 last_return_code = -rcode - 2;
1905 return -2; /* exit */
1910 pi->num_progs = save_num_progs; /* restore number of programs */
1918 if ( (rcode==EXIT_SUCCESS && pi->followup==PIPE_OR) ||
1919 (rcode!=EXIT_SUCCESS && pi->followup==PIPE_AND) )
1932 return &blanks[sizeof(blanks)-i-1];
1947 if (pi->stopped_progs > 0)
1951 for (i=0; i<pi->num_progs; i++) {
1952 child = &pi->progs[i];
1954 if (child->argv) {
1955 for (a=0,p=child->argv; *p; a++,p++) {
1959 globfree(&child->glob_result);
1961 for (a = 0; a < child->argc; a++) {
1962 free(child->argv[a]);
1964 free(child->argv);
1965 free(child->argv_nonnull);
1966 child->argc = 0;
1968 child->argv=NULL;
1969 } else if (child->group) {
1971 final_printf("%s begin group (subshell:%d)\n",ind, child->subshell);
1973 ret_code = free_pipe_list(child->group,indent+3);
1979 for (r=child->redirects; r; r=rnext) {
1980 final_printf("%s redirect %d%s", ind, r->fd, redir_table[r->type].descrip);
1981 if (r->dup == -1) {
1983 if (r->word.gl_pathv) {
1984 final_printf(" %s\n", *r->word.gl_pathv);
1985 globfree(&r->word);
1988 final_printf("&%d\n", r->dup);
1990 rnext=r->next;
1993 child->redirects=NULL;
1996 free(pi->progs); /* children are an array, they get freed all at once */
1997 pi->progs=NULL;
2007 final_printf("%s pipe reserved mode %d\n", ind, pi->r_mode);
2009 final_printf("%s pipe followup code %d\n", ind, pi->followup);
2010 next=pi->next;
2011 pi->next=NULL;
2035 /* The API for glob is arguably broken. This routine pushes a non-matching
2036 * string into the output structure, removing non-backslashed backslashes.
2055 pglob->gl_pathv=NULL;
2056 pglob->gl_pathc=0;
2057 pglob->gl_offs=0;
2058 pglob->gl_offs=0;
2060 pathc = ++pglob->gl_pathc;
2061 pglob->gl_pathv = realloc(pglob->gl_pathv, (pathc+1)*sizeof(*pglob->gl_pathv));
2062 if (pglob->gl_pathv == NULL) return GLOB_NOSPACE;
2063 pglob->gl_pathv[pathc-1]=dest;
2064 pglob->gl_pathv[pathc]=NULL;
2089 pglob->gl_pathc, pglob->gl_pathv, pglob->gl_offs, pglob->gl_flags);
2090 for (i=0; i<pglob->gl_pathc; i++)
2091 debug_printf("pglob->gl_pathv[%d] = %p = %s\n", i,
2092 pglob->gl_pathv[i], pglob->gl_pathv[i]);
2100 /* short-circuit for null word */
2102 if (dest->length == 0) {
2103 if (dest->nonnull) {
2105 gr = globhack(dest->data, flags, pglob);
2110 } else if (glob_needed(dest->data)) {
2111 gr = glob(dest->data, flags, NULL, pglob);
2115 gr = globhack(dest->data, flags, pglob);
2119 gr = globhack(dest->data, flags, pglob);
2149 for (cur = top_vars; cur; cur=cur->next)
2150 if(strcmp(cur->name, s)==0)
2151 return cur->value;
2168 return -1;
2178 return -1;
2187 return -1;
2191 for(cur = top_vars; cur; cur = cur->next) {
2192 if(strcmp(cur->name, name)==0)
2197 if(strcmp(cur->value, value)==0) {
2198 if(flg_export>0 && cur->flg_export==0)
2199 cur->flg_export=flg_export;
2203 if(cur->flg_read_only) {
2205 result = -1;
2207 if(flg_export>0 || cur->flg_export>1)
2208 cur->flg_export=1;
2209 free(cur->value);
2211 cur->value = strdup(value);
2217 result = -1;
2219 cur->name = strdup(name);
2220 if (cur->name == NULL) {
2222 result = -1;
2225 cur->value = strdup(value);
2226 cur->next = NULL;
2227 cur->flg_export = flg_export;
2228 cur->flg_read_only = 0;
2229 while(bottom->next) bottom=bottom->next;
2230 bottom->next = cur;
2236 if(result==0 && cur->flg_export==1) {
2237 *(value-1) = '=';
2255 for (cur = top_vars; cur; cur=cur->next) {
2256 if(strcmp(cur->name, name)==0)
2261 if(cur->flg_read_only) {
2266 if(cur->flg_export)
2267 unenv_set(cur->name);
2269 free(cur->name);
2270 free(cur->value);
2271 while (next->next != cur)
2272 next = next->next;
2273 next->next = cur->next;
2299 struct child_prog *child=ctx->child;
2300 struct redir_struct *redir = child->redirects;
2306 redir=redir->next;
2309 redir->next=NULL;
2310 redir->word.gl_pathv=NULL;
2312 last_redir->next=redir;
2314 child->redirects=redir;
2317 redir->type=style;
2318 redir->fd= (fd==-1) ? redir_table[style].default_fd : fd ;
2320 debug_printf("Redirect type %d%s\n", redir->fd, redir_table[style].descrip);
2323 redir->dup = redirect_dup_num(input);
2324 if (redir->dup == -2) return 1; /* syntax error */
2325 if (redir->dup != -1) {
2328 * A "-" representation of "close me" shows up as a -3 here */
2329 debug_printf("Duplicating redirect '%d>&%d'\n", redir->fd, redir->dup);
2333 * Set ctx->pending_redirect, so we know what to do at the
2336 ctx->pending_redirect = redir;
2346 pi->num_progs = 0;
2347 pi->progs = NULL;
2348 pi->next = NULL;
2349 pi->followup = 0; /* invalid */
2350 pi->r_mode = RES_NONE;
2356 ctx->pipe=NULL;
2358 ctx->pending_redirect=NULL;
2360 ctx->child=NULL;
2361 ctx->list_head=new_pipe();
2362 ctx->pipe=ctx->list_head;
2363 ctx->w=RES_NONE;
2364 ctx->stack=NULL;
2366 ctx->old_flag=0;
2381 /* Mostly a list of accepted follow-up reserved words.
2406 if (strcmp(dest->data, r->literal) == 0) {
2407 debug_printf("found reserved word %s, code %d\n",r->literal,r->code);
2408 if (r->flag & FLAG_START) {
2410 debug_printf("push stack\n");
2411 if (ctx->w == RES_IN || ctx->w == RES_FOR) {
2414 ctx->w = RES_SNTX;
2420 ctx->stack=new;
2421 } else if ( ctx->w == RES_NONE || ! (ctx->old_flag & (1<<r->code))) {
2423 ctx->w = RES_SNTX;
2427 ctx->w=r->code;
2428 ctx->old_flag = r->flag;
2429 if (ctx->old_flag & FLAG_END) {
2431 debug_printf("pop stack\n");
2433 old = ctx->stack;
2434 old->child->group = ctx->list_head;
2436 old->child->subshell = 0;
2452 struct child_prog *child=ctx->child;
2461 debug_printf("done_word: %s %p\n", dest->data, child);
2462 if (dest->length == 0 && !dest->nonnull) {
2467 if (ctx->pending_redirect) {
2468 glob_target = &ctx->pending_redirect->word;
2471 if (child->group) {
2475 if (!child->argv && (ctx->type & FLAG_PARSE_SEMICOLON)) {
2476 debug_printf("checking %s for reserved-ness\n",dest->data);
2477 if (reserved_word(dest,ctx)) return ctx->w==RES_SNTX;
2480 glob_target = &child->glob_result;
2481 if (child->argv) flags |= GLOB_APPEND;
2483 for (cnt = 1, s = dest->data; s && *s; s++) {
2489 if ( child->argv == NULL) {
2490 child->argc=0;
2492 argc = ++child->argc;
2493 child->argv = realloc(child->argv, (argc+1)*sizeof(*child->argv));
2494 if (child->argv == NULL) {
2498 child->argv_nonnull = realloc(child->argv_nonnull,
2499 (argc+1)*sizeof(*child->argv_nonnull));
2500 if (child->argv_nonnull == NULL) {
2504 child->argv[argc-1]=str;
2505 child->argv_nonnull[argc-1] = dest->nonnull;
2506 child->argv[argc]=NULL;
2507 child->argv_nonnull[argc] = 0;
2508 for (s = dest->data; s && *s; s++,str++) {
2522 if (ctx->pending_redirect) {
2523 ctx->pending_redirect=NULL;
2524 if (glob_target->gl_pathc != 1) {
2529 child->argv = glob_target->gl_pathv;
2532 if (ctx->w == RES_FOR) {
2546 * child structure, to which ctx->child points, is not
2547 * counted in pi->num_progs. */
2548 struct pipe *pi=ctx->pipe;
2549 struct child_prog *prog=ctx->child;
2551 if (prog && prog->group == NULL
2552 && prog->argv == NULL
2554 && prog->redirects == NULL) {
2561 pi->num_progs++;
2562 debug_printf("done_command: num_progs incremented to %d\n",pi->num_progs);
2566 pi->progs = xrealloc(pi->progs, sizeof(*pi->progs) * (pi->num_progs+1));
2568 prog = pi->progs + pi->num_progs;
2570 prog->redirects = NULL;
2572 prog->argv = NULL;
2573 prog->argv_nonnull = NULL;
2575 prog->is_stopped = 0;
2577 prog->group = NULL;
2579 prog->glob_result.gl_pathv = NULL;
2580 prog->family = pi;
2582 prog->sp = 0;
2583 ctx->child = prog;
2584 prog->type = ctx->type;
2586 /* but ctx->pipe and ctx->list_head remain unchanged */
2595 ctx->pipe->followup = type;
2596 ctx->pipe->r_mode = ctx->w;
2598 ctx->pipe->next = new_p;
2599 ctx->pipe = new_p;
2600 ctx->child = NULL;
2608 * returns either -2 (syntax error), -1 (no &), or the number found.
2614 if (ch != '&') return -1;
2618 if (ch == '-') {
2620 return -3; /* "-" represents "close me" */
2623 d = d*10+(ch-'0');
2631 return -2;
2640 * echo -2>foo # redirects fd 1 to file "foo", "-2" passed to echo
2642 * A -1 output from this program means no valid number was found, so the
2649 if (o->length==0) return -1;
2650 for(num=0; num<o->length; num++) {
2651 if (!isdigit(*(o->data+num))) {
2652 return -1;
2656 num=atoi(o->data);
2729 * safe, since we just read an EOF from its stdout. We could try
2746 struct child_prog *child = ctx->child;
2747 if (child->argv) {
2753 case '(': endch=')'; child->subshell=1; break;
2760 child->group = sub.list_head;
2783 if (*(sep + 1) == '-')
2847 int ch = input->peek(input); /* first character after the $ */
2851 ctx->child->sp++;
2859 i = ch-'0'; /* XXX is $0 special? */
2880 ctx->child->sp++;
2890 b_adduint(dest,global_argc ? global_argc-1 : 0);
2896 ctx->child->sp++;
2921 case '-':
2929 b_addqchr(dest,'$',dest->quote);
2934 * a nice size-optimized program. Hah! That'll be the day.
2960 /* Only double-quote state is handled in the state variable dest->quote.
2961 * A single-quote triggers a bypass of the main loop until its mate is
2962 * found. When recursing, quote state is passed in via dest->quote. */
2968 if (input->__promptme == 0) return 1;
2972 debug_printf("parse_stream: ch=%c (%d) m=%d quote=%d - %c\n",
2974 dest->quote, ctx->stack == NULL ? '*' : '.');
2976 if (m==0 || ((m==1 || m==2) && dest->quote)) {
2977 b_addqchr(dest, ch, dest->quote);
2988 if (ch == end_trigger && !dest->quote && ctx->w==RES_NONE) {
2996 run_list(ctx->list_head);
3002 if (dest->length == 0 && !dest->quote) {
3005 b_addqchr(dest, ch, dest->quote);
3013 b_addqchr(dest, '\\', dest->quote);
3014 b_addqchr(dest, b_getch(input), dest->quote);
3020 dest->nonnull = 1;
3023 if(input->__promptme == 0) return 1;
3033 dest->nonnull = 1;
3034 dest->quote = !dest->quote;
3117 dest->nonnull = 1;
3121 if (input->__promptme == 0)
3146 if (end_trigger != '\0') return -1;
3198 inp->promptmode=1;
3200 flag & FLAG_CONT_ON_NEWLINE ? -1 : '\n');
3217 if (code == -2) { /* exit */
3221 if (inp->peek == file_peek) {
3227 if (code == -1)
3232 free(ctx.stack);
3236 if (inp->__promptme == 0) printf("<INTERRUPT>\n");
3237 inp->__promptme = 1;
3241 inp->p = NULL;
3246 } while (rcode != -1 && !(flag & FLAG_EXIT_FROM_LOOP) &&
3247 (inp->peek != static_peek || b_peek(inp)));
3311 addr = (ulong) (r->literal) + gd->reloc_off;
3312 r->literal = (char *)addr;
3321 top_vars->name = "HUSH_VERSION";
3322 top_vars->value = "0.01";
3323 top_vars->next = NULL;
3324 top_vars->flg_export = 0;
3325 top_vars->flg_read_only = 1;
3365 kill (- shell_pgrp, SIGTTIN);
3367 /* Ignore interactive and job-control signals. */
3407 /* Initialize some more globals to non-zero values */
3426 if (argv[0] && argv[0][0] == '-') {
3442 global_argc = argc-optind;
3456 " or: sh -c command [args]...\n\n");
3463 /* A shell is interactive if the `-i' flag was given, or if all of
3465 * no -c command
3466 * no arguments remaining or the -s flag given
3479 printf( "\n\n" BB_BANNER " hush - the humble shell v0.01 (testing)\n");
3480 printf( "Enter 'help' for a list of built-in commands.\n\n");
3492 global_argc = argc-optind;
3503 tmp = cur->next;
3504 if (!cur->flg_read_only) {
3505 free(cur->name);
3506 free(cur->value);
3534 len = p - inp;
3606 len = p2 - p1;
3629 * inp - array of argument strings to flatten
3630 * nonnull - indicates argument was quoted when originally parsed
3675 for (cur = top_vars; cur; cur = cur->next) {
3676 printf ("%s=%s\n", cur->name, cur->value);
3687 k = -1;
3688 for (cur = top_vars; cur; cur = cur->next) {
3689 if(strcmp (cur->name, name) == 0) {
3691 printf ("%s=%s\n", cur->name, cur->value);
3709 "\n - print values of all hushshell variables\n"
3711 " - print value of hushshell variable 'name'"