Goto sanos source index
//
// syscall.c
//
// System call interface
//
// Copyright (C) 2002 Michael Ringgaard. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// 3. Neither the name of the project nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
// SUCH DAMAGE.
//
#include <os/krnl.h>
#define SYSCALL_PROFILE
//#define SYSCALL_LOGENTER
//#define SYSCALL_LOGEXIT
//#define SYSCALL_LOGONLYERRORS
//#define SYSCALL_LOGTIMEOUTS
//#define SYSCALL_LOGWAIT
#define SYSCALL_CHECKBUFFER
struct syscall_entry {
char *name;
int paramsize;
char *argfmt;
int (*func)(char *);
};
#ifdef SYSCALL_PROFILE
static unsigned long sccnt[SYSCALL_MAX + 1];
static unsigned long scerr[SYSCALL_MAX + 1];
#endif
static __inline int lock_buffer(void *buffer, int size, int modify) {
#ifdef SYSCALL_CHECKBUFFER
if (buffer) {
if (size < 0) return -EINVAL;
if (!mem_access(buffer, size, modify ? PT_USER_WRITE : PT_USER_READ)) return -EFAULT;
}
#endif
return 0;
}
static __inline void unlock_buffer(void *buffer, int size) {
}
static __inline int lock_string(char *s) {
#ifdef SYSCALL_CHECKBUFFER
if (s) {
if (!str_access(s, PT_USER_READ)) return -EFAULT;
}
#endif
return 0;
}
static __inline void unlock_string(char *s) {
}
static __inline int lock_iovec(struct iovec *iov, int count, int modify) {
#ifdef SYSCALL_CHECKBUFFER
int rc;
rc = check_iovec(iov, count, modify);
if (rc < 0) return rc;
#endif
return 0;
}
static __inline void unlock_iovec(struct iovec *iov, int count) {
}
static __inline int lock_fdset(fd_set *fds, int modify) {
#ifdef SYSCALL_CHECKBUFFER
if (fds) {
if (!mem_access(fds, sizeof(int), modify ? PT_USER_WRITE : PT_USER_READ)) return -EFAULT;
if ((void *) fds >= (void *) OSBASE) return -EFAULT;
if ((char *) fds + (fds->count + 1) * sizeof(int) >= (char *) OSBASE) return -EFAULT;
if (!mem_access(fds, (fds->count + 1) * sizeof(int), modify ? PT_USER_WRITE : PT_USER_READ)) return -EFAULT;
}
#endif
return 0;
}
static __inline void unlock_fdset(fd_set *fds) {
}
static int sys_null(char *params) {
return 0;
}
static int sys_mkfs(char *params) {
char *devname;
char *type;
char *opts;
int rc;
devname = *(char **) params;
type = *(char **) (params + 4);
opts = *(char **) (params + 8);
if (lock_string(devname) < 0) return -EFAULT;
if (lock_string(type) < 0) {
unlock_string(devname);
return -EFAULT;
}
if (lock_string(opts) < 0) {
unlock_string(type);
unlock_string(devname);
return -EFAULT;
}
rc = mkfs(devname, type, opts);
unlock_string(opts);
unlock_string(type);
unlock_string(devname);
return rc;
}
static int sys_mount(char *params) {
char *type;
char *mntto;
char *mntfrom;
char *opts;
int rc;
type = *(char **) params;
mntto = *(char **) (params + 4);
mntfrom = *(char **) (params + 8);
opts = *(char **) (params + 12);
if (lock_string(type) < 0) return -EFAULT;
if (lock_string(mntto) < 0) {
unlock_string(type);
return -EFAULT;
}
if (lock_string(mntfrom) < 0) {
unlock_string(mntto);
unlock_string(type);
return -EFAULT;
}
if (lock_string(opts) < 0) {
unlock_string(mntfrom);
unlock_string(mntto);
unlock_string(type);
return -EFAULT;
}
rc = mount(type, mntto, mntfrom, opts, NULL);
unlock_string(opts);
unlock_string(mntfrom);
unlock_string(mntto);
unlock_string(type);
return rc;
}
static int sys_umount(char *params) {
char *path;
int rc;
path = *(char **) params;
if (lock_string(path) < 0) return -EFAULT;
rc = umount(path);
unlock_string(path);
return rc;
}
static int sys_getfsstat(char *params) {
struct statfs *buf;
size_t size;
int rc;
buf = *(struct statfs **) params;
size = *(int *) (params + 4);
if (lock_buffer(buf, size, 1) < 0) return -EFAULT;
rc = getfsstat(buf, size);
unlock_buffer(buf, size);
return rc;
}
static int sys_fstatfs(char *params) {
struct file *f;
handle_t h;
struct statfs *buf;
int rc;
h = *(handle_t *) params;
buf = *(struct statfs **) (params + 4);
f = (struct file *) olock(h, OBJECT_FILE);
if (!f) return -EBADF;
if (lock_buffer(buf, sizeof(struct statfs), 1) < 0) {
orel(f);
return -EFAULT;
}
rc = fstatfs(f, buf);
unlock_buffer(buf, sizeof(struct statfs));
orel(f);
return rc;
}
static int sys_statfs(char *params) {
char *name;
struct statfs *buf;
int rc;
name = *(char **) params;
buf = *(struct statfs **) (params + 4);
if (lock_string(name) < 0) return -EFAULT;
if (lock_buffer(buf, sizeof(struct statfs), 1) < 0) {
unlock_string(name);
return -EFAULT;
}
rc = statfs(name, buf);
unlock_buffer(buf, sizeof(struct statfs));
unlock_string(name);
return rc;
}
static int sys_open(char *params) {
struct file *f;
char *name;
int flags;
int mode;
int rc;
name = *(char **) params;
flags = *(int *) (params + 4);
mode = *(int *) (params + 8);
if ((flags & O_CREAT) == 0) mode = 0;
if (lock_string(name) < 0) return -EFAULT;
rc = open(name, flags, mode, &f);
if (rc == 0) {
rc = halloc(&f->iob.object);
if (rc < 0) close(f);
}
unlock_string(name);
return rc;
}
static int sys_close(char *params) {
handle_t h;
int rc;
h = *(handle_t *) params;
rc = hfree(h);
return rc;
}
static int sys_fsync(char *params) {
struct file *f;
handle_t h;
int rc;
h = *(handle_t *) params;
f = (struct file *) olock(h, OBJECT_FILE);
if (!f) return -EBADF;
rc = fsync(f);
orel(f);
return rc;
}
static int sys_read(char *params) {
handle_t h;
struct object *o;
int rc;
void *data;
int size;
h = *(handle_t *) params;
data = *(void **) (params + 4);
size = *(int *) (params + 8);
o = olock(h, OBJECT_ANY);
if (!o) return -EBADF;
if (lock_buffer(data, size, 1) < 0) {
orel(o);
return -EFAULT;
}
if (o->type == OBJECT_FILE) {
rc = read((struct file *) o, data, size);
} else if (o->type == OBJECT_SOCKET) {
rc = recv((struct socket *) o, data, size, 0);
} else {
rc = -EBADF;
}
orel(o);
unlock_buffer(data, size);
return rc;
}
static int sys_write(char *params) {
handle_t h;
struct object *o;
int rc;
void *data;
int size;
h = *(handle_t *) params;
data = *(void **) (params + 4);
size = *(int *) (params + 8);
o = olock(h, OBJECT_ANY);
if (!o) return -EBADF;
if (lock_buffer(data, size, 0) < 0) {
orel(o);
return -EFAULT;
}
if (o->type == OBJECT_FILE) {
rc = write((struct file *) o, data, size);
} else if (o->type == OBJECT_SOCKET) {
rc = send((struct socket *) o, data, size, 0);
} else {
rc = -EBADF;
}
orel(o);
unlock_buffer(data, size);
return rc;
}
static int sys_ioctl(char *params) {
handle_t h;
struct object *o;
int rc;
int cmd;
void *data;
int size;
h = *(handle_t *) params;
cmd = *(int *) (params + 4);
data = *(void **) (params + 8);
size = *(int *) (params + 12);
o = olock(h, OBJECT_ANY);
if (!o) return -EBADF;
if (lock_buffer(data, size, 1) < 0) {
orel(o);
return -EFAULT;
}
if (o->type == OBJECT_FILE) {
rc = ioctl((struct file *) o, cmd, data, size);
} else if (o->type == OBJECT_SOCKET) {
rc = ioctlsocket((struct socket *) o, cmd, data, size);
} else {
rc = -EBADF;
}
orel(o);
return rc;
}
static int sys_tell(char *params) {
struct file *f;
handle_t h;
off64_t rc;
off64_t *retval;
h = *(handle_t *) params;
retval = *(off64_t **) (params + 4);
f = (struct file *) olock(h, OBJECT_FILE);
if (!f) return -EBADF;
if (lock_buffer(retval, sizeof(off64_t), 1) < 0) {
orel(f);
return -EFAULT;
}
rc = tell(f);
if (retval) *retval = rc;
orel(f);
unlock_buffer(retval, sizeof(off64_t));
return rc < 0 ? (int) rc : (int) (rc & 0x7FFFFFFF);
}
static int sys_threadtimes(char *params) {
handle_t h;
struct thread *t;
struct tms *tms;
int rc;
h = *(handle_t *) params;
tms = *(struct tms **) (params + 4);
t = (struct thread *) olock(h, OBJECT_THREAD);
if (!t) return -EBADF;
if (lock_buffer(tms, sizeof(struct tms), 1) < 0) {
orel(t);
return -EFAULT;
}
rc = get_thread_times(t, tms);
unlock_buffer(tms, sizeof(struct tms));
orel(t);
return rc;
}
static int sys_lseek(char *params) {
struct file *f;
handle_t h;
off64_t offset;
int origin;
off64_t rc;
off64_t *retval;
h = *(handle_t *) params;
offset = *(off64_t *) (params + 4);
origin = *(int *) (params + 12);
retval = *(off64_t **) (params + 16);
f = (struct file *) olock(h, OBJECT_FILE);
if (!f) return -EBADF;
if (lock_buffer(retval, sizeof(off64_t), 1) < 0) {
orel(f);
return -EFAULT;
}
rc = lseek(f, offset, origin);
if (retval) *retval = rc;
orel(f);
unlock_buffer(retval, sizeof(off64_t));
return rc < 0 ? (int) rc : (int) (rc & 0x7FFFFFFF);
}
static int sys_ftruncate(char *params) {
struct file *f;
handle_t h;
off64_t size;
int rc;
h = *(handle_t *) params;
size = *(off64_t *) (params + 4);
f = (struct file *) olock(h, OBJECT_FILE);
if (!f) return -EBADF;
rc = ftruncate(f, size);
orel(f);
return rc;
}
static int sys_futime(char *params) {
struct file *f;
handle_t h;
struct utimbuf *times;
int rc;
h = *(handle_t *) params;
times = *(struct utimbuf **) (params + 4);
f = (struct file *) olock(h, OBJECT_FILE);
if (!f) return -EBADF;
if (lock_buffer(times, sizeof(struct utimbuf), 1) < 0) {
orel(f);
return -EFAULT;
}
rc = futime(f, times);
unlock_buffer(times, sizeof(struct utimbuf));
orel(f);
return rc;
}
static int sys_utime(char *params) {
char *name;
struct utimbuf *times;
int rc;
name = *(char **) params;
times = *(struct utimbuf **) (params + 4);
if (lock_string(name) < 0) return -EFAULT;
if (lock_buffer(times, sizeof(struct utimbuf), 1) < 0) {
unlock_string(name);
return -EFAULT;
}
rc = utime(name, times);
unlock_buffer(times, sizeof(struct utimbuf));
unlock_string(name);
return rc;
}
static int sys_fstat(char *params) {
struct file *f;
handle_t h;
struct stat64 *buffer;
int rc;
h = *(handle_t *) params;
buffer = *(struct stat64 **) (params + 4);
f = (struct file *) olock(h, OBJECT_FILE);
if (!f) return -EBADF;
if (lock_buffer(buffer, sizeof(struct stat64), 1) < 0) {
orel(f);
return -EFAULT;
}
rc = fstat(f, buffer);
unlock_buffer(buffer, sizeof(struct stat64));
orel(f);
if (buffer && rc > 0) rc = 0;
return rc;
}
static int sys_stat(char *params) {
char *name;
struct stat64 *buffer;
int rc;
name = *(char **) params;
buffer = *(struct stat64 **) (params + 4);
if (lock_string(name) < 0) return -EFAULT;
if (lock_buffer(buffer, sizeof(struct stat64), 1) < 0) {
unlock_string(name);
return -EFAULT;
}
rc = stat(name, buffer);
unlock_buffer(buffer, sizeof(struct stat64));
unlock_string(name);
if (buffer && rc > 0) rc = 0;
return rc;
}
static int sys_mkdir(char *params) {
char *name;
int mode;
int rc;
name = *(char **) params;
mode = *(int *) (params + 4);
if (lock_string(name) < 0) return -EFAULT;
rc = mkdir(name, mode);
unlock_string(name);
return rc;
}
static int sys_rmdir(char *params) {
char *name;
int rc;
name = *(char **) params;
if (lock_string(name) < 0) return -EFAULT;
rc = rmdir(name);
unlock_string(name);
return rc;
}
static int sys_rename(char *params) {
char *oldname;
char *newname;
int rc;
oldname = *(char **) params;
newname = *(char **) (params + 4);
if (lock_string(oldname) < 0) return -EFAULT;
if (lock_string(newname) < 0) {
unlock_string(oldname);
return -EFAULT;
}
rc = rename(oldname, newname);
unlock_string(newname);
unlock_string(oldname);
return rc;
}
static int sys_link(char *params) {
char *oldname;
char *newname;
int rc;
oldname = *(char **) params;
newname = *(char **) (params + 4);
if (lock_string(oldname) < 0) return -EFAULT;
if (lock_string(newname) < 0) {
unlock_string(oldname);
return -EFAULT;
}
rc = link(oldname, newname);
unlock_string(newname);
unlock_string(oldname);
return rc;
}
static int sys_unlink(char *params) {
char *name;
int rc;
name = *(char **) params;
if (lock_string(name) < 0) return -EFAULT;
rc = unlink(name);
unlock_string(name);
return rc;
}
static int sys_opendir(char *params) {
struct file *f;
char *name;
int rc;
name = *(char **) params;
if (lock_string(name) < 0) return -EFAULT;
rc = opendir(name, &f);
if (rc == 0) {
rc = halloc(&f->iob.object);
if (rc < 0) close(f);
}
unlock_string(name);
return rc;
}
static int sys_readdir(char *params) {
handle_t h;
struct file *f;
int rc;
struct direntry *dirp;
int count;
h = *(handle_t *) params;
dirp = *(struct direntry **) (params + 4);
count = *(int *) (params + 8);
f = (struct file *) olock(h, OBJECT_FILE);
if (f == NULL) return -EBADF;
if (lock_buffer(dirp, count * sizeof(struct direntry), 1) < 0) {
orel(f);
return -EFAULT;
}
rc = readdir(f, dirp, count);
orel(f);
return rc;
}
static int sys_vmalloc(char *params) {
char *addr;
unsigned long size;
int type;
int protect;
unsigned long tag;
void *retval;
int rc;
addr = *(void **) params;
size = *(unsigned long *) (params + 4);
type = *(int *) (params + 8);
protect = *(int *) (params + 12);
tag = *(unsigned long *) (params + 16);
retval = vmalloc(addr, size, type, protect, tag, &rc);
if (!retval) {
struct tib *tib = self()->tib;
if (tib) tib->errnum = -rc;
}
return (int) retval;
}
static int sys_vmfree(char *params) {
char *addr;
unsigned long size;
int type;
int rc;
addr = *(void **) params;
size = *(unsigned long *) (params + 4);
type = *(int *) (params + 8);
rc = vmfree(addr, size, type);
return rc;
}
static int sys_vmrealloc(char *params) {
char *addr;
unsigned long oldsize;
unsigned long newsize;
int type;
int protect;
unsigned long tag;
void *retval;
addr = *(void **) params;
oldsize = *(unsigned long *) (params + 4);
newsize = *(unsigned long *) (params + 8);
type = *(int *) (params + 12);
protect = *(int *) (params + 16);
tag = *(unsigned long *) (params + 20);
retval = vmrealloc(addr, oldsize, newsize, type, protect, tag);
return (int) retval;
}
static int sys_vmprotect(char *params) {
char *addr;
unsigned long size;
int protect;
int rc;
addr = *(void **) params;
size = *(unsigned long *) (params + 4);
protect = *(int *) (params + 8);
rc = vmprotect(addr, size, protect);
return rc;
}
static int sys_vmlock(char *params) {
char *addr;
unsigned long size;
int rc;
addr = *(void **) params;
size = *(unsigned long *) (params + 4);
rc = vmlock(addr, size);
return rc;
}
static int sys_vmunlock(char *params) {
char *addr;
unsigned long size;
int rc;
addr = *(void **) params;
size = *(unsigned long *) (params + 4);
rc = vmunlock(addr, size);
return rc;
}
static int sys_vmmap(char *params) {
char *addr;
unsigned long size;
int protect;
handle_t h;
off64_t offset;
struct file *f;
void *retval;
int rc;
addr = *(void **) params;
size = *(unsigned long *) (params + 4);
protect = *(int *) (params + 8);
h = *(handle_t *) (params + 12);
offset = *(off64_t *) (params + 16);
f = (struct file *) olock(h, OBJECT_FILE);
if (!f) return -EBADF;
retval = vmmap(addr, size, protect, f, offset, &rc);
if (!retval) {
struct tib *tib = self()->tib;
if (tib) tib->errnum = -rc;
}
orel(f);
return (int) retval;
}
static int sys_vmsync(char *params) {
char *addr;
unsigned long size;
int rc;
addr = *(void **) params;
size = *(unsigned long *) (params + 4);
rc = vmsync(addr, size);
return rc;
}
static int sys_waitone(char *params) {
handle_t h;
struct object *o;
unsigned int timeout;
int rc;
h = *(handle_t *) params;
timeout = *(unsigned int *) (params + 4);
o = (struct object *) olock(h, OBJECT_ANY);
if (!o) return -EBADF;
rc = wait_for_one_object(o, timeout, 1);
orel(o);
return rc;
}
static int sys_waitall(char *params) {
handle_t *h;
int count;
unsigned int timeout;
struct object *o[MAX_WAIT_OBJECTS];
int rc;
int n;
h = *(handle_t **) params;
count = *(int *) (params + 4);
timeout = *(unsigned int *) (params + 8);
if (count < 0 || count > MAX_WAIT_OBJECTS) return -EINVAL;
if ((!h && count > 0) || lock_buffer(h, count * sizeof(handle_t *), 0) < 0) return -EFAULT;
for (n = 0; n < count; n++) {
o[n] = olock(h[n], OBJECT_ANY);
if (!o[n]) {
while (--n >= 0) orel(o[n]);
return -EBADF;
}
}
if (count == 1) {
rc = wait_for_one_object(o[0], timeout, 1);
} else {
rc = wait_for_all_objects(o, count, timeout, 1);
}
for (n = 0; n < count; n++) orel(o[n]);
return rc;
}
static int sys_waitany(char *params) {
handle_t *h;
int count;
unsigned int timeout;
struct object *o[MAX_WAIT_OBJECTS];
int rc;
int n;
h = *(handle_t **) params;
count = *(int *) (params + 4);
timeout = *(unsigned int *) (params + 8);
if (count < 0 || count > MAX_WAIT_OBJECTS) return -EINVAL;
if ((!h && count > 0) || lock_buffer(h, count * sizeof(handle_t *), 0) < 0) return -EFAULT;
for (n = 0; n < count; n++) {
o[n] = olock(h[n], OBJECT_ANY);
if (!o[n]) {
while (--n >= 0) orel(o[n]);
return -EBADF;
}
}
if (count == 1) {
rc = wait_for_one_object(o[0], timeout, 1);
} else {
rc = wait_for_any_object(o, count, timeout, 1);
}
for (n = 0; n < count; n++) orel(o[n]);
return rc;
}
static int sys_mkevent(char *params) {
int manual_reset;
int initial_state;
struct event *e;
handle_t h;
manual_reset = *(int *) params;
initial_state = *(int *) (params + 4);
e = (struct event *) kmalloc(sizeof(struct event));
if (!e) return -ENOMEM;
init_event(e, manual_reset, initial_state);
h = halloc(&e->object);
if (h < 0) {
close_object(&e->object);
return h;
}
return h;
}
static int sys_epulse(char *params) {
struct event *e;
handle_t h;
h = *(handle_t *) params;
e = (struct event *) olock(h, OBJECT_EVENT);
if (!e) return -EBADF;
pulse_event(e);
orel(e);
return 0;
}
static int sys_eset(char *params) {
struct event *e;
handle_t h;
h = *(handle_t *) params;
e = (struct event *) olock(h, OBJECT_EVENT);
if (!e) return -EBADF;
set_event(e);
orel(e);
return 0;
}
static int sys_ereset(char *params) {
struct event *e;
handle_t h;
h = *(handle_t *) params;
e = (struct event *) olock(h, OBJECT_EVENT);
if (!e) return -EBADF;
reset_event(e);
orel(e);
return 0;
}
static int sys_getthreadblock(char *params) {
handle_t h;
struct thread *t;
struct tib *tib;
h = *(handle_t *) params;
t = (struct thread *) olock(h, OBJECT_THREAD);
if (!t) return -EBADF;
tib = t->tib;
orel(t);
return (int) tib;
}
static int sys_exitos(char *params) {
int mode;
mode = *(int *) params;
stop(mode);
return 0;
}
static int sys_dup(char *params) {
handle_t h;
handle_t newh;
struct object *o;
h = *(handle_t *) params;
o = olock(h, OBJECT_ANY);
if (!o) return -EBADF;
newh = halloc(o);
orel(o);
return newh;
}
static int sys_dup2(char *params) {
handle_t h1;
handle_t h2;
struct object *o;
int rc;
h1 = *(handle_t *) params;
h2 = *(handle_t *) (params + 4);
o = olock(h1, OBJECT_ANY);
if (!o) return -EBADF;
rc = hassign(o, h2);
orel(o);
return rc;
}
static int sys_mkthread(char *params) {
void *entrypoint;
unsigned long stacksize;
char *name;
struct tib **ptib;
struct thread *t;
handle_t h;
int rc;
entrypoint = *(void **) params;
stacksize = *(unsigned long *) (params + 4);
name = *(char **) (params + 8);
ptib = *(struct tib ***) (params + 12);
if (entrypoint >= (void *) OSBASE) return -EFAULT;
if (lock_string(name) < 0) return -EFAULT;
rc = create_user_thread(entrypoint, stacksize, name, &t);
if (rc < 0) return rc;
h = halloc(&t->object);
if (h < 0) {
unlock_string(name);
return h;
}
if (ptib) *ptib = t->tib;
unlock_string(name);
return h;
}
static int sys_suspend(char *params) {
handle_t h;
struct thread *t;
int rc;
h = *(handle_t *) params;
t = (struct thread *) olock(h, OBJECT_THREAD);
if (!t || t->id == 0) return -EBADF;
rc = suspend_thread(t);
orel(t);
return rc;
}
static int sys_resume(char *params) {
handle_t h;
struct thread *t;
int rc;
h = *(handle_t *) params;
t = (struct thread *) olock(h, OBJECT_THREAD);
if (!t) return -EBADF;
rc = resume_thread(t);
orel(t);
return rc;
}
static int sys_endthread(char *params) {
int exitcode;
exitcode = *(int *) params;
terminate_thread(exitcode);
return 0;
}
static int sys_setcontext(char *params) {
handle_t h;
struct thread *t;
struct context *context;
int rc;
h = *(handle_t *) params;
context = *(struct context **) (params + 4);
t = (struct thread *) olock(h, OBJECT_THREAD);
if (!t) return -EBADF;
if (lock_buffer(context, sizeof(struct context), 0) < 0) {
orel(t);
return -EFAULT;
}
rc = set_context(t, context);
unlock_buffer(context, sizeof(struct context));
orel(t);
return rc;
}
static int sys_getcontext(char *params) {
handle_t h;
struct thread *t;
struct context *context;
int rc;
h = *(handle_t *) params;
context = *(struct context **) (params + 4);
t = (struct thread *) olock(h, OBJECT_THREAD);
if (!t) return -EBADF;
if (lock_buffer(context, sizeof(struct context), 1) < 0) {
orel(t);
return -EFAULT;
}
rc = get_context(t, context);
unlock_buffer(context, sizeof(struct context));
orel(t);
return rc;
}
static int sys_getprio(char *params) {
handle_t h;
struct thread *t;
int priority;
h = *(handle_t *) params;
t = (struct thread *) olock(h, OBJECT_THREAD);
if (!t) return -EBADF;
priority = get_thread_priority(t);
orel(t);
return priority;
}
static int sys_setprio(char *params) {
handle_t h;
struct thread *t;
int priority;
int rc;
h = *(handle_t *) params;
priority = *(int *) (params + 4);
t = (struct thread *) olock(h, OBJECT_THREAD);
if (!t) return -EBADF;
if (priority < 1 || priority > 15) {
// User mode code can only set priority levels 1-15
rc = -EINVAL;
} else if (!t->tib) {
// User mode code not allowed to set priority for kernel threads
rc = -EPERM;
} else {
// Change thread priority
rc = set_thread_priority(t, priority);
}
orel(t);
return rc;
}
static int sys_msleep(char *params) {
int millisecs;
int rc;
millisecs = *(int *) params;
rc = msleep(millisecs);
return rc;
}
static int sys_time(char *params) {
time_t *timeptr;
time_t t;
timeptr = *(time_t **) params;
if (lock_buffer(timeptr, sizeof(time_t *), 1) < 0) return -EFAULT;
t = get_time();
if (timeptr) *timeptr = t;
unlock_buffer(timeptr, sizeof(time_t *));
return t;
}
static int sys_gettimeofday(char *params) {
struct timeval *tv;
void *tzp;
tv = *(struct timeval **) params;
tzp = *(void **) (params + 4);
if (!tv) return -EINVAL;
if (lock_buffer(tv, sizeof(struct timeval), 1) < 0) return -EFAULT;
tv->tv_sec = systemclock.tv_sec;
tv->tv_usec = systemclock.tv_usec;
unlock_buffer(tv, sizeof(struct timeval));
return 0;
}
static int sys_settimeofday(char *params) {
struct timeval *tv;
tv = *(struct timeval **) params;
if (!tv) return -EINVAL;
if (lock_buffer(tv, sizeof(struct timeval), 0) < 0) return -EFAULT;
set_time(tv);
unlock_buffer(tv, sizeof(struct timeval));
return 0;
}
static int sys_clock(char *params) {
return clocks;
}
static int sys_mksem(char *params) {
int initial_count;
struct sem *s;
handle_t h;
initial_count = *(int *) params;
s = (struct sem *) kmalloc(sizeof(struct sem));
if (!s) return -ENOMEM;
init_sem(s, initial_count);
h = halloc(&s->object);
if (h < 0) {
close_object(&s->object);
return h;
}
return h;
}
static int sys_semrel(char *params) {
handle_t h;
struct sem *s;
int count;
int rc;
h = *(handle_t *) params;
count = *(int *) (params + 4);
s = (struct sem *) olock(h, OBJECT_SEMAPHORE);
if (!s) return -EBADF;
rc = release_sem(s, count);
orel(s);
return rc;
}
static int sys_accept(char *params) {
handle_t h;
struct socket *s;
struct socket *news;
int rc;
struct sockaddr *addr;
int *addrlen;
h = *(handle_t *) params;
addr = *(struct sockaddr **) (params + 4);
addrlen = *(int **) (params + 8);
s = (struct socket *) olock(h, OBJECT_SOCKET);
if (!s) return -EBADF;
if (lock_buffer(addr, sizeof(struct sockaddr), 1) < 0) {
orel(s);
return -EFAULT;
}
if (lock_buffer(addrlen, sizeof(int), 1) < 0) {
orel(s);
unlock_buffer(addr, sizeof(struct sockaddr));
return -EFAULT;
}
rc = accept(s, addr, addrlen, &news);
if (rc == 0) {
rc = halloc(&news->iob.object);
if (rc < 0) closesocket(news);
}
orel(s);
unlock_buffer(addrlen, sizeof(int));
unlock_buffer(addr, sizeof(struct sockaddr));
return rc;
}
static int sys_bind(char *params) {
handle_t h;
struct socket *s;
int rc;
struct sockaddr *name;
int namelen;
h = *(handle_t *) params;
name = *(struct sockaddr **) (params + 4);
namelen = *(int *) (params + 8);
s = (struct socket *) olock(h, OBJECT_SOCKET);
if (!s) return -EBADF;
if (lock_buffer(name, namelen, 0) < 0) {
orel(s);
return -EFAULT;
}
rc = bind(s, name, namelen);
orel(s);
unlock_buffer(name, namelen);
return rc;
}
static int sys_connect(char *params) {
handle_t h;
struct socket *s;
int rc;
struct sockaddr *name;
int namelen;
h = *(handle_t *) params;
name = *(struct sockaddr **) (params + 4);
namelen = *(int *) (params + 8);
s = (struct socket *) olock(h, OBJECT_SOCKET);
if (!s) return -EBADF;
if (lock_buffer(name, namelen, 0) < 0) {
orel(s);
return -EFAULT;
}
rc = connect(s, name, namelen);
orel(s);
unlock_buffer(name, namelen);
return rc;
}
static int sys_getpeername(char *params) {
handle_t h;
struct socket *s;
int rc;
struct sockaddr *name;
int *namelen;
h = *(handle_t *) params;
name = *(struct sockaddr **) (params + 4);
namelen = *(int **) (params + 8);
s = (struct socket *) olock(h, OBJECT_SOCKET);
if (!s) return -EBADF;
if (lock_buffer(name, sizeof(struct sockaddr), 1) < 0) {
orel(s);
return -EFAULT;
}
if (lock_buffer(namelen, 4, 1) < 0) {
orel(s);
unlock_buffer(name, sizeof(struct sockaddr));
return -EFAULT;
}
rc = getpeername(s, name, namelen);
orel(s);
unlock_buffer(namelen, 4);
unlock_buffer(name, sizeof(struct sockaddr));
return rc;
}
static int sys_getsockname(char *params) {
handle_t h;
struct socket *s;
int rc;
struct sockaddr *name;
int *namelen;
h = *(handle_t *) params;
name = *(struct sockaddr **) (params + 4);
namelen = *(int **) (params + 8);
s = (struct socket *) olock(h, OBJECT_SOCKET);
if (!s) return -EBADF;
if (lock_buffer(name, sizeof(struct sockaddr), 1) < 0) {
orel(s);
return -EFAULT;
}
if (lock_buffer(namelen, 4, 1) < 0) {
orel(s);
unlock_buffer(name, sizeof(struct sockaddr));
return -EFAULT;
}
rc = getsockname(s, name, namelen);
orel(s);
unlock_buffer(namelen, 4);
unlock_buffer(name, sizeof(struct sockaddr));
return rc;
}
static int sys_getsockopt(char *params) {
handle_t h;
struct socket *s;
int rc;
int level;
int optname;
void *optval;
int *optlen;
int inoptlen;
h = *(handle_t *) params;
level = *(int *) (params + 4);
optname = *(int *) (params + 8);
optval = *(void **) (params + 12);
optlen = *(int **) (params + 16);
s = (struct socket *) olock(h, OBJECT_SOCKET);
if (!s) return -EBADF;
if (!optlen || lock_buffer(optlen, 4, 1) < 0) {
orel(s);
return -EFAULT;
}
inoptlen = *optlen;
if (lock_buffer(optval, inoptlen, 1) < 0) {
orel(s);
unlock_buffer(optlen, 4);
return -EFAULT;
}
rc = getsockopt(s, level, optname, optval, optlen);
orel(s);
unlock_buffer(optval, inoptlen);
unlock_buffer(optlen, 4);
return rc;
}
static int sys_listen(char *params) {
handle_t h;
struct socket *s;
int rc;
int backlog;
h = *(handle_t *) params;
backlog = *(int *) (params + 4);
s = (struct socket *) olock(h, OBJECT_SOCKET);
if (!s) return -EBADF;
rc = listen(s, backlog);
orel(s);
return rc;
}
static int sys_recv(char *params) {
handle_t h;
struct socket *s;
int rc;
void *data;
int size;
unsigned int flags;
h = *(handle_t *) params;
data = *(void **) (params + 4);
size = *(int *) (params + 8);
flags = *(unsigned int *) (params + 12);
s = (struct socket *) olock(h, OBJECT_SOCKET);
if (!s) return -EBADF;
if (lock_buffer(data, size, 1) < 0) {
orel(s);
return -EFAULT;
}
rc = recv(s, data, size, flags);
orel(s);
unlock_buffer(data, size);
return rc;
}
static int sys_recvfrom(char *params) {
handle_t h;
struct socket *s;
int rc;
void *data;
int size;
unsigned int flags;
struct sockaddr *from;
int *fromlen;
h = *(handle_t *) params;
data = *(void **) (params + 4);
size = *(int *) (params + 8);
flags = *(unsigned int *) (params + 12);
from = *(struct sockaddr **) (params + 16);
fromlen = *(int **) (params + 20);
s = (struct socket *) olock(h, OBJECT_SOCKET);
if (!s) return -EBADF;
if (lock_buffer(data, size, 1) < 0) {
orel(s);
return -EFAULT;
}
if (lock_buffer(from, sizeof(struct sockaddr), 1) < 0) {
orel(s);
unlock_buffer(data, size);
return -EFAULT;
}
if (lock_buffer(fromlen, sizeof(int), 1) < 0) {
orel(s);
unlock_buffer(from, sizeof(struct sockaddr));
unlock_buffer(data, size);
return -EFAULT;
}
rc = recvfrom(s, data, size, flags, from, fromlen);
orel(s);
unlock_buffer(fromlen, sizeof(int));
unlock_buffer(from, sizeof(struct sockaddr));
unlock_buffer(data, size);
return rc;
}
static int sys_send(char *params) {
handle_t h;
struct socket *s;
int rc;
void *data;
int size;
unsigned int flags;
h = *(handle_t *) params;
data = *(void **) (params + 4);
size = *(int *) (params + 8);
flags = *(unsigned int *) (params + 12);
s = (struct socket *) olock(h, OBJECT_SOCKET);
if (!s) return -EBADF;
if (lock_buffer(data, size, 0) < 0) {
orel(s);
return -EFAULT;
}
rc = send(s, data, size, flags);
orel(s);
unlock_buffer(data, size);
return rc;
}
static int sys_sendto(char *params) {
handle_t h;
struct socket *s;
int rc;
void *data;
int size;
unsigned int flags;
struct sockaddr *to;
int tolen;
h = *(handle_t *) params;
data = *(void **) (params + 4);
size = *(int *) (params + 8);
flags = *(unsigned int *) (params + 12);
to = *(struct sockaddr **) (params + 16);
tolen = *(int *) (params + 20);
s = (struct socket *) olock(h, OBJECT_SOCKET);
if (!s) return -EBADF;
if (lock_buffer(data, size, 0) < 0) {
orel(s);
return -EFAULT;
}
if (lock_buffer(to, sizeof(struct sockaddr), 0) < 0) {
orel(s);
unlock_buffer(data, size);
return -EFAULT;
}
rc = sendto(s, data, size, flags, to, tolen);
orel(s);
unlock_buffer(to, sizeof(struct sockaddr));
unlock_buffer(data, size);
return rc;
}
static int sys_setsockopt(char *params) {
handle_t h;
struct socket *s;
int rc;
int level;
int optname;
void *optval;
int optlen;
h = *(handle_t *) params;
level = *(int *) (params + 4);
optname = *(int *) (params + 8);
optval = *(void **) (params + 12);
optlen = *(int *) (params + 16);
s = (struct socket *) olock(h, OBJECT_SOCKET);
if (!s) return -EBADF;
if (lock_buffer(optval, optlen, 0) < 0) {
orel(s);
return -EFAULT;
}
rc = setsockopt(s, level, optname, optval, optlen);
orel(s);
unlock_buffer(optval, optlen);
return rc;
}
static int sys_shutdown(char *params) {
handle_t h;
struct socket *s;
int rc;
int how;
h = *(handle_t *) params;
how = *(int *) (params + 4);
s = (struct socket *) olock(h, OBJECT_SOCKET);
if (!s) return -EBADF;
rc = shutdown(s, how);
orel(s);
return rc;
}
static int sys_socket(char *params) {
int rc;
struct socket *s;
int domain;
int type;
int protocol;
domain = *(int *) params;
type = *(int *) (params + 4);
protocol = *(int *) (params + 8);
rc = socket(domain, type, protocol, &s);
if (rc == 0) {
rc = halloc(&s->iob.object);
if (rc < 0) closesocket(s);
}
return rc;
}
static int sys_readv(char *params) {
handle_t h;
struct object *o;
int rc;
struct iovec *iov;
int count;
h = *(handle_t *) params;
iov = *(struct iovec **) (params + 4);
count = *(int *) (params + 8);
o = olock(h, OBJECT_ANY);
if (!o) return -EBADF;
if (lock_iovec(iov, count, 1) < 0) {
orel(o);
return -EFAULT;
}
if (o->type == OBJECT_FILE) {
rc = readv((struct file *) o, iov, count);
} else if (o->type == OBJECT_SOCKET) {
rc = recvv((struct socket *) o, iov, count);
} else {
rc = -EBADF;
}
unlock_iovec(iov, count);
orel(o);
return rc;
}
static int sys_writev(char *params) {
handle_t h;
struct object *o;
int rc;
struct iovec *iov;
int count;
h = *(handle_t *) params;
iov = *(struct iovec **) (params + 4);
count = *(int *) (params + 8);
o = olock(h, OBJECT_ANY);
if (!o) return -EBADF;
if (lock_iovec(iov, count, 0) < 0) {
orel(o);
return -EFAULT;
}
if (o->type == OBJECT_FILE) {
rc = writev((struct file *) o, iov, count);
} else if (o->type == OBJECT_SOCKET) {
rc = sendv((struct socket *) o, iov, count);
} else {
rc = -EBADF;
}
unlock_iovec(iov, count);
orel(o);
return rc;
}
static int sys_chdir(char *params) {
char *name;
int rc;
name = *(char **) params;
if (lock_string(name) < 0) return -EFAULT;
rc = chdir(name);
unlock_string(name);
return rc;
}
static int sys_mkiomux(char *params) {
int flags;
struct iomux *iomux;
handle_t h;
flags = *(int *) params;
iomux = (struct iomux *) kmalloc(sizeof(struct iomux));
if (!iomux) return -ENOMEM;
init_iomux(iomux, flags);
h = halloc(&iomux->object);
if (h < 0) {
close_object(&iomux->object);
return h;
}
return h;
}
static int sys_dispatch(char *params) {
handle_t ioh;
handle_t h;
struct iomux *iomux;
struct object *o;
int events;
int context;
int rc;
ioh = *(handle_t *) params;
h = *(handle_t *) (params + 4);
events = *(int *) (params + 8);
context = *(int *) (params + 12);
iomux = (struct iomux *) olock(ioh, OBJECT_IOMUX);
if (!iomux) return -EBADF;
o = (struct object *) olock(h, OBJECT_ANY);
if (!o) {
orel(iomux);
return -EBADF;
}
rc = queue_ioobject(iomux, o, events, context);
orel(o);
orel(iomux);
return rc;
}
static int sys_recvmsg(char *params) {
handle_t h;
struct msghdr *msg;
unsigned int flags;
struct socket *s;
int rc;
h = *(handle_t *) params;
msg = *(struct msghdr **) (params + 4);
flags = *(unsigned int *) (params + 8);
s = (struct socket *) olock(h, OBJECT_SOCKET);
if (!s) return -EBADF;
if (lock_buffer(msg, sizeof(struct msghdr), 1) < 0) {
orel(s);
return -EFAULT;
}
if (lock_iovec(msg->msg_iov, msg->msg_iovlen, 1) < 0) {
unlock_buffer(msg, sizeof(struct msghdr));
orel(s);
return -EFAULT;
}
if (lock_buffer(msg->msg_name, msg->msg_namelen, 1) < 0) {
unlock_iovec(msg->msg_iov, msg->msg_iovlen);
unlock_buffer(msg, sizeof(struct msghdr));
orel(s);
return -EFAULT;
}
rc = recvmsg(s, msg, flags);
unlock_iovec(msg->msg_iov, msg->msg_iovlen);
unlock_buffer(msg, sizeof(struct msghdr));
orel(s);
return rc;
}
static int sys_sendmsg(char *params) {
handle_t h;
struct msghdr *msg;
unsigned int flags;
struct socket *s;
int rc;
h = *(handle_t *) params;
msg = *(struct msghdr **) (params + 4);
flags = *(unsigned int *) (params + 8);
s = (struct socket *) olock(h, OBJECT_SOCKET);
if (!s) return -EBADF;
if (lock_buffer(msg, sizeof(struct msghdr), 0) < 0) {
orel(s);
return -EFAULT;
}
if (lock_iovec(msg->msg_iov, msg->msg_iovlen, 0) < 0) {
unlock_buffer(msg, sizeof(struct msghdr));
orel(s);
return -EFAULT;
}
if (lock_buffer(msg->msg_name, msg->msg_namelen, 0) < 0) {
unlock_iovec(msg->msg_iov, msg->msg_iovlen);
unlock_buffer(msg, sizeof(struct msghdr));
orel(s);
return -EFAULT;
}
rc = sendmsg(s, msg, flags);
unlock_iovec(msg->msg_iov, msg->msg_iovlen);
unlock_buffer(msg, sizeof(struct msghdr));
orel(s);
return rc;
}
static int sys_select(char *params) {
int nfds;
fd_set *readfds;
fd_set *writefds;
fd_set *exceptfds;
struct timeval *timeout;
int rc;
nfds = *(int *) params;
readfds = *(fd_set **) (params + 4);
writefds = *(fd_set **) (params + 8);
exceptfds = *(fd_set **) (params + 12);
timeout = *(struct timeval **) (params + 16);
if (lock_fdset(readfds, 1) < 0) return -EFAULT;
if (lock_fdset(writefds, 1) < 0) {
unlock_fdset(readfds);
return -EFAULT;
}
if (lock_fdset(exceptfds, 1) < 0) {
unlock_fdset(writefds);
unlock_fdset(readfds);
return -EFAULT;
}
if (lock_buffer(timeout, sizeof(struct timeval), 1) < 0) {
unlock_fdset(exceptfds);
unlock_fdset(writefds);
unlock_fdset(readfds);
return -EFAULT;
}
rc = select(nfds, readfds, writefds, exceptfds, timeout);
unlock_buffer(timeout, sizeof(struct timeval));
unlock_fdset(exceptfds);
unlock_fdset(writefds);
unlock_fdset(readfds);
return rc;
}
static int sys_pipe(char *params) {
handle_t *fildes;
int rc;
struct file *readpipe;
struct file *writepipe;
fildes = *(handle_t **) params;
if (lock_buffer(fildes, sizeof(handle_t) * 2, 1) < 0) return -EFAULT;
rc = pipe(&readpipe, &writepipe);
if (rc == 0) {
fildes[0] = halloc(&readpipe->iob.object);
fildes[1] = halloc(&writepipe->iob.object);
if (fildes[0] < 0 || fildes[1] < 0) {
if (fildes[0] >= 0) hfree(fildes[0]);
if (fildes[1] >= 0) hfree(fildes[1]);
close(readpipe);
close(writepipe);
rc = -ENFILE;
}
}
unlock_buffer(fildes, sizeof(handle_t) * 2);
return rc;
}
static int sys_setmode(char *params) {
handle_t h;
struct file *f;
int rc;
int mode;
h = *(handle_t *) params;
mode = *(int *) (params + 4);
f = (struct file *) olock(h, OBJECT_FILE);
if (!f) return -EBADF;
rc = setmode(f, mode);
orel(f);
return rc;
}
static int sys_chmod(char *params) {
char *name;
int mode;
int rc;
name = *(char **) params;
mode = *(int *) (params + 4);
if (lock_string(name) < 0) return -EFAULT;
rc = chmod(name, mode);
unlock_string(name);
return rc;
}
static int sys_fchmod(char *params) {
handle_t h;
struct file *f;
int rc;
int mode;
h = *(handle_t *) params;
mode = *(int *) (params + 4);
f = (struct file *) olock(h, OBJECT_FILE);
if (!f) return -EBADF;
rc = fchmod(f, mode);
orel(f);
return rc;
}
static int sys_sysinfo(char *params) {
int rc;
int cmd;
void *data;
int size;
cmd = *(int *) params;
data = *(void **) (params + 4);
size = *(int *) (params + 8);
if (lock_buffer(data, size, 1) < 0) return -EFAULT;
switch (cmd) {
case SYSINFO_CPU:
if (!data || size < sizeof(struct cpuinfo)) {
rc = -EFAULT;
} else {
rc = cpu_sysinfo((struct cpuinfo *) data);
}
break;
case SYSINFO_MEM:
if (!data || size < sizeof(struct meminfo)) {
rc = -EFAULT;
} else {
rc = mem_sysinfo((struct meminfo *) data);
}
break;
case SYSINFO_LOAD:
if (!data || size < sizeof(struct loadinfo)) {
rc = -EFAULT;
} else {
rc = load_sysinfo((struct loadinfo *) data);
}
break;
default:
rc = -EINVAL;
}
unlock_buffer(data, size);
return rc;
}
static int sys_mkmutex(char *params) {
int owned;
struct mutex *m;
handle_t h;
owned = *(int *) params;
m = (struct mutex *) kmalloc(sizeof(struct mutex));
if (!m) return -ENOMEM;
init_mutex(m, owned);
h = halloc(&m->object);
if (h < 0) {
close_object(&m->object);
return h;
}
return h;
}
static int sys_mutexrel(char *params) {
handle_t h;
struct mutex *m;
int rc;
h = *(handle_t *) params;
m = (struct mutex *) olock(h, OBJECT_MUTEX);
if (!m) return -EBADF;
rc = release_mutex(m);
orel(m);
return rc;
}
static int sys_pread(char *params) {
handle_t h;
struct object *o;
int rc;
void *data;
int size;
off64_t offset;
h = *(handle_t *) params;
data = *(void **) (params + 4);
size = *(int *) (params + 8);
offset = *(off64_t *) (params + 12);
o = olock(h, OBJECT_FILE);
if (!o) return -EBADF;
if (lock_buffer(data, size, 1) < 0) {
orel(o);
return -EFAULT;
}
rc = pread((struct file *) o, data, size, offset);
orel(o);
unlock_buffer(data, size);
return rc;
}
static int sys_pwrite(char *params) {
handle_t h;
struct object *o;
int rc;
void *data;
int size;
off64_t offset;
h = *(handle_t *) params;
data = *(void **) (params + 4);
size = *(int *) (params + 8);
offset = *(off64_t *) (params + 12);
o = olock(h, OBJECT_FILE);
if (!o) return -EBADF;
if (lock_buffer(data, size, 0) < 0) {
orel(o);
return -EFAULT;
}
rc = pwrite((struct file *) o, data, size, offset);
orel(o);
unlock_buffer(data, size);
return rc;
}
static int sys_getuid(char *params) {
return getuid();
}
static int sys_setuid(char *params) {
uid_t uid;
uid = *(uid_t *) params;
return setuid(uid);
}
static int sys_getgid(char *params) {
return getgid();
}
static int sys_setgid(char *params) {
gid_t gid;
gid = *(gid_t *) params;
return setgid(gid);
}
static int sys_geteuid(char *params) {
return geteuid();
}
static int sys_seteuid(char *params) {
uid_t uid;
uid = *(uid_t *) params;
return seteuid(uid);
}
static int sys_getegid(char *params) {
return getegid();
}
static int sys_setegid(char *params) {
gid_t gid;
gid = *(gid_t *) params;
return setegid(gid);
}
static int sys_getgroups(char *params) {
int rc;
int size;
gid_t *list;
size = *(int *) params;
list = *(gid_t **) (params + 4);
if (lock_buffer(list, size * sizeof(gid_t), 1) < 0) return -EFAULT;
rc = getgroups(size, list);
unlock_buffer(list, size * sizeof(gid_t));
return rc;
}
static int sys_setgroups(char *params) {
int rc;
int size;
gid_t *list;
size = *(int *) params;
list = *(gid_t **) (params + 4);
if (lock_buffer(list, size * sizeof(gid_t), 0) < 0) return -EFAULT;
rc = setgroups(size, list);
unlock_buffer(list, size * sizeof(gid_t));
return rc;
}
static int sys_chown(char *params) {
char *name;
int owner;
int group;
int rc;
name = *(char **) params;
owner = *(int *) (params + 4);
group = *(int *) (params + 8);
if (lock_string(name) < 0) return -EFAULT;
rc = chown(name, owner, group);
unlock_string(name);
return rc;
}
static int sys_fchown(char *params) {
handle_t h;
struct file *f;
int rc;
int owner;
int group;
h = *(handle_t *) params;
owner = *(int *) (params + 4);
group = *(int *) (params + 8);
f = (struct file *) olock(h, OBJECT_FILE);
if (!f) return -EBADF;
rc = fchown(f, owner, group);
orel(f);
return rc;
}
static int sys_access(char *params) {
char *name;
int mode;
int rc;
name = *(char **) params;
mode = *(int *) (params + 4);
if (lock_string(name) < 0) return -EFAULT;
rc = access(name, mode);
unlock_string(name);
return rc;
}
static int sys_poll(char *params) {
struct pollfd *fds;
unsigned int nfds;
int timeout;
int rc;
fds = *(struct pollfd **) params;
nfds = *(unsigned int *) (params + 4);
timeout = *(int *) (params + 8);
if (lock_buffer(fds, nfds * sizeof(struct pollfd), 1) < 0) return -EFAULT;
rc = poll(fds, nfds, timeout);
unlock_buffer(fds, nfds * sizeof(struct pollfd));
return rc;
}
static int sys_getcwd(char *params) {
char *buf;
int size;
int rc;
buf = *(char **) params;
size = *(unsigned int *) (params + 4);
if (lock_buffer(buf, size, 1) < 0) return -EFAULT;
rc = getcwd(buf, size);
unlock_buffer(buf, size);
return rc;
}
static int sys_sendsig(char *params) {
handle_t h;
int signum;
struct thread *t;
int rc;
h = *(handle_t *) params;
signum = *(int *) (params + 4);
t = (struct thread *) olock(h, OBJECT_THREAD);
if (!t) return -EBADF;
rc = send_user_signal(t, signum);
orel(t);
return rc;
}
static int sys_sigprocmask(char *params) {
int how;
sigset_t *set;
sigset_t *oldset;
int rc;
how = *(int *) params;
set = *(sigset_t **) (params + 4);
oldset = *(sigset_t **) (params + 8);
if (lock_buffer(set, sizeof(sigset_t), 0) < 0) return -EFAULT;
if (lock_buffer(oldset, sizeof(sigset_t), 1) < 0) {
unlock_buffer(set, sizeof(sigset_t));
return -EFAULT;
}
rc = set_signal_mask(how, set, oldset);
unlock_buffer(set, sizeof(sigset_t));
unlock_buffer(oldset, sizeof(sigset_t));
return rc;
}
static int sys_sigpending(char *params) {
sigset_t *set;
int rc;
set = *(sigset_t **) params;
if (lock_buffer(set, sizeof(sigset_t), 1) < 0) return -EFAULT;
rc = get_pending_signals(set);
unlock_buffer(set, sizeof(sigset_t));
return rc;
}
static int sys_alarm(char *params) {
unsigned int seconds;
int rc;
seconds = *(unsigned int *) params;
rc = schedule_alarm(seconds);
return rc;
}
struct syscall_entry syscalltab[] = {
{"null",0, "", sys_null},
{"mkfs", 12, "'%s','%s','%s'", sys_mkfs},
{"mount", 16, "'%s','%s','%s','%s'", sys_mount},
{"umount", 4, "'%s'", sys_umount},
{"open", 12, "'%s',%x,%x", sys_open},
{"close", 4, "%d", sys_close},
{"fsync", 4, "%d", sys_fsync},
{"read", 12, "%d,%p,%d", sys_read},
{"write", 12, "%d,%p,%d", sys_write},
{"tell", 8, "%d,%p", sys_tell},
{"lseek", 10, "%d,%d-%d,%d,%p", sys_lseek},
{"ftruncate", 12, "%d,%d-%d", sys_ftruncate},
{"fstat", 8, "%d,%p", sys_fstat},
{"stat", 8, "'%s',%p", sys_stat},
{"mkdir", 8, "'%s',%d", sys_mkdir},
{"rmdir", 4, "'%s'", sys_rmdir},
{"rename", 8, "'%s','%s'", sys_rename},
{"link", 8, "'%s','%s'", sys_link},
{"unlink", 4, "'%s'", sys_unlink},
{"opendir", 4, "'%s'", sys_opendir},
{"readdir", 12, "%d,%p,%d", sys_readdir},
{"vmalloc", 16, "%p,%d,%x,%x", sys_vmalloc},
{"vmfree", 12, "%p,%d,%x", sys_vmfree},
{"vmrealloc", 20, "%p,%d,%d,%x,%x", sys_vmrealloc},
{"vmprotect", 12, "%p,%d,%x", sys_vmprotect},
{"vmlock", 8, "%p,%d", sys_vmlock},
{"vmunlock", 8, "%p,%d", sys_vmunlock},
{"waitone", 8, "%d,%d", sys_waitone},
{"mkevent", 8, "%d,%d", sys_mkevent},
{"epulse", 4, "%d", sys_epulse},
{"eset", 4, "%d", sys_eset},
{"ereset", 4, "%d", sys_ereset},
{"getthreadblock", 4, "%d", sys_getthreadblock},
{"exitos", 4, "%d", sys_exitos},
{"dup", 4, "%d", sys_dup},
{"mkthread", 12, "%p,%d,%p", sys_mkthread},
{"suspend", 4, "%d", sys_suspend},
{"resume", 4, "%d", sys_resume},
{"endthread", 4, "%d", sys_endthread},
{"setcontext", 8, "%d,%p", sys_setcontext},
{"getcontext", 8, "%d,%p", sys_getcontext},
{"getprio", 4, "%d", sys_getprio},
{"setprio", 8, "%d,%d", sys_setprio},
{"msleep", 4, "%d", sys_msleep},
{"time", 0, "", sys_time},
{"gettimeofday", 8, "%p,%p", sys_gettimeofday},
{"clock", 0, "", sys_clock},
{"mksem", 4, "%d", sys_mksem},
{"semrel", 8, "%p,%d", sys_semrel},
{"ioctl", 16, "%d,%x,%p,%d", sys_ioctl},
{"getfsstat", 8, "%p,%d", sys_getfsstat},
{"fstatfs", 8, "%d,%p", sys_fstatfs},
{"statfs", 8, "'%s',%p", sys_statfs},
{"futime", 8, "%d,%p", sys_futime},
{"utime", 8, "'%s',%p", sys_utime},
{"settimeofday", 4, "%p", sys_settimeofday},
{"accept", 12, "%d,%p,%p", sys_accept},
{"bind", 12, "%d,%p,%d", sys_bind},
{"connect", 12, "%d,%p,%d", sys_connect},
{"getpeername", 12, "%d,%p,%p", sys_getpeername},
{"getsockname", 12, "%d,%p,%p", sys_getsockname},
{"getsockopt", 20, "%d,%d,%d,%p,%p", sys_getsockopt},
{"listen", 8, "%d,%d", sys_listen},
{"recv", 16, "%d,%p,%d,%d", sys_recv},
{"recvfrom", 24, "%d,%p,%d,%d,%p,%p", sys_recvfrom},
{"send", 16, "%d,%p,%d,%d", sys_send},
{"sendto", 24, "%d,%p,%d,%d,%p,%d", sys_sendto},
{"setsockopt", 20, "%d,%d,%d,%p,%d", sys_setsockopt},
{"shutdown", 8, "%d,%d", sys_shutdown},
{"socket", 12, "%d,%d,%d", sys_socket},
{"waitall", 12, "%p,%d,%d", sys_waitall},
{"waitany", 12, "%p,%d,%d", sys_waitany},
{"readv", 12, "%d,%p,%d", sys_readv},
{"writev", 12, "%d,%p,%d", sys_writev},
{"chdir", 4, "'%s'", sys_chdir},
{"mkiomux", 4, "%d", sys_mkiomux},
{"dispatch", 16, "%d,%d,%d,%d", sys_dispatch},
{"recvmsg", 12, "%d,%p,%d", sys_recvmsg},
{"sendmsg", 12, "%d,%p,%d", sys_sendmsg},
{"select", 20, "%d,%p,%p,%p,%p", sys_select},
{"pipe", 4, "%p", sys_pipe},
{"dup2", 8, "%d,%d", sys_dup2},
{"setmode", 8, "%d,%d", sys_setmode},
{"chmod", 8, "'%s',%d", sys_chmod},
{"fchmod", 8, "%d,%d", sys_fchmod},
{"sysinfo", 12, "%d,%p,%d", sys_sysinfo},
{"mkmutex", 4, "%d", sys_mkmutex},
{"mutexrel", 4, "%p", sys_mutexrel},
{"pread", 20, "%d,%p,%d,%d-%d", sys_pread},
{"pwrite", 20, "%d,%p,%d,%d-%d", sys_pwrite},
{"getuid", 0, "", sys_getuid},
{"setuid", 4, "%d", sys_setuid},
{"getgid", 0, "", sys_getgid},
{"setgid", 4, "%d", sys_setgid},
{"geteuid", 0, "", sys_geteuid},
{"seteuid", 4, "%d", sys_seteuid},
{"getegid", 0, "", sys_getegid},
{"setegid", 4, "%d", sys_setegid},
{"getgroups", 8, "%d,%p", sys_getgroups},
{"setgroups", 8, "%d,%p", sys_setgroups},
{"chown", 12, "'%s',%d,%d", sys_chown},
{"fchown", 12, "%d,%d,%d", sys_fchown},
{"access", 8, "'%s',%d", sys_access},
{"poll", 12, "%p,%d,%d", sys_poll},
{"getcwd", 8, "%p,%d", sys_getcwd},
{"sendsig", 8, "%d,%d", sys_sendsig},
{"sigprocmask", 12, "%d,%p,%p", sys_sigprocmask},
{"sigpending", 4, "%p", sys_sigpending},
{"alarm", 4, "%d", sys_alarm},
{"vmmap", 24, "%p,%d,%x,%d,%d-%d", sys_vmmap},
{"vmsync", 8, "%p,%d", sys_vmsync},
{"threadtimes", 8, "%d,%p", sys_threadtimes},
};
int syscall(int syscallno, char *params, struct context *ctxt) {
int rc;
struct thread *t = self();
t->ctxt = ctxt;
if (syscallno < 0 || syscallno > SYSCALL_MAX) return -ENOSYS;
#ifdef SYSCALL_LOGENTER
#ifndef SYSCALL_LOGWAIT
if (syscallno != SYSCALL_WAITONE && syscallno != SYSCALL_WAITALL && syscallno != SYSCALL_WAITANY)
#endif
{
char buf[1024];
vsprintf(buf, syscalltab[syscallno].argfmt, params);
print_string("<-");
print_string(syscalltab[syscallno].name);
print_string("(");
print_string(buf);
print_string(")\n");
}
#endif
#ifdef SYSCALL_PROFILE
sccnt[syscallno]++;
#endif
rc = lock_buffer(params, syscalltab[syscallno].paramsize, 0);
if (rc >= 0) {
rc = syscalltab[syscallno].func(params);
unlock_buffer(params, syscalltab[syscallno].paramsize);
}
if (rc < 0) {
struct tib *tib = t->tib;
if (tib) tib->errnum = -rc;
#ifdef SYSCALL_PROFILE
scerr[syscallno]++;
#endif
}
#if defined(SYSCALL_LOGEXIT) || defined(SYSCALL_LOGONLYERRORS)
#ifdef SYSCALL_LOGONLYERRORS
#ifdef SYSCALL_LOGTIMEOUTS
if (rc < 0)
#else
if (rc < 0 && rc != -ETIMEOUT)
#endif
#else
#ifndef SYSCALL_LOGWAIT
if (syscallno != SYSCALL_WAITONE && syscallno != SYSCALL_WAITALL && syscallno != SYSCALL_WAITANY)
#endif
#endif
{
char buf[1024];
char rcstr[16];
vsprintf(buf, syscalltab[syscallno].argfmt, params);
sprintf(rcstr, "%d", rc);
print_string(syscalltab[syscallno].name);
print_string("(");
print_string(buf);
print_string(") -> ");
print_string(rcstr);
print_string("\n");
}
#endif
check_dpc_queue();
check_preempt();
if (signals_ready(t)) deliver_pending_signals(rc);
t->ctxt = NULL;
if (rc < 0) return -1;
return rc;
}
#ifdef SYSCALL_PROFILE
static int syscalls_proc(struct proc_file *pf, void *arg) {
int i = 0;
pprintf(pf, "syscall calls errors\n");
pprintf(pf, "---------------- ---------- ----------\n");
for (i = 0; i < SYSCALL_MAX + 1; i++) {
if (sccnt[i] != 0) {
pprintf(pf, "%-16s %10d %10d\n", syscalltab[i].name, sccnt[i], scerr[i]);
}
}
return 0;
}
#endif
void init_syscall() {
#ifdef SYSCALL_PROFILE
register_proc_inode("syscalls", syscalls_proc, NULL);
#endif
}