Home | History | Annotate | Line # | Download | only in common
linux32_time.c revision 1.21
      1 /*	$NetBSD: linux32_time.c,v 1.21 2008/09/08 15:31:19 christos 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.21 2008/09/08 15:31:19 christos 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 #include <sys/timetc.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/linux_syscallargs.h>
     70 
     71 #include <compat/linux32/common/linux32_types.h>
     72 #include <compat/linux32/common/linux32_signal.h>
     73 #include <compat/linux32/common/linux32_machdep.h>
     74 #include <compat/linux32/common/linux32_sysctl.h>
     75 #include <compat/linux32/common/linux32_socketcall.h>
     76 #include <compat/linux32/linux32_syscallargs.h>
     77 
     78 extern struct timezone linux_sys_tz;
     79 
     80 static __inline void
     81 native_to_linux32_timespec(struct linux32_timespec *, struct timespec *);
     82 static __inline void
     83 linux32_to_native_timespec(struct timespec *, struct linux32_timespec *);
     84 
     85 int
     86 linux32_sys_gettimeofday(struct lwp *l, const struct linux32_sys_gettimeofday_args *uap, register_t *retval)
     87 {
     88 	/* {
     89 		syscallarg(netbsd32_timevalp_t) tp;
     90 		syscallarg(netbsd32_timezonep_t) tzp;
     91 	} */
     92 	struct timeval tv;
     93 	struct netbsd32_timeval tv32;
     94 	int error;
     95 
     96 	if (SCARG_P32(uap, tp) != NULL) {
     97 		microtime(&tv);
     98 		netbsd32_from_timeval(&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
    115 linux32_sys_settimeofday(struct lwp *l, const struct linux32_sys_settimeofday_args *uap, register_t *retval)
    116 {
    117 	/* {
    118 		syscallarg(netbsd32_timevalp_t) tp;
    119 		syscallarg(netbsd32_timezonep_t) tzp;
    120 	} */
    121 	struct linux_sys_settimeofday_args ua;
    122 
    123 	NETBSD32TOP_UAP(tp, struct timeval);
    124 	NETBSD32TOP_UAP(tzp, struct timezone);
    125 
    126 	return linux_sys_settimeofday(l, &ua, retval);
    127 }
    128 
    129 int
    130 linux32_sys_time(struct lwp *l, const struct linux32_sys_time_args *uap, register_t *retval)
    131 {
    132 	/* {
    133 		syscallcarg(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 static inline linux32_clock_t
    154 timeval_to_clock_t(struct timeval *tv)
    155 {
    156 	return tv->tv_sec * hz + tv->tv_usec / (1000000 / hz);
    157 }
    158 
    159 #define	CONVTCK(r)	(r.tv_sec * hz + r.tv_usec / (1000000 / hz))
    160 
    161 int
    162 linux32_sys_times(struct lwp *l, const struct linux32_sys_times_args *uap, register_t *retval)
    163 {
    164 	/* {
    165 		syscallarg(linux32_tmsp_t) tms;
    166 	} */
    167 	struct proc *p = l->l_proc;
    168 	struct timeval t;
    169 	int error;
    170 
    171 	if (SCARG_P32(uap, tms)) {
    172 		struct linux32_tms ltms32;
    173 		struct rusage ru;
    174 
    175 		mutex_enter(p->p_lock);
    176 		calcru(p, &ru.ru_utime, &ru.ru_stime, NULL, NULL);
    177 		ltms32.ltms32_utime = CONVTCK(ru.ru_utime);
    178 		ltms32.ltms32_stime = CONVTCK(ru.ru_stime);
    179 		ltms32.ltms32_cutime = CONVTCK(p->p_stats->p_cru.ru_utime);
    180 		ltms32.ltms32_cstime = CONVTCK(p->p_stats->p_cru.ru_stime);
    181 		mutex_exit(p->p_lock);
    182 
    183 		error = copyout(&ltms32, SCARG_P32(uap, tms), sizeof(ltms32));
    184 		if (error)
    185 			return error;
    186 	}
    187 
    188 	getmicrouptime(&t);
    189 
    190 	retval[0] = ((linux32_clock_t)(CONVTCK(t)));
    191 	return 0;
    192 }
    193 
    194 #undef CONVTCK
    195 
    196 int
    197 linux32_sys_stime(struct lwp *l, const struct linux32_sys_stime_args *uap, register_t *retval)
    198 {
    199 	/* {
    200 		syscallarg(linux32_timep_t) t;
    201 	} */
    202 	struct timespec ts;
    203 	linux32_time_t tt32;
    204 	int error;
    205 
    206 	if ((error = copyin(&tt32, SCARG_P32(uap, t), sizeof tt32)) != 0)
    207 		return error;
    208 
    209 	ts.tv_sec = (long)tt32;
    210 	ts.tv_nsec = 0;
    211 
    212 	return settime(l->l_proc, &ts);
    213 }
    214 
    215 int
    216 linux32_sys_utime(struct lwp *l, const struct linux32_sys_utime_args *uap, register_t *retval)
    217 {
    218 	/* {
    219 		syscallarg(const netbsd32_charp) path;
    220 		syscallarg(linux32_utimbufp_t) times;
    221 	} */
    222         struct timeval tv[2], *tvp;
    223         struct linux32_utimbuf lut;
    224         int error;
    225 
    226         if (SCARG_P32(uap, times) != NULL) {
    227                 if ((error = copyin(SCARG_P32(uap, times), &lut, sizeof lut)))
    228                         return error;
    229 
    230                 tv[0].tv_sec = (long)lut.l_actime;
    231                 tv[0].tv_usec = 0;
    232                 tv[1].tv_sec = (long)lut.l_modtime;
    233 		tv[1].tv_usec = 0;
    234                 tvp = tv;
    235         } else {
    236 		tvp = NULL;
    237 	}
    238 
    239         return do_sys_utimes(l, NULL, SCARG_P32(uap, path), FOLLOW,
    240 			    tvp, UIO_SYSSPACE);
    241 }
    242 
    243 static __inline void
    244 native_to_linux32_timespec(struct linux32_timespec *ltp, struct timespec *ntp)
    245 {
    246 	ltp->tv_sec = ntp->tv_sec;
    247 	ltp->tv_nsec = ntp->tv_nsec;
    248 }
    249 
    250 static __inline void
    251 linux32_to_native_timespec(struct timespec *ntp, struct linux32_timespec *ltp)
    252 {
    253 	ntp->tv_sec = ltp->tv_sec;
    254 	ntp->tv_nsec = ltp->tv_nsec;
    255 }
    256 
    257 int
    258 linux32_sys_clock_settime(struct lwp *l,
    259     const struct linux32_sys_clock_settime_args *uap, register_t *retval)
    260 {
    261 	/* {
    262 		syscallarg(clockid_t) which;
    263 		syscallarg(linux32_timespecp_t) tp;
    264 	} */
    265 	int error;
    266 	struct timespec ts;
    267 	struct linux32_timespec lts;
    268 
    269 	switch (SCARG(uap, which)) {
    270 	case LINUX_CLOCK_REALTIME:
    271 		break;
    272 	default:
    273 		return EINVAL;
    274 	}
    275 
    276 	if ((error = copyin(SCARG_P32(uap, tp), &lts, sizeof lts)))
    277 		return error;
    278 
    279 	linux32_to_native_timespec(&ts, &lts);
    280 	return settime(l->l_proc, &ts);
    281 }
    282 
    283 int
    284 linux32_sys_clock_gettime(struct lwp *l,
    285     const struct linux32_sys_clock_gettime_args *uap, register_t *retval)
    286 {
    287 	/* {
    288 		syscallarg(clockid_t) which;
    289 		syscallarg(linux32_timespecp_t) tp;
    290 	} */
    291 	struct timespec ts;
    292 	struct linux32_timespec lts;
    293 
    294 	switch (SCARG(uap, which)) {
    295 	case LINUX_CLOCK_REALTIME:
    296 		nanotime(&ts);
    297 		break;
    298 	case LINUX_CLOCK_MONOTONIC:
    299 		nanouptime(&ts);
    300 		break;
    301 	default:
    302 		return EINVAL;
    303 	}
    304 
    305 	native_to_linux32_timespec(&lts, &ts);
    306 	return copyout(&lts, SCARG_P32(uap, tp), sizeof lts);
    307 }
    308 
    309 int
    310 linux32_sys_clock_getres(struct lwp *l,
    311     const struct linux32_sys_clock_getres_args *uap, register_t *retval)
    312 {
    313 	/* {
    314 		syscallarg(clockid_t) which;
    315 		syscallarg(linux32_timespecp_t) tp;
    316 	} */
    317 	int error;
    318 	clockid_t id;
    319 	struct timespec ts;
    320 	struct linux32_timespec lts;
    321 
    322 	error = linux_to_native_clockid(&id, SCARG(uap, which));
    323 	if (error != 0 || SCARG_P32(uap, tp) == NULL)
    324 		return error;
    325 
    326 	ts.tv_sec = 0;
    327 	ts.tv_nsec = 1000000000 / tc_getfrequency();
    328 	native_to_linux32_timespec(&lts, &ts);
    329 	return copyout(&lts, SCARG_P32(uap, tp), sizeof lts);
    330 
    331 	return 0;
    332 }
    333