libc: Propagate all errors in execl() and execvpe() + add execle().
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
parent
b8ca749a6c
commit
89fd57dea4
@ -64,6 +64,9 @@ extern "C"
|
|||||||
/* Replace the current process with another one. On success, does not return. */
|
/* Replace the current process with another one. On success, does not return. */
|
||||||
int execl(const char* path, const char* arg, ...);
|
int execl(const char* path, const char* arg, ...);
|
||||||
|
|
||||||
|
/* Replace the current process with another one. On success, does not return. */
|
||||||
|
int execle(const char* path, const char* arg, ...);
|
||||||
|
|
||||||
/* Replace the current process with another one. On success, does not return. */
|
/* Replace the current process with another one. On success, does not return. */
|
||||||
int execve(const char* path, char* const* argv, char* const* envp);
|
int execve(const char* path, char* const* argv, char* const* envp);
|
||||||
|
|
||||||
|
@ -15,6 +15,71 @@ extern "C" long arch_invoke_syscall(long, uintptr_t, uintptr_t, uintptr_t, uintp
|
|||||||
|
|
||||||
extern char** environ;
|
extern char** environ;
|
||||||
|
|
||||||
|
static Result<int> try_execvpe(const char* name, char* const* argv, char* const* envp)
|
||||||
|
{
|
||||||
|
if (strchr(name, '/')) return execve(name, argv, envp);
|
||||||
|
|
||||||
|
char* path = getenv("PATH");
|
||||||
|
if (!path) path = const_cast<char*>("/bin:/sbin");
|
||||||
|
|
||||||
|
Vector<String> paths = TRY(StringView { path }.split(":"));
|
||||||
|
|
||||||
|
for (const auto& dir : paths)
|
||||||
|
{
|
||||||
|
StringBuilder sb;
|
||||||
|
TRY(sb.add(dir));
|
||||||
|
TRY(sb.add('/'));
|
||||||
|
TRY(sb.add(StringView { name }));
|
||||||
|
|
||||||
|
String file = TRY(sb.string());
|
||||||
|
|
||||||
|
int err = errno;
|
||||||
|
execve(file.chars(), argv, envp);
|
||||||
|
|
||||||
|
if (errno != ENOENT && errno != EACCES && errno != ENOEXEC) return -1;
|
||||||
|
|
||||||
|
if (errno == ENOEXEC)
|
||||||
|
{
|
||||||
|
Vector<char*> shell_argv;
|
||||||
|
TRY(shell_argv.try_append(const_cast<char*>("sh")));
|
||||||
|
char* const* arg = argv;
|
||||||
|
do {
|
||||||
|
TRY(shell_argv.try_append(*arg));
|
||||||
|
} while (*(arg++));
|
||||||
|
|
||||||
|
execve("/bin/sh", shell_argv.data(), envp);
|
||||||
|
errno = ENOEXEC;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (err == EACCES) errno = err;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Result<int> try_execl(const char* path, const char* arg, bool use_environ, va_list ap)
|
||||||
|
{
|
||||||
|
Vector<char*> args;
|
||||||
|
TRY(args.try_append(const_cast<char*>(arg)));
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
char* str = va_arg(ap, char*);
|
||||||
|
TRY(args.try_append(str));
|
||||||
|
if (!str) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (use_environ)
|
||||||
|
{
|
||||||
|
char* const* envp = va_arg(ap, char* const*);
|
||||||
|
|
||||||
|
return execve(path, args.data(), envp);
|
||||||
|
}
|
||||||
|
|
||||||
|
return execv(path, args.data());
|
||||||
|
}
|
||||||
|
|
||||||
extern "C"
|
extern "C"
|
||||||
{
|
{
|
||||||
pid_t fork(void)
|
pid_t fork(void)
|
||||||
@ -102,50 +167,13 @@ extern "C"
|
|||||||
|
|
||||||
int execvpe(const char* name, char* const* argv, char* const* envp)
|
int execvpe(const char* name, char* const* argv, char* const* envp)
|
||||||
{
|
{
|
||||||
if (strchr(name, '/')) return execve(name, argv, envp);
|
auto rc = try_execvpe(name, argv, envp);
|
||||||
|
if (rc.has_error())
|
||||||
char* path = getenv("PATH");
|
|
||||||
if (!path) path = const_cast<char*>("/bin:/sbin");
|
|
||||||
|
|
||||||
Vector<String> paths;
|
|
||||||
bool ok = StringView { path }.split(":").try_move_value_or_error(paths, errno);
|
|
||||||
if (!ok) return -1;
|
|
||||||
|
|
||||||
for (const auto& dir : paths)
|
|
||||||
{
|
{
|
||||||
// FIXME: Check for errors.
|
errno = rc.error();
|
||||||
StringBuilder sb;
|
return -1;
|
||||||
sb.add(dir);
|
|
||||||
sb.add('/');
|
|
||||||
sb.add(StringView { name });
|
|
||||||
|
|
||||||
String file;
|
|
||||||
ok = sb.string().try_move_value_or_error(file, errno);
|
|
||||||
if (!ok) return -1;
|
|
||||||
|
|
||||||
int err = errno;
|
|
||||||
execve(file.chars(), argv, envp);
|
|
||||||
|
|
||||||
if (errno != ENOENT && errno != EACCES && errno != ENOEXEC) return -1;
|
|
||||||
|
|
||||||
if (errno == ENOEXEC)
|
|
||||||
{
|
|
||||||
Vector<char*> shell_argv;
|
|
||||||
shell_argv.try_append(const_cast<char*>("sh"));
|
|
||||||
char* const* arg = argv;
|
|
||||||
do {
|
|
||||||
shell_argv.try_append(*arg);
|
|
||||||
} while (*(arg++));
|
|
||||||
|
|
||||||
execve("/bin/sh", shell_argv.data(), envp);
|
|
||||||
errno = ENOEXEC;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (err == EACCES) errno = err;
|
|
||||||
}
|
}
|
||||||
|
return rc.value();
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int execvp(const char* name, char* const* argv)
|
int execvp(const char* name, char* const* argv)
|
||||||
@ -158,19 +186,33 @@ extern "C"
|
|||||||
va_list ap;
|
va_list ap;
|
||||||
va_start(ap, arg);
|
va_start(ap, arg);
|
||||||
|
|
||||||
Vector<char*> args;
|
auto rc = try_execl(path, arg, false, ap);
|
||||||
if (args.try_append(const_cast<char*>(arg)).has_error()) return -1;
|
|
||||||
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
char* str = va_arg(ap, char*);
|
|
||||||
if (args.try_append(str).has_error()) return -1;
|
|
||||||
if (!str) break;
|
|
||||||
}
|
|
||||||
|
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
|
|
||||||
return execv(path, args.data());
|
if (rc.has_error())
|
||||||
|
{
|
||||||
|
errno = rc.error();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return rc.value();
|
||||||
|
}
|
||||||
|
|
||||||
|
int execle(const char* path, const char* arg, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
va_start(ap, arg);
|
||||||
|
|
||||||
|
auto rc = try_execl(path, arg, true, ap);
|
||||||
|
|
||||||
|
va_end(ap);
|
||||||
|
|
||||||
|
if (rc.has_error())
|
||||||
|
{
|
||||||
|
errno = rc.error();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return rc.value();
|
||||||
}
|
}
|
||||||
|
|
||||||
long syscall(long num, ...)
|
long syscall(long num, ...)
|
||||||
|
Loading…
Reference in New Issue
Block a user