diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2007-05-16 22:18:54 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2007-05-16 22:18:54 +0000 |
commit | c666f71e3b91285d66260567b0b4c57332e0ff1f (patch) | |
tree | f48578f6c1779923692e1d0ba4e2a45d35b83e36 /shell/hush.c | |
parent | 831dcc439cdaef1062e09ca9af55f5c931889845 (diff) | |
download | busybox-w32-c666f71e3b91285d66260567b0b4c57332e0ff1f.tar.gz busybox-w32-c666f71e3b91285d66260567b0b4c57332e0ff1f.tar.bz2 busybox-w32-c666f71e3b91285d66260567b0b4c57332e0ff1f.zip |
hush: take care of several easy FIXMEs. -228 bytes.
Diffstat (limited to 'shell/hush.c')
-rw-r--r-- | shell/hush.c | 192 |
1 files changed, 68 insertions, 124 deletions
diff --git a/shell/hush.c b/shell/hush.c index 84f2870f2..7a4d7f934 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
@@ -124,6 +124,7 @@ static const char *indenter(int i) | |||
124 | return &blanks[sizeof(blanks) - i - 1]; | 124 | return &blanks[sizeof(blanks) - i - 1]; |
125 | } | 125 | } |
126 | #define debug_printf_clean(...) fprintf(stderr, __VA_ARGS__) | 126 | #define debug_printf_clean(...) fprintf(stderr, __VA_ARGS__) |
127 | #define DEBUG_CLEAN 1 | ||
127 | #endif | 128 | #endif |
128 | 129 | ||
129 | 130 | ||
@@ -232,10 +233,10 @@ struct child_prog { | |||
232 | glob_t glob_result; /* result of parameter globbing */ | 233 | glob_t glob_result; /* result of parameter globbing */ |
233 | int is_stopped; /* is the program currently running? */ | 234 | int is_stopped; /* is the program currently running? */ |
234 | struct pipe *family; /* pointer back to the child's parent pipe */ | 235 | struct pipe *family; /* pointer back to the child's parent pipe */ |
235 | int sp; /* number of SPECIAL_VAR_SYMBOL */ | 236 | //sp counting seems to be broken... so commented out, grep for '//sp:' |
237 | //sp: int sp; /* number of SPECIAL_VAR_SYMBOL */ | ||
236 | int type; | 238 | int type; |
237 | }; | 239 | }; |
238 | // sp counting seems to be broken... | ||
239 | /* argv vector may contain variable references (^Cvar^C, ^C0^C etc) | 240 | /* argv vector may contain variable references (^Cvar^C, ^C0^C etc) |
240 | * and on execution these are substituted with their values. | 241 | * and on execution these are substituted with their values. |
241 | * Substitution can make _several_ words out of one argv[n]! | 242 | * Substitution can make _several_ words out of one argv[n]! |
@@ -383,7 +384,6 @@ static int b_check_space(o_string *o, int len); | |||
383 | static int b_addchr(o_string *o, int ch); | 384 | static int b_addchr(o_string *o, int ch); |
384 | static void b_reset(o_string *o); | 385 | static void b_reset(o_string *o); |
385 | static int b_addqchr(o_string *o, int ch, int quote); | 386 | static int b_addqchr(o_string *o, int ch, int quote); |
386 | //static int b_adduint(o_string *o, unsigned i); | ||
387 | /* in_str manipulations: */ | 387 | /* in_str manipulations: */ |
388 | static int static_get(struct in_str *i); | 388 | static int static_get(struct in_str *i); |
389 | static int static_peek(struct in_str *i); | 389 | static int static_peek(struct in_str *i); |
@@ -396,7 +396,10 @@ static void mark_open(int fd); | |||
396 | static void mark_closed(int fd); | 396 | static void mark_closed(int fd); |
397 | static void close_all(void); | 397 | static void close_all(void); |
398 | /* "run" the final data structures: */ | 398 | /* "run" the final data structures: */ |
399 | //TODO: remove indent argument from non-debug build! | 399 | #if !defined(DEBUG_CLEAN) |
400 | #define free_pipe_list(head, indent) free_pipe_list(head) | ||
401 | #define free_pipe(pi, indent) free_pipe(pi) | ||
402 | #endif | ||
400 | static int free_pipe_list(struct pipe *head, int indent); | 403 | static int free_pipe_list(struct pipe *head, int indent); |
401 | static int free_pipe(struct pipe *pi, int indent); | 404 | static int free_pipe(struct pipe *pi, int indent); |
402 | /* really run the final data structures: */ | 405 | /* really run the final data structures: */ |
@@ -425,7 +428,6 @@ static int parse_group(o_string *dest, struct p_context *ctx, struct in_str *inp | |||
425 | static const char *lookup_param(const char *src); | 428 | static const char *lookup_param(const char *src); |
426 | static char *make_string(char **inp); | 429 | static char *make_string(char **inp); |
427 | static int handle_dollar(o_string *dest, struct p_context *ctx, struct in_str *input); | 430 | static int handle_dollar(o_string *dest, struct p_context *ctx, struct in_str *input); |
428 | //static int parse_string(o_string *dest, struct p_context *ctx, const char *src); | ||
429 | static int parse_stream(o_string *dest, struct p_context *ctx, struct in_str *input0, const char *end_trigger); | 431 | static int parse_stream(o_string *dest, struct p_context *ctx, struct in_str *input0, const char *end_trigger); |
430 | /* setup: */ | 432 | /* setup: */ |
431 | static int parse_stream_outer(struct in_str *inp, int parse_flag); | 433 | static int parse_stream_outer(struct in_str *inp, int parse_flag); |
@@ -708,9 +710,8 @@ static int builtin_export(char **argv) | |||
708 | return EXIT_SUCCESS; | 710 | return EXIT_SUCCESS; |
709 | } | 711 | } |
710 | 712 | ||
711 | name = strdup(name); | 713 | name = xstrdup(name); |
712 | 714 | { | |
713 | if (name) { | ||
714 | const char *value = strchr(name, '='); | 715 | const char *value = strchr(name, '='); |
715 | 716 | ||
716 | if (!value) { | 717 | if (!value) { |
@@ -721,13 +722,9 @@ static int builtin_export(char **argv) | |||
721 | if (value) { | 722 | if (value) { |
722 | size_t ln = strlen(name); | 723 | size_t ln = strlen(name); |
723 | 724 | ||
724 | tmp = realloc(name, ln+strlen(value)+2); | 725 | tmp = xrealloc(name, ln+strlen(value)+2); |
725 | if (tmp == NULL) | 726 | sprintf(tmp+ln, "=%s", value); |
726 | res = -1; | 727 | name = tmp; |
727 | else { | ||
728 | sprintf(tmp+ln, "=%s", value); | ||
729 | name = tmp; | ||
730 | } | ||
731 | } else { | 728 | } else { |
732 | /* bash does not return an error when trying to export | 729 | /* bash does not return an error when trying to export |
733 | * an undefined variable. Do likewise. */ | 730 | * an undefined variable. Do likewise. */ |
@@ -967,13 +964,9 @@ static int b_check_space(o_string *o, int len) | |||
967 | /* It would be easy to drop a more restrictive policy | 964 | /* It would be easy to drop a more restrictive policy |
968 | * in here, such as setting a maximum string length */ | 965 | * in here, such as setting a maximum string length */ |
969 | if (o->length + len > o->maxlen) { | 966 | if (o->length + len > o->maxlen) { |
970 | char *old_data = o->data; | ||
971 | /* assert(data == NULL || o->maxlen != 0); */ | 967 | /* assert(data == NULL || o->maxlen != 0); */ |
972 | o->maxlen += (2*len > B_CHUNK ? 2*len : B_CHUNK); | 968 | o->maxlen += (2*len > B_CHUNK ? 2*len : B_CHUNK); |
973 | o->data = realloc(o->data, 1 + o->maxlen); | 969 | o->data = xrealloc(o->data, 1 + o->maxlen); |
974 | if (o->data == NULL) { | ||
975 | free(old_data); | ||
976 | } | ||
977 | } | 970 | } |
978 | return o->data == NULL; | 971 | return o->data == NULL; |
979 | } | 972 | } |
@@ -1019,17 +1012,6 @@ static int b_addqchr(o_string *o, int ch, int quote) | |||
1019 | return b_addchr(o, ch); | 1012 | return b_addchr(o, ch); |
1020 | } | 1013 | } |
1021 | 1014 | ||
1022 | //static int b_adduint(o_string *o, unsigned i) | ||
1023 | //{ | ||
1024 | // int r; | ||
1025 | // char buf[sizeof(unsigned)*3 + 1]; | ||
1026 | // char *p = buf; | ||
1027 | // *(utoa_to_buf(i, buf, sizeof(buf))) = '\0'; | ||
1028 | // /* no escape checking necessary */ | ||
1029 | // do r = b_addchr(o, *p++); while (r == 0 && *p); | ||
1030 | // return r; | ||
1031 | //} | ||
1032 | // | ||
1033 | static int static_get(struct in_str *i) | 1015 | static int static_get(struct in_str *i) |
1034 | { | 1016 | { |
1035 | int ch = *i->p++; | 1017 | int ch = *i->p++; |
@@ -1286,7 +1268,7 @@ static void pseudo_exec_argv(char **argv) | |||
1286 | const struct built_in_command *x; | 1268 | const struct built_in_command *x; |
1287 | 1269 | ||
1288 | for (i = 0; is_assignment(argv[i]); i++) { | 1270 | for (i = 0; is_assignment(argv[i]); i++) { |
1289 | debug_printf("pid %d environment modification: %s\n", | 1271 | debug_printf_exec("pid %d environment modification: %s\n", |
1290 | getpid(), argv[i]); | 1272 | getpid(), argv[i]); |
1291 | // FIXME: vfork case?? | 1273 | // FIXME: vfork case?? |
1292 | p = insert_var_value(argv[i]); | 1274 | p = insert_var_value(argv[i]); |
@@ -1317,23 +1299,27 @@ static void pseudo_exec_argv(char **argv) | |||
1317 | } | 1299 | } |
1318 | } | 1300 | } |
1319 | 1301 | ||
1320 | /* Check if the command matches any busybox internal commands | 1302 | /* Check if the command matches any busybox applets */ |
1321 | * ("applets") here. | ||
1322 | * FIXME: This feature is not 100% safe, since | ||
1323 | * BusyBox is not fully reentrant, so we have no guarantee the things | ||
1324 | * from the .bss are still zeroed, or that things from .data are still | ||
1325 | * at their defaults. We could exec ourself from /proc/self/exe, but I | ||
1326 | * really dislike relying on /proc for things. We could exec ourself | ||
1327 | * from global_argv[0], but if we are in a chroot, we may not be able | ||
1328 | * to find ourself... */ | ||
1329 | #if ENABLE_FEATURE_SH_STANDALONE | 1303 | #if ENABLE_FEATURE_SH_STANDALONE |
1330 | debug_printf("running applet %s\n", argv[0]); | 1304 | if (strchr(argv[0], '/') == NULL) { |
1331 | // FIXME: check NOEXEC bit, and EXEC if not set! | 1305 | const struct bb_applet *a = find_applet_by_name(argv[0]); |
1332 | run_applet_and_exit(argv[0], argv); | 1306 | if (a) { |
1333 | // is it ok that run_applet_and_exit() does exit(), not _exit()? | 1307 | if (a->noexec) { |
1334 | // NB: IIRC on NOMMU we are after _vfork_, not fork! | 1308 | current_applet = a; |
1309 | debug_printf_exec("running applet '%s'\n", argv[0]); | ||
1310 | // is it ok that run_current_applet_and_exit() does exit(), not _exit()? | ||
1311 | run_current_applet_and_exit(argv); | ||
1312 | } | ||
1313 | /* re-exec ourselves with the new arguments */ | ||
1314 | debug_printf_exec("re-execing applet '%s'\n", argv[0]); | ||
1315 | execvp(CONFIG_BUSYBOX_EXEC_PATH, argv); | ||
1316 | /* If they called chroot or otherwise made the binary no longer | ||
1317 | * executable, fall through */ | ||
1318 | } | ||
1319 | } | ||
1335 | #endif | 1320 | #endif |
1336 | debug_printf("exec of %s\n", argv[0]); | 1321 | |
1322 | debug_printf_exec("execing '%s'\n", argv[0]); | ||
1337 | execvp(argv[0], argv); | 1323 | execvp(argv[0], argv); |
1338 | bb_perror_msg("cannot exec '%s'", argv[0]); | 1324 | bb_perror_msg("cannot exec '%s'", argv[0]); |
1339 | _exit(1); | 1325 | _exit(1); |
@@ -1426,16 +1412,7 @@ static void insert_bg_job(struct pipe *pi) | |||
1426 | // TODO: do we really need to have so many fields which are just dead weight | 1412 | // TODO: do we really need to have so many fields which are just dead weight |
1427 | // at execution stage? | 1413 | // at execution stage? |
1428 | thejob->progs[i].pid = pi->progs[i].pid; | 1414 | thejob->progs[i].pid = pi->progs[i].pid; |
1429 | //rest: | 1415 | /* all other fields are not used and stay zero */ |
1430 | //char **argv; /* program name and arguments */ | ||
1431 | //struct pipe *group; /* if non-NULL, first in group or subshell */ | ||
1432 | //int subshell; /* flag, non-zero if group must be forked */ | ||
1433 | //struct redir_struct *redirects; /* I/O redirections */ | ||
1434 | //glob_t glob_result; /* result of parameter globbing */ | ||
1435 | //int is_stopped; /* is the program currently running? */ | ||
1436 | //struct pipe *family; /* pointer back to the child's parent pipe */ | ||
1437 | //int sp; /* number of SPECIAL_VAR_SYMBOL */ | ||
1438 | //int type; | ||
1439 | } | 1416 | } |
1440 | thejob->next = NULL; | 1417 | thejob->next = NULL; |
1441 | thejob->cmdtext = xstrdup(get_cmdtext(pi)); | 1418 | thejob->cmdtext = xstrdup(get_cmdtext(pi)); |
@@ -1594,10 +1571,6 @@ static int checkjobs(struct pipe* fg_pipe) | |||
1594 | 1571 | ||
1595 | if (childpid && errno != ECHILD) | 1572 | if (childpid && errno != ECHILD) |
1596 | bb_perror_msg("waitpid"); | 1573 | bb_perror_msg("waitpid"); |
1597 | |||
1598 | /* move the shell to the foreground */ | ||
1599 | //if (interactive_fd && tcsetpgrp(interactive_fd, getpgid(0))) | ||
1600 | // bb_perror_msg("tcsetpgrp-2"); | ||
1601 | return rcode; | 1574 | return rcode; |
1602 | } | 1575 | } |
1603 | 1576 | ||
@@ -1669,7 +1642,7 @@ static int run_pipe_real(struct pipe *pi) | |||
1669 | } | 1642 | } |
1670 | 1643 | ||
1671 | if (single_fg && child->argv != NULL) { | 1644 | if (single_fg && child->argv != NULL) { |
1672 | char **argv_expanded, **free_me; | 1645 | char **argv_expanded; |
1673 | char **argv = child->argv; | 1646 | char **argv = child->argv; |
1674 | 1647 | ||
1675 | for (i = 0; is_assignment(argv[i]); i++) | 1648 | for (i = 0; is_assignment(argv[i]); i++) |
@@ -1704,13 +1677,12 @@ static int run_pipe_real(struct pipe *pi) | |||
1704 | for (i = 0; is_assignment(argv[i]); i++) { | 1677 | for (i = 0; is_assignment(argv[i]); i++) { |
1705 | p = insert_var_value(argv[i]); | 1678 | p = insert_var_value(argv[i]); |
1706 | if (p != argv[i]) { | 1679 | if (p != argv[i]) { |
1707 | child->sp--; | 1680 | //sp: child->sp--; |
1708 | putenv(p); | 1681 | putenv(p); |
1709 | } else { | 1682 | } else { |
1710 | putenv(xstrdup(p)); | 1683 | putenv(xstrdup(p)); |
1711 | } | 1684 | } |
1712 | } | 1685 | } |
1713 | free_me = NULL; | ||
1714 | for (x = bltins; x->cmd; x++) { | 1686 | for (x = bltins; x->cmd; x++) { |
1715 | if (strcmp(argv[i], x->cmd) == 0) { | 1687 | if (strcmp(argv[i], x->cmd) == 0) { |
1716 | if (x->function == builtin_exec && argv[i+1] == NULL) { | 1688 | if (x->function == builtin_exec && argv[i+1] == NULL) { |
@@ -1723,14 +1695,12 @@ static int run_pipe_real(struct pipe *pi) | |||
1723 | * This is perfect for work that comes after exec(). | 1695 | * This is perfect for work that comes after exec(). |
1724 | * Is it really safe for inline use? Experimentally, | 1696 | * Is it really safe for inline use? Experimentally, |
1725 | * things seem to work with glibc. */ | 1697 | * things seem to work with glibc. */ |
1726 | // TODO: fflush(NULL)? | ||
1727 | setup_redirects(child, squirrel); | 1698 | setup_redirects(child, squirrel); |
1728 | debug_printf_exec(": builtin '%s' '%s'...\n", x->cmd, argv[i+1]); | 1699 | debug_printf_exec(": builtin '%s' '%s'...\n", x->cmd, argv[i+1]); |
1729 | argv_expanded = argv + i; | 1700 | //sp: if (child->sp) /* btw we can do it unconditionally... */ |
1730 | if (child->sp) /* btw we can do it unconditionally... */ | 1701 | argv_expanded = do_variable_expansion(argv + i); |
1731 | free_me = argv_expanded = do_variable_expansion(argv + i); | ||
1732 | rcode = x->function(argv_expanded); | 1702 | rcode = x->function(argv_expanded); |
1733 | free(free_me); | 1703 | free(argv_expanded); |
1734 | restore_redirects(squirrel); | 1704 | restore_redirects(squirrel); |
1735 | debug_printf_exec("run_pipe_real return %d\n", rcode); | 1705 | debug_printf_exec("run_pipe_real return %d\n", rcode); |
1736 | return rcode; | 1706 | return rcode; |
@@ -1743,11 +1713,11 @@ static int run_pipe_real(struct pipe *pi) | |||
1743 | setup_redirects(child, squirrel); | 1713 | setup_redirects(child, squirrel); |
1744 | save_nofork_data(&nofork_save); | 1714 | save_nofork_data(&nofork_save); |
1745 | argv_expanded = argv + i; | 1715 | argv_expanded = argv + i; |
1746 | if (child->sp) | 1716 | //sp: if (child->sp) |
1747 | free_me = argv_expanded = do_variable_expansion(argv + i); | 1717 | argv_expanded = do_variable_expansion(argv + i); |
1748 | debug_printf_exec(": run_nofork_applet '%s' '%s'...\n", argv_expanded[0], argv_expanded[1]); | 1718 | debug_printf_exec(": run_nofork_applet '%s' '%s'...\n", argv_expanded[0], argv_expanded[1]); |
1749 | rcode = run_nofork_applet_prime(&nofork_save, a, argv_expanded); | 1719 | rcode = run_nofork_applet_prime(&nofork_save, a, argv_expanded); |
1750 | free(free_me); | 1720 | free(argv_expanded); |
1751 | restore_redirects(squirrel); | 1721 | restore_redirects(squirrel); |
1752 | debug_printf_exec("run_pipe_real return %d\n", rcode); | 1722 | debug_printf_exec("run_pipe_real return %d\n", rcode); |
1753 | return rcode; | 1723 | return rcode; |
@@ -1802,7 +1772,7 @@ static int run_pipe_real(struct pipe *pi) | |||
1802 | } | 1772 | } |
1803 | } | 1773 | } |
1804 | #endif | 1774 | #endif |
1805 | // in non-interactive case fatal sigs are already SIG_DFL | 1775 | /* in non-interactive case fatal sigs are already SIG_DFL */ |
1806 | close_all(); | 1776 | close_all(); |
1807 | if (nextin != 0) { | 1777 | if (nextin != 0) { |
1808 | dup2(nextin, 0); | 1778 | dup2(nextin, 0); |
@@ -1833,13 +1803,6 @@ static int run_pipe_real(struct pipe *pi) | |||
1833 | if (pi->pgrp < 0) | 1803 | if (pi->pgrp < 0) |
1834 | pi->pgrp = child->pid; | 1804 | pi->pgrp = child->pid; |
1835 | #endif | 1805 | #endif |
1836 | |||
1837 | /* Don't check for errors. The child may be dead already, | ||
1838 | * in which case setpgid returns error code EACCES. */ | ||
1839 | //why we do it at all?? child does it itself | ||
1840 | //if (interactive_fd) | ||
1841 | // setpgid(child->pid, pi->pgrp); | ||
1842 | |||
1843 | if (nextin != 0) | 1806 | if (nextin != 0) |
1844 | close(nextin); | 1807 | close(nextin); |
1845 | if (nextout != 1) | 1808 | if (nextout != 1) |
@@ -1911,8 +1874,8 @@ static void debug_print_tree(struct pipe *pi, int lvl) | |||
1911 | } | 1874 | } |
1912 | #endif | 1875 | #endif |
1913 | 1876 | ||
1914 | // NB: called by pseudo_exec, and therefore must not modify any | 1877 | /* NB: called by pseudo_exec, and therefore must not modify any |
1915 | // global data until exec/_exit (we can be a child after vfork!) | 1878 | * global data until exec/_exit (we can be a child after vfork!) */ |
1916 | static int run_list_real(struct pipe *pi) | 1879 | static int run_list_real(struct pipe *pi) |
1917 | { | 1880 | { |
1918 | #if ENABLE_HUSH_JOB | 1881 | #if ENABLE_HUSH_JOB |
@@ -2224,9 +2187,7 @@ static int globhack(const char *src, int flags, glob_t *pglob) | |||
2224 | if (*s == '\\') s++; | 2187 | if (*s == '\\') s++; |
2225 | cnt++; | 2188 | cnt++; |
2226 | } | 2189 | } |
2227 | dest = malloc(cnt); | 2190 | dest = xmalloc(cnt); |
2228 | if (!dest) | ||
2229 | return GLOB_NOSPACE; | ||
2230 | if (!(flags & GLOB_APPEND)) { | 2191 | if (!(flags & GLOB_APPEND)) { |
2231 | pglob->gl_pathv = NULL; | 2192 | pglob->gl_pathv = NULL; |
2232 | pglob->gl_pathc = 0; | 2193 | pglob->gl_pathc = 0; |
@@ -2234,9 +2195,7 @@ static int globhack(const char *src, int flags, glob_t *pglob) | |||
2234 | pglob->gl_offs = 0; | 2195 | pglob->gl_offs = 0; |
2235 | } | 2196 | } |
2236 | pathc = ++pglob->gl_pathc; | 2197 | pathc = ++pglob->gl_pathc; |
2237 | pglob->gl_pathv = realloc(pglob->gl_pathv, (pathc+1) * sizeof(*pglob->gl_pathv)); | 2198 | pglob->gl_pathv = xrealloc(pglob->gl_pathv, (pathc+1) * sizeof(*pglob->gl_pathv)); |
2238 | if (pglob->gl_pathv == NULL) | ||
2239 | return GLOB_NOSPACE; | ||
2240 | pglob->gl_pathv[pathc-1] = dest; | 2199 | pglob->gl_pathv[pathc-1] = dest; |
2241 | pglob->gl_pathv[pathc] = NULL; | 2200 | pglob->gl_pathv[pathc] = NULL; |
2242 | for (s = src; s && *s; s++, dest++) { | 2201 | for (s = src; s && *s; s++, dest++) { |
@@ -2312,8 +2271,8 @@ static int count_ifs(const char *str) | |||
2312 | while (1) { | 2271 | while (1) { |
2313 | str += strcspn(str, ifs); | 2272 | str += strcspn(str, ifs); |
2314 | if (!*str) break; | 2273 | if (!*str) break; |
2315 | str++; // str += strspn(str, ifs); ? | 2274 | str++; /* str += strspn(str, ifs); */ |
2316 | cnt++; // cnt += strspn(str, ifs); ? | 2275 | cnt++; /* cnt += strspn(str, ifs); - but this code is larger */ |
2317 | } | 2276 | } |
2318 | debug_printf_expand(" return %d\n", cnt); | 2277 | debug_printf_expand(" return %d\n", cnt); |
2319 | return cnt; | 2278 | return cnt; |
@@ -2704,31 +2663,23 @@ static int set_local_var(const char *s, int flg_export) | |||
2704 | if (flg_export > 0 || cur->flg_export > 1) | 2663 | if (flg_export > 0 || cur->flg_export > 1) |
2705 | cur->flg_export = 1; | 2664 | cur->flg_export = 1; |
2706 | free((char*)cur->value); | 2665 | free((char*)cur->value); |
2707 | cur->value = strdup(value); | 2666 | cur->value = xstrdup(value); |
2708 | } | 2667 | } |
2709 | goto skip; | 2668 | goto skip; |
2710 | } | 2669 | } |
2711 | } | 2670 | } |
2712 | 2671 | ||
2713 | // TODO: need simpler/generic rollback on malloc failure - see ash | 2672 | cur = xzalloc(sizeof(*cur)); |
2714 | cur = malloc(sizeof(*cur)); | 2673 | cur->name = xstrdup(name); |
2715 | if (!cur) { | 2674 | cur->value = xstrdup(value); |
2716 | result = -1; | 2675 | /*cur->next = 0;*/ |
2717 | } else { | 2676 | cur->flg_export = flg_export; |
2718 | cur->name = strdup(name); | 2677 | /*cur->flg_read_only = 0;*/ |
2719 | if (!cur->name) { | 2678 | { |
2720 | free(cur); | 2679 | struct variables *bottom = top_vars; |
2721 | result = -1; | 2680 | while (bottom->next) |
2722 | } else { | 2681 | bottom = bottom->next; |
2723 | struct variables *bottom = top_vars; | 2682 | bottom->next = cur; |
2724 | cur->value = strdup(value); | ||
2725 | cur->next = 0; | ||
2726 | cur->flg_export = flg_export; | ||
2727 | cur->flg_read_only = 0; | ||
2728 | while (bottom->next) | ||
2729 | bottom = bottom->next; | ||
2730 | bottom->next = cur; | ||
2731 | } | ||
2732 | } | 2683 | } |
2733 | skip: | 2684 | skip: |
2734 | if (result == 0 && cur->flg_export == 1) { | 2685 | if (result == 0 && cur->flg_export == 1) { |
@@ -3019,7 +2970,7 @@ static int done_command(struct p_context *ctx) | |||
3019 | /*child->group = NULL;*/ | 2970 | /*child->group = NULL;*/ |
3020 | /*child->glob_result.gl_pathv = NULL;*/ | 2971 | /*child->glob_result.gl_pathv = NULL;*/ |
3021 | child->family = pi; | 2972 | child->family = pi; |
3022 | /*child->sp = 0;*/ | 2973 | //sp: /*child->sp = 0;*/ |
3023 | child->type = ctx->parse_type; | 2974 | child->type = ctx->parse_type; |
3024 | 2975 | ||
3025 | ctx->child = child; | 2976 | ctx->child = child; |
@@ -3268,7 +3219,7 @@ static int handle_dollar(o_string *dest, struct p_context *ctx, struct in_str *i | |||
3268 | debug_printf_parse("handle_dollar entered: ch='%c'\n", ch); | 3219 | debug_printf_parse("handle_dollar entered: ch='%c'\n", ch); |
3269 | if (isalpha(ch)) { | 3220 | if (isalpha(ch)) { |
3270 | b_addchr(dest, SPECIAL_VAR_SYMBOL); | 3221 | b_addchr(dest, SPECIAL_VAR_SYMBOL); |
3271 | ctx->child->sp++; | 3222 | //sp: ctx->child->sp++; |
3272 | while (1) { | 3223 | while (1) { |
3273 | debug_printf_parse(": '%c'\n", ch); | 3224 | debug_printf_parse(": '%c'\n", ch); |
3274 | b_getch(input); | 3225 | b_getch(input); |
@@ -3282,7 +3233,7 @@ static int handle_dollar(o_string *dest, struct p_context *ctx, struct in_str *i | |||
3282 | } else if (isdigit(ch)) { | 3233 | } else if (isdigit(ch)) { |
3283 | make_one_char_var: | 3234 | make_one_char_var: |
3284 | b_addchr(dest, SPECIAL_VAR_SYMBOL); | 3235 | b_addchr(dest, SPECIAL_VAR_SYMBOL); |
3285 | ctx->child->sp++; | 3236 | //sp: ctx->child->sp++; |
3286 | debug_printf_parse(": '%c'\n", ch); | 3237 | debug_printf_parse(": '%c'\n", ch); |
3287 | b_getch(input); | 3238 | b_getch(input); |
3288 | b_addchr(dest, ch | quote_mask); | 3239 | b_addchr(dest, ch | quote_mask); |
@@ -3297,7 +3248,7 @@ static int handle_dollar(o_string *dest, struct p_context *ctx, struct in_str *i | |||
3297 | goto make_one_char_var; | 3248 | goto make_one_char_var; |
3298 | case '{': | 3249 | case '{': |
3299 | b_addchr(dest, SPECIAL_VAR_SYMBOL); | 3250 | b_addchr(dest, SPECIAL_VAR_SYMBOL); |
3300 | ctx->child->sp++; | 3251 | //sp: ctx->child->sp++; |
3301 | b_getch(input); | 3252 | b_getch(input); |
3302 | /* XXX maybe someone will try to escape the '}' */ | 3253 | /* XXX maybe someone will try to escape the '}' */ |
3303 | while (1) { | 3254 | while (1) { |
@@ -3332,13 +3283,6 @@ static int handle_dollar(o_string *dest, struct p_context *ctx, struct in_str *i | |||
3332 | return 0; | 3283 | return 0; |
3333 | } | 3284 | } |
3334 | 3285 | ||
3335 | //static int parse_string(o_string *dest, struct p_context *ctx, const char *src) | ||
3336 | //{ | ||
3337 | // struct in_str foo; | ||
3338 | // setup_string_in_str(&foo, src); | ||
3339 | // return parse_stream(dest, ctx, &foo, NULL); | ||
3340 | //} | ||
3341 | // | ||
3342 | /* return code is 0 for normal exit, 1 for syntax error */ | 3286 | /* return code is 0 for normal exit, 1 for syntax error */ |
3343 | static int parse_stream(o_string *dest, struct p_context *ctx, | 3287 | static int parse_stream(o_string *dest, struct p_context *ctx, |
3344 | struct in_str *input, const char *end_trigger) | 3288 | struct in_str *input, const char *end_trigger) |
@@ -3711,9 +3655,9 @@ int hush_main(int argc, char **argv) | |||
3711 | opt = parse_string_outer(optarg, FLAG_PARSE_SEMICOLON); | 3655 | opt = parse_string_outer(optarg, FLAG_PARSE_SEMICOLON); |
3712 | goto final_return; | 3656 | goto final_return; |
3713 | case 'i': | 3657 | case 'i': |
3714 | // Well, we cannot just declare interactiveness, | 3658 | /* Well, we cannot just declare interactiveness, |
3715 | // we have to have some stuff (ctty, etc) | 3659 | * we have to have some stuff (ctty, etc) */ |
3716 | /*interactive_fd++;*/ | 3660 | /* interactive_fd++; */ |
3717 | break; | 3661 | break; |
3718 | case 'f': | 3662 | case 'f': |
3719 | fake_mode++; | 3663 | fake_mode++; |