diff --git a/arch/amd64/include/u.h b/arch/amd64/include/u.h index 96427ec..399825b 100644 --- a/arch/amd64/include/u.h +++ b/arch/amd64/include/u.h @@ -25,6 +25,8 @@ typedef int32_t pid_t; typedef uint32_t Rune; typedef union FPdbleword FPdbleword; typedef uintptr jmp_buf[10]; // for registers. +typedef long off_t; +typedef long ptrdiff_t; #define JMPBUFSP 6 #define JMPBUFPC 7 diff --git a/hacking b/hacking index b1ab4f1..eb37bc6 160000 --- a/hacking +++ b/hacking @@ -1 +1 @@ -Subproject commit b1ab4f1a08b9b7156ecb4034527bfc87e159186e +Subproject commit eb37bc6013a49cf27600b5b3df9fbc598971bf34 diff --git a/sys/include/posix.h b/sys/include/posix.h new file mode 100644 index 0000000..aecc055 --- /dev/null +++ b/sys/include/posix.h @@ -0,0 +1,152 @@ +/* + * This file is part of Jehanne. + * + * Copyright (C) 2017 Giacomo Tesio + * + * Jehanne 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, version 3 of the License. + * + * Jehanne 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 Jehanne. If not, see . + */ + +/* + * This API is designed to help porting other POSIX compliant C + * libraries (such as newlib or musl) to Jehanne, so that they can be + * used to port further software. + * + * POSIX_* functions provide a facade between the Jehanne's libc and + * the POSIX 1-2008 semantics. + * + * libposix_* functions provide the configuration point. + * + * #include + * #include + */ +typedef unsigned long clock_t; + +#define __POSIX_EXIT_PREFIX "posix error " +#define __POSIX_SIGNAL_PREFIX "posix: " + +extern void POSIX_exit(int code) __attribute__((noreturn)); +extern int POSIX_close(int *errnop, int file); +extern int POSIX_execve(int *errnop, const char *name, char * const*argv, char * const*env); +extern int POSIX_fork(int *errnop); +extern int POSIX_fstat(int *errnop, int file, void *stat); +extern int POSIX_getpid(int *errnop); +extern int POSIX_isatty(int *errnop, int file); +extern int POSIX_kill(int *errnop, int pid, int sig); +extern int POSIX_link(int *errnop, const char *old, const char *new); +extern off_t POSIX_lseek(int *errnop, int fd, off_t pos, int whence); +extern int POSIX_open(int *errnop, const char *name, int flags, int mode); +extern long POSIX_read(int *errnop, int fd, char *buf, size_t len); +extern int POSIX_stat(int *errnop, const char *file, void *stat); +extern clock_t POSIX_times(int *errnop, void *tms); +extern int POSIX_unlink(int *errnop, const char *name); +extern int POSIX_wait(int *errnop, int *status); +extern long POSIX_write(int *errnop, int fd, const void *buf, size_t len); +extern int POSIX_gettimeofday(int *errnop, void *timeval, void *timezone); +extern char* POSIX_getenv(int *errnop, const char *name); +extern void *POSIX_sbrk(int *errnop, ptrdiff_t incr); +extern void * POSIX_malloc(int *errnop, size_t size); +extern void *POSIX_realloc(int *errnop, void *ptr, size_t size); +extern void *POSIX_calloc(int *errnop, size_t nelem, size_t size); +extern void POSIX_free(void *ptr); + +/* Library initialization + */ +#define _ERRNO_H // skip the Posix part, we just need the enum +#include + +/* Initialize libposix. Should call + * + * libposix_define_errno to set the value of each PosixError + * libposix_translate_error to translate error strings to PosixError + * libposix_set_stat_reader + * libposix_set_tms_reader + * libposix_set_timeval_reader + * libposix_set_timezone_reader + */ +typedef void (*PosixInit)(void); +extern void libposix_init(int argc, char *argv[], PosixInit init) __attribute__((noreturn)); + +/* Translate an error string to a PosixError, in the context of the + * calling function (typically a pointer to a POSIX_* function). + * + * Must return 0 if unable to identify a PosixError. + * + * Translators are tried in reverse registration order. + */ +typedef PosixError (*PosixErrorTranslator)(char* error, uintptr_t caller); + +/* Register a translation between Jehanne error strings and PosixErrors. + * If caller is not zero, it is a pointer to the calling + * functions to consider. Otherwise the translation will be tried whenever + * for any caller, after the specialized ones. + */ +extern int libposix_translate_error(PosixErrorTranslator translation, uintptr_t caller); + +/* define the value of a specific PosixError according to the library headers */ +extern int libposix_define_errno(PosixError e, int errno); + +/* Map a Dir to the stat structure expected by the library. + * + * Must return 0 on success or a PosixError on failure. + */ +typedef PosixError (*PosixStatReader)(void *statp, const Dir *dir); + +extern int libposix_set_stat_reader(PosixStatReader reader); + +/* Map a time provided by times() tms structure + * expected by the library. + * + * Must return 0 on success or a PosixError on failure. + */ +typedef PosixError (*PosixTMSReader)(void *tms, + unsigned int proc_userms, unsigned int proc_sysms, + unsigned int children_userms, unsigned int children_sysms); + +extern int libposix_set_tms_reader(PosixTMSReader reader); + +/* Map a time provided by gmtime() or localtime() to a timeval + * expected by the library. + * + * Must return 0 on success or a PosixError on failure. + */ +typedef PosixError (*PosixTimevalReader)(void *timeval, const Tm *time); + +extern int libposix_set_timeval_reader(PosixTimevalReader reader); + +/* Map a time provided by gmtime() or localtime() to a timezone + * expected by the library. + * + * Must return 0 on success or a PosixError on failure. + */ +typedef PosixError (*PosixTimezoneReader)(void *timezone, const Tm *time); + +extern int libposix_set_timezone_reader(PosixTimezoneReader reader); + +/* Map the POSIX_open flag and mode to Jehanne's arguments to open + * or create. + * + * omode is a pointer to the open/create omode argument + * cperm is a pointer to the create perm argument that must be filled + * only if O_CREATE has been set in mode. + * + * Must return 0 on success or a PosixError on failure. + */ +typedef PosixError (*PosixOpenTranslator)(int flag, int mode, long *omode, long *cperm); + +extern int libposix_translate_open(PosixOpenTranslator translation); + +extern int libposix_translate_seek_whence(int seek_set, int seek_cur, int seek_end); + +typedef int (*PosixSignalTrampoline)(int signal); + +extern int libposix_set_signal_trampoline(PosixSignalTrampoline trampoline); diff --git a/sys/posix/newlib/.gitignore b/sys/posix/newlib/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/sys/posix/newlib/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/sys/src/lib/libs.json b/sys/src/lib/libs.json index dac1f43..503903a 100644 --- a/sys/src/lib/libs.json +++ b/sys/src/lib/libs.json @@ -22,6 +22,7 @@ "/sys/src/lib/mp/", "/sys/src/lib/ndb/", "/sys/src/lib/plumb/", + "/sys/src/lib/posix/", "/sys/src/lib/regexp/", "/sys/src/lib/sec/", "/sys/src/lib/stdio/", diff --git a/sys/src/lib/posix/.gitignore b/sys/src/lib/posix/.gitignore new file mode 100644 index 0000000..349825e --- /dev/null +++ b/sys/src/lib/posix/.gitignore @@ -0,0 +1,4 @@ +libc.h +libc_wrapper.h +*.a +libc.sed diff --git a/sys/src/lib/posix/build.json b/sys/src/lib/posix/build.json new file mode 100644 index 0000000..8147b7a --- /dev/null +++ b/sys/src/lib/posix/build.json @@ -0,0 +1,22 @@ +{ + "LibPosix": { + "Cflags": [ + "-fasm", + "-I." + ], + "Include": [ + "../lib.json" + ], + "Install": "/arch/$ARCH/lib/", + "Library": "libposix.a", + "SourceFiles": [ + "environment.c", + "errors.c", + "files.c", + "initlib.c", + "memory.c", + "others.c", + "processes.c" + ] + } +} diff --git a/sys/src/lib/posix/environment.c b/sys/src/lib/posix/environment.c new file mode 100644 index 0000000..7cee478 --- /dev/null +++ b/sys/src/lib/posix/environment.c @@ -0,0 +1,158 @@ +/* + * This file is part of Jehanne. + * + * Copyright (C) 2017 Giacomo Tesio + * + * This is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, version 3 of the License. + * + * Jehanne 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 Affero General Public License + * along with Jehanne. If not, see . + */ +#include +#include +#include +#include "internal.h" + +static char* __env[1] = { nil }; +char **environ = &__env[0]; /* how to map this to #e? */ + +/* In POSIX, getenv returns strings that must not be freed by the caller. + * In Jehanne (and Plan9) getenv returns strings obtained with malloc(). + * + * Thus we need a more complex managememnt to avoid that calling + * getenv("PATH") several times would leak memory. + * + * We use a sorted linked list of outputs returned by Jehanne's getenv + * and search it before actually calling it. + */ + +#define MAX_ENVNAME_LEN (127+5+1) + +typedef struct EnvVar EnvVar; +struct EnvVar +{ + char* name; + char* value; + EnvVar* next; +}; + +static RWLock list_lock; +static EnvVar* list_start; + +static void +free_env(EnvVar* e) +{ + free(e->name); + free(e->value); + free(e); +} + +static void +put_in_list(EnvVar* newenv) +{ + int cmp; + EnvVar *e, **o; + + wlock(&list_lock); + + e = list_start; + o = &list_start; + while(e != nil){ + cmp = strcmp(e->name, newenv->name); + if(cmp < 0){ + // check next (alphabetically sorted) + o = &e->next; + e = e->next; + } else { + if(cmp > 0){ + // reached the next variable + newenv->next = e; + } else { + // found the variable to replace + newenv->next = e->next; + free_env(e); + } + e = nil; // quit the lookup + } + } + + *o = newenv; + + wunlock(&list_lock); +} + +char * +POSIX_getenv(int *errno, const char *name) +{ + EnvVar* e; + if(name == nil || name[0] == 0 || strchr(name, '=') == nil){ + *errno = PosixEINVAL; + return nil; + } + + rlock(&list_lock); + e = list_start; + while(e != nil){ + if(strcmp(name, e->name) == 0) + break; + e = e->next; + } + runlock(&list_lock); + if(e != nil) + return e->value; + + e = malloc(sizeof(EnvVar)); + e->next = nil; + e->value = nil; // see free_env + e->name = strdup(name); + if(e->name == nil){ + free_env(e); + *errno = PosixENOMEM; + return nil; + } + e->value = getenv(name); + if(e->value == nil){ + free_env(e); + return nil; + } + + put_in_list(e); + return e->value; +} + +void +__libposix_setup_exec_environment(char * const *env) +{ + int fd, len; + char **e, *start, *end; + char ename[MAX_ENVNAME_LEN]; + + if(env == nil || env[0] == nil) + return; + strcpy(ename, "#e/"); + for(e = (char **)env; (start = *e); e++) { + end = strchr(start, '='); + if(!end || start==end) + continue; /* not in "var=val" format */ + len = end-start; + if(len > 127) + len = 127; + memcpy(ename+3, start, len); + ename[3+len] = 0; + fd = ocreate(ename, OWRITE, 0666); + if(fd < 0) + continue; + end++; /* after '=' */ + len = strlen(end); + sys_pwrite(fd, end, len, -1); + sys_close(fd); + } +} + diff --git a/sys/src/lib/posix/errors.c b/sys/src/lib/posix/errors.c new file mode 100644 index 0000000..b4df4c6 --- /dev/null +++ b/sys/src/lib/posix/errors.c @@ -0,0 +1,159 @@ +/* + * This file is part of Jehanne. + * + * Copyright (C) 2017 Giacomo Tesio + * + * This is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, version 3 of the License. + * + * Jehanne 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 Affero General Public License + * along with Jehanne. If not, see . + */ +#include +#include +#include +#include "internal.h" + +int *__libposix_errors_codes; + +typedef struct PosixErrorMap PosixErrorMap; +struct PosixErrorMap +{ + PosixErrorTranslator translate; + PosixErrorMap *next; +}; + +typedef struct CustomErrorMap CustomErrorMap; +struct CustomErrorMap +{ + uintptr_t caller; + PosixErrorMap *head; + CustomErrorMap *next; +}; + +static PosixErrorMap *generic_handlers; +static CustomErrorMap *custom_handlers; + +void +__libposix_errors_check_conf(void) +{ + int i; + /* check that all required configurations has been provided */ + for(i = 0; i < ERRNO_LAST-ERRNO_FIRST; ++i){ + if(__libposix_errors_codes[i] == 0) + sysfatal("libposix: PosixError %d is undefined", i + ERRNO_FIRST); + } + if(generic_handlers == nil) + sysfatal("libposix: no generic error handler"); +} + +int +libposix_define_errno(PosixError e, int errno) +{ + if(e < ERRNO_FIRST || e > ERRNO_LAST) + return 0; + __libposix_errors_codes[e - ERRNO_FIRST] = errno; + return 1; +} + +static int +register_translation(PosixErrorMap **map, PosixErrorTranslator translation) +{ + PosixErrorMap *entry = malloc(sizeof(PosixErrorMap)); + if(entry == nil) + return 0; + entry->translate = translation; + entry->next = *map; + *map = entry; + return 1; +} + +int +libposix_translate_error(PosixErrorTranslator translation, uintptr_t caller) +{ + CustomErrorMap **list = nil; + + if(__libposix_initialized()) + return 0; + if(translation == nil) + return 0; + if(caller == 0) + return register_translation(&generic_handlers, translation); + list = &custom_handlers; + while(*list != nil) + { + if((*list)->caller == caller) + break; + list = &(*list)->next; + } + if(*list == nil){ + *list = malloc(sizeof(CustomErrorMap)); + (*list)->next = nil; + (*list)->caller = caller; + (*list)->head = nil; + } + return register_translation(&(*list)->head, translation); +} + +int +__libposix_get_errno(PosixError e) +{ + if(e == 0) + return 0; + if(e < 0){ + /* this way we allow a translator to return a + * non-posix errno as a negative number that will not + * collide with the indexes declared in PosixError enum + */ + return (int)-e; + } + if(e < ERRNO_FIRST || e > ERRNO_LAST) + return PosixEINVAL; + return __libposix_errors_codes[e - ERRNO_FIRST]; +} + +static PosixError +get_posix_error(PosixErrorMap *translations, char *err, uintptr_t caller) +{ + PosixError e = 0; + while(translations != nil) + { + e = translations->translate(err, caller); + if(e != 0) + return e; + translations = translations->next; + } + return PosixEINVAL; +} + +int +__libposix_translate_errstr(uintptr_t caller) +{ + CustomErrorMap *handler; + PosixError perr = 0; + char err[ERRMAX]; + int ret; + + if(sys_errstr(err, ERRMAX) < 0) + return __libposix_get_errno(PosixEINVAL); + + handler = custom_handlers; + while(handler != nil) + { + if(handler->caller == caller) + break; + } + if(handler != nil) + perr = get_posix_error(handler->head, err, caller); + if(perr == 0) + perr = get_posix_error(generic_handlers, err, caller); + ret = __libposix_get_errno(perr); + sys_errstr(err, ERRMAX); + return ret; +} diff --git a/sys/src/lib/posix/files.c b/sys/src/lib/posix/files.c new file mode 100644 index 0000000..b2429cf --- /dev/null +++ b/sys/src/lib/posix/files.c @@ -0,0 +1,301 @@ +/* + * This file is part of Jehanne. + * + * Copyright (C) 2017 Giacomo Tesio + * + * This is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, version 3 of the License. + * + * Jehanne 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 Affero General Public License + * along with Jehanne. If not, see . + */ +#include +#include +#include +#include "internal.h" + +static PosixStatReader __libposix_stat_reader; +static PosixOpenTranslator __libposix_open_translation; + +typedef enum SeekTypes +{ + SeekSet = 0, + SeekCurrent = 1, + SeekEnd = 2 +} SeekTypes; +static int *__libposix_seek_types; + +void +__libposix_files_check_conf(void) +{ + if(__libposix_stat_reader == nil) + sysfatal("libposix: no stat reader"); + if(__libposix_open_translation == nil) + sysfatal("libposix: no open translator"); + if(__libposix_seek_types == nil) + sysfatal("libposix: no seek translations"); +} + +int +libposix_translate_open(PosixOpenTranslator translation) +{ + if(__libposix_initialized()) + return 0; + if(translation == nil) + return 0; + __libposix_open_translation = translation; + return 1; +} + +int +libposix_set_stat_reader(PosixStatReader reader) +{ + if(__libposix_initialized()) + return 0; + if(reader == nil) + return 0; + __libposix_stat_reader = reader; + return 1; +} + +int +libposix_translate_seek_whence(int seek_set, int seek_cur, int seek_end) +{ + if(__libposix_initialized()) + return 0; + if(seek_set == seek_cur) + return 0; + if(seek_set == seek_end) + return 0; + if(seek_cur == seek_end) + return 0; + __libposix_seek_types = malloc(sizeof(int)*3); + if(__libposix_seek_types == nil) + return 0; + + __libposix_seek_types[SeekSet] = seek_set; + __libposix_seek_types[SeekCurrent] = seek_cur; + __libposix_seek_types[SeekEnd] = seek_end; + return 1; +} + +static SeekTypes +find_seek_type(int whence) +{ + if(__libposix_seek_types[SeekSet] == whence) + return SeekSet; + if(__libposix_seek_types[SeekCurrent] == whence) + return SeekCurrent; + if(__libposix_seek_types[SeekEnd] == whence) + return SeekEnd; + return -1; +} + +int +POSIX_open(int *errnop, const char *name, int flags, int mode) +{ + long omode = 0, cperm = 0; + PosixError e; + int f; + + if(name == nil){ + *errnop = __libposix_get_errno(PosixENOENT); + return -1; + } + e = __libposix_open_translation(flags, mode, &omode, &cperm); + if(e != 0){ + *errnop = __libposix_get_errno(e); + return -1; + } + if(cperm == 0){ + f = sys_open(name, omode); + } else { + f = ocreate(name, (unsigned int)omode, (unsigned int)cperm); + } + if(f >= 0) + return f; + *errnop = __libposix_translate_errstr((uintptr_t)POSIX_open); + return -1; +} + +long +POSIX_read(int *errnop, int fd, char *buf, size_t len) +{ + long r; + + if(fd < 0){ + *errnop = __libposix_get_errno(PosixEBADF); + return -1; + } + r = sys_pread(fd, buf, len, -1); + if(r < 0){ + *errnop = __libposix_translate_errstr((uintptr_t)POSIX_read); + return -1; + } + return r; +} + +long +POSIX_write(int *errnop, int fd, const void *buf, size_t len) +{ + long w; + + if(fd < 0){ + *errnop = __libposix_get_errno(PosixEBADF); + return -1; + } + w = sys_pwrite(fd, buf, len, -1); + if(w < 0){ + *errnop = __libposix_translate_errstr((uintptr_t)POSIX_write); + return -1; + } + return w; +} + +off_t +POSIX_lseek(int *errnop, int fd, off_t pos, int whence) +{ + SeekTypes stype; + long r; + + stype = find_seek_type(whence); + if(stype == -1){ + *errnop = __libposix_get_errno(PosixEINVAL); + return -1; + } + if(fd < 0){ + *errnop = __libposix_get_errno(PosixEBADF); + return -1; + } + r = sys_seek(fd, pos, stype); + if(r >= 0) + return r; + *errnop = __libposix_translate_errstr((uintptr_t)POSIX_lseek); + return -1; +} + +int +POSIX_close(int *errno, int file) +{ + long ret; + + ret = sys_close(file); + switch(ret){ + case 0: + return 0; + case ~0: + *errno = __libposix_translate_errstr((uintptr_t)POSIX_close); + break; + default: + *errno = ret; + break; + } + return -1; +} + +int +POSIX_link(int *errnop, const char *old, const char *new) +{ + int err; + /* let choose the most appropriate error */ + if(old == nil || new == nil || old[0] == 0 || new[0] == 0) + err = __libposix_get_errno(PosixENOENT); + else if(access(new, AEXIST) == 0) + err = __libposix_get_errno(PosixEEXIST); + else if(access(old, AEXIST) == 0) + err = __libposix_get_errno(PosixENOENT); + else { + /* Jehanne does not support links. + * A custom overlay filesystem might support them in + * the future but so far it does not exists yet. + * + * We return EXDEV so that a posix compliant caller + * can fallback to a simple copy. + */ + err = __libposix_get_errno(PosixEXDEV); + } + *errnop = err; + return -1; +} + +int +POSIX_unlink(int *errnop, const char *name) +{ + long ret; + if(name == nil || name[0] == 0){ + *errnop = __libposix_get_errno(PosixENOENT); + return -1; + } + ret = sys_remove(name); + switch(ret){ + case 0: + return 0; + case ~0: + *errnop = __libposix_translate_errstr((uintptr_t)POSIX_unlink); + break; + default: + *errnop = ret; + break; + } + return -1; +} + +int +POSIX_fstat(int *errnop, int file, void *pstat) +{ + Dir *d; + PosixError e; + if(pstat == nil){ + *errnop = __libposix_get_errno(PosixEOVERFLOW); + return -1; + } + if(file < 0){ + *errnop = __libposix_get_errno(PosixEBADF); + return -1; + } + d = dirfstat(file); + if(d == nil) + { + *errnop = __libposix_translate_errstr((uintptr_t)POSIX_fstat); + return -1; + } + e = __libposix_stat_reader(pstat, d); + free(d); + if(e == 0) + return 0; + *errnop = __libposix_get_errno(e); + return -1; +} + +int +POSIX_stat(int *errnop, const char *file, void *pstat) +{ + Dir *d; + PosixError e; + if(pstat == nil){ + *errnop = __libposix_get_errno(PosixEOVERFLOW); + return -1; + } + if(file == nil){ + *errnop = __libposix_get_errno(PosixEBADF); + return -1; + } + d = dirstat(file); + if(d == nil) + { + *errnop = __libposix_translate_errstr((uintptr_t)POSIX_stat); + return -1; + } + e = __libposix_stat_reader(pstat, d); + free(d); + if(e == 0) + return 0; + *errnop = __libposix_get_errno(e); + return -1; +} diff --git a/sys/src/lib/posix/initlib.c b/sys/src/lib/posix/initlib.c new file mode 100644 index 0000000..f720b70 --- /dev/null +++ b/sys/src/lib/posix/initlib.c @@ -0,0 +1,63 @@ +/* + * This file is part of Jehanne. + * + * Copyright (C) 2017 Giacomo Tesio + * + * This is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, version 3 of the License. + * + * Jehanne 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 Affero General Public License + * along with Jehanne. If not, see . + */ +#include +#include +#include +#include "internal.h" + +extern int *__libposix_errors_codes; +static int __initialized; + +static void +libposix_check_configuration(void) +{ + __libposix_errors_check_conf(); + __libposix_files_check_conf(); + __libposix_processes_check_conf(); +} + +void +libposix_init(int argc, char *argv[], PosixInit init) +{ + extern int main(int, char**); + int error_codes[ERRNO_LAST-ERRNO_FIRST]; + int status; + + assert(__initialized == 0); + + /* initialize PosixErrors map */ + memset(error_codes, 0, sizeof(error_codes)); + __libposix_errors_codes=error_codes; + + if(!atnotify(__libposix_note_handler, 1)) + sysfatal("libposix: atnotify"); + + init(); + + libposix_check_configuration(); + + __initialized = 1; + status = main(argc, argv); + POSIX_exit(status); +} + +int +__libposix_initialized(void) +{ + return __initialized; +} diff --git a/sys/src/lib/posix/internal.h b/sys/src/lib/posix/internal.h new file mode 100644 index 0000000..962621c --- /dev/null +++ b/sys/src/lib/posix/internal.h @@ -0,0 +1,29 @@ +/* + * This file is part of Jehanne. + * + * Copyright (C) 2017 Giacomo Tesio + * + * This is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, version 3 of the License. + * + * Jehanne 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 Affero General Public License + * along with Jehanne. If not, see . + */ +extern void __libposix_files_check_conf(void); +extern void __libposix_errors_check_conf(void); +extern void __libposix_processes_check_conf(void); +extern int __libposix_initialized(void); + +extern int __libposix_get_errno(PosixError e); + +extern void __libposix_setup_exec_environment(char * const *env); + +extern int __libposix_translate_errstr(uintptr_t caller); + +extern int __libposix_note_handler(void *ureg, char *note); diff --git a/sys/src/lib/posix/memory.c b/sys/src/lib/posix/memory.c new file mode 100644 index 0000000..5a8ec32 --- /dev/null +++ b/sys/src/lib/posix/memory.c @@ -0,0 +1,90 @@ +/* + * This file is part of Jehanne. + * + * Copyright (C) 2017 Giacomo Tesio + * + * This is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, version 3 of the License. + * + * Jehanne 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 Affero General Public License + * along with Jehanne. If not, see . + */ +#include +#include +#include +#include "internal.h" + +void * +POSIX_sbrk(int *errnop, ptrdiff_t incr) +{ + void *p; + + p = segbrk(incr); + if(p != (void*)-1) + return p; + *errnop = __libposix_translate_errstr((uintptr_t)POSIX_sbrk); + return (void*)-1; +} + +void * +POSIX_malloc(int *errnop, size_t size) +{ + void *p; + + p = malloc(size); + if(p != nil) + return p; + *errnop = __libposix_get_errno(PosixENOMEM); + return nil; +} + +void * +POSIX_realloc(int *errnop, void *ptr, size_t size) +{ + void *p; + + p = realloc(ptr, size); + if(p != nil) + return p; + if(size == 0){ + if(ptr != nil){ + // POSIX 1-2008 requires an "implementation defined" errno + *errnop = __libposix_get_errno(PosixEINVAL); + } + } else { + *errnop = __libposix_get_errno(PosixENOMEM); + } + return nil; +} + +void * +POSIX_calloc(int *errnop, size_t nelem, size_t size) +{ + void *p; + + size = size * nelem; + if(size <= 0){ + // POSIX 1-2008 requires an "implementation defined" errno + *errnop = __libposix_get_errno(PosixEINVAL); + return nil; + } + p = malloc(size); + if(p != nil){ + memset(p, 0, size); + return p; + } + *errnop = __libposix_get_errno(PosixENOMEM); + return nil; +} + +void +POSIX_free(void *ptr) +{ + jehanne_free(ptr); +} diff --git a/sys/src/lib/posix/others.c b/sys/src/lib/posix/others.c new file mode 100644 index 0000000..fc4bed6 --- /dev/null +++ b/sys/src/lib/posix/others.c @@ -0,0 +1,56 @@ +/* + * This file is part of Jehanne. + * + * Copyright (C) 2017 Giacomo Tesio + * + * This is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, version 3 of the License. + * + * Jehanne 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 Affero General Public License + * along with Jehanne. If not, see . + */ +#include +#include +#include +#include "internal.h" + +int +POSIX_isatty(int *errnop, int fd) +{ + char buf[64]; + int l; + if(fd < 0){ + *errnop = __libposix_get_errno(PosixEBADF); + return 0; + } + if(sys_fd2path(fd, buf, sizeof(buf)) < 0){ + *errnop = __libposix_get_errno(PosixENOTTY); + return 0; + } + + l = strlen(buf); + if(l >= 9 && strcmp(buf+l-9, "/dev/cons") == 0) + return 1; + *errnop = __libposix_get_errno(PosixENOTTY); + return 0; +} + +clock_t +POSIX_times(int *errnop, void *buf) +{ + *errnop = __libposix_get_errno(PosixEINVAL); + return -1; +} + +int +POSIX_gettimeofday(int *errnop, void *timeval, void *timezone) +{ + *errnop = __libposix_get_errno(PosixEINVAL); + return -1; +} diff --git a/sys/src/lib/posix/processes.c b/sys/src/lib/posix/processes.c new file mode 100644 index 0000000..9ebd5f2 --- /dev/null +++ b/sys/src/lib/posix/processes.c @@ -0,0 +1,194 @@ +/* + * This file is part of Jehanne. + * + * Copyright (C) 2017 Giacomo Tesio + * + * This is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, version 3 of the License. + * + * Jehanne 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 Affero General Public License + * along with Jehanne. If not, see . + */ +#include +#include +#include +#include "internal.h" + +extern char **environ; + +static PosixSignalTrampoline __libposix_signal_trampoline; + +#define __POSIX_SIGNAL_PREFIX_LEN (sizeof(__POSIX_SIGNAL_PREFIX)-1) + +void +POSIX_exit(int code) +{ + char buf[64]; + + if(code == 0) + exits(nil); + snprint(buf, sizeof(buf), __POSIX_EXIT_PREFIX "%d", code); + exits(buf); +} + +int +POSIX_execve(int *errnop, const char *name, char * const*argv, char * const*env) +{ + long ret; + + // see http://pubs.opengroup.org/onlinepubs/9699919799/functions/exec.html + if(env == environ){ + /* just get a copy of the current environment */ + sys_rfork(RFENVG); + } else { + sys_rfork(RFCENVG); + __libposix_setup_exec_environment(env); + } + + ret = sys_exec(name, argv); + switch(ret){ + case 0: + return 0; + case ~0: + *errnop = __libposix_translate_errstr((uintptr_t)POSIX_execve); + break; + default: + *errnop = ret; + break; + } + return -1; +} + +int +POSIX_wait(int *errnop, int *status) +{ + Waitmsg *w; + char *s; + int ret = 0, pid; + + w = wait(); + if(w == nil){ + *errnop = __libposix_get_errno(PosixECHILD); + return -1; + } + pid = w->pid; + if(w->msg[0] != 0){ + s = strstr(w->msg, __POSIX_EXIT_PREFIX); + if(s){ + s += (sizeof(__POSIX_EXIT_PREFIX)/sizeof(char) - 1); + ret = atoi(s); + } else { + /* TODO: setup configurable interpretations */ + ret = 127; + } + } + if(status != nil) + *status = ret; + free(w); + return pid; +} + +static int +note_all_writable_processes(int *errnop, char *note) +{ + // TODO: loop over writable note files and post note. + *errnop = __libposix_get_errno(PosixEPERM); + return -1; +} + +int +POSIX_kill(int *errnop, int pid, int sig) +{ + char msg[64], file[128]; + int mode; + int ret; + + if(access("/proc", AEXEC) != 0){ + *errnop = __libposix_get_errno(PosixEPERM); + return -1; + } + + snprint(msg, sizeof(msg), __POSIX_SIGNAL_PREFIX "%d", sig); + switch(pid){ + case 0: + mode = PNGROUP; + break; + case -1: + return note_all_writable_processes(errnop, msg); + default: + if(pid < 0){ + mode = PNGROUP; + pid = -pid; + } else { + mode = PNPROC; + } + } + + snprint(file, sizeof(file), "/proc/%d/note", pid); + if(access(file, AWRITE) != 0){ + if(access(file, AEXIST) == 0) + *errnop = __libposix_get_errno(PosixEPERM); + else + *errnop = __libposix_get_errno(PosixESRCH); + return -1; + } + ret = postnote(mode, pid, msg); + if(ret != 0){ + *errnop = __libposix_translate_errstr((uintptr_t)POSIX_kill); + return -1; + } + return 0; +} + +int +POSIX_getpid(int *errnop) +{ + return getpid(); +} + +int +POSIX_fork(int *errnop) +{ + return fork(); +} + +static int +translate_jehanne_note(char *note) +{ + // TODO: implement + return 0; +} + +int +__libposix_note_handler(void *ureg, char *note) +{ + int sig; + if(strncmp(note, __POSIX_SIGNAL_PREFIX, __POSIX_SIGNAL_PREFIX_LEN) != 0) + return translate_jehanne_note(note); // TODO: should we translate common notes? + sig = atoi(note+__POSIX_SIGNAL_PREFIX_LEN); + return __libposix_signal_trampoline(sig); +} + +int +libposix_set_signal_trampoline(PosixSignalTrampoline trampoline) +{ + if(__libposix_initialized()) + return 0; + if(trampoline == nil) + return 0; + __libposix_signal_trampoline = trampoline; + return 1; +} + +void +__libposix_processes_check_conf(void) +{ + if(__libposix_signal_trampoline == nil) + sysfatal("libposix: no signal trampoline"); +}