📄 hush.c
字号:
/* job management: */static int checkjobs(struct pipe* fg_pipe);static void insert_bg_job(struct pipe *pi);static void remove_bg_job(struct pipe *pi);#endif/* local variable support */static char **make_list_in(char **inp, char *name);static char *insert_var_value(char *inp);static char *get_local_var(const char *var);#ifndef __U_BOOT__static void unset_local_var(const char *name);#endifstatic int set_local_var(const char *s, int flg_export);#ifndef __U_BOOT__/* Table of built-in functions. They can be forked or not, depending on * context: within pipes, they fork. As simple commands, they do not. * When used in non-forking context, they can change global variables * in the parent shell process. If forked, of course they can not. * For example, 'unset foo | whatever' will parse and run, but foo will * still be set at the end. */static struct built_in_command bltins[] = { {"bg", "Resume a job in the background", builtin_fg_bg}, {"break", "Exit for, while or until loop", builtin_not_written}, {"cd", "Change working directory", builtin_cd}, {"continue", "Continue for, while or until loop", builtin_not_written}, {"env", "Print all environment variables", builtin_env}, {"eval", "Construct and run shell command", builtin_eval}, {"exec", "Exec command, replacing this shell with the exec'd process", builtin_exec}, {"exit", "Exit from shell()", builtin_exit}, {"export", "Set environment variable", builtin_export}, {"fg", "Bring job into the foreground", builtin_fg_bg}, {"jobs", "Lists the active jobs", builtin_jobs}, {"pwd", "Print current directory", builtin_pwd}, {"read", "Input environment variable", builtin_read}, {"return", "Return from a function", builtin_not_written}, {"set", "Set/unset shell local variables", builtin_set}, {"shift", "Shift positional parameters", builtin_shift}, {"trap", "Trap signals", builtin_not_written}, {"ulimit","Controls resource limits", builtin_not_written}, {"umask","Sets file creation mask", builtin_umask}, {"unset", "Unset environment variable", builtin_unset}, {".", "Source-in and run commands in a file", builtin_source}, {"help", "List shell built-in commands", builtin_help}, {NULL, NULL, NULL}};static const char *set_cwd(void){ if(cwd==unknown) cwd = NULL; /* xgetcwd(arg) called free(arg) */ cwd = xgetcwd((char *)cwd); if (!cwd) cwd = unknown; return cwd;}/* built-in 'eval' handler */static int builtin_eval(struct child_prog *child){ char *str = NULL; int rcode = EXIT_SUCCESS; if (child->argv[1]) { str = make_string(child->argv + 1); parse_string_outer(str, FLAG_EXIT_FROM_LOOP | FLAG_PARSE_SEMICOLON); free(str); rcode = last_return_code; } return rcode;}/* 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: %s\n", newdir, strerror(errno)); return EXIT_FAILURE; } set_cwd(); return EXIT_SUCCESS;}/* built-in 'env' handler */static int builtin_env(struct child_prog *dummy){ char **e = environ; if (e == NULL) return EXIT_FAILURE; for (; *e; e++) { puts(*e); } 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++; pseudo_exec(child); /* never returns */}/* built-in 'exit' handler */static int builtin_exit(struct child_prog *child){ if (child->argv[1] == NULL) exit(last_return_code); exit (atoi(child->argv[1]));}/* built-in 'export VAR=value' handler */static int builtin_export(struct child_prog *child){ int res = 0; char *name = child->argv[1]; if (name == NULL) { return (builtin_env(child)); } name = strdup(name); if(name) { char *value = strchr(name, '='); if (!value) { char *tmp; /* They are exporting something without an =VALUE */ value = get_local_var(name); if (value) { size_t ln = strlen(name); tmp = realloc(name, ln+strlen(value)+2); if(tmp==NULL) res = -1; else { sprintf(tmp+ln, "=%s", value); name = tmp; } } else { /* bash does not return an error when trying to export * an undefined variable. Do likewise. */ res = 1; } } } if (res<0) perror_msg("export"); else if(res==0) res = set_local_var(name, 1); else res = 0; free(name); return res;}/* built-in 'fg' and 'bg' handler */static int builtin_fg_bg(struct child_prog *child){ int i, jobnum; struct pipe *pi=NULL; if (!interactive) return EXIT_FAILURE; /* If they gave us no args, assume they want the last backgrounded task */ if (!child->argv[1]) { for (pi = job_list; pi; pi = pi->next) { if (pi->jobid == last_jobid) { break; } } if (!pi) { 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]); return EXIT_FAILURE; } for (pi = job_list; pi; pi = pi->next) { if (pi->jobid == jobnum) { break; } } if (!pi) { 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, pi->pgrp); } /* Restart the processes in the job */ for (i = 0; i < pi->num_progs; i++) pi->progs[i].is_stopped = 0; if ( (i=kill(- pi->pgrp, SIGCONT)) < 0) { if (i == ESRCH) { remove_bg_job(pi); } else { perror_msg("kill (SIGCONT)"); } } pi->stopped_progs = 0; 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); } printf("\n\n"); return EXIT_SUCCESS;}/* built-in 'jobs' handler */static int builtin_jobs(struct child_prog *child){ struct pipe *job; char *status_string; for (job = job_list; 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){ puts(set_cwd()); return EXIT_SUCCESS;}/* built-in 'read VAR' handler */static int builtin_read(struct child_prog *child){ int res; if (child->argv[1]) { char string[BUFSIZ]; char *var = 0; string[0] = 0; /* In case stdin has only EOF */ /* read string */ fgets(string, sizeof(string), stdin); chomp(string); var = malloc(strlen(child->argv[1])+strlen(string)+2); if(var) { sprintf(var, "%s=%s", child->argv[1], string); res = set_local_var(var, 0); } else res = -1; if (res) fprintf(stderr, "read: %m\n"); free(var); /* So not move up to avoid breaking errno */ return res; } else { do res=getchar(); while(res!='\n' && res!=EOF); return 0; }}/* built-in 'set VAR=value' handler */static int builtin_set(struct child_prog *child){ char *temp = child->argv[1]; struct variables *e; if (temp == NULL) for(e = top_vars; e; e=e->next) printf("%s=%s\n", e->name, e->value); else set_local_var(temp, 0); return EXIT_SUCCESS;}/* Built-in 'shift' handler */static int builtin_shift(struct child_prog *child){ int n=1; if (child->argv[1]) { n=atoi(child->argv[1]); } if (n>=0 && n<global_argc) { /* XXX This probably breaks $0 */ global_argc -= n; global_argv += n; return EXIT_SUCCESS; } else { return EXIT_FAILURE; }}/* Built-in '.' handler (read-in and execute commands from file) */static int builtin_source(struct child_prog *child){ FILE *input; int status; if (child->argv[1] == NULL) return EXIT_FAILURE; /* XXX search through $PATH is missing */ input = fopen(child->argv[1], "r"); if (!input) { error_msg("Couldn't open file '%s'", child->argv[1]); return EXIT_FAILURE; } /* Now run the file */ /* XXX argv and argc are broken; need to save old global_argv * (pointer only is OK!) on this stack frame, * set global_argv=child->argv+1, recurse, and restore. */ mark_open(fileno(input)); status = parse_file_outer(input); mark_closed(fileno(input)); fclose(input); return (status);}static int builtin_umask(struct child_prog *child){ mode_t new_umask; const char *arg = child->argv[1]; char *end; if (arg) { new_umask=strtoul(arg, &end, 8); if (*end!='\0' || end == arg) { return EXIT_FAILURE; } } else { printf("%.3o\n", (unsigned int) (new_umask=umask(0))); } umask(new_umask); return EXIT_SUCCESS;}/* built-in 'unset VAR' handler */static int builtin_unset(struct child_prog *child){ /* bash returned already true */ unset_local_var(child->argv[1]); return EXIT_SUCCESS;}static int builtin_not_written(struct child_prog *child){ printf("builtin_%s not written\n",child->argv[0]); return EXIT_FAILURE;}#endifstatic int b_check_space(o_string *o, int len){ /* It would be easy to drop a more restrictive policy * in here, such as setting a maximum string length */ if (o->length + len > o->maxlen) { char *old_data = o->data; /* assert (data == NULL || o->maxlen != 0); */ o->maxlen += max(2*len, B_CHUNK); o->data = realloc(o->data, 1 + o->maxlen); if (o->data == NULL) { free(old_data); } } return o->data == NULL;}static int b_addchr(o_string *o, int ch){ debug_printf("b_addchr: %c %d %p\n", ch, o->length, o); if (b_check_space(o, 1)) return B_NOSPAC; o->data[o->length] = ch; o->length++; o->data[o->length] = '\0'; return 0;}static void b_reset(o_string *o){ o->length = 0; o->nonnull = 0; if (o->data != NULL) *o->data = '\0';}static void b_free(o_string *o){ b_reset(o); free(o->data); o->data = NULL; o->maxlen = 0;}/* My analysis of quoting semantics tells me that state information * is associated with a destination, not a source. */static int b_addqchr(o_string *o, int ch, int quote){ if (quote && strchr("*?[\\",ch)) { int rc; rc = b_addchr(o, '\\'); if (rc) return rc; } return b_addchr(o, ch);}/* belongs in utility.c */char *simple_itoa(unsigned int i){ /* 21 digits plus null terminator, good for 64-bit or smaller ints */ static char local[22]; char *p = &local[21]; *p-- = '\0'; do { *p-- = '0' + i % 10; i /= 10; } while (i > 0); return p + 1;}#ifndef __U_BOOT__static int b_adduint(o_string *o, unsigned int i){ int r; char *p = simple_itoa(i); /* no escape checking necessary */ do r=b_addchr(o, *p++); while (r==0 && *p); return r;}#endifstatic int static_get(struct in_str *i){ int ch = *i->p++; if (ch=='\0') return EOF; return ch;}static int static_peek(struct in_str *i){ return *i->p;}#ifndef __U_BOOT__static inline void cmdedit_set_initial_prompt(void){#ifndef CONFIG_FEATURE_SH_FANCY_PROMPT PS1 = NULL;#else PS1 = getenv("PS1"); if(PS1==0) PS1 = "\\w \\$ ";#endif}static inline void setup_prompt_string(int promptmode, char **prompt_str){ debug_printf("setup_prompt_string %d ",promptmode);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -