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

📄 hush.c

📁 为samsung2410 ARM移植的busybox工具包
💻 C
📖 第 1 页 / 共 5 页
字号:
	if (last_redir) {		last_redir->next=redir;	} else {		child->redirects=redir;	}	redir->type=style;	redir->fd= (fd==-1) ? redir_table[style].default_fd : fd ;	debug_printf("Redirect type %d%s\n", redir->fd, redir_table[style].descrip);	/* Check for a '2>&1' type redirect */ 	redir->dup = redirect_dup_num(input);	if (redir->dup == -2) return 1;  /* syntax error */	if (redir->dup != -1) {		/* Erik had a check here that the file descriptor in question		 * is legit; I postpone that to "run time"		 * A "-" representation of "close me" shows up as a -3 here */		debug_printf("Duplicating redirect '%d>&%d'\n", redir->fd, redir->dup);	} else {		/* We do _not_ try to open the file that src points to,		 * since we need to return and let src be expanded first.		 * Set ctx->pending_redirect, so we know what to do at the		 * end of the next parsed word.		 */		ctx->pending_redirect = redir;	}	return 0;}struct pipe *new_pipe(void) {	struct pipe *pi;	pi = xmalloc(sizeof(struct pipe));	pi->num_progs = 0;	pi->progs = NULL;	pi->next = NULL;	pi->followup = 0;  /* invalid */	return pi;}static void initialize_context(struct p_context *ctx){	ctx->pipe=NULL;	ctx->pending_redirect=NULL;	ctx->child=NULL;	ctx->list_head=new_pipe();	ctx->pipe=ctx->list_head;	ctx->w=RES_NONE;	ctx->stack=NULL;	done_command(ctx);   /* creates the memory for working child */}/* normal return is 0 * if a reserved word is found, and processed, return 1 * should handle if, then, elif, else, fi, for, while, until, do, done. * case, function, and select are obnoxious, save those for later. */int reserved_word(o_string *dest, struct p_context *ctx){	struct reserved_combo {		char *literal;		int code;		long flag;	};	/* Mostly a list of accepted follow-up reserved words.	 * FLAG_END means we are done with the sequence, and are ready	 * to turn the compound list into a command.	 * FLAG_START means the word must start a new compound list.	 */	static struct reserved_combo reserved_list[] = {		{ "if",    RES_IF,    FLAG_THEN | FLAG_START },		{ "then",  RES_THEN,  FLAG_ELIF | FLAG_ELSE | FLAG_FI },		{ "elif",  RES_ELIF,  FLAG_THEN },		{ "else",  RES_ELSE,  FLAG_FI   },		{ "fi",    RES_FI,    FLAG_END  },		{ "for",   RES_FOR,   FLAG_DO   | FLAG_START },		{ "while", RES_WHILE, FLAG_DO   | FLAG_START },		{ "until", RES_UNTIL, FLAG_DO   | FLAG_START },		{ "do",    RES_DO,    FLAG_DONE },		{ "done",  RES_DONE,  FLAG_END  }	};	struct reserved_combo *r;	for (r=reserved_list;#define NRES sizeof(reserved_list)/sizeof(struct reserved_combo)		r<reserved_list+NRES; r++) {		if (strcmp(dest->data, r->literal) == 0) {			debug_printf("found reserved word %s, code %d\n",r->literal,r->code);			if (r->flag & FLAG_START) {				struct p_context *new = xmalloc(sizeof(struct p_context));				debug_printf("push stack\n");				*new = *ctx;   /* physical copy */				initialize_context(ctx);				ctx->stack=new;			} else if ( ctx->w == RES_NONE || ! (ctx->old_flag & (1<<r->code))) {				syntax();				ctx->w = RES_SNTX;				b_reset (dest);				return 1;			}			ctx->w=r->code;			ctx->old_flag = r->flag;			if (ctx->old_flag & FLAG_END) {				struct p_context *old;				debug_printf("pop stack\n");				old = ctx->stack;				old->child->group = ctx->list_head;				old->child->subshell = 0;				*ctx = *old;   /* physical copy */				free(old);			}			b_reset (dest);			return 1;		}	}	return 0;}/* normal return is 0. * Syntax or xglob errors return 1. */static int done_word(o_string *dest, struct p_context *ctx){	struct child_prog *child=ctx->child;	glob_t *glob_target;	int gr, flags = 0;	debug_printf("done_word: %s %p\n", dest->data, child);	if (dest->length == 0 && !dest->nonnull) {		debug_printf("  true null, ignored\n");		return 0;	}	if (ctx->pending_redirect) {		glob_target = &ctx->pending_redirect->word;	} else {		if (child->group) {			syntax();			return 1;  /* syntax error, groups and arglists don't mix */		}		if (!child->argv) {			debug_printf("checking %s for reserved-ness\n",dest->data);			if (reserved_word(dest,ctx)) return ctx->w==RES_SNTX;		}		glob_target = &child->glob_result; 		if (child->argv) flags |= GLOB_APPEND;	}	gr = xglob(dest, flags, glob_target);	if (gr != 0) return 1;	b_reset(dest);	if (ctx->pending_redirect) {		ctx->pending_redirect=NULL;		if (glob_target->gl_pathc != 1) {			error_msg("ambiguous redirect");			return 1;		}	} else {		child->argv = glob_target->gl_pathv;	}	return 0;}/* The only possible error here is out of memory, in which case * xmalloc exits. */static int done_command(struct p_context *ctx){	/* The child is really already in the pipe structure, so	 * advance the pipe counter and make a new, null child.	 * Only real trickiness here is that the uncommitted	 * child structure, to which ctx->child points, is not	 * counted in pi->num_progs. */	struct pipe *pi=ctx->pipe;	struct child_prog *prog=ctx->child;	if (prog && prog->group == NULL	         && prog->argv == NULL	         && prog->redirects == NULL) {		debug_printf("done_command: skipping null command\n");		return 0;	} else if (prog) {		pi->num_progs++;		debug_printf("done_command: num_progs incremented to %d\n",pi->num_progs);	} else {		debug_printf("done_command: initializing\n");	}	pi->progs = xrealloc(pi->progs, sizeof(*pi->progs) * (pi->num_progs+1));	prog = pi->progs + pi->num_progs;	prog->redirects = NULL;	prog->argv = NULL;	prog->is_stopped = 0;	prog->group = NULL;	prog->glob_result.gl_pathv = NULL;	prog->family = pi;	ctx->child=prog;	/* but ctx->pipe and ctx->list_head remain unchanged */	return 0;}static int done_pipe(struct p_context *ctx, pipe_style type){	struct pipe *new_p;	done_command(ctx);  /* implicit closure of previous command */	debug_printf("done_pipe, type %d\n", type);	ctx->pipe->followup = type;	ctx->pipe->r_mode = ctx->w;	new_p=new_pipe();	ctx->pipe->next = new_p;	ctx->pipe = new_p;	ctx->child = NULL;	done_command(ctx);  /* set up new pipe to accept commands */	return 0;}/* peek ahead in the in_str to find out if we have a "&n" construct, * as in "2>&1", that represents duplicating a file descriptor. * returns either -2 (syntax error), -1 (no &), or the number found. */static int redirect_dup_num(struct in_str *input){	int ch, d=0, ok=0;	ch = b_peek(input);	if (ch != '&') return -1;	b_getch(input);  /* get the & */	ch=b_peek(input);	if (ch == '-') {		b_getch(input);		return -3;  /* "-" represents "close me" */	}	while (isdigit(ch)) {		d = d*10+(ch-'0');		ok=1;		b_getch(input);		ch = b_peek(input);	}	if (ok) return d;	error_msg("ambiguous redirect");	return -2;}/* If a redirect is immediately preceded by a number, that number is * supposed to tell which file descriptor to redirect.  This routine * looks for such preceding numbers.  In an ideal world this routine * needs to handle all the following classes of redirects... *     echo 2>foo     # redirects fd  2 to file "foo", nothing passed to echo *     echo 49>foo    # redirects fd 49 to file "foo", nothing passed to echo *     echo -2>foo    # redirects fd  1 to file "foo",    "-2" passed to echo *     echo 49x>foo   # redirects fd  1 to file "foo",   "49x" passed to echo * A -1 output from this program means no valid number was found, so the * caller should use the appropriate default for this redirection. */static int redirect_opt_num(o_string *o){	int num;	if (o->length==0) return -1;	for(num=0; num<o->length; num++) {		if (!isdigit(*(o->data+num))) {			return -1;		}	}	/* reuse num (and save an int) */	num=atoi(o->data);	b_reset(o);	return num;}FILE *generate_stream_from_list(struct pipe *head){	FILE *pf;#if 1	int pid, channel[2];	if (pipe(channel)<0) perror_msg_and_die("pipe");#if !defined(__UCLIBC__) || defined(__UCLIBC_HAS_MMU__)	pid=fork();#else	pid=vfork();#endif	if (pid<0) {		perror_msg_and_die("fork");	} else if (pid==0) {		close(channel[0]);		if (channel[1] != 1) {			dup2(channel[1],1);			close(channel[1]);		}#if 0#define SURROGATE "surrogate response"		write(1,SURROGATE,sizeof(SURROGATE));		_exit(run_list(head));#else		_exit(run_list_real(head));   /* leaks memory */#endif	}	debug_printf("forked child %d\n",pid);	close(channel[1]);	pf = fdopen(channel[0],"r");	debug_printf("pipe on FILE *%p\n",pf);#else	free_pipe_list(head,0);	pf=popen("echo surrogate response","r");	debug_printf("started fake pipe on FILE *%p\n",pf);#endif	return pf;}/* this version hacked for testing purposes *//* return code is exit status of the process that is run. */static int process_command_subs(o_string *dest, struct p_context *ctx, struct in_str *input, int subst_end){	int retcode;	o_string result=NULL_O_STRING;	struct p_context inner;	FILE *p;	struct in_str pipe_str;	initialize_context(&inner);	/* recursion to generate command */	retcode = parse_stream(&result, &inner, input, subst_end);	if (retcode != 0) return retcode;  /* syntax error or EOF */	done_word(&result, &inner);	done_pipe(&inner, PIPE_SEQ);	b_free(&result);	p=generate_stream_from_list(inner.list_head);	if (p==NULL) return 1;	mark_open(fileno(p));	setup_file_in_str(&pipe_str, p);	/* now send results of command back into original context */	retcode = parse_stream(dest, ctx, &pipe_str, '\0');	/* XXX In case of a syntax error, should we try to kill the child?	 * That would be tough to do right, so just read until EOF. */	if (retcode == 1) {		while (b_getch(&pipe_str)!=EOF) { /* discard */ };	}	debug_printf("done reading from pipe, pclose()ing\n");	/* This is the step that wait()s for the child.  Should be pretty	 * safe, since we just read an EOF from its stdout.  We could try	 * to better, by using wait(), and keeping track of background jobs	 * at the same time.  That would be a lot of work, and contrary	 * to the KISS philosophy of this program. */	mark_closed(fileno(p));	retcode=pclose(p);	free_pipe_list(inner.list_head,0);	debug_printf("pclosed, retcode=%d\n",retcode);	/* XXX this process fails to trim a single trailing newline */	return retcode;}static int parse_group(o_string *dest, struct p_context *ctx,	struct in_str *input, int ch){	int rcode, endch=0;	struct p_context sub;	struct child_prog *child = ctx->child;	if (child->argv) {		syntax();		return 1;  /* syntax error, groups and arglists don't mix */	}	initialize_context(&sub);	switch(ch) {		case '(': endch=')'; child->subshell=1; break;		case '{': endch='}'; break;		default: syntax();   /* really logic error */	}	rcode=parse_stream(dest,&sub,input,endch);	done_word(dest,&sub); /* finish off the final word in the subcontext */	done_pipe(&sub, PIPE_SEQ);  /* and the final command there, too */	child->group = sub.list_head;	return rcode;	/* child remains "open", available for possible redirects */}/* basically useful version until someone wants to get fancier, * see the bash man page under "Parameter Expansion" */static void lookup_param(o_string *dest, struct p_context *ctx, o_string *src){	const char *p=NULL;	if (src->data) { 		p = getenv(src->data);		if (!p) 			p = get_local_var(src->data);	}	if (p) parse_string(dest, ctx, p);   /* recursion */	b_free(src);}/* return code: 0 for OK, 1 for syntax error */static int handle_dollar(o_string *dest, struct p_context *ctx, struct in_str *input){	int i, advance=0;	o_string alt=NULL_O_STRING;	char sep[]=" ";	int ch = input->peek(input);  /* first character after the $ */	debug_printf("handle_dollar: ch=%c\n",ch);	if (isalpha(ch)) {		while(ch=b_peek(input),isalnum(ch) || ch=='_') {			b_getch(input);			b_addchr(&alt,ch);		}		lookup_param(dest, ctx, &alt);	} else if (isdigit(ch)) {		i = ch-'0';  /* XXX is $0 special? */		if (i<global_argc) {			parse_string(dest, ctx, global_argv[i]); /* recursion */		}		advance = 1;	} else switch (ch) {		case '$':			b_adduint(dest,getpid());			advance = 1;			break;		case '!':			if (last_bg_pid > 0) b_adduint(dest, last_bg_pid);			advance = 1;			break;		case '?':			b_adduint(dest,last_return_code);			advance = 1;			break;		case '#':			b_adduint(dest,global_argc ? global_argc-1 : 0);			advance = 1;			break;		case '{':			b_getch(input);			/* XXX maybe someone will try to escape the '}' */			while(ch=b_getch(input),ch!=EOF && ch!='}') {				b_addchr(&alt,ch);			}			if (ch != '}') {				syntax();				return 1;			}			lookup_param(dest, ctx, &alt);			break;		case '(':			b_getch(input);			process_command_subs(dest, ctx, input, ')');			break;		case '*':			sep[0]=ifs[0];			for (i=1; i<global_argc; i++) {				parse_string(dest, ctx, global_argv[i]);				if (i+1 < global_argc) parse_string(dest, ctx, sep);			}			break;		case '@':		case '-':		case '_':			/* still unhandled, but should be eventually */			error_msg("unhandled syntax: $%c",ch);			return 1;			break;		default:			b_addqchr(dest,'$',dest->quote);	}	/* Eat the character if the flag was set.  If the compiler	 * is smart en

⌨️ 快捷键说明

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