ia64/xen-unstable

view extras/mini-os/lib/sys.c @ 18782:beade55d67fc

minios: add a barebone net/if.h

net/if.h is a standard header but unfortunately lwip doesn't provide
it for any target but linux. Therefore I am adding a net/if.h, with an
empty implementation of the declared functions.

Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Tue Nov 11 11:03:58 2008 +0000 (2008-11-11)
parents 7424f989fe01
children 9c4a38f70b16
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, 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 DEBUG("lwip_select(");
715 dump_set(nfds, &sock_readfds, &sock_writefds, &sock_exceptfds, &timeout);
716 DEBUG("); -> ");
717 sock_n = lwip_select(sock_nfds, &sock_readfds, &sock_writefds, &sock_exceptfds, &timeout);
718 dump_set(nfds, &sock_readfds, &sock_writefds, &sock_exceptfds, &timeout);
719 DEBUG("\n");
720 #endif
722 /* Then see others as well. */
723 for (i = 0; i < nfds; i++) {
724 switch(files[i].type) {
725 default:
726 if (FD_ISSET(i, readfds) || FD_ISSET(i, writefds) || FD_ISSET(i, exceptfds))
727 printk("bogus fd %d in select\n", i);
728 /* Fallthrough. */
729 case FTYPE_FILE:
730 FD_CLR(i, readfds);
731 FD_CLR(i, writefds);
732 FD_CLR(i, exceptfds);
733 break;
734 case FTYPE_CONSOLE:
735 if (FD_ISSET(i, readfds)) {
736 if (xencons_ring_avail())
737 n++;
738 else
739 FD_CLR(i, readfds);
740 }
741 if (FD_ISSET(i, writefds))
742 n++;
743 FD_CLR(i, exceptfds);
744 break;
745 case FTYPE_XENBUS:
746 if (FD_ISSET(i, readfds)) {
747 if (files[i].xenbus.events)
748 n++;
749 else
750 FD_CLR(i, readfds);
751 }
752 FD_CLR(i, writefds);
753 FD_CLR(i, exceptfds);
754 break;
755 case FTYPE_EVTCHN:
756 case FTYPE_TAP:
757 case FTYPE_BLK:
758 case FTYPE_KBD:
759 case FTYPE_FB:
760 if (FD_ISSET(i, readfds)) {
761 if (files[i].read)
762 n++;
763 else
764 FD_CLR(i, readfds);
765 }
766 FD_CLR(i, writefds);
767 FD_CLR(i, exceptfds);
768 break;
769 #ifdef HAVE_LWIP
770 case FTYPE_SOCKET:
771 if (FD_ISSET(i, readfds)) {
772 /* Optimize no-network-packet case. */
773 if (sock_n && FD_ISSET(files[i].socket.fd, &sock_readfds))
774 n++;
775 else
776 FD_CLR(i, readfds);
777 }
778 if (FD_ISSET(i, writefds)) {
779 if (sock_n && FD_ISSET(files[i].socket.fd, &sock_writefds))
780 n++;
781 else
782 FD_CLR(i, writefds);
783 }
784 if (FD_ISSET(i, exceptfds)) {
785 if (sock_n && FD_ISSET(files[i].socket.fd, &sock_exceptfds))
786 n++;
787 else
788 FD_CLR(i, exceptfds);
789 }
790 break;
791 #endif
792 }
793 #ifdef LIBC_VERBOSE
794 if (FD_ISSET(i, readfds))
795 nbread[i]++;
796 if (FD_ISSET(i, writefds))
797 nbwrite[i]++;
798 if (FD_ISSET(i, exceptfds))
799 nbexcept[i]++;
800 #endif
801 }
802 #ifdef LIBC_VERBOSE
803 if (NOW() > lastshown + 1000000000ull) {
804 lastshown = NOW();
805 printk("%lu MB free, ", num_free_pages() / ((1 << 20) / PAGE_SIZE));
806 printk("%d(%d): ", nb, sock_n);
807 for (i = 0; i < nfds; i++) {
808 if (nbread[i] || nbwrite[i] || nbexcept[i])
809 printk(" %d(%c):", i, file_types[files[i].type]);
810 if (nbread[i])
811 printk(" %dR", nbread[i]);
812 if (nbwrite[i])
813 printk(" %dW", nbwrite[i]);
814 if (nbexcept[i])
815 printk(" %dE", nbexcept[i]);
816 }
817 printk("\n");
818 memset(nbread, 0, sizeof(nbread));
819 memset(nbwrite, 0, sizeof(nbwrite));
820 memset(nbexcept, 0, sizeof(nbexcept));
821 nb = 0;
822 }
823 #endif
824 return n;
825 }
827 /* The strategy is to
828 * - announce that we will maybe sleep
829 * - poll a bit ; if successful, return
830 * - if timeout, return
831 * - really sleep (except if somebody woke us in the meanwhile) */
832 int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
833 struct timeval *timeout)
834 {
835 int n, ret;
836 fd_set myread, mywrite, myexcept;
837 struct thread *thread = get_current();
838 s_time_t start = NOW(), stop;
839 DEFINE_WAIT(w1);
840 DEFINE_WAIT(w2);
841 DEFINE_WAIT(w3);
842 DEFINE_WAIT(w4);
843 DEFINE_WAIT(w5);
844 DEFINE_WAIT(w6);
846 assert(thread == main_thread);
848 DEBUG("select(%d, ", nfds);
849 dump_set(nfds, readfds, writefds, exceptfds, timeout);
850 DEBUG(");\n");
852 if (timeout)
853 stop = start + SECONDS(timeout->tv_sec) + timeout->tv_usec * 1000;
854 else
855 /* just make gcc happy */
856 stop = start;
858 /* Tell people we're going to sleep before looking at what they are
859 * saying, hence letting them wake us if events happen between here and
860 * schedule() */
861 add_waiter(w1, netfront_queue);
862 add_waiter(w2, event_queue);
863 add_waiter(w3, blkfront_queue);
864 add_waiter(w4, xenbus_watch_queue);
865 add_waiter(w5, kbdfront_queue);
866 add_waiter(w6, console_queue);
868 if (readfds)
869 myread = *readfds;
870 else
871 FD_ZERO(&myread);
872 if (writefds)
873 mywrite = *writefds;
874 else
875 FD_ZERO(&mywrite);
876 if (exceptfds)
877 myexcept = *exceptfds;
878 else
879 FD_ZERO(&myexcept);
881 DEBUG("polling ");
882 dump_set(nfds, &myread, &mywrite, &myexcept, timeout);
883 DEBUG("\n");
884 n = select_poll(nfds, &myread, &mywrite, &myexcept);
886 if (n) {
887 dump_set(nfds, readfds, writefds, exceptfds, timeout);
888 if (readfds)
889 *readfds = myread;
890 if (writefds)
891 *writefds = mywrite;
892 if (exceptfds)
893 *exceptfds = myexcept;
894 DEBUG(" -> ");
895 dump_set(nfds, readfds, writefds, exceptfds, timeout);
896 DEBUG("\n");
897 wake(thread);
898 ret = n;
899 goto out;
900 }
901 if (timeout && NOW() >= stop) {
902 if (readfds)
903 FD_ZERO(readfds);
904 if (writefds)
905 FD_ZERO(writefds);
906 if (exceptfds)
907 FD_ZERO(exceptfds);
908 timeout->tv_sec = 0;
909 timeout->tv_usec = 0;
910 wake(thread);
911 ret = 0;
912 goto out;
913 }
915 if (timeout)
916 thread->wakeup_time = stop;
917 schedule();
919 if (readfds)
920 myread = *readfds;
921 else
922 FD_ZERO(&myread);
923 if (writefds)
924 mywrite = *writefds;
925 else
926 FD_ZERO(&mywrite);
927 if (exceptfds)
928 myexcept = *exceptfds;
929 else
930 FD_ZERO(&myexcept);
932 n = select_poll(nfds, &myread, &mywrite, &myexcept);
934 if (n) {
935 if (readfds)
936 *readfds = myread;
937 if (writefds)
938 *writefds = mywrite;
939 if (exceptfds)
940 *exceptfds = myexcept;
941 ret = n;
942 goto out;
943 }
944 errno = EINTR;
945 ret = -1;
947 out:
948 remove_waiter(w1);
949 remove_waiter(w2);
950 remove_waiter(w3);
951 remove_waiter(w4);
952 remove_waiter(w5);
953 remove_waiter(w6);
954 return ret;
955 }
957 #ifdef HAVE_LWIP
958 int socket(int domain, int type, int protocol)
959 {
960 int fd, res;
961 fd = lwip_socket(domain, type, protocol);
962 if (fd < 0)
963 return -1;
964 res = alloc_fd(FTYPE_SOCKET);
965 printk("socket -> %d\n", res);
966 files[res].socket.fd = fd;
967 return res;
968 }
970 int accept(int s, struct sockaddr *addr, socklen_t *addrlen)
971 {
972 int fd, res;
973 if (files[s].type != FTYPE_SOCKET) {
974 printk("accept(%d): Bad descriptor\n", s);
975 errno = EBADF;
976 return -1;
977 }
978 fd = lwip_accept(files[s].socket.fd, addr, addrlen);
979 if (fd < 0)
980 return -1;
981 res = alloc_fd(FTYPE_SOCKET);
982 files[res].socket.fd = fd;
983 printk("accepted on %d -> %d\n", s, res);
984 return res;
985 }
987 #define LWIP_STUB(ret, name, proto, args) \
988 ret name proto \
989 { \
990 if (files[s].type != FTYPE_SOCKET) { \
991 printk(#name "(%d): Bad descriptor\n", s); \
992 errno = EBADF; \
993 return -1; \
994 } \
995 s = files[s].socket.fd; \
996 return lwip_##name args; \
997 }
999 LWIP_STUB(int, bind, (int s, struct sockaddr *my_addr, socklen_t addrlen), (s, my_addr, addrlen))
1000 LWIP_STUB(int, getsockopt, (int s, int level, int optname, void *optval, socklen_t *optlen), (s, level, optname, optval, optlen))
1001 LWIP_STUB(int, setsockopt, (int s, int level, int optname, void *optval, socklen_t optlen), (s, level, optname, optval, optlen))
1002 LWIP_STUB(int, connect, (int s, struct sockaddr *serv_addr, socklen_t addrlen), (s, serv_addr, addrlen))
1003 LWIP_STUB(int, listen, (int s, int backlog), (s, backlog));
1004 LWIP_STUB(ssize_t, recv, (int s, void *buf, size_t len, int flags), (s, buf, len, flags))
1005 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))
1006 LWIP_STUB(ssize_t, send, (int s, void *buf, size_t len, int flags), (s, buf, len, flags))
1007 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))
1008 LWIP_STUB(int, getsockname, (int s, struct sockaddr *name, socklen_t *namelen), (s, name, namelen))
1009 #endif
1011 static char *syslog_ident;
1012 void openlog(const char *ident, int option, int facility)
1014 if (syslog_ident)
1015 free(syslog_ident);
1016 syslog_ident = strdup(ident);
1019 void vsyslog(int priority, const char *format, va_list ap)
1021 printk("%s: ", syslog_ident);
1022 print(0, format, ap);
1025 void syslog(int priority, const char *format, ...)
1027 va_list ap;
1028 va_start(ap, format);
1029 vsyslog(priority, format, ap);
1030 va_end(ap);
1033 void closelog(void)
1035 free(syslog_ident);
1036 syslog_ident = NULL;
1039 void vwarn(const char *format, va_list ap)
1041 int the_errno = errno;
1042 printk("stubdom: ");
1043 if (format) {
1044 print(0, format, ap);
1045 printk(", ");
1047 printk("%s", strerror(the_errno));
1050 void warn(const char *format, ...)
1052 va_list ap;
1053 va_start(ap, format);
1054 vwarn(format, ap);
1055 va_end(ap);
1058 void verr(int eval, const char *format, va_list ap)
1060 vwarn(format, ap);
1061 exit(eval);
1064 void err(int eval, const char *format, ...)
1066 va_list ap;
1067 va_start(ap, format);
1068 verr(eval, format, ap);
1069 va_end(ap);
1072 void vwarnx(const char *format, va_list ap)
1074 printk("stubdom: ");
1075 if (format)
1076 print(0, format, ap);
1079 void warnx(const char *format, ...)
1081 va_list ap;
1082 va_start(ap, format);
1083 vwarnx(format, ap);
1084 va_end(ap);
1087 void verrx(int eval, const char *format, va_list ap)
1089 vwarnx(format, ap);
1090 exit(eval);
1093 void errx(int eval, const char *format, ...)
1095 va_list ap;
1096 va_start(ap, format);
1097 verrx(eval, format, ap);
1098 va_end(ap);
1101 int nanosleep(const struct timespec *req, struct timespec *rem)
1103 s_time_t start = NOW();
1104 s_time_t stop = start + SECONDS(req->tv_sec) + req->tv_nsec;
1105 s_time_t stopped;
1106 struct thread *thread = get_current();
1108 thread->wakeup_time = stop;
1109 clear_runnable(thread);
1110 schedule();
1111 stopped = NOW();
1113 if (rem)
1115 s_time_t remaining = stop - stopped;
1116 if (remaining > 0)
1118 rem->tv_nsec = remaining % 1000000000ULL;
1119 rem->tv_sec = remaining / 1000000000ULL;
1120 } else memset(rem, 0, sizeof(*rem));
1123 return 0;
1126 int usleep(useconds_t usec)
1128 /* "usec shall be less than one million." */
1129 struct timespec req;
1130 req.tv_nsec = usec * 1000;
1131 req.tv_sec = 0;
1133 if (nanosleep(&req, NULL))
1134 return -1;
1136 return 0;
1139 unsigned int sleep(unsigned int seconds)
1141 struct timespec req, rem;
1142 req.tv_sec = seconds;
1143 req.tv_nsec = 0;
1145 if (nanosleep(&req, &rem))
1146 return -1;
1148 if (rem.tv_nsec > 0)
1149 rem.tv_sec++;
1151 return rem.tv_sec;
1154 int clock_gettime(clockid_t clk_id, struct timespec *tp)
1156 switch (clk_id) {
1157 case CLOCK_MONOTONIC:
1159 struct timeval tv;
1161 gettimeofday(&tv, NULL);
1163 tp->tv_sec = tv.tv_sec;
1164 tp->tv_nsec = tv.tv_usec * 1000;
1166 break;
1168 case CLOCK_REALTIME:
1170 u64 nsec = monotonic_clock();
1172 tp->tv_sec = nsec / 1000000000ULL;
1173 tp->tv_nsec = nsec % 1000000000ULL;
1175 break;
1177 default:
1178 print_unsupported("clock_gettime(%d)", clk_id);
1179 errno = EINVAL;
1180 return -1;
1183 return 0;
1186 size_t getpagesize(void)
1188 return PAGE_SIZE;
1191 void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset)
1193 unsigned long n = (length + PAGE_SIZE - 1) / PAGE_SIZE;
1195 ASSERT(!start);
1196 ASSERT(prot == (PROT_READ|PROT_WRITE));
1197 ASSERT((fd == -1 && (flags == (MAP_SHARED|MAP_ANON) || flags == (MAP_PRIVATE|MAP_ANON)))
1198 || (fd != -1 && flags == MAP_SHARED));
1199 ASSERT(offset == 0);
1201 if (fd == -1)
1202 return map_zero(n, 1);
1203 else if (files[fd].type == FTYPE_XC) {
1204 unsigned long zero = 0;
1205 return map_frames_ex(&zero, n, 0, 0, 1, DOMID_SELF, 0, 0);
1206 } else ASSERT(0);
1209 #define UNMAP_BATCH ((STACK_SIZE / 2) / sizeof(multicall_entry_t))
1210 int munmap(void *start, size_t length)
1212 int total = length / PAGE_SIZE;
1213 ASSERT(!((unsigned long)start & ~PAGE_MASK));
1214 while (total) {
1215 int n = UNMAP_BATCH;
1216 if (n > total)
1217 n = total;
1219 int i;
1220 multicall_entry_t call[n];
1221 unsigned char (*data)[PAGE_SIZE] = start;
1222 int ret;
1224 for (i = 0; i < n; i++) {
1225 int arg = 0;
1226 call[i].op = __HYPERVISOR_update_va_mapping;
1227 call[i].args[arg++] = (unsigned long) &data[i];
1228 call[i].args[arg++] = 0;
1229 #ifdef __i386__
1230 call[i].args[arg++] = 0;
1231 #endif
1232 call[i].args[arg++] = UVMF_INVLPG;
1235 ret = HYPERVISOR_multicall(call, n);
1236 if (ret) {
1237 errno = -ret;
1238 return -1;
1241 for (i = 0; i < n; i++) {
1242 if (call[i].result) {
1243 errno = call[i].result;
1244 return -1;
1248 start = (char *)start + n * PAGE_SIZE;
1249 total -= n;
1251 return 0;
1254 void sparse(unsigned long data, size_t size)
1256 unsigned long newdata;
1257 xen_pfn_t *mfns;
1258 int i, n;
1260 newdata = (data + PAGE_SIZE - 1) & PAGE_MASK;
1261 if (newdata - data > size)
1262 return;
1263 size -= newdata - data;
1264 data = newdata;
1265 n = size / PAGE_SIZE;
1266 size = n * PAGE_SIZE;
1268 mfns = malloc(n * sizeof(*mfns));
1269 for (i = 0; i < n; i++) {
1270 #ifdef LIBC_DEBUG
1271 int j;
1272 for (j=0; j<PAGE_SIZE; j++)
1273 if (((char*)data + i * PAGE_SIZE)[j]) {
1274 printk("%lx is not zero!\n", data + i * PAGE_SIZE + j);
1275 exit(1);
1277 #endif
1278 mfns[i] = virtual_to_mfn(data + i * PAGE_SIZE);
1281 printk("sparsing %ldMB at %lx\n", size >> 20, data);
1283 munmap((void *) data, size);
1284 free_physical_pages(mfns, n);
1285 do_map_zero(data, n);
1289 /* Not supported by FS yet. */
1290 unsupported_function_crash(link);
1291 unsupported_function(int, readlink, -1);
1292 unsupported_function_crash(umask);
1294 /* We could support that. */
1295 unsupported_function_log(int, chdir, -1);
1297 /* No dynamic library support. */
1298 unsupported_function_log(void *, dlopen, NULL);
1299 unsupported_function_log(void *, dlsym, NULL);
1300 unsupported_function_log(char *, dlerror, NULL);
1301 unsupported_function_log(int, dlclose, -1);
1303 /* We don't raise signals anyway. */
1304 unsupported_function(int, sigemptyset, -1);
1305 unsupported_function(int, sigfillset, -1);
1306 unsupported_function(int, sigaddset, -1);
1307 unsupported_function(int, sigdelset, -1);
1308 unsupported_function(int, sigismember, -1);
1309 unsupported_function(int, sigprocmask, -1);
1310 unsupported_function(int, sigaction, -1);
1311 unsupported_function(int, __sigsetjmp, 0);
1312 unsupported_function(int, sigaltstack, -1);
1313 unsupported_function_crash(kill);
1315 /* Unsupported */
1316 unsupported_function_crash(pipe);
1317 unsupported_function_crash(fork);
1318 unsupported_function_crash(execv);
1319 unsupported_function_crash(execve);
1320 unsupported_function_crash(waitpid);
1321 unsupported_function_crash(wait);
1322 unsupported_function_crash(lockf);
1323 unsupported_function_crash(sysconf);
1324 unsupported_function(int, tcsetattr, -1);
1325 unsupported_function(int, tcgetattr, 0);
1326 unsupported_function(int, poll, -1);
1328 /* net/if.h */
1329 unsupported_function_log(unsigned int, if_nametoindex, -1);
1330 unsupported_function_log(char *, if_indextoname, (char *) NULL);
1331 unsupported_function_log(struct if_nameindex *, if_nameindex, (struct if_nameindex *) NULL);
1332 unsupported_function_crash(if_freenameindex);
1334 /* Linuxish abi for the Caml runtime, don't support */
1335 unsupported_function_log(struct dirent *, readdir64, NULL);
1336 unsupported_function_log(int, getrusage, -1);
1337 unsupported_function_log(int, getrlimit, -1);
1338 unsupported_function_log(int, getrlimit64, -1);
1339 unsupported_function_log(int, __xstat64, -1);
1340 unsupported_function_log(long, __strtol_internal, LONG_MIN);
1341 unsupported_function_log(double, __strtod_internal, HUGE_VAL);
1342 #endif