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