LibC: Implement missing execlp and cleanup exec code

This commit is contained in:
Bananymous 2024-12-02 05:52:34 +02:00
parent b8013c883c
commit fd3246113a
1 changed files with 86 additions and 92 deletions

View File

@ -150,90 +150,11 @@ int gethostname(char* name, size_t namelen)
return 0; return 0;
} }
int execl(const char* pathname, const char* arg0, ...) static int exec_impl(const char* pathname, char* const* argv, char* const* envp, bool do_path_resolution)
{ {
if (arg0 == nullptr) char buffer[PATH_MAX];
{
char* temp = nullptr;
return execv(pathname, &temp);
}
va_list ap; if (do_path_resolution && strchr(pathname, '/') == nullptr)
va_start(ap, arg0);
int argc = 1;
while (va_arg(ap, const char*))
argc++;
va_end(ap);
char** argv = (char**)malloc(sizeof(char*) * (argc + 1));
if (argv == nullptr)
{
errno = ENOMEM;
return -1;
}
va_start(ap, arg0);
argv[0] = (char*)arg0;
for (int i = 1; i < argc; i++)
argv[i] = va_arg(ap, char*);
argv[argc] = nullptr;
va_end(ap);
return execv(pathname, argv);
}
int execle(const char* pathname, const char* arg0, ...)
{
va_list ap;
int argc = 0;
if (arg0)
{
va_start(ap, arg0);
argc = 1;
while (va_arg(ap, const char*))
argc++;
va_end(ap);
}
char** argv = (char**)malloc(sizeof(char*) * (argc + 1));
if (argv == nullptr)
{
errno = ENOMEM;
return -1;
}
char** envp = nullptr;
va_start(ap, arg0);
argv[0] = (char*)arg0;
for (int i = 1; i < argc; i++)
argv[i] = va_arg(ap, char*);
argv[argc] = nullptr;
envp = va_arg(ap, char**);
va_end(ap);
return execve(pathname, argv, envp);
}
int execv(const char* pathname, char* const argv[])
{
return execve(pathname, argv, environ);
}
int execve(const char* pathname, char* const argv[], char* const envp[])
{
return syscall(SYS_EXEC, pathname, argv, envp);
}
int execvp(const char* file, char* const argv[])
{
char buffer[1024];
const char* pathname = NULL;
// do path resolution if file doesn't contain /
if (strchr(file, '/') == nullptr)
{ {
const char* cur = getenv("PATH"); const char* cur = getenv("PATH");
if (!cur) if (!cur)
@ -242,21 +163,22 @@ int execvp(const char* file, char* const argv[])
return -1; return -1;
} }
char* resolved = nullptr;
while (*cur) while (*cur)
{ {
const char* end = strchrnul(cur, ':'); const char* end = strchrnul(cur, ':');
size_t len = end - cur; size_t len = end - cur;
ASSERT(strlen(file) + 1 + len < sizeof(buffer)); ASSERT(strlen(pathname) + 1 + len < sizeof(buffer));
strncpy(buffer, cur, len); strncpy(buffer, cur, len);
strcat(buffer, "/"); strcat(buffer, "/");
strcat(buffer, file); strcat(buffer, pathname);
struct stat st; struct stat st;
if (stat(buffer, &st) == 0) if (stat(buffer, &st) == 0)
{ {
pathname = buffer; resolved = buffer;
break; break;
} }
@ -264,19 +186,91 @@ int execvp(const char* file, char* const argv[])
if (*cur) if (*cur)
cur++; cur++;
} }
}
else
{
pathname = file;
}
if (!pathname) if (!resolved)
{ {
errno = ENOENT; errno = ENOENT;
return -1; return -1;
} }
return execve(pathname, argv, environ); pathname = resolved;
}
return syscall(SYS_EXEC, pathname, argv, envp);
}
static int execl_impl(const char* pathname, const char* arg0, va_list ap, bool has_env, bool do_path_resolution)
{
int argc = 1;
va_list ap2;
va_copy(ap2, ap);
while (va_arg(ap2, char*))
argc++;
va_end(ap2);
char** argv = static_cast<char**>(malloc((argc + 1) * sizeof(char*)));
if (argv == nullptr)
{
errno = ENOMEM;
return -1;
}
argv[0] = const_cast<char*>(arg0);
for (int i = 1; i < argc; i++)
argv[i] = va_arg(ap, char*);
argv[argc] = nullptr;
char** envp = environ;
if (has_env)
{
va_arg(ap, char*);
envp = va_arg(ap, char**);;
}
return exec_impl(pathname, argv, envp, do_path_resolution);
}
int execl(const char* pathname, const char* arg0, ...)
{
va_list ap;
va_start(ap, arg0);
int ret = execl_impl(pathname, arg0, ap, false, false);
va_end(ap);
return ret;
}
int execlp(const char* pathname, const char* arg0, ...)
{
va_list ap;
va_start(ap, arg0);
int ret = execl_impl(pathname, arg0, ap, false, true);
va_end(ap);
return ret;
}
int execle(const char* pathname, const char* arg0, ...)
{
va_list ap;
va_start(ap, arg0);
int ret = execl_impl(pathname, arg0, ap, true, false);
va_end(ap);
return ret;
}
int execv(const char* pathname, char* const argv[])
{
return exec_impl(pathname, argv, environ, false);
}
int execve(const char* pathname, char* const argv[], char* const envp[])
{
return exec_impl(pathname, argv, envp, false);
}
int execvp(const char* pathname, char* const argv[])
{
return exec_impl(pathname, argv, environ, true);
} }
pid_t fork(void) pid_t fork(void)