sys.c

来自「xen虚拟机源代码安装包」· C语言 代码 · 共 1,232 行 · 第 1/2 页

C
1,232
字号
/* * POSIX-compatible libc layer * * Samuel Thibault <Samuel.Thibault@eu.citrix.net>, October 2007 * * Provides the UNIXish part of the standard libc function. * * Relatively straight-forward: just multiplex the file descriptor operations * among the various file types (console, FS, network, ...) *///#define LIBC_VERBOSE//#define LIBC_DEBUG#ifdef LIBC_DEBUG#define DEBUG(fmt,...) printk(fmt, ##__VA_ARGS__)#else#define DEBUG(fmt,...)#endif#ifdef HAVE_LIBC#include <os.h>#include <console.h>#include <sched.h>#include <events.h>#include <wait.h>#include <netfront.h>#include <blkfront.h>#include <fbfront.h>#include <xenbus.h>#include <xs.h>#include <sys/types.h>#include <sys/unistd.h>#include <sys/stat.h>#include <sys/mman.h>#include <time.h>#include <errno.h>#include <fcntl.h>#include <pthread.h>#include <assert.h>#include <dirent.h>#include <stdlib.h>#include <math.h>#ifdef HAVE_LWIP#include <lwip/sockets.h>#endif#include <fs.h>#define debug(fmt, ...) \#define print_unsupported(fmt, ...) \    printk("Unsupported function "fmt" called in Mini-OS kernel\n", ## __VA_ARGS__);/* Crash on function call */#define unsupported_function_crash(function) \    int __unsup_##function(void) asm(#function); \    int __unsup_##function(void) \    { \	print_unsupported(#function); \	do_exit(); \    }/* Log and err out on function call */#define unsupported_function_log(type, function, ret) \    type __unsup_##function(void) asm(#function); \    type __unsup_##function(void) \    { \	print_unsupported(#function); \	errno = ENOSYS; \	return ret; \    }/* Err out on function call */#define unsupported_function(type, function, ret) \    type __unsup_##function(void) asm(#function); \    type __unsup_##function(void) \    { \	errno = ENOSYS; \	return ret; \    }#define NOFILE 32extern int xc_evtchn_close(int fd);extern int xc_interface_close(int fd);extern int xc_gnttab_close(int fd);pthread_mutex_t fd_lock = PTHREAD_MUTEX_INITIALIZER;struct file files[NOFILE] = {    { .type = FTYPE_CONSOLE }, /* stdin */    { .type = FTYPE_CONSOLE }, /* stdout */    { .type = FTYPE_CONSOLE }, /* stderr */};DECLARE_WAIT_QUEUE_HEAD(event_queue);int alloc_fd(enum fd_type type){    int i;    pthread_mutex_lock(&fd_lock);    for (i=0; i<NOFILE; i++) {	if (files[i].type == FTYPE_NONE) {	    files[i].type = type;	    pthread_mutex_unlock(&fd_lock);	    return i;	}    }    pthread_mutex_unlock(&fd_lock);    printk("Too many opened files\n");    do_exit();}void close_all_files(void){    int i;    pthread_mutex_lock(&fd_lock);    for (i=NOFILE - 1; i > 0; i--)	if (files[i].type != FTYPE_NONE)            close(i);    pthread_mutex_unlock(&fd_lock);}int dup2(int oldfd, int newfd){    pthread_mutex_lock(&fd_lock);    if (files[newfd].type != FTYPE_NONE)	close(newfd);    // XXX: this is a bit bogus, as we are supposed to share the offset etc    files[newfd] = files[oldfd];    pthread_mutex_unlock(&fd_lock);    return 0;}pid_t getpid(void){    return 1;}pid_t getppid(void){    return 1;}pid_t setsid(void){    return 1;}char *getcwd(char *buf, size_t size){    snprintf(buf, size, "/");    return buf;}#define LOG_PATH "/var/log/"int mkdir(const char *pathname, mode_t mode){    int ret;    ret = fs_create(fs_import, (char *) pathname, 1, mode);    if (ret < 0) {        errno = EIO;        return -1;    }    return 0;}int open(const char *pathname, int flags, ...){    int fs_fd, fd;    /* Ugly, but fine.  */    if (!strncmp(pathname,LOG_PATH,strlen(LOG_PATH))) {	fd = alloc_fd(FTYPE_CONSOLE);        printk("open(%s) -> %d\n", pathname, fd);        return fd;    }    printk("open(%s, %x)", pathname, flags);    switch (flags & ~O_ACCMODE) {        case 0:            fs_fd = fs_open(fs_import, (void *) pathname);            break;        case O_CREAT|O_TRUNC:        {            va_list ap;            mode_t mode;            va_start(ap, flags);            mode = va_arg(ap, mode_t);            va_end(ap);            fs_fd = fs_create(fs_import, (void *) pathname, 0, mode);            break;        }        default:            printk(" unsupported flags\n");            do_exit();    }    if (fs_fd < 0) {	errno = EIO;	return -1;    }    fd = alloc_fd(FTYPE_FILE);    printk("-> %d\n", fd);    files[fd].file.fd = fs_fd;    files[fd].file.offset = 0;    return fd;}int isatty(int fd){    return files[fd].type == FTYPE_CONSOLE;}int read(int fd, void *buf, size_t nbytes){    switch (files[fd].type) {	case FTYPE_CONSOLE: {	    int ret;            DEFINE_WAIT(w);            while(1) {                add_waiter(w, console_queue);                ret = xencons_ring_recv(buf, nbytes);                if (ret)                    break;                schedule();            }            remove_waiter(w);            return ret;        }	case FTYPE_FILE: {	    ssize_t ret;	    if (nbytes > PAGE_SIZE * FSIF_NR_READ_GNTS)		nbytes = PAGE_SIZE * FSIF_NR_READ_GNTS;	    ret = fs_read(fs_import, files[fd].file.fd, buf, nbytes, files[fd].file.offset);	    if (ret > 0) {		files[fd].file.offset += ret;		return ret;	    } else if (ret < 0) {		errno = EIO;		return -1;	    }	    return 0;	}#ifdef HAVE_LWIP	case FTYPE_SOCKET:	    return lwip_read(files[fd].socket.fd, buf, nbytes);#endif	case FTYPE_TAP: {	    ssize_t ret;	    ret = netfront_receive(files[fd].tap.dev, buf, nbytes);	    if (ret <= 0) {		errno = EAGAIN;		return -1;	    }	    return ret;	}        case FTYPE_KBD: {            int ret, n;            n = nbytes / sizeof(union xenkbd_in_event);            ret = kbdfront_receive(files[fd].kbd.dev, buf, n);	    if (ret <= 0) {		errno = EAGAIN;		return -1;	    }	    return ret * sizeof(union xenkbd_in_event);        }        case FTYPE_FB: {            int ret, n;            n = nbytes / sizeof(union xenfb_in_event);            ret = fbfront_receive(files[fd].fb.dev, buf, n);	    if (ret <= 0) {		errno = EAGAIN;		return -1;	    }	    return ret * sizeof(union xenfb_in_event);        }	default:	    break;    }    printk("read(%d): Bad descriptor\n", fd);    errno = EBADF;    return -1;}int write(int fd, const void *buf, size_t nbytes){    switch (files[fd].type) {	case FTYPE_CONSOLE:	    console_print((char *)buf, nbytes);	    return nbytes;	case FTYPE_FILE: {	    ssize_t ret;	    if (nbytes > PAGE_SIZE * FSIF_NR_WRITE_GNTS)		nbytes = PAGE_SIZE * FSIF_NR_WRITE_GNTS;	    ret = fs_write(fs_import, files[fd].file.fd, (void *) buf, nbytes, files[fd].file.offset);	    if (ret > 0) {		files[fd].file.offset += ret;		return ret;	    } else if (ret < 0) {		errno = EIO;		return -1;	    }	    return 0;	}#ifdef HAVE_LWIP	case FTYPE_SOCKET:	    return lwip_write(files[fd].socket.fd, (void*) buf, nbytes);#endif	case FTYPE_TAP:	    netfront_xmit(files[fd].tap.dev, (void*) buf, nbytes);	    return nbytes;	default:	    break;    }    printk("write(%d): Bad descriptor\n", fd);    errno = EBADF;    return -1;}off_t lseek(int fd, off_t offset, int whence){    if (files[fd].type != FTYPE_FILE) {	errno = ESPIPE;	return (off_t) -1;    }    switch (whence) {	case SEEK_SET:	    files[fd].file.offset = offset;	    break;	case SEEK_CUR:	    files[fd].file.offset += offset;	    break;	case SEEK_END: {	    struct stat st;	    int ret;	    ret = fstat(fd, &st);	    if (ret)		return -1;	    files[fd].file.offset = st.st_size + offset;	    break;	}	default:	    errno = EINVAL;	    return -1;    }    return files[fd].file.offset;}int fsync(int fd) {    switch (files[fd].type) {	case FTYPE_FILE: {	    int ret;	    ret = fs_sync(fs_import, files[fd].file.fd);	    if (ret < 0) {		errno = EIO;		return -1;	    }	    return 0;	}	default:	    break;    }    printk("fsync(%d): Bad descriptor\n", fd);    errno = EBADF;    return -1;}int close(int fd){    printk("close(%d)\n", fd);    switch (files[fd].type) {        default:	    files[fd].type = FTYPE_NONE;	    return 0;	case FTYPE_FILE: {	    int ret = fs_close(fs_import, files[fd].file.fd);	    files[fd].type = FTYPE_NONE;	    if (ret < 0) {		errno = EIO;		return -1;	    }	    return 0;	}	case FTYPE_XENBUS:            xs_daemon_close((void*)(intptr_t) fd);            return 0;#ifdef HAVE_LWIP	case FTYPE_SOCKET: {	    int res = lwip_close(files[fd].socket.fd);	    files[fd].type = FTYPE_NONE;	    return res;	}#endif	case FTYPE_XC:	    xc_interface_close(fd);	    return 0;	case FTYPE_EVTCHN:            xc_evtchn_close(fd);            return 0;	case FTYPE_GNTMAP:	    xc_gnttab_close(fd);	    return 0;	case FTYPE_TAP:	    shutdown_netfront(files[fd].tap.dev);	    files[fd].type = FTYPE_NONE;	    return 0;	case FTYPE_BLK:            shutdown_blkfront(files[fd].blk.dev);	    files[fd].type = FTYPE_NONE;	    return 0;	case FTYPE_KBD:            shutdown_kbdfront(files[fd].kbd.dev);            files[fd].type = FTYPE_NONE;            return 0;	case FTYPE_FB:            shutdown_fbfront(files[fd].fb.dev);            files[fd].type = FTYPE_NONE;            return 0;	case FTYPE_NONE:	    break;    }    printk("close(%d): Bad descriptor\n", fd);    errno = EBADF;    return -1;}static void init_stat(struct stat *buf){    memset(buf, 0, sizeof(*buf));    buf->st_dev = 0;    buf->st_ino = 0;    buf->st_nlink = 1;    buf->st_rdev = 0;    buf->st_blksize = 4096;    buf->st_blocks = 0;}static void stat_from_fs(struct stat *buf, struct fsif_stat_response *stat){    buf->st_mode = stat->stat_mode;    buf->st_uid = stat->stat_uid;    buf->st_gid = stat->stat_gid;    buf->st_size = stat->stat_size;    buf->st_atime = stat->stat_atime;    buf->st_mtime = stat->stat_mtime;    buf->st_ctime = stat->stat_ctime;}int stat(const char *path, struct stat *buf){    struct fsif_stat_response stat;    int ret;    int fs_fd;    printk("stat(%s)\n", path);    fs_fd = fs_open(fs_import, (char*) path);    if (fs_fd < 0) {	errno = EIO;	ret = -1;	goto out;    }    ret = fs_stat(fs_import, fs_fd, &stat);    if (ret < 0) {	errno = EIO;	ret = -1;	goto outfd;    }    init_stat(buf);    stat_from_fs(buf, &stat);    ret = 0;outfd:    fs_close(fs_import, fs_fd);out:    return ret;}int fstat(int fd, struct stat *buf){    init_stat(buf);    switch (files[fd].type) {	case FTYPE_CONSOLE:	case FTYPE_SOCKET: {	    buf->st_mode = (files[fd].type == FTYPE_CONSOLE?S_IFCHR:S_IFSOCK) | S_IRUSR|S_IWUSR;	    buf->st_uid = 0;	    buf->st_gid = 0;	    buf->st_size = 0;	    buf->st_atime = 	    buf->st_mtime = 	    buf->st_ctime = time(NULL);	    return 0;	}	case FTYPE_FILE: {	    struct fsif_stat_response stat;	    int ret;	    ret = fs_stat(fs_import, files[fd].file.fd, &stat);	    if (ret < 0) {		errno = EIO;		return -1;	    }	    /* The protocol is a bit evasive about this value */	    stat_from_fs(buf, &stat);	    return 0;	}	default:	    break;    }    printk("statf(%d): Bad descriptor\n", fd);    errno = EBADF;    return -1;}int ftruncate(int fd, off_t length){    switch (files[fd].type) {	case FTYPE_FILE: {            int ret;            ret = fs_truncate(fs_import, files[fd].file.fd, length);	    if (ret < 0) {		errno = EIO;		return -1;	    }	    return 0;	}	default:	    break;    }    printk("ftruncate(%d): Bad descriptor\n", fd);    errno = EBADF;    return -1;}int remove(const char *pathname){    int ret;    printk("remove(%s)", pathname);    ret = fs_remove(fs_import, (char*) pathname);    if (ret < 0) {        errno = EIO;        return -1;    }    return 0;}int unlink(const char *pathname){    return remove(pathname);}int rmdir(const char *pathname){    return remove(pathname);}int fcntl(int fd, int cmd, ...){    long arg;    va_list ap;    va_start(ap, cmd);    arg = va_arg(ap, long);    va_end(ap);    switch (cmd) {#ifdef HAVE_LWIP	case F_SETFL:	    if (files[fd].type == FTYPE_SOCKET && !(arg & ~O_NONBLOCK)) {		/* Only flag supported: non-blocking mode */		uint32_t nblock = !!(arg & O_NONBLOCK);		return lwip_ioctl(files[fd].socket.fd, FIONBIO, &nblock);	    }	    /* Fallthrough */#endif	default:	    printk("fcntl(%d, %d, %lx/%lo)\n", fd, cmd, arg, arg);	    errno = ENOSYS;	    return -1;    }}DIR *opendir(const char *name){    DIR *ret;    ret = malloc(sizeof(*ret));    ret->name = strdup(name);    ret->offset = 0;    ret->entries = NULL;    ret->curentry = -1;    ret->nbentries = 0;    ret->has_more = 1;    return ret;}struct dirent *readdir(DIR *dir){    if (dir->curentry >= 0) {        free(dir->entries[dir->curentry]);        dir->entries[dir->curentry] = NULL;    }    dir->curentry++;    if (dir->curentry >= dir->nbentries) {        dir->offset += dir->nbentries;        free(dir->entries);        dir->curentry = -1;        dir->nbentries = 0;        if (!dir->has_more)            return NULL;        dir->entries = fs_list(fs_import, dir->name, dir->offset, &dir->nbentries, &dir->has_more);        if (!dir->entries || !dir->nbentries)            return NULL;        dir->curentry = 0;    }    dir->dirent.d_name = dir->entries[dir->curentry];    return &dir->dirent;} int closedir(DIR *dir){

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?