Deleted Added
full compact
linux_misc.c (141467) linux_misc.c (143197)
1/*-
2 * Copyright (c) 2002 Doug Rabson
3 * Copyright (c) 1994-1995 S�ren Schmidt
4 * 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 * in this position and unchanged.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30#include <sys/cdefs.h>
1/*-
2 * Copyright (c) 2002 Doug Rabson
3 * Copyright (c) 1994-1995 S�ren Schmidt
4 * 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 * in this position and unchanged.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30#include <sys/cdefs.h>
31__FBSDID("$FreeBSD: head/sys/compat/linux/linux_misc.c 141467 2005-02-07 18:36:21Z jhb $");
31__FBSDID("$FreeBSD: head/sys/compat/linux/linux_misc.c 143197 2005-03-07 00:18:06Z sobomax $");
32
33#include "opt_mac.h"
34
35#include <sys/param.h>
36#include <sys/blist.h>
37#include <sys/fcntl.h>
38#if defined(__i386__) || defined(__alpha__)
39#include <sys/imgact_aout.h>
40#endif
41#include <sys/jail.h>
42#include <sys/kernel.h>
43#include <sys/limits.h>
44#include <sys/lock.h>
45#include <sys/mac.h>
46#include <sys/malloc.h>
47#include <sys/mman.h>
48#include <sys/mount.h>
49#include <sys/mutex.h>
50#include <sys/namei.h>
51#include <sys/proc.h>
52#include <sys/reboot.h>
53#include <sys/resourcevar.h>
54#include <sys/signalvar.h>
55#include <sys/stat.h>
56#include <sys/syscallsubr.h>
57#include <sys/sysctl.h>
58#include <sys/sysproto.h>
59#include <sys/systm.h>
60#include <sys/time.h>
61#include <sys/vmmeter.h>
62#include <sys/vnode.h>
63#include <sys/wait.h>
64
65#include <vm/vm.h>
66#include <vm/pmap.h>
67#include <vm/vm_kern.h>
68#include <vm/vm_map.h>
69#include <vm/vm_extern.h>
70#include <vm/vm_object.h>
71#include <vm/swap_pager.h>
72
73#include <posix4/sched.h>
74
75#include "opt_compat.h"
76
32
33#include "opt_mac.h"
34
35#include <sys/param.h>
36#include <sys/blist.h>
37#include <sys/fcntl.h>
38#if defined(__i386__) || defined(__alpha__)
39#include <sys/imgact_aout.h>
40#endif
41#include <sys/jail.h>
42#include <sys/kernel.h>
43#include <sys/limits.h>
44#include <sys/lock.h>
45#include <sys/mac.h>
46#include <sys/malloc.h>
47#include <sys/mman.h>
48#include <sys/mount.h>
49#include <sys/mutex.h>
50#include <sys/namei.h>
51#include <sys/proc.h>
52#include <sys/reboot.h>
53#include <sys/resourcevar.h>
54#include <sys/signalvar.h>
55#include <sys/stat.h>
56#include <sys/syscallsubr.h>
57#include <sys/sysctl.h>
58#include <sys/sysproto.h>
59#include <sys/systm.h>
60#include <sys/time.h>
61#include <sys/vmmeter.h>
62#include <sys/vnode.h>
63#include <sys/wait.h>
64
65#include <vm/vm.h>
66#include <vm/pmap.h>
67#include <vm/vm_kern.h>
68#include <vm/vm_map.h>
69#include <vm/vm_extern.h>
70#include <vm/vm_object.h>
71#include <vm/swap_pager.h>
72
73#include <posix4/sched.h>
74
75#include "opt_compat.h"
76
77#include <compat/linux/linux_sysproto.h>
78
77#ifdef COMPAT_LINUX32
78#include <machine/../linux32/linux.h>
79#include <machine/../linux32/linux32_proto.h>
80#else
81#include <machine/../linux/linux.h>
82#include <machine/../linux/linux_proto.h>
83#endif
84
85#include <compat/linux/linux_mib.h>
86#include <compat/linux/linux_util.h>
87
88#ifdef __i386__
89#include <machine/cputypes.h>
90#endif
91
92#ifdef __alpha__
93#define BSD_TO_LINUX_SIGNAL(sig) (sig)
94#else
95#define BSD_TO_LINUX_SIGNAL(sig) \
96 (((sig) <= LINUX_SIGTBLSZ) ? bsd_to_linux_signal[_SIG_IDX(sig)] : sig)
97#endif
98
99#ifndef __alpha__
100static unsigned int linux_to_bsd_resource[LINUX_RLIM_NLIMITS] = {
101 RLIMIT_CPU, RLIMIT_FSIZE, RLIMIT_DATA, RLIMIT_STACK,
102 RLIMIT_CORE, RLIMIT_RSS, RLIMIT_NPROC, RLIMIT_NOFILE,
103 RLIMIT_MEMLOCK, -1
104};
105#endif /*!__alpha__*/
106
107struct l_sysinfo {
108 l_long uptime; /* Seconds since boot */
109 l_ulong loads[3]; /* 1, 5, and 15 minute load averages */
110#define LINUX_SYSINFO_LOADS_SCALE 65536
111 l_ulong totalram; /* Total usable main memory size */
112 l_ulong freeram; /* Available memory size */
113 l_ulong sharedram; /* Amount of shared memory */
114 l_ulong bufferram; /* Memory used by buffers */
115 l_ulong totalswap; /* Total swap space size */
116 l_ulong freeswap; /* swap space still available */
117 l_ushort procs; /* Number of current processes */
118 l_ulong totalbig;
119 l_ulong freebig;
120 l_uint mem_unit;
121 char _f[6]; /* Pads structure to 64 bytes */
122};
123#ifndef __alpha__
124int
125linux_sysinfo(struct thread *td, struct linux_sysinfo_args *args)
126{
127 struct l_sysinfo sysinfo;
128 vm_object_t object;
129 int i, j;
130 struct timespec ts;
131
132 /* Uptime is copied out of print_uptime() in kern_shutdown.c */
133 getnanouptime(&ts);
134 i = 0;
135 if (ts.tv_sec >= 86400) {
136 ts.tv_sec %= 86400;
137 i = 1;
138 }
139 if (i || ts.tv_sec >= 3600) {
140 ts.tv_sec %= 3600;
141 i = 1;
142 }
143 if (i || ts.tv_sec >= 60) {
144 ts.tv_sec %= 60;
145 i = 1;
146 }
147 sysinfo.uptime=ts.tv_sec;
148
149 /* Use the information from the mib to get our load averages */
150 for (i = 0; i < 3; i++)
151 sysinfo.loads[i] = averunnable.ldavg[i] *
152 LINUX_SYSINFO_LOADS_SCALE / averunnable.fscale;
153
154 sysinfo.totalram = physmem * PAGE_SIZE;
155 sysinfo.freeram = sysinfo.totalram - cnt.v_wire_count * PAGE_SIZE;
156
157 sysinfo.sharedram = 0;
158 mtx_lock(&vm_object_list_mtx);
159 TAILQ_FOREACH(object, &vm_object_list, object_list)
160 if (object->shadow_count > 1)
161 sysinfo.sharedram += object->resident_page_count;
162 mtx_unlock(&vm_object_list_mtx);
163
164 sysinfo.sharedram *= PAGE_SIZE;
165 sysinfo.bufferram = 0;
166
167 swap_pager_status(&i, &j);
168 sysinfo.totalswap= i * PAGE_SIZE;
169 sysinfo.freeswap = (i - j) * PAGE_SIZE;
170
171 sysinfo.procs = nprocs;
172
173 /* The following are only present in newer Linux kernels. */
174 sysinfo.totalbig = 0;
175 sysinfo.freebig = 0;
176 sysinfo.mem_unit = 1;
177
178 return copyout(&sysinfo, args->info, sizeof(sysinfo));
179}
180#endif /*!__alpha__*/
181
182#ifndef __alpha__
183int
184linux_alarm(struct thread *td, struct linux_alarm_args *args)
185{
186 struct itimerval it, old_it;
187 int error;
188
189#ifdef DEBUG
190 if (ldebug(alarm))
191 printf(ARGS(alarm, "%u"), args->secs);
192#endif
193
194 if (args->secs > 100000000)
195 return (EINVAL);
196
197 it.it_value.tv_sec = (long)args->secs;
198 it.it_value.tv_usec = 0;
199 it.it_interval.tv_sec = 0;
200 it.it_interval.tv_usec = 0;
201 error = kern_setitimer(td, ITIMER_REAL, &it, &old_it);
202 if (error)
203 return (error);
204 if (timevalisset(&old_it.it_value)) {
205 if (old_it.it_value.tv_usec != 0)
206 old_it.it_value.tv_sec++;
207 td->td_retval[0] = old_it.it_value.tv_sec;
208 }
209 return (0);
210}
211#endif /*!__alpha__*/
212
213int
214linux_brk(struct thread *td, struct linux_brk_args *args)
215{
216 struct vmspace *vm = td->td_proc->p_vmspace;
217 vm_offset_t new, old;
218 struct obreak_args /* {
219 char * nsize;
220 } */ tmp;
221
222#ifdef DEBUG
223 if (ldebug(brk))
224 printf(ARGS(brk, "%p"), (void *)(uintptr_t)args->dsend);
225#endif
226 old = (vm_offset_t)vm->vm_daddr + ctob(vm->vm_dsize);
227 new = (vm_offset_t)args->dsend;
228 tmp.nsize = (char *) new;
229 if (((caddr_t)new > vm->vm_daddr) && !obreak(td, &tmp))
230 td->td_retval[0] = (long)new;
231 else
232 td->td_retval[0] = (long)old;
233
234 return 0;
235}
236
237#if defined(__i386__) || defined(__alpha__)
238
239int
240linux_uselib(struct thread *td, struct linux_uselib_args *args)
241{
242 struct nameidata ni;
243 struct vnode *vp;
244 struct exec *a_out;
245 struct vattr attr;
246 vm_offset_t vmaddr;
247 unsigned long file_offset;
248 vm_offset_t buffer;
249 unsigned long bss_size;
250 char *library;
251 int error;
252 int locked;
253
254 LCONVPATHEXIST(td, args->library, &library);
255
256#ifdef DEBUG
257 if (ldebug(uselib))
258 printf(ARGS(uselib, "%s"), library);
259#endif
260
261 a_out = NULL;
262 locked = 0;
263 vp = NULL;
264
265 /*
266 * XXX: This code should make use of vn_open(), rather than doing
267 * all this stuff itself.
268 */
269 NDINIT(&ni, LOOKUP, FOLLOW|LOCKLEAF, UIO_SYSSPACE, library, td);
270 error = namei(&ni);
271 LFREEPATH(library);
272 if (error)
273 goto cleanup;
274
275 vp = ni.ni_vp;
276 /*
277 * XXX - This looks like a bogus check. A LOCKLEAF namei should not
278 * succeed without returning a vnode.
279 */
280 if (vp == NULL) {
281 error = ENOEXEC; /* ?? */
282 goto cleanup;
283 }
284 NDFREE(&ni, NDF_ONLY_PNBUF);
285
286 /*
287 * From here on down, we have a locked vnode that must be unlocked.
288 */
289 locked++;
290
291 /* Writable? */
292 if (vp->v_writecount) {
293 error = ETXTBSY;
294 goto cleanup;
295 }
296
297 /* Executable? */
298 error = VOP_GETATTR(vp, &attr, td->td_ucred, td);
299 if (error)
300 goto cleanup;
301
302 if ((vp->v_mount->mnt_flag & MNT_NOEXEC) ||
303 ((attr.va_mode & 0111) == 0) || (attr.va_type != VREG)) {
304 error = ENOEXEC;
305 goto cleanup;
306 }
307
308 /* Sensible size? */
309 if (attr.va_size == 0) {
310 error = ENOEXEC;
311 goto cleanup;
312 }
313
314 /* Can we access it? */
315 error = VOP_ACCESS(vp, VEXEC, td->td_ucred, td);
316 if (error)
317 goto cleanup;
318
319 /*
320 * XXX: This should use vn_open() so that it is properly authorized,
321 * and to reduce code redundancy all over the place here.
322 */
323#ifdef MAC
324 error = mac_check_vnode_open(td->td_ucred, vp, FREAD);
325 if (error)
326 goto cleanup;
327#endif
328 error = VOP_OPEN(vp, FREAD, td->td_ucred, td, -1);
329 if (error)
330 goto cleanup;
331
332 /* Pull in executable header into kernel_map */
333 error = vm_mmap(kernel_map, (vm_offset_t *)&a_out, PAGE_SIZE,
334 VM_PROT_READ, VM_PROT_READ, 0, (caddr_t)vp, 0);
335 /*
336 * Lock no longer needed
337 */
338 locked = 0;
339 VOP_UNLOCK(vp, 0, td);
340
341 if (error)
342 goto cleanup;
343
344 /* Is it a Linux binary ? */
345 if (((a_out->a_magic >> 16) & 0xff) != 0x64) {
346 error = ENOEXEC;
347 goto cleanup;
348 }
349
350 /*
351 * While we are here, we should REALLY do some more checks
352 */
353
354 /* Set file/virtual offset based on a.out variant. */
355 switch ((int)(a_out->a_magic & 0xffff)) {
356 case 0413: /* ZMAGIC */
357 file_offset = 1024;
358 break;
359 case 0314: /* QMAGIC */
360 file_offset = 0;
361 break;
362 default:
363 error = ENOEXEC;
364 goto cleanup;
365 }
366
367 bss_size = round_page(a_out->a_bss);
368
369 /* Check various fields in header for validity/bounds. */
370 if (a_out->a_text & PAGE_MASK || a_out->a_data & PAGE_MASK) {
371 error = ENOEXEC;
372 goto cleanup;
373 }
374
375 /* text + data can't exceed file size */
376 if (a_out->a_data + a_out->a_text > attr.va_size) {
377 error = EFAULT;
378 goto cleanup;
379 }
380
381 /*
382 * text/data/bss must not exceed limits
383 * XXX - this is not complete. it should check current usage PLUS
384 * the resources needed by this library.
385 */
386 PROC_LOCK(td->td_proc);
387 if (a_out->a_text > maxtsiz ||
388 a_out->a_data + bss_size > lim_cur(td->td_proc, RLIMIT_DATA)) {
389 PROC_UNLOCK(td->td_proc);
390 error = ENOMEM;
391 goto cleanup;
392 }
393 PROC_UNLOCK(td->td_proc);
394
395 mp_fixme("Unlocked vflags access.");
396 /* prevent more writers */
397 vp->v_vflag |= VV_TEXT;
398
399 /*
400 * Check if file_offset page aligned. Currently we cannot handle
401 * misalinged file offsets, and so we read in the entire image
402 * (what a waste).
403 */
404 if (file_offset & PAGE_MASK) {
405#ifdef DEBUG
406 printf("uselib: Non page aligned binary %lu\n", file_offset);
407#endif
408 /* Map text+data read/write/execute */
409
410 /* a_entry is the load address and is page aligned */
411 vmaddr = trunc_page(a_out->a_entry);
412
413 /* get anon user mapping, read+write+execute */
414 error = vm_map_find(&td->td_proc->p_vmspace->vm_map, NULL, 0,
415 &vmaddr, a_out->a_text + a_out->a_data, FALSE, VM_PROT_ALL,
416 VM_PROT_ALL, 0);
417 if (error)
418 goto cleanup;
419
420 /* map file into kernel_map */
421 error = vm_mmap(kernel_map, &buffer,
422 round_page(a_out->a_text + a_out->a_data + file_offset),
423 VM_PROT_READ, VM_PROT_READ, 0, (caddr_t)vp,
424 trunc_page(file_offset));
425 if (error)
426 goto cleanup;
427
428 /* copy from kernel VM space to user space */
429 error = copyout(PTRIN(buffer + file_offset),
430 (void *)vmaddr, a_out->a_text + a_out->a_data);
431
432 /* release temporary kernel space */
433 vm_map_remove(kernel_map, buffer, buffer +
434 round_page(a_out->a_text + a_out->a_data + file_offset));
435
436 if (error)
437 goto cleanup;
438 } else {
439#ifdef DEBUG
440 printf("uselib: Page aligned binary %lu\n", file_offset);
441#endif
442 /*
443 * for QMAGIC, a_entry is 20 bytes beyond the load address
444 * to skip the executable header
445 */
446 vmaddr = trunc_page(a_out->a_entry);
447
448 /*
449 * Map it all into the process's space as a single
450 * copy-on-write "data" segment.
451 */
452 error = vm_mmap(&td->td_proc->p_vmspace->vm_map, &vmaddr,
453 a_out->a_text + a_out->a_data, VM_PROT_ALL, VM_PROT_ALL,
454 MAP_PRIVATE | MAP_FIXED, (caddr_t)vp, file_offset);
455 if (error)
456 goto cleanup;
457 }
458#ifdef DEBUG
459 printf("mem=%08lx = %08lx %08lx\n", (long)vmaddr, ((long*)vmaddr)[0],
460 ((long*)vmaddr)[1]);
461#endif
462 if (bss_size != 0) {
463 /* Calculate BSS start address */
464 vmaddr = trunc_page(a_out->a_entry) + a_out->a_text +
465 a_out->a_data;
466
467 /* allocate some 'anon' space */
468 error = vm_map_find(&td->td_proc->p_vmspace->vm_map, NULL, 0,
469 &vmaddr, bss_size, FALSE, VM_PROT_ALL, VM_PROT_ALL, 0);
470 if (error)
471 goto cleanup;
472 }
473
474cleanup:
475 /* Unlock vnode if needed */
476 if (locked)
477 VOP_UNLOCK(vp, 0, td);
478
479 /* Release the kernel mapping. */
480 if (a_out)
481 vm_map_remove(kernel_map, (vm_offset_t)a_out,
482 (vm_offset_t)a_out + PAGE_SIZE);
483
484 return error;
485}
486
487#endif /* __i386__ || __alpha__ */
488
489int
490linux_select(struct thread *td, struct linux_select_args *args)
491{
492 l_timeval ltv;
493 struct timeval tv0, tv1, utv, *tvp;
494 int error;
495
496#ifdef DEBUG
497 if (ldebug(select))
498 printf(ARGS(select, "%d, %p, %p, %p, %p"), args->nfds,
499 (void *)args->readfds, (void *)args->writefds,
500 (void *)args->exceptfds, (void *)args->timeout);
501#endif
502
503 /*
504 * Store current time for computation of the amount of
505 * time left.
506 */
507 if (args->timeout) {
508 if ((error = copyin(args->timeout, &ltv, sizeof(ltv))))
509 goto select_out;
510 utv.tv_sec = ltv.tv_sec;
511 utv.tv_usec = ltv.tv_usec;
512#ifdef DEBUG
513 if (ldebug(select))
514 printf(LMSG("incoming timeout (%ld/%ld)"),
515 utv.tv_sec, utv.tv_usec);
516#endif
517
518 if (itimerfix(&utv)) {
519 /*
520 * The timeval was invalid. Convert it to something
521 * valid that will act as it does under Linux.
522 */
523 utv.tv_sec += utv.tv_usec / 1000000;
524 utv.tv_usec %= 1000000;
525 if (utv.tv_usec < 0) {
526 utv.tv_sec -= 1;
527 utv.tv_usec += 1000000;
528 }
529 if (utv.tv_sec < 0)
530 timevalclear(&utv);
531 }
532 microtime(&tv0);
533 tvp = &utv;
534 } else
535 tvp = NULL;
536
537 error = kern_select(td, args->nfds, args->readfds, args->writefds,
538 args->exceptfds, tvp);
539
540#ifdef DEBUG
541 if (ldebug(select))
542 printf(LMSG("real select returns %d"), error);
543#endif
544 if (error) {
545 /*
546 * See fs/select.c in the Linux kernel. Without this,
547 * Maelstrom doesn't work.
548 */
549 if (error == ERESTART)
550 error = EINTR;
551 goto select_out;
552 }
553
554 if (args->timeout) {
555 if (td->td_retval[0]) {
556 /*
557 * Compute how much time was left of the timeout,
558 * by subtracting the current time and the time
559 * before we started the call, and subtracting
560 * that result from the user-supplied value.
561 */
562 microtime(&tv1);
563 timevalsub(&tv1, &tv0);
564 timevalsub(&utv, &tv1);
565 if (utv.tv_sec < 0)
566 timevalclear(&utv);
567 } else
568 timevalclear(&utv);
569#ifdef DEBUG
570 if (ldebug(select))
571 printf(LMSG("outgoing timeout (%ld/%ld)"),
572 utv.tv_sec, utv.tv_usec);
573#endif
574 ltv.tv_sec = utv.tv_sec;
575 ltv.tv_usec = utv.tv_usec;
576 if ((error = copyout(&ltv, args->timeout, sizeof(ltv))))
577 goto select_out;
578 }
579
580select_out:
581#ifdef DEBUG
582 if (ldebug(select))
583 printf(LMSG("select_out -> %d"), error);
584#endif
585 return error;
586}
587
588int
589linux_mremap(struct thread *td, struct linux_mremap_args *args)
590{
591 struct munmap_args /* {
592 void *addr;
593 size_t len;
594 } */ bsd_args;
595 int error = 0;
596
597#ifdef DEBUG
598 if (ldebug(mremap))
599 printf(ARGS(mremap, "%p, %08lx, %08lx, %08lx"),
600 (void *)(uintptr_t)args->addr,
601 (unsigned long)args->old_len,
602 (unsigned long)args->new_len,
603 (unsigned long)args->flags);
604#endif
605 args->new_len = round_page(args->new_len);
606 args->old_len = round_page(args->old_len);
607
608 if (args->new_len > args->old_len) {
609 td->td_retval[0] = 0;
610 return ENOMEM;
611 }
612
613 if (args->new_len < args->old_len) {
614 bsd_args.addr =
615 (caddr_t)((uintptr_t)args->addr + args->new_len);
616 bsd_args.len = args->old_len - args->new_len;
617 error = munmap(td, &bsd_args);
618 }
619
620 td->td_retval[0] = error ? 0 : (uintptr_t)args->addr;
621 return error;
622}
623
624#define LINUX_MS_ASYNC 0x0001
625#define LINUX_MS_INVALIDATE 0x0002
626#define LINUX_MS_SYNC 0x0004
627
628int
629linux_msync(struct thread *td, struct linux_msync_args *args)
630{
631 struct msync_args bsd_args;
632
633 bsd_args.addr = (caddr_t)(uintptr_t)args->addr;
634 bsd_args.len = (uintptr_t)args->len;
635 bsd_args.flags = args->fl & ~LINUX_MS_SYNC;
636
637 return msync(td, &bsd_args);
638}
639
640#ifndef __alpha__
641int
642linux_time(struct thread *td, struct linux_time_args *args)
643{
644 struct timeval tv;
645 l_time_t tm;
646 int error;
647
648#ifdef DEBUG
649 if (ldebug(time))
650 printf(ARGS(time, "*"));
651#endif
652
653 microtime(&tv);
654 tm = tv.tv_sec;
655 if (args->tm && (error = copyout(&tm, args->tm, sizeof(tm))))
656 return error;
657 td->td_retval[0] = tm;
658 return 0;
659}
660#endif /*!__alpha__*/
661
662struct l_times_argv {
663 l_long tms_utime;
664 l_long tms_stime;
665 l_long tms_cutime;
666 l_long tms_cstime;
667};
668
669#ifdef __alpha__
670#define CLK_TCK 1024 /* Linux uses 1024 on alpha */
671#else
672#define CLK_TCK 100 /* Linux uses 100 */
673#endif
674
675#define CONVTCK(r) (r.tv_sec * CLK_TCK + r.tv_usec / (1000000 / CLK_TCK))
676
677int
678linux_times(struct thread *td, struct linux_times_args *args)
679{
680 struct timeval tv, utime, stime, cutime, cstime;
681 struct l_times_argv tms;
682 struct proc *p;
683 int error;
684
685#ifdef DEBUG
686 if (ldebug(times))
687 printf(ARGS(times, "*"));
688#endif
689
690 p = td->td_proc;
691 PROC_LOCK(p);
692 calcru(p, &utime, &stime);
693 calccru(p, &cutime, &cstime);
694 PROC_UNLOCK(p);
695
696 tms.tms_utime = CONVTCK(utime);
697 tms.tms_stime = CONVTCK(stime);
698
699 tms.tms_cutime = CONVTCK(cutime);
700 tms.tms_cstime = CONVTCK(cstime);
701
702 if ((error = copyout(&tms, args->buf, sizeof(tms))))
703 return error;
704
705 microuptime(&tv);
706 td->td_retval[0] = (int)CONVTCK(tv);
707 return 0;
708}
709
710int
711linux_newuname(struct thread *td, struct linux_newuname_args *args)
712{
713 struct l_new_utsname utsname;
714 char osname[LINUX_MAX_UTSNAME];
715 char osrelease[LINUX_MAX_UTSNAME];
716 char *p;
717
718#ifdef DEBUG
719 if (ldebug(newuname))
720 printf(ARGS(newuname, "*"));
721#endif
722
723 linux_get_osname(td, osname);
724 linux_get_osrelease(td, osrelease);
725
726 bzero(&utsname, sizeof(utsname));
727 strlcpy(utsname.sysname, osname, LINUX_MAX_UTSNAME);
728 getcredhostname(td->td_ucred, utsname.nodename, LINUX_MAX_UTSNAME);
729 strlcpy(utsname.release, osrelease, LINUX_MAX_UTSNAME);
730 strlcpy(utsname.version, version, LINUX_MAX_UTSNAME);
731 for (p = utsname.version; *p != '\0'; ++p)
732 if (*p == '\n') {
733 *p = '\0';
734 break;
735 }
736#ifdef __i386__
737 {
738 const char *class;
739 switch (cpu_class) {
740 case CPUCLASS_686:
741 class = "i686";
742 break;
743 case CPUCLASS_586:
744 class = "i586";
745 break;
746 case CPUCLASS_486:
747 class = "i486";
748 break;
749 default:
750 class = "i386";
751 }
752 strlcpy(utsname.machine, class, LINUX_MAX_UTSNAME);
753 }
754#elif defined(__amd64__) /* XXX: Linux can change 'personality'. */
755#ifdef COMPAT_LINUX32
756 strlcpy(utsname.machine, "i686", LINUX_MAX_UTSNAME);
757#else
758 strlcpy(utsname.machine, "x86_64", LINUX_MAX_UTSNAME);
759#endif /* COMPAT_LINUX32 */
760#else /* something other than i386 or amd64 - assume we and Linux agree */
761 strlcpy(utsname.machine, machine, LINUX_MAX_UTSNAME);
762#endif /* __i386__ */
763 strlcpy(utsname.domainname, domainname, LINUX_MAX_UTSNAME);
764
765 return (copyout(&utsname, args->buf, sizeof(utsname)));
766}
767
768#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
769struct l_utimbuf {
770 l_time_t l_actime;
771 l_time_t l_modtime;
772};
773
774int
775linux_utime(struct thread *td, struct linux_utime_args *args)
776{
777 struct timeval tv[2], *tvp;
778 struct l_utimbuf lut;
779 char *fname;
780 int error;
781
782 LCONVPATHEXIST(td, args->fname, &fname);
783
784#ifdef DEBUG
785 if (ldebug(utime))
786 printf(ARGS(utime, "%s, *"), fname);
787#endif
788
789 if (args->times) {
790 if ((error = copyin(args->times, &lut, sizeof lut))) {
791 LFREEPATH(fname);
792 return error;
793 }
794 tv[0].tv_sec = lut.l_actime;
795 tv[0].tv_usec = 0;
796 tv[1].tv_sec = lut.l_modtime;
797 tv[1].tv_usec = 0;
798 tvp = tv;
799 } else
800 tvp = NULL;
801
802 error = kern_utimes(td, fname, UIO_SYSSPACE, tvp, UIO_SYSSPACE);
803 LFREEPATH(fname);
804 return (error);
805}
806#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
807
808#define __WCLONE 0x80000000
809
810#ifndef __alpha__
811int
812linux_waitpid(struct thread *td, struct linux_waitpid_args *args)
813{
814 int error, options, tmpstat;
815
816#ifdef DEBUG
817 if (ldebug(waitpid))
818 printf(ARGS(waitpid, "%d, %p, %d"),
819 args->pid, (void *)args->status, args->options);
820#endif
821
822 options = (args->options & (WNOHANG | WUNTRACED));
823 /* WLINUXCLONE should be equal to __WCLONE, but we make sure */
824 if (args->options & __WCLONE)
825 options |= WLINUXCLONE;
826
827 error = kern_wait(td, args->pid, &tmpstat, options, NULL);
828 if (error)
829 return error;
830
831 if (args->status) {
832 tmpstat &= 0xffff;
833 if (WIFSIGNALED(tmpstat))
834 tmpstat = (tmpstat & 0xffffff80) |
835 BSD_TO_LINUX_SIGNAL(WTERMSIG(tmpstat));
836 else if (WIFSTOPPED(tmpstat))
837 tmpstat = (tmpstat & 0xffff00ff) |
838 (BSD_TO_LINUX_SIGNAL(WSTOPSIG(tmpstat)) << 8);
839 return copyout(&tmpstat, args->status, sizeof(int));
840 }
841
842 return 0;
843}
844#endif /*!__alpha__*/
845
846int
847linux_wait4(struct thread *td, struct linux_wait4_args *args)
848{
849 int error, options, tmpstat;
850 struct rusage ru, *rup;
851 struct proc *p;
852
853#ifdef DEBUG
854 if (ldebug(wait4))
855 printf(ARGS(wait4, "%d, %p, %d, %p"),
856 args->pid, (void *)args->status, args->options,
857 (void *)args->rusage);
858#endif
859
860 options = (args->options & (WNOHANG | WUNTRACED));
861 /* WLINUXCLONE should be equal to __WCLONE, but we make sure */
862 if (args->options & __WCLONE)
863 options |= WLINUXCLONE;
864
865 if (args->rusage != NULL)
866 rup = &ru;
867 else
868 rup = NULL;
869 error = kern_wait(td, args->pid, &tmpstat, options, rup);
870 if (error)
871 return error;
872
873 p = td->td_proc;
874 PROC_LOCK(p);
875 SIGDELSET(p->p_siglist, SIGCHLD);
876 PROC_UNLOCK(p);
877
878 if (args->status) {
879 tmpstat &= 0xffff;
880 if (WIFSIGNALED(tmpstat))
881 tmpstat = (tmpstat & 0xffffff80) |
882 BSD_TO_LINUX_SIGNAL(WTERMSIG(tmpstat));
883 else if (WIFSTOPPED(tmpstat))
884 tmpstat = (tmpstat & 0xffff00ff) |
885 (BSD_TO_LINUX_SIGNAL(WSTOPSIG(tmpstat)) << 8);
886 error = copyout(&tmpstat, args->status, sizeof(int));
887 }
888 if (args->rusage != NULL && error == 0)
889 error = copyout(&ru, args->rusage, sizeof(ru));
890
891 return (error);
892}
893
894int
895linux_mknod(struct thread *td, struct linux_mknod_args *args)
896{
897 char *path;
898 int error;
899
900 LCONVPATHCREAT(td, args->path, &path);
901
902#ifdef DEBUG
903 if (ldebug(mknod))
904 printf(ARGS(mknod, "%s, %d, %d"), path, args->mode, args->dev);
905#endif
906
907 if (args->mode & S_IFIFO)
908 error = kern_mkfifo(td, path, UIO_SYSSPACE, args->mode);
909 else
910 error = kern_mknod(td, path, UIO_SYSSPACE, args->mode,
911 args->dev);
912 LFREEPATH(path);
913 return (error);
914}
915
916/*
917 * UGH! This is just about the dumbest idea I've ever heard!!
918 */
919int
920linux_personality(struct thread *td, struct linux_personality_args *args)
921{
922#ifdef DEBUG
923 if (ldebug(personality))
924 printf(ARGS(personality, "%lu"), (unsigned long)args->per);
925#endif
926#ifndef __alpha__
927 if (args->per != 0)
928 return EINVAL;
929#endif
930
931 /* Yes Jim, it's still a Linux... */
932 td->td_retval[0] = 0;
933 return 0;
934}
935
936struct l_itimerval {
937 l_timeval it_interval;
938 l_timeval it_value;
939};
940
941#define B2L_ITIMERVAL(bip, lip) \
942 (bip)->it_interval.tv_sec = (lip)->it_interval.tv_sec; \
943 (bip)->it_interval.tv_usec = (lip)->it_interval.tv_usec; \
944 (bip)->it_value.tv_sec = (lip)->it_value.tv_sec; \
945 (bip)->it_value.tv_usec = (lip)->it_value.tv_usec;
946
947int
948linux_setitimer(struct thread *td, struct linux_setitimer_args *uap)
949{
950 int error;
951 struct l_itimerval ls;
952 struct itimerval aitv, oitv;
953
954#ifdef DEBUG
955 if (ldebug(setitimer))
956 printf(ARGS(setitimer, "%p, %p"),
957 (void *)uap->itv, (void *)uap->oitv);
958#endif
959
960 if (uap->itv == NULL) {
961 uap->itv = uap->oitv;
962 return (linux_getitimer(td, (struct linux_getitimer_args *)uap));
963 }
964
965 error = copyin(uap->itv, &ls, sizeof(ls));
966 if (error != 0)
967 return (error);
968 B2L_ITIMERVAL(&aitv, &ls);
969#ifdef DEBUG
970 if (ldebug(setitimer)) {
971 printf("setitimer: value: sec: %ld, usec: %ld\n",
972 aitv.it_value.tv_sec, aitv.it_value.tv_usec);
973 printf("setitimer: interval: sec: %ld, usec: %ld\n",
974 aitv.it_interval.tv_sec, aitv.it_interval.tv_usec);
975 }
976#endif
977 error = kern_setitimer(td, uap->which, &aitv, &oitv);
978 if (error != 0 || uap->oitv == NULL)
979 return (error);
980 B2L_ITIMERVAL(&ls, &oitv);
981
982 return (copyout(&ls, uap->oitv, sizeof(ls)));
983}
984
985int
986linux_getitimer(struct thread *td, struct linux_getitimer_args *uap)
987{
988 int error;
989 struct l_itimerval ls;
990 struct itimerval aitv;
991
992#ifdef DEBUG
993 if (ldebug(getitimer))
994 printf(ARGS(getitimer, "%p"), (void *)uap->itv);
995#endif
996 error = kern_getitimer(td, uap->which, &aitv);
997 if (error != 0)
998 return (error);
999 B2L_ITIMERVAL(&ls, &aitv);
1000 return (copyout(&ls, uap->itv, sizeof(ls)));
1001}
1002
1003#ifndef __alpha__
1004int
1005linux_nice(struct thread *td, struct linux_nice_args *args)
1006{
1007 struct setpriority_args bsd_args;
1008
1009 bsd_args.which = PRIO_PROCESS;
1010 bsd_args.who = 0; /* current process */
1011 bsd_args.prio = args->inc;
1012 return setpriority(td, &bsd_args);
1013}
1014#endif /*!__alpha__*/
1015
1016int
1017linux_setgroups(struct thread *td, struct linux_setgroups_args *args)
1018{
1019 struct ucred *newcred, *oldcred;
1020 l_gid_t linux_gidset[NGROUPS];
1021 gid_t *bsd_gidset;
1022 int ngrp, error;
1023 struct proc *p;
1024
1025 ngrp = args->gidsetsize;
1026 if (ngrp < 0 || ngrp >= NGROUPS)
1027 return (EINVAL);
1028 error = copyin(args->grouplist, linux_gidset, ngrp * sizeof(l_gid_t));
1029 if (error)
1030 return (error);
1031 newcred = crget();
1032 p = td->td_proc;
1033 PROC_LOCK(p);
1034 oldcred = p->p_ucred;
1035
1036 /*
1037 * cr_groups[0] holds egid. Setting the whole set from
1038 * the supplied set will cause egid to be changed too.
1039 * Keep cr_groups[0] unchanged to prevent that.
1040 */
1041
1042 if ((error = suser_cred(oldcred, SUSER_ALLOWJAIL)) != 0) {
1043 PROC_UNLOCK(p);
1044 crfree(newcred);
1045 return (error);
1046 }
1047
1048 crcopy(newcred, oldcred);
1049 if (ngrp > 0) {
1050 newcred->cr_ngroups = ngrp + 1;
1051
1052 bsd_gidset = newcred->cr_groups;
1053 ngrp--;
1054 while (ngrp >= 0) {
1055 bsd_gidset[ngrp + 1] = linux_gidset[ngrp];
1056 ngrp--;
1057 }
1058 }
1059 else
1060 newcred->cr_ngroups = 1;
1061
1062 setsugid(p);
1063 p->p_ucred = newcred;
1064 PROC_UNLOCK(p);
1065 crfree(oldcred);
1066 return (0);
1067}
1068
1069int
1070linux_getgroups(struct thread *td, struct linux_getgroups_args *args)
1071{
1072 struct ucred *cred;
1073 l_gid_t linux_gidset[NGROUPS];
1074 gid_t *bsd_gidset;
1075 int bsd_gidsetsz, ngrp, error;
1076
1077 cred = td->td_ucred;
1078 bsd_gidset = cred->cr_groups;
1079 bsd_gidsetsz = cred->cr_ngroups - 1;
1080
1081 /*
1082 * cr_groups[0] holds egid. Returning the whole set
1083 * here will cause a duplicate. Exclude cr_groups[0]
1084 * to prevent that.
1085 */
1086
1087 if ((ngrp = args->gidsetsize) == 0) {
1088 td->td_retval[0] = bsd_gidsetsz;
1089 return (0);
1090 }
1091
1092 if (ngrp < bsd_gidsetsz)
1093 return (EINVAL);
1094
1095 ngrp = 0;
1096 while (ngrp < bsd_gidsetsz) {
1097 linux_gidset[ngrp] = bsd_gidset[ngrp + 1];
1098 ngrp++;
1099 }
1100
1101 if ((error = copyout(linux_gidset, args->grouplist,
1102 ngrp * sizeof(l_gid_t))))
1103 return (error);
1104
1105 td->td_retval[0] = ngrp;
1106 return (0);
1107}
1108
1109#ifndef __alpha__
1110int
1111linux_setrlimit(struct thread *td, struct linux_setrlimit_args *args)
1112{
1113 struct rlimit bsd_rlim;
1114 struct l_rlimit rlim;
1115 u_int which;
1116 int error;
1117
1118#ifdef DEBUG
1119 if (ldebug(setrlimit))
1120 printf(ARGS(setrlimit, "%d, %p"),
1121 args->resource, (void *)args->rlim);
1122#endif
1123
1124 if (args->resource >= LINUX_RLIM_NLIMITS)
1125 return (EINVAL);
1126
1127 which = linux_to_bsd_resource[args->resource];
1128 if (which == -1)
1129 return (EINVAL);
1130
1131 error = copyin(args->rlim, &rlim, sizeof(rlim));
1132 if (error)
1133 return (error);
1134
1135 bsd_rlim.rlim_cur = (rlim_t)rlim.rlim_cur;
1136 bsd_rlim.rlim_max = (rlim_t)rlim.rlim_max;
1137 return (kern_setrlimit(td, which, &bsd_rlim));
1138}
1139
1140int
1141linux_old_getrlimit(struct thread *td, struct linux_old_getrlimit_args *args)
1142{
1143 struct l_rlimit rlim;
1144 struct proc *p = td->td_proc;
1145 struct rlimit bsd_rlim;
1146 u_int which;
1147
1148#ifdef DEBUG
1149 if (ldebug(old_getrlimit))
1150 printf(ARGS(old_getrlimit, "%d, %p"),
1151 args->resource, (void *)args->rlim);
1152#endif
1153
1154 if (args->resource >= LINUX_RLIM_NLIMITS)
1155 return (EINVAL);
1156
1157 which = linux_to_bsd_resource[args->resource];
1158 if (which == -1)
1159 return (EINVAL);
1160
1161 PROC_LOCK(p);
1162 lim_rlimit(p, which, &bsd_rlim);
1163 PROC_UNLOCK(p);
1164
1165#ifdef COMPAT_LINUX32
1166 rlim.rlim_cur = (unsigned int)bsd_rlim.rlim_cur;
1167 if (rlim.rlim_cur == UINT_MAX)
1168 rlim.rlim_cur = INT_MAX;
1169 rlim.rlim_max = (unsigned int)bsd_rlim.rlim_max;
1170 if (rlim.rlim_max == UINT_MAX)
1171 rlim.rlim_max = INT_MAX;
1172#else
1173 rlim.rlim_cur = (unsigned long)bsd_rlim.rlim_cur;
1174 if (rlim.rlim_cur == ULONG_MAX)
1175 rlim.rlim_cur = LONG_MAX;
1176 rlim.rlim_max = (unsigned long)bsd_rlim.rlim_max;
1177 if (rlim.rlim_max == ULONG_MAX)
1178 rlim.rlim_max = LONG_MAX;
1179#endif
1180 return (copyout(&rlim, args->rlim, sizeof(rlim)));
1181}
1182
1183int
1184linux_getrlimit(struct thread *td, struct linux_getrlimit_args *args)
1185{
1186 struct l_rlimit rlim;
1187 struct proc *p = td->td_proc;
1188 struct rlimit bsd_rlim;
1189 u_int which;
1190
1191#ifdef DEBUG
1192 if (ldebug(getrlimit))
1193 printf(ARGS(getrlimit, "%d, %p"),
1194 args->resource, (void *)args->rlim);
1195#endif
1196
1197 if (args->resource >= LINUX_RLIM_NLIMITS)
1198 return (EINVAL);
1199
1200 which = linux_to_bsd_resource[args->resource];
1201 if (which == -1)
1202 return (EINVAL);
1203
1204 PROC_LOCK(p);
1205 lim_rlimit(p, which, &bsd_rlim);
1206 PROC_UNLOCK(p);
1207
1208 rlim.rlim_cur = (l_ulong)bsd_rlim.rlim_cur;
1209 rlim.rlim_max = (l_ulong)bsd_rlim.rlim_max;
1210 return (copyout(&rlim, args->rlim, sizeof(rlim)));
1211}
1212#endif /*!__alpha__*/
1213
1214int
1215linux_sched_setscheduler(struct thread *td,
1216 struct linux_sched_setscheduler_args *args)
1217{
1218 struct sched_setscheduler_args bsd;
1219
1220#ifdef DEBUG
1221 if (ldebug(sched_setscheduler))
1222 printf(ARGS(sched_setscheduler, "%d, %d, %p"),
1223 args->pid, args->policy, (const void *)args->param);
1224#endif
1225
1226 switch (args->policy) {
1227 case LINUX_SCHED_OTHER:
1228 bsd.policy = SCHED_OTHER;
1229 break;
1230 case LINUX_SCHED_FIFO:
1231 bsd.policy = SCHED_FIFO;
1232 break;
1233 case LINUX_SCHED_RR:
1234 bsd.policy = SCHED_RR;
1235 break;
1236 default:
1237 return EINVAL;
1238 }
1239
1240 bsd.pid = args->pid;
1241 bsd.param = (struct sched_param *)args->param;
1242 return sched_setscheduler(td, &bsd);
1243}
1244
1245int
1246linux_sched_getscheduler(struct thread *td,
1247 struct linux_sched_getscheduler_args *args)
1248{
1249 struct sched_getscheduler_args bsd;
1250 int error;
1251
1252#ifdef DEBUG
1253 if (ldebug(sched_getscheduler))
1254 printf(ARGS(sched_getscheduler, "%d"), args->pid);
1255#endif
1256
1257 bsd.pid = args->pid;
1258 error = sched_getscheduler(td, &bsd);
1259
1260 switch (td->td_retval[0]) {
1261 case SCHED_OTHER:
1262 td->td_retval[0] = LINUX_SCHED_OTHER;
1263 break;
1264 case SCHED_FIFO:
1265 td->td_retval[0] = LINUX_SCHED_FIFO;
1266 break;
1267 case SCHED_RR:
1268 td->td_retval[0] = LINUX_SCHED_RR;
1269 break;
1270 }
1271
1272 return error;
1273}
1274
1275int
1276linux_sched_get_priority_max(struct thread *td,
1277 struct linux_sched_get_priority_max_args *args)
1278{
1279 struct sched_get_priority_max_args bsd;
1280
1281#ifdef DEBUG
1282 if (ldebug(sched_get_priority_max))
1283 printf(ARGS(sched_get_priority_max, "%d"), args->policy);
1284#endif
1285
1286 switch (args->policy) {
1287 case LINUX_SCHED_OTHER:
1288 bsd.policy = SCHED_OTHER;
1289 break;
1290 case LINUX_SCHED_FIFO:
1291 bsd.policy = SCHED_FIFO;
1292 break;
1293 case LINUX_SCHED_RR:
1294 bsd.policy = SCHED_RR;
1295 break;
1296 default:
1297 return EINVAL;
1298 }
1299 return sched_get_priority_max(td, &bsd);
1300}
1301
1302int
1303linux_sched_get_priority_min(struct thread *td,
1304 struct linux_sched_get_priority_min_args *args)
1305{
1306 struct sched_get_priority_min_args bsd;
1307
1308#ifdef DEBUG
1309 if (ldebug(sched_get_priority_min))
1310 printf(ARGS(sched_get_priority_min, "%d"), args->policy);
1311#endif
1312
1313 switch (args->policy) {
1314 case LINUX_SCHED_OTHER:
1315 bsd.policy = SCHED_OTHER;
1316 break;
1317 case LINUX_SCHED_FIFO:
1318 bsd.policy = SCHED_FIFO;
1319 break;
1320 case LINUX_SCHED_RR:
1321 bsd.policy = SCHED_RR;
1322 break;
1323 default:
1324 return EINVAL;
1325 }
1326 return sched_get_priority_min(td, &bsd);
1327}
1328
1329#define REBOOT_CAD_ON 0x89abcdef
1330#define REBOOT_CAD_OFF 0
1331#define REBOOT_HALT 0xcdef0123
1332
1333int
1334linux_reboot(struct thread *td, struct linux_reboot_args *args)
1335{
1336 struct reboot_args bsd_args;
1337
1338#ifdef DEBUG
1339 if (ldebug(reboot))
1340 printf(ARGS(reboot, "0x%x"), args->cmd);
1341#endif
1342 if (args->cmd == REBOOT_CAD_ON || args->cmd == REBOOT_CAD_OFF)
1343 return (0);
1344 bsd_args.opt = (args->cmd == REBOOT_HALT) ? RB_HALT : 0;
1345 return (reboot(td, &bsd_args));
1346}
1347
1348#ifndef __alpha__
1349
1350/*
1351 * The FreeBSD native getpid(2), getgid(2) and getuid(2) also modify
1352 * td->td_retval[1] when COMPAT_43 is defined. This
1353 * globbers registers that are assumed to be preserved. The following
1354 * lightweight syscalls fixes this. See also linux_getgid16() and
1355 * linux_getuid16() in linux_uid16.c.
1356 *
1357 * linux_getpid() - MP SAFE
1358 * linux_getgid() - MP SAFE
1359 * linux_getuid() - MP SAFE
1360 */
1361
1362int
1363linux_getpid(struct thread *td, struct linux_getpid_args *args)
1364{
1365
1366 td->td_retval[0] = td->td_proc->p_pid;
1367 return (0);
1368}
1369
1370int
1371linux_getgid(struct thread *td, struct linux_getgid_args *args)
1372{
1373
1374 td->td_retval[0] = td->td_ucred->cr_rgid;
1375 return (0);
1376}
1377
1378int
1379linux_getuid(struct thread *td, struct linux_getuid_args *args)
1380{
1381
1382 td->td_retval[0] = td->td_ucred->cr_ruid;
1383 return (0);
1384}
1385
1386#endif /*!__alpha__*/
1387
1388int
1389linux_getsid(struct thread *td, struct linux_getsid_args *args)
1390{
1391 struct getsid_args bsd;
1392 bsd.pid = args->pid;
1393 return getsid(td, &bsd);
1394}
79#ifdef COMPAT_LINUX32
80#include <machine/../linux32/linux.h>
81#include <machine/../linux32/linux32_proto.h>
82#else
83#include <machine/../linux/linux.h>
84#include <machine/../linux/linux_proto.h>
85#endif
86
87#include <compat/linux/linux_mib.h>
88#include <compat/linux/linux_util.h>
89
90#ifdef __i386__
91#include <machine/cputypes.h>
92#endif
93
94#ifdef __alpha__
95#define BSD_TO_LINUX_SIGNAL(sig) (sig)
96#else
97#define BSD_TO_LINUX_SIGNAL(sig) \
98 (((sig) <= LINUX_SIGTBLSZ) ? bsd_to_linux_signal[_SIG_IDX(sig)] : sig)
99#endif
100
101#ifndef __alpha__
102static unsigned int linux_to_bsd_resource[LINUX_RLIM_NLIMITS] = {
103 RLIMIT_CPU, RLIMIT_FSIZE, RLIMIT_DATA, RLIMIT_STACK,
104 RLIMIT_CORE, RLIMIT_RSS, RLIMIT_NPROC, RLIMIT_NOFILE,
105 RLIMIT_MEMLOCK, -1
106};
107#endif /*!__alpha__*/
108
109struct l_sysinfo {
110 l_long uptime; /* Seconds since boot */
111 l_ulong loads[3]; /* 1, 5, and 15 minute load averages */
112#define LINUX_SYSINFO_LOADS_SCALE 65536
113 l_ulong totalram; /* Total usable main memory size */
114 l_ulong freeram; /* Available memory size */
115 l_ulong sharedram; /* Amount of shared memory */
116 l_ulong bufferram; /* Memory used by buffers */
117 l_ulong totalswap; /* Total swap space size */
118 l_ulong freeswap; /* swap space still available */
119 l_ushort procs; /* Number of current processes */
120 l_ulong totalbig;
121 l_ulong freebig;
122 l_uint mem_unit;
123 char _f[6]; /* Pads structure to 64 bytes */
124};
125#ifndef __alpha__
126int
127linux_sysinfo(struct thread *td, struct linux_sysinfo_args *args)
128{
129 struct l_sysinfo sysinfo;
130 vm_object_t object;
131 int i, j;
132 struct timespec ts;
133
134 /* Uptime is copied out of print_uptime() in kern_shutdown.c */
135 getnanouptime(&ts);
136 i = 0;
137 if (ts.tv_sec >= 86400) {
138 ts.tv_sec %= 86400;
139 i = 1;
140 }
141 if (i || ts.tv_sec >= 3600) {
142 ts.tv_sec %= 3600;
143 i = 1;
144 }
145 if (i || ts.tv_sec >= 60) {
146 ts.tv_sec %= 60;
147 i = 1;
148 }
149 sysinfo.uptime=ts.tv_sec;
150
151 /* Use the information from the mib to get our load averages */
152 for (i = 0; i < 3; i++)
153 sysinfo.loads[i] = averunnable.ldavg[i] *
154 LINUX_SYSINFO_LOADS_SCALE / averunnable.fscale;
155
156 sysinfo.totalram = physmem * PAGE_SIZE;
157 sysinfo.freeram = sysinfo.totalram - cnt.v_wire_count * PAGE_SIZE;
158
159 sysinfo.sharedram = 0;
160 mtx_lock(&vm_object_list_mtx);
161 TAILQ_FOREACH(object, &vm_object_list, object_list)
162 if (object->shadow_count > 1)
163 sysinfo.sharedram += object->resident_page_count;
164 mtx_unlock(&vm_object_list_mtx);
165
166 sysinfo.sharedram *= PAGE_SIZE;
167 sysinfo.bufferram = 0;
168
169 swap_pager_status(&i, &j);
170 sysinfo.totalswap= i * PAGE_SIZE;
171 sysinfo.freeswap = (i - j) * PAGE_SIZE;
172
173 sysinfo.procs = nprocs;
174
175 /* The following are only present in newer Linux kernels. */
176 sysinfo.totalbig = 0;
177 sysinfo.freebig = 0;
178 sysinfo.mem_unit = 1;
179
180 return copyout(&sysinfo, args->info, sizeof(sysinfo));
181}
182#endif /*!__alpha__*/
183
184#ifndef __alpha__
185int
186linux_alarm(struct thread *td, struct linux_alarm_args *args)
187{
188 struct itimerval it, old_it;
189 int error;
190
191#ifdef DEBUG
192 if (ldebug(alarm))
193 printf(ARGS(alarm, "%u"), args->secs);
194#endif
195
196 if (args->secs > 100000000)
197 return (EINVAL);
198
199 it.it_value.tv_sec = (long)args->secs;
200 it.it_value.tv_usec = 0;
201 it.it_interval.tv_sec = 0;
202 it.it_interval.tv_usec = 0;
203 error = kern_setitimer(td, ITIMER_REAL, &it, &old_it);
204 if (error)
205 return (error);
206 if (timevalisset(&old_it.it_value)) {
207 if (old_it.it_value.tv_usec != 0)
208 old_it.it_value.tv_sec++;
209 td->td_retval[0] = old_it.it_value.tv_sec;
210 }
211 return (0);
212}
213#endif /*!__alpha__*/
214
215int
216linux_brk(struct thread *td, struct linux_brk_args *args)
217{
218 struct vmspace *vm = td->td_proc->p_vmspace;
219 vm_offset_t new, old;
220 struct obreak_args /* {
221 char * nsize;
222 } */ tmp;
223
224#ifdef DEBUG
225 if (ldebug(brk))
226 printf(ARGS(brk, "%p"), (void *)(uintptr_t)args->dsend);
227#endif
228 old = (vm_offset_t)vm->vm_daddr + ctob(vm->vm_dsize);
229 new = (vm_offset_t)args->dsend;
230 tmp.nsize = (char *) new;
231 if (((caddr_t)new > vm->vm_daddr) && !obreak(td, &tmp))
232 td->td_retval[0] = (long)new;
233 else
234 td->td_retval[0] = (long)old;
235
236 return 0;
237}
238
239#if defined(__i386__) || defined(__alpha__)
240
241int
242linux_uselib(struct thread *td, struct linux_uselib_args *args)
243{
244 struct nameidata ni;
245 struct vnode *vp;
246 struct exec *a_out;
247 struct vattr attr;
248 vm_offset_t vmaddr;
249 unsigned long file_offset;
250 vm_offset_t buffer;
251 unsigned long bss_size;
252 char *library;
253 int error;
254 int locked;
255
256 LCONVPATHEXIST(td, args->library, &library);
257
258#ifdef DEBUG
259 if (ldebug(uselib))
260 printf(ARGS(uselib, "%s"), library);
261#endif
262
263 a_out = NULL;
264 locked = 0;
265 vp = NULL;
266
267 /*
268 * XXX: This code should make use of vn_open(), rather than doing
269 * all this stuff itself.
270 */
271 NDINIT(&ni, LOOKUP, FOLLOW|LOCKLEAF, UIO_SYSSPACE, library, td);
272 error = namei(&ni);
273 LFREEPATH(library);
274 if (error)
275 goto cleanup;
276
277 vp = ni.ni_vp;
278 /*
279 * XXX - This looks like a bogus check. A LOCKLEAF namei should not
280 * succeed without returning a vnode.
281 */
282 if (vp == NULL) {
283 error = ENOEXEC; /* ?? */
284 goto cleanup;
285 }
286 NDFREE(&ni, NDF_ONLY_PNBUF);
287
288 /*
289 * From here on down, we have a locked vnode that must be unlocked.
290 */
291 locked++;
292
293 /* Writable? */
294 if (vp->v_writecount) {
295 error = ETXTBSY;
296 goto cleanup;
297 }
298
299 /* Executable? */
300 error = VOP_GETATTR(vp, &attr, td->td_ucred, td);
301 if (error)
302 goto cleanup;
303
304 if ((vp->v_mount->mnt_flag & MNT_NOEXEC) ||
305 ((attr.va_mode & 0111) == 0) || (attr.va_type != VREG)) {
306 error = ENOEXEC;
307 goto cleanup;
308 }
309
310 /* Sensible size? */
311 if (attr.va_size == 0) {
312 error = ENOEXEC;
313 goto cleanup;
314 }
315
316 /* Can we access it? */
317 error = VOP_ACCESS(vp, VEXEC, td->td_ucred, td);
318 if (error)
319 goto cleanup;
320
321 /*
322 * XXX: This should use vn_open() so that it is properly authorized,
323 * and to reduce code redundancy all over the place here.
324 */
325#ifdef MAC
326 error = mac_check_vnode_open(td->td_ucred, vp, FREAD);
327 if (error)
328 goto cleanup;
329#endif
330 error = VOP_OPEN(vp, FREAD, td->td_ucred, td, -1);
331 if (error)
332 goto cleanup;
333
334 /* Pull in executable header into kernel_map */
335 error = vm_mmap(kernel_map, (vm_offset_t *)&a_out, PAGE_SIZE,
336 VM_PROT_READ, VM_PROT_READ, 0, (caddr_t)vp, 0);
337 /*
338 * Lock no longer needed
339 */
340 locked = 0;
341 VOP_UNLOCK(vp, 0, td);
342
343 if (error)
344 goto cleanup;
345
346 /* Is it a Linux binary ? */
347 if (((a_out->a_magic >> 16) & 0xff) != 0x64) {
348 error = ENOEXEC;
349 goto cleanup;
350 }
351
352 /*
353 * While we are here, we should REALLY do some more checks
354 */
355
356 /* Set file/virtual offset based on a.out variant. */
357 switch ((int)(a_out->a_magic & 0xffff)) {
358 case 0413: /* ZMAGIC */
359 file_offset = 1024;
360 break;
361 case 0314: /* QMAGIC */
362 file_offset = 0;
363 break;
364 default:
365 error = ENOEXEC;
366 goto cleanup;
367 }
368
369 bss_size = round_page(a_out->a_bss);
370
371 /* Check various fields in header for validity/bounds. */
372 if (a_out->a_text & PAGE_MASK || a_out->a_data & PAGE_MASK) {
373 error = ENOEXEC;
374 goto cleanup;
375 }
376
377 /* text + data can't exceed file size */
378 if (a_out->a_data + a_out->a_text > attr.va_size) {
379 error = EFAULT;
380 goto cleanup;
381 }
382
383 /*
384 * text/data/bss must not exceed limits
385 * XXX - this is not complete. it should check current usage PLUS
386 * the resources needed by this library.
387 */
388 PROC_LOCK(td->td_proc);
389 if (a_out->a_text > maxtsiz ||
390 a_out->a_data + bss_size > lim_cur(td->td_proc, RLIMIT_DATA)) {
391 PROC_UNLOCK(td->td_proc);
392 error = ENOMEM;
393 goto cleanup;
394 }
395 PROC_UNLOCK(td->td_proc);
396
397 mp_fixme("Unlocked vflags access.");
398 /* prevent more writers */
399 vp->v_vflag |= VV_TEXT;
400
401 /*
402 * Check if file_offset page aligned. Currently we cannot handle
403 * misalinged file offsets, and so we read in the entire image
404 * (what a waste).
405 */
406 if (file_offset & PAGE_MASK) {
407#ifdef DEBUG
408 printf("uselib: Non page aligned binary %lu\n", file_offset);
409#endif
410 /* Map text+data read/write/execute */
411
412 /* a_entry is the load address and is page aligned */
413 vmaddr = trunc_page(a_out->a_entry);
414
415 /* get anon user mapping, read+write+execute */
416 error = vm_map_find(&td->td_proc->p_vmspace->vm_map, NULL, 0,
417 &vmaddr, a_out->a_text + a_out->a_data, FALSE, VM_PROT_ALL,
418 VM_PROT_ALL, 0);
419 if (error)
420 goto cleanup;
421
422 /* map file into kernel_map */
423 error = vm_mmap(kernel_map, &buffer,
424 round_page(a_out->a_text + a_out->a_data + file_offset),
425 VM_PROT_READ, VM_PROT_READ, 0, (caddr_t)vp,
426 trunc_page(file_offset));
427 if (error)
428 goto cleanup;
429
430 /* copy from kernel VM space to user space */
431 error = copyout(PTRIN(buffer + file_offset),
432 (void *)vmaddr, a_out->a_text + a_out->a_data);
433
434 /* release temporary kernel space */
435 vm_map_remove(kernel_map, buffer, buffer +
436 round_page(a_out->a_text + a_out->a_data + file_offset));
437
438 if (error)
439 goto cleanup;
440 } else {
441#ifdef DEBUG
442 printf("uselib: Page aligned binary %lu\n", file_offset);
443#endif
444 /*
445 * for QMAGIC, a_entry is 20 bytes beyond the load address
446 * to skip the executable header
447 */
448 vmaddr = trunc_page(a_out->a_entry);
449
450 /*
451 * Map it all into the process's space as a single
452 * copy-on-write "data" segment.
453 */
454 error = vm_mmap(&td->td_proc->p_vmspace->vm_map, &vmaddr,
455 a_out->a_text + a_out->a_data, VM_PROT_ALL, VM_PROT_ALL,
456 MAP_PRIVATE | MAP_FIXED, (caddr_t)vp, file_offset);
457 if (error)
458 goto cleanup;
459 }
460#ifdef DEBUG
461 printf("mem=%08lx = %08lx %08lx\n", (long)vmaddr, ((long*)vmaddr)[0],
462 ((long*)vmaddr)[1]);
463#endif
464 if (bss_size != 0) {
465 /* Calculate BSS start address */
466 vmaddr = trunc_page(a_out->a_entry) + a_out->a_text +
467 a_out->a_data;
468
469 /* allocate some 'anon' space */
470 error = vm_map_find(&td->td_proc->p_vmspace->vm_map, NULL, 0,
471 &vmaddr, bss_size, FALSE, VM_PROT_ALL, VM_PROT_ALL, 0);
472 if (error)
473 goto cleanup;
474 }
475
476cleanup:
477 /* Unlock vnode if needed */
478 if (locked)
479 VOP_UNLOCK(vp, 0, td);
480
481 /* Release the kernel mapping. */
482 if (a_out)
483 vm_map_remove(kernel_map, (vm_offset_t)a_out,
484 (vm_offset_t)a_out + PAGE_SIZE);
485
486 return error;
487}
488
489#endif /* __i386__ || __alpha__ */
490
491int
492linux_select(struct thread *td, struct linux_select_args *args)
493{
494 l_timeval ltv;
495 struct timeval tv0, tv1, utv, *tvp;
496 int error;
497
498#ifdef DEBUG
499 if (ldebug(select))
500 printf(ARGS(select, "%d, %p, %p, %p, %p"), args->nfds,
501 (void *)args->readfds, (void *)args->writefds,
502 (void *)args->exceptfds, (void *)args->timeout);
503#endif
504
505 /*
506 * Store current time for computation of the amount of
507 * time left.
508 */
509 if (args->timeout) {
510 if ((error = copyin(args->timeout, &ltv, sizeof(ltv))))
511 goto select_out;
512 utv.tv_sec = ltv.tv_sec;
513 utv.tv_usec = ltv.tv_usec;
514#ifdef DEBUG
515 if (ldebug(select))
516 printf(LMSG("incoming timeout (%ld/%ld)"),
517 utv.tv_sec, utv.tv_usec);
518#endif
519
520 if (itimerfix(&utv)) {
521 /*
522 * The timeval was invalid. Convert it to something
523 * valid that will act as it does under Linux.
524 */
525 utv.tv_sec += utv.tv_usec / 1000000;
526 utv.tv_usec %= 1000000;
527 if (utv.tv_usec < 0) {
528 utv.tv_sec -= 1;
529 utv.tv_usec += 1000000;
530 }
531 if (utv.tv_sec < 0)
532 timevalclear(&utv);
533 }
534 microtime(&tv0);
535 tvp = &utv;
536 } else
537 tvp = NULL;
538
539 error = kern_select(td, args->nfds, args->readfds, args->writefds,
540 args->exceptfds, tvp);
541
542#ifdef DEBUG
543 if (ldebug(select))
544 printf(LMSG("real select returns %d"), error);
545#endif
546 if (error) {
547 /*
548 * See fs/select.c in the Linux kernel. Without this,
549 * Maelstrom doesn't work.
550 */
551 if (error == ERESTART)
552 error = EINTR;
553 goto select_out;
554 }
555
556 if (args->timeout) {
557 if (td->td_retval[0]) {
558 /*
559 * Compute how much time was left of the timeout,
560 * by subtracting the current time and the time
561 * before we started the call, and subtracting
562 * that result from the user-supplied value.
563 */
564 microtime(&tv1);
565 timevalsub(&tv1, &tv0);
566 timevalsub(&utv, &tv1);
567 if (utv.tv_sec < 0)
568 timevalclear(&utv);
569 } else
570 timevalclear(&utv);
571#ifdef DEBUG
572 if (ldebug(select))
573 printf(LMSG("outgoing timeout (%ld/%ld)"),
574 utv.tv_sec, utv.tv_usec);
575#endif
576 ltv.tv_sec = utv.tv_sec;
577 ltv.tv_usec = utv.tv_usec;
578 if ((error = copyout(&ltv, args->timeout, sizeof(ltv))))
579 goto select_out;
580 }
581
582select_out:
583#ifdef DEBUG
584 if (ldebug(select))
585 printf(LMSG("select_out -> %d"), error);
586#endif
587 return error;
588}
589
590int
591linux_mremap(struct thread *td, struct linux_mremap_args *args)
592{
593 struct munmap_args /* {
594 void *addr;
595 size_t len;
596 } */ bsd_args;
597 int error = 0;
598
599#ifdef DEBUG
600 if (ldebug(mremap))
601 printf(ARGS(mremap, "%p, %08lx, %08lx, %08lx"),
602 (void *)(uintptr_t)args->addr,
603 (unsigned long)args->old_len,
604 (unsigned long)args->new_len,
605 (unsigned long)args->flags);
606#endif
607 args->new_len = round_page(args->new_len);
608 args->old_len = round_page(args->old_len);
609
610 if (args->new_len > args->old_len) {
611 td->td_retval[0] = 0;
612 return ENOMEM;
613 }
614
615 if (args->new_len < args->old_len) {
616 bsd_args.addr =
617 (caddr_t)((uintptr_t)args->addr + args->new_len);
618 bsd_args.len = args->old_len - args->new_len;
619 error = munmap(td, &bsd_args);
620 }
621
622 td->td_retval[0] = error ? 0 : (uintptr_t)args->addr;
623 return error;
624}
625
626#define LINUX_MS_ASYNC 0x0001
627#define LINUX_MS_INVALIDATE 0x0002
628#define LINUX_MS_SYNC 0x0004
629
630int
631linux_msync(struct thread *td, struct linux_msync_args *args)
632{
633 struct msync_args bsd_args;
634
635 bsd_args.addr = (caddr_t)(uintptr_t)args->addr;
636 bsd_args.len = (uintptr_t)args->len;
637 bsd_args.flags = args->fl & ~LINUX_MS_SYNC;
638
639 return msync(td, &bsd_args);
640}
641
642#ifndef __alpha__
643int
644linux_time(struct thread *td, struct linux_time_args *args)
645{
646 struct timeval tv;
647 l_time_t tm;
648 int error;
649
650#ifdef DEBUG
651 if (ldebug(time))
652 printf(ARGS(time, "*"));
653#endif
654
655 microtime(&tv);
656 tm = tv.tv_sec;
657 if (args->tm && (error = copyout(&tm, args->tm, sizeof(tm))))
658 return error;
659 td->td_retval[0] = tm;
660 return 0;
661}
662#endif /*!__alpha__*/
663
664struct l_times_argv {
665 l_long tms_utime;
666 l_long tms_stime;
667 l_long tms_cutime;
668 l_long tms_cstime;
669};
670
671#ifdef __alpha__
672#define CLK_TCK 1024 /* Linux uses 1024 on alpha */
673#else
674#define CLK_TCK 100 /* Linux uses 100 */
675#endif
676
677#define CONVTCK(r) (r.tv_sec * CLK_TCK + r.tv_usec / (1000000 / CLK_TCK))
678
679int
680linux_times(struct thread *td, struct linux_times_args *args)
681{
682 struct timeval tv, utime, stime, cutime, cstime;
683 struct l_times_argv tms;
684 struct proc *p;
685 int error;
686
687#ifdef DEBUG
688 if (ldebug(times))
689 printf(ARGS(times, "*"));
690#endif
691
692 p = td->td_proc;
693 PROC_LOCK(p);
694 calcru(p, &utime, &stime);
695 calccru(p, &cutime, &cstime);
696 PROC_UNLOCK(p);
697
698 tms.tms_utime = CONVTCK(utime);
699 tms.tms_stime = CONVTCK(stime);
700
701 tms.tms_cutime = CONVTCK(cutime);
702 tms.tms_cstime = CONVTCK(cstime);
703
704 if ((error = copyout(&tms, args->buf, sizeof(tms))))
705 return error;
706
707 microuptime(&tv);
708 td->td_retval[0] = (int)CONVTCK(tv);
709 return 0;
710}
711
712int
713linux_newuname(struct thread *td, struct linux_newuname_args *args)
714{
715 struct l_new_utsname utsname;
716 char osname[LINUX_MAX_UTSNAME];
717 char osrelease[LINUX_MAX_UTSNAME];
718 char *p;
719
720#ifdef DEBUG
721 if (ldebug(newuname))
722 printf(ARGS(newuname, "*"));
723#endif
724
725 linux_get_osname(td, osname);
726 linux_get_osrelease(td, osrelease);
727
728 bzero(&utsname, sizeof(utsname));
729 strlcpy(utsname.sysname, osname, LINUX_MAX_UTSNAME);
730 getcredhostname(td->td_ucred, utsname.nodename, LINUX_MAX_UTSNAME);
731 strlcpy(utsname.release, osrelease, LINUX_MAX_UTSNAME);
732 strlcpy(utsname.version, version, LINUX_MAX_UTSNAME);
733 for (p = utsname.version; *p != '\0'; ++p)
734 if (*p == '\n') {
735 *p = '\0';
736 break;
737 }
738#ifdef __i386__
739 {
740 const char *class;
741 switch (cpu_class) {
742 case CPUCLASS_686:
743 class = "i686";
744 break;
745 case CPUCLASS_586:
746 class = "i586";
747 break;
748 case CPUCLASS_486:
749 class = "i486";
750 break;
751 default:
752 class = "i386";
753 }
754 strlcpy(utsname.machine, class, LINUX_MAX_UTSNAME);
755 }
756#elif defined(__amd64__) /* XXX: Linux can change 'personality'. */
757#ifdef COMPAT_LINUX32
758 strlcpy(utsname.machine, "i686", LINUX_MAX_UTSNAME);
759#else
760 strlcpy(utsname.machine, "x86_64", LINUX_MAX_UTSNAME);
761#endif /* COMPAT_LINUX32 */
762#else /* something other than i386 or amd64 - assume we and Linux agree */
763 strlcpy(utsname.machine, machine, LINUX_MAX_UTSNAME);
764#endif /* __i386__ */
765 strlcpy(utsname.domainname, domainname, LINUX_MAX_UTSNAME);
766
767 return (copyout(&utsname, args->buf, sizeof(utsname)));
768}
769
770#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
771struct l_utimbuf {
772 l_time_t l_actime;
773 l_time_t l_modtime;
774};
775
776int
777linux_utime(struct thread *td, struct linux_utime_args *args)
778{
779 struct timeval tv[2], *tvp;
780 struct l_utimbuf lut;
781 char *fname;
782 int error;
783
784 LCONVPATHEXIST(td, args->fname, &fname);
785
786#ifdef DEBUG
787 if (ldebug(utime))
788 printf(ARGS(utime, "%s, *"), fname);
789#endif
790
791 if (args->times) {
792 if ((error = copyin(args->times, &lut, sizeof lut))) {
793 LFREEPATH(fname);
794 return error;
795 }
796 tv[0].tv_sec = lut.l_actime;
797 tv[0].tv_usec = 0;
798 tv[1].tv_sec = lut.l_modtime;
799 tv[1].tv_usec = 0;
800 tvp = tv;
801 } else
802 tvp = NULL;
803
804 error = kern_utimes(td, fname, UIO_SYSSPACE, tvp, UIO_SYSSPACE);
805 LFREEPATH(fname);
806 return (error);
807}
808#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
809
810#define __WCLONE 0x80000000
811
812#ifndef __alpha__
813int
814linux_waitpid(struct thread *td, struct linux_waitpid_args *args)
815{
816 int error, options, tmpstat;
817
818#ifdef DEBUG
819 if (ldebug(waitpid))
820 printf(ARGS(waitpid, "%d, %p, %d"),
821 args->pid, (void *)args->status, args->options);
822#endif
823
824 options = (args->options & (WNOHANG | WUNTRACED));
825 /* WLINUXCLONE should be equal to __WCLONE, but we make sure */
826 if (args->options & __WCLONE)
827 options |= WLINUXCLONE;
828
829 error = kern_wait(td, args->pid, &tmpstat, options, NULL);
830 if (error)
831 return error;
832
833 if (args->status) {
834 tmpstat &= 0xffff;
835 if (WIFSIGNALED(tmpstat))
836 tmpstat = (tmpstat & 0xffffff80) |
837 BSD_TO_LINUX_SIGNAL(WTERMSIG(tmpstat));
838 else if (WIFSTOPPED(tmpstat))
839 tmpstat = (tmpstat & 0xffff00ff) |
840 (BSD_TO_LINUX_SIGNAL(WSTOPSIG(tmpstat)) << 8);
841 return copyout(&tmpstat, args->status, sizeof(int));
842 }
843
844 return 0;
845}
846#endif /*!__alpha__*/
847
848int
849linux_wait4(struct thread *td, struct linux_wait4_args *args)
850{
851 int error, options, tmpstat;
852 struct rusage ru, *rup;
853 struct proc *p;
854
855#ifdef DEBUG
856 if (ldebug(wait4))
857 printf(ARGS(wait4, "%d, %p, %d, %p"),
858 args->pid, (void *)args->status, args->options,
859 (void *)args->rusage);
860#endif
861
862 options = (args->options & (WNOHANG | WUNTRACED));
863 /* WLINUXCLONE should be equal to __WCLONE, but we make sure */
864 if (args->options & __WCLONE)
865 options |= WLINUXCLONE;
866
867 if (args->rusage != NULL)
868 rup = &ru;
869 else
870 rup = NULL;
871 error = kern_wait(td, args->pid, &tmpstat, options, rup);
872 if (error)
873 return error;
874
875 p = td->td_proc;
876 PROC_LOCK(p);
877 SIGDELSET(p->p_siglist, SIGCHLD);
878 PROC_UNLOCK(p);
879
880 if (args->status) {
881 tmpstat &= 0xffff;
882 if (WIFSIGNALED(tmpstat))
883 tmpstat = (tmpstat & 0xffffff80) |
884 BSD_TO_LINUX_SIGNAL(WTERMSIG(tmpstat));
885 else if (WIFSTOPPED(tmpstat))
886 tmpstat = (tmpstat & 0xffff00ff) |
887 (BSD_TO_LINUX_SIGNAL(WSTOPSIG(tmpstat)) << 8);
888 error = copyout(&tmpstat, args->status, sizeof(int));
889 }
890 if (args->rusage != NULL && error == 0)
891 error = copyout(&ru, args->rusage, sizeof(ru));
892
893 return (error);
894}
895
896int
897linux_mknod(struct thread *td, struct linux_mknod_args *args)
898{
899 char *path;
900 int error;
901
902 LCONVPATHCREAT(td, args->path, &path);
903
904#ifdef DEBUG
905 if (ldebug(mknod))
906 printf(ARGS(mknod, "%s, %d, %d"), path, args->mode, args->dev);
907#endif
908
909 if (args->mode & S_IFIFO)
910 error = kern_mkfifo(td, path, UIO_SYSSPACE, args->mode);
911 else
912 error = kern_mknod(td, path, UIO_SYSSPACE, args->mode,
913 args->dev);
914 LFREEPATH(path);
915 return (error);
916}
917
918/*
919 * UGH! This is just about the dumbest idea I've ever heard!!
920 */
921int
922linux_personality(struct thread *td, struct linux_personality_args *args)
923{
924#ifdef DEBUG
925 if (ldebug(personality))
926 printf(ARGS(personality, "%lu"), (unsigned long)args->per);
927#endif
928#ifndef __alpha__
929 if (args->per != 0)
930 return EINVAL;
931#endif
932
933 /* Yes Jim, it's still a Linux... */
934 td->td_retval[0] = 0;
935 return 0;
936}
937
938struct l_itimerval {
939 l_timeval it_interval;
940 l_timeval it_value;
941};
942
943#define B2L_ITIMERVAL(bip, lip) \
944 (bip)->it_interval.tv_sec = (lip)->it_interval.tv_sec; \
945 (bip)->it_interval.tv_usec = (lip)->it_interval.tv_usec; \
946 (bip)->it_value.tv_sec = (lip)->it_value.tv_sec; \
947 (bip)->it_value.tv_usec = (lip)->it_value.tv_usec;
948
949int
950linux_setitimer(struct thread *td, struct linux_setitimer_args *uap)
951{
952 int error;
953 struct l_itimerval ls;
954 struct itimerval aitv, oitv;
955
956#ifdef DEBUG
957 if (ldebug(setitimer))
958 printf(ARGS(setitimer, "%p, %p"),
959 (void *)uap->itv, (void *)uap->oitv);
960#endif
961
962 if (uap->itv == NULL) {
963 uap->itv = uap->oitv;
964 return (linux_getitimer(td, (struct linux_getitimer_args *)uap));
965 }
966
967 error = copyin(uap->itv, &ls, sizeof(ls));
968 if (error != 0)
969 return (error);
970 B2L_ITIMERVAL(&aitv, &ls);
971#ifdef DEBUG
972 if (ldebug(setitimer)) {
973 printf("setitimer: value: sec: %ld, usec: %ld\n",
974 aitv.it_value.tv_sec, aitv.it_value.tv_usec);
975 printf("setitimer: interval: sec: %ld, usec: %ld\n",
976 aitv.it_interval.tv_sec, aitv.it_interval.tv_usec);
977 }
978#endif
979 error = kern_setitimer(td, uap->which, &aitv, &oitv);
980 if (error != 0 || uap->oitv == NULL)
981 return (error);
982 B2L_ITIMERVAL(&ls, &oitv);
983
984 return (copyout(&ls, uap->oitv, sizeof(ls)));
985}
986
987int
988linux_getitimer(struct thread *td, struct linux_getitimer_args *uap)
989{
990 int error;
991 struct l_itimerval ls;
992 struct itimerval aitv;
993
994#ifdef DEBUG
995 if (ldebug(getitimer))
996 printf(ARGS(getitimer, "%p"), (void *)uap->itv);
997#endif
998 error = kern_getitimer(td, uap->which, &aitv);
999 if (error != 0)
1000 return (error);
1001 B2L_ITIMERVAL(&ls, &aitv);
1002 return (copyout(&ls, uap->itv, sizeof(ls)));
1003}
1004
1005#ifndef __alpha__
1006int
1007linux_nice(struct thread *td, struct linux_nice_args *args)
1008{
1009 struct setpriority_args bsd_args;
1010
1011 bsd_args.which = PRIO_PROCESS;
1012 bsd_args.who = 0; /* current process */
1013 bsd_args.prio = args->inc;
1014 return setpriority(td, &bsd_args);
1015}
1016#endif /*!__alpha__*/
1017
1018int
1019linux_setgroups(struct thread *td, struct linux_setgroups_args *args)
1020{
1021 struct ucred *newcred, *oldcred;
1022 l_gid_t linux_gidset[NGROUPS];
1023 gid_t *bsd_gidset;
1024 int ngrp, error;
1025 struct proc *p;
1026
1027 ngrp = args->gidsetsize;
1028 if (ngrp < 0 || ngrp >= NGROUPS)
1029 return (EINVAL);
1030 error = copyin(args->grouplist, linux_gidset, ngrp * sizeof(l_gid_t));
1031 if (error)
1032 return (error);
1033 newcred = crget();
1034 p = td->td_proc;
1035 PROC_LOCK(p);
1036 oldcred = p->p_ucred;
1037
1038 /*
1039 * cr_groups[0] holds egid. Setting the whole set from
1040 * the supplied set will cause egid to be changed too.
1041 * Keep cr_groups[0] unchanged to prevent that.
1042 */
1043
1044 if ((error = suser_cred(oldcred, SUSER_ALLOWJAIL)) != 0) {
1045 PROC_UNLOCK(p);
1046 crfree(newcred);
1047 return (error);
1048 }
1049
1050 crcopy(newcred, oldcred);
1051 if (ngrp > 0) {
1052 newcred->cr_ngroups = ngrp + 1;
1053
1054 bsd_gidset = newcred->cr_groups;
1055 ngrp--;
1056 while (ngrp >= 0) {
1057 bsd_gidset[ngrp + 1] = linux_gidset[ngrp];
1058 ngrp--;
1059 }
1060 }
1061 else
1062 newcred->cr_ngroups = 1;
1063
1064 setsugid(p);
1065 p->p_ucred = newcred;
1066 PROC_UNLOCK(p);
1067 crfree(oldcred);
1068 return (0);
1069}
1070
1071int
1072linux_getgroups(struct thread *td, struct linux_getgroups_args *args)
1073{
1074 struct ucred *cred;
1075 l_gid_t linux_gidset[NGROUPS];
1076 gid_t *bsd_gidset;
1077 int bsd_gidsetsz, ngrp, error;
1078
1079 cred = td->td_ucred;
1080 bsd_gidset = cred->cr_groups;
1081 bsd_gidsetsz = cred->cr_ngroups - 1;
1082
1083 /*
1084 * cr_groups[0] holds egid. Returning the whole set
1085 * here will cause a duplicate. Exclude cr_groups[0]
1086 * to prevent that.
1087 */
1088
1089 if ((ngrp = args->gidsetsize) == 0) {
1090 td->td_retval[0] = bsd_gidsetsz;
1091 return (0);
1092 }
1093
1094 if (ngrp < bsd_gidsetsz)
1095 return (EINVAL);
1096
1097 ngrp = 0;
1098 while (ngrp < bsd_gidsetsz) {
1099 linux_gidset[ngrp] = bsd_gidset[ngrp + 1];
1100 ngrp++;
1101 }
1102
1103 if ((error = copyout(linux_gidset, args->grouplist,
1104 ngrp * sizeof(l_gid_t))))
1105 return (error);
1106
1107 td->td_retval[0] = ngrp;
1108 return (0);
1109}
1110
1111#ifndef __alpha__
1112int
1113linux_setrlimit(struct thread *td, struct linux_setrlimit_args *args)
1114{
1115 struct rlimit bsd_rlim;
1116 struct l_rlimit rlim;
1117 u_int which;
1118 int error;
1119
1120#ifdef DEBUG
1121 if (ldebug(setrlimit))
1122 printf(ARGS(setrlimit, "%d, %p"),
1123 args->resource, (void *)args->rlim);
1124#endif
1125
1126 if (args->resource >= LINUX_RLIM_NLIMITS)
1127 return (EINVAL);
1128
1129 which = linux_to_bsd_resource[args->resource];
1130 if (which == -1)
1131 return (EINVAL);
1132
1133 error = copyin(args->rlim, &rlim, sizeof(rlim));
1134 if (error)
1135 return (error);
1136
1137 bsd_rlim.rlim_cur = (rlim_t)rlim.rlim_cur;
1138 bsd_rlim.rlim_max = (rlim_t)rlim.rlim_max;
1139 return (kern_setrlimit(td, which, &bsd_rlim));
1140}
1141
1142int
1143linux_old_getrlimit(struct thread *td, struct linux_old_getrlimit_args *args)
1144{
1145 struct l_rlimit rlim;
1146 struct proc *p = td->td_proc;
1147 struct rlimit bsd_rlim;
1148 u_int which;
1149
1150#ifdef DEBUG
1151 if (ldebug(old_getrlimit))
1152 printf(ARGS(old_getrlimit, "%d, %p"),
1153 args->resource, (void *)args->rlim);
1154#endif
1155
1156 if (args->resource >= LINUX_RLIM_NLIMITS)
1157 return (EINVAL);
1158
1159 which = linux_to_bsd_resource[args->resource];
1160 if (which == -1)
1161 return (EINVAL);
1162
1163 PROC_LOCK(p);
1164 lim_rlimit(p, which, &bsd_rlim);
1165 PROC_UNLOCK(p);
1166
1167#ifdef COMPAT_LINUX32
1168 rlim.rlim_cur = (unsigned int)bsd_rlim.rlim_cur;
1169 if (rlim.rlim_cur == UINT_MAX)
1170 rlim.rlim_cur = INT_MAX;
1171 rlim.rlim_max = (unsigned int)bsd_rlim.rlim_max;
1172 if (rlim.rlim_max == UINT_MAX)
1173 rlim.rlim_max = INT_MAX;
1174#else
1175 rlim.rlim_cur = (unsigned long)bsd_rlim.rlim_cur;
1176 if (rlim.rlim_cur == ULONG_MAX)
1177 rlim.rlim_cur = LONG_MAX;
1178 rlim.rlim_max = (unsigned long)bsd_rlim.rlim_max;
1179 if (rlim.rlim_max == ULONG_MAX)
1180 rlim.rlim_max = LONG_MAX;
1181#endif
1182 return (copyout(&rlim, args->rlim, sizeof(rlim)));
1183}
1184
1185int
1186linux_getrlimit(struct thread *td, struct linux_getrlimit_args *args)
1187{
1188 struct l_rlimit rlim;
1189 struct proc *p = td->td_proc;
1190 struct rlimit bsd_rlim;
1191 u_int which;
1192
1193#ifdef DEBUG
1194 if (ldebug(getrlimit))
1195 printf(ARGS(getrlimit, "%d, %p"),
1196 args->resource, (void *)args->rlim);
1197#endif
1198
1199 if (args->resource >= LINUX_RLIM_NLIMITS)
1200 return (EINVAL);
1201
1202 which = linux_to_bsd_resource[args->resource];
1203 if (which == -1)
1204 return (EINVAL);
1205
1206 PROC_LOCK(p);
1207 lim_rlimit(p, which, &bsd_rlim);
1208 PROC_UNLOCK(p);
1209
1210 rlim.rlim_cur = (l_ulong)bsd_rlim.rlim_cur;
1211 rlim.rlim_max = (l_ulong)bsd_rlim.rlim_max;
1212 return (copyout(&rlim, args->rlim, sizeof(rlim)));
1213}
1214#endif /*!__alpha__*/
1215
1216int
1217linux_sched_setscheduler(struct thread *td,
1218 struct linux_sched_setscheduler_args *args)
1219{
1220 struct sched_setscheduler_args bsd;
1221
1222#ifdef DEBUG
1223 if (ldebug(sched_setscheduler))
1224 printf(ARGS(sched_setscheduler, "%d, %d, %p"),
1225 args->pid, args->policy, (const void *)args->param);
1226#endif
1227
1228 switch (args->policy) {
1229 case LINUX_SCHED_OTHER:
1230 bsd.policy = SCHED_OTHER;
1231 break;
1232 case LINUX_SCHED_FIFO:
1233 bsd.policy = SCHED_FIFO;
1234 break;
1235 case LINUX_SCHED_RR:
1236 bsd.policy = SCHED_RR;
1237 break;
1238 default:
1239 return EINVAL;
1240 }
1241
1242 bsd.pid = args->pid;
1243 bsd.param = (struct sched_param *)args->param;
1244 return sched_setscheduler(td, &bsd);
1245}
1246
1247int
1248linux_sched_getscheduler(struct thread *td,
1249 struct linux_sched_getscheduler_args *args)
1250{
1251 struct sched_getscheduler_args bsd;
1252 int error;
1253
1254#ifdef DEBUG
1255 if (ldebug(sched_getscheduler))
1256 printf(ARGS(sched_getscheduler, "%d"), args->pid);
1257#endif
1258
1259 bsd.pid = args->pid;
1260 error = sched_getscheduler(td, &bsd);
1261
1262 switch (td->td_retval[0]) {
1263 case SCHED_OTHER:
1264 td->td_retval[0] = LINUX_SCHED_OTHER;
1265 break;
1266 case SCHED_FIFO:
1267 td->td_retval[0] = LINUX_SCHED_FIFO;
1268 break;
1269 case SCHED_RR:
1270 td->td_retval[0] = LINUX_SCHED_RR;
1271 break;
1272 }
1273
1274 return error;
1275}
1276
1277int
1278linux_sched_get_priority_max(struct thread *td,
1279 struct linux_sched_get_priority_max_args *args)
1280{
1281 struct sched_get_priority_max_args bsd;
1282
1283#ifdef DEBUG
1284 if (ldebug(sched_get_priority_max))
1285 printf(ARGS(sched_get_priority_max, "%d"), args->policy);
1286#endif
1287
1288 switch (args->policy) {
1289 case LINUX_SCHED_OTHER:
1290 bsd.policy = SCHED_OTHER;
1291 break;
1292 case LINUX_SCHED_FIFO:
1293 bsd.policy = SCHED_FIFO;
1294 break;
1295 case LINUX_SCHED_RR:
1296 bsd.policy = SCHED_RR;
1297 break;
1298 default:
1299 return EINVAL;
1300 }
1301 return sched_get_priority_max(td, &bsd);
1302}
1303
1304int
1305linux_sched_get_priority_min(struct thread *td,
1306 struct linux_sched_get_priority_min_args *args)
1307{
1308 struct sched_get_priority_min_args bsd;
1309
1310#ifdef DEBUG
1311 if (ldebug(sched_get_priority_min))
1312 printf(ARGS(sched_get_priority_min, "%d"), args->policy);
1313#endif
1314
1315 switch (args->policy) {
1316 case LINUX_SCHED_OTHER:
1317 bsd.policy = SCHED_OTHER;
1318 break;
1319 case LINUX_SCHED_FIFO:
1320 bsd.policy = SCHED_FIFO;
1321 break;
1322 case LINUX_SCHED_RR:
1323 bsd.policy = SCHED_RR;
1324 break;
1325 default:
1326 return EINVAL;
1327 }
1328 return sched_get_priority_min(td, &bsd);
1329}
1330
1331#define REBOOT_CAD_ON 0x89abcdef
1332#define REBOOT_CAD_OFF 0
1333#define REBOOT_HALT 0xcdef0123
1334
1335int
1336linux_reboot(struct thread *td, struct linux_reboot_args *args)
1337{
1338 struct reboot_args bsd_args;
1339
1340#ifdef DEBUG
1341 if (ldebug(reboot))
1342 printf(ARGS(reboot, "0x%x"), args->cmd);
1343#endif
1344 if (args->cmd == REBOOT_CAD_ON || args->cmd == REBOOT_CAD_OFF)
1345 return (0);
1346 bsd_args.opt = (args->cmd == REBOOT_HALT) ? RB_HALT : 0;
1347 return (reboot(td, &bsd_args));
1348}
1349
1350#ifndef __alpha__
1351
1352/*
1353 * The FreeBSD native getpid(2), getgid(2) and getuid(2) also modify
1354 * td->td_retval[1] when COMPAT_43 is defined. This
1355 * globbers registers that are assumed to be preserved. The following
1356 * lightweight syscalls fixes this. See also linux_getgid16() and
1357 * linux_getuid16() in linux_uid16.c.
1358 *
1359 * linux_getpid() - MP SAFE
1360 * linux_getgid() - MP SAFE
1361 * linux_getuid() - MP SAFE
1362 */
1363
1364int
1365linux_getpid(struct thread *td, struct linux_getpid_args *args)
1366{
1367
1368 td->td_retval[0] = td->td_proc->p_pid;
1369 return (0);
1370}
1371
1372int
1373linux_getgid(struct thread *td, struct linux_getgid_args *args)
1374{
1375
1376 td->td_retval[0] = td->td_ucred->cr_rgid;
1377 return (0);
1378}
1379
1380int
1381linux_getuid(struct thread *td, struct linux_getuid_args *args)
1382{
1383
1384 td->td_retval[0] = td->td_ucred->cr_ruid;
1385 return (0);
1386}
1387
1388#endif /*!__alpha__*/
1389
1390int
1391linux_getsid(struct thread *td, struct linux_getsid_args *args)
1392{
1393 struct getsid_args bsd;
1394 bsd.pid = args->pid;
1395 return getsid(td, &bsd);
1396}
1397
1398int
1399linux_nosys(struct thread *td, struct nosys_args *ignore)
1400{
1401
1402 return (ENOSYS);
1403}