/* Copyright (C) 2005 David Decotigny This program 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 2 of the License, or (at your option) any later version. This program 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 this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "crt.h" #include "string.h" #include "stdarg.h" #include "libc.h" void exit (int status) { _sos_exit(status); } pid_t fork(void) { return _sos_fork(); } pid_t getpid() { return _sos_getpid(); } /** * Helper to transform the array of argv and envp into an area * suitable for the crt.c:unmarshall_argv_envp() function. * @see crt.c for the format of this array. */ static void const* marshall_execve_parameters(char* const argv[], char* const envp[], /*out*/size_t * sz) { size_t i, i_offset, count_argv, count_envp, size; char * str; void * result; addr_t * offset; *sz = 0; /* Count the number of argv parameters and the size to allocate */ for (count_argv = 0, size = 0 ; argv && argv[count_argv] != NULL ; count_argv ++) size += strlen(argv[count_argv]) + 1 /* trailing \0 */; /* Count the number of envp parameters and the size to allocate */ for (count_envp = 0 ; envp && envp[count_envp] != NULL ; count_envp ++) size += strlen(envp[count_envp]) + 1 /* trailing \0 */; size += (count_argv + count_envp + 3) * sizeof(addr_t); result = malloc(size); if (NULL == result) return NULL; /* Build the array of offsets and the string contents */ offset = (addr_t*)result; str = (char*) & offset[count_argv + count_envp + 3]; i_offset = 0; /* First element of the array is the number of argv entries */ offset [i_offset++] = count_argv; /* Marshall the argv array */ for (i = 0 ; i < count_argv ; i ++, i_offset ++) { char const* c; offset[i_offset] = (void*)str - result; for (c = argv[i] ; *c ; c ++, str ++) *str = *c; *str = '\0'; str ++; } /* The NULL between argv and envp */ offset [i_offset++] = 0; for (i = 0 ; i < count_envp ; i ++, i_offset ++) { char const* c; offset[i_offset] = (void*)str - result; for (c = envp[i] ; *c ; c ++, str ++) *str = *c; *str = '\0'; str ++; } /* Final NULL */ offset[count_argv + count_envp + 2] = 0; *sz = size; return result; } int execve(const char *filename, char *const argv [], char *const envp[]) { void const* args_area; size_t args_sz; int retval; args_area = marshall_execve_parameters(argv, envp, & args_sz); retval = _sos_exec(filename, args_area, args_sz); if (NULL != args_area) free((void*)args_area); return retval; } int execv(const char * filename, char * const argv []) { return execve(filename, argv, environ); } static int compute_nargs(va_list ap) { int nargs = 0; while (va_arg(ap, char*)) nargs ++; return nargs; } static int vexec(const char *path, va_list ap, int envp_in_list) { int retval; char ** vector, **entry; char *str; char ** envp; size_t nargs = compute_nargs(ap); /* Allocate the char* vector */ vector = malloc((nargs + 1)*sizeof(char*)); if (! vector) return -1; /* Fill it */ entry = vector; while ((str = va_arg(ap, char*)) != NULL) { *entry = str; entry ++; } *entry = NULL; if (envp_in_list) envp = (char**)va_arg(ap, char*); else envp = environ; retval = execve(path, vector, envp); free(vector); return retval; } int execl(const char *path, ...) { int retval; va_list ap; va_start(ap, path); retval = vexec(path, ap, FALSE); va_end(ap); return retval; } int execle(const char *path, ...) { int retval; va_list ap; va_start(ap, path); retval = vexec(path, ap, TRUE); va_end(ap); return retval; } int exec(char * const filename) { return execl(filename, filename, NULL); } int sleep(unsigned int seconds) { return nanosleep(seconds, 0); } int nanosleep(unsigned long int sec, unsigned long int nanosec) { return _sos_nanosleep(sec, nanosec); } /** * Max number of environment variables */ #define SOS_MAX_ENVVARS 1024 char **environ = NULL; /** * Compare the keys of two strings of the form "key=val" */ static int equal_key(const char *e1, const char *e2) { for ( ; e1 && (*e1) && e2 && (*e2) && (*e1 == *e2) ; e1++, e2++) if (*e1 == '=') return TRUE; return FALSE; } /** * Helper function to register an environment variable */ static int registerenv(char * string, int can_overwrite) { int i; char ** overwritten; /* The first time: allocate the environ table */ if (! environ) { environ = malloc(SOS_MAX_ENVVARS * sizeof(char*)); if (! environ) return 0; memset(environ, 0x0, SOS_MAX_ENVVARS * sizeof(char*)); } /* Walk the environment variables */ overwritten = NULL; for (i = 0 ; i < SOS_MAX_ENVVARS ; i ++) { /* Reached end of list ? */ if (! environ[i]) break; /* Variable already present ? */ if (equal_key(environ[i], string)) overwritten = & environ[i]; } if (overwritten) { /* Not allowed to overwrite it ! */ if (! can_overwrite) return -1; /* Overwrite allowed: do it now */ free(*overwritten); *overwritten = string; return 0; } /* Must add the variable */ /* No place left ? */ if (i >= SOS_MAX_ENVVARS) return -1; /* Ok, add it at the end */ environ[i] = string; return 0; } /** * @return TRUE when the key of the "keyvalpair" pair is "key" */ static int key_is(char * keyvalpair, const char * key, char ** /*out*/value) { for ( ; keyvalpair && *keyvalpair && key && *key ; keyvalpair ++, key ++) if (*key != *keyvalpair) break; if (value) *value = keyvalpair + 1; return (keyvalpair && (*keyvalpair == '=') && key && (*key == '\0')); } int putenv(char * string) { char * str; if (! string) return -1; str = strdup(string); if (! str) return -1; return registerenv(string, TRUE); } int setenv(const char *name, const char *value, int overwrite) { char * str, * c; size_t sz_name, sz_value; if (!name || !value) return -1; /* Allocate space for the "name=value" string */ sz_name = strlen(name); sz_value = strlen(value); str = malloc(sz_name + 1 + sz_value + 1); if (! str) return -1; /* sprintf(str, "%s=%s", name, value); */ c = str; *c = '\0'; strzcpy(c, name, sz_name+1); c += sz_name; strzcpy(c, "=", 2); c += 1; strzcpy(c, value, sz_value+1); return registerenv(str, overwrite); } char *getenv(const char *name) { int i; if (! environ) return NULL; for (i = 0 ; i < SOS_MAX_ENVVARS ; i ++) { char *value; /* Reached end of list ? */ if (! environ[i]) return NULL; /* Variable already present ? */ if (key_is(environ[i], name, & value)) return value; } return NULL; } void unsetenv(const char *name) { int i; char ** entry, ** last_entry; if (! environ) return; /* Walk the environment variables */ entry = last_entry = NULL; for (i = 0 ; i < SOS_MAX_ENVVARS ; i ++) { /* Reached end of list ? */ if (! environ[i]) break; /* Variable already present ? */ if (key_is(environ[i], name, NULL)) entry = & environ[i]; else if (entry) last_entry = & environ[i]; } /* Found nothing ! */ if (! entry) return; /* Found it: erase it... */ free(*entry); *entry = NULL; /* ... and replace it with the last entry */ if (last_entry) { *entry = *last_entry; *last_entry = NULL; } } int clearenv(void) { int i; if (! environ) return 0; for (i = 0 ; i < SOS_MAX_ENVVARS ; i ++) { if (! environ[i]) break; free(environ[i]); environ[i] = NULL; } return 0; } int munmap(void * start, size_t length) { return _sos_munmap(start, length); } void * mremap(void * old_addr, size_t old_len, size_t new_len, unsigned long flags) { void * new_uaddr = old_addr; if (0 != _sos_mresize(old_addr, old_len, & new_uaddr, new_len, flags)) return NULL; return new_uaddr; } int mprotect(const void *addr, size_t len, int prot) { return _sos_mprotect(addr, len, prot); } int msync(void *start, size_t length, int flags) { return _sos_msync(start, length, flags); } /** * The presence of this global variable without any protected access * to it explains why the "brk/sbrk" functions below are MT-unsafe ! */ static void * kernel_heap_top = NULL; int brk(void *end_data_seg) { if (! end_data_seg) return -1; kernel_heap_top = _sos_brk(end_data_seg); return 0; } void *sbrk(ptrdiff_t increment) { if (! kernel_heap_top) kernel_heap_top = _sos_brk(0); kernel_heap_top = _sos_brk(kernel_heap_top + increment); return kernel_heap_top; } void * calloc (size_t nmemb, size_t size) { return malloc(nmemb * size); } /** * The presence of this global variable without any protected access * to it explains why the "malloc/calloc" functions below are * MT-unsafe ! */ static void * malloc_heap_top = NULL; void * malloc (size_t size) { void * retval; if (size <= 0) return NULL; /* Align on a 4B boundary */ size = ((size-1) & ~3) + 4; if (! kernel_heap_top) kernel_heap_top = _sos_brk(0); if (! malloc_heap_top) malloc_heap_top = kernel_heap_top; retval = malloc_heap_top; malloc_heap_top += size; _sos_brk(malloc_heap_top); return retval; } void free(void *ptr) { // bochs_printf("Free ignored (not implemented yet)\n"); } int mount(const char *source, const char *target, const char *filesystemtype, unsigned long mountflags, const char *data) { return _sos_mount(source, target, filesystemtype, mountflags, data); } int umount(const char *target) { return _sos_umount(target); } void sync(void) { return _sos_sync(); } int statvfs(const char *path, struct statvfs *buf) { return _sos_statvfs(path, buf); } int open(const char *pathname, int flags, /* mode_t mode */...) { va_list ap; unsigned int mode = 0; va_start(ap, flags); if (flags & O_CREAT) mode = va_arg(ap, unsigned int); va_end(ap); return _sos_open(pathname, flags, mode); } int close(int fd) { return _sos_close(fd); } int read(int fd, char * buf, size_t len) { int retval = _sos_read(fd, buf, & len); if (retval < 0) return retval; return len; } int write(int fd, const char * buf, size_t len) { int retval = _sos_write(fd, buf, & len); if (retval < 0) return retval; return len; } off_t lseek(int fd, off_t offset, int whence) { loff_t result = offset; int retval = _sos_seek64(fd, & result, whence); if (retval < 0) return retval; return result; } loff_t lseek64(int fd, loff_t offset, int whence) { loff_t result = offset; int retval = _sos_seek64(fd, & result, whence); if (retval < 0) return retval; return result; } void * mmap(void *start, size_t length, int prot , int flags, int fd, loff_t offset) { /* At kernel side, offset is considered positive */ if (offset < 0) return NULL; if (0 != _sos_fmmap(& start, length, prot, flags, fd, offset)) return NULL; return start; } int ftruncate(int fd, off_t length) { return _sos_ftruncate64(fd, length); } int ftruncate64(int fd, loff_t length) { return _sos_ftruncate64(fd, length); } int fcntl(int fd, int cmd, int arg) { return _sos_fcntl(fd, cmd, arg); } int ioctl(int fd, int cmd, int arg) { return _sos_ioctl(fd, cmd, arg); } int creat(const char *pathname, mode_t mode) { return _sos_creat(pathname, mode); } int link (const char *oldpath, const char *newpath) { return _sos_link(oldpath, newpath); } int unlink(const char *pathname) { return _sos_unlink(pathname); } int rename(const char *oldpath, const char *newpath) { return _sos_rename(oldpath, newpath); } int symlink(const char *target, const char *path) { return _sos_symlink(target, path); } int mknod(const char *pathname, mode_t mode, int type, unsigned int major, unsigned minor) { if (type == S_IFREG) return creat(pathname, mode); return _sos_mknod(pathname, mode, type, major, minor); } int mkdir(const char *pathname, mode_t mode) { return _sos_mkdir(pathname, mode); } int rmdir(const char *pathname) { return _sos_rmdir(pathname); } int chmod(const char *path, mode_t mode) { return _sos_chmod(path, mode); } struct sos_DIR_struct { int fd; struct dirent dirent; }; DIR *opendir(const char *name) { DIR * result = malloc(sizeof(DIR)); if (! result) return NULL; result->fd = _sos_open(name, O_DIRECTORY | O_RDONLY, 0); return result; } int dirfd(const DIR * dir) { if (dir) return dir->fd; return -1; } struct dirent *readdir(DIR *dir) { int retval = _sos_readdir(dir->fd, & dir->dirent); if (retval < 0) return NULL; return & dir->dirent; } int closedir(DIR *dir) { close(dir->fd); free(dir); return 0; } int stat(const char *file_name, struct stat *buf) { return _sos_stat(file_name, TRUE, buf); } int lstat(const char *file_name, struct stat *buf) { return _sos_stat(file_name, FALSE, buf); } int chroot(const char *path) { return _sos_chroot(path); } int chdir(const char *path) { return _sos_chdir(path); } int fchdir(int fd) { return _sos_fchdir(fd); } int printf (const char *format, ...) { char buff[4096]; va_list ap; va_start(ap, format); vsnprintf(buff, sizeof(buff), format, ap); va_end(ap); return write (1, buff, strlen(buff)); }