More hush updates from Larry:
Update some comments. Generate partial placeholders for the missing
builtins. Write builtin_umask. Properly treat exec without arguments
as a means to open/close files within the running script. Implement
"4<&-" that encodes for file descriptor closure.
diff --git a/hush.c b/hush.c
index b8e4a55..e58ac44 100644
--- a/hush.c
+++ b/hush.c
@@ -45,24 +45,25 @@
* fancy forms of Parameter Expansion
* Arithmetic Expansion
* <(list) and >(list) Process Substitution
- * reserved words: case, esac, function
+ * reserved words: case, esac, select, function
* Here Documents ( << word )
* Functions
* Major bugs:
* job handling woefully incomplete and buggy
* reserved word execution woefully incomplete and buggy
* to-do:
- * port selected bugfixes from post-0.49 busybox lash
- * finish implementing reserved words
+ * port selected bugfixes from post-0.49 busybox lash - done?
+ * finish implementing reserved words: for, while, until, do, done
+ * change { and } from special chars to reserved words
+ * builtins: break, continue, eval, return, set, trap, ulimit
+ * test magic exec
* handle children going into background
* clean up recognition of null pipes
* have builtin_exec set flag to avoid restore_redirects
- * figure out if "echo foo}" is fixable
* check setting of global_argc and global_argv
* control-C handling, probably with longjmp
* VAR=value prefix for simple commands
* follow IFS rules more precisely, including update semantics
- * write builtin_eval, builtin_ulimit, builtin_umask
* figure out what to do with backslash-newline
* explain why we use signal instead of sigaction
* propagate syntax errors, die on resource errors?
@@ -97,6 +98,7 @@
#include <fcntl.h>
#include <getopt.h> /* should be pretty obvious */
+#include <sys/stat.h> /* ulimit */
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
@@ -323,9 +325,9 @@
static int builtin_read(struct child_prog *child);
static int builtin_shift(struct child_prog *child);
static int builtin_source(struct child_prog *child);
-static int builtin_ulimit(struct child_prog *child);
static int builtin_umask(struct child_prog *child);
static int builtin_unset(struct child_prog *child);
+static int builtin_not_written(struct child_prog *child);
/* o_string manipulation: */
static int b_check_space(o_string *o, int len);
static int b_addchr(o_string *o, int ch);
@@ -390,8 +392,11 @@
* still be set at the end. */
static struct built_in_command bltins[] = {
{"bg", "Resume a job in the background", builtin_fg_bg},
+ {"break", "Exit for, while or until loop", builtin_not_written},
{"cd", "Change working directory", builtin_cd},
+ {"continue", "Continue for, while or until loop", builtin_not_written},
{"env", "Print all environment variables", builtin_env},
+ {"eval", "Construct and run shell command", builtin_not_written},
{"exec", "Exec command, replacing this shell with the exec'd process", builtin_exec},
{"exit", "Exit from shell()", builtin_exit},
{"export", "Set environment variable", builtin_export},
@@ -399,8 +404,11 @@
{"jobs", "Lists the active jobs", builtin_jobs},
{"pwd", "Print current directory", builtin_pwd},
{"read", "Input environment variable", builtin_read},
+ {"return", "Return from a function", builtin_not_written},
+ {"set", "Set/unset shell options", builtin_not_written},
{"shift", "Shift positional parameters", builtin_shift},
- {"ulimit","Controls resource limits", builtin_ulimit},
+ {"trap", "Trap signals", builtin_not_written},
+ {"ulimit","Controls resource limits", builtin_not_written},
{"umask","Sets file creation mask", builtin_umask},
{"unset", "Unset environment variable", builtin_unset},
{".", "Source-in and run commands in a file", builtin_source},
@@ -640,16 +648,21 @@
return (status);
}
-static int builtin_ulimit(struct child_prog *child)
-{
- printf("builtin_ulimit not written\n");
- return EXIT_FAILURE;
-}
-
static int builtin_umask(struct child_prog *child)
{
- printf("builtin_umask not written\n");
- return EXIT_FAILURE;
+ mode_t new_umask;
+ const char *arg = child->argv[1];
+ char *end;
+ if (arg) {
+ new_umask=strtoul(arg, &end, 8);
+ if (*end!='\0' || end == arg) {
+ return EXIT_FAILURE;
+ }
+ } else {
+ printf("%.3o\n", (unsigned int) (new_umask=umask(0)));
+ }
+ umask(new_umask);
+ return EXIT_SUCCESS;
}
/* built-in 'unset VAR' handler */
@@ -663,6 +676,12 @@
return EXIT_SUCCESS;
}
+static int builtin_not_written(struct child_prog *child)
+{
+ printf("builtin_%s not written\n",child->argv[0]);
+ return EXIT_FAILURE;
+}
+
static int b_check_space(o_string *o, int len)
{
/* It would be easy to drop a more restrictive policy
@@ -926,8 +945,12 @@
if (squirrel && redir->fd < 3) {
squirrel[redir->fd] = dup(redir->fd);
}
- dup2(openfd, redir->fd);
- close(openfd);
+ if (openfd == -3) {
+ close(openfd);
+ } else {
+ dup2(openfd, redir->fd);
+ close(openfd);
+ }
}
}
return 0;
@@ -1216,6 +1239,11 @@
if (strcmp(child->argv[0], x->cmd) == 0 ) {
int squirrel[] = {-1, -1, -1};
int rcode;
+ if (x->function == builtin_exec && child->argv[1]==NULL) {
+ debug_printf("magic exec\n");
+ setup_redirects(child,NULL);
+ return EXIT_SUCCESS;
+ }
debug_printf("builtin inline %s\n", child->argv[0]);
/* XXX setup_redirects acts on file descriptors, not FILEs.
* This is perfect for work that comes after exec().
@@ -1569,7 +1597,8 @@
if (redir->dup == -2) return 1; /* syntax error */
if (redir->dup != -1) {
/* Erik had a check here that the file descriptor in question
- * is legit; I postpone that to "run time" */
+ * is legit; I postpone that to "run time"
+ * A "-" representation of "close me" shows up as a -3 here */
debug_printf("Duplicating redirect '%d>&%d'\n", redir->fd, redir->dup);
} else {
/* We do _not_ try to open the file that src points to,
@@ -1775,10 +1804,16 @@
if (ch != '&') return -1;
b_getch(input); /* get the & */
- while (ch=b_peek(input),isdigit(ch)) {
+ ch=b_peek(input);
+ if (ch == '-') {
+ b_getch(input);
+ return -3; /* "-" represents "close me" */
+ }
+ while (isdigit(ch)) {
d = d*10+(ch-'0');
ok=1;
b_getch(input);
+ ch = b_peek(input);
}
if (ok) return d;
diff --git a/shell/hush.c b/shell/hush.c
index b8e4a55..e58ac44 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -45,24 +45,25 @@
* fancy forms of Parameter Expansion
* Arithmetic Expansion
* <(list) and >(list) Process Substitution
- * reserved words: case, esac, function
+ * reserved words: case, esac, select, function
* Here Documents ( << word )
* Functions
* Major bugs:
* job handling woefully incomplete and buggy
* reserved word execution woefully incomplete and buggy
* to-do:
- * port selected bugfixes from post-0.49 busybox lash
- * finish implementing reserved words
+ * port selected bugfixes from post-0.49 busybox lash - done?
+ * finish implementing reserved words: for, while, until, do, done
+ * change { and } from special chars to reserved words
+ * builtins: break, continue, eval, return, set, trap, ulimit
+ * test magic exec
* handle children going into background
* clean up recognition of null pipes
* have builtin_exec set flag to avoid restore_redirects
- * figure out if "echo foo}" is fixable
* check setting of global_argc and global_argv
* control-C handling, probably with longjmp
* VAR=value prefix for simple commands
* follow IFS rules more precisely, including update semantics
- * write builtin_eval, builtin_ulimit, builtin_umask
* figure out what to do with backslash-newline
* explain why we use signal instead of sigaction
* propagate syntax errors, die on resource errors?
@@ -97,6 +98,7 @@
#include <fcntl.h>
#include <getopt.h> /* should be pretty obvious */
+#include <sys/stat.h> /* ulimit */
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
@@ -323,9 +325,9 @@
static int builtin_read(struct child_prog *child);
static int builtin_shift(struct child_prog *child);
static int builtin_source(struct child_prog *child);
-static int builtin_ulimit(struct child_prog *child);
static int builtin_umask(struct child_prog *child);
static int builtin_unset(struct child_prog *child);
+static int builtin_not_written(struct child_prog *child);
/* o_string manipulation: */
static int b_check_space(o_string *o, int len);
static int b_addchr(o_string *o, int ch);
@@ -390,8 +392,11 @@
* still be set at the end. */
static struct built_in_command bltins[] = {
{"bg", "Resume a job in the background", builtin_fg_bg},
+ {"break", "Exit for, while or until loop", builtin_not_written},
{"cd", "Change working directory", builtin_cd},
+ {"continue", "Continue for, while or until loop", builtin_not_written},
{"env", "Print all environment variables", builtin_env},
+ {"eval", "Construct and run shell command", builtin_not_written},
{"exec", "Exec command, replacing this shell with the exec'd process", builtin_exec},
{"exit", "Exit from shell()", builtin_exit},
{"export", "Set environment variable", builtin_export},
@@ -399,8 +404,11 @@
{"jobs", "Lists the active jobs", builtin_jobs},
{"pwd", "Print current directory", builtin_pwd},
{"read", "Input environment variable", builtin_read},
+ {"return", "Return from a function", builtin_not_written},
+ {"set", "Set/unset shell options", builtin_not_written},
{"shift", "Shift positional parameters", builtin_shift},
- {"ulimit","Controls resource limits", builtin_ulimit},
+ {"trap", "Trap signals", builtin_not_written},
+ {"ulimit","Controls resource limits", builtin_not_written},
{"umask","Sets file creation mask", builtin_umask},
{"unset", "Unset environment variable", builtin_unset},
{".", "Source-in and run commands in a file", builtin_source},
@@ -640,16 +648,21 @@
return (status);
}
-static int builtin_ulimit(struct child_prog *child)
-{
- printf("builtin_ulimit not written\n");
- return EXIT_FAILURE;
-}
-
static int builtin_umask(struct child_prog *child)
{
- printf("builtin_umask not written\n");
- return EXIT_FAILURE;
+ mode_t new_umask;
+ const char *arg = child->argv[1];
+ char *end;
+ if (arg) {
+ new_umask=strtoul(arg, &end, 8);
+ if (*end!='\0' || end == arg) {
+ return EXIT_FAILURE;
+ }
+ } else {
+ printf("%.3o\n", (unsigned int) (new_umask=umask(0)));
+ }
+ umask(new_umask);
+ return EXIT_SUCCESS;
}
/* built-in 'unset VAR' handler */
@@ -663,6 +676,12 @@
return EXIT_SUCCESS;
}
+static int builtin_not_written(struct child_prog *child)
+{
+ printf("builtin_%s not written\n",child->argv[0]);
+ return EXIT_FAILURE;
+}
+
static int b_check_space(o_string *o, int len)
{
/* It would be easy to drop a more restrictive policy
@@ -926,8 +945,12 @@
if (squirrel && redir->fd < 3) {
squirrel[redir->fd] = dup(redir->fd);
}
- dup2(openfd, redir->fd);
- close(openfd);
+ if (openfd == -3) {
+ close(openfd);
+ } else {
+ dup2(openfd, redir->fd);
+ close(openfd);
+ }
}
}
return 0;
@@ -1216,6 +1239,11 @@
if (strcmp(child->argv[0], x->cmd) == 0 ) {
int squirrel[] = {-1, -1, -1};
int rcode;
+ if (x->function == builtin_exec && child->argv[1]==NULL) {
+ debug_printf("magic exec\n");
+ setup_redirects(child,NULL);
+ return EXIT_SUCCESS;
+ }
debug_printf("builtin inline %s\n", child->argv[0]);
/* XXX setup_redirects acts on file descriptors, not FILEs.
* This is perfect for work that comes after exec().
@@ -1569,7 +1597,8 @@
if (redir->dup == -2) return 1; /* syntax error */
if (redir->dup != -1) {
/* Erik had a check here that the file descriptor in question
- * is legit; I postpone that to "run time" */
+ * is legit; I postpone that to "run time"
+ * A "-" representation of "close me" shows up as a -3 here */
debug_printf("Duplicating redirect '%d>&%d'\n", redir->fd, redir->dup);
} else {
/* We do _not_ try to open the file that src points to,
@@ -1775,10 +1804,16 @@
if (ch != '&') return -1;
b_getch(input); /* get the & */
- while (ch=b_peek(input),isdigit(ch)) {
+ ch=b_peek(input);
+ if (ch == '-') {
+ b_getch(input);
+ return -3; /* "-" represents "close me" */
+ }
+ while (isdigit(ch)) {
d = d*10+(ch-'0');
ok=1;
b_getch(input);
+ ch = b_peek(input);
}
if (ok) return d;