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/linux32_syscallargs.h> 78 79 extern struct timezone linux_sys_tz; 80 81 void native_to_linux32_timespec(struct linux32_timespec *, struct timespec *); 82 void linux32_to_native_timespec(struct timespec *, struct linux32_timespec *); 83 84 int 85 linux32_sys_gettimeofday(struct lwp *l, const struct linux32_sys_gettimeofday_args *uap, register_t *retval) 86 { 87 /* { 88 syscallarg(netbsd32_timeval50p_t) tp; 89 syscallarg(netbsd32_timezonep_t) tzp; 90 } */ 91 struct timeval tv; 92 struct netbsd32_timeval50 tv32; 93 int error; 94 95 if (SCARG_P32(uap, tp) != NULL) { 96 microtime(&tv); 97 netbsd32_from_timeval50(&tv, &tv32); 98 if ((error = copyout(&tv32, SCARG_P32(uap, tp), 99 sizeof(tv32))) != 0) 100 return error; 101 } 102 103 /* timezone size does not change */ 104 if (SCARG_P32(uap, tzp) != NULL) { 105 if ((error = copyout(&linux_sys_tz, SCARG_P32(uap, tzp), 106 sizeof(linux_sys_tz))) != 0) 107 return error; 108 } 109 110 return 0; 111 } 112 113 int 114 linux32_sys_settimeofday(struct lwp *l, const struct linux32_sys_settimeofday_args *uap, register_t *retval) 115 { 116 /* { 117 syscallarg(netbsd32_timeval50p_t) tp; 118 syscallarg(netbsd32_timezonep_t) tzp; 119 } */ 120 struct linux_sys_settimeofday_args ua; 121 122 NETBSD32TOP_UAP(tp, struct timeval50); 123 NETBSD32TOP_UAP(tzp, struct timezone); 124 125 return linux_sys_settimeofday(l, &ua, retval); 126 } 127 128 int 129 linux32_sys_time(struct lwp *l, const struct linux32_sys_time_args *uap, register_t *retval) 130 { 131 /* { 132 syscallarg(linux32_timep_t) t; 133 } */ 134 struct timeval atv; 135 linux32_time_t tt; 136 int error; 137 138 microtime(&atv); 139 140 tt = (linux32_time_t)atv.tv_sec; 141 142 if (SCARG_P32(uap, t) && (error = copyout(&tt, 143 SCARG_P32(uap, t), sizeof(tt)))) 144 return error; 145 146 retval[0] = tt; 147 148 return 0; 149 } 150 151 152 #define CONVTCK(r) (r.tv_sec * hz + r.tv_usec / (1000000 / hz)) 153 154 int 155 linux32_sys_times(struct lwp *l, const struct linux32_sys_times_args *uap, register_t *retval) 156 { 157 /* { 158 syscallarg(linux32_tmsp_t) tms; 159 } */ 160 struct proc *p = l->l_proc; 161 struct timeval t; 162 int error; 163 164 if (SCARG_P32(uap, tms)) { 165 struct linux32_tms ltms32; 166 struct rusage ru; 167 168 mutex_enter(p->p_lock); 169 calcru(p, &ru.ru_utime, &ru.ru_stime, NULL, NULL); 170 ltms32.ltms32_utime = CONVTCK(ru.ru_utime); 171 ltms32.ltms32_stime = CONVTCK(ru.ru_stime); 172 ltms32.ltms32_cutime = CONVTCK(p->p_stats->p_cru.ru_utime); 173 ltms32.ltms32_cstime = CONVTCK(p->p_stats->p_cru.ru_stime); 174 mutex_exit(p->p_lock); 175 176 error = copyout(<ms32, SCARG_P32(uap, tms), sizeof(ltms32)); 177 if (error) 178 return error; 179 } 180 181 getmicrouptime(&t); 182 183 retval[0] = ((linux32_clock_t)(CONVTCK(t))); 184 return 0; 185 } 186 187 #undef CONVTCK 188 189 int 190 linux32_sys_stime(struct lwp *l, const struct linux32_sys_stime_args *uap, register_t *retval) 191 { 192 /* { 193 syscallarg(linux32_timep_t) t; 194 } */ 195 struct timespec ts; 196 linux32_time_t tt32; 197 int error; 198 199 if ((error = copyin(SCARG_P32(uap, t), &tt32, sizeof tt32)) != 0) 200 return error; 201 202 ts.tv_sec = (long)tt32; 203 ts.tv_nsec = 0; 204 205 return settime(l->l_proc, &ts); 206 } 207 208 int 209 linux32_sys_utime(struct lwp *l, const struct linux32_sys_utime_args *uap, register_t *retval) 210 { 211 /* { 212 syscallarg(const netbsd32_charp) path; 213 syscallarg(linux32_utimbufp_t) times; 214 } */ 215 struct timeval tv[2], *tvp; 216 struct linux32_utimbuf lut; 217 int error; 218 219 if (SCARG_P32(uap, times) != NULL) { 220 if ((error = copyin(SCARG_P32(uap, times), &lut, sizeof lut))) 221 return error; 222 223 tv[0].tv_sec = (long)lut.l_actime; 224 tv[0].tv_usec = 0; 225 tv[1].tv_sec = (long)lut.l_modtime; 226 tv[1].tv_usec = 0; 227 tvp = tv; 228 } else { 229 tvp = NULL; 230 } 231 232 return do_sys_utimes(l, NULL, SCARG_P32(uap, path), FOLLOW, 233 tvp, UIO_SYSSPACE); 234 } 235 236 void 237 native_to_linux32_timespec(struct linux32_timespec *ltp, struct timespec *ntp) 238 { 239 ltp->tv_sec = ntp->tv_sec; 240 ltp->tv_nsec = ntp->tv_nsec; 241 } 242 243 void 244 linux32_to_native_timespec(struct timespec *ntp, struct linux32_timespec *ltp) 245 { 246 ntp->tv_sec = ltp->tv_sec; 247 ntp->tv_nsec = ltp->tv_nsec; 248 } 249 250 int 251 linux32_sys_nanosleep(struct lwp *l, 252 const struct linux32_sys_nanosleep_args *uap, register_t *retval) 253 { 254 /* { 255 syscallarg(linux32_timespecp_t) rqtp; 256 syscallarg(linux32_timespecp_t) rmtp; 257 } */ 258 struct timespec rqts, rmts; 259 struct linux32_timespec lrqts, lrmts; 260 int error, error1; 261 262 error = copyin(SCARG_P32(uap, rqtp), &lrqts, sizeof(lrqts)); 263 if (error != 0) 264 return error; 265 linux32_to_native_timespec(&rqts, &lrqts); 266 267 error = nanosleep1(l, &rqts, SCARG_P32(uap, rmtp) ? &rmts : NULL); 268 if (SCARG_P32(uap, rmtp) == NULL || (error != 0 && error != EINTR)) 269 return error; 270 271 native_to_linux32_timespec(&lrmts, &rmts); 272 error1 = copyout(&lrmts, SCARG_P32(uap, rmtp), sizeof(lrmts)); 273 return error1 ? error1 : error; 274 } 275 276 int 277 linux32_sys_clock_settime(struct lwp *l, 278 const struct linux32_sys_clock_settime_args *uap, register_t *retval) 279 { 280 /* { 281 syscallarg(clockid_t) which; 282 syscallarg(linux32_timespecp_t) tp; 283 } */ 284 int error; 285 struct timespec ts; 286 struct linux32_timespec lts; 287 clockid_t id; 288 289 error = linux_to_native_clockid(&id, SCARG(uap, which)); 290 if (error != 0) 291 return error; 292 293 if ((error = copyin(SCARG_P32(uap, tp), <s, sizeof lts))) 294 return error; 295 296 linux32_to_native_timespec(&ts, <s); 297 return clock_settime1(l->l_proc, id, &ts, true); 298 } 299 300 int 301 linux32_sys_clock_gettime(struct lwp *l, 302 const struct linux32_sys_clock_gettime_args *uap, register_t *retval) 303 { 304 /* { 305 syscallarg(clockid_t) which; 306 syscallarg(linux32_timespecp_t) tp; 307 } */ 308 int error; 309 clockid_t id; 310 struct timespec ts; 311 struct linux32_timespec lts; 312 313 error = linux_to_native_clockid(&id, SCARG(uap, which)); 314 if (error != 0) 315 return error; 316 317 error = clock_gettime1(id, &ts); 318 if (error != 0) 319 return error; 320 321 native_to_linux32_timespec(<s, &ts); 322 return copyout(<s, SCARG_P32(uap, tp), sizeof lts); 323 } 324 325 int 326 linux32_sys_clock_getres(struct lwp *l, 327 const struct linux32_sys_clock_getres_args *uap, register_t *retval) 328 { 329 /* { 330 syscallarg(clockid_t) which; 331 syscallarg(linux32_timespecp_t) tp; 332 } */ 333 int error; 334 clockid_t id; 335 struct timespec ts; 336 struct linux32_timespec lts; 337 338 error = linux_to_native_clockid(&id, SCARG(uap, which)); 339 if (error != 0 || SCARG_P32(uap, tp) == NULL) 340 return error; 341 342 error = clock_getres1(id, &ts); 343 if (error != 0) 344 return error; 345 346 native_to_linux32_timespec(<s, &ts); 347 return copyout(<s, SCARG_P32(uap, tp), sizeof lts); 348 } 349 350 int 351 linux32_sys_clock_nanosleep(struct lwp *l, 352 const struct linux32_sys_clock_nanosleep_args *uap, register_t *retval) 353 { 354 /* { 355 syscallarg(clockid_t) which; 356 syscallarg(int) flags; 357 syscallarg(linux32_timespecp_t) rqtp; 358 syscallarg(linux32_timespecp_t) rmtp; 359 } */ 360 struct linux32_timespec lrqts, lrmts; 361 struct timespec rqts, rmts; 362 int error, error1; 363 clockid_t id; 364 365 if (SCARG(uap, flags) != 0) 366 return EINVAL; /* XXX deal with TIMER_ABSTIME */ 367 368 error = linux_to_native_clockid(&id, SCARG(uap, which)); 369 if (error != 0) 370 return error; 371 372 error = copyin(SCARG_P32(uap, rqtp), &lrqts, sizeof lrqts); 373 if (error != 0) 374 return error; 375 linux32_to_native_timespec(&rqts, &lrqts); 376 377 error = nanosleep1(l, &rqts, SCARG_P32(uap, rmtp) ? &rmts : NULL); 378 if (SCARG_P32(uap, rmtp) == NULL || (error != 0 && error != EINTR)) 379 return error; 380 381 native_to_linux32_timespec(&lrmts, &rmts); 382 error1 = copyout(&lrmts, SCARG_P32(uap, rmtp), sizeof lrmts); 383 return error1 ? error1 : error; 384 } 385