2023-01-22 14:00:20 +00:00
|
|
|
#include <bits/errno-return.h>
|
2023-03-24 20:33:20 +00:00
|
|
|
#include <fcntl.h>
|
2023-05-02 08:50:39 +00:00
|
|
|
#include <luna/StringBuilder.h>
|
|
|
|
#include <luna/Vector.h>
|
2023-01-06 12:31:14 +00:00
|
|
|
#include <stdarg.h>
|
|
|
|
#include <stdint.h>
|
2023-05-20 13:36:30 +00:00
|
|
|
#include <stdio.h>
|
2023-04-07 13:39:10 +00:00
|
|
|
#include <stdlib.h>
|
2023-04-12 16:11:36 +00:00
|
|
|
#include <sys/stat.h>
|
2023-01-22 14:00:20 +00:00
|
|
|
#include <sys/syscall.h>
|
2023-04-24 19:20:44 +00:00
|
|
|
#include <sys/utsname.h>
|
2023-01-06 12:31:14 +00:00
|
|
|
#include <unistd.h>
|
|
|
|
|
|
|
|
extern "C" long arch_invoke_syscall(long, uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t);
|
|
|
|
|
2023-04-07 13:03:38 +00:00
|
|
|
extern char** environ;
|
|
|
|
|
2023-04-25 15:42:19 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2023-04-25 18:25:51 +00:00
|
|
|
static Result<int> try_execl(const char* path, const char* arg, bool use_envp, va_list ap,
|
|
|
|
int (*exec_function)(const char*, char* const*, char* const*))
|
2023-04-25 15:42:19 +00:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2023-04-25 18:25:51 +00:00
|
|
|
if (use_envp)
|
2023-04-25 15:42:19 +00:00
|
|
|
{
|
|
|
|
char* const* envp = va_arg(ap, char* const*);
|
|
|
|
|
2023-04-25 18:25:51 +00:00
|
|
|
return exec_function(path, args.data(), envp);
|
2023-04-25 15:42:19 +00:00
|
|
|
}
|
|
|
|
|
2023-04-25 18:25:51 +00:00
|
|
|
return exec_function(path, args.data(), environ);
|
2023-04-25 15:42:19 +00:00
|
|
|
}
|
|
|
|
|
2023-01-06 12:31:14 +00:00
|
|
|
extern "C"
|
|
|
|
{
|
2023-03-18 22:58:56 +00:00
|
|
|
pid_t fork(void)
|
|
|
|
{
|
|
|
|
long rc = syscall(SYS_fork);
|
|
|
|
__errno_return(rc, int);
|
|
|
|
}
|
|
|
|
|
2023-03-11 21:19:58 +00:00
|
|
|
pid_t getpid(void)
|
|
|
|
{
|
|
|
|
return (pid_t)syscall(SYS_getpid);
|
|
|
|
}
|
|
|
|
|
2023-03-24 16:39:55 +00:00
|
|
|
pid_t getppid(void)
|
|
|
|
{
|
|
|
|
return (pid_t)syscall(SYS_getppid);
|
|
|
|
}
|
|
|
|
|
2023-04-08 11:50:18 +00:00
|
|
|
uid_t getuid(void)
|
|
|
|
{
|
|
|
|
return (uid_t)syscall(SYS_getuid);
|
|
|
|
}
|
|
|
|
|
|
|
|
uid_t geteuid(void)
|
|
|
|
{
|
|
|
|
return (uid_t)syscall(SYS_geteuid);
|
|
|
|
}
|
|
|
|
|
|
|
|
gid_t getgid(void)
|
|
|
|
{
|
|
|
|
return (gid_t)syscall(SYS_getgid);
|
|
|
|
}
|
|
|
|
|
|
|
|
gid_t getegid(void)
|
|
|
|
{
|
|
|
|
return (gid_t)syscall(SYS_getegid);
|
|
|
|
}
|
|
|
|
|
|
|
|
int setuid(uid_t uid)
|
|
|
|
{
|
|
|
|
long rc = syscall(SYS_setuid, uid);
|
|
|
|
__errno_return(rc, int);
|
|
|
|
}
|
|
|
|
|
|
|
|
int seteuid(uid_t uid)
|
|
|
|
{
|
|
|
|
long rc = syscall(SYS_seteuid, uid);
|
|
|
|
__errno_return(rc, int);
|
|
|
|
}
|
|
|
|
|
|
|
|
int setgid(gid_t gid)
|
|
|
|
{
|
|
|
|
long rc = syscall(SYS_setgid, gid);
|
|
|
|
__errno_return(rc, int);
|
|
|
|
}
|
|
|
|
|
|
|
|
int setegid(gid_t gid)
|
|
|
|
{
|
|
|
|
long rc = syscall(SYS_setegid, gid);
|
|
|
|
__errno_return(rc, int);
|
|
|
|
}
|
|
|
|
|
2023-04-08 12:47:34 +00:00
|
|
|
int chown(const char* path, uid_t uid, gid_t gid)
|
|
|
|
{
|
2023-05-11 17:49:03 +00:00
|
|
|
long rc = syscall(SYS_fchownat, AT_FDCWD, path, uid, gid, 0);
|
2023-04-08 12:47:34 +00:00
|
|
|
__errno_return(rc, int);
|
|
|
|
}
|
|
|
|
|
2023-05-19 17:59:20 +00:00
|
|
|
int fchown(int fd, uid_t uid, gid_t gid)
|
|
|
|
{
|
|
|
|
long rc = syscall(SYS_fchownat, fd, "", uid, gid, AT_EMPTY_PATH);
|
|
|
|
__errno_return(rc, int);
|
|
|
|
}
|
|
|
|
|
2023-03-18 21:31:16 +00:00
|
|
|
int execv(const char* path, char* const* argv)
|
|
|
|
{
|
2023-04-07 13:03:38 +00:00
|
|
|
return execve(path, argv, environ);
|
|
|
|
}
|
|
|
|
|
|
|
|
int execve(const char* path, char* const* argv, char* const* envp)
|
|
|
|
{
|
|
|
|
long rc = syscall(SYS_execve, path, argv, envp);
|
2023-03-18 21:31:16 +00:00
|
|
|
__errno_return(rc, int);
|
|
|
|
}
|
|
|
|
|
2023-04-07 13:39:10 +00:00
|
|
|
int execvpe(const char* name, char* const* argv, char* const* envp)
|
|
|
|
{
|
2023-04-25 15:42:19 +00:00
|
|
|
auto rc = try_execvpe(name, argv, envp);
|
|
|
|
if (rc.has_error())
|
2023-04-07 13:39:10 +00:00
|
|
|
{
|
2023-04-25 15:42:19 +00:00
|
|
|
errno = rc.error();
|
|
|
|
return -1;
|
2023-04-07 13:39:10 +00:00
|
|
|
}
|
2023-04-25 15:42:19 +00:00
|
|
|
return rc.value();
|
2023-04-07 13:39:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int execvp(const char* name, char* const* argv)
|
|
|
|
{
|
|
|
|
return execvpe(name, argv, environ);
|
|
|
|
}
|
|
|
|
|
2023-03-30 19:28:39 +00:00
|
|
|
int execl(const char* path, const char* arg, ...)
|
|
|
|
{
|
|
|
|
va_list ap;
|
|
|
|
va_start(ap, arg);
|
|
|
|
|
2023-04-25 18:25:51 +00:00
|
|
|
auto rc = try_execl(path, arg, false, ap, execve);
|
|
|
|
|
|
|
|
va_end(ap);
|
|
|
|
|
|
|
|
if (rc.has_error())
|
|
|
|
{
|
|
|
|
errno = rc.error();
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return rc.value();
|
|
|
|
}
|
|
|
|
|
|
|
|
int execlp(const char* path, const char* arg, ...)
|
|
|
|
{
|
|
|
|
va_list ap;
|
|
|
|
va_start(ap, arg);
|
|
|
|
|
|
|
|
auto rc = try_execl(path, arg, false, ap, execvpe);
|
2023-03-30 19:28:39 +00:00
|
|
|
|
2023-04-25 15:42:19 +00:00
|
|
|
va_end(ap);
|
|
|
|
|
|
|
|
if (rc.has_error())
|
2023-03-30 19:28:39 +00:00
|
|
|
{
|
2023-04-25 15:42:19 +00:00
|
|
|
errno = rc.error();
|
|
|
|
return -1;
|
2023-03-30 19:28:39 +00:00
|
|
|
}
|
2023-04-25 15:42:19 +00:00
|
|
|
return rc.value();
|
|
|
|
}
|
|
|
|
|
|
|
|
int execle(const char* path, const char* arg, ...)
|
|
|
|
{
|
|
|
|
va_list ap;
|
|
|
|
va_start(ap, arg);
|
|
|
|
|
2023-04-25 18:25:51 +00:00
|
|
|
auto rc = try_execl(path, arg, true, ap, execve);
|
2023-03-30 19:28:39 +00:00
|
|
|
|
|
|
|
va_end(ap);
|
|
|
|
|
2023-04-25 15:42:19 +00:00
|
|
|
if (rc.has_error())
|
|
|
|
{
|
|
|
|
errno = rc.error();
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return rc.value();
|
2023-03-30 19:28:39 +00:00
|
|
|
}
|
|
|
|
|
2023-01-06 12:31:14 +00:00
|
|
|
long syscall(long num, ...)
|
|
|
|
{
|
|
|
|
va_list ap;
|
|
|
|
va_start(ap, num);
|
|
|
|
|
|
|
|
uintptr_t arg0 = va_arg(ap, uintptr_t);
|
|
|
|
uintptr_t arg1 = va_arg(ap, uintptr_t);
|
|
|
|
uintptr_t arg2 = va_arg(ap, uintptr_t);
|
|
|
|
uintptr_t arg3 = va_arg(ap, uintptr_t);
|
|
|
|
uintptr_t arg4 = va_arg(ap, uintptr_t);
|
|
|
|
|
|
|
|
long rc = arch_invoke_syscall(num, arg0, arg1, arg2, arg3, arg4);
|
|
|
|
|
|
|
|
va_end(ap);
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
2023-01-22 14:00:20 +00:00
|
|
|
|
|
|
|
int usleep(useconds_t us)
|
|
|
|
{
|
|
|
|
long rc = syscall(SYS_usleep, us);
|
|
|
|
__errno_return(rc, int);
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned long sleep(unsigned long seconds)
|
|
|
|
{
|
|
|
|
syscall(SYS_usleep, seconds * 1000000);
|
|
|
|
return 0;
|
|
|
|
}
|
2023-03-11 16:45:20 +00:00
|
|
|
|
|
|
|
int close(int fd)
|
|
|
|
{
|
|
|
|
long rc = syscall(SYS_close, fd);
|
|
|
|
__errno_return(rc, int);
|
|
|
|
}
|
2023-03-11 17:02:50 +00:00
|
|
|
|
|
|
|
ssize_t read(int fd, void* buf, size_t size)
|
|
|
|
{
|
|
|
|
long rc = syscall(SYS_read, fd, buf, size);
|
|
|
|
__errno_return(rc, ssize_t);
|
|
|
|
}
|
2023-03-12 10:37:41 +00:00
|
|
|
|
|
|
|
ssize_t write(int fd, const void* buf, size_t size)
|
|
|
|
{
|
|
|
|
long rc = syscall(SYS_write, fd, buf, size);
|
|
|
|
__errno_return(rc, ssize_t);
|
|
|
|
}
|
2023-03-12 12:15:24 +00:00
|
|
|
|
|
|
|
off_t lseek(int fd, off_t offset, int whence)
|
|
|
|
{
|
|
|
|
long rc = syscall(SYS_lseek, fd, offset, whence);
|
|
|
|
__errno_return(rc, off_t);
|
|
|
|
}
|
2023-03-24 20:33:20 +00:00
|
|
|
|
|
|
|
int dup(int fd)
|
|
|
|
{
|
|
|
|
return fcntl(fd, F_DUPFD, 0);
|
|
|
|
}
|
2023-04-11 20:15:21 +00:00
|
|
|
|
2023-04-25 18:37:30 +00:00
|
|
|
int dup2(int oldfd, int newfd)
|
|
|
|
{
|
|
|
|
long rc = syscall(SYS_dup2, oldfd, newfd);
|
|
|
|
__errno_return(rc, int);
|
|
|
|
}
|
|
|
|
|
2023-04-11 20:15:21 +00:00
|
|
|
int chdir(const char* path)
|
|
|
|
{
|
|
|
|
long rc = syscall(SYS_chdir, path);
|
|
|
|
__errno_return(rc, int);
|
|
|
|
}
|
2023-04-11 20:45:13 +00:00
|
|
|
|
|
|
|
static ssize_t __getcwd_wrapper(char* buf, size_t size)
|
|
|
|
{
|
|
|
|
long rc = syscall(SYS_getcwd, buf, size);
|
|
|
|
__errno_return(rc, ssize_t);
|
|
|
|
}
|
|
|
|
|
|
|
|
char* getcwd(char* buf, size_t size)
|
|
|
|
{
|
|
|
|
if (buf)
|
|
|
|
{
|
|
|
|
ssize_t rc = __getcwd_wrapper(buf, size);
|
|
|
|
if (rc < 0) return nullptr;
|
|
|
|
|
|
|
|
if (rc > (ssize_t)size)
|
|
|
|
{
|
|
|
|
errno = ERANGE;
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
else if (size)
|
|
|
|
{
|
|
|
|
buf = (char*)malloc(size);
|
|
|
|
if (!buf) return nullptr;
|
|
|
|
|
|
|
|
ssize_t rc = __getcwd_wrapper(buf, size);
|
|
|
|
if (rc < 0)
|
|
|
|
{
|
|
|
|
free(buf);
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rc > (ssize_t)size)
|
|
|
|
{
|
|
|
|
free(buf);
|
|
|
|
errno = ERANGE;
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2023-05-20 13:36:30 +00:00
|
|
|
buf = (char*)malloc(BUFSIZ);
|
2023-04-11 20:45:13 +00:00
|
|
|
if (!buf) return nullptr;
|
|
|
|
|
2023-05-20 13:36:30 +00:00
|
|
|
ssize_t rc = __getcwd_wrapper(buf, BUFSIZ);
|
2023-04-11 20:45:13 +00:00
|
|
|
if (rc < 0)
|
|
|
|
{
|
|
|
|
free(buf);
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2023-05-20 13:36:30 +00:00
|
|
|
if (rc > BUFSIZ)
|
2023-04-11 20:45:13 +00:00
|
|
|
{
|
|
|
|
free(buf);
|
|
|
|
|
|
|
|
return getcwd(NULL, rc);
|
|
|
|
}
|
|
|
|
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
}
|
2023-04-12 16:11:36 +00:00
|
|
|
|
|
|
|
int unlink(const char* path)
|
|
|
|
{
|
2023-05-05 16:50:35 +00:00
|
|
|
return unlinkat(AT_FDCWD, path, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
int unlinkat(int dirfd, const char* path, int flags)
|
|
|
|
{
|
|
|
|
long rc = syscall(SYS_unlinkat, dirfd, path, flags);
|
2023-04-12 16:11:36 +00:00
|
|
|
__errno_return(rc, int);
|
|
|
|
}
|
|
|
|
|
|
|
|
int rmdir(const char* path)
|
|
|
|
{
|
2023-05-05 16:50:35 +00:00
|
|
|
return unlinkat(AT_FDCWD, path, AT_REMOVEDIR);
|
2023-04-12 16:11:36 +00:00
|
|
|
}
|
2023-04-24 19:20:44 +00:00
|
|
|
|
|
|
|
int gethostname(char* buf, size_t len)
|
|
|
|
{
|
|
|
|
struct utsname info;
|
|
|
|
if (uname(&info) < 0) return -1;
|
|
|
|
|
|
|
|
strlcpy(buf, info.nodename, len);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int sethostname(const char* buf, size_t len)
|
|
|
|
{
|
|
|
|
long rc = syscall(SYS_sethostname, buf, len);
|
|
|
|
__errno_return(rc, int);
|
|
|
|
}
|
2023-05-10 20:48:31 +00:00
|
|
|
|
|
|
|
int pipe(int pfds[2])
|
|
|
|
{
|
|
|
|
long rc = syscall(SYS_pipe, (int*)pfds);
|
|
|
|
__errno_return(rc, int);
|
|
|
|
}
|
2023-05-20 19:47:20 +00:00
|
|
|
|
|
|
|
int symlink(const char* target, const char* linkpath)
|
|
|
|
{
|
|
|
|
long rc = syscall(SYS_symlinkat, target, AT_FDCWD, linkpath);
|
|
|
|
__errno_return(rc, int);
|
|
|
|
}
|
|
|
|
|
|
|
|
int symlinkat(const char* target, int dirfd, const char* linkpath)
|
|
|
|
{
|
|
|
|
long rc = syscall(SYS_symlinkat, target, dirfd, linkpath);
|
|
|
|
__errno_return(rc, int);
|
|
|
|
}
|
2023-05-23 13:42:38 +00:00
|
|
|
|
|
|
|
ssize_t readlink(const char* path, char* buf, size_t max)
|
|
|
|
{
|
|
|
|
long rc = syscall(SYS_readlinkat, AT_FDCWD, path, buf, max);
|
|
|
|
__errno_return(rc, ssize_t);
|
|
|
|
}
|
|
|
|
|
|
|
|
ssize_t readlinkat(int dirfd, const char* path, char* buf, size_t max)
|
|
|
|
{
|
|
|
|
long rc = syscall(SYS_readlinkat, dirfd, path, buf, max);
|
|
|
|
__errno_return(rc, ssize_t);
|
|
|
|
}
|
2023-05-27 09:32:40 +00:00
|
|
|
|
|
|
|
int link(const char* oldpath, const char* newpath)
|
|
|
|
{
|
|
|
|
long rc = syscall(SYS_linkat, AT_FDCWD, oldpath, AT_FDCWD, newpath, 0);
|
|
|
|
__errno_return(rc, int);
|
|
|
|
}
|
|
|
|
|
|
|
|
int linkat(int olddirfd, const char* oldpath, int newdirfd, const char* newpath, int flags)
|
|
|
|
{
|
|
|
|
long rc = syscall(SYS_linkat, olddirfd, oldpath, newdirfd, newpath, flags);
|
|
|
|
__errno_return(rc, int);
|
|
|
|
}
|
2023-01-06 12:31:14 +00:00
|
|
|
}
|