/*
* lash -- the BusyBox Lame-Ass SHell
*
- * Copyright (C) 1999,2000,2001 by Lineo, inc.
- * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
*
* Based in part on ladsh.c by Michael K. Johnson and Erik W. Troan, which is
* under the following liberal license: "We have placed this source code in the
*
*/
-/* This shell's parsing engine is officially at a dead-end.
- * Future work shell work should be done using hush.c
+/* This shell's parsing engine is officially at a dead-end. Future
+ * work shell work should be done using hush, msh, or ash. This is
+ * still a very useful, small shell -- it just don't need any more
+ * features beyond what it already has...
*/
//For debugging/development on the shell only...
#include "busybox.h"
#include "cmdedit.h"
-#ifdef BB_LOCALE_SUPPORT
+#ifdef CONFIG_LOCALE_SUPPORT
#include <locale.h>
#endif
#include <glob.h>
#define expand_t glob_t
+/* Always enable for the moment... */
+#define CONFIG_LASH_PIPE_N_REDIRECTS
+#define CONFIG_LASH_JOB_CONTROL
static const int MAX_READ = 128; /* size of input buffer for `read' builtin */
#define JOB_STATUS_FORMAT "[%d] %-22s %.40s\n"
+#ifdef CONFIG_LASH_PIPE_N_REDIRECTS
enum redir_type { REDIRECT_INPUT, REDIRECT_OVERWRITE,
REDIRECT_APPEND
};
+#endif
static const unsigned int DEFAULT_CONTEXT=0x1;
static const unsigned int IF_TRUE_CONTEXT=0x2;
static const unsigned int THEN_EXP_CONTEXT=0x8;
static const unsigned int ELSE_EXP_CONTEXT=0x10;
-
-struct jobset {
- struct job *head; /* head of list of running jobs */
- struct job *fg; /* current foreground job */
-};
-
+#ifdef CONFIG_LASH_PIPE_N_REDIRECTS
struct redir_struct {
enum redir_type type; /* type of redirection */
int fd; /* file descriptor being redirected */
char *filename; /* file to redirect fd to */
};
+#endif
struct child_prog {
pid_t pid; /* 0 if exited */
char **argv; /* program name and arguments */
int num_redirects; /* elements in redirection array */
- struct redir_struct *redirects; /* I/O redirects */
int is_stopped; /* is the program currently running? */
struct job *family; /* pointer back to the child's parent job */
+#ifdef CONFIG_LASH_PIPE_N_REDIRECTS
+ struct redir_struct *redirects; /* I/O redirects */
+#endif
+};
+
+struct jobset {
+ struct job *head; /* head of list of running jobs */
+ struct job *fg; /* current foreground job */
};
struct job {
};
-/* Variables we export */
-unsigned int shell_context; /* Used in cmdedit.c to reset the
- context when someone hits ^C */
+static int shell_context; /* Type prompt trigger (PS1 or PS2) */
/* Globals that are static to this file */
static int last_bg_pid;
static unsigned int last_jobid;
static int shell_terminal;
-static pid_t shell_pgrp;
static char *PS1;
static char *PS2 = "> ";
}
cwd = xgetcwd((char *)cwd);
if (!cwd)
- cwd = unknown;
+ cwd = bb_msg_unknown;
return EXIT_SUCCESS;
}
}
}
if (!job) {
- error_msg("%s: no current job", child->argv[0]);
+ bb_error_msg("%s: no current job", child->argv[0]);
return EXIT_FAILURE;
}
} else {
if (sscanf(child->argv[1], "%%%d", &jobnum) != 1) {
- error_msg("%s: bad argument '%s'", child->argv[0], child->argv[1]);
+ bb_error_msg("%s: bad argument '%s'", child->argv[0], child->argv[1]);
return EXIT_FAILURE;
}
for (job = child->family->job_list->head; job; job = job->next) {
}
}
if (!job) {
- error_msg("%s: %d: no such job", child->argv[0], jobnum);
+ bb_error_msg("%s: %d: no such job", child->argv[0], jobnum);
return EXIT_FAILURE;
}
}
if ( (i=kill(- job->pgrp, SIGCONT)) < 0) {
if (i == ESRCH) {
remove_job(&job_list, job);
+ } else {
+ bb_perror_msg("kill (SIGCONT)");
}
- perror_msg("kill (SIGCONT)");
}
return EXIT_SUCCESS;
{
cwd = xgetcwd((char *)cwd);
if (!cwd)
- cwd = unknown;
+ cwd = bb_msg_unknown;
puts(cwd);
return EXIT_SUCCESS;
}
res = putenv(v);
if (res)
fprintf(stderr, "export: %m\n");
-#ifdef BB_FEATURE_SH_FANCY_PROMPT
+#ifdef CONFIG_FEATURE_SH_FANCY_PROMPT
if (strncmp(v, "PS1=", 4)==0)
PS1 = getenv("PS1");
#endif
-#ifdef BB_LOCALE_SUPPORT
+#ifdef CONFIG_LOCALE_SUPPORT
if(strncmp(v, "LC_ALL=", 7)==0)
setlocale(LC_ALL, getenv("LC_ALL"));
if(strncmp(v, "LC_CTYPE=", 9)==0)
if (child->argv[1]) {
/* argument (VAR) given: put "VAR=" into buffer */
- strcpy(string, child->argv[1]);
+ safe_strncpy(string, child->argv[1], MAX_READ-1);
len = strlen(string);
string[len++] = '=';
string[len] = '\0';
{
struct close_me *tmp;
if (close_me_head == NULL || close_me_head->fd != fd)
- error_msg_and_die("corrupt close_me");
+ bb_error_msg_and_die("corrupt close_me");
tmp = close_me_head;
close_me_head = close_me_head->next;
free(tmp);
}
+#ifdef CONFIG_LASH_JOB_CONTROL
/* free up all memory from a job */
static void free_job(struct job *cmd)
{
for (i = 0; i < cmd->num_progs; i++) {
free(cmd->progs[i].argv);
+#ifdef CONFIG_LASH_PIPE_N_REDIRECTS
if (cmd->progs[i].redirects)
free(cmd->progs[i].redirects);
+#endif
}
- if (cmd->progs)
- free(cmd->progs);
- if (cmd->text)
- free(cmd->text);
- if (cmd->cmdbuf)
- free(cmd->cmdbuf);
+ free(cmd->progs);
+ free(cmd->text);
+ free(cmd->cmdbuf);
keep = cmd->job_list;
memset(cmd, 0, sizeof(struct job));
cmd->job_list = keep;
free(job);
}
-/* Checks to see if any background processes have exited -- if they
+/* Checks to see if any background processes have exited -- if they
have, figure out why and see if a job has completed */
static void checkjobs(struct jobset *j_list)
{
printf(JOB_STATUS_FORMAT, job->jobid, "Stopped",
job->text);
}
-#endif
+#endif
}
}
if (childpid == -1 && errno != ECHILD)
- perror_msg("waitpid");
+ bb_perror_msg("waitpid");
+}
+#else
+static void checkjobs(struct jobset *j_list)
+{
+}
+static void free_job(struct job *cmd)
+{
}
+static void remove_job(struct jobset *j_list, struct job *job)
+{
+}
+#endif
+#ifdef CONFIG_LASH_PIPE_N_REDIRECTS
/* squirrel != NULL means we squirrel away copies of stdin, stdout,
* and stderr if they are redirected. */
static int setup_redirects(struct child_prog *prog, int squirrel[])
if (openfd < 0) {
/* this could get lost if stderr has been redirected, but
bash and ash both lose it as well (though zsh doesn't!) */
- perror_msg("error opening %s", redir->filename);
+ bb_perror_msg("error opening %s", redir->filename);
return 1;
}
if (openfd != redir->fd) {
if (squirrel && redir->fd < 3) {
squirrel[redir->fd] = dup(redir->fd);
+ fcntl (squirrel[redir->fd], F_SETFD, FD_CLOEXEC);
}
dup2(openfd, redir->fd);
close(openfd);
}
}
}
+#else
+static inline int setup_redirects(struct child_prog *prog, int squirrel[])
+{
+ return 0;
+}
+static inline void restore_redirects(int squirrel[])
+{
+}
+#endif
static inline void cmdedit_set_initial_prompt(void)
{
-#ifndef BB_FEATURE_SH_FANCY_PROMPT
+#ifndef CONFIG_FEATURE_SH_FANCY_PROMPT
PS1 = NULL;
#else
PS1 = getenv("PS1");
if(PS1==0)
PS1 = "\\w \\$ ";
-#endif
+#endif
}
static inline void setup_prompt_string(char **prompt_str)
{
-#ifndef BB_FEATURE_SH_FANCY_PROMPT
+#ifndef CONFIG_FEATURE_SH_FANCY_PROMPT
/* Set up the prompt */
if (shell_context == 0) {
- if (PS1)
- free(PS1);
+ free(PS1);
PS1=xmalloc(strlen(cwd)+4);
sprintf(PS1, "%s %s", cwd, ( geteuid() != 0 ) ? "$ ":"# ");
*prompt_str = PS1;
}
#else
*prompt_str = (shell_context==0)? PS1 : PS2;
-#endif
+#endif
}
static int get_command(FILE * source, char *command)
if (source == stdin) {
setup_prompt_string(&prompt_str);
-#ifdef BB_FEATURE_COMMAND_EDITING
+#ifdef CONFIG_FEATURE_COMMAND_EDITING
/*
** enable command line editing only while a command line
** is actually being read; otherwise, we'll end up bequeathing
** child processes (rob@sysgo.de)
*/
cmdedit_read_input(prompt_str, command);
- cmdedit_terminate();
return 0;
#else
fputs(prompt_str, stdout);
(*ix)++;
}
- /* Find the end of any whitespace trailing behind
+ /* Find the end of any whitespace trailing behind
* the token and let that be part of the token */
while( string && string[*ix] && isspace(string[*ix]) ) {
(*ix)++;
token = xmalloc(*ix+1);
token[*ix] = '\0';
- strncpy(token, string, *ix);
+ strncpy(token, string, *ix);
return token;
}
int flags = GLOB_NOCHECK
#ifdef GLOB_BRACE
| GLOB_BRACE
-#endif
+#endif
#ifdef GLOB_TILDE
| GLOB_TILDE
-#endif
+#endif
;
/* get rid of the terminating \n */
while( command && command[ix]) {
if (command[ix] == '\\') {
const char *tmp = command+ix+1;
- command[ix] = process_escape_sequence( &tmp );
+ command[ix] = bb_process_escape_sequence( &tmp );
memmove(command+ix + 1, tmp, strlen(tmp)+1);
}
ix++;
/* We need a clean copy, so strsep can mess up the copy while
* we write stuff into the original (in a minute) */
- cmd = cmd_copy = strdup(command);
+ cmd = cmd_copy = bb_xstrdup(command);
*command = '\0';
- for (ix = 0, tmpcmd = cmd;
+ for (ix = 0, tmpcmd = cmd;
(tmpcmd = strsep_space(cmd, &ix)) != NULL; cmd += ix, ix=0) {
if (*tmpcmd == '\0')
break;
if (retval == GLOB_NOSPACE) {
/* Mem may have been allocated... */
globfree (&expand_result);
- error_msg(out_of_space);
+ bb_error_msg(out_of_space);
return FALSE;
} else if (retval != 0) {
/* Some other error. GLOB_NOMATCH shouldn't
- * happen because of the GLOB_NOCHECK flag in
+ * happen because of the GLOB_NOCHECK flag in
* the glob call. */
- error_msg("syntax error");
+ bb_error_msg("syntax error");
return FALSE;
} else {
/* Convert from char** (one word per string) to a simple char*,
for (i=0; i < expand_result.gl_pathc; i++) {
length=strlen(expand_result.gl_pathv[i]);
if (total_length+length+1 >= BUFSIZ) {
- error_msg(out_of_space);
+ bb_error_msg(out_of_space);
return FALSE;
}
strcat(command+total_length, " ");
free(cmd_copy);
trim(command);
- /* Now do the shell variable substitutions which
+ /* Now do the shell variable substitutions which
* wordexp can't do for us, namely $? and $! */
src = command;
while((dst = strchr(src,'$')) != NULL){
case '0':case '1':case '2':case '3':case '4':
case '5':case '6':case '7':case '8':case '9':
{
- int ixx=*(dst + 1)-48;
+ int ixx=*(dst+1)-48+1;
if (ixx >= argc) {
var='\0';
} else {
}
if (var) {
- /* a single character construction was found, and
+ /* a single character construction was found, and
* already handled in the case statement */
src=dst+2;
} else {
int subst_len = strlen(var);
int trail_len = strlen(src);
if (dst+subst_len+trail_len >= command+BUFSIZ) {
- error_msg(out_of_space);
+ bb_error_msg(out_of_space);
return FALSE;
}
/* Move stuff to the end of the string to accommodate
/* Return cmd->num_progs as 0 if no command is present (e.g. an empty
line). If a valid command is found, command_ptr is set to point to
- the beginning of the next command (if the original command had more
- then one job associated with it) or NULL if no more commands are
+ the beginning of the next command (if the original command had more
+ then one job associated with it) or NULL if no more commands are
present. */
static int parse_command(char **command_ptr, struct job *job, int *inbg)
{
char *command;
char *return_command = NULL;
- char *src, *buf, *chptr;
+ char *src, *buf;
int argc_l = 0;
int done = 0;
int argv_alloced;
- int i, saw_quote = 0;
+ int saw_quote = 0;
char quote = '\0';
int count;
struct child_prog *prog;
+#ifdef CONFIG_LASH_PIPE_N_REDIRECTS
+ int i;
+ char *chptr;
+#endif
/* skip leading white space */
while (**command_ptr && isspace(**command_ptr))
job->num_progs = 1;
job->progs = xmalloc(sizeof(*job->progs));
- /* We set the argv elements to point inside of this string. The
+ /* We set the argv elements to point inside of this string. The
memory is freed by free_job(). Allocate twice the original
length in case we need to quote every single character.
- Getting clean memory relieves us of the task of NULL
- terminating things and makes the rest of this look a bit
+ Getting clean memory relieves us of the task of NULL
+ terminating things and makes the rest of this look a bit
cleaner (though it is, admittedly, a tad less efficient) */
job->cmdbuf = command = xcalloc(2*strlen(*command_ptr) + 1, sizeof(char));
job->text = NULL;
prog = job->progs;
prog->num_redirects = 0;
- prog->redirects = NULL;
prog->is_stopped = 0;
prog->family = job;
+#ifdef CONFIG_LASH_PIPE_N_REDIRECTS
+ prog->redirects = NULL;
+#endif
argv_alloced = 5;
prog->argv = xmalloc(sizeof(*prog->argv) * argv_alloced);
if (*src == '\\') {
src++;
if (!*src) {
- error_msg("character expected after \\");
+ bb_error_msg("character expected after \\");
free_job(job);
return 1;
}
done = 1;
break;
+#ifdef CONFIG_LASH_PIPE_N_REDIRECTS
case '>': /* redirects */
case '<':
i = prog->num_redirects++;
prog->redirects[i].fd = -1;
if (buf != prog->argv[argc_l]) {
- /* the stuff before this character may be the file number
+ /* the stuff before this character may be the file number
being redirected */
prog->redirects[i].fd =
strtol(prog->argv[argc_l], &chptr, 10);
chptr++;
if (!*chptr) {
- error_msg("file name expected after %c", *(src-1));
+ bb_error_msg("file name expected after %c", *(src-1));
free_job(job);
job->num_progs=0;
return 1;
if (*prog->argv[argc_l] || saw_quote)
argc_l++;
if (!argc_l) {
- error_msg("empty command in pipe");
+ bb_error_msg("empty command in pipe");
free_job(job);
job->num_progs=0;
return 1;
src++;
if (!*src) {
- error_msg("empty command in pipe");
+ bb_error_msg("empty command in pipe");
free_job(job);
job->num_progs=0;
return 1;
src--; /* we'll ++ it at the end of the loop */
break;
+#endif
+#ifdef CONFIG_LASH_JOB_CONTROL
case '&': /* background */
*inbg = 1;
+#endif
case ';': /* multiple commands */
done = 1;
return_command = *command_ptr + (src - *command_ptr) + 1;
case '\\':
src++;
if (!*src) {
- error_msg("character expected after \\");
+ bb_error_msg("character expected after \\");
free_job(job);
return 1;
}
}
*command_ptr = return_command;
-
+
return 0;
}
static int pseudo_exec(struct child_prog *child)
{
struct built_in_command *x;
-#ifdef BB_FEATURE_SH_STANDALONE_SHELL
+#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
char *name;
#endif
*/
for (x = bltins; x->cmd; x++) {
if (strcmp(child->argv[0], x->cmd) == 0 ) {
- exit(x->function(child));
+ _exit(x->function(child));
}
}
/* Check if the command matches any of the forking builtins. */
for (x = bltins_forking; x->cmd; x++) {
if (strcmp(child->argv[0], x->cmd) == 0) {
- applet_name=x->cmd;
- exit (x->function(child));
+ bb_applet_name=x->cmd;
+ _exit (x->function(child));
}
}
-#ifdef BB_FEATURE_SH_STANDALONE_SHELL
+#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
/* 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
+ * November 2000 on busybox@busybox.net, don't use
+ * bb_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.
*/
name = child->argv[0];
-#ifdef BB_FEATURE_SH_APPLETS_ALWAYS_WIN
- /* If you enable BB_FEATURE_SH_APPLETS_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. :-)
- */
- name = get_last_path_component(name);
-#endif
-
{
char** argv_l=child->argv;
int argc_l;
#endif
execvp(child->argv[0], child->argv);
- perror_msg_and_die("%s", child->argv[0]);
+
+ /* Do not use bb_perror_msg_and_die() here, since we must not
+ * call exit() but should call _exit() instead */
+ fprintf(stderr, "%s: %m\n", child->argv[0]);
+ _exit(EXIT_FAILURE);
}
static void insert_job(struct job *newjob, int inbg)
thejob->running_progs = thejob->num_progs;
thejob->stopped_progs = 0;
+#ifdef CONFIG_LASH_JOB_CONTROL
if (inbg) {
- /* we don't wait for background thejobs to return -- append it
+ /* we don't wait for background thejobs to return -- append it
to the list of backgrounded thejobs and leave it alone */
printf("[%d] %d\n", thejob->jobid,
newjob->progs[newjob->num_progs - 1].pid);
/* move the new process group into the foreground */
/* suppress messages when run from /linuxrc mag@sysgo.de */
if (tcsetpgrp(shell_terminal, newjob->pgrp) && errno != ENOTTY)
- perror_msg("tcsetpgrp");
+ bb_perror_msg("tcsetpgrp");
}
+#endif
}
static int run_command(struct job *newjob, int inbg, int outpipe[2])
child = & (newjob->progs[i]);
if ((i + 1) < newjob->num_progs) {
- if (pipe(pipefds)<0) perror_msg_and_die("pipe");
+ if (pipe(pipefds)<0) bb_perror_msg_and_die("pipe");
nextout = pipefds[1];
} else {
if (outpipe[1]!=-1) {
if (newjob->num_progs == 1) {
for (x = bltins; x->cmd; x++) {
if (strcmp(child->argv[0], x->cmd) == 0 ) {
- int squirrel[] = {-1, -1, -1};
int rcode;
+ int squirrel[] = {-1, -1, -1};
setup_redirects(child, squirrel);
rcode = x->function(child);
restore_redirects(squirrel);
}
}
- if (!(child->pid = fork())) {
+#if !defined(__UCLIBC__) || defined(__ARCH_HAS_MMU__)
+ if (!(child->pid = fork()))
+#else
+ if (!(child->pid = vfork()))
+#endif
+ {
/* Set the handling for job control signals back to the default. */
signal(SIGINT, SIG_DFL);
signal(SIGQUIT, SIG_DFL);
if (nextout != 1)
close(nextout);
- /* If there isn't another process, nextin is garbage
+ /* If there isn't another process, nextin is garbage
but it doesn't matter */
nextin = pipefds[0];
}
char *command;
char *next_command = NULL;
struct job newjob;
- pid_t parent_pgrp;
int i;
int inbg;
int status;
- newjob.job_list = &job_list;
- newjob.job_context = DEFAULT_CONTEXT;
-
+#ifdef CONFIG_LASH_JOB_CONTROL
+ pid_t parent_pgrp;
/* save current owner of TTY so we can restore it on exit */
parent_pgrp = tcgetpgrp(shell_terminal);
+#endif
+ newjob.job_list = &job_list;
+ newjob.job_context = DEFAULT_CONTEXT;
command = (char *) xcalloc(BUFSIZ, sizeof(char));
next_command = command;
}
- if (expand_arguments(next_command) == FALSE) {
+ if (! expand_arguments(next_command)) {
free(command);
command = (char *) xcalloc(BUFSIZ, sizeof(char));
next_command = NULL;
if (!parse_command(&next_command, &newjob, &inbg) &&
newjob.num_progs) {
int pipefds[2] = {-1,-1};
- debug_printf( "job=%p fed to run_command by busy_loop()'\n",
+ debug_printf( "job=%p fed to run_command by busy_loop()'\n",
&newjob);
run_command(&newjob, inbg, pipefds);
}
while (!job_list.fg->progs[i].pid ||
job_list.fg->progs[i].is_stopped == 1) i++;
- if (waitpid(job_list.fg->progs[i].pid, &status, WUNTRACED)<0)
- perror_msg_and_die("waitpid(%d)",job_list.fg->progs[i].pid);
+ if (waitpid(job_list.fg->progs[i].pid, &status, WUNTRACED)<0) {
+ if (errno != ECHILD) {
+ bb_perror_msg_and_die("waitpid(%d)",job_list.fg->progs[i].pid);
+ }
+ }
if (WIFEXITED(status) || WIFSIGNALED(status)) {
/* the child exited */
remove_job(&job_list, job_list.fg);
job_list.fg = NULL;
}
- } else {
+ }
+#ifdef CONFIG_LASH_JOB_CONTROL
+ else {
/* the child was stopped */
job_list.fg->stopped_progs++;
job_list.fg->progs[i].is_stopped = 1;
/* move the shell to the foreground */
/* suppress messages when run from /linuxrc mag@sysgo.de */
if (tcsetpgrp(shell_terminal, getpgrp()) && errno != ENOTTY)
- perror_msg("tcsetpgrp");
+ bb_perror_msg("tcsetpgrp");
}
+#endif
}
}
free(command);
+#ifdef CONFIG_LASH_JOB_CONTROL
/* return controlling TTY back to parent process group before exiting */
- if (tcsetpgrp(shell_terminal, parent_pgrp))
- perror_msg("tcsetpgrp");
+ if (tcsetpgrp(shell_terminal, parent_pgrp) && errno != ENOTTY)
+ bb_perror_msg("tcsetpgrp");
+#endif
/* return exit status if called with "-c" */
if (input == NULL && WIFEXITED(status))
return WEXITSTATUS(status);
-
+
return 0;
}
-
-#ifdef BB_FEATURE_CLEAN_UP
+#ifdef CONFIG_FEATURE_CLEAN_UP
void free_memory(void)
{
- if (cwd) {
- free(cwd);
+ if (cwd && cwd!=bb_msg_unknown) {
+ free((char*)cwd);
}
if (local_pending_command)
free(local_pending_command);
}
#endif
+#ifdef CONFIG_LASH_JOB_CONTROL
/* Make sure we have a controlling tty. If we get started under a job
* aware app (like bash for example), make sure we are now in charge so
* we don't fight over who gets the foreground */
-static void setup_job_control()
+static void setup_job_control(void)
{
+ int status;
+ pid_t shell_pgrp;
+
/* Loop until we are in the foreground. */
- while (tcgetpgrp (shell_terminal) != (shell_pgrp = getpgrp ()))
+ while ((status = tcgetpgrp (shell_terminal)) >= 0) {
+ if (status == (shell_pgrp = getpgrp ())) {
+ break;
+ }
kill (- shell_pgrp, SIGTTIN);
+ }
/* Ignore interactive and job-control signals. */
signal(SIGINT, SIG_IGN);
/* Grab control of the terminal. */
tcsetpgrp(shell_terminal, shell_pgrp);
}
+#else
+static inline void setup_job_control(void)
+{
+}
+#endif
-int shell_main(int argc_l, char **argv_l)
+int lash_main(int argc_l, char **argv_l)
{
int opt, interactive=FALSE;
FILE *input = stdin;
/* These variables need re-initializing when recursing */
last_jobid = 0;
- shell_context = 0;
local_pending_command = NULL;
close_me_head = NULL;
job_list.head = NULL;
prof_input = fopen("/etc/profile", "r");
if (prof_input) {
int tmp_fd = fileno(prof_input);
- mark_open(tmp_fd);
+ mark_open(tmp_fd);
/* Now run the file */
busy_loop(prof_input);
fclose(prof_input);
case 'c':
input = NULL;
if (local_pending_command != 0)
- error_msg_and_die("multiple -c arguments");
- local_pending_command = xstrdup(argv[optind]);
+ bb_error_msg_and_die("multiple -c arguments");
+ local_pending_command = bb_xstrdup(argv[optind]);
optind++;
argv = argv+optind;
break;
interactive = TRUE;
break;
default:
- show_usage();
+ bb_show_usage();
}
}
/* A shell is interactive if the `-i' flag was given, or if all of
* standard output is a terminal
* Refer to Posix.2, the description of the `sh' utility. */
if (argv[optind]==NULL && input==stdin &&
- isatty(fileno(stdin)) && isatty(fileno(stdout))) {
+ isatty(STDIN_FILENO) && isatty(STDOUT_FILENO)) {
interactive=TRUE;
}
setup_job_control();
if (interactive==TRUE) {
//printf( "optind=%d argv[optind]='%s'\n", optind, argv[optind]);
/* Looks like they want an interactive shell */
+#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
printf( "\n\n" BB_BANNER " Built-in shell (lash)\n");
printf( "Enter 'help' for a list of built-in commands.\n\n");
+#endif
} else if (local_pending_command==NULL) {
//printf( "optind=%d argv[optind]='%s'\n", optind, argv[optind]);
- input = xfopen(argv[optind], "r");
+ input = bb_xfopen(argv[optind], "r");
mark_open(fileno(input)); /* be lazy, never mark this closed */
}
/* initialize the cwd -- this is never freed...*/
cwd = xgetcwd(0);
if (!cwd)
- cwd = unknown;
+ cwd = bb_msg_unknown;
-#ifdef BB_FEATURE_CLEAN_UP
+#ifdef CONFIG_FEATURE_CLEAN_UP
atexit(free_memory);
#endif
-#ifdef BB_FEATURE_COMMAND_EDITING
+#ifdef CONFIG_FEATURE_COMMAND_EDITING
cmdedit_set_initial_prompt();
#else
PS1 = NULL;
#endif
-
+
return (busy_loop(input));
}