?? hush.c
字號:
export_me=1; } free(name); p = insert_var_value(child->argv[i]); set_local_var(p, export_me); if (p != child->argv[i]) free(p); } return EXIT_SUCCESS; /* don't worry about errors in set_local_var() yet */ } for (i = 0; is_assignment(child->argv[i]); i++) { p = insert_var_value(child->argv[i]); putenv(strdup(p)); if (p != child->argv[i]) { child->sp--; free(p); } } if (child->sp) { char * str = NULL; str = make_string((child->argv + i)); parse_string_outer(str, FLAG_EXIT_FROM_LOOP | FLAG_REPARSING); free(str); return last_return_code; } for (x = bltins; x->cmd; x++) { if (strcmp(child->argv[i], x->cmd) == 0 ) { int squirrel[] = {-1, -1, -1}; int rcode; if (x->function == builtin_exec && child->argv[i+1]==NULL) { debug_printf("magic exec\n"); setup_redirects(child,NULL); return EXIT_SUCCESS; } debug_printf("builtin inline %s\n", child->argv[0]); /* XXX setup_redirects acts on file descriptors, not FILEs. * This is perfect for work that comes after exec(). * Is it really safe for inline use? Experimentally, * things seem to work with glibc. */ setup_redirects(child, squirrel); child->argv+=i; /* XXX horrible hack */ rcode = x->function(child); child->argv-=i; /* XXX restore hack so free() can work right */ restore_redirects(squirrel); return rcode; } } } for (i = 0; i < pi->num_progs; i++) { child = & (pi->progs[i]); /* pipes are inserted between pairs of commands */ if ((i + 1) < pi->num_progs) { if (pipe(pipefds)<0) perror_msg_and_die("pipe"); nextout = pipefds[1]; } else { nextout=1; pipefds[0] = -1; } /* XXX test for failed fork()? */ if (!(child->pid = fork())) { /* Set the handling for job control signals back to the default. */ signal(SIGINT, SIG_DFL); signal(SIGQUIT, SIG_DFL); signal(SIGTERM, SIG_DFL); signal(SIGTSTP, SIG_DFL); signal(SIGTTIN, SIG_DFL); signal(SIGTTOU, SIG_DFL); signal(SIGCHLD, SIG_DFL); close_all(); if (nextin != 0) { dup2(nextin, 0); close(nextin); } if (nextout != 1) { dup2(nextout, 1); close(nextout); } if (pipefds[0]!=-1) { close(pipefds[0]); /* opposite end of our output pipe */ } /* Like bash, explicit redirects override pipes, * and the pipe fd is available for dup'ing. */ setup_redirects(child,NULL); if (interactive && pi->followup!=PIPE_BG) { /* If we (the child) win the race, put ourselves in the process * group whose leader is the first process in this pipe. */ if (pi->pgrp < 0) { pi->pgrp = getpid(); } if (setpgid(0, pi->pgrp) == 0) { tcsetpgrp(2, pi->pgrp); } } pseudo_exec(child); } /* put our child in the process group whose leader is the first process in this pipe */ if (pi->pgrp < 0) { pi->pgrp = child->pid; } /* Don't check for errors. The child may be dead already, * in which case setpgid returns error code EACCES. */ setpgid(child->pid, pi->pgrp); if (nextin != 0) close(nextin); if (nextout != 1) close(nextout); /* If there isn't another process, nextin is garbage but it doesn't matter */ nextin = pipefds[0]; } return -1;}static int run_list_real(struct pipe *pi){ char *save_name = NULL; char **list = NULL; char **save_list = NULL; struct pipe *rpipe; int flag_rep = 0; int save_num_progs; int rcode=0, flag_skip=1; int flag_restore = 0; int if_code=0, next_if_code=0; /* need double-buffer to handle elif */ reserved_style rmode, skip_more_in_this_rmode=RES_XXXX; /* check syntax for "for" */ for (rpipe = pi; rpipe; rpipe = rpipe->next) { if ((rpipe->r_mode == RES_IN || rpipe->r_mode == RES_FOR) && (rpipe->next == NULL)) { syntax(); return 1; } if ((rpipe->r_mode == RES_IN && (rpipe->next->r_mode == RES_IN && rpipe->next->progs->argv != NULL))|| (rpipe->r_mode == RES_FOR && rpipe->next->r_mode != RES_IN)) { syntax(); return 1; } } for (; pi; pi = (flag_restore != 0) ? rpipe : pi->next) { if (pi->r_mode == RES_WHILE || pi->r_mode == RES_UNTIL || pi->r_mode == RES_FOR) { flag_restore = 0; if (!rpipe) { flag_rep = 0; rpipe = pi; } } rmode = pi->r_mode; debug_printf("rmode=%d if_code=%d next_if_code=%d skip_more=%d\n", rmode, if_code, next_if_code, skip_more_in_this_rmode); if (rmode == skip_more_in_this_rmode && flag_skip) { if (pi->followup == PIPE_SEQ) flag_skip=0; continue; } flag_skip = 1; skip_more_in_this_rmode = RES_XXXX; if (rmode == RES_THEN || rmode == RES_ELSE) if_code = next_if_code; if (rmode == RES_THEN && if_code) continue; if (rmode == RES_ELSE && !if_code) continue; if (rmode == RES_ELIF && !if_code) continue; if (rmode == RES_FOR && pi->num_progs) { if (!list) { /* if no variable values after "in" we skip "for" */ if (!pi->next->progs->argv) continue; /* create list of variable values */ list = make_list_in(pi->next->progs->argv, pi->progs->argv[0]); save_list = list; save_name = pi->progs->argv[0]; pi->progs->argv[0] = NULL; flag_rep = 1; } if (!(*list)) { free(pi->progs->argv[0]); free(save_list); list = NULL; flag_rep = 0; pi->progs->argv[0] = save_name; pi->progs->glob_result.gl_pathv[0] = pi->progs->argv[0]; continue; } else { /* insert new value from list for variable */ if (pi->progs->argv[0]) free(pi->progs->argv[0]); pi->progs->argv[0] = *list++; pi->progs->glob_result.gl_pathv[0] = pi->progs->argv[0]; } } if (rmode == RES_IN) continue; if (rmode == RES_DO) { if (!flag_rep) continue; } if ((rmode == RES_DONE)) { if (flag_rep) { flag_restore = 1; } else { rpipe = NULL; } } if (pi->num_progs == 0) continue; save_num_progs = pi->num_progs; /* save number of programs */ rcode = run_pipe_real(pi); debug_printf("run_pipe_real returned %d\n",rcode); if (rcode!=-1) { /* We only ran a builtin: rcode was set by the return value * of run_pipe_real(), and we don't need to wait for anything. */ } else if (pi->followup==PIPE_BG) { /* XXX check bash's behavior with nontrivial pipes */ /* XXX compute jobid */ /* XXX what does bash do with attempts to background builtins? */ insert_bg_job(pi); rcode = EXIT_SUCCESS; } else { if (interactive) { /* move the new process group into the foreground */ if (tcsetpgrp(shell_terminal, pi->pgrp) && errno != ENOTTY) perror_msg("tcsetpgrp-3"); rcode = checkjobs(pi); /* move the shell to the foreground */ if (tcsetpgrp(shell_terminal, getpgid(0)) && errno != ENOTTY) perror_msg("tcsetpgrp-4"); } else { rcode = checkjobs(pi); } debug_printf("checkjobs returned %d\n",rcode); } last_return_code=rcode; pi->num_progs = save_num_progs; /* restore number of programs */ if ( rmode == RES_IF || rmode == RES_ELIF ) next_if_code=rcode; /* can be overwritten a number of times */ if (rmode == RES_WHILE) flag_rep = !last_return_code; if (rmode == RES_UNTIL) flag_rep = last_return_code; if ( (rcode==EXIT_SUCCESS && pi->followup==PIPE_OR) || (rcode!=EXIT_SUCCESS && pi->followup==PIPE_AND) ) skip_more_in_this_rmode=rmode; checkjobs(NULL); } return rcode;}/* broken, of course, but OK for testing */static char *indenter(int i){ static char blanks[]=" "; return &blanks[sizeof(blanks)-i-1];}/* return code is the exit status of the pipe */static int free_pipe(struct pipe *pi, int indent){ char **p; struct child_prog *child; struct redir_struct *r, *rnext; int a, i, ret_code=0; char *ind = indenter(indent); if (pi->stopped_progs > 0) return ret_code; final_printf("%s run pipe: (pid %d)\n",ind,getpid()); for (i=0; i<pi->num_progs; i++) { child = &pi->progs[i]; final_printf("%s command %d:\n",ind,i); if (child->argv) { for (a=0,p=child->argv; *p; a++,p++) { final_printf("%s argv[%d] = %s\n",ind,a,*p); } globfree(&child->glob_result); child->argv=NULL; } else if (child->group) { final_printf("%s begin group (subshell:%d)\n",ind, child->subshell); ret_code = free_pipe_list(child->group,indent+3); final_printf("%s end group\n",ind); } else { final_printf("%s (nil)\n",ind); } for (r=child->redirects; r; r=rnext) { final_printf("%s redirect %d%s", ind, r->fd, redir_table[r->type].descrip); if (r->dup == -1) { /* guard against the case >$FOO, where foo is unset or blank */ if (r->word.gl_pathv) { final_printf(" %s\n", *r->word.gl_pathv); globfree(&r->word); } } else { final_printf("&%d\n", r->dup); } rnext=r->next; free(r); } child->redirects=NULL; } free(pi->progs); /* children are an array, they get freed all at once */ pi->progs=NULL; return ret_code;}static int free_pipe_list(struct pipe *head, int indent){ int rcode=0; /* if list has no members */ struct pipe *pi, *next; char *ind = indenter(indent); for (pi=head; pi; pi=next) { final_printf("%s pipe reserved mode %d\n", ind, pi->r_mode); rcode = free_pipe(pi, indent); final_printf("%s pipe followup code %d\n", ind, pi->followup); next=pi->next; pi->next=NULL; free(pi); } return rcode; }/* Select which version we will use */static int run_list(struct pipe *pi){ int rcode=0; if (fake_mode==0) { rcode = run_list_real(pi); } /* free_pipe_list has the side effect of clearing memory * In the long run that function can be merged with run_list_real, * but doing that now would hobble the debugging effort. */ free_pipe_list(pi,0); return rcode;}/* The API for glob is arguably broken. This routine pushes a non-matching * string into the output structure, removing non-backslashed backslashes. * If someone can prove me wrong, by performing this function within the * original glob(3) api, feel free to rewrite this routine into oblivion. * Return code (0 vs. GLOB_NOSPACE) matches glob(3). * XXX broken if the last character is '\\', check that before calling. */static int globhack(const char *src, int flags, glob_t *pglob){ int cnt=0, pathc; const char *s; char *dest; for (cnt=1, s=src; s && *s; s++) { if (*s == '\\') s++; cnt++; } dest = malloc(cnt); if (!dest) return GLOB_NOSPACE; if (!(flags & GLOB_APPEND)) { pglob->gl_pathv=NULL; pglob->gl_pathc=0; pglob->gl_offs=0; pglob->gl_offs=0; } pathc = ++pglob->gl_pathc; pglob->gl_pathv = realloc(pglob->gl_pathv, (pathc+1)*sizeof(*pglob->gl_pathv)); if (pglob->gl_pathv == NULL) return GLOB_NOSPACE; pglob->gl_pathv[pathc-1]=dest; pglob->gl_pathv[pathc]=NULL; for (s=src; s && *s; s++, dest++) { if (*s == '\\') s++; *dest = *s; } *dest='\0'; return 0;}/* XXX broken if the last character is '\\', check that before calling */static int glob_needed(const char *s){ for (; *s; s++) { if (*s == '\\') s++; if (strchr("*[?",*s)) return 1; } return 0;}#if 0static void globprint(glob_t *pglob){ int i; debug_printf("glob_t at %p:\n", pglob); debug_printf(" gl_pathc=%d gl_pathv=%p gl_offs=%d gl_flags=%d\n", pglob->gl_pathc, pglob->gl_pathv, pglob->gl_offs, pglob->gl_flags); for (i=0; i<pglob->gl_pathc; i++) debug_printf("pglob->gl_pathv[%d] = %p = %s\n", i, pglob->gl_pathv[i], pglob->gl_pathv[i]);}#endifstatic int xglob(o_string *dest, int flags, glob_t *pglob){ int gr; /* short-circuit for null word */ /* we can code this better when the debug_printf's are gone */ if (dest->length == 0) { if (dest->nonnull) { /* bash man page calls this an "explicit" null */ gr = globhack(dest->data, flags, pglob); debug_printf("globhack returned %d\n",gr); } else { return 0; } } else if (glob_needed(dest->data)) { gr = glob(dest->data, flags, NULL, pglob); debug_printf("glob returned %d\n",gr); if (gr == GLOB_NOMATCH) { /* quote removal, or more accurately, backslash removal */ gr = globhack(dest->data, flags, pglob); debug_printf("globhack returned %d\n",gr); } } else { gr = globhack(dest->data, flags, pglob); debug_printf("globhack returned %d\n",gr); } if (gr == GLOB_NOSPACE) error_msg_and_die("out of memory during glob"); if (gr != 0) { /* GLOB_ABORTED ? */ error_msg("glob(3) error %d",gr); } /* globprint(glob_target); */ return gr;}/* This is used to get/check local shell variables */static char *get_local_var(const char *s){ struct variables *cur; if (!s) return NULL; for (cur = top_vars; cur; cur=cur->next) if(strcmp(cur->name, s)==0) return cur->value; return NULL;}/* This is used to set local shell variables flg_export==0 if only local (not exporting) variable flg_export==1 if "new" exporting environ flg_export>1 if current startup environ (not call putenv()) */static int set_local_var(const char *s, int flg_export){ char *name, *value; int result=0; struct variables *cur; name=strdup(s);
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -