debuggers.hg

view extras/mini-os/lib/sys.c @ 19811:11d8ca329b54

minios: support secondary guest consoles.

Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Wed Jun 17 07:22:18 2009 +0100 (2009-06-17)
parents b4de3a393f21
children 01ad2654815a
line source
1 /*
2 * POSIX-compatible libc layer
3 *
4 * Samuel Thibault <Samuel.Thibault@eu.citrix.net>, October 2007
5 *
6 * Provides the UNIXish part of the standard libc function.
7 *
8 * Relatively straight-forward: just multiplex the file descriptor operations
9 * among the various file types (console, FS, network, ...)
10 */
12 //#define LIBC_VERBOSE
13 //#define LIBC_DEBUG
15 #ifdef LIBC_DEBUG
16 #define DEBUG(fmt,...) printk(fmt, ##__VA_ARGS__)
17 #else
18 #define DEBUG(fmt,...)
19 #endif
21 #ifdef HAVE_LIBC
22 #include <os.h>
23 #include <console.h>
24 #include <sched.h>
25 #include <events.h>
26 #include <wait.h>
27 #include <netfront.h>
28 #include <blkfront.h>
29 #include <fbfront.h>
30 #include <xenbus.h>
31 #include <xs.h>
33 #include <sys/types.h>
34 #include <sys/unistd.h>
35 #include <sys/stat.h>
36 #include <sys/mman.h>
37 #include <net/if.h>
38 #include <time.h>
39 #include <errno.h>
40 #include <fcntl.h>
41 #include <pthread.h>
42 #include <assert.h>
43 #include <dirent.h>
44 #include <stdlib.h>
45 #include <math.h>
47 #ifdef HAVE_LWIP
48 #include <lwip/sockets.h>
49 #endif
50 #include <fs.h>
52 #define debug(fmt, ...) \
54 #define print_unsupported(fmt, ...) \
55 printk("Unsupported function "fmt" called in Mini-OS kernel\n", ## __VA_ARGS__);
57 /* Crash on function call */
58 #define unsupported_function_crash(function) \
59 int __unsup_##function(void) asm(#function); \
60 int __unsup_##function(void) \
61 { \
62 print_unsupported(#function); \
63 do_exit(); \
64 }
66 /* Log and err out on function call */
67 #define unsupported_function_log(type, function, ret) \
68 type __unsup_##function(void) asm(#function); \
69 type __unsup_##function(void) \
70 { \
71 print_unsupported(#function); \
72 errno = ENOSYS; \
73 return ret; \
74 }
76 /* Err out on function call */
77 #define unsupported_function(type, function, ret) \
78 type __unsup_##function(void) asm(#function); \
79 type __unsup_##function(void) \
80 { \
81 errno = ENOSYS; \
82 return ret; \
83 }
85 #define NOFILE 32
86 extern int xc_evtchn_close(int fd);
87 extern int xc_interface_close(int fd);
88 extern int xc_gnttab_close(int fd);
90 pthread_mutex_t fd_lock = PTHREAD_MUTEX_INITIALIZER;
91 struct file files[NOFILE] = {
92 { .type = FTYPE_CONSOLE }, /* stdin */
93 { .type = FTYPE_CONSOLE }, /* stdout */
94 { .type = FTYPE_CONSOLE }, /* stderr */
95 };
97 DECLARE_WAIT_QUEUE_HEAD(event_queue);
99 int alloc_fd(enum fd_type type)
100 {
101 int i;
102 pthread_mutex_lock(&fd_lock);
103 for (i=0; i<NOFILE; i++) {
104 if (files[i].type == FTYPE_NONE) {
105 files[i].type = type;
106 pthread_mutex_unlock(&fd_lock);
107 return i;
108 }
109 }
110 pthread_mutex_unlock(&fd_lock);
111 printk("Too many opened files\n");
112 do_exit();
113 }
115 void close_all_files(void)
116 {
117 int i;
118 pthread_mutex_lock(&fd_lock);
119 for (i=NOFILE - 1; i > 0; i--)
120 if (files[i].type != FTYPE_NONE)
121 close(i);
122 pthread_mutex_unlock(&fd_lock);
123 }
125 int dup2(int oldfd, int newfd)
126 {
127 pthread_mutex_lock(&fd_lock);
128 if (files[newfd].type != FTYPE_NONE)
129 close(newfd);
130 // XXX: this is a bit bogus, as we are supposed to share the offset etc
131 files[newfd] = files[oldfd];
132 pthread_mutex_unlock(&fd_lock);
133 return 0;
134 }
136 pid_t getpid(void)
137 {
138 return 1;
139 }
141 pid_t getppid(void)
142 {
143 return 1;
144 }
146 pid_t setsid(void)
147 {
148 return 1;
149 }
151 char *getcwd(char *buf, size_t size)
152 {
153 snprintf(buf, size, "/");
154 return buf;
155 }
157 #define LOG_PATH "/var/log/"
159 int mkdir(const char *pathname, mode_t mode)
160 {
161 int ret;
162 ret = fs_create(fs_import, (char *) pathname, 1, mode);
163 if (ret < 0) {
164 errno = EIO;
165 return -1;
166 }
167 return 0;
168 }
170 int openpty(void)
171 {
172 struct consfront_dev *dev;
174 dev = init_consfront(NULL);
175 dev->fd = alloc_fd(FTYPE_CONSOLE);
176 files[dev->fd].cons.dev = dev;
178 printk("fd(%d) = openpty\n", dev->fd);
179 return(dev->fd);
180 }
182 int open(const char *pathname, int flags, ...)
183 {
184 int fs_fd, fd;
185 /* Ugly, but fine. */
186 if (!strncmp(pathname,LOG_PATH,strlen(LOG_PATH))) {
187 fd = alloc_fd(FTYPE_CONSOLE);
188 printk("open(%s) -> %d\n", pathname, fd);
189 return fd;
190 }
191 printk("open(%s, %x)", pathname, flags);
192 switch (flags & ~O_ACCMODE) {
193 case 0:
194 fs_fd = fs_open(fs_import, (void *) pathname);
195 break;
196 case O_CREAT|O_TRUNC:
197 {
198 va_list ap;
199 mode_t mode;
200 va_start(ap, flags);
201 mode = va_arg(ap, mode_t);
202 va_end(ap);
203 fs_fd = fs_create(fs_import, (void *) pathname, 0, mode);
204 break;
205 }
206 default:
207 printk(" unsupported flags\n");
208 do_exit();
209 }
210 if (fs_fd < 0) {
211 errno = EIO;
212 return -1;
213 }
214 fd = alloc_fd(FTYPE_FILE);
215 printk("-> %d\n", fd);
216 files[fd].file.fd = fs_fd;
217 files[fd].file.offset = 0;
218 return fd;
219 }
221 int isatty(int fd)
222 {
223 return files[fd].type == FTYPE_CONSOLE;
224 }
226 int read(int fd, void *buf, size_t nbytes)
227 {
228 switch (files[fd].type) {
229 case FTYPE_CONSOLE: {
230 int ret;
231 DEFINE_WAIT(w);
232 while(1) {
233 add_waiter(w, console_queue);
234 ret = xencons_ring_recv(files[fd].cons.dev, buf, nbytes);
235 if (ret)
236 break;
237 schedule();
238 }
239 remove_waiter(w);
240 return ret;
241 }
242 case FTYPE_FILE: {
243 ssize_t ret;
244 if (nbytes > PAGE_SIZE * FSIF_NR_READ_GNTS)
245 nbytes = PAGE_SIZE * FSIF_NR_READ_GNTS;
246 ret = fs_read(fs_import, files[fd].file.fd, buf, nbytes, files[fd].file.offset);
247 if (ret > 0) {
248 files[fd].file.offset += ret;
249 return ret;
250 } else if (ret < 0) {
251 errno = EIO;
252 return -1;
253 }
254 return 0;
255 }
256 #ifdef HAVE_LWIP
257 case FTYPE_SOCKET:
258 return lwip_read(files[fd].socket.fd, buf, nbytes);
259 #endif
260 case FTYPE_TAP: {
261 ssize_t ret;
262 ret = netfront_receive(files[fd].tap.dev, buf, nbytes);
263 if (ret <= 0) {
264 errno = EAGAIN;
265 return -1;
266 }
267 return ret;
268 }
269 case FTYPE_KBD: {
270 int ret, n;
271 n = nbytes / sizeof(union xenkbd_in_event);
272 ret = kbdfront_receive(files[fd].kbd.dev, buf, n);
273 if (ret <= 0) {
274 errno = EAGAIN;
275 return -1;
276 }
277 return ret * sizeof(union xenkbd_in_event);
278 }
279 case FTYPE_FB: {
280 int ret, n;
281 n = nbytes / sizeof(union xenfb_in_event);
282 ret = fbfront_receive(files[fd].fb.dev, buf, n);
283 if (ret <= 0) {
284 errno = EAGAIN;
285 return -1;
286 }
287 return ret * sizeof(union xenfb_in_event);
288 }
289 default:
290 break;
291 }
292 printk("read(%d): Bad descriptor\n", fd);
293 errno = EBADF;
294 return -1;
295 }
297 int write(int fd, const void *buf, size_t nbytes)
298 {
299 switch (files[fd].type) {
300 case FTYPE_CONSOLE:
301 console_print(files[fd].cons.dev, (char *)buf, nbytes);
302 return nbytes;
303 case FTYPE_FILE: {
304 ssize_t ret;
305 if (nbytes > PAGE_SIZE * FSIF_NR_WRITE_GNTS)
306 nbytes = PAGE_SIZE * FSIF_NR_WRITE_GNTS;
307 ret = fs_write(fs_import, files[fd].file.fd, (void *) buf, nbytes, files[fd].file.offset);
308 if (ret > 0) {
309 files[fd].file.offset += ret;
310 return ret;
311 } else if (ret < 0) {
312 errno = EIO;
313 return -1;
314 }
315 return 0;
316 }
317 #ifdef HAVE_LWIP
318 case FTYPE_SOCKET:
319 return lwip_write(files[fd].socket.fd, (void*) buf, nbytes);
320 #endif
321 case FTYPE_TAP:
322 netfront_xmit(files[fd].tap.dev, (void*) buf, nbytes);
323 return nbytes;
324 default:
325 break;
326 }
327 printk("write(%d): Bad descriptor\n", fd);
328 errno = EBADF;
329 return -1;
330 }
332 off_t lseek(int fd, off_t offset, int whence)
333 {
334 if (files[fd].type != FTYPE_FILE) {
335 errno = ESPIPE;
336 return (off_t) -1;
337 }
338 switch (whence) {
339 case SEEK_SET:
340 files[fd].file.offset = offset;
341 break;
342 case SEEK_CUR:
343 files[fd].file.offset += offset;
344 break;
345 case SEEK_END: {
346 struct stat st;
347 int ret;
348 ret = fstat(fd, &st);
349 if (ret)
350 return -1;
351 files[fd].file.offset = st.st_size + offset;
352 break;
353 }
354 default:
355 errno = EINVAL;
356 return -1;
357 }
358 return files[fd].file.offset;
359 }
361 int fsync(int fd) {
362 switch (files[fd].type) {
363 case FTYPE_FILE: {
364 int ret;
365 ret = fs_sync(fs_import, files[fd].file.fd);
366 if (ret < 0) {
367 errno = EIO;
368 return -1;
369 }
370 return 0;
371 }
372 default:
373 break;
374 }
375 printk("fsync(%d): Bad descriptor\n", fd);
376 errno = EBADF;
377 return -1;
378 }
380 int close(int fd)
381 {
382 printk("close(%d)\n", fd);
383 switch (files[fd].type) {
384 default:
385 files[fd].type = FTYPE_NONE;
386 return 0;
387 case FTYPE_FILE: {
388 int ret = fs_close(fs_import, files[fd].file.fd);
389 files[fd].type = FTYPE_NONE;
390 if (ret < 0) {
391 errno = EIO;
392 return -1;
393 }
394 return 0;
395 }
396 case FTYPE_XENBUS:
397 xs_daemon_close((void*)(intptr_t) fd);
398 return 0;
399 #ifdef HAVE_LWIP
400 case FTYPE_SOCKET: {
401 int res = lwip_close(files[fd].socket.fd);
402 files[fd].type = FTYPE_NONE;
403 return res;
404 }
405 #endif
406 case FTYPE_XC:
407 xc_interface_close(fd);
408 return 0;
409 case FTYPE_EVTCHN:
410 xc_evtchn_close(fd);
411 return 0;
412 case FTYPE_GNTMAP:
413 xc_gnttab_close(fd);
414 return 0;
415 case FTYPE_TAP:
416 shutdown_netfront(files[fd].tap.dev);
417 files[fd].type = FTYPE_NONE;
418 return 0;
419 case FTYPE_BLK:
420 shutdown_blkfront(files[fd].blk.dev);
421 files[fd].type = FTYPE_NONE;
422 return 0;
423 case FTYPE_KBD:
424 shutdown_kbdfront(files[fd].kbd.dev);
425 files[fd].type = FTYPE_NONE;
426 return 0;
427 case FTYPE_FB:
428 shutdown_fbfront(files[fd].fb.dev);
429 files[fd].type = FTYPE_NONE;
430 return 0;
431 case FTYPE_CONSOLE:
432 fini_console(files[fd].cons.dev);
433 files[fd].type = FTYPE_NONE;
434 return 0;
435 case FTYPE_NONE:
436 break;
437 }
438 printk("close(%d): Bad descriptor\n", fd);
439 errno = EBADF;
440 return -1;
441 }
443 static void init_stat(struct stat *buf)
444 {
445 memset(buf, 0, sizeof(*buf));
446 buf->st_dev = 0;
447 buf->st_ino = 0;
448 buf->st_nlink = 1;
449 buf->st_rdev = 0;
450 buf->st_blksize = 4096;
451 buf->st_blocks = 0;
452 }
454 static void stat_from_fs(struct stat *buf, struct fsif_stat_response *stat)
455 {
456 buf->st_mode = stat->stat_mode;
457 buf->st_uid = stat->stat_uid;
458 buf->st_gid = stat->stat_gid;
459 buf->st_size = stat->stat_size;
460 buf->st_atime = stat->stat_atime;
461 buf->st_mtime = stat->stat_mtime;
462 buf->st_ctime = stat->stat_ctime;
463 }
465 int stat(const char *path, struct stat *buf)
466 {
467 struct fsif_stat_response stat;
468 int ret;
469 int fs_fd;
470 printk("stat(%s)\n", path);
471 fs_fd = fs_open(fs_import, (char*) path);
472 if (fs_fd < 0) {
473 errno = EIO;
474 ret = -1;
475 goto out;
476 }
477 ret = fs_stat(fs_import, fs_fd, &stat);
478 if (ret < 0) {
479 errno = EIO;
480 ret = -1;
481 goto outfd;
482 }
483 init_stat(buf);
484 stat_from_fs(buf, &stat);
485 ret = 0;
487 outfd:
488 fs_close(fs_import, fs_fd);
489 out:
490 return ret;
491 }
493 int fstat(int fd, struct stat *buf)
494 {
495 init_stat(buf);
496 switch (files[fd].type) {
497 case FTYPE_CONSOLE:
498 case FTYPE_SOCKET: {
499 buf->st_mode = (files[fd].type == FTYPE_CONSOLE?S_IFCHR:S_IFSOCK) | S_IRUSR|S_IWUSR;
500 buf->st_uid = 0;
501 buf->st_gid = 0;
502 buf->st_size = 0;
503 buf->st_atime =
504 buf->st_mtime =
505 buf->st_ctime = time(NULL);
506 return 0;
507 }
508 case FTYPE_FILE: {
509 struct fsif_stat_response stat;
510 int ret;
511 ret = fs_stat(fs_import, files[fd].file.fd, &stat);
512 if (ret < 0) {
513 errno = EIO;
514 return -1;
515 }
516 /* The protocol is a bit evasive about this value */
517 stat_from_fs(buf, &stat);
518 return 0;
519 }
520 default:
521 break;
522 }
524 printk("statf(%d): Bad descriptor\n", fd);
525 errno = EBADF;
526 return -1;
527 }
529 int ftruncate(int fd, off_t length)
530 {
531 switch (files[fd].type) {
532 case FTYPE_FILE: {
533 int ret;
534 ret = fs_truncate(fs_import, files[fd].file.fd, length);
535 if (ret < 0) {
536 errno = EIO;
537 return -1;
538 }
539 return 0;
540 }
541 default:
542 break;
543 }
545 printk("ftruncate(%d): Bad descriptor\n", fd);
546 errno = EBADF;
547 return -1;
548 }
550 int remove(const char *pathname)
551 {
552 int ret;
553 printk("remove(%s)", pathname);
554 ret = fs_remove(fs_import, (char*) pathname);
555 if (ret < 0) {
556 errno = EIO;
557 return -1;
558 }
559 return 0;
560 }
562 int unlink(const char *pathname)
563 {
564 return remove(pathname);
565 }
567 int rmdir(const char *pathname)
568 {
569 return remove(pathname);
570 }
572 int fcntl(int fd, int cmd, ...)
573 {
574 long arg;
575 va_list ap;
576 va_start(ap, cmd);
577 arg = va_arg(ap, long);
578 va_end(ap);
580 switch (cmd) {
581 #ifdef HAVE_LWIP
582 case F_SETFL:
583 if (files[fd].type == FTYPE_SOCKET && !(arg & ~O_NONBLOCK)) {
584 /* Only flag supported: non-blocking mode */
585 uint32_t nblock = !!(arg & O_NONBLOCK);
586 return lwip_ioctl(files[fd].socket.fd, FIONBIO, &nblock);
587 }
588 /* Fallthrough */
589 #endif
590 default:
591 printk("fcntl(%d, %d, %lx/%lo)\n", fd, cmd, arg, arg);
592 errno = ENOSYS;
593 return -1;
594 }
595 }
597 DIR *opendir(const char *name)
598 {
599 DIR *ret;
600 ret = malloc(sizeof(*ret));
601 ret->name = strdup(name);
602 ret->offset = 0;
603 ret->entries = NULL;
604 ret->curentry = -1;
605 ret->nbentries = 0;
606 ret->has_more = 1;
607 return ret;
608 }
610 struct dirent *readdir(DIR *dir)
611 {
612 if (dir->curentry >= 0) {
613 free(dir->entries[dir->curentry]);
614 dir->entries[dir->curentry] = NULL;
615 }
616 dir->curentry++;
617 if (dir->curentry >= dir->nbentries) {
618 dir->offset += dir->nbentries;
619 free(dir->entries);
620 dir->curentry = -1;
621 dir->nbentries = 0;
622 if (!dir->has_more)
623 return NULL;
624 dir->entries = fs_list(fs_import, dir->name, dir->offset, &dir->nbentries, &dir->has_more);
625 if (!dir->entries || !dir->nbentries)
626 return NULL;
627 dir->curentry = 0;
628 }
629 dir->dirent.d_name = dir->entries[dir->curentry];
630 return &dir->dirent;
631 }
632 int closedir(DIR *dir)
633 {
634 int i;
635 for (i=0; i<dir->nbentries; i++)
636 free(dir->entries[i]);
637 free(dir->entries);
638 free(dir->name);
639 free(dir);
640 return 0;
641 }
643 /* We assume that only the main thread calls select(). */
645 static const char file_types[] = {
646 [FTYPE_NONE] = 'N',
647 [FTYPE_CONSOLE] = 'C',
648 [FTYPE_FILE] = 'F',
649 [FTYPE_XENBUS] = 'S',
650 [FTYPE_XC] = 'X',
651 [FTYPE_EVTCHN] = 'E',
652 [FTYPE_SOCKET] = 's',
653 [FTYPE_TAP] = 'T',
654 [FTYPE_BLK] = 'B',
655 [FTYPE_KBD] = 'K',
656 [FTYPE_FB] = 'G',
657 };
658 #ifdef LIBC_DEBUG
659 static void dump_set(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout)
660 {
661 int i, comma;
662 #define printfds(set) do {\
663 comma = 0; \
664 for (i = 0; i < nfds; i++) { \
665 if (FD_ISSET(i, set)) { \
666 if (comma) \
667 printk(", "); \
668 printk("%d(%c)", i, file_types[files[i].type]); \
669 comma = 1; \
670 } \
671 } \
672 } while (0)
674 printk("[");
675 if (readfds)
676 printfds(readfds);
677 printk("], [");
678 if (writefds)
679 printfds(writefds);
680 printk("], [");
681 if (exceptfds)
682 printfds(exceptfds);
683 printk("], ");
684 if (timeout)
685 printk("{ %ld, %ld }", timeout->tv_sec, timeout->tv_usec);
686 }
687 #else
688 #define dump_set(nfds, readfds, writefds, exceptfds, timeout)
689 #endif
691 /* Just poll without blocking */
692 static int select_poll(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds)
693 {
694 int i, n = 0;
695 #ifdef HAVE_LWIP
696 int sock_n = 0, sock_nfds = 0;
697 fd_set sock_readfds, sock_writefds, sock_exceptfds;
698 struct timeval timeout = { .tv_sec = 0, .tv_usec = 0};
699 #endif
701 #ifdef LIBC_VERBOSE
702 static int nb;
703 static int nbread[NOFILE], nbwrite[NOFILE], nbexcept[NOFILE];
704 static s_time_t lastshown;
706 nb++;
707 #endif
709 #ifdef HAVE_LWIP
710 /* first poll network */
711 FD_ZERO(&sock_readfds);
712 FD_ZERO(&sock_writefds);
713 FD_ZERO(&sock_exceptfds);
714 for (i = 0; i < nfds; i++) {
715 if (files[i].type == FTYPE_SOCKET) {
716 if (FD_ISSET(i, readfds)) {
717 FD_SET(files[i].socket.fd, &sock_readfds);
718 sock_nfds = i+1;
719 }
720 if (FD_ISSET(i, writefds)) {
721 FD_SET(files[i].socket.fd, &sock_writefds);
722 sock_nfds = i+1;
723 }
724 if (FD_ISSET(i, exceptfds)) {
725 FD_SET(files[i].socket.fd, &sock_exceptfds);
726 sock_nfds = i+1;
727 }
728 }
729 }
730 if (sock_nfds > 0) {
731 DEBUG("lwip_select(");
732 dump_set(nfds, &sock_readfds, &sock_writefds, &sock_exceptfds, &timeout);
733 DEBUG("); -> ");
734 sock_n = lwip_select(sock_nfds, &sock_readfds, &sock_writefds, &sock_exceptfds, &timeout);
735 dump_set(nfds, &sock_readfds, &sock_writefds, &sock_exceptfds, &timeout);
736 DEBUG("\n");
737 }
738 #endif
740 /* Then see others as well. */
741 for (i = 0; i < nfds; i++) {
742 switch(files[i].type) {
743 default:
744 if (FD_ISSET(i, readfds) || FD_ISSET(i, writefds) || FD_ISSET(i, exceptfds))
745 printk("bogus fd %d in select\n", i);
746 /* Fallthrough. */
747 case FTYPE_FILE:
748 FD_CLR(i, readfds);
749 FD_CLR(i, writefds);
750 FD_CLR(i, exceptfds);
751 break;
752 case FTYPE_CONSOLE:
753 if (FD_ISSET(i, readfds)) {
754 if (xencons_ring_avail(files[i].cons.dev))
755 n++;
756 else
757 FD_CLR(i, readfds);
758 }
759 if (FD_ISSET(i, writefds))
760 n++;
761 FD_CLR(i, exceptfds);
762 break;
763 case FTYPE_XENBUS:
764 if (FD_ISSET(i, readfds)) {
765 if (files[i].xenbus.events)
766 n++;
767 else
768 FD_CLR(i, readfds);
769 }
770 FD_CLR(i, writefds);
771 FD_CLR(i, exceptfds);
772 break;
773 case FTYPE_EVTCHN:
774 case FTYPE_TAP:
775 case FTYPE_BLK:
776 case FTYPE_KBD:
777 case FTYPE_FB:
778 if (FD_ISSET(i, readfds)) {
779 if (files[i].read)
780 n++;
781 else
782 FD_CLR(i, readfds);
783 }
784 FD_CLR(i, writefds);
785 FD_CLR(i, exceptfds);
786 break;
787 #ifdef HAVE_LWIP
788 case FTYPE_SOCKET:
789 if (FD_ISSET(i, readfds)) {
790 /* Optimize no-network-packet case. */
791 if (sock_n && FD_ISSET(files[i].socket.fd, &sock_readfds))
792 n++;
793 else
794 FD_CLR(i, readfds);
795 }
796 if (FD_ISSET(i, writefds)) {
797 if (sock_n && FD_ISSET(files[i].socket.fd, &sock_writefds))
798 n++;
799 else
800 FD_CLR(i, writefds);
801 }
802 if (FD_ISSET(i, exceptfds)) {
803 if (sock_n && FD_ISSET(files[i].socket.fd, &sock_exceptfds))
804 n++;
805 else
806 FD_CLR(i, exceptfds);
807 }
808 break;
809 #endif
810 }
811 #ifdef LIBC_VERBOSE
812 if (FD_ISSET(i, readfds))
813 nbread[i]++;
814 if (FD_ISSET(i, writefds))
815 nbwrite[i]++;
816 if (FD_ISSET(i, exceptfds))
817 nbexcept[i]++;
818 #endif
819 }
820 #ifdef LIBC_VERBOSE
821 if (NOW() > lastshown + 1000000000ull) {
822 lastshown = NOW();
823 printk("%lu MB free, ", num_free_pages() / ((1 << 20) / PAGE_SIZE));
824 printk("%d(%d): ", nb, sock_n);
825 for (i = 0; i < nfds; i++) {
826 if (nbread[i] || nbwrite[i] || nbexcept[i])
827 printk(" %d(%c):", i, file_types[files[i].type]);
828 if (nbread[i])
829 printk(" %dR", nbread[i]);
830 if (nbwrite[i])
831 printk(" %dW", nbwrite[i]);
832 if (nbexcept[i])
833 printk(" %dE", nbexcept[i]);
834 }
835 printk("\n");
836 memset(nbread, 0, sizeof(nbread));
837 memset(nbwrite, 0, sizeof(nbwrite));
838 memset(nbexcept, 0, sizeof(nbexcept));
839 nb = 0;
840 }
841 #endif
842 return n;
843 }
845 /* The strategy is to
846 * - announce that we will maybe sleep
847 * - poll a bit ; if successful, return
848 * - if timeout, return
849 * - really sleep (except if somebody woke us in the meanwhile) */
850 int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
851 struct timeval *timeout)
852 {
853 int n, ret;
854 fd_set myread, mywrite, myexcept;
855 struct thread *thread = get_current();
856 s_time_t start = NOW(), stop;
857 DEFINE_WAIT(w1);
858 DEFINE_WAIT(w2);
859 DEFINE_WAIT(w3);
860 DEFINE_WAIT(w4);
861 DEFINE_WAIT(w5);
862 DEFINE_WAIT(w6);
864 assert(thread == main_thread);
866 DEBUG("select(%d, ", nfds);
867 dump_set(nfds, readfds, writefds, exceptfds, timeout);
868 DEBUG(");\n");
870 if (timeout)
871 stop = start + SECONDS(timeout->tv_sec) + timeout->tv_usec * 1000;
872 else
873 /* just make gcc happy */
874 stop = start;
876 /* Tell people we're going to sleep before looking at what they are
877 * saying, hence letting them wake us if events happen between here and
878 * schedule() */
879 add_waiter(w1, netfront_queue);
880 add_waiter(w2, event_queue);
881 add_waiter(w3, blkfront_queue);
882 add_waiter(w4, xenbus_watch_queue);
883 add_waiter(w5, kbdfront_queue);
884 add_waiter(w6, console_queue);
886 if (readfds)
887 myread = *readfds;
888 else
889 FD_ZERO(&myread);
890 if (writefds)
891 mywrite = *writefds;
892 else
893 FD_ZERO(&mywrite);
894 if (exceptfds)
895 myexcept = *exceptfds;
896 else
897 FD_ZERO(&myexcept);
899 DEBUG("polling ");
900 dump_set(nfds, &myread, &mywrite, &myexcept, timeout);
901 DEBUG("\n");
902 n = select_poll(nfds, &myread, &mywrite, &myexcept);
904 if (n) {
905 dump_set(nfds, readfds, writefds, exceptfds, timeout);
906 if (readfds)
907 *readfds = myread;
908 if (writefds)
909 *writefds = mywrite;
910 if (exceptfds)
911 *exceptfds = myexcept;
912 DEBUG(" -> ");
913 dump_set(nfds, readfds, writefds, exceptfds, timeout);
914 DEBUG("\n");
915 wake(thread);
916 ret = n;
917 goto out;
918 }
919 if (timeout && NOW() >= stop) {
920 if (readfds)
921 FD_ZERO(readfds);
922 if (writefds)
923 FD_ZERO(writefds);
924 if (exceptfds)
925 FD_ZERO(exceptfds);
926 timeout->tv_sec = 0;
927 timeout->tv_usec = 0;
928 wake(thread);
929 ret = 0;
930 goto out;
931 }
933 if (timeout)
934 thread->wakeup_time = stop;
935 schedule();
937 if (readfds)
938 myread = *readfds;
939 else
940 FD_ZERO(&myread);
941 if (writefds)
942 mywrite = *writefds;
943 else
944 FD_ZERO(&mywrite);
945 if (exceptfds)
946 myexcept = *exceptfds;
947 else
948 FD_ZERO(&myexcept);
950 n = select_poll(nfds, &myread, &mywrite, &myexcept);
952 if (n) {
953 if (readfds)
954 *readfds = myread;
955 if (writefds)
956 *writefds = mywrite;
957 if (exceptfds)
958 *exceptfds = myexcept;
959 ret = n;
960 goto out;
961 }
962 errno = EINTR;
963 ret = -1;
965 out:
966 remove_waiter(w1);
967 remove_waiter(w2);
968 remove_waiter(w3);
969 remove_waiter(w4);
970 remove_waiter(w5);
971 remove_waiter(w6);
972 return ret;
973 }
975 #ifdef HAVE_LWIP
976 int socket(int domain, int type, int protocol)
977 {
978 int fd, res;
979 fd = lwip_socket(domain, type, protocol);
980 if (fd < 0)
981 return -1;
982 res = alloc_fd(FTYPE_SOCKET);
983 printk("socket -> %d\n", res);
984 files[res].socket.fd = fd;
985 return res;
986 }
988 int accept(int s, struct sockaddr *addr, socklen_t *addrlen)
989 {
990 int fd, res;
991 if (files[s].type != FTYPE_SOCKET) {
992 printk("accept(%d): Bad descriptor\n", s);
993 errno = EBADF;
994 return -1;
995 }
996 fd = lwip_accept(files[s].socket.fd, addr, addrlen);
997 if (fd < 0)
998 return -1;
999 res = alloc_fd(FTYPE_SOCKET);
1000 files[res].socket.fd = fd;
1001 printk("accepted on %d -> %d\n", s, res);
1002 return res;
1005 #define LWIP_STUB(ret, name, proto, args) \
1006 ret name proto \
1007 { \
1008 if (files[s].type != FTYPE_SOCKET) { \
1009 printk(#name "(%d): Bad descriptor\n", s); \
1010 errno = EBADF; \
1011 return -1; \
1012 } \
1013 s = files[s].socket.fd; \
1014 return lwip_##name args; \
1017 LWIP_STUB(int, bind, (int s, struct sockaddr *my_addr, socklen_t addrlen), (s, my_addr, addrlen))
1018 LWIP_STUB(int, getsockopt, (int s, int level, int optname, void *optval, socklen_t *optlen), (s, level, optname, optval, optlen))
1019 LWIP_STUB(int, setsockopt, (int s, int level, int optname, void *optval, socklen_t optlen), (s, level, optname, optval, optlen))
1020 LWIP_STUB(int, connect, (int s, struct sockaddr *serv_addr, socklen_t addrlen), (s, serv_addr, addrlen))
1021 LWIP_STUB(int, listen, (int s, int backlog), (s, backlog));
1022 LWIP_STUB(ssize_t, recv, (int s, void *buf, size_t len, int flags), (s, buf, len, flags))
1023 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))
1024 LWIP_STUB(ssize_t, send, (int s, void *buf, size_t len, int flags), (s, buf, len, flags))
1025 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))
1026 LWIP_STUB(int, getsockname, (int s, struct sockaddr *name, socklen_t *namelen), (s, name, namelen))
1027 #endif
1029 static char *syslog_ident;
1030 void openlog(const char *ident, int option, int facility)
1032 if (syslog_ident)
1033 free(syslog_ident);
1034 syslog_ident = strdup(ident);
1037 void vsyslog(int priority, const char *format, va_list ap)
1039 printk("%s: ", syslog_ident);
1040 print(0, format, ap);
1043 void syslog(int priority, const char *format, ...)
1045 va_list ap;
1046 va_start(ap, format);
1047 vsyslog(priority, format, ap);
1048 va_end(ap);
1051 void closelog(void)
1053 free(syslog_ident);
1054 syslog_ident = NULL;
1057 void vwarn(const char *format, va_list ap)
1059 int the_errno = errno;
1060 printk("stubdom: ");
1061 if (format) {
1062 print(0, format, ap);
1063 printk(", ");
1065 printk("%s", strerror(the_errno));
1068 void warn(const char *format, ...)
1070 va_list ap;
1071 va_start(ap, format);
1072 vwarn(format, ap);
1073 va_end(ap);
1076 void verr(int eval, const char *format, va_list ap)
1078 vwarn(format, ap);
1079 exit(eval);
1082 void err(int eval, const char *format, ...)
1084 va_list ap;
1085 va_start(ap, format);
1086 verr(eval, format, ap);
1087 va_end(ap);
1090 void vwarnx(const char *format, va_list ap)
1092 printk("stubdom: ");
1093 if (format)
1094 print(0, format, ap);
1097 void warnx(const char *format, ...)
1099 va_list ap;
1100 va_start(ap, format);
1101 vwarnx(format, ap);
1102 va_end(ap);
1105 void verrx(int eval, const char *format, va_list ap)
1107 vwarnx(format, ap);
1108 exit(eval);
1111 void errx(int eval, const char *format, ...)
1113 va_list ap;
1114 va_start(ap, format);
1115 verrx(eval, format, ap);
1116 va_end(ap);
1119 int nanosleep(const struct timespec *req, struct timespec *rem)
1121 s_time_t start = NOW();
1122 s_time_t stop = start + SECONDS(req->tv_sec) + req->tv_nsec;
1123 s_time_t stopped;
1124 struct thread *thread = get_current();
1126 thread->wakeup_time = stop;
1127 clear_runnable(thread);
1128 schedule();
1129 stopped = NOW();
1131 if (rem)
1133 s_time_t remaining = stop - stopped;
1134 if (remaining > 0)
1136 rem->tv_nsec = remaining % 1000000000ULL;
1137 rem->tv_sec = remaining / 1000000000ULL;
1138 } else memset(rem, 0, sizeof(*rem));
1141 return 0;
1144 int usleep(useconds_t usec)
1146 /* "usec shall be less than one million." */
1147 struct timespec req;
1148 req.tv_nsec = usec * 1000;
1149 req.tv_sec = 0;
1151 if (nanosleep(&req, NULL))
1152 return -1;
1154 return 0;
1157 unsigned int sleep(unsigned int seconds)
1159 struct timespec req, rem;
1160 req.tv_sec = seconds;
1161 req.tv_nsec = 0;
1163 if (nanosleep(&req, &rem))
1164 return -1;
1166 if (rem.tv_nsec > 0)
1167 rem.tv_sec++;
1169 return rem.tv_sec;
1172 int clock_gettime(clockid_t clk_id, struct timespec *tp)
1174 switch (clk_id) {
1175 case CLOCK_MONOTONIC:
1177 struct timeval tv;
1179 gettimeofday(&tv, NULL);
1181 tp->tv_sec = tv.tv_sec;
1182 tp->tv_nsec = tv.tv_usec * 1000;
1184 break;
1186 case CLOCK_REALTIME:
1188 u64 nsec = monotonic_clock();
1190 tp->tv_sec = nsec / 1000000000ULL;
1191 tp->tv_nsec = nsec % 1000000000ULL;
1193 break;
1195 default:
1196 print_unsupported("clock_gettime(%d)", clk_id);
1197 errno = EINVAL;
1198 return -1;
1201 return 0;
1204 uid_t getuid(void)
1206 return 0;
1209 uid_t geteuid(void)
1211 return 0;
1214 gid_t getgid(void)
1216 return 0;
1219 gid_t getegid(void)
1221 return 0;
1224 int gethostname(char *name, size_t namelen)
1226 strncpy(name, "mini-os", namelen);
1227 return 0;
1230 size_t getpagesize(void)
1232 return PAGE_SIZE;
1235 void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset)
1237 unsigned long n = (length + PAGE_SIZE - 1) / PAGE_SIZE;
1239 ASSERT(!start);
1240 ASSERT(prot == (PROT_READ|PROT_WRITE));
1241 ASSERT((fd == -1 && (flags == (MAP_SHARED|MAP_ANON) || flags == (MAP_PRIVATE|MAP_ANON)))
1242 || (fd != -1 && flags == MAP_SHARED));
1243 ASSERT(offset == 0);
1245 if (fd == -1)
1246 return map_zero(n, 1);
1247 else if (files[fd].type == FTYPE_XC) {
1248 unsigned long zero = 0;
1249 return map_frames_ex(&zero, n, 0, 0, 1, DOMID_SELF, 0, 0);
1250 } else ASSERT(0);
1253 int munmap(void *start, size_t length)
1255 int total = length / PAGE_SIZE;
1256 int ret;
1258 ret = unmap_frames((unsigned long)start, (unsigned long)total);
1259 if (ret) {
1260 errno = ret;
1261 return -1;
1263 return 0;
1266 void sparse(unsigned long data, size_t size)
1268 unsigned long newdata;
1269 xen_pfn_t *mfns;
1270 int i, n;
1272 newdata = (data + PAGE_SIZE - 1) & PAGE_MASK;
1273 if (newdata - data > size)
1274 return;
1275 size -= newdata - data;
1276 data = newdata;
1277 n = size / PAGE_SIZE;
1278 size = n * PAGE_SIZE;
1280 mfns = malloc(n * sizeof(*mfns));
1281 for (i = 0; i < n; i++) {
1282 #ifdef LIBC_DEBUG
1283 int j;
1284 for (j=0; j<PAGE_SIZE; j++)
1285 if (((char*)data + i * PAGE_SIZE)[j]) {
1286 printk("%lx is not zero!\n", data + i * PAGE_SIZE + j);
1287 exit(1);
1289 #endif
1290 mfns[i] = virtual_to_mfn(data + i * PAGE_SIZE);
1293 printk("sparsing %ldMB at %lx\n", size >> 20, data);
1295 munmap((void *) data, size);
1296 free_physical_pages(mfns, n);
1297 do_map_zero(data, n);
1300 int nice(int inc)
1302 printk("nice() stub called with inc=%d\n", inc);
1303 return 0;
1307 /* Not supported by FS yet. */
1308 unsupported_function_crash(link);
1309 unsupported_function(int, readlink, -1);
1310 unsupported_function_crash(umask);
1312 /* We could support that. */
1313 unsupported_function_log(int, chdir, -1);
1315 /* No dynamic library support. */
1316 unsupported_function_log(void *, dlopen, NULL);
1317 unsupported_function_log(void *, dlsym, NULL);
1318 unsupported_function_log(char *, dlerror, NULL);
1319 unsupported_function_log(int, dlclose, -1);
1321 /* We don't raise signals anyway. */
1322 unsupported_function(int, sigemptyset, -1);
1323 unsupported_function(int, sigfillset, -1);
1324 unsupported_function(int, sigaddset, -1);
1325 unsupported_function(int, sigdelset, -1);
1326 unsupported_function(int, sigismember, -1);
1327 unsupported_function(int, sigprocmask, -1);
1328 unsupported_function(int, sigaction, -1);
1329 unsupported_function(int, __sigsetjmp, 0);
1330 unsupported_function(int, sigaltstack, -1);
1331 unsupported_function_crash(kill);
1333 /* Unsupported */
1334 unsupported_function_crash(pipe);
1335 unsupported_function_crash(fork);
1336 unsupported_function_crash(execv);
1337 unsupported_function_crash(execve);
1338 unsupported_function_crash(waitpid);
1339 unsupported_function_crash(wait);
1340 unsupported_function_crash(lockf);
1341 unsupported_function_crash(sysconf);
1342 unsupported_function(int, tcsetattr, -1);
1343 unsupported_function(int, tcgetattr, 0);
1344 unsupported_function(int, poll, -1);
1346 /* net/if.h */
1347 unsupported_function_log(unsigned int, if_nametoindex, -1);
1348 unsupported_function_log(char *, if_indextoname, (char *) NULL);
1349 unsupported_function_log(struct if_nameindex *, if_nameindex, (struct if_nameindex *) NULL);
1350 unsupported_function_crash(if_freenameindex);
1352 /* Linuxish abi for the Caml runtime, don't support
1353 Log, and return an error code if possible. If it is not possible
1354 to inform the application of an error, then crash instead!
1355 */
1356 unsupported_function_log(struct dirent *, readdir64, NULL);
1357 unsupported_function_log(int, getrusage, -1);
1358 unsupported_function_log(int, getrlimit, -1);
1359 unsupported_function_log(int, getrlimit64, -1);
1360 unsupported_function_log(int, __xstat64, -1);
1361 unsupported_function_log(long, __strtol_internal, LONG_MIN);
1362 unsupported_function_log(double, __strtod_internal, HUGE_VAL);
1363 unsupported_function_log(int, utime, -1);
1364 unsupported_function_log(int, truncate64, -1);
1365 unsupported_function_log(int, tcflow, -1);
1366 unsupported_function_log(int, tcflush, -1);
1367 unsupported_function_log(int, tcdrain, -1);
1368 unsupported_function_log(int, tcsendbreak, -1);
1369 unsupported_function_log(int, cfsetospeed, -1);
1370 unsupported_function_log(int, cfsetispeed, -1);
1371 unsupported_function_crash(cfgetospeed);
1372 unsupported_function_crash(cfgetispeed);
1373 unsupported_function_log(int, symlink, -1);
1374 unsupported_function_log(const char*, inet_ntop, NULL);
1375 unsupported_function_crash(__fxstat64);
1376 unsupported_function_crash(__lxstat64);
1377 unsupported_function_log(int, socketpair, -1);
1378 unsupported_function_crash(sigsuspend);
1379 unsupported_function_log(int, sigpending, -1);
1380 unsupported_function_log(int, shutdown, -1);
1381 unsupported_function_log(int, setuid, -1);
1382 unsupported_function_log(int, setgid, -1);
1383 unsupported_function_crash(rewinddir);
1384 unsupported_function_log(int, getpriority, -1);
1385 unsupported_function_log(int, setpriority, -1);
1386 unsupported_function_log(int, mkfifo, -1);
1387 unsupported_function_log(int, getitimer, -1);
1388 unsupported_function_log(int, setitimer, -1);
1389 unsupported_function_log(void *, getservbyport, NULL);
1390 unsupported_function_log(void *, getservbyname, NULL);
1391 unsupported_function_log(void *, getpwuid, NULL);
1392 unsupported_function_log(void *, getpwnam, NULL);
1393 unsupported_function_log(void *, getprotobynumber, NULL);
1394 unsupported_function_log(void *, getprotobyname, NULL);
1395 unsupported_function_log(int, getpeername, -1);
1396 unsupported_function_log(int, getnameinfo, -1);
1397 unsupported_function_log(char *, getlogin, NULL);
1398 unsupported_function_crash(__h_errno_location);
1399 unsupported_function_log(int, gethostbyname_r, -1);
1400 unsupported_function_log(int, gethostbyaddr_r, -1);
1401 unsupported_function_log(int, getgroups, -1);
1402 unsupported_function_log(void *, getgrgid, NULL);
1403 unsupported_function_log(void *, getgrnam, NULL);
1404 unsupported_function_log(int, getaddrinfo, -1);
1405 unsupported_function_log(int, freeaddrinfo, -1);
1406 unsupported_function_log(int, ftruncate64, -1);
1407 unsupported_function_log(int, fchown, -1);
1408 unsupported_function_log(int, fchmod, -1);
1409 unsupported_function_crash(execvp);
1410 unsupported_function_log(int, dup, -1)
1411 unsupported_function_log(int, chroot, -1)
1412 unsupported_function_log(int, chown, -1);
1413 unsupported_function_log(int, chmod, -1);
1414 unsupported_function_crash(alarm);
1415 unsupported_function_log(int, inet_pton, -1);
1416 unsupported_function_log(int, access, -1);
1417 #endif