int execvp(const char * name, char * const argv[]) { char * pathstr; char * cp; char fname[NAME_MAX]; unsigned etxtbsy = 1; int eacces = 0; pathstr = getenv("PATH"); if (!pathstr) pathstr = _PATH_STDPATH; cp = strchr(name, '/') ? "" : pathstr; do { cp = execat(cp, name, fname); retry: execve(fname, argv, environ); switch (errno) { case ENOEXEC: return exec_script(argv, fname); case ETXTBSY: if (++etxtbsy > 5) return -1; sleep(etxtbsy); goto retry; case EACCES: eacces = 1; break; case E2BIG: case EFAULT: case ENOMEM: return -1; } } while (cp); if (eacces) errno = EACCES; return -1; }
/* ARGSUSED */ int posix_spawnp( pid_t *pidp, const char *file, const posix_spawn_file_actions_t *file_actions, const posix_spawnattr_t *attrp, char *const argv[], char *const envp[]) { spawn_attr_t *sap = attrp? attrp->__spawn_attrp : NULL; file_attr_t *fap = file_actions? file_actions->__file_attrp : NULL; void *dirbuf = NULL; const char *pathstr = (strchr(file, '/') == NULL)? getenv("PATH") : ""; int xpg4 = libc__xpg4; int error = 0; /* this will be set by the child */ char path[PATH_MAX+4]; const char *cp; pid_t pid; char **newargs; int argc; int i; if (attrp != NULL && sap == NULL) return (EINVAL); if (*file == '\0') return (EACCES); if (fap != NULL && fap->fa_need_dirbuf) { /* * Preallocate the buffer for the call to getdents64() in * spawn_closefrom() since we can't do it in the vfork() child. */ if ((dirbuf = lmalloc(DIRBUF)) == NULL) return (ENOMEM); } /* * We may need to invoke the shell with a slightly modified * argv[] array. To do this we need to preallocate the array. * We must call alloca() before calling vfork() because doing * it after vfork() (in the child) would corrupt the parent. */ for (argc = 0; argv[argc] != NULL; argc++) continue; newargs = alloca((argc + 2) * sizeof (char *)); switch (pid = vforkx(forkflags(sap))) { case 0: /* child */ break; case -1: /* parent, failure */ if (dirbuf) lfree(dirbuf, DIRBUF); return (errno); default: /* parent, success */ /* * We don't get here until the child exec()s or exit()s */ if (pidp != NULL && get_error(&error) == 0) *pidp = pid; if (dirbuf) lfree(dirbuf, DIRBUF); return (get_error(&error)); } if (sap != NULL) if (set_error(&error, perform_flag_actions(sap)) != 0) _exit(_EVAPORATE); if (fap != NULL) if (set_error(&error, perform_file_actions(fap, dirbuf)) != 0) _exit(_EVAPORATE); if (pathstr == NULL) { /* * XPG4: pathstr is equivalent to _CS_PATH, except that * :/usr/sbin is appended when root, and pathstr must end * with a colon when not root. Keep these paths in sync * with _CS_PATH in confstr.c. Note that pathstr must end * with a colon when not root so that when file doesn't * contain '/', the last call to execat() will result in an * attempt to execv file from the current directory. */ if (geteuid() == 0 || getuid() == 0) { if (!xpg4) pathstr = "/usr/sbin:/usr/ccs/bin:/usr/bin"; else pathstr = "/usr/xpg4/bin:/usr/ccs/bin:" "/usr/bin:/opt/SUNWspro/bin:/usr/sbin"; } else { if (!xpg4) pathstr = "/usr/ccs/bin:/usr/bin:"; else pathstr = "/usr/xpg4/bin:/usr/ccs/bin:" "/usr/bin:/opt/SUNWspro/bin:"; } } cp = pathstr; do { cp = execat(cp, file, path); /* * 4025035 and 4038378 * if a filename begins with a "-" prepend "./" so that * the shell can't interpret it as an option */ if (*path == '-') { char *s; for (s = path; *s != '\0'; s++) continue; for (; s >= path; s--) *(s + 2) = *s; path[0] = '.'; path[1] = '/'; } (void) set_error(&error, 0); (void) execve(path, argv, envp); if (set_error(&error, errno) == ENOEXEC) { newargs[0] = "sh"; newargs[1] = path; for (i = 1; i <= argc; i++) newargs[i + 1] = argv[i]; (void) set_error(&error, 0); (void) execve(_PATH_BSHELL, newargs, envp); if (sap != NULL && (sap->sa_psflags & POSIX_SPAWN_NOEXECERR_NP)) _exit(127); (void) set_error(&error, errno); _exit(_EVAPORATE); } } while (cp); if (sap != NULL && (sap->sa_psflags & POSIX_SPAWN_NOEXECERR_NP)) { (void) set_error(&error, 0); _exit(127); } _exit(_EVAPORATE); return (0); /* not reached */ }
/* * Similiar to execvp(), execpt you can supply an environment and we always * use /bin/sh for shell scripts. The PATH searched is the PATH in the * current environment, not the environment in the argument list. * This was pretty much stolen from libc/gen/port/execvp.c */ static int execvpe(char *name, char *const argv[], char *const envp[]) { char *path; char fname[PATH_MAX+2]; char *newargs[256]; int i; const char *cp; unsigned etxtbsy = 1; int eacces = 0; if (*name == '\0') { errno = ENOENT; return (-1); } if ((path = getenv("PATH")) == NULL) path = "/usr/bin:/bin"; cp = strchr(name, '/')? (const char *)"": path; do { cp = execat(cp, name, fname); retry: /* * 4025035 and 4038378 * if a filename begins with a "-" prepend "./" so that * the shell can't interpret it as an option */ if (*fname == '-') { size_t size = strlen(fname) + 1; if ((size + 2) > sizeof (fname)) { errno = E2BIG; return (-1); } (void) memmove(fname + 2, fname, size); fname[0] = '.'; fname[1] = '/'; } (void) execve(fname, argv, envp); switch (errno) { case ENOEXEC: newargs[0] = "sh"; newargs[1] = fname; for (i = 1; (newargs[i + 1] = argv[i]) != NULL; ++i) { if (i >= 254) { errno = E2BIG; return (-1); } } (void) execve("/bin/sh", newargs, envp); return (-1); case ETXTBSY: if (++etxtbsy > 5) return (-1); (void) sleep(etxtbsy); goto retry; case EACCES: ++eacces; break; case ENOMEM: case E2BIG: case EFAULT: return (-1); } } while (cp); if (eacces) errno = EACCES; return (-1); }