diff --git a/Userspace/libc/include/dirent.h b/Userspace/libc/include/dirent.h index 80e02154..99ac3620 100644 --- a/Userspace/libc/include/dirent.h +++ b/Userspace/libc/include/dirent.h @@ -59,7 +59,7 @@ extern "C" #define DT_TMO int alphasort(const struct dirent **, const struct dirent **); - int closedir(DIR *); + int closedir(DIR *dirp); int dirfd(DIR *); DIR *fdopendir(int); DIR *opendir(const char *); diff --git a/Userspace/libc/include/fcntl.h b/Userspace/libc/include/fcntl.h index 039155b8..c444c77e 100644 --- a/Userspace/libc/include/fcntl.h +++ b/Userspace/libc/include/fcntl.h @@ -23,6 +23,8 @@ extern "C" { #endif // __cplusplus +#include + typedef struct f_owner_ex { int type; /* Discriminator for pid. */ diff --git a/Userspace/libc/include/stdio.h b/Userspace/libc/include/stdio.h index 50ec245d..fee0fe7e 100644 --- a/Userspace/libc/include/stdio.h +++ b/Userspace/libc/include/stdio.h @@ -90,9 +90,9 @@ extern "C" int feof(FILE *); int ferror(FILE *); int fflush(FILE *stream); - int fgetc(FILE *); + int fgetc(FILE *stream); int fgetpos(FILE *restrict, fpos_t *restrict); - char *fgets(char *restrict, int, FILE *restrict); + char *fgets(char *restrict s, int n, FILE *restrict stream); int fileno(FILE *); void flockfile(FILE *); FILE *fmemopen(void *restrict, size_t, const char *restrict); @@ -119,7 +119,7 @@ extern "C" ssize_t getline(char **restrict, size_t *restrict, FILE *restrict); FILE *open_memstream(char **, size_t *); int pclose(FILE *); - void perror(const char *); + void perror(const char *s); FILE *popen(const char *, const char *); int printf(const char *restrict format, ...); int putc(int c, FILE *stream); @@ -134,8 +134,8 @@ extern "C" int scanf(const char *restrict, ...); void setbuf(FILE *restrict, char *restrict); int setvbuf(FILE *restrict, char *restrict, int, size_t); - int snprintf(char *restrict, size_t, const char *restrict, ...); - int sprintf(char *restrict, const char *restrict, ...); + int snprintf(char *restrict s, size_t n, const char *restrict format, ...); + int sprintf(char *restrict s, const char *restrict format, ...); int sscanf(const char *restrict, const char *restrict, ...); FILE *tmpfile(void); char *tmpnam(char *); diff --git a/Userspace/libc/include/stdlib.h b/Userspace/libc/include/stdlib.h index 5191a601..478ee63f 100644 --- a/Userspace/libc/include/stdlib.h +++ b/Userspace/libc/include/stdlib.h @@ -51,7 +51,7 @@ extern "C" long a64l(const char *); void abort(void); - int abs(int); + int abs(int i); int atexit(void (*func)(void)); double atof(const char *); int atoi(const char *); @@ -66,7 +66,7 @@ extern "C" char *fcvt(double, int, int *, int *); void free(void *ptr); char *gcvt(double, int, char *); - char *getenv(const char *); + char *getenv(const char *name); int getsubopt(char **, char *const *, char **); int grantpt(int); char *initstate(unsigned int, char *, size_t); diff --git a/Userspace/libc/include/string.h b/Userspace/libc/include/string.h index b77231cf..ac6578c3 100644 --- a/Userspace/libc/include/string.h +++ b/Userspace/libc/include/string.h @@ -36,7 +36,7 @@ extern "C" char *stpcpy(char *restrict, const char *restrict); char *stpncpy(char *restrict, const char *restrict, size_t); char *strcat(char *restrict, const char *restrict); - char *strchr(const char *, int); + char *strchr(const char *s, int c); int strcmp(const char *s1, const char *s2); int strcoll(const char *, const char *); int strcoll_l(const char *, const char *, locale_t); @@ -48,19 +48,19 @@ extern "C" int strerror_r(int, char *, size_t); size_t strlcat(char *restrict, const char *restrict, size_t); size_t strlcpy(char *restrict, const char *restrict, size_t); - size_t strlen(const char *); + size_t strlen(const char *s); char *strncat(char *restrict, const char *restrict, size_t); - int strncmp(const char *, const char *, size_t); + int strncmp(const char *s1, const char *s2, size_t n); char *strncpy(char *restrict, const char *restrict, size_t); char *strndup(const char *, size_t); size_t strnlen(const char *, size_t); - char *strpbrk(const char *, const char *); + char *strpbrk(const char *s1, const char *s2); char *strrchr(const char *, int); - char *strsignal(int); - size_t strspn(const char *, const char *); + char *strsignal(int signum); + size_t strspn(const char *s1, const char *s2); char *strstr(const char *, const char *); - char *strtok(char *restrict, const char *restrict); - char *strtok_r(char *restrict, const char *restrict, char **restrict); + char *strtok(char *restrict s, const char *restrict sep); + char *strtok_r(char *restrict s, const char *restrict sep, char **restrict state); size_t strxfrm(char *restrict, const char *restrict, size_t); size_t strxfrm_l(char *restrict, const char *restrict, size_t, locale_t); diff --git a/Userspace/libc/include/sys/stat.h b/Userspace/libc/include/sys/stat.h index 21a6b5c5..92d4a560 100644 --- a/Userspace/libc/include/sys/stat.h +++ b/Userspace/libc/include/sys/stat.h @@ -91,8 +91,8 @@ extern "C" int fstatat(int, const char *restrict, struct stat *restrict, int); int futimens(int, const struct timespec[2]); int lstat(const char *restrict, struct stat *restrict); - int mkdir(const char *, mode_t); - int mkdirat(int, const char *, mode_t); + int mkdir(const char *path, mode_t mode); + int mkdirat(int fd, const char *path, mode_t mode); int mkfifo(const char *, mode_t); int mkfifoat(int, const char *, mode_t); int mknod(const char *, mode_t, dev_t); diff --git a/Userspace/libc/include/sys/wait.h b/Userspace/libc/include/sys/wait.h index 032105de..a9914275 100644 --- a/Userspace/libc/include/sys/wait.h +++ b/Userspace/libc/include/sys/wait.h @@ -54,9 +54,9 @@ extern "C" typedef unsigned int id_t; typedef int pid_t; - pid_t wait(int *); - int waitid(idtype_t, id_t, siginfo_t *, int); - pid_t waitpid(pid_t, int *, int); + pid_t wait(int *stat_loc); + int waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options); + pid_t waitpid(pid_t pid, int *stat_loc, int options); #ifdef __cplusplus } diff --git a/Userspace/libc/include/unistd.h b/Userspace/libc/include/unistd.h index 068bad8f..759f8ceb 100644 --- a/Userspace/libc/include/unistd.h +++ b/Userspace/libc/include/unistd.h @@ -57,9 +57,10 @@ extern "C" extern char *optarg; extern int optind, opterr, optopt; + extern char **environ; int access(const char *, int); - unsigned int alarm(unsigned int); + unsigned int alarm(unsigned int seconds); int brk(void *); int chdir(const char *); int chroot(const char *); @@ -72,12 +73,12 @@ extern "C" int dup(int); int dup2(int, int); void encrypt(char[64], int); - int execl(const char *, const char *, ...); - int execle(const char *, const char *, ...); - int execlp(const char *, const char *, ...); - int execv(const char *, char *const[]); - int execve(const char *, char *const[], char *const[]); - int execvp(const char *, char *const[]); + int execl(const char *path, const char *arg0, ... /*, (char *)0 */); + int execle(const char *path, const char *arg0, ... /*, (char *)0, char *const envp[]*/); + int execlp(const char *file, const char *arg0, ... /*, (char *)0 */); + int execv(const char *path, char *const argv[]); + int execve(const char *path, char *const argv[], char *const envp[]); + int execvp(const char *file, char *const argv[]); void _exit(int); int fchown(int, uid_t, gid_t); int fchdir(int); @@ -128,7 +129,7 @@ extern "C" int setreuid(uid_t, uid_t); pid_t setsid(void); int setuid(uid_t); - unsigned int sleep(unsigned int); + unsigned int sleep(unsigned int seconds); void swab(const void *, void *, ssize_t); int symlink(const char *, const char *); void sync(void); diff --git a/Userspace/libc/src/std/dirent.c b/Userspace/libc/src/std/dirent.c new file mode 100644 index 00000000..f0ff6b3d --- /dev/null +++ b/Userspace/libc/src/std/dirent.c @@ -0,0 +1,57 @@ +/* + This file is part of Fennix C Library. + + Fennix C Library is free software: you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + Fennix C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Fennix C Library. If not, see . +*/ + +#include +#include +#include +#include + +export int alphasort(const struct dirent **, const struct dirent **); + +export int closedir(DIR *dirp) +{ + if (!dirp) + { + errno = EBADF; + return -1; + } + + int fd = dirfd(dirp); + if (fd == -1) + { + errno = EBADF; + return -1; + } + + int result = close(fd); + if (result == -1) + return -1; + + free(dirp); + return 0; +} + +export int dirfd(DIR *); +export DIR *fdopendir(int); +export DIR *opendir(const char *); +export ssize_t posix_getdents(int, void *, size_t, int); +export struct dirent *readdir(DIR *); +export int readdir_r(DIR *restrict, struct dirent *restrict, struct dirent **restrict); +export void rewinddir(DIR *); +export int scandir(const char *, struct dirent ***, int (*)(const struct dirent *), int (*)(const struct dirent **, const struct dirent **)); +export void seekdir(DIR *, long); +export long telldir(DIR *); diff --git a/Userspace/libc/src/std/stdio.c b/Userspace/libc/src/std/stdio.c index bde21155..602da4f9 100644 --- a/Userspace/libc/src/std/stdio.c +++ b/Userspace/libc/src/std/stdio.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include "../print/printf.h" @@ -109,9 +110,54 @@ export int fflush(FILE *stream) return 0; } -export int fgetc(FILE *); +export int fgetc(FILE *stream) +{ + if (!stream || !(stream->flags & _i_READ)) + return EOF; + + if (stream->buffer_pos >= stream->buffer_size) + { + int res = call_read(stream->fd, stream->buffer, 4096); + if (res <= 0) + { + if (res == 0) + stream->eof = 1; + else + stream->error = 1; + return EOF; + } + stream->buffer_pos = 0; + stream->buffer_size = res; + } + + return (unsigned char)stream->buffer[stream->buffer_pos++]; +} + export int fgetpos(FILE *restrict, fpos_t *restrict); -export char *fgets(char *restrict, int, FILE *restrict); + +export char *fgets(char *restrict s, int n, FILE *restrict stream) +{ + if (!s || n <= 0 || !stream) + return NULL; + + int i = 0; + while (i < n - 1) + { + int c = fgetc(stream); + if (c == EOF) + { + if (i == 0) + return NULL; + break; + } + s[i++] = (char)c; + if (c == '\n') + break; + } + s[i] = '\0'; + return s; +} + export int fileno(FILE *); export void flockfile(FILE *); export FILE *fmemopen(void *restrict, size_t, const char *restrict); @@ -302,7 +348,15 @@ export ssize_t getdelim(char **restrict, size_t *restrict, int, FILE *restrict); export ssize_t getline(char **restrict, size_t *restrict, FILE *restrict); export FILE *open_memstream(char **, size_t *); export int pclose(FILE *); -export void perror(const char *); + +export void perror(const char *s) +{ + fputs(s, stderr); + fputs(": ", stderr); + fputs(strerror(errno), stderr); + fputc('\n', stderr); +} + export FILE *popen(const char *, const char *); export int printf(const char *restrict format, ...) @@ -327,8 +381,25 @@ export void rewind(FILE *); export int scanf(const char *restrict, ...); export void setbuf(FILE *restrict, char *restrict); export int setvbuf(FILE *restrict, char *restrict, int, size_t); -export int snprintf(char *restrict, size_t, const char *restrict, ...); -export int sprintf(char *restrict, const char *restrict, ...); + +export int snprintf(char *restrict s, size_t n, const char *restrict format, ...) +{ + va_list args; + va_start(args, format); + int ret = vsnprintf_(s, n, format, args); + va_end(args); + return ret; +} + +export int sprintf(char *restrict s, const char *restrict format, ...) +{ + va_list args; + va_start(args, format); + int ret = vsprintf_(s, format, args); + va_end(args); + return ret; +} + export int sscanf(const char *restrict, const char *restrict, ...); export FILE *tmpfile(void); export char *tmpnam(char *); diff --git a/Userspace/libc/src/std/stdlib.c b/Userspace/libc/src/std/stdlib.c index 4a31ac51..c8f177e8 100644 --- a/Userspace/libc/src/std/stdlib.c +++ b/Userspace/libc/src/std/stdlib.c @@ -17,6 +17,7 @@ #include #include +#include #include "../mem/liballoc_1_1.h" #define MAX_ATEXIT_FUNCS 32 @@ -31,7 +32,10 @@ export _Noreturn void abort(void) __builtin_unreachable(); } -export int abs(int); +export int abs(int i) +{ + return (i < 0) ? -i : i; +} export int atexit(void (*func)(void)) { @@ -62,7 +66,18 @@ export void exit(int status) export char *fcvt(double, int, int *, int *); export void free(void *ptr) { return PREFIX(free)(ptr); } export char *gcvt(double, int, char *); -export char *getenv(const char *); + +export char *getenv(const char *name) +{ + for (char **env = environ; *env != 0; ++env) + { + char *thisEnv = *env; + if (strncmp(thisEnv, name, strlen(name)) == 0 && thisEnv[strlen(name)] == '=') + return thisEnv + strlen(name) + 1; + } + return NULL; +} + export int getsubopt(char **, char *const *, char **); export int grantpt(int); export char *initstate(unsigned int, char *, size_t); diff --git a/Userspace/libc/src/std/string.c b/Userspace/libc/src/std/string.c index a283583a..0307adca 100644 --- a/Userspace/libc/src/std/string.c +++ b/Userspace/libc/src/std/string.c @@ -17,6 +17,7 @@ #include #include +#include export void *memccpy(void *restrict, const void *restrict, int, size_t); export void *memchr(const void *, int, size_t); @@ -46,7 +47,19 @@ export void *memset(void *, int, size_t); export char *stpcpy(char *restrict, const char *restrict); export char *stpncpy(char *restrict, const char *restrict, size_t); export char *strcat(char *restrict, const char *restrict); -export char *strchr(const char *, int); + +export char *strchr(const char *s, int c) +{ + while (*s) + { + if (*s == (char)c) + return (char *)s; + s++; + } + if (c == '\0') + return (char *)s; + return NULL; +} export int strcmp(const char *s1, const char *s2) { @@ -69,18 +82,171 @@ export char *strerror_l(int, locale_t); export int strerror_r(int, char *, size_t); export size_t strlcat(char *restrict, const char *restrict, size_t); export size_t strlcpy(char *restrict, const char *restrict, size_t); -export size_t strlen(const char *); + +export size_t strlen(const char *s) +{ + const char *start = s; + while (*s) + s++; + return s - start; +} + export char *strncat(char *restrict, const char *restrict, size_t); -export int strncmp(const char *, const char *, size_t); + +export int strncmp(const char *s1, const char *s2, size_t n) +{ + while (n--) + { + if (*s1 != *s2) + return *(unsigned char *)s1 - *(unsigned char *)s2; + if (*s1 == '\0') + return 0; + s1++; + s2++; + } + return 0; +} + export char *strncpy(char *restrict, const char *restrict, size_t); export char *strndup(const char *, size_t); export size_t strnlen(const char *, size_t); -export char *strpbrk(const char *, const char *); + +export char *strpbrk(const char *s1, const char *s2) +{ + while (*s1) + { + const char *s = s2; + while (*s) + { + if (*s1 == *s) + return (char *)s1; + s++; + } + s1++; + } + return NULL; +} + export char *strrchr(const char *, int); -export char *strsignal(int); -export size_t strspn(const char *, const char *); + +export char *strsignal(int signum) +{ + switch (signum) + { + case __SYS_SIGNULL: + return "NULL signal"; + case __SYS_SIGABRT: + return "Aborted"; + case __SYS_SIGALRM: + return "Alarm clock"; + case __SYS_SIGBUS: + return "Bus error"; + case __SYS_SIGCHLD: + return "Child status changed"; + case __SYS_SIGCONT: + return "Continued"; + case __SYS_SIGFPE: + return "Arithmetic exception"; + case __SYS_SIGHUP: + return "Hangup"; + case __SYS_SIGILL: + return "Illegal instruction"; + case __SYS_SIGINT: + return "Interrupt"; + case __SYS_SIGKILL: + return "Killed"; + case __SYS_SIGPIPE: + return "Broken pipe"; + case __SYS_SIGQUIT: + return "Quit"; + case __SYS_SIGSEGV: + return "Segmentation fault"; + case __SYS_SIGSTOP: + return "Stopped (signal)"; + case __SYS_SIGTERM: + return "Terminated"; + case __SYS_SIGTSTP: + return "Stopped (user)"; + case __SYS_SIGTTIN: + return "Stopped (tty input)"; + case __SYS_SIGTTOU: + return "Stopped (tty output)"; + case __SYS_SIGUSR1: + return "User defined signal 1"; + case __SYS_SIGUSR2: + return "User defined signal 2"; + case __SYS_SIGPOLL: + return "Pollable event occurred"; + case __SYS_SIGPROF: + return "Profiling timer expired"; + case __SYS_SIGSYS: + return "Bad system call"; + case __SYS_SIGTRAP: + return "Trace/breakpoint trap"; + case __SYS_SIGURG: + return "Urgent I/O condition"; + case __SYS_SIGVTALRM: + return "Virtual timer expired"; + case __SYS_SIGXCPU: + return "CPU time limit exceeded"; + case __SYS_SIGXFSZ: + return "File size limit exceeded"; + default: + return NULL; + } +} + +export size_t strspn(const char *s1, const char *s2) +{ + const char *p = s1; + const char *spanp; + char c, sc; + +cont: + c = *p++; + for (spanp = s2; (sc = *spanp++) != 0;) + { + if (sc == c) + goto cont; + } + return p - 1 - s1; +} + export char *strstr(const char *, const char *); -export char *strtok(char *restrict, const char *restrict); -export char *strtok_r(char *restrict, const char *restrict, char **restrict); + +export char *strtok(char *restrict s, const char *restrict sep) +{ + static char *last; + return strtok_r(s, sep, &last); +} + +export char *strtok_r(char *restrict s, const char *restrict sep, char **restrict state) +{ + char *start; + char *end; + + if (s == NULL) + s = *state; + + s += strspn(s, sep); + if (*s == '\0') + { + *state = s; + return NULL; + } + + start = s; + end = strpbrk(start, sep); + if (end) + { + *end = '\0'; + *state = end + 1; + } + else + *state = start + strlen(start); + + return start; +} + export size_t strxfrm(char *restrict, const char *restrict, size_t); export size_t strxfrm_l(char *restrict, const char *restrict, size_t, locale_t); diff --git a/Userspace/libc/src/std/sys/stat.c b/Userspace/libc/src/std/sys/stat.c new file mode 100644 index 00000000..6de4f2d3 --- /dev/null +++ b/Userspace/libc/src/std/sys/stat.c @@ -0,0 +1,47 @@ +/* + This file is part of Fennix C Library. + + Fennix C Library is free software: you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + Fennix C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Fennix C Library. If not, see . +*/ + +#include +#include +#include + +export int chmod(const char *, mode_t); +export int fchmod(int, mode_t); +export int fchmodat(int, const char *, mode_t, int); +export int fstat(int, struct stat *); +export int fstatat(int, const char *restrict, struct stat *restrict, int); +export int futimens(int, const struct timespec[2]); +export int lstat(const char *restrict, struct stat *restrict); + +export int mkdir(const char *path, mode_t mode) +{ + return __check_errno(call_mkdir(path, mode), -1); +} + +export int mkdirat(int fd, const char *path, mode_t mode) +{ + printf("mkdirat() is unimplemented\n"); + return __check_errno(-ENOSYS, -1); +} + +export int mkfifo(const char *, mode_t); +export int mkfifoat(int, const char *, mode_t); +export int mknod(const char *, mode_t, dev_t); +export int mknodat(int, const char *, mode_t, dev_t); +export int stat(const char *restrict, struct stat *restrict); +export mode_t umask(mode_t); +export int utimensat(int, const char *, const struct timespec[2], int); diff --git a/Userspace/libc/src/std/sys/wait.c b/Userspace/libc/src/std/sys/wait.c new file mode 100644 index 00000000..6b0ef80d --- /dev/null +++ b/Userspace/libc/src/std/sys/wait.c @@ -0,0 +1,38 @@ +/* + This file is part of Fennix C Library. + + Fennix C Library is free software: you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + Fennix C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Fennix C Library. If not, see . +*/ + +#include +#include +#include +#include +#include + +export pid_t wait(int *stat_loc) +{ + return waitpid((pid_t)-1, stat_loc, 0); +} + +export int waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options) +{ + printf("waitid() is unimplemented\n"); + return __check_errno(-ENOSYS, -1); +} + +export pid_t waitpid(pid_t pid, int *stat_loc, int options) +{ + return __check_errno(call_waitpid(pid, stat_loc, options), -1); +} diff --git a/Userspace/libc/src/std/unistd.c b/Userspace/libc/src/std/unistd.c index 53388fb8..5702edb4 100644 --- a/Userspace/libc/src/std/unistd.c +++ b/Userspace/libc/src/std/unistd.c @@ -16,13 +16,26 @@ */ #include +#include +#include +#include +#include +#include +#include #include export char *optarg; export int optind, opterr, optopt; +export char **environ; export int access(const char *, int); -export unsigned int alarm(unsigned int); + +export unsigned int alarm(unsigned int seconds) +{ + printf("alarm() is unimplemented\n"); + return __check_errno(-ENOSYS, -1); +} + export int brk(void *); export int chdir(const char *); export int chroot(const char *); @@ -35,17 +48,122 @@ export char *cuserid(char *s); export int dup(int); export int dup2(int, int); export void encrypt(char[64], int); -export int execl(const char *, const char *, ...); -export int execle(const char *, const char *, ...); -export int execlp(const char *, const char *, ...); -export int execv(const char *, char *const[]); -export int execve(const char *, char *const[], char *const[]); -export int execvp(const char *, char *const[]); + +export int execl(const char *path, const char *arg0, ...) +{ + va_list args; + va_start(args, arg0); + + int argc = 1; + while (va_arg(args, const char *)) + argc++; + va_end(args); + + char *argv[argc + 1]; + va_start(args, arg0); + argv[0] = (char *)arg0; + for (int i = 1; i < argc; i++) + argv[i] = va_arg(args, char *); + + argv[argc] = NULL; + va_end(args); + return execve(path, argv, environ); +} + +export int execle(const char *path, const char *arg0, ...) +{ + va_list args; + va_start(args, arg0); + + int argc = 1; + while (va_arg(args, const char *)) + argc++; + va_end(args); + + char *argv[argc + 1]; + va_start(args, arg0); + argv[0] = (char *)arg0; + for (int i = 1; i < argc; i++) + argv[i] = va_arg(args, char *); + + argv[argc] = NULL; + + char *const *envp = va_arg(args, char *const *); + va_end(args); + + return execve(path, argv, envp); +} + +export int execlp(const char *file, const char *arg0, ...) +{ + va_list args; + va_start(args, arg0); + + int argc = 1; + while (va_arg(args, const char *)) + argc++; + + va_end(args); + + char *argv[argc + 1]; + va_start(args, arg0); + argv[0] = (char *)arg0; + for (int i = 1; i < argc; i++) + argv[i] = va_arg(args, char *); + + argv[argc] = NULL; + va_end(args); + + return execvp(file, argv); +} + +export int execv(const char *path, char *const argv[]) +{ + return execve(path, argv, environ); +} + +export int execve(const char *path, char *const argv[], char *const envp[]) +{ + return __check_errno(call_execve(path, argv, envp), -1); +} + +export int execvp(const char *file, char *const argv[]) +{ + if (strchr(file, '/')) + return execve(file, argv, environ); + + char *path = getenv("PATH"); + if (!path) + { + errno = ENOENT; + return -1; + } + + char *p = strtok(path, ":"); + while (p) + { + char fullpath[PATH_MAX]; + snprintf(fullpath, sizeof(fullpath), "%s/%s", p, file); + execve(fullpath, argv, environ); + if (errno != ENOENT && errno != ENOTDIR) + return -1; + p = strtok(NULL, ":"); + } + + errno = ENOENT; + return -1; +} + export void _exit(int); export int fchown(int, uid_t, gid_t); export int fchdir(int); export int fdatasync(int); -export pid_t fork(void); + +export pid_t fork(void) +{ + return __check_errno(call_fork(), -1); +} + export long int fpathconf(int, int); export int fsync(int); export int ftruncate(int, off_t); @@ -79,7 +197,13 @@ export int lockf(int, int, off_t); export off_t lseek(int, off_t, int); export int nice(int); export long int pathconf(const char *, int); -export int pause(void); + +export int pause(void) +{ + printf("pause() is unimplemented\n"); + return __check_errno(-ENOSYS, -1); +} + export int pipe(int[2]); export ssize_t pread(int, void *, size_t, off_t); export int pthread_atfork(void (*)(void), void (*)(void), void (*)(void)); @@ -95,10 +219,31 @@ export int setregid(gid_t, gid_t); export int setreuid(uid_t, uid_t); export pid_t setsid(void); export int setuid(uid_t); -export unsigned int sleep(unsigned int); + +export unsigned int sleep(unsigned int seconds) +{ + unsigned int unslept = alarm(0); /* Cancel any existing alarm */ + if (unslept > 0) + { + alarm(unslept); /* Restore the previous alarm if it was set */ + return unslept; + } + + alarm(seconds); /* Set the alarm for the requested sleep time */ + pause(); /* Suspend execution until a signal is received */ + + unslept = alarm(0); /* Cancel the alarm and get the remaining time */ + return unslept; +} + export void swab(const void *, void *, ssize_t); export int symlink(const char *, const char *); -export void sync(void); + +export void sync(void) +{ + printf("sync() is unimplemented\n"); +} + export long int sysconf(int); export pid_t tcgetpgrp(int); export int tcsetpgrp(int, pid_t);