diff --git a/ports/include/noux_session/noux_session.h b/ports/include/noux_session/noux_session.h index b59e0455e..9c130c58f 100644 --- a/ports/include/noux_session/noux_session.h +++ b/ports/include/noux_session/noux_session.h @@ -72,6 +72,9 @@ namespace Noux { SYSCALL_SHUTDOWN, SYSCALL_CONNECT, SYSCALL_USERINFO, + SYSCALL_GETTIMEOFDAY, + SYSCALL_CLOCK_GETTIME, + SYSCALL_UTIMES, SYSCALL_INVALID = -1 }; @@ -116,6 +119,9 @@ namespace Noux { NOUX_DECL_SYSCALL_NAME(SHUTDOWN) NOUX_DECL_SYSCALL_NAME(CONNECT) NOUX_DECL_SYSCALL_NAME(USERINFO) + NOUX_DECL_SYSCALL_NAME(GETTIMEOFDAY) + NOUX_DECL_SYSCALL_NAME(CLOCK_GETTIME) + NOUX_DECL_SYSCALL_NAME(UTIMES) case SYSCALL_INVALID: return 0; } return 0; diff --git a/ports/include/noux_session/sysio.h b/ports/include/noux_session/sysio.h index 82deebd34..2231bd0d9 100644 --- a/ports/include/noux_session/sysio.h +++ b/ports/include/noux_session/sysio.h @@ -284,6 +284,11 @@ namespace Noux { typedef char Home[MAX_HOME_LEN]; typedef unsigned int Uid; + /** + * time/clock definitions + */ + enum Clock_Id { CLOCK_ID_SECOND }; + enum General_error { ERR_FD_INVALID, NUM_GENERAL_ERRORS }; enum Stat_error { STAT_ERR_NO_ENTRY = NUM_GENERAL_ERRORS }; enum Fcntl_error { FCNTL_ERR_CMD_INVALID = NUM_GENERAL_ERRORS }; @@ -337,6 +342,13 @@ namespace Noux { enum Socket_error { SOCKET_ERR_ACCESS, SOCKET_ERR_NO_AF_SUPPORT, SOCKET_ERR_INVALID, SOCKET_ERR_NO_MEMORY }; + enum Clock_error { CLOCK_ERR_INVALID, CLOCK_ERR_FAULT, CLOCK_ERR_NO_PERM }; + + enum Utimes_error { UTIMES_ERR_ACCESS, UTIMES_ERR_FAUL, UTIMES_ERR_EIO, + UTIMES_ERR_NAME_TOO_LONG, UTIMES_ERR_NO_ENTRY, + UTIMES_ERR_NOT_DIRECTORY, UTIMES_ERR_NO_PERM, + UTIMES_ERR_READ_ONLY }; + union { General_error general; Stat_error stat; @@ -359,6 +371,8 @@ namespace Noux { Send_error send; Shutdown_error shutdown; Socket_error socket; + Clock_error clock; + Utimes_error utimes; } error; union { @@ -462,6 +476,14 @@ namespace Noux { SYSIO_DECL(userinfo, { int request; Uid uid; }, { User name; Uid uid; Uid gid; Shell shell; Home home; }); + + SYSIO_DECL(gettimeofday, { }, { unsigned long sec; unsigned int usec; }); + + SYSIO_DECL(clock_gettime, { Clock_Id clock_id; }, + { unsigned long sec; unsigned long nsec; }); + + SYSIO_DECL(utimes, { Path path; unsigned long sec; unsigned long usec; }, + { }); }; }; }; diff --git a/ports/src/lib/libc_noux/plugin.cc b/ports/src/lib/libc_noux/plugin.cc index 79a02b8c8..2c5ff1c0a 100644 --- a/ports/src/lib/libc_noux/plugin.cc +++ b/ports/src/lib/libc_noux/plugin.cc @@ -456,21 +456,52 @@ extern "C" pid_t _wait4(pid_t pid, int *status, int options, extern "C" int clock_gettime(clockid_t clk_id, struct timespec *tp) { - if (verbose) - PDBG("clock_gettime called - not implemented"); - errno = EINVAL; - return -1; + /* we currently only support CLOCK_SECOND */ + switch (clk_id) { + case CLOCK_SECOND: + sysio()->clock_gettime_in.clock_id = Noux::Sysio::CLOCK_ID_SECOND; + break; + default: + /* let's save the trip to noux and return directly */ + errno = EINVAL; + return -1; + } + + if (!noux()->syscall(Noux::Session::SYSCALL_CLOCK_GETTIME)) { + switch (sysio()->error.clock) { + case Noux::Sysio::CLOCK_ERR_INVALID: errno = EINVAL; break; + default: errno = 0; break; + } + + return -1; + } + + tp->tv_sec = sysio()->clock_gettime_out.sec; + tp->tv_nsec = sysio()->clock_gettime_out.nsec; + + return 0; } extern "C" int gettimeofday(struct timeval *tv, struct timezone *tz) { - if (verbose) - PDBG("gettimeofday() called - not implemented"); + if (!noux()->syscall(Noux::Session::SYSCALL_GETTIMEOFDAY)) { + errno = EINVAL; + return -1; + } - if (tv) { - tv->tv_sec = 0; - tv->tv_usec = 0; + tv->tv_sec = sysio()->gettimeofday_out.sec; + tv->tv_usec = sysio()->gettimeofday_out.usec; + + return 0; +} + + +extern "C" int utimes(const char* path, const struct timeval *times) +{ + if (!noux()->syscall(Noux::Session::SYSCALL_UTIMES)) { + errno = EINVAL; + return -1; } return 0; diff --git a/ports/src/noux/main.cc b/ports/src/noux/main.cc index cd231f36b..017c5f838 100644 --- a/ports/src/noux/main.cc +++ b/ports/src/noux/main.cc @@ -70,7 +70,7 @@ namespace Noux { } public: - Timeout_scheduler() : _curr_time(0) { start(); } + Timeout_scheduler(unsigned long curr_time) : _curr_time(curr_time) { start(); } Alarm::Time curr_time() const { return _curr_time; } }; @@ -595,6 +595,70 @@ bool Noux::Child::syscall(Noux::Session::Syscall sc) return true; } + case SYSCALL_GETTIMEOFDAY: + { + /** + * Since the timeout_scheduler thread is started after noux it + * basicly returns the eleapsed time since noux was started. We + * abuse this timer to provide a more useful implemenation of + * gettimeofday() to make certain programs (e.g. ping(1)) happy. + * Note: this is just a short-term solution because Genode currently + * lacks a proper time interface (there is a RTC driver however, but + * there is no interface for it). + */ + unsigned long time = Noux::timeout_scheduler()->curr_time(); + + _sysio->gettimeofday_out.sec = (time / 1000); + _sysio->gettimeofday_out.usec = (time % 1000) * 1000; + + return true; + } + + case SYSCALL_CLOCK_GETTIME: + { + /** + * It's the same procedure as in SYSCALL_GETTIMEOFDAY. + */ + unsigned long time = Noux::timeout_scheduler()->curr_time(); + + switch (_sysio->clock_gettime_in.clock_id) { + + /* CLOCK_SECOND is used by time(3) in the libc. */ + case Sysio::CLOCK_ID_SECOND: + { + _sysio->clock_gettime_out.sec = (time / 1000); + _sysio->clock_gettime_out.nsec = 0; + + return true; + } + + default: + { + _sysio->clock_gettime_out.sec = 0; + _sysio->clock_gettime_out.nsec = 0; + _sysio->error.clock = Sysio::CLOCK_ERR_INVALID; + + return false; + } + + } + + return false; + + } + + case SYSCALL_UTIMES: + { + /** + * This systemcall is currently not implemented because we lack + * the needed mechanisms in most file-systems. + * + * But we return true anyway to keep certain programs, e.g. make + * happy. + */ + return true; + } + case SYSCALL_SOCKET: case SYSCALL_GETSOCKOPT: case SYSCALL_SETSOCKOPT: @@ -713,7 +777,7 @@ Noux::Pid_allocator *Noux::pid_allocator() Noux::Timeout_scheduler *Noux::timeout_scheduler() { - static Noux::Timeout_scheduler inst; + static Noux::Timeout_scheduler inst(0); return &inst; } diff --git a/ports/src/noux/net/net.cc b/ports/src/noux/net/net.cc index a2ca5c5e7..29d18d9b8 100644 --- a/ports/src/noux/net/net.cc +++ b/ports/src/noux/net/net.cc @@ -176,6 +176,9 @@ bool Noux::Child::_syscall_net(Noux::Session::Syscall sc) case SYSCALL_READLINK: case SYSCALL_SYMLINK: case SYSCALL_USERINFO: + case SYSCALL_GETTIMEOFDAY: + case SYSCALL_CLOCK_GETTIME: + case SYSCALL_UTIMES: break; case SYSCALL_SOCKET: {