From b99e0f9bd0dfcf6f1b3d33534ea78f8fb33be92a Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 27 Jul 2013 18:23:26 +0800 Subject: [PATCH] Usermode/libc - Improved strerror, added some basic time functions --- Usermode/Libraries/libc.so_src/Makefile | 2 +- Usermode/Libraries/libc.so_src/env.c | 74 +++++++++++++++++-- Usermode/Libraries/libc.so_src/errno.c | 36 ++++++--- .../libc.so_src/include_exp/errno.enum.h | 12 +-- .../libc.so_src/include_exp/signal.h | 39 +++++++++- .../libc.so_src/include_exp/stdlib.h | 1 + Usermode/Libraries/libc.so_src/perror.c | 5 +- Usermode/Libraries/libc.so_src/signals.c | 37 +++++++++- Usermode/Libraries/libc.so_src/stub.c | 4 +- Usermode/Libraries/libc.so_src/time.c | 69 +++++++++++++++++ 10 files changed, 247 insertions(+), 32 deletions(-) mode change 100644 => 100755 Usermode/Libraries/libc.so_src/include_exp/errno.enum.h diff --git a/Usermode/Libraries/libc.so_src/Makefile b/Usermode/Libraries/libc.so_src/Makefile index c8f4e5d3..7b345871 100644 --- a/Usermode/Libraries/libc.so_src/Makefile +++ b/Usermode/Libraries/libc.so_src/Makefile @@ -4,7 +4,7 @@ -include ../Makefile.cfg CPPFLAGS += -CFLAGS += -Werror -Wextra +CFLAGS += -Wall -Werror -Wextra ASFLAGS += LDFLAGS += -Map map.txt diff --git a/Usermode/Libraries/libc.so_src/env.c b/Usermode/Libraries/libc.so_src/env.c index b38e279f..e1b5d81d 100644 --- a/Usermode/Libraries/libc.so_src/env.c +++ b/Usermode/Libraries/libc.so_src/env.c @@ -4,31 +4,93 @@ */ #include #include +#include // === GLOBALS === -char **_envp = NULL; +char **environ = NULL; +static char **expected_environ = NULL; +static int num_allocated_slots; // === CODE === char *getenv(const char *name) { - char **env; char *env_str; int len; - if(!_envp) return NULL; + if(!environ) return NULL; if(!name) return NULL; len = strlen((char*)name); - env = _envp; - while(*env) + for( char **env = environ; *env; env ++ ) { env_str = *env; if(strncmp(name, env_str, len) == 0 && env_str[len] == '=') { return env_str+len+1; } - env ++; } return NULL; } + + +int putenv(char *string) +{ + char *eqpos = strchr(string, '='); + if( !eqpos ) { + errno = EINVAL; + return -1; + } + size_t namelen = eqpos - string; + + static const int alloc_step = 10; + if( expected_environ == NULL || expected_environ != environ ) + { + if( expected_environ ) + free(expected_environ); + + int envc = 0; + // Take a copy + for( char **env = environ; *env; env ++ ) + envc ++; + envc ++; // NULL termination + envc ++; // assume we're adding a new value + + num_allocated_slots = (envc + alloc_step-1) / alloc_step * alloc_step; + + expected_environ = malloc(num_allocated_slots*sizeof(char*)); + if(!expected_environ) + return 1; + + int idx = 0; + for( char **env = environ; *env; env ++ ) + expected_environ[idx++] = *env; + expected_environ[idx++] = NULL; + + environ = expected_environ; + } + + int envc = 0; + for( char **env = environ; *env; env ++, envc++ ) + { + if( strncmp(*env, string, namelen) != 0 ) + continue ; + if( *env[namelen] != '=' ) + continue ; + *env = string; + return 0; + } + if( num_allocated_slots >= envc+1 ) + { + num_allocated_slots += alloc_step; + expected_environ = realloc(expected_environ, num_allocated_slots*sizeof(char*)); + if(!expected_environ) + return 1; + environ = expected_environ; + } + environ[envc] = string; + environ[envc+1] = NULL; + + return 0; +} + diff --git a/Usermode/Libraries/libc.so_src/errno.c b/Usermode/Libraries/libc.so_src/errno.c index b5fe9587..af369b12 100644 --- a/Usermode/Libraries/libc.so_src/errno.c +++ b/Usermode/Libraries/libc.so_src/errno.c @@ -17,20 +17,38 @@ EXPORT int *libc_geterrno() EXPORT char *strerror(int errnum) { - switch(errnum) + switch((enum libc_eErrorNumbers)errnum) { case EOK: return "Success"; - case EISDIR: return "Is a directory"; - case ENOTDIR: return "Not a directory"; case ENOSYS: return "Invalid instruction/syscall"; + case EINVAL: return "Bad argument(s)"; + case EBADF: return "Invalid file"; + case ENOMEM: return "No free memory"; + case EACCES: return "Not permitted"; + case EBUSY: return "Resource is busy"; + case ERANGE: return "Value out of range"; + case ENOTFOUND: return "Item not found"; + case EROFS: return "Read only filesystem"; + case ENOTIMPL: return "Not implimented"; case ENOENT: return "No such file or directory"; - case EINVAL: return "Bad arguments"; - case EPERM: return "Permissions error"; - default: - _SysDebug("strerror: errnum=%i unk", errnum); - errno = EINVAL; - return "unknown error"; + case EEXIST: return "Already exists"; + case ENFILE: return "Too many open files"; + case ENOTDIR: return "Not a directory"; + case EISDIR: return "Is a directory"; + case EIO: return "IO Error"; + case EINTR: return "Interrupted"; + case EWOULDBLOCK: return "Operation would have blocked"; + case ENODEV: return "No such device"; + case EADDRNOTAVAIL: return "Address not avaliable"; + case EINPROGRESS: return "Operation in process"; + case EPERM: return "Operation not permitted"; + case EAGAIN: return "Try again"; + case EALREADY: return "Operation was no-op"; + case EINTERNAL: return "Internal error"; } + _SysDebug("strerror: errnum=%i unk", errnum); + errno = EINVAL; + return "unknown error"; } EXPORT int strerror_r(int errnum, char *buf, size_t bufsiz) diff --git a/Usermode/Libraries/libc.so_src/include_exp/errno.enum.h b/Usermode/Libraries/libc.so_src/include_exp/errno.enum.h old mode 100644 new mode 100755 index 831ab658..be953d48 --- a/Usermode/Libraries/libc.so_src/include_exp/errno.enum.h +++ b/Usermode/Libraries/libc.so_src/include_exp/errno.enum.h @@ -1,5 +1,5 @@ -enum { +enum libc_eErrorNumbers { EOK, ENOSYS, // Invalid Instruction EINVAL, // Invalid Paramater @@ -9,7 +9,7 @@ enum { EBUSY, // Resource is busy ERANGE, // Value out of range ENOTFOUND, // Item not found - EREADONLY, // Read only (duplicate with EROFS?) + EROFS, // Read only ENOTIMPL, // Not implemented ENOENT, // No entry? EEXIST, // Already exists @@ -22,14 +22,14 @@ enum { ENODEV, // ??? EADDRNOTAVAIL, // ? EINPROGRESS, // ? - EROFS, EPERM, // Permissions error EAGAIN, // Try again - EALREADY, // Operation was a NOP - EINTERNAL, // Internal Error - NUM_ERRNO + + EINTERNAL // Internal Error }; + +#define NUM_ERRNO (EINTERNAL+1) diff --git a/Usermode/Libraries/libc.so_src/include_exp/signal.h b/Usermode/Libraries/libc.so_src/include_exp/signal.h index c2d03e15..e25db034 100644 --- a/Usermode/Libraries/libc.so_src/include_exp/signal.h +++ b/Usermode/Libraries/libc.so_src/include_exp/signal.h @@ -36,10 +36,43 @@ extern int raise(int sig); #define SIGUSR1 16 #define SIGUSR2 17 -#define SIGPIPE 1001 -#define SIGCHLD 1002 +#define SIGSTOP 30 // Stop process +#define SIGTSTP 31 // ? ^Z +#define SIGTTIN 32 // Background process read TTY +#define SIGTTOU 33 // Background process write TTY +#define SIGPIPE 34 +#define SIGCHLD 35 +#define SIGWINCH 36 -typedef int sigset_t; +typedef long long unsigned int sigset_t; +extern int sigemptyset(sigset_t *set); +extern int sigfillset(sigset_t *set); + +typedef struct siginfo_s siginfo_t; + +struct siginfo_s +{ + int si_signo; + int si_errno; + int si_code; + int si_trapno; + pid_t si_pid; + uid_t si_uid; + int si_status; + // TODO: There's others +}; + +struct sigaction +{ + sighandler_t sa_handler; + //void (*sa_sigaction)(int, siginfo_t *, void *); + sigset_t sa_mask; + int sa_flags; +}; + +#define SA_NOCLDSTOP 0x001 + +extern int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact); #endif diff --git a/Usermode/Libraries/libc.so_src/include_exp/stdlib.h b/Usermode/Libraries/libc.so_src/include_exp/stdlib.h index bbf76eba..2bfb00d2 100644 --- a/Usermode/Libraries/libc.so_src/include_exp/stdlib.h +++ b/Usermode/Libraries/libc.so_src/include_exp/stdlib.h @@ -76,6 +76,7 @@ extern long long int llabs(long long int j); /* --- Environment --- */ extern char *getenv(const char *name); +extern int putenv(char *string); /* --- Search/Sort --- */ typedef int (*_stdlib_compar_t)(const void *, const void *); diff --git a/Usermode/Libraries/libc.so_src/perror.c b/Usermode/Libraries/libc.so_src/perror.c index 0431635d..53c01f89 100644 --- a/Usermode/Libraries/libc.so_src/perror.c +++ b/Usermode/Libraries/libc.so_src/perror.c @@ -7,8 +7,11 @@ */ #include #include +#include void perror(const char *s) { - fprintf(stderr, "%s: Error (%i)\n", s, errno); + int errnum = errno; + _SysDebug("perror(): %s: Error (%i) %s", s, errnum, strerror(errnum)); + fprintf(stderr, "%s: Error (%i) %s\n", s, errnum, strerror(errnum)); } diff --git a/Usermode/Libraries/libc.so_src/signals.c b/Usermode/Libraries/libc.so_src/signals.c index c33019e4..5e32fc86 100644 --- a/Usermode/Libraries/libc.so_src/signals.c +++ b/Usermode/Libraries/libc.so_src/signals.c @@ -6,20 +6,22 @@ #include #include #include "lib.h" +#include // === CONSTANTS === -#define NUM_SIGNALS 32 +#define NUM_SIGNALS 40 // === GLOBALS === -sighandler_t sighandlers[NUM_SIGNALS]; +struct sigaction sighandlers[NUM_SIGNALS]; // === CODE === sighandler_t signal(int num, sighandler_t handler) { sighandler_t prev; if(num < 0 || num >= NUM_SIGNALS) return NULL; - prev = sighandlers[num]; - sighandlers[num] = handler; + prev = sighandlers[num].sa_handler; + sighandlers[num].sa_handler = handler; + sighandlers[num].sa_mask = 0; return prev; } @@ -41,3 +43,30 @@ void abort(void) // raise(SIGABRT); _exit(-1); } + +// POSIX +int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact) +{ + if( signum < 0 || signum >= NUM_SIGNALS ) { + errno = EINVAL; + return 1; + } + + if( oldact ) + *oldact = sighandlers[signum]; + if( act ) + sighandlers[signum] = *act; + + return 0; +} + +int sigemptyset(sigset_t *set) +{ + *set = 0; + return 0; +} +int sigfillset(sigset_t *set) +{ + *set = -1; + return 0; +} diff --git a/Usermode/Libraries/libc.so_src/stub.c b/Usermode/Libraries/libc.so_src/stub.c index f723d544..e20deae3 100644 --- a/Usermode/Libraries/libc.so_src/stub.c +++ b/Usermode/Libraries/libc.so_src/stub.c @@ -28,7 +28,7 @@ extern void _stdio_init(void); extern void _call_atexit_handlers(void); // === GLOBALS === -extern char **_envp; +extern char **environ; // --- CPU Features --- #if USE_CPUID tCPUID gCPU_Features; @@ -46,7 +46,7 @@ tCPUID gCPU_Features; int SoMain(UNUSED(uintptr_t, BaseAddress), UNUSED(int, argc), UNUSED(char **, argv), char **envp) { // Init for env.c - _envp = envp; + environ = envp; #if 0 { diff --git a/Usermode/Libraries/libc.so_src/time.c b/Usermode/Libraries/libc.so_src/time.c index aa4b2de8..412475b3 100644 --- a/Usermode/Libraries/libc.so_src/time.c +++ b/Usermode/Libraries/libc.so_src/time.c @@ -7,6 +7,7 @@ */ #include #include +#include clock_t clock(void) { @@ -20,3 +21,71 @@ time_t time(time_t *t) *t = ret; return ret; } + +static struct tm static_tm; + +struct tm *localtime(const time_t *timer) +{ + struct tm *ret = &static_tm; + + // TODO: This breaks on negative timestamps + + int64_t day = *timer / (1000*60*60*24); + int64_t iday = *timer % (1000*60*60*24); + + ret->tm_sec = (iday / 1000) % 60;; + ret->tm_min = (iday / (1000*60)) % 60; + ret->tm_hour = (iday / (1000*60*60)); + ret->tm_year = 0; + ret->tm_mon = 0; + ret->tm_mday = 0; + ret->tm_wday = (day + 6) % 7; // 1 Jan 2000 was a saturday + ret->tm_yday = 0; + ret->tm_isdst = 0; // Fuck DST + return ret; +} + +static inline size_t MIN(size_t a, size_t b) { return a < b ? a : b; } +static size_t _puts(char * restrict s, size_t maxsize, size_t ofs, const char *str, size_t len) +{ + if( s && ofs < maxsize ) { + size_t addlen = MIN(len, maxsize-1-ofs); + memcpy(s+ofs, str, addlen); + } + return len; +} + +size_t strftime(char*restrict s, size_t maxsize, const char*restrict format, const struct tm*restrict timeptr) +{ + size_t ofs = 0; + + while( *format ) + { + const char *restrict start = format; + while( *format && *format != '%' ) + format ++; + if( format != start ) + ofs += _puts(s, maxsize, ofs, start, format-start); + if( *format == 0 ) + break; + format ++; + switch(*format++) + { + case 0: format--; break; + case '%': ofs += _puts(s, maxsize, ofs, format-1, 1); break; + case 'd': // The day of the month as a decimal number (range 01 to 31). + { + char tmp[2] = {'0','0'}; + tmp[0] += (timeptr->tm_mday / 10) % 10; + tmp[1] += timeptr->tm_mday % 10; + ofs += _puts(s, maxsize, ofs, tmp, 2); + } + break; + default: + _SysDebug("TODO: strftime('...%%%c...')", format[-1]); + break; + } + } + + return ofs; +} -- 2.20.1