1/* $NetBSD: linux32_time.c,v 1.35 2010/07/12 12:01:53 njoly Exp $ */ 2 3/*- 4 * Copyright (c) 2006 Emmanuel Dreyfus, all rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. All advertising materials mentioning features or use of this software 15 * must display the following acknowledgement: 16 * This product includes software developed by Emmanuel Dreyfus 17 * 4. The name of the author may not be used to endorse or promote 18 * products derived from this software without specific prior written 19 * permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE THE AUTHOR AND CONTRIBUTORS ``AS IS'' 22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 23 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS 25 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31 * POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34#include <sys/cdefs.h> 35 36__KERNEL_RCSID(0, "$NetBSD: linux32_time.c,v 1.35 2010/07/12 12:01:53 njoly Exp $"); 37 38#include <sys/types.h> 39#include <sys/param.h> 40#include <sys/fstypes.h> 41#include <sys/signal.h> 42#include <sys/dirent.h> 43#include <sys/kauth.h> 44#include <sys/kernel.h> 45#include <sys/fcntl.h> 46#include <sys/namei.h> 47#include <sys/select.h> 48#include <sys/proc.h> 49#include <sys/resourcevar.h> 50#include <sys/ucred.h> 51#include <sys/swap.h> 52#include <sys/vfs_syscalls.h> 53 54#include <machine/types.h> 55 56#include <sys/syscallargs.h> 57 58#include <compat/netbsd32/netbsd32.h> 59#include <compat/netbsd32/netbsd32_conv.h> 60#include <compat/netbsd32/netbsd32_syscallargs.h> 61 62#include <compat/linux/common/linux_types.h> 63#include <compat/linux/common/linux_signal.h> 64#include <compat/linux/common/linux_machdep.h> 65#include <compat/linux/common/linux_misc.h> 66#include <compat/linux/common/linux_oldolduname.h> 67#include <compat/linux/common/linux_sched.h> 68#include <compat/linux/common/linux_ipc.h> 69#include <compat/linux/common/linux_sem.h> 70#include <compat/linux/linux_syscallargs.h> 71 72#include <compat/linux32/common/linux32_types.h> 73#include <compat/linux32/common/linux32_signal.h> 74#include <compat/linux32/common/linux32_machdep.h> 75#include <compat/linux32/common/linux32_sysctl.h> 76#include <compat/linux32/common/linux32_socketcall.h> 77#include <compat/linux32/common/linux32_sched.h> 78#include <compat/linux32/linux32_syscallargs.h> 79 80extern struct timezone linux_sys_tz; 81 82void native_to_linux32_timespec(struct linux32_timespec *, struct timespec *); 83void linux32_to_native_timespec(struct timespec *, struct linux32_timespec *); 84 85int 86linux32_sys_gettimeofday(struct lwp *l, const struct linux32_sys_gettimeofday_args *uap, register_t *retval) 87{ 88 /* { 89 syscallarg(netbsd32_timeval50p_t) tp; 90 syscallarg(netbsd32_timezonep_t) tzp; 91 } */ 92 struct timeval tv; 93 struct netbsd32_timeval50 tv32; 94 int error; 95 96 if (SCARG_P32(uap, tp) != NULL) { 97 microtime(&tv); 98 netbsd32_from_timeval50(&tv, &tv32); 99 if ((error = copyout(&tv32, SCARG_P32(uap, tp), 100 sizeof(tv32))) != 0) 101 return error; 102 } 103 104 /* timezone size does not change */ 105 if (SCARG_P32(uap, tzp) != NULL) { 106 if ((error = copyout(&linux_sys_tz, SCARG_P32(uap, tzp), 107 sizeof(linux_sys_tz))) != 0) 108 return error; 109 } 110 111 return 0; 112} 113 114int 115linux32_sys_settimeofday(struct lwp *l, const struct linux32_sys_settimeofday_args *uap, register_t *retval) 116{ 117 /* { 118 syscallarg(netbsd32_timeval50p_t) tp; 119 syscallarg(netbsd32_timezonep_t) tzp; 120 } */ 121 struct linux_sys_settimeofday_args ua; 122 123 NETBSD32TOP_UAP(tp, struct timeval50); 124 NETBSD32TOP_UAP(tzp, struct timezone); 125 126 return linux_sys_settimeofday(l, &ua, retval); 127} 128 129int 130linux32_sys_time(struct lwp *l, const struct linux32_sys_time_args *uap, register_t *retval) 131{ 132 /* { 133 syscallarg(linux32_timep_t) t; 134 } */ 135 struct timeval atv; 136 linux32_time_t tt; 137 int error; 138 139 microtime(&atv); 140 141 tt = (linux32_time_t)atv.tv_sec; 142 143 if (SCARG_P32(uap, t) && (error = copyout(&tt, 144 SCARG_P32(uap, t), sizeof(tt)))) 145 return error; 146 147 retval[0] = tt; 148 149 return 0; 150} 151 152 153#define CONVTCK(r) (r.tv_sec * hz + r.tv_usec / (1000000 / hz)) 154 155int 156linux32_sys_times(struct lwp *l, const struct linux32_sys_times_args *uap, register_t *retval) 157{ 158 /* { 159 syscallarg(linux32_tmsp_t) tms; 160 } */ 161 struct proc *p = l->l_proc; 162 struct timeval t; 163 int error; 164 165 if (SCARG_P32(uap, tms)) { 166 struct linux32_tms ltms32; 167 struct rusage ru; 168 169 mutex_enter(p->p_lock); 170 calcru(p, &ru.ru_utime, &ru.ru_stime, NULL, NULL); 171 ltms32.ltms32_utime = CONVTCK(ru.ru_utime); 172 ltms32.ltms32_stime = CONVTCK(ru.ru_stime); 173 ltms32.ltms32_cutime = CONVTCK(p->p_stats->p_cru.ru_utime); 174 ltms32.ltms32_cstime = CONVTCK(p->p_stats->p_cru.ru_stime); 175 mutex_exit(p->p_lock); 176 177 error = copyout(<ms32, SCARG_P32(uap, tms), sizeof(ltms32)); 178 if (error) 179 return error; 180 } 181 182 getmicrouptime(&t); 183 184 retval[0] = ((linux32_clock_t)(CONVTCK(t))); 185 return 0; 186} 187 188#undef CONVTCK 189 190int 191linux32_sys_stime(struct lwp *l, const struct linux32_sys_stime_args *uap, register_t *retval) 192{ 193 /* { 194 syscallarg(linux32_timep_t) t; 195 } */ 196 struct timespec ts; 197 linux32_time_t tt32; 198 int error; 199 200 if ((error = copyin(SCARG_P32(uap, t), &tt32, sizeof tt32)) != 0) 201 return error; 202 203 ts.tv_sec = (long)tt32; 204 ts.tv_nsec = 0; 205 206 return settime(l->l_proc, &ts); 207} 208 209int 210linux32_sys_utime(struct lwp *l, const struct linux32_sys_utime_args *uap, register_t *retval) 211{ 212 /* { 213 syscallarg(const netbsd32_charp) path; 214 syscallarg(linux32_utimbufp_t) times; 215 } */ 216 struct timeval tv[2], *tvp; 217 struct linux32_utimbuf lut; 218 int error; 219 220 if (SCARG_P32(uap, times) != NULL) { 221 if ((error = copyin(SCARG_P32(uap, times), &lut, sizeof lut))) 222 return error; 223 224 tv[0].tv_sec = (long)lut.l_actime; 225 tv[0].tv_usec = 0; 226 tv[1].tv_sec = (long)lut.l_modtime; 227 tv[1].tv_usec = 0; 228 tvp = tv; 229 } else { 230 tvp = NULL; 231 } 232 233 return do_sys_utimes(l, NULL, SCARG_P32(uap, path), FOLLOW, 234 tvp, UIO_SYSSPACE); 235} 236 237void 238native_to_linux32_timespec(struct linux32_timespec *ltp, struct timespec *ntp) 239{ 240 ltp->tv_sec = ntp->tv_sec; 241 ltp->tv_nsec = ntp->tv_nsec; 242} 243 244void 245linux32_to_native_timespec(struct timespec *ntp, struct linux32_timespec *ltp) 246{ 247 ntp->tv_sec = ltp->tv_sec; 248 ntp->tv_nsec = ltp->tv_nsec; 249} 250 251int 252linux32_sys_nanosleep(struct lwp *l, 253 const struct linux32_sys_nanosleep_args *uap, register_t *retval) 254{ 255 /* { 256 syscallarg(linux32_timespecp_t) rqtp; 257 syscallarg(linux32_timespecp_t) rmtp; 258 } */ 259 struct timespec rqts, rmts; 260 struct linux32_timespec lrqts, lrmts; 261 int error, error1; 262 263 error = copyin(SCARG_P32(uap, rqtp), &lrqts, sizeof(lrqts)); 264 if (error != 0) 265 return error; 266 linux32_to_native_timespec(&rqts, &lrqts); 267 268 error = nanosleep1(l, &rqts, SCARG_P32(uap, rmtp) ? &rmts : NULL); 269 if (SCARG_P32(uap, rmtp) == NULL || (error != 0 && error != EINTR)) 270 return error; 271 272 native_to_linux32_timespec(&lrmts, &rmts); 273 error1 = copyout(&lrmts, SCARG_P32(uap, rmtp), sizeof(lrmts)); 274 return error1 ? error1 : error; 275} 276 277int 278linux32_sys_clock_settime(struct lwp *l, 279 const struct linux32_sys_clock_settime_args *uap, register_t *retval) 280{ 281 /* { 282 syscallarg(clockid_t) which; 283 syscallarg(linux32_timespecp_t) tp; 284 } */ 285 int error; 286 struct timespec ts; 287 struct linux32_timespec lts; 288 clockid_t id; 289 290 error = linux_to_native_clockid(&id, SCARG(uap, which)); 291 if (error != 0) 292 return error; 293 294 if ((error = copyin(SCARG_P32(uap, tp), <s, sizeof lts))) 295 return error; 296 297 linux32_to_native_timespec(&ts, <s); 298 return clock_settime1(l->l_proc, id, &ts, true); 299} 300 301int 302linux32_sys_clock_gettime(struct lwp *l, 303 const struct linux32_sys_clock_gettime_args *uap, register_t *retval) 304{ 305 /* { 306 syscallarg(clockid_t) which; 307 syscallarg(linux32_timespecp_t) tp; 308 } */ 309 int error; 310 clockid_t id; 311 struct timespec ts; 312 struct linux32_timespec lts; 313 314 error = linux_to_native_clockid(&id, SCARG(uap, which)); 315 if (error != 0) 316 return error; 317 318 error = clock_gettime1(id, &ts); 319 if (error != 0) 320 return error; 321 322 native_to_linux32_timespec(<s, &ts); 323 return copyout(<s, SCARG_P32(uap, tp), sizeof lts); 324} 325 326int 327linux32_sys_clock_getres(struct lwp *l, 328 const struct linux32_sys_clock_getres_args *uap, register_t *retval) 329{ 330 /* { 331 syscallarg(clockid_t) which; 332 syscallarg(linux32_timespecp_t) tp; 333 } */ 334 int error; 335 clockid_t id; 336 struct timespec ts; 337 struct linux32_timespec lts; 338 339 error = linux_to_native_clockid(&id, SCARG(uap, which)); 340 if (error != 0 || SCARG_P32(uap, tp) == NULL) 341 return error; 342 343 error = clock_getres1(id, &ts); 344 if (error != 0) 345 return error; 346 347 native_to_linux32_timespec(<s, &ts); 348 return copyout(<s, SCARG_P32(uap, tp), sizeof lts); 349} 350 351int 352linux32_sys_clock_nanosleep(struct lwp *l, 353 const struct linux32_sys_clock_nanosleep_args *uap, register_t *retval) 354{ 355 /* { 356 syscallarg(clockid_t) which; 357 syscallarg(int) flags; 358 syscallarg(linux32_timespecp_t) rqtp; 359 syscallarg(linux32_timespecp_t) rmtp; 360 } */ 361 struct linux32_timespec lrqts, lrmts; 362 struct timespec rqts, rmts; 363 int error, error1; 364 clockid_t id; 365 366 if (SCARG(uap, flags) != 0) 367 return EINVAL; /* XXX deal with TIMER_ABSTIME */ 368 369 error = linux_to_native_clockid(&id, SCARG(uap, which)); 370 if (error != 0) 371 return error; 372 373 error = copyin(SCARG_P32(uap, rqtp), &lrqts, sizeof lrqts); 374 if (error != 0) 375 return error; 376 linux32_to_native_timespec(&rqts, &lrqts); 377 378 error = nanosleep1(l, &rqts, SCARG_P32(uap, rmtp) ? &rmts : NULL); 379 if (SCARG_P32(uap, rmtp) == NULL || (error != 0 && error != EINTR)) 380 return error; 381 382 native_to_linux32_timespec(&lrmts, &rmts); 383 error1 = copyout(&lrmts, SCARG_P32(uap, rmtp), sizeof lrmts); 384 return error1 ? error1 : error; 385} 386