⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 lash.c

📁 shell-HHARM9200.rar 华恒 AT91rm9200 中Busybox shell的源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* vi: set sw=4 ts=4: *//* * lash -- the BusyBox Lame-Ass SHell * * 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 * public domain. Use it in any project, free or commercial." * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * *//* 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...//#define DEBUG_SHELL#include <stdio.h>#include <stdlib.h>#include <ctype.h>#include <errno.h>#include <fcntl.h>#include <signal.h>#include <string.h>#include <sys/ioctl.h>#include <sys/wait.h>#include <unistd.h>#include <getopt.h>#include <termios.h>#include "busybox.h"#include "cmdedit.h"#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_CONTROLstatic 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_REDIRECTSenum redir_type { REDIRECT_INPUT, REDIRECT_OVERWRITE,	REDIRECT_APPEND};#endifstatic const unsigned int DEFAULT_CONTEXT=0x1;static const unsigned int IF_TRUE_CONTEXT=0x2;static const unsigned int IF_FALSE_CONTEXT=0x4;static const unsigned int THEN_EXP_CONTEXT=0x8;static const unsigned int ELSE_EXP_CONTEXT=0x10;#ifdef CONFIG_LASH_PIPE_N_REDIRECTSstruct redir_struct {	enum redir_type type;	/* type of redirection */	int fd;						/* file descriptor being redirected */	char *filename;				/* file to redirect fd to */};#endifstruct child_prog {	pid_t pid;					/* 0 if exited */	char **argv;				/* program name and arguments */	int num_redirects;			/* elements in redirection array */	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 {	int jobid;					/* job number */	int num_progs;				/* total number of programs in job */	int running_progs;			/* number of programs running */	char *text;					/* name of job */	char *cmdbuf;				/* buffer various argv's point into */	pid_t pgrp;					/* process group ID for the job */	struct child_prog *progs;	/* array of programs in job */	struct job *next;			/* to track background commands */	int stopped_progs;			/* number of programs alive, but stopped */	unsigned int job_context;	/* bitmask defining current context */	struct jobset *job_list;};struct built_in_command {	char *cmd;					/* name */	char *descr;				/* description */	int (*function) (struct child_prog *);	/* function ptr */};struct close_me {	int fd;	struct close_me *next;};/* function prototypes for builtins */static int builtin_cd(struct child_prog *cmd);static int builtin_exec(struct child_prog *cmd);static int builtin_exit(struct child_prog *cmd);static int builtin_fg_bg(struct child_prog *cmd);static int builtin_help(struct child_prog *cmd);static int builtin_jobs(struct child_prog *dummy);static int builtin_pwd(struct child_prog *dummy);static int builtin_export(struct child_prog *cmd);static int builtin_source(struct child_prog *cmd);static int builtin_unset(struct child_prog *cmd);static int builtin_read(struct child_prog *cmd);/* function prototypes for shell stuff */static void mark_open(int fd);static void mark_closed(int fd);static void close_all(void);static void checkjobs(struct jobset *job_list);static void remove_job(struct jobset *j_list, struct job *job);static int get_command(FILE * source, char *command);static int parse_command(char **command_ptr, struct job *job, int *inbg);static int run_command(struct job *newjob, int inbg, int outpipe[2]);static int pseudo_exec(struct child_prog *cmd) __attribute__ ((noreturn));static int busy_loop(FILE * input);/* Table of built-in functions (these are non-forking builtins, meaning they * can change global variables in the parent shell process but they will not * work with pipes and redirects; 'unset foo | whatever' will not work) */static struct built_in_command 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},	{"export", "Set environment variable", builtin_export},	{"unset", "Unset environment variable", builtin_unset},	{"read", "Input environment variable", builtin_read},	{".", "Source-in and run commands in a file", builtin_source},	/* to do: add ulimit */	{NULL, NULL, NULL}};/* Table of forking built-in functions (things that fork cannot change global * variables in the parent process, such as the current working directory) */static struct built_in_command bltins_forking[] = {	{"pwd", "Print current directory", builtin_pwd},	{"help", "List shell built-in commands", builtin_help},	{NULL, NULL, NULL}};static int shell_context;  /* Type prompt trigger (PS1 or PS2) *//* Globals that are static to this file */static const char *cwd;static char *local_pending_command = NULL;static struct jobset job_list = { NULL, NULL };static int argc;static char **argv;static struct close_me *close_me_head;static int last_return_code;static int last_bg_pid;static unsigned int last_jobid;static int shell_terminal;static char *PS1;static char *PS2 = "> ";#ifdef DEBUG_SHELLstatic inline void debug_printf(const char *format, ...){	va_list args;	va_start(args, format);	vfprintf(stderr, format, args);	va_end(args);}#elsestatic inline void debug_printf(const char *format, ...) { }#endif/*	Most builtins need access to the struct child_prog that has	their arguments, previously coded as cmd->progs[0].  That coding	can exhibit a bug, if the builtin is not the first command in	a pipeline: "echo foo | exec sort" will attempt to exec foo.builtin   previous use      notes------ -----------------  ---------cd      cmd->progs[0]exec    cmd->progs[0]  squashed bug: didn't look for applets or forking builtinsexit    cmd->progs[0]fg_bg   cmd->progs[0], job_list->head, job_list->fghelp    0jobs    job_list->headpwd     0export  cmd->progs[0]source  cmd->progs[0]unset   cmd->progs[0]read    cmd->progs[0]I added "struct job *family;" to struct child_prog,and switched API to builtin_foo(struct child_prog *child);So   cmd->text        becomes  child->family->text     cmd->job_context  becomes  child->family->job_context     cmd->progs[0]    becomes  *child     job_list          becomes  child->family->job_list *//* built-in 'cd <path>' handler */static int builtin_cd(struct child_prog *child){	char *newdir;	if (child->argv[1] == NULL)		newdir = getenv("HOME");	else		newdir = child->argv[1];	if (chdir(newdir)) {		printf("cd: %s: %m\n", newdir);		return EXIT_FAILURE;	}	cwd = xgetcwd((char *)cwd);	if (!cwd)		cwd = bb_msg_unknown;	return EXIT_SUCCESS;}/* built-in 'exec' handler */static int builtin_exec(struct child_prog *child){	if (child->argv[1] == NULL)		return EXIT_SUCCESS;   /* Really? */	child->argv++;	close_all();	pseudo_exec(child);	/* never returns */}/* built-in 'exit' handler */static int builtin_exit(struct child_prog *child){	if (child->argv[1] == NULL)		exit(EXIT_SUCCESS);	exit (atoi(child->argv[1]));}/* built-in 'fg' and 'bg' handler */static int builtin_fg_bg(struct child_prog *child){	int i, jobnum;	struct job *job=NULL;	/* If they gave us no args, assume they want the last backgrounded task */	if (!child->argv[1]) {		for (job = child->family->job_list->head; job; job = job->next) {			if (job->jobid == last_jobid) {				break;			}		}		if (!job) {			bb_error_msg("%s: no current job", child->argv[0]);			return EXIT_FAILURE;		}	} else {		if (sscanf(child->argv[1], "%%%d", &jobnum) != 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->jobid == jobnum) {				break;			}		}		if (!job) {			bb_error_msg("%s: %d: no such job", child->argv[0], jobnum);			return EXIT_FAILURE;		}	}	if (*child->argv[0] == 'f') {		/* Put the job into the foreground.  */		tcsetpgrp(shell_terminal, job->pgrp);		child->family->job_list->fg = job;	}	/* Restart the processes in the job */	for (i = 0; i < job->num_progs; i++)		job->progs[i].is_stopped = 0;	job->stopped_progs = 0;	if ( (i=kill(- job->pgrp, SIGCONT)) < 0) {		if (i == ESRCH) {			remove_job(&job_list, job);		} else {			bb_perror_msg("kill (SIGCONT)");		}	}	return EXIT_SUCCESS;}/* built-in 'help' handler */static int builtin_help(struct child_prog *dummy){	struct built_in_command *x;	printf("\nBuilt-in commands:\n");	printf("-------------------\n");	for (x = bltins; x->cmd; x++) {		if (x->descr==NULL)			continue;		printf("%s\t%s\n", x->cmd, x->descr);	}	for (x = bltins_forking; x->cmd; x++) {		if (x->descr==NULL)			continue;		printf("%s\t%s\n", x->cmd, x->descr);	}	printf("\n\n");	return EXIT_SUCCESS;}/* built-in 'jobs' handler */static int builtin_jobs(struct child_prog *child){	struct job *job;	char *status_string;	for (job = child->family->job_list->head; job; job = job->next) {		if (job->running_progs == job->stopped_progs)			status_string = "Stopped";		else			status_string = "Running";		printf(JOB_STATUS_FORMAT, job->jobid, status_string, job->text);	}	return EXIT_SUCCESS;}/* built-in 'pwd' handler */static int builtin_pwd(struct child_prog *dummy){	cwd = xgetcwd((char *)cwd);	if (!cwd)		cwd = bb_msg_unknown;	puts(cwd);	return EXIT_SUCCESS;}/* built-in 'export VAR=value' handler */static int builtin_export(struct child_prog *child){	int res;	char *v = child->argv[1];	if (v == NULL) {		char **e;		for (e = environ; *e; e++) {			puts(*e);		}		return 0;	}	res = putenv(v);	if (res)		fprintf(stderr, "export: %m\n");#ifdef CONFIG_FEATURE_SH_FANCY_PROMPT	if (strncmp(v, "PS1=", 4)==0)		PS1 = getenv("PS1");#endif#ifdef CONFIG_LOCALE_SUPPORT	if(strncmp(v, "LC_ALL=", 7)==0)		setlocale(LC_ALL, getenv("LC_ALL"));	if(strncmp(v, "LC_CTYPE=", 9)==0)		setlocale(LC_CTYPE, getenv("LC_CTYPE"));#endif	return (res);}/* built-in 'read VAR' handler */static int builtin_read(struct child_prog *child){	int res = 0, len, newlen;	char *s;	char string[MAX_READ];	if (child->argv[1]) {		/* argument (VAR) given: put "VAR=" into buffer */		safe_strncpy(string, child->argv[1], MAX_READ-1);		len = strlen(string);		string[len++] = '=';		string[len]   = '\0';		fgets(&string[len], sizeof(string) - len, stdin);	/* read string */		newlen = strlen(string);		if(newlen > len)			string[--newlen] = '\0';	/* chomp trailing newline */		/*		** string should now contain "VAR=<value>"		** copy it (putenv() won't do that, so we must make sure		** the string resides in a static buffer!)		*/		res = -1;		if((s = strdup(string)))			res = putenv(s);		if (res)			fprintf(stderr, "read: %m\n");	}	else		fgets(string, sizeof(string), stdin);	return (res);}/* Built-in '.' handler (read-in and execute commands from file) */static int builtin_source(struct child_prog *child){	FILE *input;	int status;	int fd;	if (child->argv[1] == NULL)		return EXIT_FAILURE;	input = fopen(child->argv[1], "r");	if (!input) {		printf( "Couldn't open file '%s'\n", child->argv[1]);		return EXIT_FAILURE;	}	fd=fileno(input);	mark_open(fd);	/* Now run the file */	status = busy_loop(input);	fclose(input);	mark_closed(fd);	return (status);}/* built-in 'unset VAR' handler */static int builtin_unset(struct child_prog *child){	if (child->argv[1] == NULL) {		printf( "unset: parameter required.\n");		return EXIT_FAILURE;	}	unsetenv(child->argv[1]);	return EXIT_SUCCESS;}static void mark_open(int fd){	struct close_me *new = xmalloc(sizeof(struct close_me));	new->fd = fd;	new->next = close_me_head;	close_me_head = new;}static void mark_closed(int fd){	struct close_me *tmp;	if (close_me_head == NULL || close_me_head->fd != fd)		bb_error_msg_and_die("corrupt close_me");	tmp = close_me_head;	close_me_head = close_me_head->next;	free(tmp);}static void close_all(){	struct close_me *c, *tmp;	for (c=close_me_head; c; c=tmp) {		close(c->fd);		tmp=c->next;		free(c);	}	close_me_head = NULL;}#ifdef CONFIG_LASH_JOB_CONTROL/* free up all memory from a job */static void free_job(struct job *cmd){	int i;	struct jobset *keep;	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	}	free(cmd->progs);	free(cmd->text);	free(cmd->cmdbuf);	keep = cmd->job_list;	memset(cmd, 0, sizeof(struct job));	cmd->job_list = keep;}/* remove a job from a jobset */static void remove_job(struct jobset *j_list, struct job *job){	struct job *prevjob;	free_job(job);	if (job == j_list->head) {		j_list->head = job->next;	} else {		prevjob = j_list->head;		while (prevjob->next != job)			prevjob = prevjob->next;		prevjob->next = job->next;	}	if (j_list->head)		last_jobid = j_list->head->jobid;	else		last_jobid = 0;	free(job);}/* 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){	struct job *job;	pid_t childpid;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -