809 lines
14 KiB
C
809 lines
14 KiB
C
/* 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));
|
|
}
|
|
|
|
|