1 /* $NetBSD: linux32_time.c,v 1.40 2021/09/19 23:51:37 thorpej 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.40 2021/09/19 23:51:37 thorpej 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/timerfd.h>
49 #include <sys/proc.h>
50 #include <sys/resourcevar.h>
51 #include <sys/ucred.h>
52 #include <sys/swap.h>
53 #include <sys/vfs_syscalls.h>
54
55 #include <machine/types.h>
56
57 #include <sys/syscallargs.h>
58
59 #include <compat/netbsd32/netbsd32.h>
60 #include <compat/netbsd32/netbsd32_conv.h>
61 #include <compat/netbsd32/netbsd32_syscallargs.h>
62
63 #include <compat/linux/common/linux_types.h>
64 #include <compat/linux/common/linux_signal.h>
65 #include <compat/linux/common/linux_machdep.h>
66 #include <compat/linux/common/linux_misc.h>
67 #include <compat/linux/common/linux_oldolduname.h>
68 #include <compat/linux/common/linux_sched.h>
69 #include <compat/linux/common/linux_ipc.h>
70 #include <compat/linux/common/linux_sem.h>
71 #include <compat/linux/linux_syscallargs.h>
72
73 #include <compat/linux32/common/linux32_types.h>
74 #include <compat/linux32/common/linux32_signal.h>
75 #include <compat/linux32/common/linux32_machdep.h>
76 #include <compat/linux32/common/linux32_sysctl.h>
77 #include <compat/linux32/common/linux32_socketcall.h>
78 #include <compat/linux32/common/linux32_sched.h>
79 #include <compat/linux32/linux32_syscallargs.h>
80
81 CTASSERT(LINUX_TIMER_ABSTIME == TIMER_ABSTIME);
82
83 extern struct timezone linux_sys_tz;
84
85 int
linux32_sys_gettimeofday(struct lwp * l,const struct linux32_sys_gettimeofday_args * uap,register_t * retval)86 linux32_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
114 int
linux32_sys_settimeofday(struct lwp * l,const struct linux32_sys_settimeofday_args * uap,register_t * retval)115 linux32_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
129 int
linux32_sys_time(struct lwp * l,const struct linux32_sys_time_args * uap,register_t * retval)130 linux32_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
155 int
linux32_sys_times(struct lwp * l,const struct linux32_sys_times_args * uap,register_t * retval)156 linux32_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 memset(<ms32, 0, sizeof(ltms32));
170
171 mutex_enter(p->p_lock);
172 calcru(p, &ru.ru_utime, &ru.ru_stime, NULL, NULL);
173 ltms32.ltms32_utime = CONVTCK(ru.ru_utime);
174 ltms32.ltms32_stime = CONVTCK(ru.ru_stime);
175 ltms32.ltms32_cutime = CONVTCK(p->p_stats->p_cru.ru_utime);
176 ltms32.ltms32_cstime = CONVTCK(p->p_stats->p_cru.ru_stime);
177 mutex_exit(p->p_lock);
178
179 error = copyout(<ms32, SCARG_P32(uap, tms), sizeof(ltms32));
180 if (error)
181 return error;
182 }
183
184 getmicrouptime(&t);
185
186 retval[0] = ((linux32_clock_t)(CONVTCK(t)));
187 return 0;
188 }
189
190 #undef CONVTCK
191
192 int
linux32_sys_stime(struct lwp * l,const struct linux32_sys_stime_args * uap,register_t * retval)193 linux32_sys_stime(struct lwp *l, const struct linux32_sys_stime_args *uap, register_t *retval)
194 {
195 /* {
196 syscallarg(linux32_timep_t) t;
197 } */
198 struct timespec ts;
199 linux32_time_t tt32;
200 int error;
201
202 if ((error = copyin(SCARG_P32(uap, t), &tt32, sizeof tt32)) != 0)
203 return error;
204
205 ts.tv_sec = (long)tt32;
206 ts.tv_nsec = 0;
207
208 return settime(l->l_proc, &ts);
209 }
210
211 int
linux32_sys_utime(struct lwp * l,const struct linux32_sys_utime_args * uap,register_t * retval)212 linux32_sys_utime(struct lwp *l, const struct linux32_sys_utime_args *uap, register_t *retval)
213 {
214 /* {
215 syscallarg(const netbsd32_charp) path;
216 syscallarg(linux32_utimbufp_t) times;
217 } */
218 struct timeval tv[2], *tvp;
219 struct linux32_utimbuf lut;
220 int error;
221
222 if (SCARG_P32(uap, times) != NULL) {
223 if ((error = copyin(SCARG_P32(uap, times), &lut, sizeof lut)))
224 return error;
225
226 tv[0].tv_sec = (long)lut.l_actime;
227 tv[0].tv_usec = 0;
228 tv[1].tv_sec = (long)lut.l_modtime;
229 tv[1].tv_usec = 0;
230 tvp = tv;
231 } else {
232 tvp = NULL;
233 }
234
235 return do_sys_utimes(l, NULL, SCARG_P32(uap, path), FOLLOW,
236 tvp, UIO_SYSSPACE);
237 }
238
239 void
native_to_linux32_timespec(struct linux32_timespec * ltp,const struct timespec * ntp)240 native_to_linux32_timespec(struct linux32_timespec *ltp,
241 const struct timespec *ntp)
242 {
243
244 memset(ltp, 0, sizeof(*ltp));
245 ltp->tv_sec = ntp->tv_sec;
246 ltp->tv_nsec = ntp->tv_nsec;
247 }
248
249 void
linux32_to_native_timespec(struct timespec * ntp,const struct linux32_timespec * ltp)250 linux32_to_native_timespec(struct timespec *ntp,
251 const struct linux32_timespec *ltp)
252 {
253
254 memset(ntp, 0, sizeof(*ntp));
255 ntp->tv_sec = ltp->tv_sec;
256 ntp->tv_nsec = ltp->tv_nsec;
257 }
258
259 void
native_to_linux32_itimerspec(struct linux32_itimerspec * litp,const struct itimerspec * nitp)260 native_to_linux32_itimerspec(struct linux32_itimerspec *litp,
261 const struct itimerspec *nitp)
262 {
263 memset(litp, 0, sizeof(*litp));
264 native_to_linux32_timespec(&litp->it_interval, &nitp->it_interval);
265 native_to_linux32_timespec(&litp->it_value, &nitp->it_value);
266 }
267
268 void
linux32_to_native_itimerspec(struct itimerspec * nitp,const struct linux32_itimerspec * litp)269 linux32_to_native_itimerspec(struct itimerspec *nitp,
270 const struct linux32_itimerspec *litp)
271 {
272 memset(nitp, 0, sizeof(*nitp));
273 linux32_to_native_timespec(&nitp->it_interval, &litp->it_interval);
274 linux32_to_native_timespec(&nitp->it_value, &litp->it_value);
275 }
276
277 int
linux32_sys_nanosleep(struct lwp * l,const struct linux32_sys_nanosleep_args * uap,register_t * retval)278 linux32_sys_nanosleep(struct lwp *l,
279 const struct linux32_sys_nanosleep_args *uap, register_t *retval)
280 {
281 /* {
282 syscallarg(linux32_timespecp_t) rqtp;
283 syscallarg(linux32_timespecp_t) rmtp;
284 } */
285 struct timespec rqts, rmts;
286 struct linux32_timespec lrqts, lrmts;
287 int error, error1;
288
289 error = copyin(SCARG_P32(uap, rqtp), &lrqts, sizeof(lrqts));
290 if (error != 0)
291 return error;
292 linux32_to_native_timespec(&rqts, &lrqts);
293
294 error = nanosleep1(l, CLOCK_MONOTONIC, 0, &rqts,
295 SCARG_P32(uap, rmtp) ? &rmts : NULL);
296 if (SCARG_P32(uap, rmtp) == NULL || (error != 0 && error != EINTR))
297 return error;
298
299 native_to_linux32_timespec(&lrmts, &rmts);
300 error1 = copyout(&lrmts, SCARG_P32(uap, rmtp), sizeof(lrmts));
301 return error1 ? error1 : error;
302 }
303
304 int
linux32_sys_clock_settime(struct lwp * l,const struct linux32_sys_clock_settime_args * uap,register_t * retval)305 linux32_sys_clock_settime(struct lwp *l,
306 const struct linux32_sys_clock_settime_args *uap, register_t *retval)
307 {
308 /* {
309 syscallarg(clockid_t) which;
310 syscallarg(linux32_timespecp_t) tp;
311 } */
312 int error;
313 struct timespec ts;
314 struct linux32_timespec lts;
315 clockid_t id;
316
317 error = linux_to_native_clockid(&id, SCARG(uap, which));
318 if (error != 0)
319 return error;
320
321 if ((error = copyin(SCARG_P32(uap, tp), <s, sizeof lts)))
322 return error;
323
324 linux32_to_native_timespec(&ts, <s);
325 return clock_settime1(l->l_proc, id, &ts, true);
326 }
327
328 int
linux32_sys_clock_gettime(struct lwp * l,const struct linux32_sys_clock_gettime_args * uap,register_t * retval)329 linux32_sys_clock_gettime(struct lwp *l,
330 const struct linux32_sys_clock_gettime_args *uap, register_t *retval)
331 {
332 /* {
333 syscallarg(clockid_t) which;
334 syscallarg(linux32_timespecp_t) tp;
335 } */
336 int error;
337 clockid_t id;
338 struct timespec ts;
339 struct linux32_timespec lts;
340
341 error = linux_to_native_clockid(&id, SCARG(uap, which));
342 if (error != 0)
343 return error;
344
345 error = clock_gettime1(id, &ts);
346 if (error != 0)
347 return error;
348
349 native_to_linux32_timespec(<s, &ts);
350 return copyout(<s, SCARG_P32(uap, tp), sizeof lts);
351 }
352
353 int
linux32_sys_clock_getres(struct lwp * l,const struct linux32_sys_clock_getres_args * uap,register_t * retval)354 linux32_sys_clock_getres(struct lwp *l,
355 const struct linux32_sys_clock_getres_args *uap, register_t *retval)
356 {
357 /* {
358 syscallarg(clockid_t) which;
359 syscallarg(linux32_timespecp_t) tp;
360 } */
361 int error;
362 clockid_t id;
363 struct timespec ts;
364 struct linux32_timespec lts;
365
366 error = linux_to_native_clockid(&id, SCARG(uap, which));
367 if (error != 0 || SCARG_P32(uap, tp) == NULL)
368 return error;
369
370 error = clock_getres1(id, &ts);
371 if (error != 0)
372 return error;
373
374 native_to_linux32_timespec(<s, &ts);
375 return copyout(<s, SCARG_P32(uap, tp), sizeof lts);
376 }
377
378 int
linux32_sys_clock_nanosleep(struct lwp * l,const struct linux32_sys_clock_nanosleep_args * uap,register_t * retval)379 linux32_sys_clock_nanosleep(struct lwp *l,
380 const struct linux32_sys_clock_nanosleep_args *uap, register_t *retval)
381 {
382 /* {
383 syscallarg(clockid_t) which;
384 syscallarg(int) flags;
385 syscallarg(linux32_timespecp_t) rqtp;
386 syscallarg(linux32_timespecp_t) rmtp;
387 } */
388 struct linux32_timespec lrqts, lrmts;
389 struct timespec rqts, rmts;
390 int error, error1, flags;
391 clockid_t id;
392
393 flags = SCARG(uap, flags) != 0 ? TIMER_ABSTIME : 0;
394
395 error = linux_to_native_clockid(&id, SCARG(uap, which));
396 if (error != 0)
397 return error;
398
399 error = copyin(SCARG_P32(uap, rqtp), &lrqts, sizeof lrqts);
400 if (error != 0)
401 return error;
402 linux32_to_native_timespec(&rqts, &lrqts);
403
404 error = nanosleep1(l, id, flags, &rqts,
405 SCARG_P32(uap, rmtp) ? &rmts : NULL);
406 if (SCARG_P32(uap, rmtp) == NULL || (error != 0 && error != EINTR))
407 return error;
408
409 native_to_linux32_timespec(&lrmts, &rmts);
410 error1 = copyout(&lrmts, SCARG_P32(uap, rmtp), sizeof lrmts);
411 return error1 ? error1 : error;
412 }
413
414 int
linux32_sys_timer_create(struct lwp * l,const struct linux32_sys_timer_create_args * uap,register_t * retval)415 linux32_sys_timer_create(struct lwp *l,
416 const struct linux32_sys_timer_create_args *uap, register_t *retval)
417 {
418 /* {
419 syscallarg(clockid_t) clockid;
420 syscallarg(struct linux32_sigevent *) evp;
421 syscallarg(timer_t *) timerid;
422 } */
423 clockid_t id;
424 int error;
425
426 error = linux_to_native_timer_create_clockid(&id, SCARG(uap, clockid));
427 if (error == 0) {
428 error = timer_create1(SCARG(uap, timerid), id,
429 (void *)SCARG(uap, evp), linux32_sigevent_copyin, l);
430 }
431
432 return error;
433 }
434
435 int
linux32_sys_timer_settime(struct lwp * l,const struct linux32_sys_timer_settime_args * uap,register_t * retval)436 linux32_sys_timer_settime(struct lwp *l,
437 const struct linux32_sys_timer_settime_args *uap, register_t *retval)
438 {
439 /* {
440 syscallarg(timer_t) timerid;
441 syscallarg(int) flags;
442 syscallarg(const struct linux32_itimerspec *) tim;
443 syscallarg(struct linux32_itimerspec *) otim;
444 } */
445 struct itimerspec value, ovalue, *ovp = NULL;
446 struct linux32_itimerspec tim, otim;
447 int error;
448
449 error = copyin(SCARG(uap, tim), &tim, sizeof(tim));
450 if (error) {
451 return error;
452 }
453 linux32_to_native_itimerspec(&value, &tim);
454
455 if (SCARG(uap, otim)) {
456 ovp = &ovalue;
457 }
458
459 if (SCARG(uap, flags) & ~TIMER_ABSTIME) {
460 return EINVAL;
461 }
462
463 error = dotimer_settime(SCARG(uap, timerid), &value, ovp,
464 SCARG(uap, flags), l->l_proc);
465 if (error) {
466 return error;
467 }
468
469 if (ovp) {
470 native_to_linux32_itimerspec(&otim, ovp);
471 error = copyout(&otim, SCARG(uap, otim), sizeof(otim));
472 }
473
474 return error;
475 }
476
477 int
linux32_sys_timer_gettime(struct lwp * l,const struct linux32_sys_timer_gettime_args * uap,register_t * retval)478 linux32_sys_timer_gettime(struct lwp *l,
479 const struct linux32_sys_timer_gettime_args *uap, register_t *retval)
480 {
481 /* {
482 syscallarg(timer_t) timerid;
483 syscallarg(struct linux32_itimerspec *) tim;
484 } */
485 struct itimerspec its;
486 struct linux32_itimerspec lits;
487 int error;
488
489 error = dotimer_gettime(SCARG(uap, timerid), l->l_proc, &its);
490 if (error == 0) {
491 native_to_linux32_itimerspec(&lits, &its);
492 error = copyout(&lits, SCARG(uap, tim), sizeof(lits));
493 }
494
495 return error;
496 }
497
498 /*
499 * timer_gettoverrun(2) and timer_delete(2) are handled directly
500 * by the native calls.
501 */
502
503 /*
504 * timerfd_create() is handled by the standard COMPAT_LINUX call.
505 */
506
507 int
linux32_sys_timerfd_gettime(struct lwp * l,const struct linux32_sys_timerfd_gettime_args * uap,register_t * retval)508 linux32_sys_timerfd_gettime(struct lwp *l,
509 const struct linux32_sys_timerfd_gettime_args *uap, register_t *retval)
510 {
511 /* {
512 syscallarg(int) fd;
513 syscallarg(struct linux32_itimerspec *) tim;
514 } */
515 struct itimerspec its;
516 struct linux32_itimerspec lits;
517 int error;
518
519 error = do_timerfd_gettime(l, SCARG(uap, fd), &its, retval);
520 if (error == 0) {
521 native_to_linux32_itimerspec(&lits, &its);
522 error = copyout(&lits, SCARG(uap, tim), sizeof(lits));
523 }
524
525 return error;
526 }
527
528 int
linux32_sys_timerfd_settime(struct lwp * l,const struct linux32_sys_timerfd_settime_args * uap,register_t * retval)529 linux32_sys_timerfd_settime(struct lwp *l,
530 const struct linux32_sys_timerfd_settime_args *uap, register_t *retval)
531 {
532 /* {
533 syscallarg(int) fd;
534 syscallarg(int) flags;
535 syscallarg(const struct linux32_itimerspec *) tim;
536 syscallarg(struct linux32_itimerspec *) otim;
537 } */
538 struct itimerspec nits, oits, *oitsp = NULL;
539 struct linux32_itimerspec lits;
540 int nflags;
541 int error;
542
543 error = copyin(SCARG(uap, tim), &lits, sizeof(lits));
544 if (error) {
545 return error;
546 }
547 linux32_to_native_itimerspec(&nits, &lits);
548
549 error = linux_to_native_timerfd_settime_flags(&nflags,
550 SCARG(uap, flags));
551 if (error) {
552 return error;
553 }
554
555 if (SCARG(uap, otim)) {
556 oitsp = &oits;
557 }
558
559 error = do_timerfd_settime(l, SCARG(uap, fd), nflags,
560 &nits, oitsp, retval);
561 if (error == 0 && oitsp != NULL) {
562 native_to_linux32_itimerspec(&lits, oitsp);
563 error = copyout(&lits, SCARG(uap, otim), sizeof(lits));
564 }
565
566 return error;
567 }
568