ia64/xen-unstable

view extras/mini-os/lib/sys.c @ 18378:79d168323727

stubdom: add syslog functions

Signed-off-by: Samuel Thibault <samuel.thibault@eu.citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Wed Aug 27 09:45:42 2008 +0100 (2008-08-27)
parents 26afc8557f9f
children 846590f85062
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 <time.h>
38 #include <errno.h>
39 #include <fcntl.h>
40 #include <pthread.h>
41 #include <assert.h>
42 #include <dirent.h>
43 #include <stdlib.h>
44 #include <math.h>
46 #ifdef HAVE_LWIP
47 #include <lwip/sockets.h>
48 #endif
49 #include <fs.h>
51 #define debug(fmt, ...) \
53 #define print_unsupported(fmt, ...) \
54 printk("Unsupported function "fmt" called in Mini-OS kernel\n", ## __VA_ARGS__);
56 /* Crash on function call */
57 #define unsupported_function_crash(function) \
58 int __unsup_##function(void) asm(#function); \
59 int __unsup_##function(void) \
60 { \
61 print_unsupported(#function); \
62 do_exit(); \
63 }
65 /* Log and err out on function call */
66 #define unsupported_function_log(type, function, ret) \
67 type __unsup_##function(void) asm(#function); \
68 type __unsup_##function(void) \
69 { \
70 print_unsupported(#function); \
71 errno = ENOSYS; \
72 return ret; \
73 }
75 /* Err out on function call */
76 #define unsupported_function(type, function, ret) \
77 type __unsup_##function(void) asm(#function); \
78 type __unsup_##function(void) \
79 { \
80 errno = ENOSYS; \
81 return ret; \
82 }
84 #define NOFILE 32
85 extern int xc_evtchn_close(int fd);
86 extern int xc_interface_close(int fd);
87 extern int xc_gnttab_close(int fd);
89 pthread_mutex_t fd_lock = PTHREAD_MUTEX_INITIALIZER;
90 struct file files[NOFILE] = {
91 { .type = FTYPE_CONSOLE }, /* stdin */
92 { .type = FTYPE_CONSOLE }, /* stdout */
93 { .type = FTYPE_CONSOLE }, /* stderr */
94 };
96 DECLARE_WAIT_QUEUE_HEAD(event_queue);
98 int alloc_fd(enum fd_type type)
99 {
100 int i;
101 pthread_mutex_lock(&fd_lock);
102 for (i=0; i<NOFILE; i++) {
103 if (files[i].type == FTYPE_NONE) {
104 files[i].type = type;
105 pthread_mutex_unlock(&fd_lock);
106 return i;
107 }
108 }
109 pthread_mutex_unlock(&fd_lock);
110 printk("Too many opened files\n");
111 do_exit();
112 }
114 void close_all_files(void)
115 {
116 int i;
117 pthread_mutex_lock(&fd_lock);
118 for (i=NOFILE - 1; i > 0; i--)
119 if (files[i].type != FTYPE_NONE)
120 close(i);
121 pthread_mutex_unlock(&fd_lock);
122 }
124 int dup2(int oldfd, int newfd)
125 {
126 pthread_mutex_lock(&fd_lock);
127 if (files[newfd].type != FTYPE_NONE)
128 close(newfd);
129 // XXX: this is a bit bogus, as we are supposed to share the offset etc
130 files[newfd] = files[oldfd];
131 pthread_mutex_unlock(&fd_lock);
132 return 0;
133 }
135 pid_t getpid(void)
136 {
137 return 1;
138 }
140 pid_t getppid(void)
141 {
142 return 1;
143 }
145 pid_t setsid(void)
146 {
147 return 1;
148 }
150 char *getcwd(char *buf, size_t size)
151 {
152 snprintf(buf, size, "/");
153 return buf;
154 }
156 #define LOG_PATH "/var/log/"
158 int mkdir(const char *pathname, mode_t mode)
159 {
160 int ret;
161 ret = fs_create(fs_import, (char *) pathname, 1, mode);
162 if (ret < 0) {
163 errno = EIO;
164 return -1;
165 }
166 return 0;
167 }
169 int open(const char *pathname, int flags, ...)
170 {
171 int fs_fd, fd;
172 /* Ugly, but fine. */
173 if (!strncmp(pathname,LOG_PATH,strlen(LOG_PATH))) {
174 fd = alloc_fd(FTYPE_CONSOLE);
175 printk("open(%s) -> %d\n", pathname, fd);
176 return fd;
177 }
178 printk("open(%s, %x)", pathname, flags);
179 switch (flags & ~O_ACCMODE) {
180 case 0:
181 fs_fd = fs_open(fs_import, (void *) pathname);
182 break;
183 case O_CREAT|O_TRUNC:
184 {
185 va_list ap;
186 mode_t mode;
187 va_start(ap, flags);
188 mode = va_arg(ap, mode_t);
189 va_end(ap);
190 fs_fd = fs_create(fs_import, (void *) pathname, 0, mode);
191 break;
192 }
193 default:
194 printk(" unsupported flags\n");
195 do_exit();
196 }
197 if (fs_fd < 0) {
198 errno = EIO;
199 return -1;
200 }
201 fd = alloc_fd(FTYPE_FILE);
202 printk("-> %d\n", fd);
203 files[fd].file.fd = fs_fd;
204 files[fd].file.offset = 0;
205 return fd;
206 }
208 int isatty(int fd)
209 {
210 return files[fd].type == FTYPE_CONSOLE;
211 }
213 int read(int fd, void *buf, size_t nbytes)
214 {
215 switch (files[fd].type) {
216 case FTYPE_CONSOLE: {
217 int ret;
218 DEFINE_WAIT(w);
219 while(1) {
220 add_waiter(w, console_queue);
221 ret = xencons_ring_recv(buf, nbytes);
222 if (ret)
223 break;
224 schedule();
225 }
226 remove_waiter(w);
227 return ret;
228 }
229 case FTYPE_FILE: {
230 ssize_t ret;
231 if (nbytes > PAGE_SIZE * FSIF_NR_READ_GNTS)
232 nbytes = PAGE_SIZE * FSIF_NR_READ_GNTS;
233 ret = fs_read(fs_import, files[fd].file.fd, buf, nbytes, files[fd].file.offset);
234 if (ret > 0) {
235 files[fd].file.offset += ret;
236 return ret;
237 } else if (ret < 0) {
238 errno = EIO;
239 return -1;
240 }
241 return 0;
242 }
243 #ifdef HAVE_LWIP
244 case FTYPE_SOCKET:
245 return lwip_read(files[fd].socket.fd, buf, nbytes);
246 #endif
247 case FTYPE_TAP: {
248 ssize_t ret;
249 ret = netfront_receive(files[fd].tap.dev, buf, nbytes);
250 if (ret <= 0) {
251 errno = EAGAIN;
252 return -1;
253 }
254 return ret;
255 }
256 case FTYPE_KBD: {
257 int ret, n;
258 n = nbytes / sizeof(union xenkbd_in_event);
259 ret = kbdfront_receive(files[fd].kbd.dev, buf, n);
260 if (ret <= 0) {
261 errno = EAGAIN;
262 return -1;
263 }
264 return ret * sizeof(union xenkbd_in_event);
265 }
266 case FTYPE_FB: {
267 int ret, n;
268 n = nbytes / sizeof(union xenfb_in_event);
269 ret = fbfront_receive(files[fd].fb.dev, buf, n);
270 if (ret <= 0) {
271 errno = EAGAIN;
272 return -1;
273 }
274 return ret * sizeof(union xenfb_in_event);
275 }
276 default:
277 break;
278 }
279 printk("read(%d): Bad descriptor\n", fd);
280 errno = EBADF;
281 return -1;
282 }
284 int write(int fd, const void *buf, size_t nbytes)
285 {
286 switch (files[fd].type) {
287 case FTYPE_CONSOLE:
288 console_print((char *)buf, nbytes);
289 return nbytes;
290 case FTYPE_FILE: {
291 ssize_t ret;
292 if (nbytes > PAGE_SIZE * FSIF_NR_WRITE_GNTS)
293 nbytes = PAGE_SIZE * FSIF_NR_WRITE_GNTS;
294 ret = fs_write(fs_import, files[fd].file.fd, (void *) buf, nbytes, files[fd].file.offset);
295 if (ret > 0) {
296 files[fd].file.offset += ret;
297 return ret;
298 } else if (ret < 0) {
299 errno = EIO;
300 return -1;
301 }
302 return 0;
303 }
304 #ifdef HAVE_LWIP
305 case FTYPE_SOCKET:
306 return lwip_write(files[fd].socket.fd, (void*) buf, nbytes);
307 #endif
308 case FTYPE_TAP:
309 netfront_xmit(files[fd].tap.dev, (void*) buf, nbytes);
310 return nbytes;
311 default:
312 break;
313 }
314 printk("write(%d): Bad descriptor\n", fd);
315 errno = EBADF;
316 return -1;
317 }
319 off_t lseek(int fd, off_t offset, int whence)
320 {
321 if (files[fd].type != FTYPE_FILE) {
322 errno = ESPIPE;
323 return (off_t) -1;
324 }
325 switch (whence) {
326 case SEEK_SET:
327 files[fd].file.offset = offset;
328 break;
329 case SEEK_CUR:
330 files[fd].file.offset += offset;
331 break;
332 case SEEK_END: {
333 struct stat st;
334 int ret;
335 ret = fstat(fd, &st);
336 if (ret)
337 return -1;
338 files[fd].file.offset = st.st_size + offset;
339 break;
340 }
341 default:
342 errno = EINVAL;
343 return -1;
344 }
345 return files[fd].file.offset;
346 }
348 int fsync(int fd) {
349 switch (files[fd].type) {
350 case FTYPE_FILE: {
351 int ret;
352 ret = fs_sync(fs_import, files[fd].file.fd);
353 if (ret < 0) {
354 errno = EIO;
355 return -1;
356 }
357 return 0;
358 }
359 default:
360 break;
361 }
362 printk("fsync(%d): Bad descriptor\n", fd);
363 errno = EBADF;
364 return -1;
365 }
367 int close(int fd)
368 {
369 printk("close(%d)\n", fd);
370 switch (files[fd].type) {
371 default:
372 files[fd].type = FTYPE_NONE;
373 return 0;
374 case FTYPE_FILE: {
375 int ret = fs_close(fs_import, files[fd].file.fd);
376 files[fd].type = FTYPE_NONE;
377 if (ret < 0) {
378 errno = EIO;
379 return -1;
380 }
381 return 0;
382 }
383 case FTYPE_XENBUS:
384 xs_daemon_close((void*)(intptr_t) fd);
385 return 0;
386 #ifdef HAVE_LWIP
387 case FTYPE_SOCKET: {
388 int res = lwip_close(files[fd].socket.fd);
389 files[fd].type = FTYPE_NONE;
390 return res;
391 }
392 #endif
393 case FTYPE_XC:
394 xc_interface_close(fd);
395 return 0;
396 case FTYPE_EVTCHN:
397 xc_evtchn_close(fd);
398 return 0;
399 case FTYPE_GNTMAP:
400 xc_gnttab_close(fd);
401 return 0;
402 case FTYPE_TAP:
403 shutdown_netfront(files[fd].tap.dev);
404 files[fd].type = FTYPE_NONE;
405 return 0;
406 case FTYPE_BLK:
407 shutdown_blkfront(files[fd].blk.dev);
408 files[fd].type = FTYPE_NONE;
409 return 0;
410 case FTYPE_KBD:
411 shutdown_kbdfront(files[fd].kbd.dev);
412 files[fd].type = FTYPE_NONE;
413 return 0;
414 case FTYPE_FB:
415 shutdown_fbfront(files[fd].fb.dev);
416 files[fd].type = FTYPE_NONE;
417 return 0;
418 case FTYPE_NONE:
419 break;
420 }
421 printk("close(%d): Bad descriptor\n", fd);
422 errno = EBADF;
423 return -1;
424 }
426 static void init_stat(struct stat *buf)
427 {
428 memset(buf, 0, sizeof(*buf));
429 buf->st_dev = 0;
430 buf->st_ino = 0;
431 buf->st_nlink = 1;
432 buf->st_rdev = 0;
433 buf->st_blksize = 4096;
434 buf->st_blocks = 0;
435 }
437 static void stat_from_fs(struct stat *buf, struct fsif_stat_response *stat)
438 {
439 buf->st_mode = stat->stat_mode;
440 buf->st_uid = stat->stat_uid;
441 buf->st_gid = stat->stat_gid;
442 buf->st_size = stat->stat_size;
443 buf->st_atime = stat->stat_atime;
444 buf->st_mtime = stat->stat_mtime;
445 buf->st_ctime = stat->stat_ctime;
446 }
448 int stat(const char *path, struct stat *buf)
449 {
450 struct fsif_stat_response stat;
451 int ret;
452 int fs_fd;
453 printk("stat(%s)\n", path);
454 fs_fd = fs_open(fs_import, (char*) path);
455 if (fs_fd < 0) {
456 errno = EIO;
457 ret = -1;
458 goto out;
459 }
460 ret = fs_stat(fs_import, fs_fd, &stat);
461 if (ret < 0) {
462 errno = EIO;
463 ret = -1;
464 goto outfd;
465 }
466 init_stat(buf);
467 stat_from_fs(buf, &stat);
468 ret = 0;
470 outfd:
471 fs_close(fs_import, fs_fd);
472 out:
473 return ret;
474 }
476 int fstat(int fd, struct stat *buf)
477 {
478 init_stat(buf);
479 switch (files[fd].type) {
480 case FTYPE_CONSOLE:
481 case FTYPE_SOCKET: {
482 buf->st_mode = (files[fd].type == FTYPE_CONSOLE?S_IFCHR:S_IFSOCK) | S_IRUSR|S_IWUSR;
483 buf->st_uid = 0;
484 buf->st_gid = 0;
485 buf->st_size = 0;
486 buf->st_atime =
487 buf->st_mtime =
488 buf->st_ctime = time(NULL);
489 return 0;
490 }
491 case FTYPE_FILE: {
492 struct fsif_stat_response stat;
493 int ret;
494 ret = fs_stat(fs_import, files[fd].file.fd, &stat);
495 if (ret < 0) {
496 errno = EIO;
497 return -1;
498 }
499 /* The protocol is a bit evasive about this value */
500 stat_from_fs(buf, &stat);
501 return 0;
502 }
503 default:
504 break;
505 }
507 printk("statf(%d): Bad descriptor\n", fd);
508 errno = EBADF;
509 return -1;
510 }
512 int ftruncate(int fd, off_t length)
513 {
514 switch (files[fd].type) {
515 case FTYPE_FILE: {
516 int ret;
517 ret = fs_truncate(fs_import, files[fd].file.fd, length);
518 if (ret < 0) {
519 errno = EIO;
520 return -1;
521 }
522 return 0;
523 }
524 default:
525 break;
526 }
528 printk("ftruncate(%d): Bad descriptor\n", fd);
529 errno = EBADF;
530 return -1;
531 }
533 int remove(const char *pathname)
534 {
535 int ret;
536 printk("remove(%s)", pathname);
537 ret = fs_remove(fs_import, (char*) pathname);
538 if (ret < 0) {
539 errno = EIO;
540 return -1;
541 }
542 return 0;
543 }
545 int unlink(const char *pathname)
546 {
547 return remove(pathname);
548 }
550 int rmdir(const char *pathname)
551 {
552 return remove(pathname);
553 }
555 int fcntl(int fd, int cmd, ...)
556 {
557 long arg;
558 va_list ap;
559 va_start(ap, cmd);
560 arg = va_arg(ap, long);
561 va_end(ap);
563 switch (cmd) {
564 #ifdef HAVE_LWIP
565 case F_SETFL:
566 if (files[fd].type == FTYPE_SOCKET && !(arg & ~O_NONBLOCK)) {
567 /* Only flag supported: non-blocking mode */
568 uint32_t nblock = !!(arg & O_NONBLOCK);
569 return lwip_ioctl(files[fd].socket.fd, FIONBIO, &nblock);
570 }
571 /* Fallthrough */
572 #endif
573 default:
574 printk("fcntl(%d, %d, %lx/%lo)\n", fd, cmd, arg, arg);
575 errno = ENOSYS;
576 return -1;
577 }
578 }
580 DIR *opendir(const char *name)
581 {
582 DIR *ret;
583 ret = malloc(sizeof(*ret));
584 ret->name = strdup(name);
585 ret->offset = 0;
586 ret->entries = NULL;
587 ret->curentry = -1;
588 ret->nbentries = 0;
589 ret->has_more = 1;
590 return ret;
591 }
593 struct dirent *readdir(DIR *dir)
594 {
595 if (dir->curentry >= 0) {
596 free(dir->entries[dir->curentry]);
597 dir->entries[dir->curentry] = NULL;
598 }
599 dir->curentry++;
600 if (dir->curentry >= dir->nbentries) {
601 dir->offset += dir->nbentries;
602 free(dir->entries);
603 dir->curentry = -1;
604 dir->nbentries = 0;
605 if (!dir->has_more)
606 return NULL;
607 dir->entries = fs_list(fs_import, dir->name, dir->offset, &dir->nbentries, &dir->has_more);
608 if (!dir->entries || !dir->nbentries)
609 return NULL;
610 dir->curentry = 0;
611 }
612 dir->dirent.d_name = dir->entries[dir->curentry];
613 return &dir->dirent;
614 }
615 int closedir(DIR *dir)
616 {
617 int i;
618 for (i=0; i<dir->nbentries; i++)
619 free(dir->entries[i]);
620 free(dir->entries);
621 free(dir->name);
622 free(dir);
623 return 0;
624 }
626 /* We assume that only the main thread calls select(). */
628 static const char file_types[] = {
629 [FTYPE_NONE] = 'N',
630 [FTYPE_CONSOLE] = 'C',
631 [FTYPE_FILE] = 'F',
632 [FTYPE_XENBUS] = 'S',
633 [FTYPE_XC] = 'X',
634 [FTYPE_EVTCHN] = 'E',
635 [FTYPE_SOCKET] = 's',
636 [FTYPE_TAP] = 'T',
637 [FTYPE_BLK] = 'B',
638 [FTYPE_KBD] = 'K',
639 [FTYPE_FB] = 'G',
640 };
641 #ifdef LIBC_DEBUG
642 static void dump_set(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout)
643 {
644 int i, comma;
645 #define printfds(set) do {\
646 comma = 0; \
647 for (i = 0; i < nfds; i++) { \
648 if (FD_ISSET(i, set)) { \
649 if (comma) \
650 printk(", "); \
651 printk("%d(%c)", i, file_types[files[i].type]); \
652 comma = 1; \
653 } \
654 } \
655 } while (0)
657 printk("[");
658 if (readfds)
659 printfds(readfds);
660 printk("], [");
661 if (writefds)
662 printfds(writefds);
663 printk("], [");
664 if (exceptfds)
665 printfds(exceptfds);
666 printk("], ");
667 if (timeout)
668 printk("{ %ld, %ld }", timeout->tv_sec, timeout->tv_usec);
669 }
670 #else
671 #define dump_set(nfds, readfds, writefds, exceptfds, timeout)
672 #endif
674 /* Just poll without blocking */
675 static int select_poll(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds)
676 {
677 int i, n = 0;
678 #ifdef HAVE_LWIP
679 int sock_n, sock_nfds = 0;
680 fd_set sock_readfds, sock_writefds, sock_exceptfds;
681 struct timeval timeout = { .tv_sec = 0, .tv_usec = 0};
682 #endif
684 #ifdef LIBC_VERBOSE
685 static int nb;
686 static int nbread[NOFILE], nbwrite[NOFILE], nbexcept[NOFILE];
687 static s_time_t lastshown;
689 nb++;
690 #endif
692 #ifdef HAVE_LWIP
693 /* first poll network */
694 FD_ZERO(&sock_readfds);
695 FD_ZERO(&sock_writefds);
696 FD_ZERO(&sock_exceptfds);
697 for (i = 0; i < nfds; i++) {
698 if (files[i].type == FTYPE_SOCKET) {
699 if (FD_ISSET(i, readfds)) {
700 FD_SET(files[i].socket.fd, &sock_readfds);
701 sock_nfds = i+1;
702 }
703 if (FD_ISSET(i, writefds)) {
704 FD_SET(files[i].socket.fd, &sock_writefds);
705 sock_nfds = i+1;
706 }
707 if (FD_ISSET(i, exceptfds)) {
708 FD_SET(files[i].socket.fd, &sock_exceptfds);
709 sock_nfds = i+1;
710 }
711 }
712 }
713 DEBUG("lwip_select(");
714 dump_set(nfds, &sock_readfds, &sock_writefds, &sock_exceptfds, &timeout);
715 DEBUG("); -> ");
716 sock_n = lwip_select(sock_nfds, &sock_readfds, &sock_writefds, &sock_exceptfds, &timeout);
717 dump_set(nfds, &sock_readfds, &sock_writefds, &sock_exceptfds, &timeout);
718 DEBUG("\n");
719 #endif
721 /* Then see others as well. */
722 for (i = 0; i < nfds; i++) {
723 switch(files[i].type) {
724 default:
725 if (FD_ISSET(i, readfds) || FD_ISSET(i, writefds) || FD_ISSET(i, exceptfds))
726 printk("bogus fd %d in select\n", i);
727 /* Fallthrough. */
728 case FTYPE_FILE:
729 FD_CLR(i, readfds);
730 FD_CLR(i, writefds);
731 FD_CLR(i, exceptfds);
732 break;
733 case FTYPE_CONSOLE:
734 if (FD_ISSET(i, readfds)) {
735 if (xencons_ring_avail())
736 n++;
737 else
738 FD_CLR(i, readfds);
739 }
740 if (FD_ISSET(i, writefds))
741 n++;
742 FD_CLR(i, exceptfds);
743 break;
744 case FTYPE_XENBUS:
745 if (FD_ISSET(i, readfds)) {
746 if (files[i].xenbus.events)
747 n++;
748 else
749 FD_CLR(i, readfds);
750 }
751 FD_CLR(i, writefds);
752 FD_CLR(i, exceptfds);
753 break;
754 case FTYPE_EVTCHN:
755 case FTYPE_TAP:
756 case FTYPE_BLK:
757 case FTYPE_KBD:
758 case FTYPE_FB:
759 if (FD_ISSET(i, readfds)) {
760 if (files[i].read)
761 n++;
762 else
763 FD_CLR(i, readfds);
764 }
765 FD_CLR(i, writefds);
766 FD_CLR(i, exceptfds);
767 break;
768 #ifdef HAVE_LWIP
769 case FTYPE_SOCKET:
770 if (FD_ISSET(i, readfds)) {
771 /* Optimize no-network-packet case. */
772 if (sock_n && FD_ISSET(files[i].socket.fd, &sock_readfds))
773 n++;
774 else
775 FD_CLR(i, readfds);
776 }
777 if (FD_ISSET(i, writefds)) {
778 if (sock_n && FD_ISSET(files[i].socket.fd, &sock_writefds))
779 n++;
780 else
781 FD_CLR(i, writefds);
782 }
783 if (FD_ISSET(i, exceptfds)) {
784 if (sock_n && FD_ISSET(files[i].socket.fd, &sock_exceptfds))
785 n++;
786 else
787 FD_CLR(i, exceptfds);
788 }
789 break;
790 #endif
791 }
792 #ifdef LIBC_VERBOSE
793 if (FD_ISSET(i, readfds))
794 nbread[i]++;
795 if (FD_ISSET(i, writefds))
796 nbwrite[i]++;
797 if (FD_ISSET(i, exceptfds))
798 nbexcept[i]++;
799 #endif
800 }
801 #ifdef LIBC_VERBOSE
802 if (NOW() > lastshown + 1000000000ull) {
803 lastshown = NOW();
804 printk("%lu MB free, ", num_free_pages() / ((1 << 20) / PAGE_SIZE));
805 printk("%d(%d): ", nb, sock_n);
806 for (i = 0; i < nfds; i++) {
807 if (nbread[i] || nbwrite[i] || nbexcept[i])
808 printk(" %d(%c):", i, file_types[files[i].type]);
809 if (nbread[i])
810 printk(" %dR", nbread[i]);
811 if (nbwrite[i])
812 printk(" %dW", nbwrite[i]);
813 if (nbexcept[i])
814 printk(" %dE", nbexcept[i]);
815 }
816 printk("\n");
817 memset(nbread, 0, sizeof(nbread));
818 memset(nbwrite, 0, sizeof(nbwrite));
819 memset(nbexcept, 0, sizeof(nbexcept));
820 nb = 0;
821 }
822 #endif
823 return n;
824 }
826 /* The strategy is to
827 * - announce that we will maybe sleep
828 * - poll a bit ; if successful, return
829 * - if timeout, return
830 * - really sleep (except if somebody woke us in the meanwhile) */
831 int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
832 struct timeval *timeout)
833 {
834 int n, ret;
835 fd_set myread, mywrite, myexcept;
836 struct thread *thread = get_current();
837 s_time_t start = NOW(), stop;
838 DEFINE_WAIT(w1);
839 DEFINE_WAIT(w2);
840 DEFINE_WAIT(w3);
841 DEFINE_WAIT(w4);
842 DEFINE_WAIT(w5);
843 DEFINE_WAIT(w6);
845 assert(thread == main_thread);
847 DEBUG("select(%d, ", nfds);
848 dump_set(nfds, readfds, writefds, exceptfds, timeout);
849 DEBUG(");\n");
851 if (timeout)
852 stop = start + SECONDS(timeout->tv_sec) + timeout->tv_usec * 1000;
853 else
854 /* just make gcc happy */
855 stop = start;
857 /* Tell people we're going to sleep before looking at what they are
858 * saying, hence letting them wake us if events happen between here and
859 * schedule() */
860 add_waiter(w1, netfront_queue);
861 add_waiter(w2, event_queue);
862 add_waiter(w3, blkfront_queue);
863 add_waiter(w4, xenbus_watch_queue);
864 add_waiter(w5, kbdfront_queue);
865 add_waiter(w6, console_queue);
867 if (readfds)
868 myread = *readfds;
869 else
870 FD_ZERO(&myread);
871 if (writefds)
872 mywrite = *writefds;
873 else
874 FD_ZERO(&mywrite);
875 if (exceptfds)
876 myexcept = *exceptfds;
877 else
878 FD_ZERO(&myexcept);
880 DEBUG("polling ");
881 dump_set(nfds, &myread, &mywrite, &myexcept, timeout);
882 DEBUG("\n");
883 n = select_poll(nfds, &myread, &mywrite, &myexcept);
885 if (n) {
886 dump_set(nfds, readfds, writefds, exceptfds, timeout);
887 if (readfds)
888 *readfds = myread;
889 if (writefds)
890 *writefds = mywrite;
891 if (exceptfds)
892 *exceptfds = myexcept;
893 DEBUG(" -> ");
894 dump_set(nfds, readfds, writefds, exceptfds, timeout);
895 DEBUG("\n");
896 wake(thread);
897 ret = n;
898 goto out;
899 }
900 if (timeout && NOW() >= stop) {
901 if (readfds)
902 FD_ZERO(readfds);
903 if (writefds)
904 FD_ZERO(writefds);
905 if (exceptfds)
906 FD_ZERO(exceptfds);
907 timeout->tv_sec = 0;
908 timeout->tv_usec = 0;
909 wake(thread);
910 ret = 0;
911 goto out;
912 }
914 if (timeout)
915 thread->wakeup_time = stop;
916 schedule();
918 if (readfds)
919 myread = *readfds;
920 else
921 FD_ZERO(&myread);
922 if (writefds)
923 mywrite = *writefds;
924 else
925 FD_ZERO(&mywrite);
926 if (exceptfds)
927 myexcept = *exceptfds;
928 else
929 FD_ZERO(&myexcept);
931 n = select_poll(nfds, &myread, &mywrite, &myexcept);
933 if (n) {
934 if (readfds)
935 *readfds = myread;
936 if (writefds)
937 *writefds = mywrite;
938 if (exceptfds)
939 *exceptfds = myexcept;
940 ret = n;
941 goto out;
942 }
943 errno = EINTR;
944 ret = -1;
946 out:
947 remove_waiter(w1);
948 remove_waiter(w2);
949 remove_waiter(w3);
950 remove_waiter(w4);
951 remove_waiter(w5);
952 remove_waiter(w6);
953 return ret;
954 }
956 #ifdef HAVE_LWIP
957 int socket(int domain, int type, int protocol)
958 {
959 int fd, res;
960 fd = lwip_socket(domain, type, protocol);
961 if (fd < 0)
962 return -1;
963 res = alloc_fd(FTYPE_SOCKET);
964 printk("socket -> %d\n", res);
965 files[res].socket.fd = fd;
966 return res;
967 }
969 int accept(int s, struct sockaddr *addr, socklen_t *addrlen)
970 {
971 int fd, res;
972 if (files[s].type != FTYPE_SOCKET) {
973 printk("accept(%d): Bad descriptor\n", s);
974 errno = EBADF;
975 return -1;
976 }
977 fd = lwip_accept(files[s].socket.fd, addr, addrlen);
978 if (fd < 0)
979 return -1;
980 res = alloc_fd(FTYPE_SOCKET);
981 files[res].socket.fd = fd;
982 printk("accepted on %d -> %d\n", s, res);
983 return res;
984 }
986 #define LWIP_STUB(ret, name, proto, args) \
987 ret name proto \
988 { \
989 if (files[s].type != FTYPE_SOCKET) { \
990 printk(#name "(%d): Bad descriptor\n", s); \
991 errno = EBADF; \
992 return -1; \
993 } \
994 s = files[s].socket.fd; \
995 return lwip_##name args; \
996 }
998 LWIP_STUB(int, bind, (int s, struct sockaddr *my_addr, socklen_t addrlen), (s, my_addr, addrlen))
999 LWIP_STUB(int, getsockopt, (int s, int level, int optname, void *optval, socklen_t *optlen), (s, level, optname, optval, optlen))
1000 LWIP_STUB(int, setsockopt, (int s, int level, int optname, void *optval, socklen_t optlen), (s, level, optname, optval, optlen))
1001 LWIP_STUB(int, connect, (int s, struct sockaddr *serv_addr, socklen_t addrlen), (s, serv_addr, addrlen))
1002 LWIP_STUB(int, listen, (int s, int backlog), (s, backlog));
1003 LWIP_STUB(ssize_t, recv, (int s, void *buf, size_t len, int flags), (s, buf, len, flags))
1004 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))
1005 LWIP_STUB(ssize_t, send, (int s, void *buf, size_t len, int flags), (s, buf, len, flags))
1006 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))
1007 LWIP_STUB(int, getsockname, (int s, struct sockaddr *name, socklen_t *namelen), (s, name, namelen))
1008 #endif
1010 static char *syslog_ident;
1011 void openlog(const char *ident, int option, int facility)
1013 if (syslog_ident)
1014 free(syslog_ident);
1015 syslog_ident = strdup(ident);
1018 void vsyslog(int priority, const char *format, va_list ap)
1020 printk("%s: ", syslog_ident);
1021 print(0, format, ap);
1024 void syslog(int priority, const char *format, ...)
1026 va_list ap;
1027 va_start(ap, format);
1028 vsyslog(priority, format, ap);
1029 va_end(ap);
1032 void closelog(void)
1034 free(syslog_ident);
1035 syslog_ident = NULL;
1038 int nanosleep(const struct timespec *req, struct timespec *rem)
1040 s_time_t start = NOW();
1041 s_time_t stop = start + SECONDS(req->tv_sec) + req->tv_nsec;
1042 s_time_t stopped;
1043 struct thread *thread = get_current();
1045 thread->wakeup_time = stop;
1046 clear_runnable(thread);
1047 schedule();
1048 stopped = NOW();
1050 if (rem)
1052 s_time_t remaining = stop - stopped;
1053 if (remaining > 0)
1055 rem->tv_nsec = remaining % 1000000000ULL;
1056 rem->tv_sec = remaining / 1000000000ULL;
1057 } else memset(rem, 0, sizeof(*rem));
1060 return 0;
1063 int usleep(useconds_t usec)
1065 /* "usec shall be less than one million." */
1066 struct timespec req;
1067 req.tv_nsec = usec * 1000;
1068 req.tv_sec = 0;
1070 if (nanosleep(&req, NULL))
1071 return -1;
1073 return 0;
1076 unsigned int sleep(unsigned int seconds)
1078 struct timespec req, rem;
1079 req.tv_sec = seconds;
1080 req.tv_nsec = 0;
1082 if (nanosleep(&req, &rem))
1083 return -1;
1085 if (rem.tv_nsec > 0)
1086 rem.tv_sec++;
1088 return rem.tv_sec;
1091 int clock_gettime(clockid_t clk_id, struct timespec *tp)
1093 switch (clk_id) {
1094 case CLOCK_MONOTONIC:
1096 struct timeval tv;
1098 gettimeofday(&tv, NULL);
1100 tp->tv_sec = tv.tv_sec;
1101 tp->tv_nsec = tv.tv_usec * 1000;
1103 break;
1105 case CLOCK_REALTIME:
1107 u64 nsec = monotonic_clock();
1109 tp->tv_sec = nsec / 1000000000ULL;
1110 tp->tv_nsec = nsec % 1000000000ULL;
1112 break;
1114 default:
1115 print_unsupported("clock_gettime(%d)", clk_id);
1116 errno = EINVAL;
1117 return -1;
1120 return 0;
1123 size_t getpagesize(void)
1125 return PAGE_SIZE;
1128 void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset)
1130 unsigned long n = (length + PAGE_SIZE - 1) / PAGE_SIZE;
1132 ASSERT(!start);
1133 ASSERT(prot == (PROT_READ|PROT_WRITE));
1134 ASSERT((fd == -1 && (flags == (MAP_SHARED|MAP_ANON) || flags == (MAP_PRIVATE|MAP_ANON)))
1135 || (fd != -1 && flags == MAP_SHARED));
1136 ASSERT(offset == 0);
1138 if (fd == -1)
1139 return map_zero(n, 1);
1140 else if (files[fd].type == FTYPE_XC) {
1141 unsigned long zero = 0;
1142 return map_frames_ex(&zero, n, 0, 0, 1, DOMID_SELF, 0, 0);
1143 } else ASSERT(0);
1146 int munmap(void *start, size_t length)
1148 int i, n = length / PAGE_SIZE;
1149 multicall_entry_t call[n];
1150 unsigned char (*data)[PAGE_SIZE] = start;
1151 int ret;
1152 ASSERT(!((unsigned long)start & ~PAGE_MASK));
1153 ASSERT(!(length & ~PAGE_MASK));
1155 for (i = 0; i < n; i++) {
1156 call[i].op = __HYPERVISOR_update_va_mapping;
1157 call[i].args[0] = (unsigned long) &data[i];
1158 call[i].args[1] = 0;
1159 call[i].args[2] = 0;
1160 call[i].args[3] = UVMF_INVLPG;
1163 ret = HYPERVISOR_multicall(call, n);
1164 if (ret) {
1165 errno = -ret;
1166 return -1;
1169 for (i = 0; i < n; i++) {
1170 if (call[i].result) {
1171 errno = call[i].result;
1172 return -1;
1175 return 0;
1178 void sparse(unsigned long data, size_t size)
1180 unsigned long newdata;
1181 xen_pfn_t *mfns;
1182 int i, n;
1184 newdata = (data + PAGE_SIZE - 1) & PAGE_MASK;
1185 if (newdata - data > size)
1186 return;
1187 size -= newdata - data;
1188 data = newdata;
1189 n = size / PAGE_SIZE;
1190 size = n * PAGE_SIZE;
1192 mfns = malloc(n * sizeof(*mfns));
1193 for (i = 0; i < n; i++) {
1194 #ifdef LIBC_DEBUG
1195 int j;
1196 for (j=0; j<PAGE_SIZE; j++)
1197 if (((char*)data + i * PAGE_SIZE)[j]) {
1198 printk("%lx is not zero!\n", data + i * PAGE_SIZE + j);
1199 exit(1);
1201 #endif
1202 mfns[i] = virtual_to_mfn(data + i * PAGE_SIZE);
1205 printk("sparsing %ldMB at %lx\n", size >> 20, data);
1207 munmap((void *) data, size);
1208 free_physical_pages(mfns, n);
1209 do_map_zero(data, n);
1213 /* Not supported by FS yet. */
1214 unsupported_function_crash(link);
1215 unsupported_function(int, readlink, -1);
1216 unsupported_function_crash(umask);
1218 /* We could support that. */
1219 unsupported_function_log(int, chdir, -1);
1221 /* No dynamic library support. */
1222 unsupported_function_log(void *, dlopen, NULL);
1223 unsupported_function_log(void *, dlsym, NULL);
1224 unsupported_function_log(char *, dlerror, NULL);
1225 unsupported_function_log(int, dlclose, -1);
1227 /* We don't raise signals anyway. */
1228 unsupported_function(int, sigemptyset, -1);
1229 unsupported_function(int, sigfillset, -1);
1230 unsupported_function(int, sigaddset, -1);
1231 unsupported_function(int, sigdelset, -1);
1232 unsupported_function(int, sigismember, -1);
1233 unsupported_function(int, sigprocmask, -1);
1234 unsupported_function(int, sigaction, -1);
1235 unsupported_function(int, __sigsetjmp, 0);
1236 unsupported_function(int, sigaltstack, -1);
1237 unsupported_function_crash(kill);
1239 /* Unsupported */
1240 unsupported_function_crash(pipe);
1241 unsupported_function_crash(fork);
1242 unsupported_function_crash(execv);
1243 unsupported_function_crash(execve);
1244 unsupported_function_crash(waitpid);
1245 unsupported_function_crash(wait);
1246 unsupported_function_crash(lockf);
1247 unsupported_function_crash(sysconf);
1248 unsupported_function(int, tcsetattr, -1);
1249 unsupported_function(int, tcgetattr, 0);
1251 /* Linuxish abi for the Caml runtime, don't support */
1252 unsupported_function_log(struct dirent *, readdir64, NULL);
1253 unsupported_function_log(int, getrusage, -1);
1254 unsupported_function_log(int, getrlimit, -1);
1255 unsupported_function_log(int, getrlimit64, -1);
1256 unsupported_function_log(int, __xstat64, -1);
1257 unsupported_function_log(long, __strtol_internal, LONG_MIN);
1258 unsupported_function_log(double, __strtod_internal, HUGE_VAL);
1259 #endif