debuggers.hg

view extras/mini-os/lib/sys.c @ 19660:b4de3a393f21

minios: Implement some extra lib functions for ocaml xenstored stubdom

We could stub them out as unsupported, but we may as well implement
them as they are very simple.

Signed-off-by: Alex Zeffertt <alex.zeffertt@eu.citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Tue May 19 14:15:43 2009 +0100 (2009-05-19)
parents 49f2f2aa5f83
children 11d8ca329b54
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 open(const char *pathname, int flags, ...)
171 {
172 int fs_fd, fd;
173 /* Ugly, but fine. */
174 if (!strncmp(pathname,LOG_PATH,strlen(LOG_PATH))) {
175 fd = alloc_fd(FTYPE_CONSOLE);
176 printk("open(%s) -> %d\n", pathname, fd);
177 return fd;
178 }
179 printk("open(%s, %x)", pathname, flags);
180 switch (flags & ~O_ACCMODE) {
181 case 0:
182 fs_fd = fs_open(fs_import, (void *) pathname);
183 break;
184 case O_CREAT|O_TRUNC:
185 {
186 va_list ap;
187 mode_t mode;
188 va_start(ap, flags);
189 mode = va_arg(ap, mode_t);
190 va_end(ap);
191 fs_fd = fs_create(fs_import, (void *) pathname, 0, mode);
192 break;
193 }
194 default:
195 printk(" unsupported flags\n");
196 do_exit();
197 }
198 if (fs_fd < 0) {
199 errno = EIO;
200 return -1;
201 }
202 fd = alloc_fd(FTYPE_FILE);
203 printk("-> %d\n", fd);
204 files[fd].file.fd = fs_fd;
205 files[fd].file.offset = 0;
206 return fd;
207 }
209 int isatty(int fd)
210 {
211 return files[fd].type == FTYPE_CONSOLE;
212 }
214 int read(int fd, void *buf, size_t nbytes)
215 {
216 switch (files[fd].type) {
217 case FTYPE_CONSOLE: {
218 int ret;
219 DEFINE_WAIT(w);
220 while(1) {
221 add_waiter(w, console_queue);
222 ret = xencons_ring_recv(buf, nbytes);
223 if (ret)
224 break;
225 schedule();
226 }
227 remove_waiter(w);
228 return ret;
229 }
230 case FTYPE_FILE: {
231 ssize_t ret;
232 if (nbytes > PAGE_SIZE * FSIF_NR_READ_GNTS)
233 nbytes = PAGE_SIZE * FSIF_NR_READ_GNTS;
234 ret = fs_read(fs_import, files[fd].file.fd, buf, nbytes, files[fd].file.offset);
235 if (ret > 0) {
236 files[fd].file.offset += ret;
237 return ret;
238 } else if (ret < 0) {
239 errno = EIO;
240 return -1;
241 }
242 return 0;
243 }
244 #ifdef HAVE_LWIP
245 case FTYPE_SOCKET:
246 return lwip_read(files[fd].socket.fd, buf, nbytes);
247 #endif
248 case FTYPE_TAP: {
249 ssize_t ret;
250 ret = netfront_receive(files[fd].tap.dev, buf, nbytes);
251 if (ret <= 0) {
252 errno = EAGAIN;
253 return -1;
254 }
255 return ret;
256 }
257 case FTYPE_KBD: {
258 int ret, n;
259 n = nbytes / sizeof(union xenkbd_in_event);
260 ret = kbdfront_receive(files[fd].kbd.dev, buf, n);
261 if (ret <= 0) {
262 errno = EAGAIN;
263 return -1;
264 }
265 return ret * sizeof(union xenkbd_in_event);
266 }
267 case FTYPE_FB: {
268 int ret, n;
269 n = nbytes / sizeof(union xenfb_in_event);
270 ret = fbfront_receive(files[fd].fb.dev, buf, n);
271 if (ret <= 0) {
272 errno = EAGAIN;
273 return -1;
274 }
275 return ret * sizeof(union xenfb_in_event);
276 }
277 default:
278 break;
279 }
280 printk("read(%d): Bad descriptor\n", fd);
281 errno = EBADF;
282 return -1;
283 }
285 int write(int fd, const void *buf, size_t nbytes)
286 {
287 switch (files[fd].type) {
288 case FTYPE_CONSOLE:
289 console_print((char *)buf, nbytes);
290 return nbytes;
291 case FTYPE_FILE: {
292 ssize_t ret;
293 if (nbytes > PAGE_SIZE * FSIF_NR_WRITE_GNTS)
294 nbytes = PAGE_SIZE * FSIF_NR_WRITE_GNTS;
295 ret = fs_write(fs_import, files[fd].file.fd, (void *) buf, nbytes, files[fd].file.offset);
296 if (ret > 0) {
297 files[fd].file.offset += ret;
298 return ret;
299 } else if (ret < 0) {
300 errno = EIO;
301 return -1;
302 }
303 return 0;
304 }
305 #ifdef HAVE_LWIP
306 case FTYPE_SOCKET:
307 return lwip_write(files[fd].socket.fd, (void*) buf, nbytes);
308 #endif
309 case FTYPE_TAP:
310 netfront_xmit(files[fd].tap.dev, (void*) buf, nbytes);
311 return nbytes;
312 default:
313 break;
314 }
315 printk("write(%d): Bad descriptor\n", fd);
316 errno = EBADF;
317 return -1;
318 }
320 off_t lseek(int fd, off_t offset, int whence)
321 {
322 if (files[fd].type != FTYPE_FILE) {
323 errno = ESPIPE;
324 return (off_t) -1;
325 }
326 switch (whence) {
327 case SEEK_SET:
328 files[fd].file.offset = offset;
329 break;
330 case SEEK_CUR:
331 files[fd].file.offset += offset;
332 break;
333 case SEEK_END: {
334 struct stat st;
335 int ret;
336 ret = fstat(fd, &st);
337 if (ret)
338 return -1;
339 files[fd].file.offset = st.st_size + offset;
340 break;
341 }
342 default:
343 errno = EINVAL;
344 return -1;
345 }
346 return files[fd].file.offset;
347 }
349 int fsync(int fd) {
350 switch (files[fd].type) {
351 case FTYPE_FILE: {
352 int ret;
353 ret = fs_sync(fs_import, files[fd].file.fd);
354 if (ret < 0) {
355 errno = EIO;
356 return -1;
357 }
358 return 0;
359 }
360 default:
361 break;
362 }
363 printk("fsync(%d): Bad descriptor\n", fd);
364 errno = EBADF;
365 return -1;
366 }
368 int close(int fd)
369 {
370 printk("close(%d)\n", fd);
371 switch (files[fd].type) {
372 default:
373 files[fd].type = FTYPE_NONE;
374 return 0;
375 case FTYPE_FILE: {
376 int ret = fs_close(fs_import, files[fd].file.fd);
377 files[fd].type = FTYPE_NONE;
378 if (ret < 0) {
379 errno = EIO;
380 return -1;
381 }
382 return 0;
383 }
384 case FTYPE_XENBUS:
385 xs_daemon_close((void*)(intptr_t) fd);
386 return 0;
387 #ifdef HAVE_LWIP
388 case FTYPE_SOCKET: {
389 int res = lwip_close(files[fd].socket.fd);
390 files[fd].type = FTYPE_NONE;
391 return res;
392 }
393 #endif
394 case FTYPE_XC:
395 xc_interface_close(fd);
396 return 0;
397 case FTYPE_EVTCHN:
398 xc_evtchn_close(fd);
399 return 0;
400 case FTYPE_GNTMAP:
401 xc_gnttab_close(fd);
402 return 0;
403 case FTYPE_TAP:
404 shutdown_netfront(files[fd].tap.dev);
405 files[fd].type = FTYPE_NONE;
406 return 0;
407 case FTYPE_BLK:
408 shutdown_blkfront(files[fd].blk.dev);
409 files[fd].type = FTYPE_NONE;
410 return 0;
411 case FTYPE_KBD:
412 shutdown_kbdfront(files[fd].kbd.dev);
413 files[fd].type = FTYPE_NONE;
414 return 0;
415 case FTYPE_FB:
416 shutdown_fbfront(files[fd].fb.dev);
417 files[fd].type = FTYPE_NONE;
418 return 0;
419 case FTYPE_NONE:
420 break;
421 }
422 printk("close(%d): Bad descriptor\n", fd);
423 errno = EBADF;
424 return -1;
425 }
427 static void init_stat(struct stat *buf)
428 {
429 memset(buf, 0, sizeof(*buf));
430 buf->st_dev = 0;
431 buf->st_ino = 0;
432 buf->st_nlink = 1;
433 buf->st_rdev = 0;
434 buf->st_blksize = 4096;
435 buf->st_blocks = 0;
436 }
438 static void stat_from_fs(struct stat *buf, struct fsif_stat_response *stat)
439 {
440 buf->st_mode = stat->stat_mode;
441 buf->st_uid = stat->stat_uid;
442 buf->st_gid = stat->stat_gid;
443 buf->st_size = stat->stat_size;
444 buf->st_atime = stat->stat_atime;
445 buf->st_mtime = stat->stat_mtime;
446 buf->st_ctime = stat->stat_ctime;
447 }
449 int stat(const char *path, struct stat *buf)
450 {
451 struct fsif_stat_response stat;
452 int ret;
453 int fs_fd;
454 printk("stat(%s)\n", path);
455 fs_fd = fs_open(fs_import, (char*) path);
456 if (fs_fd < 0) {
457 errno = EIO;
458 ret = -1;
459 goto out;
460 }
461 ret = fs_stat(fs_import, fs_fd, &stat);
462 if (ret < 0) {
463 errno = EIO;
464 ret = -1;
465 goto outfd;
466 }
467 init_stat(buf);
468 stat_from_fs(buf, &stat);
469 ret = 0;
471 outfd:
472 fs_close(fs_import, fs_fd);
473 out:
474 return ret;
475 }
477 int fstat(int fd, struct stat *buf)
478 {
479 init_stat(buf);
480 switch (files[fd].type) {
481 case FTYPE_CONSOLE:
482 case FTYPE_SOCKET: {
483 buf->st_mode = (files[fd].type == FTYPE_CONSOLE?S_IFCHR:S_IFSOCK) | S_IRUSR|S_IWUSR;
484 buf->st_uid = 0;
485 buf->st_gid = 0;
486 buf->st_size = 0;
487 buf->st_atime =
488 buf->st_mtime =
489 buf->st_ctime = time(NULL);
490 return 0;
491 }
492 case FTYPE_FILE: {
493 struct fsif_stat_response stat;
494 int ret;
495 ret = fs_stat(fs_import, files[fd].file.fd, &stat);
496 if (ret < 0) {
497 errno = EIO;
498 return -1;
499 }
500 /* The protocol is a bit evasive about this value */
501 stat_from_fs(buf, &stat);
502 return 0;
503 }
504 default:
505 break;
506 }
508 printk("statf(%d): Bad descriptor\n", fd);
509 errno = EBADF;
510 return -1;
511 }
513 int ftruncate(int fd, off_t length)
514 {
515 switch (files[fd].type) {
516 case FTYPE_FILE: {
517 int ret;
518 ret = fs_truncate(fs_import, files[fd].file.fd, length);
519 if (ret < 0) {
520 errno = EIO;
521 return -1;
522 }
523 return 0;
524 }
525 default:
526 break;
527 }
529 printk("ftruncate(%d): Bad descriptor\n", fd);
530 errno = EBADF;
531 return -1;
532 }
534 int remove(const char *pathname)
535 {
536 int ret;
537 printk("remove(%s)", pathname);
538 ret = fs_remove(fs_import, (char*) pathname);
539 if (ret < 0) {
540 errno = EIO;
541 return -1;
542 }
543 return 0;
544 }
546 int unlink(const char *pathname)
547 {
548 return remove(pathname);
549 }
551 int rmdir(const char *pathname)
552 {
553 return remove(pathname);
554 }
556 int fcntl(int fd, int cmd, ...)
557 {
558 long arg;
559 va_list ap;
560 va_start(ap, cmd);
561 arg = va_arg(ap, long);
562 va_end(ap);
564 switch (cmd) {
565 #ifdef HAVE_LWIP
566 case F_SETFL:
567 if (files[fd].type == FTYPE_SOCKET && !(arg & ~O_NONBLOCK)) {
568 /* Only flag supported: non-blocking mode */
569 uint32_t nblock = !!(arg & O_NONBLOCK);
570 return lwip_ioctl(files[fd].socket.fd, FIONBIO, &nblock);
571 }
572 /* Fallthrough */
573 #endif
574 default:
575 printk("fcntl(%d, %d, %lx/%lo)\n", fd, cmd, arg, arg);
576 errno = ENOSYS;
577 return -1;
578 }
579 }
581 DIR *opendir(const char *name)
582 {
583 DIR *ret;
584 ret = malloc(sizeof(*ret));
585 ret->name = strdup(name);
586 ret->offset = 0;
587 ret->entries = NULL;
588 ret->curentry = -1;
589 ret->nbentries = 0;
590 ret->has_more = 1;
591 return ret;
592 }
594 struct dirent *readdir(DIR *dir)
595 {
596 if (dir->curentry >= 0) {
597 free(dir->entries[dir->curentry]);
598 dir->entries[dir->curentry] = NULL;
599 }
600 dir->curentry++;
601 if (dir->curentry >= dir->nbentries) {
602 dir->offset += dir->nbentries;
603 free(dir->entries);
604 dir->curentry = -1;
605 dir->nbentries = 0;
606 if (!dir->has_more)
607 return NULL;
608 dir->entries = fs_list(fs_import, dir->name, dir->offset, &dir->nbentries, &dir->has_more);
609 if (!dir->entries || !dir->nbentries)
610 return NULL;
611 dir->curentry = 0;
612 }
613 dir->dirent.d_name = dir->entries[dir->curentry];
614 return &dir->dirent;
615 }
616 int closedir(DIR *dir)
617 {
618 int i;
619 for (i=0; i<dir->nbentries; i++)
620 free(dir->entries[i]);
621 free(dir->entries);
622 free(dir->name);
623 free(dir);
624 return 0;
625 }
627 /* We assume that only the main thread calls select(). */
629 static const char file_types[] = {
630 [FTYPE_NONE] = 'N',
631 [FTYPE_CONSOLE] = 'C',
632 [FTYPE_FILE] = 'F',
633 [FTYPE_XENBUS] = 'S',
634 [FTYPE_XC] = 'X',
635 [FTYPE_EVTCHN] = 'E',
636 [FTYPE_SOCKET] = 's',
637 [FTYPE_TAP] = 'T',
638 [FTYPE_BLK] = 'B',
639 [FTYPE_KBD] = 'K',
640 [FTYPE_FB] = 'G',
641 };
642 #ifdef LIBC_DEBUG
643 static void dump_set(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout)
644 {
645 int i, comma;
646 #define printfds(set) do {\
647 comma = 0; \
648 for (i = 0; i < nfds; i++) { \
649 if (FD_ISSET(i, set)) { \
650 if (comma) \
651 printk(", "); \
652 printk("%d(%c)", i, file_types[files[i].type]); \
653 comma = 1; \
654 } \
655 } \
656 } while (0)
658 printk("[");
659 if (readfds)
660 printfds(readfds);
661 printk("], [");
662 if (writefds)
663 printfds(writefds);
664 printk("], [");
665 if (exceptfds)
666 printfds(exceptfds);
667 printk("], ");
668 if (timeout)
669 printk("{ %ld, %ld }", timeout->tv_sec, timeout->tv_usec);
670 }
671 #else
672 #define dump_set(nfds, readfds, writefds, exceptfds, timeout)
673 #endif
675 /* Just poll without blocking */
676 static int select_poll(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds)
677 {
678 int i, n = 0;
679 #ifdef HAVE_LWIP
680 int sock_n = 0, sock_nfds = 0;
681 fd_set sock_readfds, sock_writefds, sock_exceptfds;
682 struct timeval timeout = { .tv_sec = 0, .tv_usec = 0};
683 #endif
685 #ifdef LIBC_VERBOSE
686 static int nb;
687 static int nbread[NOFILE], nbwrite[NOFILE], nbexcept[NOFILE];
688 static s_time_t lastshown;
690 nb++;
691 #endif
693 #ifdef HAVE_LWIP
694 /* first poll network */
695 FD_ZERO(&sock_readfds);
696 FD_ZERO(&sock_writefds);
697 FD_ZERO(&sock_exceptfds);
698 for (i = 0; i < nfds; i++) {
699 if (files[i].type == FTYPE_SOCKET) {
700 if (FD_ISSET(i, readfds)) {
701 FD_SET(files[i].socket.fd, &sock_readfds);
702 sock_nfds = i+1;
703 }
704 if (FD_ISSET(i, writefds)) {
705 FD_SET(files[i].socket.fd, &sock_writefds);
706 sock_nfds = i+1;
707 }
708 if (FD_ISSET(i, exceptfds)) {
709 FD_SET(files[i].socket.fd, &sock_exceptfds);
710 sock_nfds = i+1;
711 }
712 }
713 }
714 if (sock_nfds > 0) {
715 DEBUG("lwip_select(");
716 dump_set(nfds, &sock_readfds, &sock_writefds, &sock_exceptfds, &timeout);
717 DEBUG("); -> ");
718 sock_n = lwip_select(sock_nfds, &sock_readfds, &sock_writefds, &sock_exceptfds, &timeout);
719 dump_set(nfds, &sock_readfds, &sock_writefds, &sock_exceptfds, &timeout);
720 DEBUG("\n");
721 }
722 #endif
724 /* Then see others as well. */
725 for (i = 0; i < nfds; i++) {
726 switch(files[i].type) {
727 default:
728 if (FD_ISSET(i, readfds) || FD_ISSET(i, writefds) || FD_ISSET(i, exceptfds))
729 printk("bogus fd %d in select\n", i);
730 /* Fallthrough. */
731 case FTYPE_FILE:
732 FD_CLR(i, readfds);
733 FD_CLR(i, writefds);
734 FD_CLR(i, exceptfds);
735 break;
736 case FTYPE_CONSOLE:
737 if (FD_ISSET(i, readfds)) {
738 if (xencons_ring_avail())
739 n++;
740 else
741 FD_CLR(i, readfds);
742 }
743 if (FD_ISSET(i, writefds))
744 n++;
745 FD_CLR(i, exceptfds);
746 break;
747 case FTYPE_XENBUS:
748 if (FD_ISSET(i, readfds)) {
749 if (files[i].xenbus.events)
750 n++;
751 else
752 FD_CLR(i, readfds);
753 }
754 FD_CLR(i, writefds);
755 FD_CLR(i, exceptfds);
756 break;
757 case FTYPE_EVTCHN:
758 case FTYPE_TAP:
759 case FTYPE_BLK:
760 case FTYPE_KBD:
761 case FTYPE_FB:
762 if (FD_ISSET(i, readfds)) {
763 if (files[i].read)
764 n++;
765 else
766 FD_CLR(i, readfds);
767 }
768 FD_CLR(i, writefds);
769 FD_CLR(i, exceptfds);
770 break;
771 #ifdef HAVE_LWIP
772 case FTYPE_SOCKET:
773 if (FD_ISSET(i, readfds)) {
774 /* Optimize no-network-packet case. */
775 if (sock_n && FD_ISSET(files[i].socket.fd, &sock_readfds))
776 n++;
777 else
778 FD_CLR(i, readfds);
779 }
780 if (FD_ISSET(i, writefds)) {
781 if (sock_n && FD_ISSET(files[i].socket.fd, &sock_writefds))
782 n++;
783 else
784 FD_CLR(i, writefds);
785 }
786 if (FD_ISSET(i, exceptfds)) {
787 if (sock_n && FD_ISSET(files[i].socket.fd, &sock_exceptfds))
788 n++;
789 else
790 FD_CLR(i, exceptfds);
791 }
792 break;
793 #endif
794 }
795 #ifdef LIBC_VERBOSE
796 if (FD_ISSET(i, readfds))
797 nbread[i]++;
798 if (FD_ISSET(i, writefds))
799 nbwrite[i]++;
800 if (FD_ISSET(i, exceptfds))
801 nbexcept[i]++;
802 #endif
803 }
804 #ifdef LIBC_VERBOSE
805 if (NOW() > lastshown + 1000000000ull) {
806 lastshown = NOW();
807 printk("%lu MB free, ", num_free_pages() / ((1 << 20) / PAGE_SIZE));
808 printk("%d(%d): ", nb, sock_n);
809 for (i = 0; i < nfds; i++) {
810 if (nbread[i] || nbwrite[i] || nbexcept[i])
811 printk(" %d(%c):", i, file_types[files[i].type]);
812 if (nbread[i])
813 printk(" %dR", nbread[i]);
814 if (nbwrite[i])
815 printk(" %dW", nbwrite[i]);
816 if (nbexcept[i])
817 printk(" %dE", nbexcept[i]);
818 }
819 printk("\n");
820 memset(nbread, 0, sizeof(nbread));
821 memset(nbwrite, 0, sizeof(nbwrite));
822 memset(nbexcept, 0, sizeof(nbexcept));
823 nb = 0;
824 }
825 #endif
826 return n;
827 }
829 /* The strategy is to
830 * - announce that we will maybe sleep
831 * - poll a bit ; if successful, return
832 * - if timeout, return
833 * - really sleep (except if somebody woke us in the meanwhile) */
834 int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
835 struct timeval *timeout)
836 {
837 int n, ret;
838 fd_set myread, mywrite, myexcept;
839 struct thread *thread = get_current();
840 s_time_t start = NOW(), stop;
841 DEFINE_WAIT(w1);
842 DEFINE_WAIT(w2);
843 DEFINE_WAIT(w3);
844 DEFINE_WAIT(w4);
845 DEFINE_WAIT(w5);
846 DEFINE_WAIT(w6);
848 assert(thread == main_thread);
850 DEBUG("select(%d, ", nfds);
851 dump_set(nfds, readfds, writefds, exceptfds, timeout);
852 DEBUG(");\n");
854 if (timeout)
855 stop = start + SECONDS(timeout->tv_sec) + timeout->tv_usec * 1000;
856 else
857 /* just make gcc happy */
858 stop = start;
860 /* Tell people we're going to sleep before looking at what they are
861 * saying, hence letting them wake us if events happen between here and
862 * schedule() */
863 add_waiter(w1, netfront_queue);
864 add_waiter(w2, event_queue);
865 add_waiter(w3, blkfront_queue);
866 add_waiter(w4, xenbus_watch_queue);
867 add_waiter(w5, kbdfront_queue);
868 add_waiter(w6, console_queue);
870 if (readfds)
871 myread = *readfds;
872 else
873 FD_ZERO(&myread);
874 if (writefds)
875 mywrite = *writefds;
876 else
877 FD_ZERO(&mywrite);
878 if (exceptfds)
879 myexcept = *exceptfds;
880 else
881 FD_ZERO(&myexcept);
883 DEBUG("polling ");
884 dump_set(nfds, &myread, &mywrite, &myexcept, timeout);
885 DEBUG("\n");
886 n = select_poll(nfds, &myread, &mywrite, &myexcept);
888 if (n) {
889 dump_set(nfds, readfds, writefds, exceptfds, timeout);
890 if (readfds)
891 *readfds = myread;
892 if (writefds)
893 *writefds = mywrite;
894 if (exceptfds)
895 *exceptfds = myexcept;
896 DEBUG(" -> ");
897 dump_set(nfds, readfds, writefds, exceptfds, timeout);
898 DEBUG("\n");
899 wake(thread);
900 ret = n;
901 goto out;
902 }
903 if (timeout && NOW() >= stop) {
904 if (readfds)
905 FD_ZERO(readfds);
906 if (writefds)
907 FD_ZERO(writefds);
908 if (exceptfds)
909 FD_ZERO(exceptfds);
910 timeout->tv_sec = 0;
911 timeout->tv_usec = 0;
912 wake(thread);
913 ret = 0;
914 goto out;
915 }
917 if (timeout)
918 thread->wakeup_time = stop;
919 schedule();
921 if (readfds)
922 myread = *readfds;
923 else
924 FD_ZERO(&myread);
925 if (writefds)
926 mywrite = *writefds;
927 else
928 FD_ZERO(&mywrite);
929 if (exceptfds)
930 myexcept = *exceptfds;
931 else
932 FD_ZERO(&myexcept);
934 n = select_poll(nfds, &myread, &mywrite, &myexcept);
936 if (n) {
937 if (readfds)
938 *readfds = myread;
939 if (writefds)
940 *writefds = mywrite;
941 if (exceptfds)
942 *exceptfds = myexcept;
943 ret = n;
944 goto out;
945 }
946 errno = EINTR;
947 ret = -1;
949 out:
950 remove_waiter(w1);
951 remove_waiter(w2);
952 remove_waiter(w3);
953 remove_waiter(w4);
954 remove_waiter(w5);
955 remove_waiter(w6);
956 return ret;
957 }
959 #ifdef HAVE_LWIP
960 int socket(int domain, int type, int protocol)
961 {
962 int fd, res;
963 fd = lwip_socket(domain, type, protocol);
964 if (fd < 0)
965 return -1;
966 res = alloc_fd(FTYPE_SOCKET);
967 printk("socket -> %d\n", res);
968 files[res].socket.fd = fd;
969 return res;
970 }
972 int accept(int s, struct sockaddr *addr, socklen_t *addrlen)
973 {
974 int fd, res;
975 if (files[s].type != FTYPE_SOCKET) {
976 printk("accept(%d): Bad descriptor\n", s);
977 errno = EBADF;
978 return -1;
979 }
980 fd = lwip_accept(files[s].socket.fd, addr, addrlen);
981 if (fd < 0)
982 return -1;
983 res = alloc_fd(FTYPE_SOCKET);
984 files[res].socket.fd = fd;
985 printk("accepted on %d -> %d\n", s, res);
986 return res;
987 }
989 #define LWIP_STUB(ret, name, proto, args) \
990 ret name proto \
991 { \
992 if (files[s].type != FTYPE_SOCKET) { \
993 printk(#name "(%d): Bad descriptor\n", s); \
994 errno = EBADF; \
995 return -1; \
996 } \
997 s = files[s].socket.fd; \
998 return lwip_##name args; \
999 }
1001 LWIP_STUB(int, bind, (int s, struct sockaddr *my_addr, socklen_t addrlen), (s, my_addr, addrlen))
1002 LWIP_STUB(int, getsockopt, (int s, int level, int optname, void *optval, socklen_t *optlen), (s, level, optname, optval, optlen))
1003 LWIP_STUB(int, setsockopt, (int s, int level, int optname, void *optval, socklen_t optlen), (s, level, optname, optval, optlen))
1004 LWIP_STUB(int, connect, (int s, struct sockaddr *serv_addr, socklen_t addrlen), (s, serv_addr, addrlen))
1005 LWIP_STUB(int, listen, (int s, int backlog), (s, backlog));
1006 LWIP_STUB(ssize_t, recv, (int s, void *buf, size_t len, int flags), (s, buf, len, flags))
1007 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))
1008 LWIP_STUB(ssize_t, send, (int s, void *buf, size_t len, int flags), (s, buf, len, flags))
1009 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))
1010 LWIP_STUB(int, getsockname, (int s, struct sockaddr *name, socklen_t *namelen), (s, name, namelen))
1011 #endif
1013 static char *syslog_ident;
1014 void openlog(const char *ident, int option, int facility)
1016 if (syslog_ident)
1017 free(syslog_ident);
1018 syslog_ident = strdup(ident);
1021 void vsyslog(int priority, const char *format, va_list ap)
1023 printk("%s: ", syslog_ident);
1024 print(0, format, ap);
1027 void syslog(int priority, const char *format, ...)
1029 va_list ap;
1030 va_start(ap, format);
1031 vsyslog(priority, format, ap);
1032 va_end(ap);
1035 void closelog(void)
1037 free(syslog_ident);
1038 syslog_ident = NULL;
1041 void vwarn(const char *format, va_list ap)
1043 int the_errno = errno;
1044 printk("stubdom: ");
1045 if (format) {
1046 print(0, format, ap);
1047 printk(", ");
1049 printk("%s", strerror(the_errno));
1052 void warn(const char *format, ...)
1054 va_list ap;
1055 va_start(ap, format);
1056 vwarn(format, ap);
1057 va_end(ap);
1060 void verr(int eval, const char *format, va_list ap)
1062 vwarn(format, ap);
1063 exit(eval);
1066 void err(int eval, const char *format, ...)
1068 va_list ap;
1069 va_start(ap, format);
1070 verr(eval, format, ap);
1071 va_end(ap);
1074 void vwarnx(const char *format, va_list ap)
1076 printk("stubdom: ");
1077 if (format)
1078 print(0, format, ap);
1081 void warnx(const char *format, ...)
1083 va_list ap;
1084 va_start(ap, format);
1085 vwarnx(format, ap);
1086 va_end(ap);
1089 void verrx(int eval, const char *format, va_list ap)
1091 vwarnx(format, ap);
1092 exit(eval);
1095 void errx(int eval, const char *format, ...)
1097 va_list ap;
1098 va_start(ap, format);
1099 verrx(eval, format, ap);
1100 va_end(ap);
1103 int nanosleep(const struct timespec *req, struct timespec *rem)
1105 s_time_t start = NOW();
1106 s_time_t stop = start + SECONDS(req->tv_sec) + req->tv_nsec;
1107 s_time_t stopped;
1108 struct thread *thread = get_current();
1110 thread->wakeup_time = stop;
1111 clear_runnable(thread);
1112 schedule();
1113 stopped = NOW();
1115 if (rem)
1117 s_time_t remaining = stop - stopped;
1118 if (remaining > 0)
1120 rem->tv_nsec = remaining % 1000000000ULL;
1121 rem->tv_sec = remaining / 1000000000ULL;
1122 } else memset(rem, 0, sizeof(*rem));
1125 return 0;
1128 int usleep(useconds_t usec)
1130 /* "usec shall be less than one million." */
1131 struct timespec req;
1132 req.tv_nsec = usec * 1000;
1133 req.tv_sec = 0;
1135 if (nanosleep(&req, NULL))
1136 return -1;
1138 return 0;
1141 unsigned int sleep(unsigned int seconds)
1143 struct timespec req, rem;
1144 req.tv_sec = seconds;
1145 req.tv_nsec = 0;
1147 if (nanosleep(&req, &rem))
1148 return -1;
1150 if (rem.tv_nsec > 0)
1151 rem.tv_sec++;
1153 return rem.tv_sec;
1156 int clock_gettime(clockid_t clk_id, struct timespec *tp)
1158 switch (clk_id) {
1159 case CLOCK_MONOTONIC:
1161 struct timeval tv;
1163 gettimeofday(&tv, NULL);
1165 tp->tv_sec = tv.tv_sec;
1166 tp->tv_nsec = tv.tv_usec * 1000;
1168 break;
1170 case CLOCK_REALTIME:
1172 u64 nsec = monotonic_clock();
1174 tp->tv_sec = nsec / 1000000000ULL;
1175 tp->tv_nsec = nsec % 1000000000ULL;
1177 break;
1179 default:
1180 print_unsupported("clock_gettime(%d)", clk_id);
1181 errno = EINVAL;
1182 return -1;
1185 return 0;
1188 uid_t getuid(void)
1190 return 0;
1193 uid_t geteuid(void)
1195 return 0;
1198 gid_t getgid(void)
1200 return 0;
1203 gid_t getegid(void)
1205 return 0;
1208 int gethostname(char *name, size_t namelen)
1210 strncpy(name, "mini-os", namelen);
1211 return 0;
1214 size_t getpagesize(void)
1216 return PAGE_SIZE;
1219 void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset)
1221 unsigned long n = (length + PAGE_SIZE - 1) / PAGE_SIZE;
1223 ASSERT(!start);
1224 ASSERT(prot == (PROT_READ|PROT_WRITE));
1225 ASSERT((fd == -1 && (flags == (MAP_SHARED|MAP_ANON) || flags == (MAP_PRIVATE|MAP_ANON)))
1226 || (fd != -1 && flags == MAP_SHARED));
1227 ASSERT(offset == 0);
1229 if (fd == -1)
1230 return map_zero(n, 1);
1231 else if (files[fd].type == FTYPE_XC) {
1232 unsigned long zero = 0;
1233 return map_frames_ex(&zero, n, 0, 0, 1, DOMID_SELF, 0, 0);
1234 } else ASSERT(0);
1237 int munmap(void *start, size_t length)
1239 int total = length / PAGE_SIZE;
1240 int ret;
1242 ret = unmap_frames((unsigned long)start, (unsigned long)total);
1243 if (ret) {
1244 errno = ret;
1245 return -1;
1247 return 0;
1250 void sparse(unsigned long data, size_t size)
1252 unsigned long newdata;
1253 xen_pfn_t *mfns;
1254 int i, n;
1256 newdata = (data + PAGE_SIZE - 1) & PAGE_MASK;
1257 if (newdata - data > size)
1258 return;
1259 size -= newdata - data;
1260 data = newdata;
1261 n = size / PAGE_SIZE;
1262 size = n * PAGE_SIZE;
1264 mfns = malloc(n * sizeof(*mfns));
1265 for (i = 0; i < n; i++) {
1266 #ifdef LIBC_DEBUG
1267 int j;
1268 for (j=0; j<PAGE_SIZE; j++)
1269 if (((char*)data + i * PAGE_SIZE)[j]) {
1270 printk("%lx is not zero!\n", data + i * PAGE_SIZE + j);
1271 exit(1);
1273 #endif
1274 mfns[i] = virtual_to_mfn(data + i * PAGE_SIZE);
1277 printk("sparsing %ldMB at %lx\n", size >> 20, data);
1279 munmap((void *) data, size);
1280 free_physical_pages(mfns, n);
1281 do_map_zero(data, n);
1284 int nice(int inc)
1286 printk("nice() stub called with inc=%d\n", inc);
1287 return 0;
1291 /* Not supported by FS yet. */
1292 unsupported_function_crash(link);
1293 unsupported_function(int, readlink, -1);
1294 unsupported_function_crash(umask);
1296 /* We could support that. */
1297 unsupported_function_log(int, chdir, -1);
1299 /* No dynamic library support. */
1300 unsupported_function_log(void *, dlopen, NULL);
1301 unsupported_function_log(void *, dlsym, NULL);
1302 unsupported_function_log(char *, dlerror, NULL);
1303 unsupported_function_log(int, dlclose, -1);
1305 /* We don't raise signals anyway. */
1306 unsupported_function(int, sigemptyset, -1);
1307 unsupported_function(int, sigfillset, -1);
1308 unsupported_function(int, sigaddset, -1);
1309 unsupported_function(int, sigdelset, -1);
1310 unsupported_function(int, sigismember, -1);
1311 unsupported_function(int, sigprocmask, -1);
1312 unsupported_function(int, sigaction, -1);
1313 unsupported_function(int, __sigsetjmp, 0);
1314 unsupported_function(int, sigaltstack, -1);
1315 unsupported_function_crash(kill);
1317 /* Unsupported */
1318 unsupported_function_crash(pipe);
1319 unsupported_function_crash(fork);
1320 unsupported_function_crash(execv);
1321 unsupported_function_crash(execve);
1322 unsupported_function_crash(waitpid);
1323 unsupported_function_crash(wait);
1324 unsupported_function_crash(lockf);
1325 unsupported_function_crash(sysconf);
1326 unsupported_function(int, tcsetattr, -1);
1327 unsupported_function(int, tcgetattr, 0);
1328 unsupported_function(int, poll, -1);
1330 /* net/if.h */
1331 unsupported_function_log(unsigned int, if_nametoindex, -1);
1332 unsupported_function_log(char *, if_indextoname, (char *) NULL);
1333 unsupported_function_log(struct if_nameindex *, if_nameindex, (struct if_nameindex *) NULL);
1334 unsupported_function_crash(if_freenameindex);
1336 /* Linuxish abi for the Caml runtime, don't support
1337 Log, and return an error code if possible. If it is not possible
1338 to inform the application of an error, then crash instead!
1339 */
1340 unsupported_function_log(struct dirent *, readdir64, NULL);
1341 unsupported_function_log(int, getrusage, -1);
1342 unsupported_function_log(int, getrlimit, -1);
1343 unsupported_function_log(int, getrlimit64, -1);
1344 unsupported_function_log(int, __xstat64, -1);
1345 unsupported_function_log(long, __strtol_internal, LONG_MIN);
1346 unsupported_function_log(double, __strtod_internal, HUGE_VAL);
1347 unsupported_function_log(int, utime, -1);
1348 unsupported_function_log(int, truncate64, -1);
1349 unsupported_function_log(int, tcflow, -1);
1350 unsupported_function_log(int, tcflush, -1);
1351 unsupported_function_log(int, tcdrain, -1);
1352 unsupported_function_log(int, tcsendbreak, -1);
1353 unsupported_function_log(int, cfsetospeed, -1);
1354 unsupported_function_log(int, cfsetispeed, -1);
1355 unsupported_function_crash(cfgetospeed);
1356 unsupported_function_crash(cfgetispeed);
1357 unsupported_function_log(int, symlink, -1);
1358 unsupported_function_log(const char*, inet_ntop, NULL);
1359 unsupported_function_crash(__fxstat64);
1360 unsupported_function_crash(__lxstat64);
1361 unsupported_function_log(int, socketpair, -1);
1362 unsupported_function_crash(sigsuspend);
1363 unsupported_function_log(int, sigpending, -1);
1364 unsupported_function_log(int, shutdown, -1);
1365 unsupported_function_log(int, setuid, -1);
1366 unsupported_function_log(int, setgid, -1);
1367 unsupported_function_crash(rewinddir);
1368 unsupported_function_log(int, getpriority, -1);
1369 unsupported_function_log(int, setpriority, -1);
1370 unsupported_function_log(int, mkfifo, -1);
1371 unsupported_function_log(int, getitimer, -1);
1372 unsupported_function_log(int, setitimer, -1);
1373 unsupported_function_log(void *, getservbyport, NULL);
1374 unsupported_function_log(void *, getservbyname, NULL);
1375 unsupported_function_log(void *, getpwuid, NULL);
1376 unsupported_function_log(void *, getpwnam, NULL);
1377 unsupported_function_log(void *, getprotobynumber, NULL);
1378 unsupported_function_log(void *, getprotobyname, NULL);
1379 unsupported_function_log(int, getpeername, -1);
1380 unsupported_function_log(int, getnameinfo, -1);
1381 unsupported_function_log(char *, getlogin, NULL);
1382 unsupported_function_crash(__h_errno_location);
1383 unsupported_function_log(int, gethostbyname_r, -1);
1384 unsupported_function_log(int, gethostbyaddr_r, -1);
1385 unsupported_function_log(int, getgroups, -1);
1386 unsupported_function_log(void *, getgrgid, NULL);
1387 unsupported_function_log(void *, getgrnam, NULL);
1388 unsupported_function_log(int, getaddrinfo, -1);
1389 unsupported_function_log(int, freeaddrinfo, -1);
1390 unsupported_function_log(int, ftruncate64, -1);
1391 unsupported_function_log(int, fchown, -1);
1392 unsupported_function_log(int, fchmod, -1);
1393 unsupported_function_crash(execvp);
1394 unsupported_function_log(int, dup, -1)
1395 unsupported_function_log(int, chroot, -1)
1396 unsupported_function_log(int, chown, -1);
1397 unsupported_function_log(int, chmod, -1);
1398 unsupported_function_crash(alarm);
1399 unsupported_function_log(int, inet_pton, -1);
1400 unsupported_function_log(int, access, -1);
1401 #endif