/*
 * ntp_adjtime() - NTP daemon application interface
 */
int
sys_ntp_adjtime(struct lwp *l, const struct sys_ntp_adjtime_args *uap, register_t *retval)
{
	/* {
		syscallarg(struct timex *) tp;
	} */
	struct timex ntv;
	int error = 0;

	error = copyin((void *)SCARG(uap, tp), (void *)&ntv, sizeof(ntv));
	if (error != 0)
		return (error);

	if (ntv.modes != 0 && (error = kauth_authorize_system(l->l_cred,
	    KAUTH_SYSTEM_TIME, KAUTH_REQ_SYSTEM_TIME_NTPADJTIME, NULL,
	    NULL, NULL)) != 0)
		return (error);

	ntp_adjtime1(&ntv);

	error = copyout((void *)&ntv, (void *)SCARG(uap, tp), sizeof(ntv));
	if (!error)
		*retval = ntp_timestatus();

	return error;
}
int
netbsd32_ntp_adjtime(struct lwp *l, const struct netbsd32_ntp_adjtime_args *uap, register_t *retval)
{
	/* {
		syscallarg(netbsd32_timexp_t) tp;
	} */
	struct netbsd32_timex ntv32;
	struct timex ntv;
	int error = 0;
	int modes;

	if ((error = copyin(SCARG_P32(uap, tp), &ntv32, sizeof(ntv32))))
		return (error);

	netbsd32_to_timex(&ntv32, &ntv);

	/*
	 * Update selected clock variables - only the superuser can
	 * change anything. Note that there is no error checking here on
	 * the assumption the superuser should know what it is doing.
	 */
	modes = ntv.modes;
	if (modes != 0 && (error = kauth_authorize_system(l->l_cred,
	    KAUTH_SYSTEM_TIME, KAUTH_REQ_SYSTEM_TIME_NTPADJTIME, NULL, NULL,
	    NULL)))
		return (error);

	ntp_adjtime1(&ntv);

	netbsd32_from_timex(&ntv, &ntv32);
	error = copyout(&ntv32, SCARG_P32(uap, tp), sizeof(ntv32));
	if (!error) {
		*retval = ntp_timestatus();
	}
	return error;
}
int
clockctlioctl(
    dev_t dev,
    u_long cmd,
    void *data,
    int flags,
    struct lwp *l)
{
	int error = 0;

	switch (cmd) {
	case CLOCKCTL_SETTIMEOFDAY: {
		struct clockctl_settimeofday *args = data;

		error = settimeofday1(args->tv, true, args->tzp, l, false);
		break;
	}
	case CLOCKCTL_ADJTIME: {
		struct timeval atv, oldatv;
		struct clockctl_adjtime *args = data;

		if (args->delta) {
			error = copyin(args->delta, &atv, sizeof(atv));
			if (error)
				return (error);
		}
		adjtime1(args->delta ? &atv : NULL,
		    args->olddelta ? &oldatv : NULL, l->l_proc);
		if (args->olddelta)
			error = copyout(&oldatv, args->olddelta,
			    sizeof(oldatv));
		break;
	}
	case CLOCKCTL_CLOCK_SETTIME: {
		struct clockctl_clock_settime *args = data;
		struct timespec ts;

		error = copyin(args->tp, &ts, sizeof ts);
		if (error)
			return (error);
		error = clock_settime1(l->l_proc, args->clock_id, &ts, false);
		break;
	}
#ifdef NTP
	case CLOCKCTL_NTP_ADJTIME: {
		struct clockctl_ntp_adjtime *args = data;
		struct timex ntv;

		error = copyin(args->tp, &ntv, sizeof(ntv));
		if (error)
			return (error);

		ntp_adjtime1(&ntv);

		error = copyout(&ntv, args->tp, sizeof(ntv));
		if (error == 0)
			args->retval = ntp_timestatus();
		break;
	}
#endif /* NTP */
	default:
#ifdef COMPAT_50
		error = compat50_clockctlioctl(dev, cmd, data, flags, l);
#else
		error = EINVAL;
#endif
	}

	return (error);
}