1 /* $NetBSD: kern_time_50.c,v 1.31 2016/03/11 18:32:29 christos 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.31 2016/03/11 18:32:29 christos Exp $"); 33 34 #ifdef _KERNEL_OPT 35 #include "opt_aio.h" 36 #include "opt_ntp.h" 37 #include "opt_mqueue.h" 38 #endif 39 40 #include <sys/param.h> 41 #include <sys/conf.h> 42 #include <sys/systm.h> 43 #include <sys/namei.h> 44 #include <sys/filedesc.h> 45 #include <sys/kernel.h> 46 #include <sys/file.h> 47 #include <sys/stat.h> 48 #include <sys/socketvar.h> 49 #include <sys/vnode.h> 50 #include <sys/proc.h> 51 #include <sys/uio.h> 52 #include <sys/dirent.h> 53 #include <sys/kauth.h> 54 #include <sys/time.h> 55 #include <sys/timex.h> 56 #include <sys/clockctl.h> 57 #include <sys/aio.h> 58 #include <sys/poll.h> 59 #include <sys/syscallargs.h> 60 #include <sys/sysctl.h> 61 #include <sys/resource.h> 62 63 #include <compat/common/compat_util.h> 64 #include <compat/common/compat_mod.h> 65 #include <compat/sys/time.h> 66 #include <compat/sys/timex.h> 67 #include <compat/sys/resource.h> 68 #include <compat/sys/clockctl.h> 69 70 struct timeval50 boottime50; 71 72 int 73 compat_50_sys_clock_gettime(struct lwp *l, 74 const struct compat_50_sys_clock_gettime_args *uap, register_t *retval) 75 { 76 /* { 77 syscallarg(clockid_t) clock_id; 78 syscallarg(struct timespec50 *) tp; 79 } */ 80 int error; 81 struct timespec ats; 82 struct timespec50 ats50; 83 84 error = clock_gettime1(SCARG(uap, clock_id), &ats); 85 if (error != 0) 86 return error; 87 88 timespec_to_timespec50(&ats, &ats50); 89 90 return copyout(&ats50, SCARG(uap, tp), sizeof(ats50)); 91 } 92 93 /* ARGSUSED */ 94 int 95 compat_50_sys_clock_settime(struct lwp *l, 96 const struct compat_50_sys_clock_settime_args *uap, register_t *retval) 97 { 98 /* { 99 syscallarg(clockid_t) clock_id; 100 syscallarg(const struct timespec50 *) tp; 101 } */ 102 int error; 103 struct timespec ats; 104 struct timespec50 ats50; 105 106 error = copyin(SCARG(uap, tp), &ats50, sizeof(ats50)); 107 if (error) 108 return error; 109 timespec50_to_timespec(&ats50, &ats); 110 111 return clock_settime1(l->l_proc, SCARG(uap, clock_id), &ats, 112 true); 113 } 114 115 116 int 117 compat_50_sys_clock_getres(struct lwp *l, 118 const struct compat_50_sys_clock_getres_args *uap, register_t *retval) 119 { 120 /* { 121 syscallarg(clockid_t) clock_id; 122 syscallarg(struct timespec50 *) tp; 123 } */ 124 struct timespec50 ats50; 125 struct timespec ats; 126 int error; 127 128 error = clock_getres1(SCARG(uap, clock_id), &ats); 129 if (error != 0) 130 return error; 131 132 if (SCARG(uap, tp)) { 133 timespec_to_timespec50(&ats, &ats50); 134 error = copyout(&ats50, SCARG(uap, tp), sizeof(ats50)); 135 } 136 137 return error; 138 } 139 140 /* ARGSUSED */ 141 int 142 compat_50_sys_nanosleep(struct lwp *l, 143 const struct compat_50_sys_nanosleep_args *uap, register_t *retval) 144 { 145 /* { 146 syscallarg(struct timespec50 *) rqtp; 147 syscallarg(struct timespec50 *) rmtp; 148 } */ 149 struct timespec rmt, rqt; 150 struct timespec50 rmt50, rqt50; 151 int error, error1; 152 153 error = copyin(SCARG(uap, rqtp), &rqt50, sizeof(rqt50)); 154 if (error) 155 return error; 156 timespec50_to_timespec(&rqt50, &rqt); 157 158 error = nanosleep1(l, CLOCK_MONOTONIC, 0, &rqt, 159 SCARG(uap, rmtp) ? &rmt : NULL); 160 if (SCARG(uap, rmtp) == NULL || (error != 0 && error != EINTR)) 161 return error; 162 163 timespec_to_timespec50(&rmt, &rmt50); 164 error1 = copyout(&rmt50, SCARG(uap, rmtp), sizeof(*SCARG(uap, rmtp))); 165 return error1 ? error1 : error; 166 } 167 168 /* ARGSUSED */ 169 int 170 compat_50_sys_gettimeofday(struct lwp *l, 171 const struct compat_50_sys_gettimeofday_args *uap, register_t *retval) 172 { 173 /* { 174 syscallarg(struct timeval50 *) tp; 175 syscallarg(void *) tzp; really "struct timezone *"; 176 } */ 177 struct timeval atv; 178 struct timeval50 atv50; 179 int error = 0; 180 struct timezone tzfake; 181 182 if (SCARG(uap, tp)) { 183 microtime(&atv); 184 timeval_to_timeval50(&atv, &atv50); 185 error = copyout(&atv50, SCARG(uap, tp), sizeof(*SCARG(uap, tp))); 186 if (error) 187 return error; 188 } 189 if (SCARG(uap, tzp)) { 190 /* 191 * NetBSD has no kernel notion of time zone, so we just 192 * fake up a timezone struct and return it if demanded. 193 */ 194 tzfake.tz_minuteswest = 0; 195 tzfake.tz_dsttime = 0; 196 error = copyout(&tzfake, SCARG(uap, tzp), sizeof(tzfake)); 197 } 198 return error; 199 } 200 201 /* ARGSUSED */ 202 int 203 compat_50_sys_settimeofday(struct lwp *l, 204 const struct compat_50_sys_settimeofday_args *uap, register_t *retval) 205 { 206 /* { 207 syscallarg(const struct timeval50 *) tv; 208 syscallarg(const void *) tzp; really "const struct timezone *"; 209 } */ 210 struct timeval50 atv50; 211 struct timeval atv; 212 int error = copyin(SCARG(uap, tv), &atv50, sizeof(atv50)); 213 if (error) 214 return error; 215 timeval50_to_timeval(&atv50, &atv); 216 return settimeofday1(&atv, false, SCARG(uap, tzp), l, true); 217 } 218 219 /* ARGSUSED */ 220 int 221 compat_50_sys_adjtime(struct lwp *l, 222 const struct compat_50_sys_adjtime_args *uap, register_t *retval) 223 { 224 /* { 225 syscallarg(const struct timeval50 *) delta; 226 syscallarg(struct timeval50 *) olddelta; 227 } */ 228 int error; 229 struct timeval50 delta50, olddelta50; 230 struct timeval delta, olddelta; 231 232 if ((error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_TIME, 233 KAUTH_REQ_SYSTEM_TIME_ADJTIME, NULL, NULL, NULL)) != 0) 234 return error; 235 236 if (SCARG(uap, delta)) { 237 error = copyin(SCARG(uap, delta), &delta50, 238 sizeof(*SCARG(uap, delta))); 239 if (error) 240 return (error); 241 timeval50_to_timeval(&delta50, &delta); 242 } 243 adjtime1(SCARG(uap, delta) ? &delta : NULL, 244 SCARG(uap, olddelta) ? &olddelta : NULL, l->l_proc); 245 if (SCARG(uap, olddelta)) { 246 timeval_to_timeval50(&olddelta, &olddelta50); 247 error = copyout(&olddelta50, SCARG(uap, olddelta), 248 sizeof(*SCARG(uap, olddelta))); 249 } 250 return error; 251 } 252 253 /* BSD routine to set/arm an interval timer. */ 254 /* ARGSUSED */ 255 int 256 compat_50_sys_getitimer(struct lwp *l, 257 const struct compat_50_sys_getitimer_args *uap, register_t *retval) 258 { 259 /* { 260 syscallarg(int) which; 261 syscallarg(struct itimerval50 *) itv; 262 } */ 263 struct proc *p = l->l_proc; 264 struct itimerval aitv; 265 struct itimerval50 aitv50; 266 int error; 267 268 error = dogetitimer(p, SCARG(uap, which), &aitv); 269 if (error) 270 return error; 271 itimerval_to_itimerval50(&aitv, &aitv50); 272 return copyout(&aitv50, SCARG(uap, itv), sizeof(*SCARG(uap, itv))); 273 } 274 275 int 276 compat_50_sys_setitimer(struct lwp *l, 277 const struct compat_50_sys_setitimer_args *uap, register_t *retval) 278 { 279 /* { 280 syscallarg(int) which; 281 syscallarg(const struct itimerval50 *) itv; 282 syscallarg(struct itimerval50 *) oitv; 283 } */ 284 struct proc *p = l->l_proc; 285 int which = SCARG(uap, which); 286 struct compat_50_sys_getitimer_args getargs; 287 const struct itimerval50 *itvp; 288 struct itimerval50 aitv50; 289 struct itimerval aitv; 290 int error; 291 292 if ((u_int)which > ITIMER_PROF) 293 return (EINVAL); 294 itvp = SCARG(uap, itv); 295 if (itvp && 296 (error = copyin(itvp, &aitv50, sizeof(aitv50))) != 0) 297 return (error); 298 itimerval50_to_itimerval(&aitv50, &aitv); 299 if (SCARG(uap, oitv) != NULL) { 300 SCARG(&getargs, which) = which; 301 SCARG(&getargs, itv) = SCARG(uap, oitv); 302 if ((error = compat_50_sys_getitimer(l, &getargs, retval)) != 0) 303 return (error); 304 } 305 if (itvp == 0) 306 return (0); 307 308 return dosetitimer(p, which, &aitv); 309 } 310 311 int 312 compat_50_sys_aio_suspend(struct lwp *l, 313 const struct compat_50_sys_aio_suspend_args *uap, register_t *retval) 314 { 315 /* { 316 syscallarg(const struct aiocb *const[]) list; 317 syscallarg(int) nent; 318 syscallarg(const struct timespec50 *) timeout; 319 } */ 320 #ifdef AIO 321 struct aiocb **list; 322 struct timespec ts; 323 struct timespec50 ts50; 324 int error, nent; 325 326 nent = SCARG(uap, nent); 327 if (nent <= 0 || nent > aio_listio_max) 328 return EAGAIN; 329 330 if (SCARG(uap, timeout)) { 331 /* Convert timespec to ticks */ 332 error = copyin(SCARG(uap, timeout), &ts50, 333 sizeof(*SCARG(uap, timeout))); 334 if (error) 335 return error; 336 timespec50_to_timespec(&ts50, &ts); 337 } 338 list = kmem_alloc(nent * sizeof(*list), KM_SLEEP); 339 error = copyin(SCARG(uap, list), list, nent * sizeof(*list)); 340 if (error) 341 goto out; 342 error = aio_suspend1(l, list, nent, SCARG(uap, timeout) ? &ts : NULL); 343 out: 344 kmem_free(list, nent * sizeof(*list)); 345 return error; 346 #else 347 return ENOSYS; 348 #endif 349 } 350 351 int 352 compat_50_sys_mq_timedsend(struct lwp *l, 353 const struct compat_50_sys_mq_timedsend_args *uap, register_t *retval) 354 { 355 /* { 356 syscallarg(mqd_t) mqdes; 357 syscallarg(const char *) msg_ptr; 358 syscallarg(size_t) msg_len; 359 syscallarg(unsigned) msg_prio; 360 syscallarg(const struct timespec50 *) abs_timeout; 361 } */ 362 #ifdef MQUEUE 363 struct timespec50 ts50; 364 struct timespec ts, *tsp; 365 int error; 366 367 /* Get and convert time value */ 368 if (SCARG(uap, abs_timeout)) { 369 error = copyin(SCARG(uap, abs_timeout), &ts50, sizeof(ts50)); 370 if (error) 371 return error; 372 timespec50_to_timespec(&ts50, &ts); 373 tsp = &ts; 374 } else { 375 tsp = NULL; 376 } 377 378 return mq_send1(SCARG(uap, mqdes), SCARG(uap, msg_ptr), 379 SCARG(uap, msg_len), SCARG(uap, msg_prio), tsp); 380 #else 381 return ENOSYS; 382 #endif 383 } 384 385 int 386 compat_50_sys_mq_timedreceive(struct lwp *l, 387 const struct compat_50_sys_mq_timedreceive_args *uap, register_t *retval) 388 { 389 /* { 390 syscallarg(mqd_t) mqdes; 391 syscallarg(char *) msg_ptr; 392 syscallarg(size_t) msg_len; 393 syscallarg(unsigned *) msg_prio; 394 syscallarg(const struct timespec50 *) abs_timeout; 395 } */ 396 #ifdef MQUEUE 397 struct timespec ts, *tsp; 398 struct timespec50 ts50; 399 ssize_t mlen; 400 int error; 401 402 /* Get and convert time value */ 403 if (SCARG(uap, abs_timeout)) { 404 error = copyin(SCARG(uap, abs_timeout), &ts50, sizeof(ts50)); 405 if (error) 406 return error; 407 408 timespec50_to_timespec(&ts50, &ts); 409 tsp = &ts; 410 } else { 411 tsp = NULL; 412 } 413 414 error = mq_recv1(SCARG(uap, mqdes), SCARG(uap, msg_ptr), 415 SCARG(uap, msg_len), SCARG(uap, msg_prio), tsp, &mlen); 416 if (error == 0) 417 *retval = mlen; 418 419 return error; 420 #else 421 return ENOSYS; 422 #endif 423 } 424 425 void 426 rusage_to_rusage50(const struct rusage *ru, struct rusage50 *ru50) 427 { 428 (void)memcpy(&ru50->ru_first, &ru->ru_first, 429 (char *)&ru50->ru_last - (char *)&ru50->ru_first + 430 sizeof(ru50->ru_last)); 431 ru50->ru_maxrss = ru->ru_maxrss; 432 timeval_to_timeval50(&ru->ru_utime, &ru50->ru_utime); 433 timeval_to_timeval50(&ru->ru_stime, &ru50->ru_stime); 434 } 435 436 int 437 compat_50_sys_getrusage(struct lwp *l, 438 const struct compat_50_sys_getrusage_args *uap, register_t *retval) 439 { 440 /* { 441 syscallarg(int) who; 442 syscallarg(struct rusage50 *) rusage; 443 } */ 444 int error; 445 struct rusage ru; 446 struct rusage50 ru50; 447 struct proc *p = l->l_proc; 448 449 error = getrusage1(p, SCARG(uap, who), &ru); 450 if (error != 0) 451 return error; 452 453 rusage_to_rusage50(&ru, &ru50); 454 return copyout(&ru50, SCARG(uap, rusage), sizeof(ru50)); 455 } 456 457 458 /* Return the time remaining until a POSIX timer fires. */ 459 int 460 compat_50_sys_timer_gettime(struct lwp *l, 461 const struct compat_50_sys_timer_gettime_args *uap, register_t *retval) 462 { 463 /* { 464 syscallarg(timer_t) timerid; 465 syscallarg(struct itimerspec50 *) value; 466 } */ 467 struct itimerspec its; 468 struct itimerspec50 its50; 469 int error; 470 471 if ((error = dotimer_gettime(SCARG(uap, timerid), l->l_proc, 472 &its)) != 0) 473 return error; 474 itimerspec_to_itimerspec50(&its, &its50); 475 476 return copyout(&its50, SCARG(uap, value), sizeof(its50)); 477 } 478 479 /* Set and arm a POSIX realtime timer */ 480 int 481 compat_50_sys_timer_settime(struct lwp *l, 482 const struct compat_50_sys_timer_settime_args *uap, register_t *retval) 483 { 484 /* { 485 syscallarg(timer_t) timerid; 486 syscallarg(int) flags; 487 syscallarg(const struct itimerspec50 *) value; 488 syscallarg(struct itimerspec50 *) ovalue; 489 } */ 490 int error; 491 struct itimerspec value, ovalue, *ovp = NULL; 492 struct itimerspec50 value50, ovalue50; 493 494 if ((error = copyin(SCARG(uap, value), &value50, sizeof(value50))) != 0) 495 return error; 496 497 itimerspec50_to_itimerspec(&value50, &value); 498 if (SCARG(uap, ovalue)) 499 ovp = &ovalue; 500 501 if ((error = dotimer_settime(SCARG(uap, timerid), &value, ovp, 502 SCARG(uap, flags), l->l_proc)) != 0) 503 return error; 504 505 if (ovp) { 506 itimerspec_to_itimerspec50(&ovalue, &ovalue50); 507 return copyout(&ovalue50, SCARG(uap, ovalue), sizeof(ovalue50)); 508 } 509 return 0; 510 } 511 512 /* 513 * ntp_gettime() - NTP user application interface 514 */ 515 int 516 compat_50_sys___ntp_gettime30(struct lwp *l, 517 const struct compat_50_sys___ntp_gettime30_args *uap, register_t *retval) 518 { 519 #ifdef NTP 520 /* { 521 syscallarg(struct ntptimeval *) ntvp; 522 } */ 523 struct ntptimeval ntv; 524 struct ntptimeval50 ntv50; 525 int error; 526 527 if (SCARG(uap, ntvp)) { 528 ntp_gettime(&ntv); 529 timespec_to_timespec50(&ntv.time, &ntv50.time); 530 ntv50.maxerror = ntv.maxerror; 531 ntv50.esterror = ntv.esterror; 532 ntv50.tai = ntv.tai; 533 ntv50.time_state = ntv.time_state; 534 535 error = copyout(&ntv50, SCARG(uap, ntvp), sizeof(ntv50)); 536 if (error) 537 return error; 538 } 539 *retval = ntp_timestatus(); 540 return 0; 541 #else 542 return ENOSYS; 543 #endif 544 } 545 546 void 547 compat_sysctl_time(struct sysctllog **clog) 548 { 549 struct timeval tv; 550 551 TIMESPEC_TO_TIMEVAL(&tv, &boottime); 552 timeval_to_timeval50(&tv, &boottime50); 553 554 sysctl_createv(clog, 0, NULL, NULL, 555 CTLFLAG_PERMANENT, 556 CTLTYPE_STRUCT, "oboottime", 557 SYSCTL_DESCR("System boot time"), 558 NULL, 0, &boottime50, sizeof(boottime50), 559 CTL_KERN, KERN_OBOOTTIME, CTL_EOL); 560 } 561