libposix: initial draft
This commit is contained in:
parent
e70feee4a3
commit
188a07782d
|
@ -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
|
||||
|
|
2
hacking
2
hacking
|
@ -1 +1 @@
|
|||
Subproject commit b1ab4f1a08b9b7156ecb4034527bfc87e159186e
|
||||
Subproject commit eb37bc6013a49cf27600b5b3df9fbc598971bf34
|
|
@ -0,0 +1,152 @@
|
|||
/*
|
||||
* This file is part of Jehanne.
|
||||
*
|
||||
* Copyright (C) 2017 Giacomo Tesio <giacomo@tesio.it>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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 <u.h>
|
||||
* #include <posix.h>
|
||||
*/
|
||||
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 <apw/errno.h>
|
||||
|
||||
/* 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);
|
|
@ -0,0 +1,2 @@
|
|||
*
|
||||
!.gitignore
|
|
@ -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/",
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
libc.h
|
||||
libc_wrapper.h
|
||||
*.a
|
||||
libc.sed
|
|
@ -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"
|
||||
]
|
||||
}
|
||||
}
|
|
@ -0,0 +1,158 @@
|
|||
/*
|
||||
* This file is part of Jehanne.
|
||||
*
|
||||
* Copyright (C) 2017 Giacomo Tesio <giacomo@tesio.it>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <u.h>
|
||||
#include <lib9.h>
|
||||
#include <posix.h>
|
||||
#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);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,159 @@
|
|||
/*
|
||||
* This file is part of Jehanne.
|
||||
*
|
||||
* Copyright (C) 2017 Giacomo Tesio <giacomo@tesio.it>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <u.h>
|
||||
#include <lib9.h>
|
||||
#include <posix.h>
|
||||
#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;
|
||||
}
|
|
@ -0,0 +1,301 @@
|
|||
/*
|
||||
* This file is part of Jehanne.
|
||||
*
|
||||
* Copyright (C) 2017 Giacomo Tesio <giacomo@tesio.it>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <u.h>
|
||||
#include <lib9.h>
|
||||
#include <posix.h>
|
||||
#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;
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* This file is part of Jehanne.
|
||||
*
|
||||
* Copyright (C) 2017 Giacomo Tesio <giacomo@tesio.it>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <u.h>
|
||||
#include <lib9.h>
|
||||
#include <posix.h>
|
||||
#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;
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* This file is part of Jehanne.
|
||||
*
|
||||
* Copyright (C) 2017 Giacomo Tesio <giacomo@tesio.it>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
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);
|
|
@ -0,0 +1,90 @@
|
|||
/*
|
||||
* This file is part of Jehanne.
|
||||
*
|
||||
* Copyright (C) 2017 Giacomo Tesio <giacomo@tesio.it>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <u.h>
|
||||
#include <lib9.h>
|
||||
#include <posix.h>
|
||||
#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);
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* This file is part of Jehanne.
|
||||
*
|
||||
* Copyright (C) 2017 Giacomo Tesio <giacomo@tesio.it>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <u.h>
|
||||
#include <lib9.h>
|
||||
#include <posix.h>
|
||||
#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;
|
||||
}
|
|
@ -0,0 +1,194 @@
|
|||
/*
|
||||
* This file is part of Jehanne.
|
||||
*
|
||||
* Copyright (C) 2017 Giacomo Tesio <giacomo@tesio.it>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <u.h>
|
||||
#include <lib9.h>
|
||||
#include <posix.h>
|
||||
#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");
|
||||
}
|
Loading…
Reference in New Issue