1 | /* $NetBSD: kern_time_50.c,v 1.33 2019/01/27 02:08:39 pgoyette Exp $ */ |
2 | |
3 | /*- |
4 | * Copyright (c) 2008, 2009 The NetBSD Foundation, Inc. |
5 | * All rights reserved. |
6 | * |
7 | * This code is derived from software contributed to The NetBSD Foundation |
8 | * by Christos Zoulas. |
9 | * |
10 | * Redistribution and use in source and binary forms, with or without |
11 | * modification, are permitted provided that the following conditions |
12 | * are met: |
13 | * 1. Redistributions of source code must retain the above copyright |
14 | * notice, this list of conditions and the following disclaimer. |
15 | * 2. Redistributions in binary form must reproduce the above copyright |
16 | * notice, this list of conditions and the following disclaimer in the |
17 | * documentation and/or other materials provided with the distribution. |
18 | * |
19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
29 | * POSSIBILITY OF SUCH DAMAGE. |
30 | */ |
31 | #include <sys/cdefs.h> |
32 | __KERNEL_RCSID(0, "$NetBSD: kern_time_50.c,v 1.33 2019/01/27 02:08:39 pgoyette Exp $" ); |
33 | |
34 | #ifdef _KERNEL_OPT |
35 | #include "opt_compat_netbsd.h" |
36 | #include "opt_aio.h" |
37 | #include "opt_ntp.h" |
38 | #include "opt_mqueue.h" |
39 | #endif |
40 | |
41 | #include <sys/param.h> |
42 | #include <sys/conf.h> |
43 | #include <sys/systm.h> |
44 | #include <sys/namei.h> |
45 | #include <sys/filedesc.h> |
46 | #include <sys/kernel.h> |
47 | #include <sys/file.h> |
48 | #include <sys/stat.h> |
49 | #include <sys/socketvar.h> |
50 | #include <sys/vnode.h> |
51 | #include <sys/proc.h> |
52 | #include <sys/uio.h> |
53 | #include <sys/dirent.h> |
54 | #include <sys/kauth.h> |
55 | #include <sys/time.h> |
56 | #include <sys/timex.h> |
57 | #include <sys/clockctl.h> |
58 | #include <sys/aio.h> |
59 | #include <sys/poll.h> |
60 | #include <sys/syscall.h> |
61 | #include <sys/syscallargs.h> |
62 | #include <sys/syscallvar.h> |
63 | #include <sys/sysctl.h> |
64 | #include <sys/resource.h> |
65 | #include <sys/compat_stub.h> |
66 | |
67 | #include <compat/common/compat_util.h> |
68 | #include <compat/common/compat_mod.h> |
69 | #include <compat/sys/time.h> |
70 | #include <compat/sys/timex.h> |
71 | #include <compat/sys/resource.h> |
72 | #include <compat/sys/clockctl.h> |
73 | |
74 | struct timeval50 boottime50; |
75 | |
76 | static struct sysctllog *kern_time_50_clog = NULL; |
77 | |
78 | static const struct syscall_package kern_time_50_syscalls[] = { |
79 | { SYS_compat_50_clock_gettime, 0, |
80 | (sy_call_t *)compat_50_sys_clock_gettime }, |
81 | { SYS_compat_50_clock_settime, 0, |
82 | (sy_call_t *)compat_50_sys_clock_settime }, |
83 | { SYS_compat_50_clock_getres, 0, |
84 | (sy_call_t *)compat_50_sys_clock_getres}, |
85 | { SYS_compat_50_nanosleep, 0, (sy_call_t *)compat_50_sys_nanosleep }, |
86 | { SYS_compat_50_gettimeofday, 0, |
87 | (sy_call_t *)compat_50_sys_gettimeofday }, |
88 | { SYS_compat_50_settimeofday, 0, |
89 | (sy_call_t *)compat_50_sys_settimeofday }, |
90 | { SYS_compat_50_adjtime, 0, (sy_call_t *)compat_50_sys_adjtime }, |
91 | { SYS_compat_50_setitimer, 0, (sy_call_t *)compat_50_sys_setitimer }, |
92 | { SYS_compat_50_getitimer, 0, (sy_call_t *)compat_50_sys_getitimer }, |
93 | { SYS_compat_50_aio_suspend, 0, |
94 | (sy_call_t *)compat_50_sys_aio_suspend }, |
95 | { SYS_compat_50_mq_timedsend, 0, |
96 | (sy_call_t *)compat_50_sys_mq_timedsend }, |
97 | { SYS_compat_50_mq_timedreceive, 0, |
98 | (sy_call_t *)compat_50_sys_mq_timedreceive }, |
99 | { SYS_compat_50_getrusage, 0, (sy_call_t *)compat_50_sys_getrusage }, |
100 | { SYS_compat_50_timer_settime, 0, |
101 | (sy_call_t *)compat_50_sys_timer_settime }, |
102 | { SYS_compat_50_timer_gettime, 0, |
103 | (sy_call_t *)compat_50_sys_timer_gettime }, |
104 | { SYS_compat_50___ntp_gettime30, 0, |
105 | (sy_call_t *)compat_50_sys___ntp_gettime30 }, |
106 | { 0, 0, NULL } |
107 | }; |
108 | |
109 | int |
110 | compat_50_sys_clock_gettime(struct lwp *l, |
111 | const struct compat_50_sys_clock_gettime_args *uap, register_t *retval) |
112 | { |
113 | /* { |
114 | syscallarg(clockid_t) clock_id; |
115 | syscallarg(struct timespec50 *) tp; |
116 | } */ |
117 | int error; |
118 | struct timespec ats; |
119 | struct timespec50 ats50; |
120 | |
121 | error = clock_gettime1(SCARG(uap, clock_id), &ats); |
122 | if (error != 0) |
123 | return error; |
124 | |
125 | timespec_to_timespec50(&ats, &ats50); |
126 | |
127 | return copyout(&ats50, SCARG(uap, tp), sizeof(ats50)); |
128 | } |
129 | |
130 | /* ARGSUSED */ |
131 | int |
132 | compat_50_sys_clock_settime(struct lwp *l, |
133 | const struct compat_50_sys_clock_settime_args *uap, register_t *retval) |
134 | { |
135 | /* { |
136 | syscallarg(clockid_t) clock_id; |
137 | syscallarg(const struct timespec50 *) tp; |
138 | } */ |
139 | int error; |
140 | struct timespec ats; |
141 | struct timespec50 ats50; |
142 | |
143 | error = copyin(SCARG(uap, tp), &ats50, sizeof(ats50)); |
144 | if (error) |
145 | return error; |
146 | timespec50_to_timespec(&ats50, &ats); |
147 | |
148 | return clock_settime1(l->l_proc, SCARG(uap, clock_id), &ats, |
149 | true); |
150 | } |
151 | |
152 | |
153 | int |
154 | compat_50_sys_clock_getres(struct lwp *l, |
155 | const struct compat_50_sys_clock_getres_args *uap, register_t *retval) |
156 | { |
157 | /* { |
158 | syscallarg(clockid_t) clock_id; |
159 | syscallarg(struct timespec50 *) tp; |
160 | } */ |
161 | struct timespec50 ats50; |
162 | struct timespec ats; |
163 | int error; |
164 | |
165 | error = clock_getres1(SCARG(uap, clock_id), &ats); |
166 | if (error != 0) |
167 | return error; |
168 | |
169 | if (SCARG(uap, tp)) { |
170 | timespec_to_timespec50(&ats, &ats50); |
171 | error = copyout(&ats50, SCARG(uap, tp), sizeof(ats50)); |
172 | } |
173 | |
174 | return error; |
175 | } |
176 | |
177 | /* ARGSUSED */ |
178 | int |
179 | compat_50_sys_nanosleep(struct lwp *l, |
180 | const struct compat_50_sys_nanosleep_args *uap, register_t *retval) |
181 | { |
182 | /* { |
183 | syscallarg(struct timespec50 *) rqtp; |
184 | syscallarg(struct timespec50 *) rmtp; |
185 | } */ |
186 | struct timespec rmt, rqt; |
187 | struct timespec50 rmt50, rqt50; |
188 | int error, error1; |
189 | |
190 | error = copyin(SCARG(uap, rqtp), &rqt50, sizeof(rqt50)); |
191 | if (error) |
192 | return error; |
193 | timespec50_to_timespec(&rqt50, &rqt); |
194 | |
195 | error = nanosleep1(l, CLOCK_MONOTONIC, 0, &rqt, |
196 | SCARG(uap, rmtp) ? &rmt : NULL); |
197 | if (SCARG(uap, rmtp) == NULL || (error != 0 && error != EINTR)) |
198 | return error; |
199 | |
200 | timespec_to_timespec50(&rmt, &rmt50); |
201 | error1 = copyout(&rmt50, SCARG(uap, rmtp), sizeof(*SCARG(uap, rmtp))); |
202 | return error1 ? error1 : error; |
203 | } |
204 | |
205 | /* ARGSUSED */ |
206 | int |
207 | compat_50_sys_gettimeofday(struct lwp *l, |
208 | const struct compat_50_sys_gettimeofday_args *uap, register_t *retval) |
209 | { |
210 | /* { |
211 | syscallarg(struct timeval50 *) tp; |
212 | syscallarg(void *) tzp; really "struct timezone *"; |
213 | } */ |
214 | struct timeval atv; |
215 | struct timeval50 atv50; |
216 | int error = 0; |
217 | struct timezone tzfake; |
218 | |
219 | if (SCARG(uap, tp)) { |
220 | microtime(&atv); |
221 | timeval_to_timeval50(&atv, &atv50); |
222 | error = copyout(&atv50, SCARG(uap, tp), sizeof(*SCARG(uap, tp))); |
223 | if (error) |
224 | return error; |
225 | } |
226 | if (SCARG(uap, tzp)) { |
227 | /* |
228 | * NetBSD has no kernel notion of time zone, so we just |
229 | * fake up a timezone struct and return it if demanded. |
230 | */ |
231 | tzfake.tz_minuteswest = 0; |
232 | tzfake.tz_dsttime = 0; |
233 | error = copyout(&tzfake, SCARG(uap, tzp), sizeof(tzfake)); |
234 | } |
235 | return error; |
236 | } |
237 | |
238 | /* ARGSUSED */ |
239 | int |
240 | compat_50_sys_settimeofday(struct lwp *l, |
241 | const struct compat_50_sys_settimeofday_args *uap, register_t *retval) |
242 | { |
243 | /* { |
244 | syscallarg(const struct timeval50 *) tv; |
245 | syscallarg(const void *) tzp; really "const struct timezone *"; |
246 | } */ |
247 | struct timeval50 atv50; |
248 | struct timeval atv; |
249 | int error = copyin(SCARG(uap, tv), &atv50, sizeof(atv50)); |
250 | if (error) |
251 | return error; |
252 | timeval50_to_timeval(&atv50, &atv); |
253 | return settimeofday1(&atv, false, SCARG(uap, tzp), l, true); |
254 | } |
255 | |
256 | /* ARGSUSED */ |
257 | int |
258 | compat_50_sys_adjtime(struct lwp *l, |
259 | const struct compat_50_sys_adjtime_args *uap, register_t *retval) |
260 | { |
261 | /* { |
262 | syscallarg(const struct timeval50 *) delta; |
263 | syscallarg(struct timeval50 *) olddelta; |
264 | } */ |
265 | int error; |
266 | struct timeval50 delta50, olddelta50; |
267 | struct timeval delta, olddelta; |
268 | |
269 | if ((error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_TIME, |
270 | KAUTH_REQ_SYSTEM_TIME_ADJTIME, NULL, NULL, NULL)) != 0) |
271 | return error; |
272 | |
273 | if (SCARG(uap, delta)) { |
274 | error = copyin(SCARG(uap, delta), &delta50, |
275 | sizeof(*SCARG(uap, delta))); |
276 | if (error) |
277 | return (error); |
278 | timeval50_to_timeval(&delta50, &delta); |
279 | } |
280 | adjtime1(SCARG(uap, delta) ? &delta : NULL, |
281 | SCARG(uap, olddelta) ? &olddelta : NULL, l->l_proc); |
282 | if (SCARG(uap, olddelta)) { |
283 | timeval_to_timeval50(&olddelta, &olddelta50); |
284 | error = copyout(&olddelta50, SCARG(uap, olddelta), |
285 | sizeof(*SCARG(uap, olddelta))); |
286 | } |
287 | return error; |
288 | } |
289 | |
290 | /* BSD routine to set/arm an interval timer. */ |
291 | /* ARGSUSED */ |
292 | int |
293 | compat_50_sys_getitimer(struct lwp *l, |
294 | const struct compat_50_sys_getitimer_args *uap, register_t *retval) |
295 | { |
296 | /* { |
297 | syscallarg(int) which; |
298 | syscallarg(struct itimerval50 *) itv; |
299 | } */ |
300 | struct proc *p = l->l_proc; |
301 | struct itimerval aitv; |
302 | struct itimerval50 aitv50; |
303 | int error; |
304 | |
305 | error = dogetitimer(p, SCARG(uap, which), &aitv); |
306 | if (error) |
307 | return error; |
308 | itimerval_to_itimerval50(&aitv, &aitv50); |
309 | return copyout(&aitv50, SCARG(uap, itv), sizeof(*SCARG(uap, itv))); |
310 | } |
311 | |
312 | int |
313 | compat_50_sys_setitimer(struct lwp *l, |
314 | const struct compat_50_sys_setitimer_args *uap, register_t *retval) |
315 | { |
316 | /* { |
317 | syscallarg(int) which; |
318 | syscallarg(const struct itimerval50 *) itv; |
319 | syscallarg(struct itimerval50 *) oitv; |
320 | } */ |
321 | struct proc *p = l->l_proc; |
322 | int which = SCARG(uap, which); |
323 | struct compat_50_sys_getitimer_args getargs; |
324 | const struct itimerval50 *itvp; |
325 | struct itimerval50 aitv50; |
326 | struct itimerval aitv; |
327 | int error; |
328 | |
329 | if ((u_int)which > ITIMER_PROF) |
330 | return (EINVAL); |
331 | itvp = SCARG(uap, itv); |
332 | if (itvp && |
333 | (error = copyin(itvp, &aitv50, sizeof(aitv50))) != 0) |
334 | return (error); |
335 | itimerval50_to_itimerval(&aitv50, &aitv); |
336 | if (SCARG(uap, oitv) != NULL) { |
337 | SCARG(&getargs, which) = which; |
338 | SCARG(&getargs, itv) = SCARG(uap, oitv); |
339 | if ((error = compat_50_sys_getitimer(l, &getargs, retval)) != 0) |
340 | return (error); |
341 | } |
342 | if (itvp == 0) |
343 | return (0); |
344 | |
345 | return dosetitimer(p, which, &aitv); |
346 | } |
347 | |
348 | int |
349 | compat_50_sys_aio_suspend(struct lwp *l, |
350 | const struct compat_50_sys_aio_suspend_args *uap, register_t *retval) |
351 | { |
352 | /* { |
353 | syscallarg(const struct aiocb *const[]) list; |
354 | syscallarg(int) nent; |
355 | syscallarg(const struct timespec50 *) timeout; |
356 | } */ |
357 | #ifdef AIO |
358 | struct aiocb **list; |
359 | struct timespec ts; |
360 | struct timespec50 ts50; |
361 | int error, nent; |
362 | |
363 | nent = SCARG(uap, nent); |
364 | if (nent <= 0 || nent > aio_listio_max) |
365 | return EAGAIN; |
366 | |
367 | if (SCARG(uap, timeout)) { |
368 | /* Convert timespec to ticks */ |
369 | error = copyin(SCARG(uap, timeout), &ts50, |
370 | sizeof(*SCARG(uap, timeout))); |
371 | if (error) |
372 | return error; |
373 | timespec50_to_timespec(&ts50, &ts); |
374 | } |
375 | list = kmem_alloc(nent * sizeof(*list), KM_SLEEP); |
376 | error = copyin(SCARG(uap, list), list, nent * sizeof(*list)); |
377 | if (error) |
378 | goto out; |
379 | error = aio_suspend1(l, list, nent, SCARG(uap, timeout) ? &ts : NULL); |
380 | out: |
381 | kmem_free(list, nent * sizeof(*list)); |
382 | return error; |
383 | #else |
384 | return ENOSYS; |
385 | #endif |
386 | } |
387 | |
388 | int |
389 | compat_50_sys_mq_timedsend(struct lwp *l, |
390 | const struct compat_50_sys_mq_timedsend_args *uap, register_t *retval) |
391 | { |
392 | /* { |
393 | syscallarg(mqd_t) mqdes; |
394 | syscallarg(const char *) msg_ptr; |
395 | syscallarg(size_t) msg_len; |
396 | syscallarg(unsigned) msg_prio; |
397 | syscallarg(const struct timespec50 *) abs_timeout; |
398 | } */ |
399 | #ifdef MQUEUE |
400 | struct timespec50 ts50; |
401 | struct timespec ts, *tsp; |
402 | int error; |
403 | |
404 | /* Get and convert time value */ |
405 | if (SCARG(uap, abs_timeout)) { |
406 | error = copyin(SCARG(uap, abs_timeout), &ts50, sizeof(ts50)); |
407 | if (error) |
408 | return error; |
409 | timespec50_to_timespec(&ts50, &ts); |
410 | tsp = &ts; |
411 | } else { |
412 | tsp = NULL; |
413 | } |
414 | |
415 | return mq_send1(SCARG(uap, mqdes), SCARG(uap, msg_ptr), |
416 | SCARG(uap, msg_len), SCARG(uap, msg_prio), tsp); |
417 | #else |
418 | return ENOSYS; |
419 | #endif |
420 | } |
421 | |
422 | int |
423 | compat_50_sys_mq_timedreceive(struct lwp *l, |
424 | const struct compat_50_sys_mq_timedreceive_args *uap, register_t *retval) |
425 | { |
426 | /* { |
427 | syscallarg(mqd_t) mqdes; |
428 | syscallarg(char *) msg_ptr; |
429 | syscallarg(size_t) msg_len; |
430 | syscallarg(unsigned *) msg_prio; |
431 | syscallarg(const struct timespec50 *) abs_timeout; |
432 | } */ |
433 | #ifdef MQUEUE |
434 | struct timespec ts, *tsp; |
435 | struct timespec50 ts50; |
436 | ssize_t mlen; |
437 | int error; |
438 | |
439 | /* Get and convert time value */ |
440 | if (SCARG(uap, abs_timeout)) { |
441 | error = copyin(SCARG(uap, abs_timeout), &ts50, sizeof(ts50)); |
442 | if (error) |
443 | return error; |
444 | |
445 | timespec50_to_timespec(&ts50, &ts); |
446 | tsp = &ts; |
447 | } else { |
448 | tsp = NULL; |
449 | } |
450 | |
451 | error = mq_recv1(SCARG(uap, mqdes), SCARG(uap, msg_ptr), |
452 | SCARG(uap, msg_len), SCARG(uap, msg_prio), tsp, &mlen); |
453 | if (error == 0) |
454 | *retval = mlen; |
455 | |
456 | return error; |
457 | #else |
458 | return ENOSYS; |
459 | #endif |
460 | } |
461 | |
462 | void |
463 | rusage_to_rusage50(const struct rusage *ru, struct rusage50 *ru50) |
464 | { |
465 | (void)memcpy(&ru50->ru_first, &ru->ru_first, |
466 | (char *)&ru50->ru_last - (char *)&ru50->ru_first + |
467 | sizeof(ru50->ru_last)); |
468 | ru50->ru_maxrss = ru->ru_maxrss; |
469 | timeval_to_timeval50(&ru->ru_utime, &ru50->ru_utime); |
470 | timeval_to_timeval50(&ru->ru_stime, &ru50->ru_stime); |
471 | } |
472 | |
473 | int |
474 | compat_50_sys_getrusage(struct lwp *l, |
475 | const struct compat_50_sys_getrusage_args *uap, register_t *retval) |
476 | { |
477 | /* { |
478 | syscallarg(int) who; |
479 | syscallarg(struct rusage50 *) rusage; |
480 | } */ |
481 | int error; |
482 | struct rusage ru; |
483 | struct rusage50 ru50; |
484 | struct proc *p = l->l_proc; |
485 | |
486 | error = getrusage1(p, SCARG(uap, who), &ru); |
487 | if (error != 0) |
488 | return error; |
489 | |
490 | rusage_to_rusage50(&ru, &ru50); |
491 | return copyout(&ru50, SCARG(uap, rusage), sizeof(ru50)); |
492 | } |
493 | |
494 | |
495 | /* Return the time remaining until a POSIX timer fires. */ |
496 | int |
497 | compat_50_sys_timer_gettime(struct lwp *l, |
498 | const struct compat_50_sys_timer_gettime_args *uap, register_t *retval) |
499 | { |
500 | /* { |
501 | syscallarg(timer_t) timerid; |
502 | syscallarg(struct itimerspec50 *) value; |
503 | } */ |
504 | struct itimerspec its; |
505 | struct itimerspec50 its50; |
506 | int error; |
507 | |
508 | if ((error = dotimer_gettime(SCARG(uap, timerid), l->l_proc, |
509 | &its)) != 0) |
510 | return error; |
511 | itimerspec_to_itimerspec50(&its, &its50); |
512 | |
513 | return copyout(&its50, SCARG(uap, value), sizeof(its50)); |
514 | } |
515 | |
516 | /* Set and arm a POSIX realtime timer */ |
517 | int |
518 | compat_50_sys_timer_settime(struct lwp *l, |
519 | const struct compat_50_sys_timer_settime_args *uap, register_t *retval) |
520 | { |
521 | /* { |
522 | syscallarg(timer_t) timerid; |
523 | syscallarg(int) flags; |
524 | syscallarg(const struct itimerspec50 *) value; |
525 | syscallarg(struct itimerspec50 *) ovalue; |
526 | } */ |
527 | int error; |
528 | struct itimerspec value, ovalue, *ovp = NULL; |
529 | struct itimerspec50 value50, ovalue50; |
530 | |
531 | if ((error = copyin(SCARG(uap, value), &value50, sizeof(value50))) != 0) |
532 | return error; |
533 | |
534 | itimerspec50_to_itimerspec(&value50, &value); |
535 | if (SCARG(uap, ovalue)) |
536 | ovp = &ovalue; |
537 | |
538 | if ((error = dotimer_settime(SCARG(uap, timerid), &value, ovp, |
539 | SCARG(uap, flags), l->l_proc)) != 0) |
540 | return error; |
541 | |
542 | if (ovp) { |
543 | itimerspec_to_itimerspec50(&ovalue, &ovalue50); |
544 | return copyout(&ovalue50, SCARG(uap, ovalue), sizeof(ovalue50)); |
545 | } |
546 | return 0; |
547 | } |
548 | |
549 | /* |
550 | * ntp_gettime() - NTP user application interface |
551 | */ |
552 | int |
553 | compat_50_sys___ntp_gettime30(struct lwp *l, |
554 | const struct compat_50_sys___ntp_gettime30_args *uap, register_t *retval) |
555 | { |
556 | if (vec_ntp_gettime == NULL) |
557 | return ENOSYS; /* No NTP available in kernel */ |
558 | |
559 | /* { |
560 | syscallarg(struct ntptimeval *) ntvp; |
561 | } */ |
562 | struct ntptimeval ntv; |
563 | struct ntptimeval50 ntv50; |
564 | int error; |
565 | |
566 | if (SCARG(uap, ntvp)) { |
567 | (*vec_ntp_gettime)(&ntv); |
568 | memset(&ntv50, 0, sizeof(ntv50)); |
569 | timespec_to_timespec50(&ntv.time, &ntv50.time); |
570 | ntv50.maxerror = ntv.maxerror; |
571 | ntv50.esterror = ntv.esterror; |
572 | ntv50.tai = ntv.tai; |
573 | ntv50.time_state = ntv.time_state; |
574 | |
575 | error = copyout(&ntv50, SCARG(uap, ntvp), sizeof(ntv50)); |
576 | if (error) |
577 | return error; |
578 | } |
579 | *retval = (*vec_ntp_timestatus)(); |
580 | return 0; |
581 | } |
582 | |
583 | static void |
584 | compat_sysctl_time(struct sysctllog **clog) |
585 | { |
586 | struct timeval tv; |
587 | |
588 | TIMESPEC_TO_TIMEVAL(&tv, &boottime); |
589 | timeval_to_timeval50(&tv, &boottime50); |
590 | |
591 | sysctl_createv(clog, 0, NULL, NULL, |
592 | CTLFLAG_PERMANENT, |
593 | CTLTYPE_STRUCT, "oboottime" , |
594 | SYSCTL_DESCR("System boot time" ), |
595 | NULL, 0, &boottime50, sizeof(boottime50), |
596 | CTL_KERN, KERN_OBOOTTIME, CTL_EOL); |
597 | } |
598 | |
599 | int |
600 | kern_time_50_init(void) |
601 | { |
602 | int error; |
603 | |
604 | compat_sysctl_time(&kern_time_50_clog); |
605 | |
606 | error = syscall_establish(NULL, kern_time_50_syscalls); |
607 | if (error != 0) |
608 | sysctl_teardown(&kern_time_50_clog); |
609 | |
610 | return error; |
611 | } |
612 | |
613 | int |
614 | kern_time_50_fini(void) |
615 | { |
616 | int error; |
617 | |
618 | error = syscall_disestablish(NULL, kern_time_50_syscalls); |
619 | if (error == 0) |
620 | sysctl_teardown(&kern_time_50_clog); |
621 | |
622 | return error; |
623 | } |
624 | |