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 + -
显示快捷键?