xref: /netbsd-src/sys/compat/linux32/common/linux32_unistd.c (revision cac8e449158efc7261bebc8657cbb0125a2cfdde)
1 /*	$NetBSD: linux32_unistd.c,v 1.22 2008/04/15 21:13:34 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_unistd.c,v 1.22 2008/04/15 21:13:34 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/kernel.h>
44 #include <sys/fcntl.h>
45 #include <sys/select.h>
46 #include <sys/proc.h>
47 #include <sys/ucred.h>
48 #include <sys/swap.h>
49 
50 #include <machine/types.h>
51 
52 #include <sys/syscallargs.h>
53 
54 #include <compat/netbsd32/netbsd32.h>
55 #include <compat/netbsd32/netbsd32_conv.h>
56 
57 #include <compat/linux/common/linux_types.h>
58 #include <compat/linux/common/linux_signal.h>
59 #include <compat/linux/common/linux_machdep.h>
60 #include <compat/linux/common/linux_misc.h>
61 #include <compat/linux/common/linux_oldolduname.h>
62 #include <compat/linux/linux_syscallargs.h>
63 
64 #include <compat/linux32/common/linux32_types.h>
65 #include <compat/linux32/common/linux32_signal.h>
66 #include <compat/linux32/common/linux32_machdep.h>
67 #include <compat/linux32/common/linux32_sysctl.h>
68 #include <compat/linux32/common/linux32_socketcall.h>
69 #include <compat/linux32/linux32_syscallargs.h>
70 
71 static int linux32_select1(struct lwp *, register_t *,
72     int, fd_set *, fd_set *, fd_set *, struct timeval *);
73 
74 int
75 linux32_sys_brk(struct lwp *l, const struct linux32_sys_brk_args *uap, register_t *retval)
76 {
77 	/* {
78 		syscallarg(netbsd32_charp) nsize;
79 	} */
80 	struct linux_sys_brk_args ua;
81 
82 	NETBSD32TOP_UAP(nsize, char);
83 	return linux_sys_brk(l, &ua, retval);
84 }
85 
86 int
87 linux32_sys_llseek(struct lwp *l, const struct linux32_sys_llseek_args *uap, register_t *retval)
88 {
89 	/* {
90 		syscallcarg(int) fd;
91                 syscallarg(u_int32_t) ohigh;
92                 syscallarg(u_int32_t) olow;
93 		syscallarg(netbsd32_caddr_t) res;
94 		syscallcarg(int) whence;
95 	} */
96 	struct linux_sys_llseek_args ua;
97 
98 	NETBSD32TO64_UAP(fd);
99 	NETBSD32TO64_UAP(ohigh);
100 	NETBSD32TO64_UAP(olow);
101 	NETBSD32TOP_UAP(res, char);
102 	NETBSD32TO64_UAP(whence);
103 
104 	return linux_sys_llseek(l, &ua, retval);
105 }
106 
107 int
108 linux32_sys_select(struct lwp *l, const struct linux32_sys_select_args *uap, register_t *retval)
109 {
110 	/* {
111 		syscallarg(int) nfds;
112 		syscallarg(netbsd32_fd_setp_t) readfds;
113 		syscallarg(netbsd32_fd_setp_t) writefds;
114 		syscallarg(netbsd32_fd_setp_t) exceptfds;
115 		syscallarg(netbsd32_timevalp_t) timeout;
116 	} */
117 
118 	return linux32_select1(l, retval, SCARG(uap, nfds),
119 	    SCARG_P32(uap, readfds),
120 	    SCARG_P32(uap, writefds),
121 	    SCARG_P32(uap, exceptfds),
122 	    SCARG_P32(uap, timeout));
123 }
124 
125 int
126 linux32_sys_oldselect(struct lwp *l, const struct linux32_sys_oldselect_args *uap, register_t *retval)
127 {
128 	/* {
129 		syscallarg(linux32_oldselectp_t) lsp;
130 	} */
131 	struct linux32_oldselect lsp32;
132 	int error;
133 
134 	if ((error = copyin(SCARG_P32(uap, lsp), &lsp32, sizeof(lsp32))) != 0)
135 		return error;
136 
137 	return linux32_select1(l, retval, lsp32.nfds,
138 	     NETBSD32PTR64(lsp32.readfds), NETBSD32PTR64(lsp32.writefds),
139 	     NETBSD32PTR64(lsp32.exceptfds), NETBSD32PTR64(lsp32.timeout));
140 }
141 
142 static int
143 linux32_select1(l, retval, nfds, readfds, writefds, exceptfds, timeout)
144         struct lwp *l;
145         register_t *retval;
146         int nfds;
147         fd_set *readfds, *writefds, *exceptfds;
148         struct timeval *timeout;
149 {
150 	struct timeval tv0, tv1, utv, *tv = NULL;
151 	struct netbsd32_timeval utv32;
152 	int error;
153 
154 	timerclear(&utv); /* XXX GCC4 */
155 
156 	/*
157 	 * Store current time for computation of the amount of
158 	 * time left.
159 	 */
160 	if (timeout) {
161 		if ((error = copyin(timeout, &utv32, sizeof(utv32))))
162 			return error;
163 
164 		netbsd32_to_timeval(&utv32, &utv);
165 
166 		if (itimerfix(&utv)) {
167 			/*
168 			 * The timeval was invalid.  Convert it to something
169 			 * valid that will act as it does under Linux.
170 			 */
171 			utv.tv_sec += utv.tv_usec / 1000000;
172 			utv.tv_usec %= 1000000;
173 			if (utv.tv_usec < 0) {
174 				utv.tv_sec -= 1;
175 				utv.tv_usec += 1000000;
176 			}
177 			if (utv.tv_sec < 0)
178 				timerclear(&utv);
179 		}
180 		microtime(&tv0);
181 		tv = &utv;
182 	}
183 
184 	error = selcommon(l, retval, nfds,
185 	    readfds, writefds, exceptfds, tv, NULL);
186 
187 	if (error) {
188 		/*
189 		 * See fs/select.c in the Linux kernel.  Without this,
190 		 * Maelstrom doesn't work.
191 		 */
192 		if (error == ERESTART)
193 			error = EINTR;
194 		return error;
195 	}
196 
197 	if (timeout) {
198 		if (*retval) {
199 			/*
200 			 * Compute how much time was left of the timeout,
201 			 * by subtracting the current time and the time
202 			 * before we started the call, and subtracting
203 			 * that result from the user-supplied value.
204 			 */
205 			microtime(&tv1);
206 			timersub(&tv1, &tv0, &tv1);
207 			timersub(&utv, &tv1, &utv);
208 			if (utv.tv_sec < 0)
209 				timerclear(&utv);
210 		} else {
211 			timerclear(&utv);
212 		}
213 
214 		netbsd32_from_timeval(&utv, &utv32);
215 
216 		if ((error = copyout(&utv32, timeout, sizeof(utv32))))
217 			return error;
218 	}
219 
220 	return 0;
221 }
222 
223 int
224 linux32_sys_pipe(struct lwp *l, const struct linux32_sys_pipe_args *uap, register_t *retval)
225 {
226 	/* {
227 		syscallarg(netbsd32_intp) fd;
228 	} */
229 	int error;
230 	int pfds[2];
231 
232 	if ((error = sys_pipe(l, 0, retval)))
233 		return error;
234 
235 	pfds[0] = (int)retval[0];
236 	pfds[1] = (int)retval[1];
237 
238 	if ((error = copyout(pfds, SCARG_P32(uap, fd), 2 * sizeof (int))) != 0)
239 		return error;
240 
241 	retval[0] = 0;
242 	retval[1] = 0;
243 
244 	return 0;
245 }
246 
247 
248 int
249 linux32_sys_unlink(struct lwp *l, const struct linux32_sys_unlink_args *uap, register_t *retval)
250 {
251 	/* {
252 		syscallarg(const netbsd32_charp) path;
253 	} */
254 	struct linux_sys_unlink_args ua;
255 
256 	NETBSD32TOP_UAP(path, const char);
257 
258 	return linux_sys_unlink(l, &ua, retval);
259 }
260 
261 int
262 linux32_sys_creat(struct lwp *l, const struct linux32_sys_creat_args *uap, register_t *retval)
263 {
264 	/* {
265 		syscallarg(const netbsd32_charp) path;
266 		syscallarg(int) mode;
267 	} */
268 	struct sys_open_args ua;
269 
270 	NETBSD32TOP_UAP(path, const char);
271 	SCARG(&ua, flags) = O_CREAT | O_TRUNC | O_WRONLY;
272 	NETBSD32TO64_UAP(mode);
273 
274 	return sys_open(l, &ua, retval);
275 }
276 
277 int
278 linux32_sys_mknod(struct lwp *l, const struct linux32_sys_mknod_args *uap, register_t *retval)
279 {
280 	/* {
281 		syscallarg(const netbsd32_charp) path;
282 		syscallarg(int) mode;
283 		syscallarg(int) dev;
284 	} */
285 	struct linux_sys_mknod_args ua;
286 
287 	NETBSD32TOP_UAP(path, const char);
288 	NETBSD32TO64_UAP(mode);
289 	NETBSD32TO64_UAP(dev);
290 
291 	return linux_sys_mknod(l, &ua, retval);
292 }
293 
294 int
295 linux32_sys_break(struct lwp *l, const struct linux32_sys_break_args *uap, register_t *retval)
296 {
297 #if 0
298 	/* {
299 		syscallarg(const netbsd32_charp) nsize;
300 	} */
301 #endif
302 
303 	return ENOSYS;
304 }
305 
306 int
307 linux32_sys_rename(struct lwp *l, const struct linux32_sys_rename_args *uap, register_t *retval)
308 {
309 	/* {
310 		syscallarg(const netbsd32_charp) from;
311 		syscallarg(const netbsd32_charp) to;
312 	} */
313 	struct sys___posix_rename_args ua;
314 
315 	NETBSD32TOP_UAP(from, const char);
316 	NETBSD32TOP_UAP(to, const char);
317 
318 	return sys___posix_rename(l, &ua, retval);
319 }
320 
321 int
322 linux32_sys_swapon(struct lwp *l, const struct linux32_sys_swapon_args *uap, register_t *retval)
323 {
324 	/* {
325 		syscallarg(const netbsd32_charp) name;
326 	} */
327 	struct sys_swapctl_args ua;
328 
329         SCARG(&ua, cmd) = SWAP_ON;
330         SCARG(&ua, arg) = SCARG_P32(uap, name);
331         SCARG(&ua, misc) = 0;   /* priority */
332         return (sys_swapctl(l, &ua, retval));
333 }
334 
335 int
336 linux32_sys_swapoff(struct lwp *l, const struct linux32_sys_swapoff_args *uap, register_t *retval)
337 {
338 	/* {
339 		syscallarg(const netbsd32_charp) path;
340 	} */
341 	struct sys_swapctl_args ua;
342 
343         SCARG(&ua, cmd) = SWAP_OFF;
344         SCARG(&ua, arg) = SCARG_P32(uap, path);
345         SCARG(&ua, misc) = 0;   /* priority */
346         return (sys_swapctl(l, &ua, retval));
347 }
348 
349 
350 int
351 linux32_sys_reboot(struct lwp *l, const struct linux32_sys_reboot_args *uap, register_t *retval)
352 {
353 	/* {
354 		syscallarg(int) magic1;
355 		syscallarg(int) magic2;
356 		syscallarg(int) cmd;
357 		syscallarg(netbsd32_voidp) arg;
358 	} */
359 	struct linux_sys_reboot_args ua;
360 
361 	NETBSD32TO64_UAP(magic1);
362 	NETBSD32TO64_UAP(magic2);
363 	NETBSD32TO64_UAP(cmd);
364 	NETBSD32TOP_UAP(arg, void);
365 
366 	return linux_sys_reboot(l, &ua, retval);
367 }
368 
369 int
370 linux32_sys_truncate(struct lwp *l, const struct linux32_sys_truncate_args *uap, register_t *retval)
371 {
372 	/* {
373 		syscallarg(const netbsd32_charp) path;
374 		syscallarg(netbsd32_charp) buf;
375 		syscallarg(int) count;
376 	} */
377 	struct compat_43_sys_truncate_args ua;
378 
379 	NETBSD32TOP_UAP(path, const char);
380 	NETBSD32TO64_UAP(length);
381 
382 	return compat_43_sys_truncate(l, &ua, retval);
383 }
384 
385 int
386 linux32_sys_setresuid(struct lwp *l, const struct linux32_sys_setresuid_args *uap, register_t *retval)
387 {
388 	/* {
389 		syscallarg(uid_t) ruid;
390 		syscallarg(uid_t) euid;
391 		syscallarg(uid_t) suid;
392 	} */
393 	struct linux_sys_setresuid_args ua;
394 
395 	SCARG(&ua, ruid) = (SCARG(uap, ruid) == -1) ? -1 : SCARG(uap, ruid);
396 	SCARG(&ua, euid) = (SCARG(uap, euid) == -1) ? -1 : SCARG(uap, euid);
397 	SCARG(&ua, suid) = (SCARG(uap, suid) == -1) ? -1 : SCARG(uap, suid);
398 
399 	return linux_sys_setresuid(l, &ua, retval);
400 }
401 
402 int
403 linux32_sys_setresgid(struct lwp *l, const struct linux32_sys_setresgid_args *uap, register_t *retval)
404 {
405 	/* {
406 		syscallarg(gid_t) rgid;
407 		syscallarg(gid_t) egid;
408 		syscallarg(gid_t) sgid;
409 	} */
410 	struct linux_sys_setresgid_args ua;
411 
412 	SCARG(&ua, rgid) = (SCARG(uap, rgid) == -1) ? -1 : SCARG(uap, rgid);
413 	SCARG(&ua, egid) = (SCARG(uap, egid) == -1) ? -1 : SCARG(uap, egid);
414 	SCARG(&ua, sgid) = (SCARG(uap, sgid) == -1) ? -1 : SCARG(uap, sgid);
415 
416 	return linux_sys_setresgid(l, &ua, retval);
417 }
418 
419 int
420 linux32_sys_nice(struct lwp *l, const struct linux32_sys_nice_args *uap, register_t *retval)
421 {
422 	/* {
423 		syscallarg(int) incr;
424 	} */
425 	struct sys_setpriority_args bsa;
426 
427 	SCARG(&bsa, which) = PRIO_PROCESS;
428 	SCARG(&bsa, who) = 0;
429 	SCARG(&bsa, prio) = SCARG(uap, incr);
430 
431 	return sys_setpriority(l, &bsa, retval);
432 }
433 
434 int
435 linux32_sys_alarm(struct lwp *l, const struct linux32_sys_alarm_args *uap, register_t *retval)
436 {
437 	/* {
438 		syscallarg(unsigned int) secs;
439 	} */
440 	struct linux_sys_alarm_args ua;
441 
442 	NETBSD32TO64_UAP(secs);
443 
444 	return linux_sys_alarm(l, &ua, retval);
445 }
446 
447 int
448 linux32_sys_fdatasync(struct lwp *l, const struct linux32_sys_fdatasync_args *uap, register_t *retval)
449 {
450 	/* {
451 		syscallarg(int) fd;
452 	} */
453 	struct linux_sys_fdatasync_args ua;
454 
455 	NETBSD32TO64_UAP(fd);
456 
457 	return linux_sys_fdatasync(l, &ua, retval);
458 }
459 
460 int
461 linux32_sys_setfsuid(struct lwp *l, const struct linux32_sys_setfsuid_args *uap, register_t *retval)
462 {
463 	/* {
464 		syscallarg(uid_t) uid;
465 	} */
466 	struct linux_sys_setfsuid_args ua;
467 
468 	NETBSD32TO64_UAP(uid);
469 
470 	return linux_sys_setfsuid(l, &ua, retval);
471 }
472 
473 int
474 linux32_sys_setfsgid(struct lwp *l, const struct linux32_sys_setfsgid_args *uap, register_t *retval)
475 {
476 	/* {
477 		syscallarg(gid_t) gid;
478 	} */
479 	struct linux_sys_setfsgid_args ua;
480 
481 	NETBSD32TO64_UAP(gid);
482 
483 	return linux_sys_setfsgid(l, &ua, retval);
484 }
485 
486 /*
487  * pread(2).
488  */
489 int
490 linux32_sys_pread(struct lwp *l,
491     const struct linux32_sys_pread_args *uap, register_t *retval)
492 {
493 	/* {
494 		syscallarg(int) fd;
495 		syscallarg(netbsd32_voidp) buf;
496 		syscallarg(netbsd32_size_t) nbyte;
497 		syscallarg(linux32_off_t) offset;
498 	} */
499 	struct sys_pread_args pra;
500 
501 	SCARG(&pra, fd) = SCARG(uap, fd);
502 	SCARG(&pra, buf) = SCARG_P32(uap, buf);
503 	SCARG(&pra, nbyte) = SCARG(uap, nbyte);
504 	SCARG(&pra, offset) = SCARG(uap, offset);
505 
506 	return sys_pread(l, &pra, retval);
507 }
508 
509 /*
510  * pwrite(2).
511  */
512 int
513 linux32_sys_pwrite(struct lwp *l,
514     const struct linux32_sys_pwrite_args *uap, register_t *retval)
515 {
516 	/* {
517 		syscallarg(int) fd;
518 		syscallarg(const netbsd32_voidp) buf;
519 		syscallarg(netbsd32_size_t) nbyte;
520 		syscallarg(linux32_off_t) offset;
521 	} */
522 	struct sys_pwrite_args pra;
523 
524 	SCARG(&pra, fd) = SCARG(uap, fd);
525 	SCARG(&pra, buf) = SCARG_P32(uap, buf);
526 	SCARG(&pra, nbyte) = SCARG(uap, nbyte);
527 	SCARG(&pra, offset) = SCARG(uap, offset);
528 
529 	return sys_pwrite(l, &pra, retval);
530 }
531 
532