//#define BB_FEATURE_SH_BACKTICKS
//#define BB_FEATURE_SH_IF_EXPRESSIONS
-//#define BB_FEATURE_SH_ENVIRONMENT
+#define BB_FEATURE_SH_ENVIRONMENT
//#define DEBUG_SHELL
-#include "internal.h"
+#include "busybox.h"
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <sys/wait.h>
#include <unistd.h>
#include <getopt.h>
-#ifdef BB_FEATURE_SH_COMMAND_EDITING
#include "cmdedit.h"
-#endif
#define MAX_LINE 256 /* size of input buffer for `read' builtin */
#define MAX_READ 128 /* size of input buffer for `read' builtin */
#define JOB_STATUS_FORMAT "[%d] %-22s %.40s\n"
+extern size_t NUM_APPLETS;
+
+
enum redirectionType { REDIRECT_INPUT, REDIRECT_OVERWRITE,
/* function prototypes for builtins */
static int builtin_cd(struct job *cmd, struct jobSet *junk);
static int builtin_env(struct job *dummy, struct jobSet *junk);
+static int builtin_exec(struct job *cmd, struct jobSet *junk);
static int builtin_exit(struct job *cmd, struct jobSet *junk);
static int builtin_fg_bg(struct job *cmd, struct jobSet *jobList);
static int builtin_help(struct job *cmd, struct jobSet *junk);
static struct builtInCommand bltins[] = {
{"bg", "Resume a job in the background", builtin_fg_bg},
{"cd", "Change working directory", builtin_cd},
+ {"exec", "Exec command, replacing this shell with the exec'd process", builtin_exec},
{"exit", "Exit from shell()", builtin_exit},
{"fg", "Bring job into the foreground", builtin_fg_bg},
{"jobs", "Lists the active jobs", builtin_jobs},
{NULL, NULL, NULL}
};
-static char *prompt = "# ";
+static char prompt[3];
static char *cwd;
static char *local_pending_command = NULL;
static char *promptStr = NULL;
static int showXtrace=FALSE;
#endif
+#ifdef DEBUG_SHELL
+static inline void debug_printf(const char *format, ...)
+{
+ va_list args;
+ va_start(args, format);
+ vfprintf(stderr, s, p);
+ va_end(args);
+}
+#else
+static inline void debug_printf(const char *format, ...) { }
+#endif
#ifdef BB_FEATURE_SH_COMMAND_EDITING
-void win_changed(int junk)
+static inline void win_changed(int junk)
{
struct winsize win = { 0, 0, 0, 0 };
ioctl(0, TIOCGWINSZ, &win);
cmdedit_setwidth( win.ws_col - 1);
}
}
+#else
+static inline void win_changed(int junk) {}
#endif
newdir = cmd->progs[0].argv[1];
if (chdir(newdir)) {
printf("cd: %s: %s\n", newdir, strerror(errno));
- return FALSE;
+ return EXIT_FAILURE;
}
getcwd(cwd, sizeof(char)*MAX_LINE);
- return TRUE;
+ return EXIT_SUCCESS;
}
/* built-in 'env' handler */
return (0);
}
+/* built-in 'exec' handler */
+static int builtin_exec(struct job *cmd, struct jobSet *junk)
+{
+ if (cmd->progs[0].argv[1])
+ {
+ cmd->progs[0].argv++;
+ execvp(cmd->progs[0].argv[0], cmd->progs[0].argv);
+ fatalError("Exec to %s failed: %s\n", cmd->progs[0].argv[0],
+ strerror(errno));
+ }
+ return EXIT_SUCCESS;
+}
+
/* built-in 'exit' handler */
static int builtin_exit(struct job *cmd, struct jobSet *junk)
{
if (!cmd->progs[0].argv[1] == 1)
- exit TRUE;
+ exit(EXIT_SUCCESS);
exit (atoi(cmd->progs[0].argv[1]));
}
if (!cmd->progs[0].argv[1] || cmd->progs[0].argv[2]) {
errorMsg("%s: exactly one argument is expected\n",
cmd->progs[0].argv[0]);
- return FALSE;
+ return EXIT_FAILURE;
}
if (sscanf(cmd->progs[0].argv[1], "%%%d", &jobNum) != 1) {
errorMsg("%s: bad argument '%s'\n",
cmd->progs[0].argv[0], cmd->progs[0].argv[1]);
- return FALSE;
+ return EXIT_FAILURE;
for (job = jobList->head; job; job = job->next) {
if (job->jobId == jobNum) {
break;
if (!job) {
errorMsg("%s: unknown job %d\n",
cmd->progs[0].argv[0], jobNum);
- return FALSE;
+ return EXIT_FAILURE;
}
if (*cmd->progs[0].argv[0] == 'f') {
job->stoppedProgs = 0;
- return TRUE;
+ return EXIT_SUCCESS;
}
/* built-in 'help' handler */
fprintf(stdout, "%s\t%s\n", x->cmd, x->descr);
}
fprintf(stdout, "\n\n");
- return TRUE;
+ return EXIT_SUCCESS;
}
/* built-in 'jobs' handler */
printf(JOB_STATUS_FORMAT, job->jobId, statusString, job->text);
}
- return TRUE;
+ return EXIT_SUCCESS;
}
{
getcwd(cwd, sizeof(char)*MAX_LINE);
fprintf(stdout, "%s\n", cwd);
- return TRUE;
+ return EXIT_SUCCESS;
}
/* built-in 'export VAR=value' handler */
local_pending_command = xmalloc(status+1);
strncpy(local_pending_command, charptr1, status);
local_pending_command[status]='\0';
-#ifdef DEBUG_SHELL
- fprintf(stderr, "'if' now testing '%s'\n", local_pending_command);
-#endif
+ debug_printf(stderr, "'if' now testing '%s'\n", local_pending_command);
status = busy_loop(NULL); /* Frees local_pending_command */
-#ifdef DEBUG_SHELL
- fprintf(stderr, "if test returned ");
-#endif
+ debug_printf(stderr, "if test returned ");
if (status == 0) {
-#ifdef DEBUG_SHELL
- fprintf(stderr, "TRUE\n");
-#endif
+ debug_printf(stderr, "TRUE\n");
cmd->jobContext |= IF_TRUE_CONTEXT;
} else {
-#ifdef DEBUG_SHELL
- fprintf(stderr, "FALSE\n");
-#endif
+ debug_printf(stderr, "FALSE\n");
cmd->jobContext |= IF_FALSE_CONTEXT;
}
if (! (cmd->jobContext & (IF_TRUE_CONTEXT|IF_FALSE_CONTEXT))) {
errorMsg("unexpected token `then'\n");
- return FALSE;
+ return EXIT_FAILURE;
}
/* If the if result was FALSE, skip the 'then' stuff */
if (cmd->jobContext & IF_FALSE_CONTEXT) {
- return TRUE;
+ return EXIT_SUCCESS;
}
cmd->jobContext |= THEN_EXP_CONTEXT;
local_pending_command = xmalloc(status+1);
strncpy(local_pending_command, charptr1, status);
local_pending_command[status]='\0';
-#ifdef DEBUG_SHELL
- fprintf(stderr, "'then' now running '%s'\n", charptr1);
-#endif
+ debug_printf(stderr, "'then' now running '%s'\n", charptr1);
return( busy_loop(NULL));
}
if (! (cmd->jobContext & (IF_TRUE_CONTEXT|IF_FALSE_CONTEXT))) {
errorMsg("unexpected token `else'\n");
- return FALSE;
+ return EXIT_FAILURE;
}
/* If the if result was TRUE, skip the 'else' stuff */
if (cmd->jobContext & IF_TRUE_CONTEXT) {
- return TRUE;
+ return EXIT_SUCCESS;
}
cmd->jobContext |= ELSE_EXP_CONTEXT;
local_pending_command = xmalloc(status+1);
strncpy(local_pending_command, charptr1, status);
local_pending_command[status]='\0';
-#ifdef DEBUG_SHELL
- fprintf(stderr, "'else' now running '%s'\n", charptr1);
-#endif
+ debug_printf(stderr, "'else' now running '%s'\n", charptr1);
return( busy_loop(NULL));
}
{
if (! (cmd->jobContext & (IF_TRUE_CONTEXT|IF_FALSE_CONTEXT))) {
errorMsg("unexpected token `fi'\n");
- return FALSE;
+ return EXIT_FAILURE;
}
/* Clear out the if and then context bits */
cmd->jobContext &= ~(IF_TRUE_CONTEXT|IF_FALSE_CONTEXT|THEN_EXP_CONTEXT|ELSE_EXP_CONTEXT);
-#ifdef DEBUG_SHELL
- fprintf(stderr, "Hit an fi -- jobContext=%d\n", cmd->jobContext);
-#endif
- return TRUE;
+ debug_printf(stderr, "Hit an fi -- jobContext=%d\n", cmd->jobContext);
+ return EXIT_SUCCESS;
}
#endif
int status;
if (!cmd->progs[0].argv[1] == 1)
- return FALSE;
+ return EXIT_FAILURE;
input = fopen(cmd->progs[0].argv[1], "r");
if (!input) {
fprintf(stdout, "Couldn't open file '%s'\n",
cmd->progs[0].argv[1]);
- return FALSE;
+ return EXIT_FAILURE;
}
/* Now run the file */
{
if (!cmd->progs[0].argv[1] == 1) {
fprintf(stdout, "unset: parameter required.\n");
- return FALSE;
+ return EXIT_FAILURE;
}
unsetenv(cmd->progs[0].argv[1]);
- return TRUE;
+ return EXIT_SUCCESS;
}
/* free up all memory from a job */
mode = O_RDONLY;
break;
case REDIRECT_OVERWRITE:
- mode = O_RDWR | O_CREAT | O_TRUNC;
+ mode = O_WRONLY | O_CREAT | O_TRUNC;
break;
case REDIRECT_APPEND:
- mode = O_RDWR | O_CREAT | O_APPEND;
+ mode = O_WRONLY | O_CREAT | O_APPEND;
break;
}
static int getCommand(FILE * source, char *command)
{
+ char *user,buf[255],*s;
+
if (source == NULL) {
if (local_pending_command) {
/* a command specified (-c option): return it & mark it done */
return 1;
}
+ /* get User Name and setup prompt */
+ strcpy(prompt,( geteuid() != 0 ) ? "$ ":"# ");
+ user=xcalloc(sizeof(int), 9);
+ my_getpwuid(user, geteuid());
+
+ /* get HostName */
+ gethostname(buf, 255);
+ s = strchr(buf, '.');
+ if (s)
+ *s = 0;
+
if (source == stdin) {
#ifdef BB_FEATURE_SH_COMMAND_EDITING
int len;
*/
cmdedit_init();
signal(SIGWINCH, win_changed);
- len=fprintf(stdout, "%s %s", cwd, prompt);
+ len=fprintf(stdout, "[%s@%s %s]%s", user, buf,
+ get_last_path_component(cwd), prompt);
fflush(stdout);
promptStr=(char*)xmalloc(sizeof(char)*(len+1));
- sprintf(promptStr, "%s %s", cwd, prompt);
+ sprintf(promptStr, "[%s@%s %s]%s", user, buf,
+ get_last_path_component(cwd), prompt);
cmdedit_read_input(promptStr, command);
free( promptStr);
cmdedit_terminate();
signal(SIGWINCH, SIG_DFL);
return 0;
#else
- fprintf(stdout, "%s %s", cwd, prompt);
+ i=strlen(cwd);
+ i--;
+ if (i>1){
+ while ((i>0) && (*(cwd+i)!='/') ) i--;
+ if (*(cwd+i)=='/') i++;
+ }
+
+ fprintf(stdout, "[%s@%s %s]%s",user, buf, (cwd+i), prompt);
fflush(stdout);
#endif
}
+ /* don't leak memory */
+ free(user);
+
if (!fgets(command, BUFSIZ - 2, source)) {
if (source == stdin)
printf("\n");
}
#ifdef BB_FEATURE_SH_ENVIRONMENT
-#define __MAX_INT_CHARS 7
static char* itoa(register int i)
{
- static char a[__MAX_INT_CHARS];
+ static char a[7]; /* Max 7 ints */
register char *b = a + sizeof(a) - 1;
int sign = (i < 0);
#endif
}
- rc = glob(prog->argv[argc_l - 1], flags, NULL, &prog->globResult);
- if (rc == GLOB_NOSPACE) {
- errorMsg("out of space during glob operation\n");
- return;
- } else if (rc == GLOB_NOMATCH ||
+ if (strpbrk(prog->argv[argc_l - 1],"*[]?")!= NULL){
+ rc = glob(prog->argv[argc_l - 1], flags, NULL, &prog->globResult);
+ if (rc == GLOB_NOSPACE) {
+ errorMsg("out of space during glob operation\n");
+ return;
+ } else if (rc == GLOB_NOMATCH ||
(!rc && (prog->globResult.gl_pathc - i) == 1 &&
strcmp(prog->argv[argc_l - 1],
prog->globResult.gl_pathv[i]) == 0)) {
- /* we need to remove whatever \ quoting is still present */
- src = dst = prog->argv[argc_l - 1];
- while (*src) {
- if (*src != '\\')
- *dst++ = *src;
- src++;
+ /* we need to remove whatever \ quoting is still present */
+ src = dst = prog->argv[argc_l - 1];
+ while (*src) {
+ if (*src == '\\') {
+ src++;
+ *dst++ = process_escape_sequence(&src);
+ } else {
+ *dst++ = *src;
+ src++;
+ }
+ }
+ *dst = '\0';
+ } else if (!rc) {
+ argcAlloced += (prog->globResult.gl_pathc - i);
+ prog->argv = xrealloc(prog->argv, argcAlloced * sizeof(*prog->argv));
+ memcpy(prog->argv + (argc_l - 1), prog->globResult.gl_pathv + i,
+ sizeof(*(prog->argv)) * (prog->globResult.gl_pathc - i));
+ argc_l += (prog->globResult.gl_pathc - i - 1);
}
- *dst = '\0';
- } else if (!rc) {
- argcAlloced += (prog->globResult.gl_pathc - i);
- prog->argv = xrealloc(prog->argv, argcAlloced * sizeof(*prog->argv));
- memcpy(prog->argv + (argc_l - 1), prog->globResult.gl_pathv + i,
- sizeof(*(prog->argv)) * (prog->globResult.gl_pathc - i));
- argc_l += (prog->globResult.gl_pathc - i - 1);
+ }else{
+ src = dst = prog->argv[argc_l - 1];
+ while (*src) {
+ if (*src == '\\') {
+ src++;
+ *dst++ = process_escape_sequence(&src);
+ } else {
+ *dst++ = *src;
+ src++;
+ }
+ }
+ *dst = '\0';
+
+ prog->globResult.gl_pathc=0;
+ if (flags==0)
+ prog->globResult.gl_pathv=NULL;
}
-
*argcAllocedPtr = argcAlloced;
*argcPtr = argc_l;
}
/* Make some space to hold just the backticked command */
charptr1 = charptr2 = xmalloc(1+ptr-src);
- snprintf(charptr1, 1+ptr-src, src);
+ memcpy(charptr1, src, ptr-src);
+ charptr1[ptr-src] = '\0';
newJob = xmalloc(sizeof(struct job));
/* Now parse and run the backticked command */
if (!parseCommand(&charptr1, newJob, &njobList, inBg)
}
*commandPtr = returnCommand;
-
+
return 0;
}
int pipefds[2]; /* pipefd[0] is for reading */
struct builtInCommand *x;
#ifdef BB_FEATURE_SH_STANDALONE_SHELL
- const struct BB_applet *a = applets;
+ struct BB_applet search_applet, *applet;
#endif
-
nextin = 0, nextout = 1;
for (i = 0; i < newJob->numProgs; i++) {
if ((i + 1) < newJob->numProgs) {
}
}
#ifdef BB_FEATURE_SH_STANDALONE_SHELL
- /* Check if the command matches any busybox internal commands here */
- while (a->name != 0) {
- if (strcmp(get_last_path_component(newJob->progs[i].argv[0]), a->name) == 0) {
- int argc_l;
- char** argv=newJob->progs[i].argv;
- for(argc_l=0;*argv!=NULL; argv++, argc_l++);
- applet_name=a->name;
- optind = 1;
- exit((*(a->main)) (argc_l, newJob->progs[i].argv));
- }
- a++;
+ /* Check if the command matches any busybox internal
+ * commands ("applets") here. Following discussions from
+ * November 2000 on busybox@opensource.lineo.com, don't use
+ * get_last_path_component(). This way explicit (with
+ * slashes) filenames will never be interpreted as an
+ * applet, just like with builtins. This way the user can
+ * override an applet with an explicit filename reference.
+ * The only downside to this change is that an explicit
+ * /bin/foo invocation fill fork and exec /bin/foo, even if
+ * /bin/foo is a symlink to busybox.
+ */
+ search_applet.name = newJob->progs[i].argv[0];
+
+#ifdef BB_FEATURE_SH_BUILTINS_ALWAYS_WIN
+ /* If you enable BB_FEATURE_SH_BUILTINS_ALWAYS_WIN, then
+ * if you run /bin/cat, it will use BusyBox cat even if
+ * /bin/cat exists on the filesystem and is _not_ busybox.
+ * Some systems want this, others do not. Choose wisely. :-)
+ */
+ search_applet.name = get_last_path_component(search_applet.name);
+#endif
+
+ /* Do a binary search to find the applet entry given the name. */
+ applet = bsearch(&search_applet, applets, NUM_APPLETS,
+ sizeof(struct BB_applet), applet_name_compare);
+ if (applet != NULL) {
+ int argc_l;
+ char** argv=newJob->progs[i].argv;
+ for(argc_l=0;*argv!=NULL; argv++, argc_l++);
+ applet_name=applet->name;
+ optind = 1;
+ exit((*(applet->main)) (argc_l, newJob->progs[i].argv));
}
#endif
execvp(newJob->progs[i].argv[0], newJob->progs[i].argv);
fatalError("%s: %s\n", newJob->progs[i].argv[0],
- strerror(errno));
+ strerror(errno));
}
if (outPipe[1]!=-1) {
close(outPipe[1]);
#ifdef BB_FEATURE_SH_ENVIRONMENT
lastReturnCode=WEXITSTATUS(status);
#endif
-#if 0
- printf("'%s' exited -- return code %d\n", jobList.fg->text, lastReturnCode);
-#endif
+ debug_printf("'%s' exited -- return code %d\n", jobList.fg->text, lastReturnCode);
if (!jobList.fg->runningProgs) {
/* child exited */
argv = argv_l;
- //if (argv[0] && argv[0][0] == '-') {
- // builtin_source("/etc/profile");
- //}
+ if (argv[0] && argv[0][0] == '-') {
+ FILE *input;
+ input = fopen("/etc/profile", "r");
+ if (!input) {
+ fprintf(stdout, "Couldn't open file '/etc/profile'\n");
+ } else {
+ /* Now run the file */
+ busy_loop(input);
+ fclose(input);
+ }
+ }
while ((opt = getopt(argc_l, argv_l, "cx")) > 0) {
switch (opt) {
fprintf(stdout, "Enter 'help' for a list of built-in commands.\n\n");
} else if (local_pending_command==NULL) {
//fprintf(stdout, "optind=%d argv[optind]='%s'\n", optind, argv[optind]);
- input = fopen(argv[optind], "r");
- if (!input) {
- fatalError("%s: %s\n", argv[optind], strerror(errno));
- }
+ input = xfopen(argv[optind], "r");
}
/* initialize the cwd -- this is never freed...*/
atexit(free_memory);
#endif
-#ifdef BB_FEATURE_SH_COMMAND_EDITING
win_changed(0);
-#endif
-
return (busy_loop(input));
}