ia64/xen-unstable

view extras/mini-os/lib/sys.c @ 19790:01ad2654815a

minios: Use posix_openpt() rather than non-standard openpty().

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