Finish off fixing up the memleaks (I think). Added the beginnings of
some if-then-else-fi support (nonfunctional and turned off) -Erik
This commit is contained in:
parent
b040d4f3da
commit
fad9c1198a
161
lash.c
161
lash.c
@ -27,6 +27,7 @@
|
|||||||
|
|
||||||
|
|
||||||
#define BB_FEATURE_SH_BACKTICKS
|
#define BB_FEATURE_SH_BACKTICKS
|
||||||
|
//#define BB_FEATURE_SH_IF_EXPRESSIONS
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -55,6 +56,14 @@ enum redirectionType { REDIRECT_INPUT, REDIRECT_OVERWRITE,
|
|||||||
REDIRECT_APPEND
|
REDIRECT_APPEND
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define REGULAR_JOB_CONTEXT 0x1
|
||||||
|
#define IF_EXP_CONTEXT 0x2
|
||||||
|
#define THEN_EXP_CONTEXT 0x4
|
||||||
|
#define ELSE_EXP_CONTEXT 0x8
|
||||||
|
|
||||||
|
enum jobContext { REGULAR_APP, IF_CONTEXT, THEN_CONTEXT
|
||||||
|
};
|
||||||
|
|
||||||
struct jobSet {
|
struct jobSet {
|
||||||
struct job *head; /* head of list of running jobs */
|
struct job *head; /* head of list of running jobs */
|
||||||
struct job *fg; /* current foreground job */
|
struct job *fg; /* current foreground job */
|
||||||
@ -86,12 +95,12 @@ struct job {
|
|||||||
struct childProgram *progs; /* array of programs in job */
|
struct childProgram *progs; /* array of programs in job */
|
||||||
struct job *next; /* to track background commands */
|
struct job *next; /* to track background commands */
|
||||||
int stoppedProgs; /* number of programs alive, but stopped */
|
int stoppedProgs; /* number of programs alive, but stopped */
|
||||||
|
int jobContext; /* bitmask defining current context */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct builtInCommand {
|
struct builtInCommand {
|
||||||
char *cmd; /* name */
|
char *cmd; /* name */
|
||||||
char *descr; /* description */
|
char *descr; /* description */
|
||||||
char *usage; /* usage */
|
|
||||||
int (*function) (struct job *, struct jobSet * jobList); /* function ptr */
|
int (*function) (struct job *, struct jobSet * jobList); /* function ptr */
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -107,6 +116,12 @@ static int builtin_export(struct job *cmd, struct jobSet *junk);
|
|||||||
static int builtin_source(struct job *cmd, struct jobSet *jobList);
|
static int builtin_source(struct job *cmd, struct jobSet *jobList);
|
||||||
static int builtin_unset(struct job *cmd, struct jobSet *junk);
|
static int builtin_unset(struct job *cmd, struct jobSet *junk);
|
||||||
static int builtin_read(struct job *cmd, struct jobSet *junk);
|
static int builtin_read(struct job *cmd, struct jobSet *junk);
|
||||||
|
#ifdef BB_FEATURE_SH_IF_EXPRESSIONS
|
||||||
|
static int builtin_if(struct job *cmd, struct jobSet *junk);
|
||||||
|
static int builtin_then(struct job *cmd, struct jobSet *junk);
|
||||||
|
static int builtin_else(struct job *cmd, struct jobSet *junk);
|
||||||
|
static int builtin_fi(struct job *cmd, struct jobSet *junk);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/* function prototypes for shell stuff */
|
/* function prototypes for shell stuff */
|
||||||
@ -122,30 +137,38 @@ static int busy_loop(FILE * input);
|
|||||||
* can change global variables in the parent shell process but they will not
|
* can change global variables in the parent shell process but they will not
|
||||||
* work with pipes and redirects; 'unset foo | whatever' will not work) */
|
* work with pipes and redirects; 'unset foo | whatever' will not work) */
|
||||||
static struct builtInCommand bltins[] = {
|
static struct builtInCommand bltins[] = {
|
||||||
{"bg", "Resume a job in the background", "bg [%%job]", builtin_fg_bg},
|
{"bg", "Resume a job in the background", builtin_fg_bg},
|
||||||
{"cd", "Change working directory", "cd [dir]", builtin_cd},
|
{"cd", "Change working directory", builtin_cd},
|
||||||
{"exit", "Exit from shell()", "exit", builtin_exit},
|
{"exit", "Exit from shell()", builtin_exit},
|
||||||
{"fg", "Bring job into the foreground", "fg [%%job]", builtin_fg_bg},
|
{"fg", "Bring job into the foreground", builtin_fg_bg},
|
||||||
{"jobs", "Lists the active jobs", "jobs", builtin_jobs},
|
{"jobs", "Lists the active jobs", builtin_jobs},
|
||||||
{"export", "Set environment variable", "export [VAR=value]", builtin_export},
|
{"export", "Set environment variable", builtin_export},
|
||||||
{"unset", "Unset environment variable", "unset VAR", builtin_unset},
|
{"unset", "Unset environment variable", builtin_unset},
|
||||||
{"read", "Input environment variable", "read [VAR]", builtin_read},
|
{"read", "Input environment variable", builtin_read},
|
||||||
{NULL, NULL, NULL, NULL}
|
{NULL, NULL, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Table of forking built-in functions (things that fork cannot change global
|
/* Table of forking built-in functions (things that fork cannot change global
|
||||||
* variables in the parent process, such as the current working directory) */
|
* variables in the parent process, such as the current working directory) */
|
||||||
static struct builtInCommand bltins_forking[] = {
|
static struct builtInCommand bltins_forking[] = {
|
||||||
{"env", "Print all environment variables", "env", builtin_env},
|
{"env", "Print all environment variables", builtin_env},
|
||||||
{"pwd", "Print current directory", "pwd", builtin_pwd},
|
{"pwd", "Print current directory", builtin_pwd},
|
||||||
{".", "Source-in and run commands in a file", ". filename", builtin_source},
|
#ifdef BB_FEATURE_SH_IF_EXPRESSIONS
|
||||||
{"help", "List shell built-in commands", "help", builtin_help},
|
{"if", NULL, builtin_if},
|
||||||
{NULL, NULL, NULL, NULL}
|
{"then", NULL, builtin_then},
|
||||||
|
{"else", NULL, builtin_else},
|
||||||
|
{"fi", NULL, builtin_fi},
|
||||||
|
#endif
|
||||||
|
{".", "Source-in and run commands in a file", builtin_source},
|
||||||
|
{"help", "List shell built-in commands", builtin_help},
|
||||||
|
{NULL, NULL, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
static char *prompt = "# ";
|
static char *prompt = "# ";
|
||||||
static char *cwd;
|
static char *cwd;
|
||||||
static char *local_pending_command = NULL;
|
static char *local_pending_command = NULL;
|
||||||
|
static char *promptStr = NULL;
|
||||||
|
static struct jobSet jobList = { NULL, NULL };
|
||||||
|
|
||||||
#ifdef BB_FEATURE_SH_COMMAND_EDITING
|
#ifdef BB_FEATURE_SH_COMMAND_EDITING
|
||||||
void win_changed(int junk)
|
void win_changed(int junk)
|
||||||
@ -256,9 +279,13 @@ static int builtin_help(struct job *dummy, struct jobSet *junk)
|
|||||||
fprintf(stdout, "\nBuilt-in commands:\n");
|
fprintf(stdout, "\nBuilt-in commands:\n");
|
||||||
fprintf(stdout, "-------------------\n");
|
fprintf(stdout, "-------------------\n");
|
||||||
for (x = bltins; x->cmd; x++) {
|
for (x = bltins; x->cmd; x++) {
|
||||||
|
if (x->descr==NULL)
|
||||||
|
continue;
|
||||||
fprintf(stdout, "%s\t%s\n", x->cmd, x->descr);
|
fprintf(stdout, "%s\t%s\n", x->cmd, x->descr);
|
||||||
}
|
}
|
||||||
for (x = bltins_forking; x->cmd; x++) {
|
for (x = bltins_forking; x->cmd; x++) {
|
||||||
|
if (x->descr==NULL)
|
||||||
|
continue;
|
||||||
fprintf(stdout, "%s\t%s\n", x->cmd, x->descr);
|
fprintf(stdout, "%s\t%s\n", x->cmd, x->descr);
|
||||||
}
|
}
|
||||||
fprintf(stdout, "\n\n");
|
fprintf(stdout, "\n\n");
|
||||||
@ -339,6 +366,44 @@ static int builtin_read(struct job *cmd, struct jobSet *junk)
|
|||||||
return (res);
|
return (res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef BB_FEATURE_SH_IF_EXPRESSIONS
|
||||||
|
/* Built-in handler for 'if' commands */
|
||||||
|
static int builtin_if(struct job *cmd, struct jobSet *junk)
|
||||||
|
{
|
||||||
|
cmd->jobContext |= IF_EXP_CONTEXT;
|
||||||
|
printf("Hit an if -- jobContext=%d\n", cmd->jobContext);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Built-in handler for 'then' (part of the 'if' command) */
|
||||||
|
static int builtin_then(struct job *cmd, struct jobSet *junk)
|
||||||
|
{
|
||||||
|
if (cmd->jobContext & IF_EXP_CONTEXT) {
|
||||||
|
fprintf(stderr, "unexpected token `then'\n");
|
||||||
|
fflush(stderr);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
cmd->jobContext |= THEN_EXP_CONTEXT;
|
||||||
|
printf("Hit an then -- jobContext=%d\n", cmd->jobContext);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Built-in handler for 'else' (part of the 'if' command) */
|
||||||
|
static int builtin_else(struct job *cmd, struct jobSet *junk)
|
||||||
|
{
|
||||||
|
printf("Hit an else\n");
|
||||||
|
cmd->jobContext |= ELSE_EXP_CONTEXT;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Built-in handler for 'fi' (part of the 'if' command) */
|
||||||
|
static int builtin_fi(struct job *cmd, struct jobSet *junk)
|
||||||
|
{
|
||||||
|
printf("Hit an fi\n");
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Built-in '.' handler (read-in and execute commands from file) */
|
/* Built-in '.' handler (read-in and execute commands from file) */
|
||||||
static int builtin_source(struct job *cmd, struct jobSet *junk)
|
static int builtin_source(struct job *cmd, struct jobSet *junk)
|
||||||
{
|
{
|
||||||
@ -471,7 +536,6 @@ static int getCommand(FILE * source, char *command)
|
|||||||
if (source == stdin) {
|
if (source == stdin) {
|
||||||
#ifdef BB_FEATURE_SH_COMMAND_EDITING
|
#ifdef BB_FEATURE_SH_COMMAND_EDITING
|
||||||
int len;
|
int len;
|
||||||
char *promptStr;
|
|
||||||
len=fprintf(stdout, "%s %s", cwd, prompt);
|
len=fprintf(stdout, "%s %s", cwd, prompt);
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
promptStr=(char*)xmalloc(sizeof(char)*(len+1));
|
promptStr=(char*)xmalloc(sizeof(char)*(len+1));
|
||||||
@ -587,8 +651,9 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
|
|||||||
Getting clean memory relieves us of the task of NULL
|
Getting clean memory relieves us of the task of NULL
|
||||||
terminating things and makes the rest of this look a bit
|
terminating things and makes the rest of this look a bit
|
||||||
cleaner (though it is, admittedly, a tad less efficient) */
|
cleaner (though it is, admittedly, a tad less efficient) */
|
||||||
job->cmdBuf = command = calloc(1, 2*strlen(*commandPtr) + 1);
|
job->cmdBuf = command = calloc(2*strlen(*commandPtr) + 1, sizeof(char));
|
||||||
job->text = NULL;
|
job->text = NULL;
|
||||||
|
job->jobContext = REGULAR_JOB_CONTEXT;
|
||||||
|
|
||||||
prog = job->progs;
|
prog = job->progs;
|
||||||
prog->numRedirections = 0;
|
prog->numRedirections = 0;
|
||||||
@ -863,7 +928,7 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
|
|||||||
|
|
||||||
static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg, int outPipe[2])
|
static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg, int outPipe[2])
|
||||||
{
|
{
|
||||||
struct job *job;
|
struct job *theJob;
|
||||||
int i;
|
int i;
|
||||||
int nextin, nextout;
|
int nextin, nextout;
|
||||||
int pipefds[2]; /* pipefd[0] is for reading */
|
int pipefds[2]; /* pipefd[0] is for reading */
|
||||||
@ -957,33 +1022,33 @@ static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg, int
|
|||||||
|
|
||||||
newJob->pgrp = newJob->progs[0].pid;
|
newJob->pgrp = newJob->progs[0].pid;
|
||||||
|
|
||||||
/* find the ID for the job to use */
|
/* find the ID for the theJob to use */
|
||||||
newJob->jobId = 1;
|
newJob->jobId = 1;
|
||||||
for (job = jobList->head; job; job = job->next)
|
for (theJob = jobList->head; theJob; theJob = theJob->next)
|
||||||
if (job->jobId >= newJob->jobId)
|
if (theJob->jobId >= newJob->jobId)
|
||||||
newJob->jobId = job->jobId + 1;
|
newJob->jobId = theJob->jobId + 1;
|
||||||
|
|
||||||
/* add the job to the list of running jobs */
|
/* add the theJob to the list of running jobs */
|
||||||
if (!jobList->head) {
|
if (!jobList->head) {
|
||||||
job = jobList->head = malloc(sizeof(*job));
|
theJob = jobList->head = malloc(sizeof(*theJob));
|
||||||
} else {
|
} else {
|
||||||
for (job = jobList->head; job->next; job = job->next);
|
for (theJob = jobList->head; theJob->next; theJob = theJob->next);
|
||||||
job->next = malloc(sizeof(*job));
|
theJob->next = malloc(sizeof(*theJob));
|
||||||
job = job->next;
|
theJob = theJob->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
*job = *newJob;
|
*theJob = *newJob;
|
||||||
job->next = NULL;
|
theJob->next = NULL;
|
||||||
job->runningProgs = job->numProgs;
|
theJob->runningProgs = theJob->numProgs;
|
||||||
job->stoppedProgs = 0;
|
theJob->stoppedProgs = 0;
|
||||||
|
|
||||||
if (inBg) {
|
if (inBg) {
|
||||||
/* we don't wait for background jobs to return -- append it
|
/* we don't wait for background theJobs to return -- append it
|
||||||
to the list of backgrounded jobs and leave it alone */
|
to the list of backgrounded theJobs and leave it alone */
|
||||||
printf("[%d] %d\n", job->jobId,
|
printf("[%d] %d\n", theJob->jobId,
|
||||||
newJob->progs[newJob->numProgs - 1].pid);
|
newJob->progs[newJob->numProgs - 1].pid);
|
||||||
} else {
|
} else {
|
||||||
jobList->fg = job;
|
jobList->fg = theJob;
|
||||||
|
|
||||||
/* move the new process group into the foreground */
|
/* move the new process group into the foreground */
|
||||||
/* suppress messages when run from /linuxrc mag@sysgo.de */
|
/* suppress messages when run from /linuxrc mag@sysgo.de */
|
||||||
@ -1037,7 +1102,6 @@ static int busy_loop(FILE * input)
|
|||||||
{
|
{
|
||||||
char *command;
|
char *command;
|
||||||
char *nextCommand = NULL;
|
char *nextCommand = NULL;
|
||||||
struct jobSet jobList = { NULL, NULL };
|
|
||||||
struct job newJob;
|
struct job newJob;
|
||||||
pid_t parent_pgrp;
|
pid_t parent_pgrp;
|
||||||
int i;
|
int i;
|
||||||
@ -1070,7 +1134,8 @@ static int busy_loop(FILE * input)
|
|||||||
newJob.numProgs) {
|
newJob.numProgs) {
|
||||||
int pipefds[2] = {-1,-1};
|
int pipefds[2] = {-1,-1};
|
||||||
runCommand(&newJob, &jobList, inBg, pipefds);
|
runCommand(&newJob, &jobList, inBg, pipefds);
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
free(command);
|
free(command);
|
||||||
command = (char *) calloc(BUFSIZ, sizeof(char));
|
command = (char *) calloc(BUFSIZ, sizeof(char));
|
||||||
nextCommand = NULL;
|
nextCommand = NULL;
|
||||||
@ -1079,7 +1144,7 @@ static int busy_loop(FILE * input)
|
|||||||
/* a job is running in the foreground; wait for it */
|
/* a job is running in the foreground; wait for it */
|
||||||
i = 0;
|
i = 0;
|
||||||
while (!jobList.fg->progs[i].pid ||
|
while (!jobList.fg->progs[i].pid ||
|
||||||
jobList.fg->progs[i].isStopped) i++;
|
jobList.fg->progs[i].isStopped == 1) i++;
|
||||||
|
|
||||||
waitpid(jobList.fg->progs[i].pid, &status, WUNTRACED);
|
waitpid(jobList.fg->progs[i].pid, &status, WUNTRACED);
|
||||||
|
|
||||||
@ -1128,6 +1193,22 @@ static int busy_loop(FILE * input)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef BB_FEATURE_CLEAN_UP
|
||||||
|
void free_memory(void)
|
||||||
|
{
|
||||||
|
if (promptStr)
|
||||||
|
free(promptStr);
|
||||||
|
if (cwd)
|
||||||
|
free(cwd);
|
||||||
|
if (local_pending_command)
|
||||||
|
free(local_pending_command);
|
||||||
|
|
||||||
|
if (jobList.fg && !jobList.fg->runningProgs) {
|
||||||
|
removeJob(&jobList, jobList.fg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
int shell_main(int argc, char **argv)
|
int shell_main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
@ -1137,6 +1218,10 @@ int shell_main(int argc, char **argv)
|
|||||||
cwd=(char*)xmalloc(sizeof(char)*MAX_LINE+1);
|
cwd=(char*)xmalloc(sizeof(char)*MAX_LINE+1);
|
||||||
getcwd(cwd, sizeof(char)*MAX_LINE);
|
getcwd(cwd, sizeof(char)*MAX_LINE);
|
||||||
|
|
||||||
|
#ifdef BB_FEATURE_CLEAN_UP
|
||||||
|
atexit(free_memory);
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef BB_FEATURE_SH_COMMAND_EDITING
|
#ifdef BB_FEATURE_SH_COMMAND_EDITING
|
||||||
cmdedit_init();
|
cmdedit_init();
|
||||||
signal(SIGWINCH, win_changed);
|
signal(SIGWINCH, win_changed);
|
||||||
|
161
sh.c
161
sh.c
@ -27,6 +27,7 @@
|
|||||||
|
|
||||||
|
|
||||||
#define BB_FEATURE_SH_BACKTICKS
|
#define BB_FEATURE_SH_BACKTICKS
|
||||||
|
//#define BB_FEATURE_SH_IF_EXPRESSIONS
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -55,6 +56,14 @@ enum redirectionType { REDIRECT_INPUT, REDIRECT_OVERWRITE,
|
|||||||
REDIRECT_APPEND
|
REDIRECT_APPEND
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define REGULAR_JOB_CONTEXT 0x1
|
||||||
|
#define IF_EXP_CONTEXT 0x2
|
||||||
|
#define THEN_EXP_CONTEXT 0x4
|
||||||
|
#define ELSE_EXP_CONTEXT 0x8
|
||||||
|
|
||||||
|
enum jobContext { REGULAR_APP, IF_CONTEXT, THEN_CONTEXT
|
||||||
|
};
|
||||||
|
|
||||||
struct jobSet {
|
struct jobSet {
|
||||||
struct job *head; /* head of list of running jobs */
|
struct job *head; /* head of list of running jobs */
|
||||||
struct job *fg; /* current foreground job */
|
struct job *fg; /* current foreground job */
|
||||||
@ -86,12 +95,12 @@ struct job {
|
|||||||
struct childProgram *progs; /* array of programs in job */
|
struct childProgram *progs; /* array of programs in job */
|
||||||
struct job *next; /* to track background commands */
|
struct job *next; /* to track background commands */
|
||||||
int stoppedProgs; /* number of programs alive, but stopped */
|
int stoppedProgs; /* number of programs alive, but stopped */
|
||||||
|
int jobContext; /* bitmask defining current context */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct builtInCommand {
|
struct builtInCommand {
|
||||||
char *cmd; /* name */
|
char *cmd; /* name */
|
||||||
char *descr; /* description */
|
char *descr; /* description */
|
||||||
char *usage; /* usage */
|
|
||||||
int (*function) (struct job *, struct jobSet * jobList); /* function ptr */
|
int (*function) (struct job *, struct jobSet * jobList); /* function ptr */
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -107,6 +116,12 @@ static int builtin_export(struct job *cmd, struct jobSet *junk);
|
|||||||
static int builtin_source(struct job *cmd, struct jobSet *jobList);
|
static int builtin_source(struct job *cmd, struct jobSet *jobList);
|
||||||
static int builtin_unset(struct job *cmd, struct jobSet *junk);
|
static int builtin_unset(struct job *cmd, struct jobSet *junk);
|
||||||
static int builtin_read(struct job *cmd, struct jobSet *junk);
|
static int builtin_read(struct job *cmd, struct jobSet *junk);
|
||||||
|
#ifdef BB_FEATURE_SH_IF_EXPRESSIONS
|
||||||
|
static int builtin_if(struct job *cmd, struct jobSet *junk);
|
||||||
|
static int builtin_then(struct job *cmd, struct jobSet *junk);
|
||||||
|
static int builtin_else(struct job *cmd, struct jobSet *junk);
|
||||||
|
static int builtin_fi(struct job *cmd, struct jobSet *junk);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/* function prototypes for shell stuff */
|
/* function prototypes for shell stuff */
|
||||||
@ -122,30 +137,38 @@ static int busy_loop(FILE * input);
|
|||||||
* can change global variables in the parent shell process but they will not
|
* can change global variables in the parent shell process but they will not
|
||||||
* work with pipes and redirects; 'unset foo | whatever' will not work) */
|
* work with pipes and redirects; 'unset foo | whatever' will not work) */
|
||||||
static struct builtInCommand bltins[] = {
|
static struct builtInCommand bltins[] = {
|
||||||
{"bg", "Resume a job in the background", "bg [%%job]", builtin_fg_bg},
|
{"bg", "Resume a job in the background", builtin_fg_bg},
|
||||||
{"cd", "Change working directory", "cd [dir]", builtin_cd},
|
{"cd", "Change working directory", builtin_cd},
|
||||||
{"exit", "Exit from shell()", "exit", builtin_exit},
|
{"exit", "Exit from shell()", builtin_exit},
|
||||||
{"fg", "Bring job into the foreground", "fg [%%job]", builtin_fg_bg},
|
{"fg", "Bring job into the foreground", builtin_fg_bg},
|
||||||
{"jobs", "Lists the active jobs", "jobs", builtin_jobs},
|
{"jobs", "Lists the active jobs", builtin_jobs},
|
||||||
{"export", "Set environment variable", "export [VAR=value]", builtin_export},
|
{"export", "Set environment variable", builtin_export},
|
||||||
{"unset", "Unset environment variable", "unset VAR", builtin_unset},
|
{"unset", "Unset environment variable", builtin_unset},
|
||||||
{"read", "Input environment variable", "read [VAR]", builtin_read},
|
{"read", "Input environment variable", builtin_read},
|
||||||
{NULL, NULL, NULL, NULL}
|
{NULL, NULL, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Table of forking built-in functions (things that fork cannot change global
|
/* Table of forking built-in functions (things that fork cannot change global
|
||||||
* variables in the parent process, such as the current working directory) */
|
* variables in the parent process, such as the current working directory) */
|
||||||
static struct builtInCommand bltins_forking[] = {
|
static struct builtInCommand bltins_forking[] = {
|
||||||
{"env", "Print all environment variables", "env", builtin_env},
|
{"env", "Print all environment variables", builtin_env},
|
||||||
{"pwd", "Print current directory", "pwd", builtin_pwd},
|
{"pwd", "Print current directory", builtin_pwd},
|
||||||
{".", "Source-in and run commands in a file", ". filename", builtin_source},
|
#ifdef BB_FEATURE_SH_IF_EXPRESSIONS
|
||||||
{"help", "List shell built-in commands", "help", builtin_help},
|
{"if", NULL, builtin_if},
|
||||||
{NULL, NULL, NULL, NULL}
|
{"then", NULL, builtin_then},
|
||||||
|
{"else", NULL, builtin_else},
|
||||||
|
{"fi", NULL, builtin_fi},
|
||||||
|
#endif
|
||||||
|
{".", "Source-in and run commands in a file", builtin_source},
|
||||||
|
{"help", "List shell built-in commands", builtin_help},
|
||||||
|
{NULL, NULL, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
static char *prompt = "# ";
|
static char *prompt = "# ";
|
||||||
static char *cwd;
|
static char *cwd;
|
||||||
static char *local_pending_command = NULL;
|
static char *local_pending_command = NULL;
|
||||||
|
static char *promptStr = NULL;
|
||||||
|
static struct jobSet jobList = { NULL, NULL };
|
||||||
|
|
||||||
#ifdef BB_FEATURE_SH_COMMAND_EDITING
|
#ifdef BB_FEATURE_SH_COMMAND_EDITING
|
||||||
void win_changed(int junk)
|
void win_changed(int junk)
|
||||||
@ -256,9 +279,13 @@ static int builtin_help(struct job *dummy, struct jobSet *junk)
|
|||||||
fprintf(stdout, "\nBuilt-in commands:\n");
|
fprintf(stdout, "\nBuilt-in commands:\n");
|
||||||
fprintf(stdout, "-------------------\n");
|
fprintf(stdout, "-------------------\n");
|
||||||
for (x = bltins; x->cmd; x++) {
|
for (x = bltins; x->cmd; x++) {
|
||||||
|
if (x->descr==NULL)
|
||||||
|
continue;
|
||||||
fprintf(stdout, "%s\t%s\n", x->cmd, x->descr);
|
fprintf(stdout, "%s\t%s\n", x->cmd, x->descr);
|
||||||
}
|
}
|
||||||
for (x = bltins_forking; x->cmd; x++) {
|
for (x = bltins_forking; x->cmd; x++) {
|
||||||
|
if (x->descr==NULL)
|
||||||
|
continue;
|
||||||
fprintf(stdout, "%s\t%s\n", x->cmd, x->descr);
|
fprintf(stdout, "%s\t%s\n", x->cmd, x->descr);
|
||||||
}
|
}
|
||||||
fprintf(stdout, "\n\n");
|
fprintf(stdout, "\n\n");
|
||||||
@ -339,6 +366,44 @@ static int builtin_read(struct job *cmd, struct jobSet *junk)
|
|||||||
return (res);
|
return (res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef BB_FEATURE_SH_IF_EXPRESSIONS
|
||||||
|
/* Built-in handler for 'if' commands */
|
||||||
|
static int builtin_if(struct job *cmd, struct jobSet *junk)
|
||||||
|
{
|
||||||
|
cmd->jobContext |= IF_EXP_CONTEXT;
|
||||||
|
printf("Hit an if -- jobContext=%d\n", cmd->jobContext);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Built-in handler for 'then' (part of the 'if' command) */
|
||||||
|
static int builtin_then(struct job *cmd, struct jobSet *junk)
|
||||||
|
{
|
||||||
|
if (cmd->jobContext & IF_EXP_CONTEXT) {
|
||||||
|
fprintf(stderr, "unexpected token `then'\n");
|
||||||
|
fflush(stderr);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
cmd->jobContext |= THEN_EXP_CONTEXT;
|
||||||
|
printf("Hit an then -- jobContext=%d\n", cmd->jobContext);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Built-in handler for 'else' (part of the 'if' command) */
|
||||||
|
static int builtin_else(struct job *cmd, struct jobSet *junk)
|
||||||
|
{
|
||||||
|
printf("Hit an else\n");
|
||||||
|
cmd->jobContext |= ELSE_EXP_CONTEXT;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Built-in handler for 'fi' (part of the 'if' command) */
|
||||||
|
static int builtin_fi(struct job *cmd, struct jobSet *junk)
|
||||||
|
{
|
||||||
|
printf("Hit an fi\n");
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Built-in '.' handler (read-in and execute commands from file) */
|
/* Built-in '.' handler (read-in and execute commands from file) */
|
||||||
static int builtin_source(struct job *cmd, struct jobSet *junk)
|
static int builtin_source(struct job *cmd, struct jobSet *junk)
|
||||||
{
|
{
|
||||||
@ -471,7 +536,6 @@ static int getCommand(FILE * source, char *command)
|
|||||||
if (source == stdin) {
|
if (source == stdin) {
|
||||||
#ifdef BB_FEATURE_SH_COMMAND_EDITING
|
#ifdef BB_FEATURE_SH_COMMAND_EDITING
|
||||||
int len;
|
int len;
|
||||||
char *promptStr;
|
|
||||||
len=fprintf(stdout, "%s %s", cwd, prompt);
|
len=fprintf(stdout, "%s %s", cwd, prompt);
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
promptStr=(char*)xmalloc(sizeof(char)*(len+1));
|
promptStr=(char*)xmalloc(sizeof(char)*(len+1));
|
||||||
@ -587,8 +651,9 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
|
|||||||
Getting clean memory relieves us of the task of NULL
|
Getting clean memory relieves us of the task of NULL
|
||||||
terminating things and makes the rest of this look a bit
|
terminating things and makes the rest of this look a bit
|
||||||
cleaner (though it is, admittedly, a tad less efficient) */
|
cleaner (though it is, admittedly, a tad less efficient) */
|
||||||
job->cmdBuf = command = calloc(1, 2*strlen(*commandPtr) + 1);
|
job->cmdBuf = command = calloc(2*strlen(*commandPtr) + 1, sizeof(char));
|
||||||
job->text = NULL;
|
job->text = NULL;
|
||||||
|
job->jobContext = REGULAR_JOB_CONTEXT;
|
||||||
|
|
||||||
prog = job->progs;
|
prog = job->progs;
|
||||||
prog->numRedirections = 0;
|
prog->numRedirections = 0;
|
||||||
@ -863,7 +928,7 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
|
|||||||
|
|
||||||
static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg, int outPipe[2])
|
static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg, int outPipe[2])
|
||||||
{
|
{
|
||||||
struct job *job;
|
struct job *theJob;
|
||||||
int i;
|
int i;
|
||||||
int nextin, nextout;
|
int nextin, nextout;
|
||||||
int pipefds[2]; /* pipefd[0] is for reading */
|
int pipefds[2]; /* pipefd[0] is for reading */
|
||||||
@ -957,33 +1022,33 @@ static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg, int
|
|||||||
|
|
||||||
newJob->pgrp = newJob->progs[0].pid;
|
newJob->pgrp = newJob->progs[0].pid;
|
||||||
|
|
||||||
/* find the ID for the job to use */
|
/* find the ID for the theJob to use */
|
||||||
newJob->jobId = 1;
|
newJob->jobId = 1;
|
||||||
for (job = jobList->head; job; job = job->next)
|
for (theJob = jobList->head; theJob; theJob = theJob->next)
|
||||||
if (job->jobId >= newJob->jobId)
|
if (theJob->jobId >= newJob->jobId)
|
||||||
newJob->jobId = job->jobId + 1;
|
newJob->jobId = theJob->jobId + 1;
|
||||||
|
|
||||||
/* add the job to the list of running jobs */
|
/* add the theJob to the list of running jobs */
|
||||||
if (!jobList->head) {
|
if (!jobList->head) {
|
||||||
job = jobList->head = malloc(sizeof(*job));
|
theJob = jobList->head = malloc(sizeof(*theJob));
|
||||||
} else {
|
} else {
|
||||||
for (job = jobList->head; job->next; job = job->next);
|
for (theJob = jobList->head; theJob->next; theJob = theJob->next);
|
||||||
job->next = malloc(sizeof(*job));
|
theJob->next = malloc(sizeof(*theJob));
|
||||||
job = job->next;
|
theJob = theJob->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
*job = *newJob;
|
*theJob = *newJob;
|
||||||
job->next = NULL;
|
theJob->next = NULL;
|
||||||
job->runningProgs = job->numProgs;
|
theJob->runningProgs = theJob->numProgs;
|
||||||
job->stoppedProgs = 0;
|
theJob->stoppedProgs = 0;
|
||||||
|
|
||||||
if (inBg) {
|
if (inBg) {
|
||||||
/* we don't wait for background jobs to return -- append it
|
/* we don't wait for background theJobs to return -- append it
|
||||||
to the list of backgrounded jobs and leave it alone */
|
to the list of backgrounded theJobs and leave it alone */
|
||||||
printf("[%d] %d\n", job->jobId,
|
printf("[%d] %d\n", theJob->jobId,
|
||||||
newJob->progs[newJob->numProgs - 1].pid);
|
newJob->progs[newJob->numProgs - 1].pid);
|
||||||
} else {
|
} else {
|
||||||
jobList->fg = job;
|
jobList->fg = theJob;
|
||||||
|
|
||||||
/* move the new process group into the foreground */
|
/* move the new process group into the foreground */
|
||||||
/* suppress messages when run from /linuxrc mag@sysgo.de */
|
/* suppress messages when run from /linuxrc mag@sysgo.de */
|
||||||
@ -1037,7 +1102,6 @@ static int busy_loop(FILE * input)
|
|||||||
{
|
{
|
||||||
char *command;
|
char *command;
|
||||||
char *nextCommand = NULL;
|
char *nextCommand = NULL;
|
||||||
struct jobSet jobList = { NULL, NULL };
|
|
||||||
struct job newJob;
|
struct job newJob;
|
||||||
pid_t parent_pgrp;
|
pid_t parent_pgrp;
|
||||||
int i;
|
int i;
|
||||||
@ -1070,7 +1134,8 @@ static int busy_loop(FILE * input)
|
|||||||
newJob.numProgs) {
|
newJob.numProgs) {
|
||||||
int pipefds[2] = {-1,-1};
|
int pipefds[2] = {-1,-1};
|
||||||
runCommand(&newJob, &jobList, inBg, pipefds);
|
runCommand(&newJob, &jobList, inBg, pipefds);
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
free(command);
|
free(command);
|
||||||
command = (char *) calloc(BUFSIZ, sizeof(char));
|
command = (char *) calloc(BUFSIZ, sizeof(char));
|
||||||
nextCommand = NULL;
|
nextCommand = NULL;
|
||||||
@ -1079,7 +1144,7 @@ static int busy_loop(FILE * input)
|
|||||||
/* a job is running in the foreground; wait for it */
|
/* a job is running in the foreground; wait for it */
|
||||||
i = 0;
|
i = 0;
|
||||||
while (!jobList.fg->progs[i].pid ||
|
while (!jobList.fg->progs[i].pid ||
|
||||||
jobList.fg->progs[i].isStopped) i++;
|
jobList.fg->progs[i].isStopped == 1) i++;
|
||||||
|
|
||||||
waitpid(jobList.fg->progs[i].pid, &status, WUNTRACED);
|
waitpid(jobList.fg->progs[i].pid, &status, WUNTRACED);
|
||||||
|
|
||||||
@ -1128,6 +1193,22 @@ static int busy_loop(FILE * input)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef BB_FEATURE_CLEAN_UP
|
||||||
|
void free_memory(void)
|
||||||
|
{
|
||||||
|
if (promptStr)
|
||||||
|
free(promptStr);
|
||||||
|
if (cwd)
|
||||||
|
free(cwd);
|
||||||
|
if (local_pending_command)
|
||||||
|
free(local_pending_command);
|
||||||
|
|
||||||
|
if (jobList.fg && !jobList.fg->runningProgs) {
|
||||||
|
removeJob(&jobList, jobList.fg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
int shell_main(int argc, char **argv)
|
int shell_main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
@ -1137,6 +1218,10 @@ int shell_main(int argc, char **argv)
|
|||||||
cwd=(char*)xmalloc(sizeof(char)*MAX_LINE+1);
|
cwd=(char*)xmalloc(sizeof(char)*MAX_LINE+1);
|
||||||
getcwd(cwd, sizeof(char)*MAX_LINE);
|
getcwd(cwd, sizeof(char)*MAX_LINE);
|
||||||
|
|
||||||
|
#ifdef BB_FEATURE_CLEAN_UP
|
||||||
|
atexit(free_memory);
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef BB_FEATURE_SH_COMMAND_EDITING
|
#ifdef BB_FEATURE_SH_COMMAND_EDITING
|
||||||
cmdedit_init();
|
cmdedit_init();
|
||||||
signal(SIGWINCH, win_changed);
|
signal(SIGWINCH, win_changed);
|
||||||
|
161
shell/lash.c
161
shell/lash.c
@ -27,6 +27,7 @@
|
|||||||
|
|
||||||
|
|
||||||
#define BB_FEATURE_SH_BACKTICKS
|
#define BB_FEATURE_SH_BACKTICKS
|
||||||
|
//#define BB_FEATURE_SH_IF_EXPRESSIONS
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -55,6 +56,14 @@ enum redirectionType { REDIRECT_INPUT, REDIRECT_OVERWRITE,
|
|||||||
REDIRECT_APPEND
|
REDIRECT_APPEND
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define REGULAR_JOB_CONTEXT 0x1
|
||||||
|
#define IF_EXP_CONTEXT 0x2
|
||||||
|
#define THEN_EXP_CONTEXT 0x4
|
||||||
|
#define ELSE_EXP_CONTEXT 0x8
|
||||||
|
|
||||||
|
enum jobContext { REGULAR_APP, IF_CONTEXT, THEN_CONTEXT
|
||||||
|
};
|
||||||
|
|
||||||
struct jobSet {
|
struct jobSet {
|
||||||
struct job *head; /* head of list of running jobs */
|
struct job *head; /* head of list of running jobs */
|
||||||
struct job *fg; /* current foreground job */
|
struct job *fg; /* current foreground job */
|
||||||
@ -86,12 +95,12 @@ struct job {
|
|||||||
struct childProgram *progs; /* array of programs in job */
|
struct childProgram *progs; /* array of programs in job */
|
||||||
struct job *next; /* to track background commands */
|
struct job *next; /* to track background commands */
|
||||||
int stoppedProgs; /* number of programs alive, but stopped */
|
int stoppedProgs; /* number of programs alive, but stopped */
|
||||||
|
int jobContext; /* bitmask defining current context */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct builtInCommand {
|
struct builtInCommand {
|
||||||
char *cmd; /* name */
|
char *cmd; /* name */
|
||||||
char *descr; /* description */
|
char *descr; /* description */
|
||||||
char *usage; /* usage */
|
|
||||||
int (*function) (struct job *, struct jobSet * jobList); /* function ptr */
|
int (*function) (struct job *, struct jobSet * jobList); /* function ptr */
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -107,6 +116,12 @@ static int builtin_export(struct job *cmd, struct jobSet *junk);
|
|||||||
static int builtin_source(struct job *cmd, struct jobSet *jobList);
|
static int builtin_source(struct job *cmd, struct jobSet *jobList);
|
||||||
static int builtin_unset(struct job *cmd, struct jobSet *junk);
|
static int builtin_unset(struct job *cmd, struct jobSet *junk);
|
||||||
static int builtin_read(struct job *cmd, struct jobSet *junk);
|
static int builtin_read(struct job *cmd, struct jobSet *junk);
|
||||||
|
#ifdef BB_FEATURE_SH_IF_EXPRESSIONS
|
||||||
|
static int builtin_if(struct job *cmd, struct jobSet *junk);
|
||||||
|
static int builtin_then(struct job *cmd, struct jobSet *junk);
|
||||||
|
static int builtin_else(struct job *cmd, struct jobSet *junk);
|
||||||
|
static int builtin_fi(struct job *cmd, struct jobSet *junk);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/* function prototypes for shell stuff */
|
/* function prototypes for shell stuff */
|
||||||
@ -122,30 +137,38 @@ static int busy_loop(FILE * input);
|
|||||||
* can change global variables in the parent shell process but they will not
|
* can change global variables in the parent shell process but they will not
|
||||||
* work with pipes and redirects; 'unset foo | whatever' will not work) */
|
* work with pipes and redirects; 'unset foo | whatever' will not work) */
|
||||||
static struct builtInCommand bltins[] = {
|
static struct builtInCommand bltins[] = {
|
||||||
{"bg", "Resume a job in the background", "bg [%%job]", builtin_fg_bg},
|
{"bg", "Resume a job in the background", builtin_fg_bg},
|
||||||
{"cd", "Change working directory", "cd [dir]", builtin_cd},
|
{"cd", "Change working directory", builtin_cd},
|
||||||
{"exit", "Exit from shell()", "exit", builtin_exit},
|
{"exit", "Exit from shell()", builtin_exit},
|
||||||
{"fg", "Bring job into the foreground", "fg [%%job]", builtin_fg_bg},
|
{"fg", "Bring job into the foreground", builtin_fg_bg},
|
||||||
{"jobs", "Lists the active jobs", "jobs", builtin_jobs},
|
{"jobs", "Lists the active jobs", builtin_jobs},
|
||||||
{"export", "Set environment variable", "export [VAR=value]", builtin_export},
|
{"export", "Set environment variable", builtin_export},
|
||||||
{"unset", "Unset environment variable", "unset VAR", builtin_unset},
|
{"unset", "Unset environment variable", builtin_unset},
|
||||||
{"read", "Input environment variable", "read [VAR]", builtin_read},
|
{"read", "Input environment variable", builtin_read},
|
||||||
{NULL, NULL, NULL, NULL}
|
{NULL, NULL, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Table of forking built-in functions (things that fork cannot change global
|
/* Table of forking built-in functions (things that fork cannot change global
|
||||||
* variables in the parent process, such as the current working directory) */
|
* variables in the parent process, such as the current working directory) */
|
||||||
static struct builtInCommand bltins_forking[] = {
|
static struct builtInCommand bltins_forking[] = {
|
||||||
{"env", "Print all environment variables", "env", builtin_env},
|
{"env", "Print all environment variables", builtin_env},
|
||||||
{"pwd", "Print current directory", "pwd", builtin_pwd},
|
{"pwd", "Print current directory", builtin_pwd},
|
||||||
{".", "Source-in and run commands in a file", ". filename", builtin_source},
|
#ifdef BB_FEATURE_SH_IF_EXPRESSIONS
|
||||||
{"help", "List shell built-in commands", "help", builtin_help},
|
{"if", NULL, builtin_if},
|
||||||
{NULL, NULL, NULL, NULL}
|
{"then", NULL, builtin_then},
|
||||||
|
{"else", NULL, builtin_else},
|
||||||
|
{"fi", NULL, builtin_fi},
|
||||||
|
#endif
|
||||||
|
{".", "Source-in and run commands in a file", builtin_source},
|
||||||
|
{"help", "List shell built-in commands", builtin_help},
|
||||||
|
{NULL, NULL, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
static char *prompt = "# ";
|
static char *prompt = "# ";
|
||||||
static char *cwd;
|
static char *cwd;
|
||||||
static char *local_pending_command = NULL;
|
static char *local_pending_command = NULL;
|
||||||
|
static char *promptStr = NULL;
|
||||||
|
static struct jobSet jobList = { NULL, NULL };
|
||||||
|
|
||||||
#ifdef BB_FEATURE_SH_COMMAND_EDITING
|
#ifdef BB_FEATURE_SH_COMMAND_EDITING
|
||||||
void win_changed(int junk)
|
void win_changed(int junk)
|
||||||
@ -256,9 +279,13 @@ static int builtin_help(struct job *dummy, struct jobSet *junk)
|
|||||||
fprintf(stdout, "\nBuilt-in commands:\n");
|
fprintf(stdout, "\nBuilt-in commands:\n");
|
||||||
fprintf(stdout, "-------------------\n");
|
fprintf(stdout, "-------------------\n");
|
||||||
for (x = bltins; x->cmd; x++) {
|
for (x = bltins; x->cmd; x++) {
|
||||||
|
if (x->descr==NULL)
|
||||||
|
continue;
|
||||||
fprintf(stdout, "%s\t%s\n", x->cmd, x->descr);
|
fprintf(stdout, "%s\t%s\n", x->cmd, x->descr);
|
||||||
}
|
}
|
||||||
for (x = bltins_forking; x->cmd; x++) {
|
for (x = bltins_forking; x->cmd; x++) {
|
||||||
|
if (x->descr==NULL)
|
||||||
|
continue;
|
||||||
fprintf(stdout, "%s\t%s\n", x->cmd, x->descr);
|
fprintf(stdout, "%s\t%s\n", x->cmd, x->descr);
|
||||||
}
|
}
|
||||||
fprintf(stdout, "\n\n");
|
fprintf(stdout, "\n\n");
|
||||||
@ -339,6 +366,44 @@ static int builtin_read(struct job *cmd, struct jobSet *junk)
|
|||||||
return (res);
|
return (res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef BB_FEATURE_SH_IF_EXPRESSIONS
|
||||||
|
/* Built-in handler for 'if' commands */
|
||||||
|
static int builtin_if(struct job *cmd, struct jobSet *junk)
|
||||||
|
{
|
||||||
|
cmd->jobContext |= IF_EXP_CONTEXT;
|
||||||
|
printf("Hit an if -- jobContext=%d\n", cmd->jobContext);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Built-in handler for 'then' (part of the 'if' command) */
|
||||||
|
static int builtin_then(struct job *cmd, struct jobSet *junk)
|
||||||
|
{
|
||||||
|
if (cmd->jobContext & IF_EXP_CONTEXT) {
|
||||||
|
fprintf(stderr, "unexpected token `then'\n");
|
||||||
|
fflush(stderr);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
cmd->jobContext |= THEN_EXP_CONTEXT;
|
||||||
|
printf("Hit an then -- jobContext=%d\n", cmd->jobContext);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Built-in handler for 'else' (part of the 'if' command) */
|
||||||
|
static int builtin_else(struct job *cmd, struct jobSet *junk)
|
||||||
|
{
|
||||||
|
printf("Hit an else\n");
|
||||||
|
cmd->jobContext |= ELSE_EXP_CONTEXT;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Built-in handler for 'fi' (part of the 'if' command) */
|
||||||
|
static int builtin_fi(struct job *cmd, struct jobSet *junk)
|
||||||
|
{
|
||||||
|
printf("Hit an fi\n");
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Built-in '.' handler (read-in and execute commands from file) */
|
/* Built-in '.' handler (read-in and execute commands from file) */
|
||||||
static int builtin_source(struct job *cmd, struct jobSet *junk)
|
static int builtin_source(struct job *cmd, struct jobSet *junk)
|
||||||
{
|
{
|
||||||
@ -471,7 +536,6 @@ static int getCommand(FILE * source, char *command)
|
|||||||
if (source == stdin) {
|
if (source == stdin) {
|
||||||
#ifdef BB_FEATURE_SH_COMMAND_EDITING
|
#ifdef BB_FEATURE_SH_COMMAND_EDITING
|
||||||
int len;
|
int len;
|
||||||
char *promptStr;
|
|
||||||
len=fprintf(stdout, "%s %s", cwd, prompt);
|
len=fprintf(stdout, "%s %s", cwd, prompt);
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
promptStr=(char*)xmalloc(sizeof(char)*(len+1));
|
promptStr=(char*)xmalloc(sizeof(char)*(len+1));
|
||||||
@ -587,8 +651,9 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
|
|||||||
Getting clean memory relieves us of the task of NULL
|
Getting clean memory relieves us of the task of NULL
|
||||||
terminating things and makes the rest of this look a bit
|
terminating things and makes the rest of this look a bit
|
||||||
cleaner (though it is, admittedly, a tad less efficient) */
|
cleaner (though it is, admittedly, a tad less efficient) */
|
||||||
job->cmdBuf = command = calloc(1, 2*strlen(*commandPtr) + 1);
|
job->cmdBuf = command = calloc(2*strlen(*commandPtr) + 1, sizeof(char));
|
||||||
job->text = NULL;
|
job->text = NULL;
|
||||||
|
job->jobContext = REGULAR_JOB_CONTEXT;
|
||||||
|
|
||||||
prog = job->progs;
|
prog = job->progs;
|
||||||
prog->numRedirections = 0;
|
prog->numRedirections = 0;
|
||||||
@ -863,7 +928,7 @@ static int parseCommand(char **commandPtr, struct job *job, struct jobSet *jobLi
|
|||||||
|
|
||||||
static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg, int outPipe[2])
|
static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg, int outPipe[2])
|
||||||
{
|
{
|
||||||
struct job *job;
|
struct job *theJob;
|
||||||
int i;
|
int i;
|
||||||
int nextin, nextout;
|
int nextin, nextout;
|
||||||
int pipefds[2]; /* pipefd[0] is for reading */
|
int pipefds[2]; /* pipefd[0] is for reading */
|
||||||
@ -957,33 +1022,33 @@ static int runCommand(struct job *newJob, struct jobSet *jobList, int inBg, int
|
|||||||
|
|
||||||
newJob->pgrp = newJob->progs[0].pid;
|
newJob->pgrp = newJob->progs[0].pid;
|
||||||
|
|
||||||
/* find the ID for the job to use */
|
/* find the ID for the theJob to use */
|
||||||
newJob->jobId = 1;
|
newJob->jobId = 1;
|
||||||
for (job = jobList->head; job; job = job->next)
|
for (theJob = jobList->head; theJob; theJob = theJob->next)
|
||||||
if (job->jobId >= newJob->jobId)
|
if (theJob->jobId >= newJob->jobId)
|
||||||
newJob->jobId = job->jobId + 1;
|
newJob->jobId = theJob->jobId + 1;
|
||||||
|
|
||||||
/* add the job to the list of running jobs */
|
/* add the theJob to the list of running jobs */
|
||||||
if (!jobList->head) {
|
if (!jobList->head) {
|
||||||
job = jobList->head = malloc(sizeof(*job));
|
theJob = jobList->head = malloc(sizeof(*theJob));
|
||||||
} else {
|
} else {
|
||||||
for (job = jobList->head; job->next; job = job->next);
|
for (theJob = jobList->head; theJob->next; theJob = theJob->next);
|
||||||
job->next = malloc(sizeof(*job));
|
theJob->next = malloc(sizeof(*theJob));
|
||||||
job = job->next;
|
theJob = theJob->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
*job = *newJob;
|
*theJob = *newJob;
|
||||||
job->next = NULL;
|
theJob->next = NULL;
|
||||||
job->runningProgs = job->numProgs;
|
theJob->runningProgs = theJob->numProgs;
|
||||||
job->stoppedProgs = 0;
|
theJob->stoppedProgs = 0;
|
||||||
|
|
||||||
if (inBg) {
|
if (inBg) {
|
||||||
/* we don't wait for background jobs to return -- append it
|
/* we don't wait for background theJobs to return -- append it
|
||||||
to the list of backgrounded jobs and leave it alone */
|
to the list of backgrounded theJobs and leave it alone */
|
||||||
printf("[%d] %d\n", job->jobId,
|
printf("[%d] %d\n", theJob->jobId,
|
||||||
newJob->progs[newJob->numProgs - 1].pid);
|
newJob->progs[newJob->numProgs - 1].pid);
|
||||||
} else {
|
} else {
|
||||||
jobList->fg = job;
|
jobList->fg = theJob;
|
||||||
|
|
||||||
/* move the new process group into the foreground */
|
/* move the new process group into the foreground */
|
||||||
/* suppress messages when run from /linuxrc mag@sysgo.de */
|
/* suppress messages when run from /linuxrc mag@sysgo.de */
|
||||||
@ -1037,7 +1102,6 @@ static int busy_loop(FILE * input)
|
|||||||
{
|
{
|
||||||
char *command;
|
char *command;
|
||||||
char *nextCommand = NULL;
|
char *nextCommand = NULL;
|
||||||
struct jobSet jobList = { NULL, NULL };
|
|
||||||
struct job newJob;
|
struct job newJob;
|
||||||
pid_t parent_pgrp;
|
pid_t parent_pgrp;
|
||||||
int i;
|
int i;
|
||||||
@ -1070,7 +1134,8 @@ static int busy_loop(FILE * input)
|
|||||||
newJob.numProgs) {
|
newJob.numProgs) {
|
||||||
int pipefds[2] = {-1,-1};
|
int pipefds[2] = {-1,-1};
|
||||||
runCommand(&newJob, &jobList, inBg, pipefds);
|
runCommand(&newJob, &jobList, inBg, pipefds);
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
free(command);
|
free(command);
|
||||||
command = (char *) calloc(BUFSIZ, sizeof(char));
|
command = (char *) calloc(BUFSIZ, sizeof(char));
|
||||||
nextCommand = NULL;
|
nextCommand = NULL;
|
||||||
@ -1079,7 +1144,7 @@ static int busy_loop(FILE * input)
|
|||||||
/* a job is running in the foreground; wait for it */
|
/* a job is running in the foreground; wait for it */
|
||||||
i = 0;
|
i = 0;
|
||||||
while (!jobList.fg->progs[i].pid ||
|
while (!jobList.fg->progs[i].pid ||
|
||||||
jobList.fg->progs[i].isStopped) i++;
|
jobList.fg->progs[i].isStopped == 1) i++;
|
||||||
|
|
||||||
waitpid(jobList.fg->progs[i].pid, &status, WUNTRACED);
|
waitpid(jobList.fg->progs[i].pid, &status, WUNTRACED);
|
||||||
|
|
||||||
@ -1128,6 +1193,22 @@ static int busy_loop(FILE * input)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef BB_FEATURE_CLEAN_UP
|
||||||
|
void free_memory(void)
|
||||||
|
{
|
||||||
|
if (promptStr)
|
||||||
|
free(promptStr);
|
||||||
|
if (cwd)
|
||||||
|
free(cwd);
|
||||||
|
if (local_pending_command)
|
||||||
|
free(local_pending_command);
|
||||||
|
|
||||||
|
if (jobList.fg && !jobList.fg->runningProgs) {
|
||||||
|
removeJob(&jobList, jobList.fg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
int shell_main(int argc, char **argv)
|
int shell_main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
@ -1137,6 +1218,10 @@ int shell_main(int argc, char **argv)
|
|||||||
cwd=(char*)xmalloc(sizeof(char)*MAX_LINE+1);
|
cwd=(char*)xmalloc(sizeof(char)*MAX_LINE+1);
|
||||||
getcwd(cwd, sizeof(char)*MAX_LINE);
|
getcwd(cwd, sizeof(char)*MAX_LINE);
|
||||||
|
|
||||||
|
#ifdef BB_FEATURE_CLEAN_UP
|
||||||
|
atexit(free_memory);
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef BB_FEATURE_SH_COMMAND_EDITING
|
#ifdef BB_FEATURE_SH_COMMAND_EDITING
|
||||||
cmdedit_init();
|
cmdedit_init();
|
||||||
signal(SIGWINCH, win_changed);
|
signal(SIGWINCH, win_changed);
|
||||||
|
Loading…
Reference in New Issue
Block a user