1 /** $MirOS: src/sys/compat/linux/linux_misc.c,v 1.5 2008/11/08 23:04:11 tg Exp $ */
2 /* $OpenBSD: linux_misc.c,v 1.58 2005/02/17 18:07:36 jfb Exp $ */
3 /* $NetBSD: linux_misc.c,v 1.27 1996/05/20 01:59:21 fvdl Exp $ */
4
5 /*-
6 * Copyright (c) 2004
7 * Thorsten "mirabilos" Glaser <tg@mirbsd.org>
8 * Copyright (c) 1995, 1998, 1999 The NetBSD Foundation, Inc.
9 * All rights reserved.
10 *
11 * This code is derived from software contributed to The NetBSD Foundation
12 * by Frank van der Linden and Eric Haszlakiewicz; by Jason R. Thorpe
13 * of the Numerical Aerospace Simulation Facility, NASA Ames Research Center.
14 *
15 * Redistribution and use in source and binary forms, with or without
16 * modification, are permitted provided that the following conditions
17 * are met:
18 * 1. Redistributions of source code must retain the above copyright
19 * notice, this list of conditions and the following disclaimer.
20 * 2. Redistributions in binary form must reproduce the above copyright
21 * notice, this list of conditions and the following disclaimer in the
22 * documentation and/or other materials provided with the distribution.
23 * 3. All advertising materials mentioning features or use of this software
24 * must display the following acknowledgement:
25 * This product includes software developed by the NetBSD
26 * Foundation, Inc. and its contributors.
27 * 4. Neither the name of The NetBSD Foundation nor the names of its
28 * contributors may be used to endorse or promote products derived
29 * from this software without specific prior written permission.
30 *
31 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
32 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
33 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
34 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
35 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
36 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
37 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
38 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
39 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
40 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41 * POSSIBILITY OF SUCH DAMAGE.
42 */
43
44 /*
45 * Linux compatibility module. Try to deal with various Linux system calls.
46 */
47
48 #include <sys/param.h>
49 #include <sys/systm.h>
50 #include <sys/namei.h>
51 #include <sys/proc.h>
52 #include <sys/dirent.h>
53 #include <sys/file.h>
54 #include <sys/stat.h>
55 #include <sys/filedesc.h>
56 #include <sys/ioctl.h>
57 #include <sys/kernel.h>
58 #include <sys/malloc.h>
59 #include <sys/mbuf.h>
60 #include <sys/mman.h>
61 #include <sys/mount.h>
62 #include <sys/ptrace.h>
63 #include <sys/resource.h>
64 #include <sys/resourcevar.h>
65 #include <sys/signal.h>
66 #include <sys/signalvar.h>
67 #include <sys/socket.h>
68 #include <sys/time.h>
69 #include <sys/times.h>
70 #include <sys/vnode.h>
71 #include <sys/uio.h>
72 #include <sys/wait.h>
73 #include <sys/utsname.h>
74 #include <sys/unistd.h>
75
76 #include <sys/syscallargs.h>
77
78 #include <uvm/uvm_extern.h>
79
80 #include <compat/linux/linux_types.h>
81 #include <compat/linux/linux_fcntl.h>
82 #include <compat/linux/linux_misc.h>
83 #include <compat/linux/linux_mmap.h>
84 #include <compat/linux/linux_sched.h>
85 #include <compat/linux/linux_signal.h>
86 #include <compat/linux/linux_syscallargs.h>
87 #include <compat/linux/linux_util.h>
88 #include <compat/linux/linux_dirent.h>
89 #include <compat/linux/linux_emuldata.h>
90 #include <compat/linux/linux_ptrace.h>
91
92 #include <compat/common/compat_dir.h>
93
94 const int linux_ptrace_request_map[] = {
95 LINUX_PTRACE_TRACEME, PT_TRACE_ME,
96 LINUX_PTRACE_PEEKTEXT, PT_READ_I,
97 LINUX_PTRACE_PEEKDATA, PT_READ_D,
98 LINUX_PTRACE_POKETEXT, PT_WRITE_I,
99 LINUX_PTRACE_POKEDATA, PT_WRITE_D,
100 LINUX_PTRACE_CONT, PT_CONTINUE,
101 LINUX_PTRACE_KILL, PT_KILL,
102 LINUX_PTRACE_ATTACH, PT_ATTACH,
103 LINUX_PTRACE_DETACH, PT_DETACH,
104 #ifdef PT_STEP
105 LINUX_PTRACE_SINGLESTEP, PT_STEP,
106 #endif
107 -1
108 };
109
110 struct compat_time_sys_wait4_args {
111 syscallarg(pid_t) pid;
112 syscallarg(int *) status;
113 syscallarg(int) options;
114 syscallarg(struct rusage_compat *) rusage;
115 };
116
117 extern char emul_uname[];
118 extern int compat_time_sys_wait4(struct proc *, void *, register_t *);
119
120 /* linux_misc.c */
121 static void bsd_to_linux_statfs(struct statfs *, struct linux_statfs *);
122 int linux_select1(struct proc *, register_t *, int, fd_set *,
123 fd_set *, fd_set *, struct timeval_compat *);
124 static int getdents_common(struct proc *, void *, register_t *, int);
125 static void linux_to_bsd_mmap_args(struct sys_mmap_args *,
126 const struct linux_sys_mmap2_args *);
127
128 /*
129 * The information on a terminated (or stopped) process needs
130 * to be converted in order for Linux binaries to get a valid signal
131 * number out of it.
132 */
133 void
bsd_to_linux_wstat(status)134 bsd_to_linux_wstat(status)
135 int *status;
136 {
137
138 if (WIFSIGNALED(*status))
139 *status = (*status & ~0177) |
140 bsd_to_linux_sig[WTERMSIG(*status)];
141 else if (WIFSTOPPED(*status))
142 *status = (*status & ~0xff00) |
143 (bsd_to_linux_sig[WSTOPSIG(*status)] << 8);
144 }
145
146 /*
147 * waitpid(2). Passed on to the OpenBSD call, surrounded by code to
148 * reserve some space for a OpenBSD-style wait status, and converting
149 * it to what Linux wants.
150 */
151 int
linux_sys_waitpid(p,v,retval)152 linux_sys_waitpid(p, v, retval)
153 struct proc *p;
154 void *v;
155 register_t *retval;
156 {
157 struct linux_sys_waitpid_args /* {
158 syscallarg(int) pid;
159 syscallarg(int *) status;
160 syscallarg(int) options;
161 } */ *uap = v;
162 struct sys_wait4_args w4a;
163 int error, *status, tstat;
164 caddr_t sg;
165
166 if (SCARG(uap, status) != NULL) {
167 sg = stackgap_init(p->p_emul);
168 status = (int *) stackgap_alloc(&sg, sizeof status);
169 } else
170 status = NULL;
171
172 SCARG(&w4a, pid) = SCARG(uap, pid);
173 SCARG(&w4a, status) = status;
174 SCARG(&w4a, options) = SCARG(uap, options);
175 SCARG(&w4a, rusage) = NULL;
176
177 if ((error = sys_wait4(p, &w4a, retval)))
178 return error;
179
180 p->p_siglist &= ~sigmask(SIGCHLD);
181
182 if (status != NULL) {
183 if ((error = copyin(status, &tstat, sizeof tstat)))
184 return error;
185
186 bsd_to_linux_wstat(&tstat);
187 return copyout(&tstat, SCARG(uap, status), sizeof tstat);
188 }
189
190 return 0;
191 }
192
193 /*
194 * This is very much the same as waitpid()
195 */
196 int
linux_sys_wait4(p,v,retval)197 linux_sys_wait4(p, v, retval)
198 struct proc *p;
199 void *v;
200 register_t *retval;
201 {
202 struct linux_sys_wait4_args /* {
203 syscallarg(int) pid;
204 syscallarg(int *) status;
205 syscallarg(int) options;
206 syscallarg(struct rusage_compat *) rusage;
207 } */ *uap = v;
208 struct compat_time_sys_wait4_args w4a;
209 int error, *status, tstat, linux_options, options;
210 caddr_t sg;
211
212 if (SCARG(uap, status) != NULL) {
213 sg = stackgap_init(p->p_emul);
214 status = (int *) stackgap_alloc(&sg, sizeof status);
215 } else
216 status = NULL;
217
218 linux_options = SCARG(uap, options);
219 options = 0;
220 if (linux_options &
221 ~(LINUX_WAIT4_WNOHANG|LINUX_WAIT4_WUNTRACED|LINUX_WAIT4_WCLONE))
222 return (EINVAL);
223
224 if (linux_options & LINUX_WAIT4_WNOHANG)
225 options |= WNOHANG;
226 if (linux_options & LINUX_WAIT4_WUNTRACED)
227 options |= WUNTRACED;
228 if (linux_options & LINUX_WAIT4_WCLONE)
229 options |= WALTSIG;
230
231 SCARG(&w4a, pid) = SCARG(uap, pid);
232 SCARG(&w4a, status) = status;
233 SCARG(&w4a, options) = options;
234 SCARG(&w4a, rusage) = SCARG(uap, rusage);
235
236 if ((error = compat_time_sys_wait4(p, &w4a, retval)))
237 return error;
238
239 p->p_siglist &= ~sigmask(SIGCHLD);
240
241 if (status != NULL) {
242 if ((error = copyin(status, &tstat, sizeof tstat)))
243 return error;
244
245 bsd_to_linux_wstat(&tstat);
246 return copyout(&tstat, SCARG(uap, status), sizeof tstat);
247 }
248
249 return 0;
250 }
251
252 int
linux_sys_setresgid16(p,v,retval)253 linux_sys_setresgid16(p, v, retval)
254 struct proc *p;
255 void *v;
256 register_t *retval;
257 {
258 struct linux_sys_setresgid16_args /* {
259 syscallarg(u_int16_t) rgid;
260 syscallarg(u_int16_t) egid;
261 syscallarg(u_int16_t) sgid;
262 } */ *uap = v;
263 struct sys_setresgid_args nuap;
264 u_int16_t rgid, egid, sgid;
265
266 rgid = SCARG(uap, rgid);
267 SCARG(&nuap, rgid) = (rgid == (u_int16_t)-1) ? (gid_t)-1 : rgid;
268 egid = SCARG(uap, egid);
269 SCARG(&nuap, egid) = (egid == (u_int16_t)-1) ? (gid_t)-1 : egid;
270 sgid = SCARG(uap, sgid);
271 SCARG(&nuap, sgid) = (sgid == (u_int16_t)-1) ? (gid_t)-1 : sgid;
272
273 return sys_setresgid(p, &nuap, retval);
274 }
275
276 int
linux_sys_getresgid16(p,v,retval)277 linux_sys_getresgid16(p, v, retval)
278 struct proc *p;
279 void *v;
280 register_t *retval;
281 {
282 struct linux_sys_getresgid16_args /* {
283 syscallarg(u_int16_t *) rgid;
284 syscallarg(u_int16_t *) egid;
285 syscallarg(u_int16_t *) sgid;
286 } */ *uap = v;
287 struct sys_getresgid_args nuap;
288
289 SCARG(&nuap, rgid) = (gid_t *)SCARG(uap, rgid);
290 SCARG(&nuap, egid) = (gid_t *)SCARG(uap, egid);
291 SCARG(&nuap, sgid) = (gid_t *)SCARG(uap, sgid);
292
293 return sys_getresgid(p, &nuap, retval);
294 }
295
296 int
linux_sys_setresuid16(p,v,retval)297 linux_sys_setresuid16(p, v, retval)
298 struct proc *p;
299 void *v;
300 register_t *retval;
301 {
302 struct linux_sys_setresuid16_args /* {
303 syscallarg(u_int16_t) ruid;
304 syscallarg(u_int16_t) euid;
305 syscallarg(u_int16_t) suid;
306 } */ *uap = v;
307 struct sys_setresuid_args nuap;
308 u_int16_t ruid, euid, suid;
309
310 ruid = SCARG(uap, ruid);
311 SCARG(&nuap, ruid) = (ruid == (u_int16_t)-1) ? (uid_t)-1 : ruid;
312 euid = SCARG(uap, euid);
313 SCARG(&nuap, euid) = (euid == (u_int16_t)-1) ? (uid_t)-1 : euid;
314 suid = SCARG(uap, suid);
315 SCARG(&nuap, suid) = (suid == (u_int16_t)-1) ? (uid_t)-1 : suid;
316
317 return sys_setresuid(p, &nuap, retval);
318 }
319
320 int
linux_sys_getresuid16(p,v,retval)321 linux_sys_getresuid16(p, v, retval)
322 struct proc *p;
323 void *v;
324 register_t *retval;
325 {
326 struct linux_sys_getresuid16_args /* {
327 syscallarg(u_int16_t *) ruid;
328 syscallarg(u_int16_t *) euid;
329 syscallarg(u_int16_t *) suid;
330 } */ *uap = v;
331 struct sys_getresuid_args nuap;
332
333 SCARG(&nuap, ruid) = (uid_t *)SCARG(uap, ruid);
334 SCARG(&nuap, euid) = (uid_t *)SCARG(uap, euid);
335 SCARG(&nuap, suid) = (uid_t *)SCARG(uap, suid);
336
337 return sys_getresuid(p, &nuap, retval);
338 }
339
340 /*
341 * This is the old brk(2) call. I don't think anything in the Linux
342 * world uses this anymore
343 */
344 int
linux_sys_break(p,v,retval)345 linux_sys_break(p, v, retval)
346 struct proc *p;
347 void *v;
348 register_t *retval;
349 {
350 #if 0
351 struct linux_sys_brk_args /* {
352 syscallarg(char *) nsize;
353 } */ *uap = v;
354 #endif
355
356 return ENOSYS;
357 }
358
359 /*
360 * Linux brk(2). The check if the new address is >= the old one is
361 * done in the kernel in Linux. OpenBSD does it in the library.
362 */
363 int
linux_sys_brk(p,v,retval)364 linux_sys_brk(p, v, retval)
365 struct proc *p;
366 void *v;
367 register_t *retval;
368 {
369 struct linux_sys_brk_args /* {
370 syscallarg(char *) nsize;
371 } */ *uap = v;
372 char *nbrk = SCARG(uap, nsize);
373 struct sys_obreak_args oba;
374 struct vmspace *vm = p->p_vmspace;
375 struct linux_emuldata *ed = (struct linux_emuldata*)p->p_emuldata;
376
377 SCARG(&oba, nsize) = nbrk;
378
379 if ((caddr_t) nbrk > vm->vm_daddr && sys_obreak(p, &oba, retval) == 0)
380 ed->p_break = (char*)nbrk;
381 else
382 nbrk = ed->p_break;
383
384 retval[0] = (register_t)nbrk;
385
386 return 0;
387 }
388
389 /*
390 * I wonder why Linux has gettimeofday() _and_ time().. Still, we
391 * need to deal with it.
392 */
393 int
linux_sys_time(p,v,retval)394 linux_sys_time(p, v, retval)
395 struct proc *p;
396 void *v;
397 register_t *retval;
398 {
399 struct linux_sys_time_args /* {
400 linux_time_t *t;
401 } */ *uap = v;
402 struct timeval atv;
403 linux_time_t tt;
404 int error;
405
406 microtime(&atv);
407
408 tt = atv.tv_sec;
409 if (SCARG(uap, t) && (error = copyout(&tt, SCARG(uap, t), sizeof tt)))
410 return error;
411
412 retval[0] = tt;
413 return 0;
414 }
415
416 /*
417 * Convert BSD statfs structure to Linux statfs structure.
418 * The Linux structure has less fields, and it also wants
419 * the length of a name in a dir entry in a field, which
420 * we fake (probably the wrong way).
421 */
422 static void
bsd_to_linux_statfs(bsp,lsp)423 bsd_to_linux_statfs(bsp, lsp)
424 struct statfs *bsp;
425 struct linux_statfs *lsp;
426 {
427
428 /*
429 * Convert BSD filesystem names to Linux filesystem type numbers
430 * where possible. Linux statfs uses a value of -1 to indicate
431 * an unsupported field.
432 */
433 if (!strcmp(bsp->f_fstypename, MOUNT_FFS) ||
434 !strcmp(bsp->f_fstypename, MOUNT_MFS))
435 lsp->l_ftype = 0x11954;
436 else if (!strcmp(bsp->f_fstypename, MOUNT_NFS))
437 lsp->l_ftype = 0x6969;
438 else if (!strcmp(bsp->f_fstypename, MOUNT_MSDOS))
439 lsp->l_ftype = 0x4d44;
440 else if (!strcmp(bsp->f_fstypename, MOUNT_PROCFS))
441 lsp->l_ftype = 0x9fa0;
442 else if (!strcmp(bsp->f_fstypename, MOUNT_EXT2FS))
443 lsp->l_ftype = 0xef53;
444 else if (!strcmp(bsp->f_fstypename, MOUNT_CD9660))
445 lsp->l_ftype = 0x9660;
446 else if (!strcmp(bsp->f_fstypename, MOUNT_NCPFS))
447 lsp->l_ftype = 0x6969;
448 else
449 lsp->l_ftype = -1;
450
451 lsp->l_fbsize = bsp->f_bsize;
452 lsp->l_fblocks = bsp->f_blocks;
453 lsp->l_fbfree = bsp->f_bfree;
454 lsp->l_fbavail = bsp->f_bavail;
455 lsp->l_ffiles = bsp->f_files;
456 lsp->l_fffree = bsp->f_ffree;
457 lsp->l_ffsid.val[0] = bsp->f_fsid.val[0];
458 lsp->l_ffsid.val[1] = bsp->f_fsid.val[1];
459 lsp->l_fnamelen = MAXNAMLEN; /* XXX */
460 }
461
462 /*
463 * Implement the fs stat functions. Straightforward.
464 */
465 int
linux_sys_statfs(p,v,retval)466 linux_sys_statfs(p, v, retval)
467 struct proc *p;
468 void *v;
469 register_t *retval;
470 {
471 struct linux_sys_statfs_args /* {
472 syscallarg(char *) path;
473 syscallarg(struct linux_statfs *) sp;
474 } */ *uap = v;
475 struct statfs btmp, *bsp;
476 struct linux_statfs ltmp;
477 struct sys_statfs_args bsa;
478 caddr_t sg;
479 int error;
480
481 sg = stackgap_init(p->p_emul);
482 bsp = (struct statfs *) stackgap_alloc(&sg, sizeof (struct statfs));
483
484 LINUX_CHECK_ALT_EXIST(p, &sg, SCARG(uap, path));
485
486 SCARG(&bsa, path) = SCARG(uap, path);
487 SCARG(&bsa, buf) = bsp;
488
489 if ((error = sys_statfs(p, &bsa, retval)))
490 return error;
491
492 if ((error = copyin((caddr_t) bsp, (caddr_t) &btmp, sizeof btmp)))
493 return error;
494
495 bsd_to_linux_statfs(&btmp, <mp);
496
497 return copyout((caddr_t) <mp, (caddr_t) SCARG(uap, sp), sizeof ltmp);
498 }
499
500 int
linux_sys_fstatfs(p,v,retval)501 linux_sys_fstatfs(p, v, retval)
502 struct proc *p;
503 void *v;
504 register_t *retval;
505 {
506 struct linux_sys_fstatfs_args /* {
507 syscallarg(int) fd;
508 syscallarg(struct linux_statfs *) sp;
509 } */ *uap = v;
510 struct statfs btmp, *bsp;
511 struct linux_statfs ltmp;
512 struct sys_fstatfs_args bsa;
513 caddr_t sg;
514 int error;
515
516 sg = stackgap_init(p->p_emul);
517 bsp = (struct statfs *) stackgap_alloc(&sg, sizeof (struct statfs));
518
519 SCARG(&bsa, fd) = SCARG(uap, fd);
520 SCARG(&bsa, buf) = bsp;
521
522 if ((error = sys_fstatfs(p, &bsa, retval)))
523 return error;
524
525 if ((error = copyin((caddr_t) bsp, (caddr_t) &btmp, sizeof btmp)))
526 return error;
527
528 bsd_to_linux_statfs(&btmp, <mp);
529
530 return copyout((caddr_t) <mp, (caddr_t) SCARG(uap, sp), sizeof ltmp);
531 }
532
533 /*
534 * uname(). Just copy the info from the various strings stored in the
535 * kernel, and put it in the Linux utsname structure. That structure
536 * is almost the same as the OpenBSD one, only it has fields 65 characters
537 * long, and an extra domainname field.
538 */
539 int
linux_sys_uname(p,v,retval)540 linux_sys_uname(p, v, retval)
541 struct proc *p;
542 void *v;
543 register_t *retval;
544 {
545 struct linux_sys_uname_args /* {
546 syscallarg(struct linux_utsname *) up;
547 } */ *uap = v;
548 extern char hostname[], machine[];
549 struct linux_utsname luts;
550 int len;
551 char *cp;
552
553 strlcpy(luts.l_sysname, emul_uname, sizeof(luts.l_sysname));
554 strlcpy(luts.l_nodename, hostname, sizeof(luts.l_nodename));
555 strlcpy(luts.l_release, osrelease, sizeof(luts.l_release));
556 strlcpy(luts.l_version, version, sizeof(luts.l_version));
557 strlcpy(luts.l_machine, machine, sizeof(luts.l_machine));
558 luts.l_domainname[0] = '\0';
559
560 /* This part taken from the uname() in libc */
561 len = sizeof(luts.l_version);
562 for (cp = luts.l_version; len--; ++cp)
563 if (*cp == '\n' || *cp == '\t')
564 *cp = (len > 1) ? ' ' : '\0';
565
566 return copyout(&luts, SCARG(uap, up), sizeof(luts));
567 }
568
569 int
linux_sys_olduname(p,v,retval)570 linux_sys_olduname(p, v, retval)
571 struct proc *p;
572 void *v;
573 register_t *retval;
574 {
575 struct linux_sys_uname_args /* {
576 syscallarg(struct linux_oldutsname *) up;
577 } */ *uap = v;
578 extern char hostname[], machine[];
579 struct linux_oldutsname luts;
580 int len;
581 char *cp;
582
583 strlcpy(luts.l_sysname, emul_uname, sizeof(luts.l_sysname));
584 strlcpy(luts.l_nodename, hostname, sizeof(luts.l_nodename));
585 strlcpy(luts.l_release, osrelease, sizeof(luts.l_release));
586 strlcpy(luts.l_version, version, sizeof(luts.l_version));
587 strlcpy(luts.l_machine, machine, sizeof(luts.l_machine));
588
589 /* This part taken from the uname() in libc */
590 len = sizeof(luts.l_version);
591 for (cp = luts.l_version; len--; ++cp)
592 if (*cp == '\n' || *cp == '\t')
593 *cp = (len > 1) ? ' ' : '\0';
594
595 return copyout(&luts, SCARG(uap, up), sizeof(luts));
596 }
597
598 int
linux_sys_oldolduname(p,v,retval)599 linux_sys_oldolduname(p, v, retval)
600 struct proc *p;
601 void *v;
602 register_t *retval;
603 {
604 struct linux_sys_uname_args /* {
605 syscallarg(struct linux_oldoldutsname *) up;
606 } */ *uap = v;
607 extern char hostname[], machine[];
608 struct linux_oldoldutsname luts;
609 int len;
610 char *cp;
611
612 strlcpy(luts.l_sysname, emul_uname, sizeof(luts.l_sysname));
613 strlcpy(luts.l_nodename, hostname, sizeof(luts.l_nodename));
614 strlcpy(luts.l_release, osrelease, sizeof(luts.l_release));
615 strlcpy(luts.l_version, version, sizeof(luts.l_version));
616 strlcpy(luts.l_machine, machine, sizeof(luts.l_machine));
617
618 /* This part taken from the uname() in libc */
619 len = sizeof(luts.l_version);
620 for (cp = luts.l_version; len--; ++cp)
621 if (*cp == '\n' || *cp == '\t')
622 *cp = (len > 1) ? ' ' : '\0';
623
624 return copyout(&luts, SCARG(uap, up), sizeof(luts));
625 }
626
627 /*
628 * Linux wants to pass everything to a syscall in registers. However,
629 * mmap() has 6 of them. Oops: out of register error. They just pass
630 * everything in a structure.
631 */
632 int
linux_sys_mmap(p,v,retval)633 linux_sys_mmap(p, v, retval)
634 struct proc *p;
635 void *v;
636 register_t *retval;
637 {
638 struct linux_sys_mmap_args /* {
639 syscallarg(struct linux_mmap *) lmp;
640 } */ *uap = v;
641 struct linux_mmap lmap;
642 struct linux_sys_mmap2_args nlmap;
643 struct sys_mmap_args cma;
644 int error;
645
646 if ((error = copyin(SCARG(uap, lmp), &lmap, sizeof lmap)))
647 return error;
648
649 if (lmap.lm_pos & PAGE_MASK)
650 return EINVAL;
651
652 /* repackage into something sane */
653 SCARG(&nlmap,addr) = (unsigned long)lmap.lm_addr;
654 SCARG(&nlmap,len) = lmap.lm_len;
655 SCARG(&nlmap,prot) = lmap.lm_prot;
656 SCARG(&nlmap,flags) = lmap.lm_flags;
657 SCARG(&nlmap,fd) = lmap.lm_fd;
658 SCARG(&nlmap,offset) = (unsigned)lmap.lm_pos;
659
660 linux_to_bsd_mmap_args(&cma, &nlmap);
661 SCARG(&cma, pos) = (off_t)SCARG(&nlmap, offset);
662
663 return sys_mmap(p, &cma, retval);
664 }
665
666 /*
667 * Guts of most architectures' mmap64() implementations. This shares
668 * its list of arguments with linux_sys_mmap().
669 *
670 * The difference in linux_sys_mmap2() is that "offset" is actually
671 * (offset / pagesize), not an absolute byte count. This translation
672 * to pagesize offsets is done inside glibc between the mmap64() call
673 * point, and the actual syscall.
674 */
675 int
linux_sys_mmap2(p,v,retval)676 linux_sys_mmap2(p, v, retval)
677 struct proc *p;
678 void *v;
679 register_t *retval;
680 {
681 struct linux_sys_mmap2_args /* {
682 syscallarg(unsigned long) addr;
683 syscallarg(size_t) len;
684 syscallarg(int) prot;
685 syscallarg(int) flags;
686 syscallarg(int) fd;
687 syscallarg(linux_off_t) offset;
688 } */ *uap = v;
689 struct sys_mmap_args cma;
690
691 linux_to_bsd_mmap_args(&cma, uap);
692 SCARG(&cma, pos) = ((off_t)SCARG(uap, offset)) << PAGE_SHIFT;
693
694 return sys_mmap(p, &cma, retval);
695 }
696
697 static void
linux_to_bsd_mmap_args(cma,uap)698 linux_to_bsd_mmap_args(cma, uap)
699 struct sys_mmap_args *cma;
700 const struct linux_sys_mmap2_args *uap;
701 {
702 int flags = MAP_TRYFIXED, fl = SCARG(uap, flags);
703
704 flags |= cvtto_bsd_mask(fl, LINUX_MAP_SHARED, MAP_SHARED);
705 flags |= cvtto_bsd_mask(fl, LINUX_MAP_PRIVATE, MAP_PRIVATE);
706 flags |= cvtto_bsd_mask(fl, LINUX_MAP_FIXED, MAP_FIXED);
707 flags |= cvtto_bsd_mask(fl, LINUX_MAP_ANON, MAP_ANON);
708 /* XXX XAX ERH: Any other flags here? There are more defined... */
709
710 SCARG(cma, addr) = (void *)SCARG(uap, addr);
711 SCARG(cma, len) = SCARG(uap, len);
712 SCARG(cma, prot) = SCARG(uap, prot);
713 if (SCARG(cma, prot) & VM_PROT_WRITE) /* XXX */
714 SCARG(cma, prot) |= VM_PROT_READ;
715 SCARG(cma, flags) = flags;
716 SCARG(cma, fd) = flags & MAP_ANON ? -1 : SCARG(uap, fd);
717 SCARG(cma, pad) = 0;
718 }
719
720 int
linux_sys_mremap(p,v,retval)721 linux_sys_mremap(p, v, retval)
722 struct proc *p;
723 void *v;
724 register_t *retval;
725 {
726
727 struct linux_sys_mremap_args /* {
728 syscallarg(void *) old_address;
729 syscallarg(size_t) old_size;
730 syscallarg(size_t) new_size;
731 syscallarg(u_long) flags;
732 } */ *uap = v;
733 struct sys_munmap_args mua;
734 size_t old_size, new_size;
735 int error;
736
737 old_size = round_page(SCARG(uap, old_size));
738 new_size = round_page(SCARG(uap, new_size));
739
740 /*
741 * Growing mapped region.
742 */
743 if (new_size > old_size) {
744 /*
745 * XXX Implement me. What we probably want to do is
746 * XXX dig out the guts of the old mapping, mmap that
747 * XXX object again with the new size, then munmap
748 * XXX the old mapping.
749 */
750 *retval = 0;
751 return (ENOMEM);
752 }
753 /*
754 * Shrinking mapped region.
755 */
756 if (new_size < old_size) {
757 SCARG(&mua, addr) = (caddr_t)SCARG(uap, old_address) + new_size;
758 SCARG(&mua, len) = old_size - new_size;
759 error = sys_munmap(p, &mua, retval);
760 *retval = error ? 0 : (register_t)SCARG(uap, old_address);
761 return (error);
762 }
763
764 /*
765 * No change.
766 */
767 *retval = (register_t)SCARG(uap, old_address);
768 return (0);
769
770 }
771
772 /*
773 * This code is partly stolen from src/lib/libc/gen/times.c
774 * XXX - CLK_TCK isn't declared in /sys, just in <time.h>, done here
775 */
776
777 #define CLK_TCK 100
778 #define CONVTCK(r) (r.tv_sec * CLK_TCK + r.tv_usec / (1000000 / CLK_TCK))
779
780 int
linux_sys_times(p,v,retval)781 linux_sys_times(p, v, retval)
782 struct proc *p;
783 void *v;
784 register_t *retval;
785 {
786 struct linux_sys_times_args /* {
787 syscallarg(struct times *) tms;
788 } */ *uap = v;
789 struct timeval t;
790 struct linux_tms ltms;
791 struct rusage ru;
792 int error, s;
793
794 calcru(p, &ru.ru_utime, &ru.ru_stime, NULL);
795 ltms.ltms_utime = CONVTCK(ru.ru_utime);
796 ltms.ltms_stime = CONVTCK(ru.ru_stime);
797
798 ltms.ltms_cutime = CONVTCK(p->p_stats->p_cru.ru_utime);
799 ltms.ltms_cstime = CONVTCK(p->p_stats->p_cru.ru_stime);
800
801 if ((error = copyout(<ms, SCARG(uap, tms), sizeof ltms)))
802 return error;
803
804 s = splclock();
805 timersub(&time, &boottime, &t);
806 splx(s);
807
808 retval[0] = ((linux_clock_t)(CONVTCK(t)));
809 return 0;
810 }
811
812 /*
813 * OpenBSD passes fd[0] in retval[0], and fd[1] in retval[1].
814 * Linux directly passes the pointer.
815 */
816 int
linux_sys_pipe(p,v,retval)817 linux_sys_pipe(p, v, retval)
818 struct proc *p;
819 void *v;
820 register_t *retval;
821 {
822 struct linux_sys_pipe_args /* {
823 syscallarg(int *) pfds;
824 } */ *uap = v;
825 int error;
826 int pfds[2];
827 #ifdef __i386__
828 int reg_edx = retval[1];
829 #endif /* __i386__ */
830
831 if ((error = sys_opipe(p, 0, retval))) {
832 #ifdef __i386__
833 retval[1] = reg_edx;
834 #endif /* __i386__ */
835 return error;
836 }
837
838 /* Assumes register_t is an int */
839
840 pfds[0] = retval[0];
841 pfds[1] = retval[1];
842 if ((error = copyout(pfds, SCARG(uap, pfds), 2 * sizeof (int)))) {
843 #ifdef __i386__
844 retval[1] = reg_edx;
845 #endif /* __i386__ */
846 fdrelease(p, retval[0]);
847 fdrelease(p, retval[1]);
848 return error;
849 }
850
851 retval[0] = 0;
852 #ifdef __i386__
853 retval[1] = reg_edx;
854 #endif /* __i386__ */
855 return 0;
856 }
857
858 /*
859 * Alarm. This is a libc call which uses setitimer(2) in OpenBSD.
860 * Fiddle with the timers to make it work.
861 */
862 int
linux_sys_alarm(p,v,retval)863 linux_sys_alarm(p, v, retval)
864 struct proc *p;
865 void *v;
866 register_t *retval;
867 {
868 struct linux_sys_alarm_args /* {
869 syscallarg(unsigned int) secs;
870 } */ *uap = v;
871 int s;
872 struct itimerval *itp, it;
873 int timo;
874
875 itp = &p->p_realtimer;
876 s = splclock();
877 /*
878 * Clear any pending timer alarms.
879 */
880
881 timeout_del(&p->p_realit_to);
882 timerclear(&itp->it_interval);
883 if (timerisset(&itp->it_value) &&
884 timercmp(&itp->it_value, &time, >))
885 timersub(&itp->it_value, &time, &itp->it_value);
886 /*
887 * Return how many seconds were left (rounded up)
888 */
889 retval[0] = itp->it_value.tv_sec;
890 if (itp->it_value.tv_usec)
891 retval[0]++;
892
893 /*
894 * alarm(0) just resets the timer.
895 */
896 if (SCARG(uap, secs) == 0) {
897 timerclear(&itp->it_value);
898 splx(s);
899 return 0;
900 }
901
902 /*
903 * Check the new alarm time for sanity, and set it.
904 */
905 timerclear(&it.it_interval);
906 it.it_value.tv_sec = SCARG(uap, secs);
907 it.it_value.tv_usec = 0;
908 if (itimerfix(&it.it_value) || itimerfix(&it.it_interval)) {
909 splx(s);
910 return (EINVAL);
911 }
912
913 if (timerisset(&it.it_value)) {
914 timo = tvtohz(&it.it_value);
915 if (timo <= 0)
916 timo = 1;
917 timeradd(&it.it_value, &time, &it.it_value);
918 timeout_add(&p->p_realit_to, timo);
919 }
920 p->p_realtimer = it;
921 splx(s);
922
923 return 0;
924 }
925
926 /*
927 * utime(). Do conversion to things that utimes() understands,
928 * and pass it on.
929 */
930 int
linux_sys_utime(p,v,retval)931 linux_sys_utime(p, v, retval)
932 struct proc *p;
933 void *v;
934 register_t *retval;
935 {
936 struct linux_sys_utime_args /* {
937 syscallarg(char *) path;
938 syscallarg(struct linux_utimbuf *)times;
939 } */ *uap = v;
940 caddr_t sg;
941 int error;
942 struct sys_utimes_args ua;
943 struct timeval tv[2], *tvp;
944 struct linux_utimbuf lut;
945
946 sg = stackgap_init(p->p_emul);
947 tvp = (struct timeval *) stackgap_alloc(&sg, sizeof(tv));
948 LINUX_CHECK_ALT_EXIST(p, &sg, SCARG(uap, path));
949
950 SCARG(&ua, path) = SCARG(uap, path);
951
952 if (SCARG(uap, times) != NULL) {
953 if ((error = copyin(SCARG(uap, times), &lut, sizeof lut)))
954 return error;
955 tv[0].tv_usec = tv[1].tv_usec = 0;
956 tv[0].tv_sec = lut.l_actime;
957 tv[1].tv_sec = lut.l_modtime;
958 if ((error = copyout(tv, tvp, sizeof tv)))
959 return error;
960 SCARG(&ua, tptr) = tvp;
961 }
962 else
963 SCARG(&ua, tptr) = NULL;
964
965 return sys_utimes(p, &ua, retval);
966 }
967
968 /*
969 * The old Linux readdir was only able to read one entry at a time,
970 * even though it had a 'count' argument. In fact, the emulation
971 * of the old call was better than the original, because it did handle
972 * the count arg properly. Don't bother with it anymore now, and use
973 * it to distinguish between old and new. The difference is that the
974 * newer one actually does multiple entries, and the reclen field
975 * really is the reclen, not the namelength.
976 */
977 int
linux_sys_readdir(p,v,retval)978 linux_sys_readdir(p, v, retval)
979 struct proc *p;
980 void *v;
981 register_t *retval;
982 {
983 struct linux_sys_readdir_args /* {
984 syscallarg(int) fd;
985 syscallarg(struct linux_dirent *) dent;
986 syscallarg(unsigned int) count;
987 } */ *uap = v;
988
989 SCARG(uap, count) = 1;
990
991 return linux_sys_getdents(p, uap, retval);
992 }
993
994 /*
995 * Linux 'readdir' call. This code is mostly taken from the
996 * SunOS getdents call (see compat/sunos/sunos_misc.c), though
997 * an attempt has been made to keep it a little cleaner (failing
998 * miserably, because of the cruft needed if count 1 is passed).
999 *
1000 * The d_off field should contain the offset of the next valid entry,
1001 * but in Linux it has the offset of the entry itself. We emulate
1002 * that bug here.
1003 *
1004 * Read in BSD-style entries, convert them, and copy them out.
1005 *
1006 * Note that this doesn't handle union-mounted filesystems.
1007 */
1008 int linux_readdir_callback(void *, struct dirent *, off_t);
1009
1010 struct linux_readdir_callback_args {
1011 caddr_t outp;
1012 int resid;
1013 int oldcall;
1014 int is64bit;
1015 };
1016
1017 int
linux_readdir_callback(arg,bdp,cookie)1018 linux_readdir_callback(arg, bdp, cookie)
1019 void *arg;
1020 struct dirent *bdp;
1021 off_t cookie;
1022 {
1023 struct linux_dirent64 idb64;
1024 struct linux_dirent idb;
1025 struct linux_readdir_callback_args *cb = arg;
1026 int linux_reclen;
1027 int error;
1028
1029 if (cb->oldcall == 2)
1030 return (ENOMEM);
1031
1032 linux_reclen = (cb->is64bit) ?
1033 LINUX_RECLEN(&idb64, bdp->d_namlen) :
1034 LINUX_RECLEN(&idb, bdp->d_namlen);
1035
1036 if (cb->resid < linux_reclen)
1037 return (ENOMEM);
1038
1039 if (cb->is64bit) {
1040 idb64.d_ino = (linux_ino64_t)bdp->d_fileno;
1041 idb64.d_off = (linux_off64_t)cookie;
1042 idb64.d_reclen = (u_short)linux_reclen;
1043 idb64.d_type = bdp->d_type;
1044 strlcpy(idb64.d_name, bdp->d_name, sizeof(idb64.d_name));
1045 error = copyout((caddr_t)&idb64, cb->outp, linux_reclen);
1046 } else {
1047 idb.d_ino = (linux_ino_t)bdp->d_fileno;
1048 if (cb->oldcall) {
1049 /*
1050 * The old readdir() call misuses the offset
1051 * and reclen fields.
1052 */
1053 idb.d_off = (linux_off_t)linux_reclen;
1054 idb.d_reclen = (u_short)bdp->d_namlen;
1055 } else {
1056 idb.d_off = (linux_off_t)cookie;
1057 idb.d_reclen = (u_short)linux_reclen;
1058 }
1059 strlcpy(idb.d_name, bdp->d_name, sizeof(idb.d_name));
1060 error = copyout((caddr_t)&idb, cb->outp, linux_reclen);
1061 }
1062 if (error)
1063 return (error);
1064
1065 /* advance output past Linux-shaped entry */
1066 cb->outp += linux_reclen;
1067 cb->resid -= linux_reclen;
1068
1069 if (cb->oldcall == 1)
1070 ++cb->oldcall;
1071
1072 return (0);
1073 }
1074
1075 int
linux_sys_getdents64(p,v,retval)1076 linux_sys_getdents64(p, v, retval)
1077 struct proc *p;
1078 void *v;
1079 register_t *retval;
1080 {
1081 return getdents_common(p, v, retval, 1);
1082 }
1083
1084 int
linux_sys_getdents(p,v,retval)1085 linux_sys_getdents(p, v, retval)
1086 struct proc *p;
1087 void *v;
1088 register_t *retval;
1089 {
1090 return getdents_common(p, v, retval, 0);
1091 }
1092
1093 static int
getdents_common(p,v,retval,is64bit)1094 getdents_common(p, v, retval, is64bit)
1095 struct proc *p;
1096 void *v;
1097 register_t *retval;
1098 int is64bit;
1099 {
1100 struct linux_sys_getdents_args /* {
1101 syscallarg(int) fd;
1102 syscallarg(void *) dirent;
1103 syscallarg(unsigned) count;
1104 } */ *uap = v;
1105 struct linux_readdir_callback_args args;
1106 struct file *fp;
1107 int error;
1108 int nbytes = SCARG(uap, count);
1109
1110 if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
1111 return (error);
1112
1113 if (nbytes == 1) { /* emulating old, broken behaviour */
1114 /* readdir(2) case. Always struct dirent. */
1115 if (is64bit) {
1116 FRELE(fp);
1117 return (EINVAL);
1118 }
1119 nbytes = sizeof(struct linux_dirent);
1120 args.oldcall = 1;
1121 } else {
1122 args.oldcall = 0;
1123 }
1124
1125 args.resid = nbytes;
1126 args.outp = (caddr_t)SCARG(uap, dirent);
1127 args.is64bit = is64bit;
1128
1129 if ((error = readdir_with_callback(fp, &fp->f_offset, nbytes,
1130 linux_readdir_callback, &args)) != 0)
1131 goto exit;
1132
1133 *retval = nbytes - args.resid;
1134
1135 exit:
1136 FRELE(fp);
1137 return (error);
1138 }
1139
1140 /*
1141 * Not sure why the arguments to this older version of select() were put
1142 * into a structure, because there are 5, and that can all be handled
1143 * in registers on the i386 like Linux wants to.
1144 */
1145 int
linux_sys_oldselect(p,v,retval)1146 linux_sys_oldselect(p, v, retval)
1147 struct proc *p;
1148 void *v;
1149 register_t *retval;
1150 {
1151 struct linux_sys_oldselect_args /* {
1152 syscallarg(struct linux_select *) lsp;
1153 } */ *uap = v;
1154 struct linux_select ls;
1155 int error;
1156
1157 if ((error = copyin(SCARG(uap, lsp), &ls, sizeof(ls))))
1158 return error;
1159
1160 return linux_select1(p, retval, ls.nfds, ls.readfds, ls.writefds,
1161 ls.exceptfds, ls.timeout);
1162 }
1163
1164 /*
1165 * Even when just using registers to pass arguments to syscalls you can
1166 * have 5 of them on the i386. So this newer version of select() does
1167 * this.
1168 */
1169 int
linux_sys_select(p,v,retval)1170 linux_sys_select(p, v, retval)
1171 struct proc *p;
1172 void *v;
1173 register_t *retval;
1174 {
1175 struct linux_sys_select_args /* {
1176 syscallarg(int) nfds;
1177 syscallarg(fd_set *) readfds;
1178 syscallarg(fd_set *) writefds;
1179 syscallarg(fd_set *) exceptfds;
1180 syscallarg(struct timeval_compat *) timeout;
1181 } */ *uap = v;
1182
1183 return linux_select1(p, retval, SCARG(uap, nfds), SCARG(uap, readfds),
1184 SCARG(uap, writefds), SCARG(uap, exceptfds), SCARG(uap, timeout));
1185 }
1186
1187 /*
1188 * Common code for the old and new versions of select(). A couple of
1189 * things are important:
1190 * 1) return the amount of time left in the 'timeout' parameter
1191 * 2) select never returns ERESTART on Linux, always return EINTR
1192 */
1193 int
linux_select1(p,retval,nfds,readfds,writefds,exceptfds,timeout)1194 linux_select1(p, retval, nfds, readfds, writefds, exceptfds, timeout)
1195 struct proc *p;
1196 register_t *retval;
1197 int nfds;
1198 fd_set *readfds, *writefds, *exceptfds;
1199 struct timeval_compat *timeout;
1200 {
1201 struct sys_select_args bsa;
1202 struct timeval tv0, tv1, utv64, *tvp;
1203 struct timeval_compat utv;
1204 caddr_t sg;
1205 int error;
1206
1207 sg = stackgap_init(p->p_emul);
1208 tvp = stackgap_alloc(&sg, sizeof(utv64));
1209
1210 SCARG(&bsa, nd) = nfds;
1211 SCARG(&bsa, in) = readfds;
1212 SCARG(&bsa, ou) = writefds;
1213 SCARG(&bsa, ex) = exceptfds;
1214 SCARG(&bsa, tv) = NULL;
1215
1216 /*
1217 * Store current time for computation of the amount of
1218 * time left.
1219 */
1220 if (timeout) {
1221 if ((error = copyin(timeout, &utv, sizeof(utv))))
1222 return error;
1223 utv64.tv_sec = utv.tv_sec;
1224 utv64.tv_usec = utv.tv_usec;
1225 if (itimerfix(&utv64)) {
1226 /*
1227 * The timeval was invalid. Convert it to something
1228 * valid that will act as it does under Linux.
1229 */
1230 utv64.tv_sec += utv64.tv_usec / 1000000;
1231 utv64.tv_usec %= 1000000;
1232 if (utv64.tv_usec < 0) {
1233 utv64.tv_sec -= 1;
1234 utv64.tv_usec += 1000000;
1235 }
1236 if (utv64.tv_sec < 0)
1237 timerclear(&utv64);
1238 }
1239 if ((error = copyout(&utv64, tvp, sizeof(utv64))))
1240 return error;
1241 SCARG(&bsa, tv) = tvp;
1242 microtime(&tv0);
1243 }
1244
1245 error = sys_select(p, &bsa, retval);
1246 if (error) {
1247 /*
1248 * See fs/select.c in the Linux kernel. Without this,
1249 * Maelstrom doesn't work.
1250 */
1251 if (error == ERESTART)
1252 error = EINTR;
1253 return error;
1254 }
1255
1256 if (timeout) {
1257 if (*retval) {
1258 /*
1259 * Compute how much time was left of the timeout,
1260 * by subtracting the current time and the time
1261 * before we started the call, and subtracting
1262 * that result from the user-supplied value.
1263 */
1264 microtime(&tv1);
1265 timersub(&tv1, &tv0, &tv1);
1266 timersub(&utv64, &tv1, &utv64);
1267 if (utv64.tv_sec < 0)
1268 timerclear(&utv64);
1269 } else
1270 timerclear(&utv64);
1271 utv.tv_sec = utv64.tv_sec;
1272 utv.tv_usec = utv64.tv_usec;
1273 if ((error = copyout(&utv, timeout, sizeof(utv))))
1274 return error;
1275 }
1276
1277 return 0;
1278 }
1279
1280 /*
1281 * Get the process group of a certain process. Look it up
1282 * and return the value.
1283 */
1284 int
linux_sys_getpgid(p,v,retval)1285 linux_sys_getpgid(p, v, retval)
1286 struct proc *p;
1287 void *v;
1288 register_t *retval;
1289 {
1290 struct linux_sys_getpgid_args /* {
1291 syscallarg(int) pid;
1292 } */ *uap = v;
1293 struct proc *targp;
1294
1295 if (SCARG(uap, pid) != 0 && SCARG(uap, pid) != p->p_pid) {
1296 if ((targp = pfind(SCARG(uap, pid))) == 0)
1297 return ESRCH;
1298 }
1299 else
1300 targp = p;
1301
1302 retval[0] = targp->p_pgid;
1303 return 0;
1304 }
1305
1306 /*
1307 * Set the 'personality' (emulation mode) for the current process. Only
1308 * accept the Linux personality here (0). This call is needed because
1309 * the Linux ELF crt0 issues it in an ugly kludge to make sure that
1310 * ELF binaries run in Linux mode, not SVR4 mode.
1311 */
1312 int
linux_sys_personality(p,v,retval)1313 linux_sys_personality(p, v, retval)
1314 struct proc *p;
1315 void *v;
1316 register_t *retval;
1317 {
1318 struct linux_sys_personality_args /* {
1319 syscallarg(int) per;
1320 } */ *uap = v;
1321
1322 if (SCARG(uap, per) != 0)
1323 return EINVAL;
1324 retval[0] = 0;
1325 return 0;
1326 }
1327
1328 /*
1329 * The calls are here because of type conversions.
1330 */
1331 int
linux_sys_setreuid16(p,v,retval)1332 linux_sys_setreuid16(p, v, retval)
1333 struct proc *p;
1334 void *v;
1335 register_t *retval;
1336 {
1337 struct linux_sys_setreuid16_args /* {
1338 syscallarg(int) ruid;
1339 syscallarg(int) euid;
1340 } */ *uap = v;
1341 struct sys_setreuid_args bsa;
1342
1343 SCARG(&bsa, ruid) = ((linux_uid_t)SCARG(uap, ruid) == (linux_uid_t)-1) ?
1344 (uid_t)-1 : SCARG(uap, ruid);
1345 SCARG(&bsa, euid) = ((linux_uid_t)SCARG(uap, euid) == (linux_uid_t)-1) ?
1346 (uid_t)-1 : SCARG(uap, euid);
1347
1348 return sys_setreuid(p, &bsa, retval);
1349 }
1350
1351 int
linux_sys_setregid16(p,v,retval)1352 linux_sys_setregid16(p, v, retval)
1353 struct proc *p;
1354 void *v;
1355 register_t *retval;
1356 {
1357 struct linux_sys_setregid16_args /* {
1358 syscallarg(int) rgid;
1359 syscallarg(int) egid;
1360 } */ *uap = v;
1361 struct sys_setregid_args bsa;
1362
1363 SCARG(&bsa, rgid) = ((linux_gid_t)SCARG(uap, rgid) == (linux_gid_t)-1) ?
1364 (uid_t)-1 : SCARG(uap, rgid);
1365 SCARG(&bsa, egid) = ((linux_gid_t)SCARG(uap, egid) == (linux_gid_t)-1) ?
1366 (uid_t)-1 : SCARG(uap, egid);
1367
1368 return sys_setregid(p, &bsa, retval);
1369 }
1370
1371 int
linux_sys_getsid(p,v,retval)1372 linux_sys_getsid(p, v, retval)
1373 struct proc *p;
1374 void *v;
1375 register_t *retval;
1376 {
1377 struct linux_sys_getsid_args /* {
1378 syscallarg(int) pid;
1379 } */ *uap = v;
1380 struct proc *p1;
1381 pid_t pid;
1382
1383 pid = (pid_t)SCARG(uap, pid);
1384
1385 if (pid == 0) {
1386 retval[0] = (int)p->p_session; /* XXX Oh well */
1387 return 0;
1388 }
1389
1390 p1 = pfind((int)pid);
1391 if (p1 == NULL)
1392 return ESRCH;
1393
1394 retval[0] = (int)p1->p_session;
1395 return 0;
1396 }
1397
1398 int
linux_sys___sysctl(p,v,retval)1399 linux_sys___sysctl(p, v, retval)
1400 struct proc *p;
1401 void *v;
1402 register_t *retval;
1403 {
1404 struct linux_sys___sysctl_args /* {
1405 syscallarg(struct linux___sysctl *) lsp;
1406 } */ *uap = v;
1407 struct linux___sysctl ls;
1408 struct sys___sysctl_args bsa;
1409 int error;
1410
1411 if ((error = copyin(SCARG(uap, lsp), &ls, sizeof ls)))
1412 return error;
1413 SCARG(&bsa, name) = ls.name;
1414 SCARG(&bsa, namelen) = ls.namelen;
1415 SCARG(&bsa, old) = ls.old;
1416 SCARG(&bsa, oldlenp) = ls.oldlenp;
1417 SCARG(&bsa, new) = ls.new;
1418 SCARG(&bsa, newlen) = ls.newlen;
1419
1420 return sys___sysctl(p, &bsa, retval);
1421 }
1422
1423 /*
1424 * We have nonexistent fsuid equal to uid.
1425 * If modification is requested, refuse.
1426 */
1427 int
linux_sys_setfsuid(p,v,retval)1428 linux_sys_setfsuid(p, v, retval)
1429 struct proc *p;
1430 void *v;
1431 register_t *retval;
1432 {
1433 struct linux_sys_setfsuid_args /* {
1434 syscallarg(uid_t) uid;
1435 } */ *uap = v;
1436 uid_t uid;
1437
1438 uid = SCARG(uap, uid);
1439 if (p->p_cred->p_ruid != uid)
1440 return sys_nosys(p, v, retval);
1441 else
1442 return (0);
1443 }
1444
1445 int
linux_sys_getfsuid(p,v,retval)1446 linux_sys_getfsuid(p, v, retval)
1447 struct proc *p;
1448 void *v;
1449 register_t *retval;
1450 {
1451 return sys_getuid(p, v, retval);
1452 }
1453
1454
1455 int
linux_sys_nice(p,v,retval)1456 linux_sys_nice(p, v, retval)
1457 struct proc *p;
1458 void *v;
1459 register_t *retval;
1460 {
1461 struct linux_sys_nice_args /* {
1462 syscallarg(int) incr;
1463 } */ *uap = v;
1464 struct sys_setpriority_args bsa;
1465
1466 SCARG(&bsa, which) = PRIO_PROCESS;
1467 SCARG(&bsa, who) = 0;
1468 SCARG(&bsa, prio) = SCARG(uap, incr);
1469 return sys_setpriority(p, &bsa, retval);
1470 }
1471
1472 int
linux_sys_stime(p,v,retval)1473 linux_sys_stime(p, v, retval)
1474 struct proc *p;
1475 void *v;
1476 register_t *retval;
1477 {
1478 struct linux_sys_time_args /* {
1479 linux_time_t *t;
1480 } */ *uap = v;
1481 struct timeval atv;
1482 linux_time_t tt;
1483 int error;
1484
1485 if ((error = suser(p, 0)) != 0)
1486 return (error);
1487
1488 if ((error = copyin(SCARG(uap, t), &tt, sizeof(tt))) != 0)
1489 return (error);
1490
1491 atv.tv_sec = tt;
1492 atv.tv_usec = 0;
1493
1494 error = settime(&atv);
1495
1496 return (error);
1497 }
1498
1499 int
linux_sys_getpid(p,v,retval)1500 linux_sys_getpid(p, v, retval)
1501 struct proc *p;
1502 void *v;
1503 register_t *retval;
1504 {
1505
1506 *retval = p->p_pid;
1507 return (0);
1508 }
1509
1510 int
linux_sys_getuid(p,v,retval)1511 linux_sys_getuid(p, v, retval)
1512 struct proc *p;
1513 void *v;
1514 register_t *retval;
1515 {
1516
1517 *retval = p->p_cred->p_ruid;
1518 return (0);
1519 }
1520
1521 int
linux_sys_getgid(p,v,retval)1522 linux_sys_getgid(p, v, retval)
1523 struct proc *p;
1524 void *v;
1525 register_t *retval;
1526 {
1527
1528 *retval = p->p_cred->p_rgid;
1529 return (0);
1530 }
1531
1532
1533 /*
1534 * sysinfo()
1535 */
1536 /* ARGSUSED */
1537 int
linux_sys_sysinfo(p,v,retval)1538 linux_sys_sysinfo(p, v, retval)
1539 struct proc *p;
1540 void *v;
1541 register_t *retval;
1542 {
1543 struct linux_sys_sysinfo_args /* {
1544 syscallarg(struct linux_sysinfo *) sysinfo;
1545 } */ *uap = v;
1546 struct linux_sysinfo si;
1547 struct loadavg *la;
1548 extern int bufpages;
1549
1550
1551 si.uptime = time.tv_sec - boottime.tv_sec;
1552 la = &averunnable;
1553 si.loads[0] = la->ldavg[0] * LINUX_SYSINFO_LOADS_SCALE / la->fscale;
1554 si.loads[1] = la->ldavg[1] * LINUX_SYSINFO_LOADS_SCALE / la->fscale;
1555 si.loads[2] = la->ldavg[2] * LINUX_SYSINFO_LOADS_SCALE / la->fscale;
1556 si.totalram = ctob(physmem);
1557 si.freeram = uvmexp.free * uvmexp.pagesize;
1558 si.sharedram = 0;/* XXX */
1559 si.bufferram = bufpages * PAGE_SIZE;
1560 si.totalswap = uvmexp.swpages * PAGE_SIZE;
1561 si.freeswap = (uvmexp.swpages - uvmexp.swpginuse) * PAGE_SIZE;
1562 si.procs = nprocs;
1563 /* The following are only present in newer Linux kernels. */
1564 si.totalbig = 0;
1565 si.freebig = 0;
1566 si.mem_unit = 1;
1567
1568 return (copyout(&si, SCARG(uap, sysinfo), sizeof(si)));
1569 }
1570
1571 int
linux_sys_ptrace(l,v,retval)1572 linux_sys_ptrace(l, v, retval)
1573 struct proc *l;
1574 void *v;
1575 register_t *retval;
1576 {
1577 struct linux_sys_ptrace_args /* {
1578 i386, m68k, powerpc: T=int
1579 alpha, amd64: T=long
1580 syscallarg(T) request;
1581 syscallarg(T) pid;
1582 syscallarg(T) addr;
1583 syscallarg(T) data;
1584 } */ *uap = v;
1585 const int *ptr;
1586 int request;
1587 int error;
1588
1589 ptr = linux_ptrace_request_map;
1590 request = SCARG(uap, request);
1591 while (*ptr != -1)
1592 if (*ptr++ == request) {
1593 struct sys_ptrace_args pta;
1594
1595 SCARG(&pta, req) = *ptr;
1596 SCARG(&pta, pid) = SCARG(uap, pid);
1597 SCARG(&pta, addr) = (caddr_t)SCARG(uap, addr);
1598 SCARG(&pta, data) = SCARG(uap, data);
1599
1600 /*
1601 * Linux ptrace(PTRACE_CONT, pid, 0, 0) means actually
1602 * to continue where the process left off previously.
1603 * The same thing is achieved by addr == (caddr_t) 1
1604 * on NetBSD, so rewrite 'addr' appropriately.
1605 */
1606 if (request == LINUX_PTRACE_CONT && SCARG(uap, addr)==0)
1607 SCARG(&pta, addr) = (caddr_t) 1;
1608
1609 error = sys_ptrace(l, &pta, retval);
1610 if (error)
1611 return error;
1612 switch (request) {
1613 case LINUX_PTRACE_PEEKTEXT:
1614 case LINUX_PTRACE_PEEKDATA:
1615 error = copyout (retval,
1616 (caddr_t)SCARG(uap, data),
1617 sizeof *retval);
1618 *retval = SCARG(uap, data);
1619 break;
1620 default:
1621 break;
1622 }
1623 return error;
1624 }
1625 else
1626 ptr++;
1627
1628 return LINUX_SYS_PTRACE_ARCH(l, uap, retval);
1629 }
1630