📄 exec.c
字号:
} typeset(cp, type_flags, 0, 0, 0); } if ((cp = *ap) == NULL) { rv = subst_exstat; goto Leave; } else if (!tp) { if (Flag(FRESTRICTED) && ksh_strchr_dirsep(cp)) { warningf(TRUE, "%s: restricted", cp); rv = 1; goto Leave; } tp = findcom(cp, fcflags); } switch (tp->type) { case CSHELL: /* shell built-in */ rv = call_builtin(tp, ap); break; case CFUNC: /* function call */ { volatile int old_xflag; volatile Tflag old_inuse; const char *volatile old_kshname; if (!(tp->flag & ISSET)) { struct tbl *ftp; if (!tp->u.fpath) { if (tp->u2.errno_) { warningf(TRUE, "%s: can't find function definition file - %s", cp, strerror(tp->u2.errno_)); rv = 126; } else { warningf(TRUE, "%s: can't find function definition file", cp); rv = 127; } break; } if (include(tp->u.fpath, 0, (char **) 0, 0) < 0) { warningf(TRUE, "%s: can't open function definition file %s - %s", cp, tp->u.fpath, strerror(errno)); rv = 127; break; } if (!(ftp = findfunc(cp, hash(cp), FALSE)) || !(ftp->flag & ISSET)) { warningf(TRUE, "%s: function not defined by %s", cp, tp->u.fpath); rv = 127; break; } tp = ftp; } /* ksh functions set $0 to function name, POSIX functions leave * $0 unchanged. */ old_kshname = kshname; if (tp->flag & FKSH) kshname = ap[0]; else ap[0] = (char *) kshname; e->loc->argv = ap; for (i = 0; *ap++ != NULL; i++) ; e->loc->argc = i - 1; /* ksh-style functions handle getopts sanely, * bourne/posix functions are insane... */ if (tp->flag & FKSH) { e->loc->flags |= BF_DOGETOPTS; e->loc->getopts_state = user_opt; getopts_reset(1); } old_xflag = Flag(FXTRACE); Flag(FXTRACE) = tp->flag & TRACE ? TRUE : FALSE; old_inuse = tp->flag & FINUSE; tp->flag |= FINUSE; e->type = E_FUNC; i = ksh_sigsetjmp(e->jbuf, 0); if (i == 0) { /* seems odd to pass XERROK here, but at&t ksh does */ exstat = execute(tp->val.t, flags & XERROK); i = LRETURN; } kshname = old_kshname; Flag(FXTRACE) = old_xflag; tp->flag = (tp->flag & ~FINUSE) | old_inuse; /* Were we deleted while executing? If so, free the execution * tree. todo: Unfortunately, the table entry is never re-used * until the lookup table is expanded. */ if ((tp->flag & (FDELETE|FINUSE)) == FDELETE) { if (tp->flag & ALLOC) { tp->flag &= ~ALLOC; tfree(tp->val.t, tp->areap); } tp->flag = 0; } switch (i) { case LRETURN: case LERROR: rv = exstat; break; case LINTR: case LEXIT: case LLEAVE: case LSHELL: quitenv(); unwind(i); /*NOTREACHED*/ default: quitenv(); internal_errorf(1, "CFUNC %d", i); } break; } case CEXEC: /* executable command */ case CTALIAS: /* tracked alias */ if (!(tp->flag&ISSET)) { /* errno_ will be set if the named command was found * but could not be executed (permissions, no execute * bit, directory, etc). Print out a (hopefully) * useful error message and set the exit status to 126. */ if (tp->u2.errno_) { warningf(TRUE, "%s: cannot execute - %s", cp, strerror(tp->u2.errno_)); rv = 126; /* POSIX */ } else { warningf(TRUE, "%s: not found", cp); rv = 127; } break; }#ifdef KSH /* set $_ to program's full path */ /* setstr() can't fail here */ setstr(typeset("_", LOCAL|EXPORT, 0, INTEGER, 0), tp->val.s, KSH_RETURN_ERROR);#endif /* KSH */ if (flags&XEXEC) { j_exit(); if (!(flags&XBGND) || Flag(FMONITOR)) { setexecsig(&sigtraps[SIGINT], SS_RESTORE_ORIG); setexecsig(&sigtraps[SIGQUIT], SS_RESTORE_ORIG); } } /* to fork we set up a TEXEC node and call execute */ texec.type = TEXEC; texec.left = t; /* for tprint */ texec.str = tp->val.s; texec.args = ap; rv = exchild(&texec, flags, -1); break; } Leave: if (flags & XEXEC) { exstat = rv; unwind(LLEAVE); } return rv;}static voidscriptexec(tp, ap) register struct op *tp; register char **ap;{ char *shell; shell = str_val(global(EXECSHELL_STR)); if (shell && *shell) shell = search(shell, path, X_OK, (int *) 0); if (!shell || !*shell) shell = EXECSHELL; *tp->args-- = tp->str;#ifdef SHARPBANG { char buf[LINE]; register char *cp; register int fd, n; buf[0] = '\0'; if ((fd = open(tp->str, O_RDONLY)) >= 0) { if ((n = read(fd, buf, LINE - 1)) > 0) buf[n] = '\0'; (void) close(fd); } if ((buf[0] == '#' && buf[1] == '!' && (cp = &buf[2]))# ifdef OS2 || (strncmp(buf, "extproc", 7) == 0 && isspace(buf[7]) && (cp = &buf[7]))# endif /* OS2 */ ) { while (*cp && (*cp == ' ' || *cp == '\t')) cp++; if (*cp && *cp != '\n') { char *a0 = cp, *a1 = (char *) 0;# ifdef OS2 char *a2 = cp;# endif /* OS2 */ while (*cp && *cp != '\n' && *cp != ' ' && *cp != '\t') {# ifdef OS2 /* Allow shell search without prepended path * if shell with / in pathname cannot be found. * Use / explicitly so \ can be used if explicit * needs to be forced. */ if (*cp == '/') a2 = cp + 1;# endif /* OS2 */ cp++; } if (*cp && *cp != '\n') { *cp++ = '\0'; while (*cp && (*cp == ' ' || *cp == '\t')) cp++; if (*cp && *cp != '\n') { a1 = cp; /* all one argument */ while (*cp && *cp != '\n') cp++; } } if (*cp == '\n') { *cp = '\0'; if (a1) *tp->args-- = a1;# ifdef OS2 if (a0 != a2) { char *tmp_a0 = str_nsave(a0, strlen(a0) + 5, ATEMP); if (search_access(tmp_a0, X_OK, (int *) 0)) a0 = a2; afree(tmp_a0, ATEMP); }# endif /* OS2 */ shell = a0; } }# ifdef OS2 } else { /* Use ksh documented shell default if present * else use OS2_SHELL which is assumed to need * the /c option and '\' as dir separater. */ char *p = shell; shell = str_val(global("EXECSHELL")); if (shell && *shell) shell = search(shell, path, X_OK, (int *) 0); if (!shell || !*shell) { shell = p; *tp->args-- = "/c"; for (p = tp->str; *p; p++) if (*p == '/') *p = '\\'; }# endif /* OS2 */ } }#endif /* SHARPBANG */ *tp->args = shell; ksh_execve(tp->args[0], tp->args, ap, 0); /* report both the program that was run and the bogus shell */ errorf("%s: %s: %s", tp->str, shell, strerror(errno));}intshcomexec(wp) register char **wp;{ register struct tbl *tp; tp = tsearch(&builtins, *wp, hash(*wp)); if (tp == NULL) internal_errorf(1, "shcomexec: %s", *wp); return call_builtin(tp, wp);}/* * Search function tables for a function. If create set, a table entry * is created if none is found. */struct tbl *findfunc(name, h, create) const char *name; unsigned int h; int create;{ struct block *l; struct tbl *tp = (struct tbl *) 0; for (l = e->loc; l; l = l->next) { tp = tsearch(&l->funs, name, h); if (tp) break; if (!l->next && create) { tp = tenter(&l->funs, name, h); tp->flag = DEFINED; tp->type = CFUNC; tp->val.t = (struct op *) 0; break; } } return tp;}/* * define function. Returns 1 if function is being undefined (t == 0) and * function did not exist, returns 0 otherwise. */intdefine(name, t) const char *name; struct op *t;{ struct tbl *tp; int was_set = 0; while (1) { tp = findfunc(name, hash(name), TRUE); if (tp->flag & ISSET) was_set = 1; /* If this function is currently being executed, we zap this * table entry so findfunc() won't see it */ if (tp->flag & FINUSE) { tp->name[0] = '\0'; tp->flag &= ~DEFINED; /* ensure it won't be found */ tp->flag |= FDELETE; } else break; } if (tp->flag & ALLOC) { tp->flag &= ~(ISSET|ALLOC); tfree(tp->val.t, tp->areap); } if (t == NULL) { /* undefine */ tdelete(tp); return was_set ? 0 : 1; } tp->val.t = tcopy(t->left, tp->areap); tp->flag |= (ISSET|ALLOC); if (t->u.ksh_func) tp->flag |= FKSH; return 0;}/* * add builtin */voidbuiltin(name, func) const char *name; int (*func) ARGS((char **));{ register struct tbl *tp; Tflag flag; /* see if any flags should be set for this builtin */ for (flag = 0; ; name++) { if (*name == '=') /* command does variable assignment */ flag |= KEEPASN; else if (*name == '*') /* POSIX special builtin */ flag |= SPEC_BI; else if (*name == '+') /* POSIX regular builtin */ flag |= REG_BI; else break; } tp = tenter(&builtins, name, hash(name)); tp->flag = DEFINED | flag; tp->type = CSHELL; tp->val.f = func;}/* * find command * either function, hashed command, or built-in (in that order) */struct tbl *findcom(name, flags) const char *name; int flags; /* FC_* */{ static struct tbl temp; unsigned int h = hash(name); struct tbl *tp = NULL, *tbi; int insert = Flag(FTRACKALL); /* insert if not found */ char *fpath; /* for function autoloading */ char *npath; if (ksh_strchr_dirsep(name) != NULL) { insert = 0; /* prevent FPATH search below */ flags &= ~FC_FUNC; goto Search; } tbi = (flags & FC_BI) ? tsearch(&builtins, name, h) : NULL; /* POSIX says special builtins first, then functions, then * POSIX regular builtins, then search path... */ if ((flags & FC_SPECBI) && tbi && (tbi->flag & SPEC_BI)) tp = tbi; if (!tp && (flags & FC_FUNC)) { tp = findfunc(name, h, FALSE); if (tp && !(tp->flag & ISSET)) { if ((fpath = str_val(global("FPATH"))) == null) { tp->u.fpath = (char *) 0; tp->u2.errno_ = 0; } else tp->u.fpath = search(name, fpath, R_OK, &tp->u2.errno_); } } if (!tp && (flags & FC_REGBI) && tbi && (tbi->flag & REG_BI)) tp = tbi; /* todo: posix says non-special/non-regular builtins must * be triggered by some user-controllable means like a * special directory in PATH. Requires modifications to * the search() function. Tracked aliases should be * modified to allow tracking of builtin commands. * This should be under control of the FPOSIX flag. * If this is changed, also change c_whence... */ if (!tp && (flags & FC_UNREGBI) && tbi) tp = tbi; if (!tp && (flags & FC_PATH) && !(flags & FC_DEFPATH)) { tp = tsearch(&taliases, name, h); if (tp && (tp->flag & ISSET) && eaccess(tp->val.s, X_OK) != 0) { if (tp->flag & ALLOC) { tp->flag &= ~ALLOC; afree(tp->val.s, APERM); } tp->flag &= ~ISSET; } } Search: if ((!tp || (tp->type == CTALIAS && !(tp->flag&ISSET))) && (flags & FC_PATH)) { if (!tp) { if (insert && !(flags & FC_DEFPATH)) { tp = tenter(&taliases, name, h); tp->type = CTALIAS; } else { tp = &temp; tp->type = CEXEC; } tp->flag = DEFINED; /* make ~ISSET */ } npath = search(name, flags & FC_DEFPATH ? def_path : path, X_OK, &tp->u2.errno_); if (npath) { tp->val.s = tp == &temp ? npath : str_save(npath, APERM); tp->flag |= ISSET|ALLOC; } else if ((flags & FC_FUNC) && (fpath = str_val(global("FPATH"))) != null && (npath = search(name, fpath, R_OK, &tp->u2.errno_)) != (char *) 0) { /* An undocumented feature of at&t ksh is that it * searches FPATH if a command is not found, even * if the command hasn't been set up as an autoloaded * function (ie, no typeset -uf). */ tp = &temp; tp->type = CFUNC; tp->flag = DEFINED; /* make ~ISSET */ tp->u.fpath = npath; } } return tp;}/* * flush executable commands with relative paths */voidflushcom(all) int all; /* just relative or all */{ struct tbl *tp; struct tstate ts; for (twalk(&ts, &taliases); (tp = tnext(&ts)) != NULL; ) if ((tp->flag&ISSET) && (all || !ISDIRSEP(tp->val.s[0]))) { if (tp->flag&ALLOC) { tp->flag &= ~(ALLOC|ISSET); afree(tp->val.s, APERM); } tp->flag &= ~ISSET; }}/* Check if path is something we want to find. Returns -1 for failure. */intsearch_access(path, mode, errnop) const char *path; int mode; int *errnop; /* set if candidate found, but not suitable */{#ifndef OS2 int ret, err = 0; struct stat statb; if (stat(path, &statb) < 0) return -1; ret = eaccess(path, mode); if (ret < 0) err = errno; /* File exists, but we can't access it */ else if (mode == X_OK && (!S_ISREG(statb.st_mode) /* This 'cause access() says root can execute everything */ || !(statb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)))) { ret = -1; err = S_ISDIR(statb.st_mode) ? EISDIR : EACCES; } if (err && errnop && !*errnop) *errnop = err; return ret;#else /* !OS2 */ /* * NOTE: ASSUMES path can be modified and has enough room at the * end of the string for a suffix (ie, 4 extra characters). * Certain code knows this (eg, eval.c(globit()), * exec.c(search())). */ static char *xsuffixes[] = { ".ksh", ".exe", ".", ".sh", ".cmd",
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -