xref: /netbsd-src/sys/compat/linux32/common/linux32_time.c (revision b5677b36047b601b9addaaa494a58ceae82c2a6c)
1 /*	$NetBSD: linux32_time.c,v 1.28 2009/01/16 13:10:47 njoly 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.28 2009/01/16 13:10:47 njoly 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/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/linux32_syscallargs.h>
79 
80 extern struct timezone linux_sys_tz;
81 
82 static __inline void
83 native_to_linux32_timespec(struct linux32_timespec *, struct timespec *);
84 static __inline void
85 linux32_to_native_timespec(struct timespec *, struct linux32_timespec *);
86 
87 int
88 linux32_sys_gettimeofday(struct lwp *l, const struct linux32_sys_gettimeofday_args *uap, register_t *retval)
89 {
90 	/* {
91 		syscallarg(netbsd32_timeval50p_t) tp;
92 		syscallarg(netbsd32_timezonep_t) tzp;
93 	} */
94 	struct timeval tv;
95 	struct netbsd32_timeval50 tv32;
96 	int error;
97 
98 	if (SCARG_P32(uap, tp) != NULL) {
99 		microtime(&tv);
100 		netbsd32_from_timeval50(&tv, &tv32);
101 		if ((error = copyout(&tv32, SCARG_P32(uap, tp),
102 		    sizeof(tv32))) != 0)
103 			return error;
104 	}
105 
106 	/* timezone size does not change */
107 	if (SCARG_P32(uap, tzp) != NULL) {
108 		if ((error = copyout(&linux_sys_tz, SCARG_P32(uap, tzp),
109 		    sizeof(linux_sys_tz))) != 0)
110 			return error;
111 	}
112 
113 	return 0;
114 }
115 
116 int
117 linux32_sys_settimeofday(struct lwp *l, const struct linux32_sys_settimeofday_args *uap, register_t *retval)
118 {
119 	/* {
120 		syscallarg(netbsd32_timeval50p_t) tp;
121 		syscallarg(netbsd32_timezonep_t) tzp;
122 	} */
123 	struct linux_sys_settimeofday_args ua;
124 
125 	NETBSD32TOP_UAP(tp, struct timeval50);
126 	NETBSD32TOP_UAP(tzp, struct timezone);
127 
128 	return linux_sys_settimeofday(l, &ua, retval);
129 }
130 
131 int
132 linux32_sys_time(struct lwp *l, const struct linux32_sys_time_args *uap, register_t *retval)
133 {
134 	/* {
135 		syscallarg(linux32_timep_t) t;
136 	} */
137         struct timeval atv;
138         linux32_time_t tt;
139         int error;
140 
141         microtime(&atv);
142 
143         tt = (linux32_time_t)atv.tv_sec;
144 
145         if (SCARG_P32(uap, t) && (error = copyout(&tt,
146 	    SCARG_P32(uap, t), sizeof(tt))))
147                 return error;
148 
149         retval[0] = tt;
150 
151         return 0;
152 }
153 
154 
155 #define	CONVTCK(r)	(r.tv_sec * hz + r.tv_usec / (1000000 / hz))
156 
157 int
158 linux32_sys_times(struct lwp *l, const struct linux32_sys_times_args *uap, register_t *retval)
159 {
160 	/* {
161 		syscallarg(linux32_tmsp_t) tms;
162 	} */
163 	struct proc *p = l->l_proc;
164 	struct timeval t;
165 	int error;
166 
167 	if (SCARG_P32(uap, tms)) {
168 		struct linux32_tms ltms32;
169 		struct rusage ru;
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(&ltms32, 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
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
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 static __inline void
240 native_to_linux32_timespec(struct linux32_timespec *ltp, struct timespec *ntp)
241 {
242 	ltp->tv_sec = ntp->tv_sec;
243 	ltp->tv_nsec = ntp->tv_nsec;
244 }
245 
246 static __inline void
247 linux32_to_native_timespec(struct timespec *ntp, struct linux32_timespec *ltp)
248 {
249 	ntp->tv_sec = ltp->tv_sec;
250 	ntp->tv_nsec = ltp->tv_nsec;
251 }
252 
253 int
254 linux32_sys_nanosleep(struct lwp *l,
255     const struct linux32_sys_nanosleep_args *uap, register_t *retval)
256 {
257 	/* {
258 		syscallarg(linux32_timespecp_t) rqtp;
259 		syscallarg(linux32_timespecp_t) rmtp;
260 	} */
261 	struct timespec rqts, rmts;
262 	struct linux32_timespec lrqts, lrmts;
263 	int error, error1;
264 
265 	error = copyin(SCARG_P32(uap, rqtp), &lrqts, sizeof(lrqts));
266 	if (error != 0)
267 		return error;
268 	linux32_to_native_timespec(&rqts, &lrqts);
269 
270 	error = nanosleep1(l, &rqts, SCARG_P32(uap, rmtp) ? &rmts : NULL);
271 	if (SCARG_P32(uap, rmtp) == NULL || (error != 0 && error != EINTR))
272 		return error;
273 
274 	native_to_linux32_timespec(&lrmts, &rmts);
275 	error1 = copyout(&lrmts, SCARG_P32(uap, rmtp), sizeof(lrmts));
276 	return error1 ? error1 : error;
277 }
278 
279 int
280 linux32_sys_clock_settime(struct lwp *l,
281     const struct linux32_sys_clock_settime_args *uap, register_t *retval)
282 {
283 	/* {
284 		syscallarg(clockid_t) which;
285 		syscallarg(linux32_timespecp_t) tp;
286 	} */
287 	int error;
288 	struct timespec ts;
289 	struct linux32_timespec lts;
290 
291 	switch (SCARG(uap, which)) {
292 	case LINUX_CLOCK_REALTIME:
293 		break;
294 	default:
295 		return EINVAL;
296 	}
297 
298 	if ((error = copyin(SCARG_P32(uap, tp), &lts, sizeof lts)))
299 		return error;
300 
301 	linux32_to_native_timespec(&ts, &lts);
302 	return settime(l->l_proc, &ts);
303 }
304 
305 int
306 linux32_sys_clock_gettime(struct lwp *l,
307     const struct linux32_sys_clock_gettime_args *uap, register_t *retval)
308 {
309 	/* {
310 		syscallarg(clockid_t) which;
311 		syscallarg(linux32_timespecp_t) tp;
312 	} */
313 	struct timespec ts;
314 	struct linux32_timespec lts;
315 
316 	switch (SCARG(uap, which)) {
317 	case LINUX_CLOCK_REALTIME:
318 		nanotime(&ts);
319 		break;
320 	case LINUX_CLOCK_MONOTONIC:
321 		nanouptime(&ts);
322 		break;
323 	default:
324 		return EINVAL;
325 	}
326 
327 	native_to_linux32_timespec(&lts, &ts);
328 	return copyout(&lts, SCARG_P32(uap, tp), sizeof lts);
329 }
330 
331 int
332 linux32_sys_clock_getres(struct lwp *l,
333     const struct linux32_sys_clock_getres_args *uap, register_t *retval)
334 {
335 	/* {
336 		syscallarg(clockid_t) which;
337 		syscallarg(linux32_timespecp_t) tp;
338 	} */
339 	int error;
340 	clockid_t id;
341 	struct timespec ts;
342 	struct linux32_timespec lts;
343 
344 	error = linux_to_native_clockid(&id, SCARG(uap, which));
345 	if (error != 0 || SCARG_P32(uap, tp) == NULL)
346 		return error;
347 
348 	ts.tv_sec = 0;
349 	ts.tv_nsec = 1000000000 / tc_getfrequency();
350 	native_to_linux32_timespec(&lts, &ts);
351 	return copyout(&lts, SCARG_P32(uap, tp), sizeof lts);
352 
353 	return 0;
354 }
355 
356 int
357 linux32_sys_clock_nanosleep(struct lwp *l,
358     const struct linux32_sys_clock_nanosleep_args *uap, register_t *retval)
359 {
360 	/* {
361 		syscallarg(clockid_t) which;
362 		syscallarg(int) flags;
363 		syscallarg(linux32_timespecp_t) rqtp;
364 		syscallarg(linux32_timespecp_t) rmtp;
365 	} */
366 	struct linux32_timespec lrqts, lrmts;
367 	struct timespec rqts, rmts;
368 	int error, error1;
369 
370 	if (SCARG(uap, flags) != 0)
371 		return EINVAL;          /* XXX deal with TIMER_ABSTIME */
372 	if (SCARG(uap, which) != LINUX_CLOCK_REALTIME)
373 		return EINVAL;
374 
375 	error = copyin(SCARG_P32(uap, rqtp), &lrqts, sizeof lrqts);
376 	if (error != 0)
377 		return error;
378 	linux32_to_native_timespec(&rqts, &lrqts);
379 
380 	error = nanosleep1(l, &rqts, SCARG_P32(uap, rmtp) ? &rmts : 0);
381 	if (SCARG_P32(uap, rmtp) == NULL || (error != 0 && error != EINTR))
382 		return error;
383 
384 	native_to_linux32_timespec(&lrmts, &rmts);
385 	error1 = copyout(&lrmts, SCARG_P32(uap, rmtp), sizeof lrmts);
386 	return error1 ? error1 : error;
387 }
388