xref: /netbsd-src/sys/compat/linux32/common/linux32_time.c (revision b1c86f5f087524e68db12794ee9c3e3da1ab17a0)
1 /*	$NetBSD: linux32_time.c,v 1.35 2010/07/12 12:01:53 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.35 2010/07/12 12:01:53 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 
54 #include <machine/types.h>
55 
56 #include <sys/syscallargs.h>
57 
58 #include <compat/netbsd32/netbsd32.h>
59 #include <compat/netbsd32/netbsd32_conv.h>
60 #include <compat/netbsd32/netbsd32_syscallargs.h>
61 
62 #include <compat/linux/common/linux_types.h>
63 #include <compat/linux/common/linux_signal.h>
64 #include <compat/linux/common/linux_machdep.h>
65 #include <compat/linux/common/linux_misc.h>
66 #include <compat/linux/common/linux_oldolduname.h>
67 #include <compat/linux/common/linux_sched.h>
68 #include <compat/linux/common/linux_ipc.h>
69 #include <compat/linux/common/linux_sem.h>
70 #include <compat/linux/linux_syscallargs.h>
71 
72 #include <compat/linux32/common/linux32_types.h>
73 #include <compat/linux32/common/linux32_signal.h>
74 #include <compat/linux32/common/linux32_machdep.h>
75 #include <compat/linux32/common/linux32_sysctl.h>
76 #include <compat/linux32/common/linux32_socketcall.h>
77 #include <compat/linux32/linux32_syscallargs.h>
78 
79 extern struct timezone linux_sys_tz;
80 
81 void native_to_linux32_timespec(struct linux32_timespec *, struct timespec *);
82 void linux32_to_native_timespec(struct timespec *, struct linux32_timespec *);
83 
84 int
85 linux32_sys_gettimeofday(struct lwp *l, const struct linux32_sys_gettimeofday_args *uap, register_t *retval)
86 {
87 	/* {
88 		syscallarg(netbsd32_timeval50p_t) tp;
89 		syscallarg(netbsd32_timezonep_t) tzp;
90 	} */
91 	struct timeval tv;
92 	struct netbsd32_timeval50 tv32;
93 	int error;
94 
95 	if (SCARG_P32(uap, tp) != NULL) {
96 		microtime(&tv);
97 		netbsd32_from_timeval50(&tv, &tv32);
98 		if ((error = copyout(&tv32, SCARG_P32(uap, tp),
99 		    sizeof(tv32))) != 0)
100 			return error;
101 	}
102 
103 	/* timezone size does not change */
104 	if (SCARG_P32(uap, tzp) != NULL) {
105 		if ((error = copyout(&linux_sys_tz, SCARG_P32(uap, tzp),
106 		    sizeof(linux_sys_tz))) != 0)
107 			return error;
108 	}
109 
110 	return 0;
111 }
112 
113 int
114 linux32_sys_settimeofday(struct lwp *l, const struct linux32_sys_settimeofday_args *uap, register_t *retval)
115 {
116 	/* {
117 		syscallarg(netbsd32_timeval50p_t) tp;
118 		syscallarg(netbsd32_timezonep_t) tzp;
119 	} */
120 	struct linux_sys_settimeofday_args ua;
121 
122 	NETBSD32TOP_UAP(tp, struct timeval50);
123 	NETBSD32TOP_UAP(tzp, struct timezone);
124 
125 	return linux_sys_settimeofday(l, &ua, retval);
126 }
127 
128 int
129 linux32_sys_time(struct lwp *l, const struct linux32_sys_time_args *uap, register_t *retval)
130 {
131 	/* {
132 		syscallarg(linux32_timep_t) t;
133 	} */
134         struct timeval atv;
135         linux32_time_t tt;
136         int error;
137 
138         microtime(&atv);
139 
140         tt = (linux32_time_t)atv.tv_sec;
141 
142         if (SCARG_P32(uap, t) && (error = copyout(&tt,
143 	    SCARG_P32(uap, t), sizeof(tt))))
144                 return error;
145 
146         retval[0] = tt;
147 
148         return 0;
149 }
150 
151 
152 #define	CONVTCK(r)	(r.tv_sec * hz + r.tv_usec / (1000000 / hz))
153 
154 int
155 linux32_sys_times(struct lwp *l, const struct linux32_sys_times_args *uap, register_t *retval)
156 {
157 	/* {
158 		syscallarg(linux32_tmsp_t) tms;
159 	} */
160 	struct proc *p = l->l_proc;
161 	struct timeval t;
162 	int error;
163 
164 	if (SCARG_P32(uap, tms)) {
165 		struct linux32_tms ltms32;
166 		struct rusage ru;
167 
168 		mutex_enter(p->p_lock);
169 		calcru(p, &ru.ru_utime, &ru.ru_stime, NULL, NULL);
170 		ltms32.ltms32_utime = CONVTCK(ru.ru_utime);
171 		ltms32.ltms32_stime = CONVTCK(ru.ru_stime);
172 		ltms32.ltms32_cutime = CONVTCK(p->p_stats->p_cru.ru_utime);
173 		ltms32.ltms32_cstime = CONVTCK(p->p_stats->p_cru.ru_stime);
174 		mutex_exit(p->p_lock);
175 
176 		error = copyout(&ltms32, SCARG_P32(uap, tms), sizeof(ltms32));
177 		if (error)
178 			return error;
179 	}
180 
181 	getmicrouptime(&t);
182 
183 	retval[0] = ((linux32_clock_t)(CONVTCK(t)));
184 	return 0;
185 }
186 
187 #undef CONVTCK
188 
189 int
190 linux32_sys_stime(struct lwp *l, const struct linux32_sys_stime_args *uap, register_t *retval)
191 {
192 	/* {
193 		syscallarg(linux32_timep_t) t;
194 	} */
195 	struct timespec ts;
196 	linux32_time_t tt32;
197 	int error;
198 
199 	if ((error = copyin(SCARG_P32(uap, t), &tt32, sizeof tt32)) != 0)
200 		return error;
201 
202 	ts.tv_sec = (long)tt32;
203 	ts.tv_nsec = 0;
204 
205 	return settime(l->l_proc, &ts);
206 }
207 
208 int
209 linux32_sys_utime(struct lwp *l, const struct linux32_sys_utime_args *uap, register_t *retval)
210 {
211 	/* {
212 		syscallarg(const netbsd32_charp) path;
213 		syscallarg(linux32_utimbufp_t) times;
214 	} */
215         struct timeval tv[2], *tvp;
216         struct linux32_utimbuf lut;
217         int error;
218 
219         if (SCARG_P32(uap, times) != NULL) {
220                 if ((error = copyin(SCARG_P32(uap, times), &lut, sizeof lut)))
221                         return error;
222 
223                 tv[0].tv_sec = (long)lut.l_actime;
224                 tv[0].tv_usec = 0;
225                 tv[1].tv_sec = (long)lut.l_modtime;
226 		tv[1].tv_usec = 0;
227                 tvp = tv;
228         } else {
229 		tvp = NULL;
230 	}
231 
232         return do_sys_utimes(l, NULL, SCARG_P32(uap, path), FOLLOW,
233 			    tvp, UIO_SYSSPACE);
234 }
235 
236 void
237 native_to_linux32_timespec(struct linux32_timespec *ltp, struct timespec *ntp)
238 {
239 	ltp->tv_sec = ntp->tv_sec;
240 	ltp->tv_nsec = ntp->tv_nsec;
241 }
242 
243 void
244 linux32_to_native_timespec(struct timespec *ntp, struct linux32_timespec *ltp)
245 {
246 	ntp->tv_sec = ltp->tv_sec;
247 	ntp->tv_nsec = ltp->tv_nsec;
248 }
249 
250 int
251 linux32_sys_nanosleep(struct lwp *l,
252     const struct linux32_sys_nanosleep_args *uap, register_t *retval)
253 {
254 	/* {
255 		syscallarg(linux32_timespecp_t) rqtp;
256 		syscallarg(linux32_timespecp_t) rmtp;
257 	} */
258 	struct timespec rqts, rmts;
259 	struct linux32_timespec lrqts, lrmts;
260 	int error, error1;
261 
262 	error = copyin(SCARG_P32(uap, rqtp), &lrqts, sizeof(lrqts));
263 	if (error != 0)
264 		return error;
265 	linux32_to_native_timespec(&rqts, &lrqts);
266 
267 	error = nanosleep1(l, &rqts, SCARG_P32(uap, rmtp) ? &rmts : NULL);
268 	if (SCARG_P32(uap, rmtp) == NULL || (error != 0 && error != EINTR))
269 		return error;
270 
271 	native_to_linux32_timespec(&lrmts, &rmts);
272 	error1 = copyout(&lrmts, SCARG_P32(uap, rmtp), sizeof(lrmts));
273 	return error1 ? error1 : error;
274 }
275 
276 int
277 linux32_sys_clock_settime(struct lwp *l,
278     const struct linux32_sys_clock_settime_args *uap, register_t *retval)
279 {
280 	/* {
281 		syscallarg(clockid_t) which;
282 		syscallarg(linux32_timespecp_t) tp;
283 	} */
284 	int error;
285 	struct timespec ts;
286 	struct linux32_timespec lts;
287 	clockid_t id;
288 
289 	error = linux_to_native_clockid(&id, SCARG(uap, which));
290 	if (error != 0)
291 		return error;
292 
293 	if ((error = copyin(SCARG_P32(uap, tp), &lts, sizeof lts)))
294 		return error;
295 
296 	linux32_to_native_timespec(&ts, &lts);
297 	return clock_settime1(l->l_proc, id, &ts, true);
298 }
299 
300 int
301 linux32_sys_clock_gettime(struct lwp *l,
302     const struct linux32_sys_clock_gettime_args *uap, register_t *retval)
303 {
304 	/* {
305 		syscallarg(clockid_t) which;
306 		syscallarg(linux32_timespecp_t) tp;
307 	} */
308 	int error;
309 	clockid_t id;
310 	struct timespec ts;
311 	struct linux32_timespec lts;
312 
313 	error = linux_to_native_clockid(&id, SCARG(uap, which));
314 	if (error != 0)
315 		return error;
316 
317 	error = clock_gettime1(id, &ts);
318 	if (error != 0)
319 		return error;
320 
321 	native_to_linux32_timespec(&lts, &ts);
322 	return copyout(&lts, SCARG_P32(uap, tp), sizeof lts);
323 }
324 
325 int
326 linux32_sys_clock_getres(struct lwp *l,
327     const struct linux32_sys_clock_getres_args *uap, register_t *retval)
328 {
329 	/* {
330 		syscallarg(clockid_t) which;
331 		syscallarg(linux32_timespecp_t) tp;
332 	} */
333 	int error;
334 	clockid_t id;
335 	struct timespec ts;
336 	struct linux32_timespec lts;
337 
338 	error = linux_to_native_clockid(&id, SCARG(uap, which));
339 	if (error != 0 || SCARG_P32(uap, tp) == NULL)
340 		return error;
341 
342 	error = clock_getres1(id, &ts);
343 	if (error != 0)
344 		return error;
345 
346 	native_to_linux32_timespec(&lts, &ts);
347 	return copyout(&lts, SCARG_P32(uap, tp), sizeof lts);
348 }
349 
350 int
351 linux32_sys_clock_nanosleep(struct lwp *l,
352     const struct linux32_sys_clock_nanosleep_args *uap, register_t *retval)
353 {
354 	/* {
355 		syscallarg(clockid_t) which;
356 		syscallarg(int) flags;
357 		syscallarg(linux32_timespecp_t) rqtp;
358 		syscallarg(linux32_timespecp_t) rmtp;
359 	} */
360 	struct linux32_timespec lrqts, lrmts;
361 	struct timespec rqts, rmts;
362 	int error, error1;
363 	clockid_t id;
364 
365 	if (SCARG(uap, flags) != 0)
366 		return EINVAL;          /* XXX deal with TIMER_ABSTIME */
367 
368 	error = linux_to_native_clockid(&id, SCARG(uap, which));
369 	if (error != 0)
370 		return error;
371 
372 	error = copyin(SCARG_P32(uap, rqtp), &lrqts, sizeof lrqts);
373 	if (error != 0)
374 		return error;
375 	linux32_to_native_timespec(&rqts, &lrqts);
376 
377 	error = nanosleep1(l, &rqts, SCARG_P32(uap, rmtp) ? &rmts : NULL);
378 	if (SCARG_P32(uap, rmtp) == NULL || (error != 0 && error != EINTR))
379 		return error;
380 
381 	native_to_linux32_timespec(&lrmts, &rmts);
382 	error1 = copyout(&lrmts, SCARG_P32(uap, rmtp), sizeof lrmts);
383 	return error1 ? error1 : error;
384 }
385