/* * POSIX-compatible libc layer * * Samuel Thibault , 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_LWIP #include #endif #include #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 32 extern 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 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 posix_openpt(int flags) { struct consfront_dev *dev; /* Ignore flags */ dev = init_consfront(NULL); dev->fd = alloc_fd(FTYPE_CONSOLE); files[dev->fd].cons.dev = dev; printk("fd(%d) = posix_openpt\n", dev->fd); return(dev->fd); } 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; } if (!strncmp(pathname, "/dev/ptmx", strlen("/dev/ptmx"))) return posix_openpt(flags); 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(files[fd].cons.dev, 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(files[fd].cons.dev, (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_CONSOLE: fini_console(files[fd].cons.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) { int i; for (i=0; inbentries; i++) free(dir->entries[i]); free(dir->entries); free(dir->name); free(dir); return 0; } /* We assume that only the main thread calls select(). */ static const char file_types[] = { [FTYPE_NONE] = 'N', [FTYPE_CONSOLE] = 'C', [FTYPE_FILE] = 'F', [FTYPE_XENBUS] = 'S', [FTYPE_XC] = 'X', [FTYPE_EVTCHN] = 'E', [FTYPE_SOCKET] = 's', [FTYPE_TAP] = 'T', [FTYPE_BLK] = 'B', [FTYPE_KBD] = 'K', [FTYPE_FB] = 'G', }; #ifdef LIBC_DEBUG static void dump_set(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout) { int i, comma; #define printfds(set) do {\ comma = 0; \ for (i = 0; i < nfds; i++) { \ if (FD_ISSET(i, set)) { \ if (comma) \ printk(", "); \ printk("%d(%c)", i, file_types[files[i].type]); \ comma = 1; \ } \ } \ } while (0) printk("["); if (readfds) printfds(readfds); printk("], ["); if (writefds) printfds(writefds); printk("], ["); if (exceptfds) printfds(exceptfds); printk("], "); if (timeout) printk("{ %ld, %ld }", timeout->tv_sec, timeout->tv_usec); } #else #define dump_set(nfds, readfds, writefds, exceptfds, timeout) #endif /* Just poll without blocking */ static int select_poll(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds) { int i, n = 0; #ifdef HAVE_LWIP int sock_n = 0, sock_nfds = 0; fd_set sock_readfds, sock_writefds, sock_exceptfds; struct timeval timeout = { .tv_sec = 0, .tv_usec = 0}; #endif #ifdef LIBC_VERBOSE static int nb; static int nbread[NOFILE], nbwrite[NOFILE], nbexcept[NOFILE]; static s_time_t lastshown; nb++; #endif #ifdef HAVE_LWIP /* first poll network */ FD_ZERO(&sock_readfds); FD_ZERO(&sock_writefds); FD_ZERO(&sock_exceptfds); for (i = 0; i < nfds; i++) { if (files[i].type == FTYPE_SOCKET) { if (FD_ISSET(i, readfds)) { FD_SET(files[i].socket.fd, &sock_readfds); sock_nfds = i+1; } if (FD_ISSET(i, writefds)) { FD_SET(files[i].socket.fd, &sock_writefds); sock_nfds = i+1; } if (FD_ISSET(i, exceptfds)) { FD_SET(files[i].socket.fd, &sock_exceptfds); sock_nfds = i+1; } } } if (sock_nfds > 0) { DEBUG("lwip_select("); dump_set(nfds, &sock_readfds, &sock_writefds, &sock_exceptfds, &timeout); DEBUG("); -> "); sock_n = lwip_select(sock_nfds, &sock_readfds, &sock_writefds, &sock_exceptfds, &timeout); dump_set(nfds, &sock_readfds, &sock_writefds, &sock_exceptfds, &timeout); DEBUG("\n"); } #endif /* Then see others as well. */ for (i = 0; i < nfds; i++) { switch(files[i].type) { default: if (FD_ISSET(i, readfds) || FD_ISSET(i, writefds) || FD_ISSET(i, exceptfds)) printk("bogus fd %d in select\n", i); /* Fallthrough. */ case FTYPE_FILE: FD_CLR(i, readfds); FD_CLR(i, writefds); FD_CLR(i, exceptfds); break; case FTYPE_CONSOLE: if (FD_ISSET(i, readfds)) { if (xencons_ring_avail(files[i].cons.dev)) n++; else FD_CLR(i, readfds); } if (FD_ISSET(i, writefds)) n++; FD_CLR(i, exceptfds); break; case FTYPE_XENBUS: if (FD_ISSET(i, readfds)) { if (files[i].xenbus.events) n++; else FD_CLR(i, readfds); } FD_CLR(i, writefds); FD_CLR(i, exceptfds); break; case FTYPE_EVTCHN: case FTYPE_TAP: case FTYPE_BLK: case FTYPE_KBD: case FTYPE_FB: if (FD_ISSET(i, readfds)) { if (files[i].read) n++; else FD_CLR(i, readfds); } FD_CLR(i, writefds); FD_CLR(i, exceptfds); break; #ifdef HAVE_LWIP case FTYPE_SOCKET: if (FD_ISSET(i, readfds)) { /* Optimize no-network-packet case. */ if (sock_n && FD_ISSET(files[i].socket.fd, &sock_readfds)) n++; else FD_CLR(i, readfds); } if (FD_ISSET(i, writefds)) { if (sock_n && FD_ISSET(files[i].socket.fd, &sock_writefds)) n++; else FD_CLR(i, writefds); } if (FD_ISSET(i, exceptfds)) { if (sock_n && FD_ISSET(files[i].socket.fd, &sock_exceptfds)) n++; else FD_CLR(i, exceptfds); } break; #endif } #ifdef LIBC_VERBOSE if (FD_ISSET(i, readfds)) nbread[i]++; if (FD_ISSET(i, writefds)) nbwrite[i]++; if (FD_ISSET(i, exceptfds)) nbexcept[i]++; #endif } #ifdef LIBC_VERBOSE if (NOW() > lastshown + 1000000000ull) { lastshown = NOW(); printk("%lu MB free, ", num_free_pages() / ((1 << 20) / PAGE_SIZE)); printk("%d(%d): ", nb, sock_n); for (i = 0; i < nfds; i++) { if (nbread[i] || nbwrite[i] || nbexcept[i]) printk(" %d(%c):", i, file_types[files[i].type]); if (nbread[i]) printk(" %dR", nbread[i]); if (nbwrite[i]) printk(" %dW", nbwrite[i]); if (nbexcept[i]) printk(" %dE", nbexcept[i]); } printk("\n"); memset(nbread, 0, sizeof(nbread)); memset(nbwrite, 0, sizeof(nbwrite)); memset(nbexcept, 0, sizeof(nbexcept)); nb = 0; } #endif return n; } /* The strategy is to * - announce that we will maybe sleep * - poll a bit ; if successful, return * - if timeout, return * - really sleep (except if somebody woke us in the meanwhile) */ int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout) { int n, ret; fd_set myread, mywrite, myexcept; struct thread *thread = get_current(); s_time_t start = NOW(), stop; DEFINE_WAIT(w1); DEFINE_WAIT(w2); DEFINE_WAIT(w3); DEFINE_WAIT(w4); DEFINE_WAIT(w5); DEFINE_WAIT(w6); assert(thread == main_thread); DEBUG("select(%d, ", nfds); dump_set(nfds, readfds, writefds, exceptfds, timeout); DEBUG(");\n"); if (timeout) stop = start + SECONDS(timeout->tv_sec) + timeout->tv_usec * 1000; else /* just make gcc happy */ stop = start; /* Tell people we're going to sleep before looking at what they are * saying, hence letting them wake us if events happen between here and * schedule() */ add_waiter(w1, netfront_queue); add_waiter(w2, event_queue); add_waiter(w3, blkfront_queue); add_waiter(w4, xenbus_watch_queue); add_waiter(w5, kbdfront_queue); add_waiter(w6, console_queue); if (readfds) myread = *readfds; else FD_ZERO(&myread); if (writefds) mywrite = *writefds; else FD_ZERO(&mywrite); if (exceptfds) myexcept = *exceptfds; else FD_ZERO(&myexcept); DEBUG("polling "); dump_set(nfds, &myread, &mywrite, &myexcept, timeout); DEBUG("\n"); n = select_poll(nfds, &myread, &mywrite, &myexcept); if (n) { dump_set(nfds, readfds, writefds, exceptfds, timeout); if (readfds) *readfds = myread; if (writefds) *writefds = mywrite; if (exceptfds) *exceptfds = myexcept; DEBUG(" -> "); dump_set(nfds, readfds, writefds, exceptfds, timeout); DEBUG("\n"); wake(thread); ret = n; goto out; } if (timeout && NOW() >= stop) { if (readfds) FD_ZERO(readfds); if (writefds) FD_ZERO(writefds); if (exceptfds) FD_ZERO(exceptfds); timeout->tv_sec = 0; timeout->tv_usec = 0; wake(thread); ret = 0; goto out; } if (timeout) thread->wakeup_time = stop; schedule(); if (readfds) myread = *readfds; else FD_ZERO(&myread); if (writefds) mywrite = *writefds; else FD_ZERO(&mywrite); if (exceptfds) myexcept = *exceptfds; else FD_ZERO(&myexcept); n = select_poll(nfds, &myread, &mywrite, &myexcept); if (n) { if (readfds) *readfds = myread; if (writefds) *writefds = mywrite; if (exceptfds) *exceptfds = myexcept; ret = n; goto out; } errno = EINTR; ret = -1; out: remove_waiter(w1); remove_waiter(w2); remove_waiter(w3); remove_waiter(w4); remove_waiter(w5); remove_waiter(w6); return ret; } #ifdef HAVE_LWIP int socket(int domain, int type, int protocol) { int fd, res; fd = lwip_socket(domain, type, protocol); if (fd < 0) return -1; res = alloc_fd(FTYPE_SOCKET); printk("socket -> %d\n", res); files[res].socket.fd = fd; return res; } int accept(int s, struct sockaddr *addr, socklen_t *addrlen) { int fd, res; if (files[s].type != FTYPE_SOCKET) { printk("accept(%d): Bad descriptor\n", s); errno = EBADF; return -1; } fd = lwip_accept(files[s].socket.fd, addr, addrlen); if (fd < 0) return -1; res = alloc_fd(FTYPE_SOCKET); files[res].socket.fd = fd; printk("accepted on %d -> %d\n", s, res); return res; } #define LWIP_STUB(ret, name, proto, args) \ ret name proto \ { \ if (files[s].type != FTYPE_SOCKET) { \ printk(#name "(%d): Bad descriptor\n", s); \ errno = EBADF; \ return -1; \ } \ s = files[s].socket.fd; \ return lwip_##name args; \ } LWIP_STUB(int, bind, (int s, struct sockaddr *my_addr, socklen_t addrlen), (s, my_addr, addrlen)) LWIP_STUB(int, getsockopt, (int s, int level, int optname, void *optval, socklen_t *optlen), (s, level, optname, optval, optlen)) LWIP_STUB(int, setsockopt, (int s, int level, int optname, void *optval, socklen_t optlen), (s, level, optname, optval, optlen)) LWIP_STUB(int, connect, (int s, struct sockaddr *serv_addr, socklen_t addrlen), (s, serv_addr, addrlen)) LWIP_STUB(int, listen, (int s, int backlog), (s, backlog)); LWIP_STUB(ssize_t, recv, (int s, void *buf, size_t len, int flags), (s, buf, len, flags)) LWIP_STUB(ssize_t, recvfrom, (int s, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen), (s, buf, len, flags, from, fromlen)) LWIP_STUB(ssize_t, send, (int s, void *buf, size_t len, int flags), (s, buf, len, flags)) LWIP_STUB(ssize_t, sendto, (int s, void *buf, size_t len, int flags, struct sockaddr *to, socklen_t tolen), (s, buf, len, flags, to, tolen)) LWIP_STUB(int, getsockname, (int s, struct sockaddr *name, socklen_t *namelen), (s, name, namelen)) #endif static char *syslog_ident; void openlog(const char *ident, int option, int facility) { if (syslog_ident) free(syslog_ident); syslog_ident = strdup(ident); } void vsyslog(int priority, const char *format, va_list ap) { printk("%s: ", syslog_ident); print(0, format, ap); } void syslog(int priority, const char *format, ...) { va_list ap; va_start(ap, format); vsyslog(priority, format, ap); va_end(ap); } void closelog(void) { free(syslog_ident); syslog_ident = NULL; } void vwarn(const char *format, va_list ap) { int the_errno = errno; printk("stubdom: "); if (format) { print(0, format, ap); printk(", "); } printk("%s", strerror(the_errno))
#
# Copyright (C) 2006-2012 OpenWrt.org
#
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.
#

BLOCK_MENU:=Block Devices

define KernelPackage/aoe
  SUBMENU:=$(BLOCK_MENU)
  TITLE:=ATA over Ethernet support
  KCONFIG:=CONFIG_ATA_OVER_ETH
  FILES:=$(LINUX_DIR)/drivers/block/aoe/aoe.ko
  AUTOLOAD:=$(call AutoLoad,30,aoe)
endef

define KernelPackage/aoe/description
 Kernel support for ATA over Ethernet
endef

$(eval $(call KernelPackage,aoe))


define KernelPackage/ata-core
  SUBMENU:=$(BLOCK_MENU)
  TITLE:=Serial and Parallel ATA support
  DEPENDS:=@PCI_SUPPORT +kmod-scsi-core
  KCONFIG:=CONFIG_ATA
  FILES:=$(LINUX_DIR)/drivers/ata/libata.ko
endef

$(eval $(call KernelPackage,ata-core))


define AddDepends/ata
  SUBMENU:=$(BLOCK_MENU)
  DEPENDS+=kmod-ata-core $(1)
endef


define KernelPackage/ata-ahci
  TITLE:=AHCI Serial ATA support
  KCONFIG:=CONFIG_SATA_AHCI
  FILES:= \
    $(LINUX_DIR)/drivers/ata/ahci.ko \
    $(LINUX_DIR)/drivers/ata/libahci.ko
  AUTOLOAD:=$(call AutoLoad,41,libahci ahci,1)
  $(call AddDepends/ata)
endef

define KernelPackage/ata-ahci/description
 Support for AHCI Serial ATA controllers
endef

$(eval $(call KernelPackage,ata-ahci))


define KernelPackage/ata-artop
  TITLE:=ARTOP 6210/6260 PATA support
  KCONFIG:=CONFIG_PATA_ARTOP
  FILES:=$(LINUX_DIR)/drivers/ata/pata_artop.ko
  AUTOLOAD:=$(call AutoLoad,41,pata_artop,1)
  $(call AddDepends/ata)
endef

define KernelPackage/ata-artop/description
 PATA support for ARTOP 6210/6260 host controllers
endef

$(eval $(call KernelPackage,ata-artop))


define KernelPackage/ata-imx
  TITLE:=Freescale i.MX AHCI SATA support
  DEPENDS:=@TARGET_imx6
  KCONFIG:=\
	CONFIG_AHCI_IMX \
	CONFIG_SATA_AHCI_PLATFORM \
	CONFIG_PATA_IMX=n
  FILES:=$(LINUX_DIR)/drivers/ata/ahci_imx.ko
  AUTOLOAD:=$(call AutoLoad,41,ahci_imx,1)
  $(call AddDepends/ata)
endef

define KernelPackage/ata-imx/description
 SATA support for the Freescale i.MX6 SoC's onboard AHCI SATA
endef

$(eval $(call KernelPackage,ata-imx))


define KernelPackage/ata-marvell-sata
  TITLE:=Marvell Serial ATA support
  KCONFIG:=CONFIG_SATA_MV
  FILES:=$(LINUX_DIR)/drivers/ata/sata_mv.ko
  AUTOLOAD:=$(call AutoLoad,41,sata_mv,1)
  $(call AddDepends/ata)
endef

define KernelPackage/ata-marvell-sata/description
 SATA support for marvell chipsets
endef

$(eval $(call KernelPackage,ata-marvell-sata))


define KernelPackage/ata-nvidia-sata
  TITLE:=Nvidia Serial ATA support
  KCONFIG:=CONFIG_SATA_NV
  FILES:=$(LINUX_DIR)/drivers/ata/sata_nv.ko
  AUTOLOAD:=$(call AutoLoad,41,sata_nv,1)
  $(call AddDepends/ata)
endef

$(eval $(call KernelPackage,ata-nvidia-sata))


define KernelPackage/ata-oxnas-sata
  TITLE:=oxnas Serial ATA support
  KCONFIG:=CONFIG_SATA_OXNAS
  DEPENDS:=@TARGET_oxnas
  FILES:=$(LINUX_DIR)/drivers/ata/sata_oxnas.ko
  AUTOLOAD:=$(call AutoLoad,41,sata_oxnas,1)
  $(call AddDepends/ata)
endef

define KernelPackage/ata-oxnas-sata/description
 SATA support for OX934 core found in the OX82x/PLX782x SoCs
endef

$(eval $(call KernelPackage,ata-oxnas-sata))


define KernelPackage/ata-pdc202xx-old
  SUBMENU:=$(BLOCK_MENU)
  TITLE:=Older Promise PATA controller support
  DEPENDS:=kmod-ata-core
  KCONFIG:= \
       CONFIG_ATA_SFF=y \
       CONFIG_PATA_PDC_OLD
  FILES:=$(LINUX_DIR)/drivers/ata/pata_pdc202xx_old.ko
  AUTOLOAD:=$(call AutoLoad,41,pata_pdc202xx_old,1)
endef

define KernelPackage/ata-pdc202xx-old/description
 This option enables support for the Promise 20246, 20262, 20263,
 20265 and 20267 adapters
endef

$(eval $(call KernelPackage,ata-pdc202xx-old))


define KernelPackage/ata-piix
  TITLE:=Intel PIIX PATA/SATA support
  KCONFIG:=CONFIG_ATA_PIIX
  FILES:=$(LINUX_DIR)/drivers/ata/ata_piix.ko
  AUTOLOAD:=$(call AutoLoad,41,ata_piix,1)
  $(call AddDepends/ata)
endef

define KernelPackage/ata-piix/description
 SATA support for Intel ICH5/6/7/8 series host controllers and
 PATA support for Intel ESB/ICH/PIIX3/PIIX4 series host controllers
endef

$(eval $(call KernelPackage,ata-piix))


define KernelPackage/ata-sil
  TITLE:=Silicon Image SATA support
  KCONFIG:=CONFIG_SATA_SIL
  FILES:=$(LINUX_DIR)/drivers/ata/sata_sil.ko
  AUTOLOAD:=$(call AutoLoad,41,sata_sil,1)
  $(call AddDepends/ata)
endef

define KernelPackage/ata-sil/description
 Support for Silicon Image Serial ATA controllers
endef

$(eval $(call KernelPackage,ata-sil))


define KernelPackage/ata-sil24
  TITLE:=Silicon Image 3124/3132 SATA support
  KCONFIG:=CONFIG_SATA_SIL24
  FILES:=$(LINUX_DIR)/drivers/ata/sata_sil24.ko
  AUTOLOAD:=$(call AutoLoad,41,sata_sil24,1)
  $(call AddDepends/ata)
endef

define KernelPackage/ata-sil24/description
 Support for Silicon Image 3124/3132 Serial ATA controllers
endef

$(eval $(call KernelPackage,ata-sil24))


define KernelPackage/ata-via-sata
  TITLE:=VIA SATA support
  KCONFIG:=CONFIG_SATA_VIA
  FILES:=$(LINUX_DIR)/drivers/ata/sata_via.ko
  AUTOLOAD:=$(call AutoLoad,41,sata_via,1)
  $(call AddDepends/ata)
endef

define KernelPackage/ata-via-sata/description
 This option enables support for VIA Serial ATA
endef

$(eval $(call KernelPackage,ata-via-sata))


define KernelPackage/block2mtd
  SUBMENU:=$(BLOCK_MENU)
  TITLE:=Block device MTD emulation
  KCONFIG:=CONFIG_MTD_BLOCK2MTD
  FILES:=$(LINUX_DIR)/drivers/mtd/devices/block2mtd.ko
endef

$(eval $(call KernelPackage,block2mtd))


define KernelPackage/dm
  SUBMENU:=$(BLOCK_MENU)
  TITLE:=Device Mapper
  DEPENDS:=+kmod-crypto-manager
  # All the "=n" are unnecessary, they're only there
  # to stop the config from asking the question.
  # MIRROR is M because I've needed it for pvmove.
  KCONFIG:= \
	CONFIG_BLK_DEV_MD=n \
	CONFIG_DM_DEBUG=n \
	CONFIG_DM_UEVENT=n \
	CONFIG_DM_DELAY=n \
	CONFIG_DM_MULTIPATH=n \
	CONFIG_DM_ZERO=n \
	CONFIG_DM_SNAPSHOT=n \
	CONFIG_DM_LOG_USERSPACE=n \
	CONFIG_MD=y \
	CONFIG_BLK_DEV_DM \
	CONFIG_DM_CRYPT \
	CONFIG_DM_MIRROR
  FILES:=$(LINUX_DIR)/drivers/md/dm-*.ko
  AUTOLOAD:=$(call AutoLoad,30,dm-mod dm-log dm-region-hash dm-mirror dm-crypt)
endef

define KernelPackage/dm/description
 Kernel module necessary for LVM2 support
endef

$(eval $(call KernelPackage,dm))


define KernelPackage/md-mod
  SUBMENU:=$(BLOCK_MENU)
  TITLE:=MD RAID
  KCONFIG:= \
       CONFIG_MD=y \
       CONFIG_BLK_DEV_MD=m \
       CONFIG_MD_AUTODETECT=y \
       CONFIG_MD_FAULTY=n
  FILES:=$(LINUX_DIR)/drivers/md/md-mod.ko
  AUTOLOAD:=$(call AutoLoad,27,md-mod)
endef

define KernelPackage/md-mod/description
 Kernel RAID md module (md-mod.ko).
 You will need to select at least one RAID level module below.
endef

$(eval $(call KernelPackage,md-mod))


define KernelPackage/md/Depends
  SUBMENU:=$(BLOCK_MENU)
  DEPENDS:=kmod-md-mod $(1)
endef


define KernelPackage/md-linear
$(call KernelPackage/md/Depends,)
  TITLE:=RAID Linear Module
  KCONFIG:=CONFIG_MD_LINEAR
  FILES:=$(LINUX_DIR)/drivers/md/linear.ko
  AUTOLOAD:=$(call AutoLoad,28,linear)
endef

define KernelPackage/md-linear/description
 RAID "Linear" or "Append" driver module (linear.ko)
endef

$(eval $(call KernelPackage,md-linear))


define KernelPackage/md-raid0
$(call KernelPackage/md/Depends,)
  TITLE:=RAID0 Module
  KCONFIG:=CONFIG_MD_RAID0
  FILES:=$(LINUX_DIR)/drivers/md/raid0.ko
  AUTOLOAD:=$(call AutoLoad,28,raid0)
endef

define KernelPackage/md-raid0/description
 RAID Level 0 (Striping) driver module (raid0.ko)
endef

$(eval $(call KernelPackage,md-raid0))


define KernelPackage/md-raid1
$(call KernelPackage/md/Depends,)
  TITLE:=RAID1 Module
  KCONFIG:=CONFIG_MD_RAID1
  FILES:=$(LINUX_DIR)/drivers/md/raid1.ko
  AUTOLOAD:=$(call AutoLoad,28,raid1)
endef

define KernelPackage/md-raid1/description
 RAID Level 1 (Mirroring) driver (raid1.ko)
endef

$(eval $(call KernelPackage,md-raid1))


define KernelPackage/md-raid10
$(call KernelPackage/md/Depends,)
  TITLE:=RAID10 Module
  KCONFIG:=CONFIG_MD_RAID10
  FILES:=$(LINUX_DIR)/drivers/md/raid10.ko
  AUTOLOAD:=$(call AutoLoad,28,raid10)
endef

define KernelPackage/md-raid10/description
 RAID Level 10 (Mirroring+Striping) driver module (raid10.ko)
endef

$(eval $(call KernelPackage,md-raid10))


define KernelPackage/md-raid456
$(call KernelPackage/md/Depends,+kmod-lib-raid6 +kmod-lib-xor)
  TITLE:=RAID Level 456 Driver
  KCONFIG:= \
       CONFIG_ASYNC_CORE \
       CONFIG_ASYNC_MEMCPY \
       CONFIG_ASYNC_XOR \
       CONFIG_ASYNC_PQ \
       CONFIG_ASYNC_RAID6_RECOV \
       CONFIG_ASYNC_RAID6_TEST=n \
       CONFIG_MD_RAID456 \
       CONFIG_MULTICORE_RAID456=n
  FILES:= \
	$(LINUX_DIR)/crypto/async_tx/async_tx.ko \
	$(LINUX_DIR)/crypto/async_tx/async_memcpy.ko \
	$(LINUX_DIR)/crypto/async_tx/async_xor.ko \
	$(LINUX_DIR)/crypto/async_tx/async_pq.ko \
	$(LINUX_DIR)/crypto/async_tx/async_raid6_recov.ko \
	$(LINUX_DIR)/drivers/md/raid456.ko
  AUTOLOAD:=$(call AutoLoad,28, async_tx async_memcpy async_xor async_pq async_raid6_recov raid456)
endef

define KernelPackage/md-raid456/description
 RAID Level 4,5,6 kernel module (raid456.ko)

 Includes the following modules required by
 raid456.ko:
    xor.ko
    async_tx.ko
    async_xor.ko
    async_memcpy.ko
    async_pq.ko
    async_raid5_recov.ko
    raid6_pq.ko
endef

$(eval $(call KernelPackage,md-raid456))


define KernelPackage/md-multipath
$(call KernelPackage/md/Depends,)
  TITLE:=MD Multipath Module
  KCONFIG:=CONFIG_MD_MULTIPATH
  FILES:=$(LINUX_DIR)/drivers/md/multipath.ko
  AUTOLOAD:=$(call AutoLoad,29,multipath)
endef

define KernelPackage/md-multipath/description
 Multipath driver module (multipath.ko)
endef

$(eval $(call KernelPackage,md-multipath))


define KernelPackage/ide-core
  SUBMENU:=$(BLOCK_MENU)
  TITLE:=IDE (ATA/ATAPI) device support
  DEPENDS:=@PCI_SUPPORT
  KCONFIG:= \
	CONFIG_IDE \
	CONFIG_BLK_DEV_IDE \
	CONFIG_BLK_DEV_IDEDISK \
	CONFIG_IDE_GD \
	CONFIG_IDE_GD_ATA=y \
	CONFIG_IDE_GD_ATAPI=n \
	CONFIG_IDEPCI_PCIBUS_ORDER=y \
	CONFIG_BLK_DEV_IDEDMA_PCI=y \
	CONFIG_BLK_DEV_IDEPCI=y
  FILES:= \
	$(LINUX_DIR)/drivers/ide/ide-core.ko \
	$(LINUX_DIR)/drivers/ide/ide-gd_mod.ko
endef

define KernelPackage/ide-core/description
 Kernel support for IDE, useful for usb mass storage devices (e.g. on WL-HDD)
 Includes:
 - ide-core
 - ide-gd_mod
endef

$(eval $(call KernelPackage,ide-core))


define AddDepends/ide
  SUBMENU:=$(BLOCK_MENU)
  DEPENDS+=kmod-ide-core $(1)
endef


define KernelPackage/ide-generic
  SUBMENU:=$(BLOCK_MENU)
  DEPENDS:=@PCI_SUPPORT
  TITLE:=Kernel support for generic PCI IDE chipsets
  KCONFIG:=CONFIG_BLK_DEV_GENERIC
  FILES:=$(LINUX_DIR)/drivers/ide/ide-pci-generic.ko
  AUTOLOAD:=$(call AutoLoad,30,ide-pci-generic,1)
  $(call AddDepends/ide)
endef

$(eval $(call KernelPackage,ide-generic))


define KernelPackage/ide-generic-old
  SUBMENU:=$(BLOCK_MENU)
  TITLE:=Kernel support for generic (legacy) IDE chipsets
  KCONFIG:=CONFIG_IDE_GENERIC
  FILES:=$(LINUX_DIR)/drivers/ide/ide-generic.ko
  AUTOLOAD:=$(call AutoLoad,30,ide-generic,1)
  $(call AddDepends/ide)
endef

$(eval $(call KernelPackage,ide-generic-old))


define KernelPackage/ide-aec62xx
  TITLE:=Acard AEC62xx IDE driver
  DEPENDS:=@PCI_SUPPORT
  KCONFIG:=CONFIG_BLK_DEV_AEC62XX
  FILES:=$(LINUX_DIR)/drivers/ide/aec62xx.ko
  AUTOLOAD:=$(call AutoLoad,30,aec62xx,1)
  $(call AddDepends/ide)
endef

define KernelPackage/ide-aec62xx/description
 Support for Acard AEC62xx (Artop ATP8xx) IDE controllers
endef

$(eval $(call KernelPackage,ide-aec62xx,1))


define KernelPackage/ide-pdc202xx
  TITLE:=Promise PDC202xx IDE driver
  DEPENDS:=@PCI_SUPPORT
  KCONFIG:=CONFIG_BLK_DEV_PDC202XX_OLD
  FILES:=$(LINUX_DIR)/drivers/ide/pdc202xx_old.ko
  AUTOLOAD:=$(call AutoLoad,30,pdc202xx_old,1)
  $(call AddDepends/ide)
endef

define KernelPackage/ide-pdc202xx/description
 Support for the Promise Ultra 33/66/100 (PDC202{46|62|65|67|68}) IDE
 controllers.
endef

$(eval $(call KernelPackage,ide-pdc202xx))


define KernelPackage/ide-it821x
  TITLE:=ITE IT821x IDE driver
  DEPENDS:=@PCI_SUPPORT
  KCONFIG:=CONFIG_BLK_DEV_IT821X
  FILES=$(LINUX_DIR)/drivers/ide/it821x.ko
  AUTOLOAD:=$(call AutoLoad,30,it821x,1)
  $(call AddDepends/ide)
endef

define KernelPackage/ide-it821x/description
 Kernel module for the ITE IDE821x IDE controllers
endef

$(eval $(call KernelPackage,ide-it821x))


define KernelPackage/libsas
  SUBMENU:=$(BLOCK_MENU)
  DEPENDS:=@TARGET_x86
  TITLE:=SAS Domain Transport Attributes
  KCONFIG:=CONFIG_SCSI_SAS_LIBSAS \
	CONFIG_SCSI_SAS_ATTRS \
	CONFIG_SCSI_SAS_ATA=y \
	CONFIG_SCSI_SAS_HOST_SMP=y \
	CONFIG_SCSI_SAS_LIBSAS_DEBUG=y
  FILES:= \
	$(LINUX_DIR)/drivers/scsi/scsi_transport_sas.ko \
	$(LINUX_DIR)/drivers/scsi/libsas/libsas.ko
  AUTOLOAD:=$(call AutoLoad,29,scsi_transport_sas libsas,1)
endef

define KernelPackage/libsas/description
 SAS Domain Transport Attributes support
endef

$(eval $(call KernelPackage,libsas,1))


define KernelPackage/loop
  SUBMENU:=$(BLOCK_MENU)
  TITLE:=Loopback device support
  KCONFIG:= \
	CONFIG_BLK_DEV_LOOP \
	CONFIG_BLK_DEV_CRYPTOLOOP=n
  FILES:=$(LINUX_DIR)/drivers/block/loop.ko
  AUTOLOAD:=$(call AutoLoad,30,loop)
endef

define KernelPackage/loop/description
 Kernel module for loopback device support
endef

$(eval $(call KernelPackage,loop))


define KernelPackage/mvsas
  SUBMENU:=$(BLOCK_MENU)
  TITLE:=Marvell 88SE6440 SAS/SATA driver
  DEPENDS:=@TARGET_x86 +kmod-libsas
  KCONFIG:= \
	CONFIG_SCSI_MVSAS \
	CONFIG_SCSI_MVSAS_TASKLET=n
  FILES:=$(LINUX_DIR)/drivers/scsi/mvsas/mvsas.ko
  AUTOLOAD:=$(call AutoLoad,40,mvsas,1)
endef

define KernelPackage/mvsas/description
 Kernel support for the Marvell SAS SCSI adapters
endef

$(eval $(call KernelPackage,mvsas))


define KernelPackage/nbd
  SUBMENU:=$(BLOCK_MENU)
  TITLE:=Network block device support
  KCONFIG:=CONFIG_BLK_DEV_NBD
  FILES:=$(LINUX_DIR)/drivers/block/nbd.ko
  AUTOLOAD:=$(call AutoLoad,30,nbd)
endef

define KernelPackage/nbd/description
 Kernel module for network block device support
endef

$(eval $(call KernelPackage,nbd))


define KernelPackage/scsi-core
  SUBMENU:=$(BLOCK_MENU)
  TITLE:=SCSI device support
  KCONFIG:= \
	CONFIG_SCSI \
	CONFIG_BLK_DEV_SD
  FILES:= \
	$(if $(findstring y,$(CONFIG_SCSI)),,$(LINUX_DIR)/drivers/scsi/scsi_mod.ko) \
	$(LINUX_DIR)/drivers/scsi/sd_mod.ko
  AUTOLOAD:=$(call AutoLoad,40,sd_mod,1)
endef

$(eval $(call KernelPackage,scsi-core))


define KernelPackage/scsi-generic
  SUBMENU:=$(BLOCK_MENU)
  TITLE:=Kernel support for SCSI generic
  DEPENDS:=+kmod-scsi-core
  KCONFIG:= \
	CONFIG_CHR_DEV_SG
  FILES:= \
	$(LINUX_DIR)/drivers/scsi/sg.ko
  AUTOLOAD:=$(call AutoLoad,65,sg)
endef

$(eval $(call KernelPackage,scsi-generic))


define KernelPackage/scsi-cdrom
  SUBMENU:=$(BLOCK_MENU)
  TITLE:=Kernel support for CD / DVD drives
  DEPENDS:=+kmod-scsi-core
  KCONFIG:= \
    CONFIG_BLK_DEV_SR \
    CONFIG_BLK_DEV_SR_VENDOR=n
  FILES:= \
    $(LINUX_DIR)/drivers/cdrom/cdrom.ko \
    $(LINUX_DIR)/drivers/scsi/sr_mod.ko
  AUTOLOAD:=$(call AutoLoad,45,sr_mod)
endef

$(eval $(call KernelPackage,scsi-cdrom))