kernel = Fix tsleep(), remove MAILBOX signals, change signalset locks for LWPs
[dragonfly.git] / sys / emulation / linux / linux_misc.c
1 /*-
2  * Copyright (c) 1994-1995 Søren Schmidt
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer
10  *    in this position and unchanged.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. The name of the author may not be used to endorse or promote products
15  *    derived from this software without specific prior written permission
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  *
28  * $FreeBSD: src/sys/compat/linux/linux_misc.c,v 1.85.2.9 2002/09/24 08:11:41 mdodd Exp $
29  * $DragonFly: src/sys/emulation/linux/linux_misc.c,v 1.39 2007/06/26 19:31:03 dillon Exp $
30  */
31
32 #include "opt_compat.h"
33
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/fcntl.h>
37 #include <sys/imgact_aout.h>
38 #include <sys/kernel.h>
39 #include <sys/kern_syscall.h>
40 #include <sys/lock.h>
41 #include <sys/mman.h>
42 #include <sys/mount.h>
43 #include <sys/poll.h>
44 #include <sys/proc.h>
45 #include <sys/priv.h>
46 #include <sys/nlookup.h>
47 #include <sys/blist.h>
48 #include <sys/reboot.h>
49 #include <sys/resourcevar.h>
50 #include <sys/signalvar.h>
51 #include <sys/stat.h>
52 #include <sys/sysctl.h>
53 #include <sys/sysproto.h>
54 #include <sys/time.h>
55 #include <sys/unistd.h>
56 #include <sys/vmmeter.h>
57 #include <sys/vnode.h>
58 #include <sys/wait.h>
59
60 #include <sys/signal2.h>
61 #include <sys/thread2.h>
62 #include <sys/mplock2.h>
63
64 #include <vm/vm.h>
65 #include <vm/pmap.h>
66 #include <vm/vm_kern.h>
67 #include <vm/vm_map.h>
68 #include <vm/vm_extern.h>
69 #include <vm/vm_object.h>
70 #include <vm/vm_zone.h>
71 #include <vm/swap_pager.h>
72
73 #include <machine/frame.h>
74 #include <machine/limits.h>
75 #include <machine/psl.h>
76 #include <machine/sysarch.h>
77 #ifdef __i386__
78 #include <machine/segments.h>
79 #endif
80
81 #include <sys/sched.h>
82
83 #include <emulation/linux/linux_sysproto.h>
84 #include <arch_linux/linux.h>
85 #include <arch_linux/linux_proto.h>
86 #include "linux_mib.h"
87 #include "linux_util.h"
88 #include "linux_emuldata.h"
89 #include "i386/linux.h"
90
91 #define BSD_TO_LINUX_SIGNAL(sig)        \
92         (((sig) <= LINUX_SIGTBLSZ) ? bsd_to_linux_signal[_SIG_IDX(sig)] : sig)
93
94 static unsigned int linux_to_bsd_resource[LINUX_RLIM_NLIMITS] = {
95         RLIMIT_CPU, RLIMIT_FSIZE, RLIMIT_DATA, RLIMIT_STACK,
96         RLIMIT_CORE, RLIMIT_RSS, RLIMIT_NPROC, RLIMIT_NOFILE,
97         RLIMIT_MEMLOCK, -1
98 };
99
100 struct l_sysinfo {
101         l_long          uptime;         /* Seconds since boot */
102         l_ulong         loads[3];       /* 1, 5, and 15 minute load averages */
103         l_ulong         totalram;       /* Total usable main memory size */
104         l_ulong         freeram;        /* Available memory size */
105         l_ulong         sharedram;      /* Amount of shared memory */
106         l_ulong         bufferram;      /* Memory used by buffers */
107         l_ulong         totalswap;      /* Total swap space size */
108         l_ulong         freeswap;       /* swap space still available */
109         l_ushort        procs;          /* Number of current processes */
110         l_ushort        pad;            /* explicit padding */
111         l_ulong         totalhigh;      /* Total high memory size */
112         l_ulong         freehigh;       /* Available high memory size */
113         l_uint          mem_unit;       /* Memory unit size in bytes */
114         char            _f[20-2*sizeof(l_long)-sizeof(l_int)]; /* Padding for libc5 */
115 };
116
117 int
118 sys_linux_madvise(struct linux_madvise_args *args)
119 {
120         return 0;
121 }
122
123 /*
124  * MPALMOSTSAFE
125  */
126 int
127 sys_linux_sysinfo(struct linux_sysinfo_args *args)
128 {
129         struct l_sysinfo sysinfo;
130         vm_object_t object;
131         struct timespec ts;
132         int error;
133         int i;
134
135         /* Uptime is copied out of print_uptime() in kern_shutdown.c */
136         getnanouptime(&ts);
137         i = 0;
138         if (ts.tv_sec >= 86400) {
139                 ts.tv_sec %= 86400;
140                 i = 1;
141         }
142         if (i || ts.tv_sec >= 3600) {
143                 ts.tv_sec %= 3600;
144                 i = 1;
145         }
146         if (i || ts.tv_sec >= 60) {
147                 ts.tv_sec %= 60;
148                 i = 1;
149         }
150
151         bzero(&sysinfo, sizeof(sysinfo));
152         sysinfo.uptime=ts.tv_sec;
153
154         /* Use the information from the mib to get our load averages */
155         for (i = 0; i < 3; i++)
156                 sysinfo.loads[i] = averunnable.ldavg[i];
157
158         sysinfo.totalram = Maxmem * PAGE_SIZE;
159         sysinfo.freeram = sysinfo.totalram - vmstats.v_wire_count * PAGE_SIZE;
160         sysinfo.sharedram = 0;
161
162         lwkt_gettoken(&vmobj_token);
163         for (object = TAILQ_FIRST(&vm_object_list); object != NULL;
164              object = TAILQ_NEXT(object, object_list)) {
165                 if (object->type == OBJT_MARKER)
166                         continue;
167                 if (object->shadow_count > 1)
168                         sysinfo.sharedram += object->resident_page_count;
169         }
170         lwkt_reltoken(&vmobj_token);
171
172         sysinfo.sharedram *= PAGE_SIZE;
173         sysinfo.bufferram = 0;
174
175         if (swapblist == NULL) {
176                 sysinfo.totalswap= 0;
177                 sysinfo.freeswap = 0;
178         } else {
179                 sysinfo.totalswap = swapblist->bl_blocks * 1024;
180                 sysinfo.freeswap = swapblist->bl_root->u.bmu_avail * PAGE_SIZE;
181         }
182
183         sysinfo.procs = nprocs;
184         sysinfo.totalhigh = 0;
185         sysinfo.freehigh = 0;
186         sysinfo.mem_unit = 1; /* Set the basic mem unit to 1 */
187
188         error = copyout(&sysinfo, (caddr_t)args->info, sizeof(sysinfo));
189         return (error);
190 }
191
192 /*
193  * MPALMOSTSAFE
194  */
195 int
196 sys_linux_alarm(struct linux_alarm_args *args)
197 {
198         struct thread *td = curthread;
199         struct proc *p = td->td_proc;
200         struct itimerval it, old_it;
201         struct timeval tv;
202
203 #ifdef DEBUG
204         if (ldebug(alarm))
205                 kprintf(ARGS(alarm, "%u"), args->secs);
206 #endif
207
208         if (args->secs > 100000000)
209                 return EINVAL;
210
211         it.it_value.tv_sec = (long)args->secs;
212         it.it_value.tv_usec = 0;
213         it.it_interval.tv_sec = 0;
214         it.it_interval.tv_usec = 0;
215         get_mplock();
216         crit_enter();
217         old_it = p->p_realtimer;
218         getmicrouptime(&tv);
219         if (timevalisset(&old_it.it_value))
220                 callout_stop(&p->p_ithandle);
221         if (it.it_value.tv_sec != 0) {
222                 callout_reset(&p->p_ithandle, tvtohz_high(&it.it_value),
223                              realitexpire, p);
224                 timevaladd(&it.it_value, &tv);
225         }
226         p->p_realtimer = it;
227         crit_exit();
228         rel_mplock();
229         if (timevalcmp(&old_it.it_value, &tv, >)) {
230                 timevalsub(&old_it.it_value, &tv);
231                 if (old_it.it_value.tv_usec != 0)
232                         old_it.it_value.tv_sec++;
233                 args->sysmsg_result = old_it.it_value.tv_sec;
234         }
235         return 0;
236 }
237
238 /*
239  * MPALMOSTSAFE
240  */
241 int
242 sys_linux_brk(struct linux_brk_args *args)
243 {
244         struct thread *td = curthread;
245         struct proc *p = td->td_proc;
246         struct vmspace *vm;
247         vm_offset_t new, old;
248         struct obreak_args bsd_args;
249
250         get_mplock();
251         vm = p->p_vmspace;
252 #ifdef DEBUG
253         if (ldebug(brk))
254                 kprintf(ARGS(brk, "%p"), (void *)args->dsend);
255 #endif
256         old = (vm_offset_t)vm->vm_daddr + ctob(vm->vm_dsize);
257         new = (vm_offset_t)args->dsend;
258         bsd_args.sysmsg_result = 0;
259         bsd_args.nsize = (char *) new;
260         bsd_args.sysmsg_result = 0;
261         if (((caddr_t)new > vm->vm_daddr) && !sys_obreak(&bsd_args))
262                 args->sysmsg_result = (long)new;
263         else
264                 args->sysmsg_result = (long)old;
265         rel_mplock();
266
267         return 0;
268 }
269
270 /*
271  * MPALMOSTSAFE
272  */
273 int
274 sys_linux_uselib(struct linux_uselib_args *args)
275 {
276         struct thread *td = curthread;
277         struct proc *p;
278         struct nlookupdata nd;
279         struct vnode *vp;
280         struct exec *a_out;
281         struct vattr attr;
282         vm_offset_t vmaddr;
283         unsigned long file_offset;
284         vm_offset_t buffer;
285         unsigned long bss_size;
286         int error;
287         int locked;
288         char *path;
289
290         p = td->td_proc;
291
292         error = linux_copyin_path(args->library, &path, LINUX_PATH_EXISTS);
293         if (error)
294                 return (error);
295 #ifdef DEBUG
296         if (ldebug(uselib))
297                 kprintf(ARGS(uselib, "%s"), path);
298 #endif
299
300         a_out = NULL;
301         locked = 0;
302         vp = NULL;
303
304         get_mplock();
305         error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW);
306         nd.nl_flags |= NLC_EXEC;
307         if (error == 0)
308                 error = nlookup(&nd);
309         if (error == 0)
310                 error = cache_vget(&nd.nl_nch, nd.nl_cred, LK_EXCLUSIVE, &vp);
311         if (error)
312                 goto cleanup;
313         /*
314          * From here on down, we have a locked vnode that must be unlocked.
315          */
316         locked = 1;
317
318         /* Writable? */
319         if (vp->v_writecount) {
320                 error = ETXTBSY;
321                 goto cleanup;
322         }
323
324         /* Executable? */
325         error = VOP_GETATTR(vp, &attr);
326         if (error)
327                 goto cleanup;
328
329         if ((vp->v_mount->mnt_flag & MNT_NOEXEC) ||
330             ((attr.va_mode & 0111) == 0) || (attr.va_type != VREG)) {
331                 error = ENOEXEC;
332                 goto cleanup;
333         }
334
335         /* Sensible size? */
336         if (attr.va_size == 0) {
337                 error = ENOEXEC;
338                 goto cleanup;
339         }
340
341         error = VOP_OPEN(vp, FREAD, td->td_ucred, NULL);
342         if (error)
343                 goto cleanup;
344
345         /*
346          * Lock no longer needed
347          */
348         vn_unlock(vp);
349         locked = 0;
350
351         /* Pull in executable header into kernel_map */
352         error = vm_mmap(&kernel_map, (vm_offset_t *)&a_out, PAGE_SIZE,
353             VM_PROT_READ, VM_PROT_READ, 0, (caddr_t)vp, 0);
354         if (error)
355                 goto cleanup;
356
357         /* Is it a Linux binary ? */
358         if (((a_out->a_magic >> 16) & 0xff) != 0x64) {
359                 error = ENOEXEC;
360                 goto cleanup;
361         }
362
363         /*
364          * While we are here, we should REALLY do some more checks
365          */
366
367         /* Set file/virtual offset based on a.out variant. */
368         switch ((int)(a_out->a_magic & 0xffff)) {
369         case 0413:      /* ZMAGIC */
370                 file_offset = 1024;
371                 break;
372         case 0314:      /* QMAGIC */
373                 file_offset = 0;
374                 break;
375         default:
376                 error = ENOEXEC;
377                 goto cleanup;
378         }
379
380         bss_size = round_page(a_out->a_bss);
381
382         /* Check various fields in header for validity/bounds. */
383         if (a_out->a_text & PAGE_MASK || a_out->a_data & PAGE_MASK) {
384                 error = ENOEXEC;
385                 goto cleanup;
386         }
387
388         /* text + data can't exceed file size */
389         if (a_out->a_data + a_out->a_text > attr.va_size) {
390                 error = EFAULT;
391                 goto cleanup;
392         }
393
394         /*
395          * text/data/bss must not exceed limits
396          * XXX - this is not complete. it should check current usage PLUS
397          * the resources needed by this library.
398          */
399         if (a_out->a_text > maxtsiz ||
400             a_out->a_data + bss_size > p->p_rlimit[RLIMIT_DATA].rlim_cur) {
401                 error = ENOMEM;
402                 goto cleanup;
403         }
404
405         /* prevent more writers */
406         vsetflags(vp, VTEXT);
407
408         /*
409          * Check if file_offset page aligned. Currently we cannot handle
410          * misalinged file offsets, and so we read in the entire image
411          * (what a waste).
412          */
413         if (file_offset & PAGE_MASK) {
414 #ifdef DEBUG
415                 kprintf("uselib: Non page aligned binary %lu\n", file_offset);
416 #endif
417                 /* Map text+data read/write/execute */
418
419                 /* a_entry is the load address and is page aligned */
420                 vmaddr = trunc_page(a_out->a_entry);
421
422                 /* get anon user mapping, read+write+execute */
423                 error = vm_map_find(&p->p_vmspace->vm_map, NULL, 0,
424                                     &vmaddr, a_out->a_text + a_out->a_data,
425                                     PAGE_SIZE,
426                                     FALSE, VM_MAPTYPE_NORMAL,
427                                     VM_PROT_ALL, VM_PROT_ALL,
428                                     0);
429                 if (error)
430                         goto cleanup;
431
432                 /* map file into kernel_map */
433                 error = vm_mmap(&kernel_map, &buffer,
434                     round_page(a_out->a_text + a_out->a_data + file_offset),
435                     VM_PROT_READ, VM_PROT_READ, 0, (caddr_t)vp,
436                     trunc_page(file_offset));
437                 if (error)
438                         goto cleanup;
439
440                 /* copy from kernel VM space to user space */
441                 error = copyout((caddr_t)(uintptr_t)(buffer + file_offset),
442                     (caddr_t)vmaddr, a_out->a_text + a_out->a_data);
443
444                 /* release temporary kernel space */
445                 vm_map_remove(&kernel_map, buffer, buffer +
446                     round_page(a_out->a_text + a_out->a_data + file_offset));
447
448                 if (error)
449                         goto cleanup;
450         } else {
451 #ifdef DEBUG
452                 kprintf("uselib: Page aligned binary %lu\n", file_offset);
453 #endif
454                 /*
455                  * for QMAGIC, a_entry is 20 bytes beyond the load address
456                  * to skip the executable header
457                  */
458                 vmaddr = trunc_page(a_out->a_entry);
459
460                 /*
461                  * Map it all into the process's space as a single
462                  * copy-on-write "data" segment.
463                  */
464                 error = vm_mmap(&p->p_vmspace->vm_map, &vmaddr,
465                     a_out->a_text + a_out->a_data, VM_PROT_ALL, VM_PROT_ALL,
466                     MAP_PRIVATE | MAP_FIXED, (caddr_t)vp, file_offset);
467                 if (error)
468                         goto cleanup;
469         }
470 #ifdef DEBUG
471         kprintf("mem=%08lx = %08lx %08lx\n", (long)vmaddr, ((long*)vmaddr)[0],
472             ((long*)vmaddr)[1]);
473 #endif
474         if (bss_size != 0) {
475                 /* Calculate BSS start address */
476                 vmaddr = trunc_page(a_out->a_entry) + a_out->a_text +
477                     a_out->a_data;
478
479                 /* allocate some 'anon' space */
480                 error = vm_map_find(&p->p_vmspace->vm_map, NULL, 0,
481                                     &vmaddr, bss_size,
482                                     PAGE_SIZE,
483                                     FALSE, VM_MAPTYPE_NORMAL,
484                                     VM_PROT_ALL, VM_PROT_ALL,
485                                     0);
486                 if (error)
487                         goto cleanup;
488         }
489
490 cleanup:
491         /* Unlock/release vnode */
492         if (vp) {
493                 if (locked)
494                         vn_unlock(vp);
495                 vrele(vp);
496         }
497         /* Release the kernel mapping. */
498         if (a_out) {
499                 vm_map_remove(&kernel_map, (vm_offset_t)a_out,
500                     (vm_offset_t)a_out + PAGE_SIZE);
501         }
502         nlookup_done(&nd);
503         rel_mplock();
504         linux_free_path(&path);
505         return (error);
506 }
507
508 /*
509  * MPSAFE
510  */
511 int
512 sys_linux_select(struct linux_select_args *args)
513 {
514         struct select_args bsa;
515         struct timeval tv0, tv1, utv, *tvp;
516         caddr_t sg;
517         int error;
518
519 #ifdef DEBUG
520         if (ldebug(select))
521                 kprintf(ARGS(select, "%d, %p, %p, %p, %p"), args->nfds,
522                     (void *)args->readfds, (void *)args->writefds,
523                     (void *)args->exceptfds, (void *)args->timeout);
524 #endif
525
526         error = 0;
527         bsa.sysmsg_result = 0;
528         bsa.nd = args->nfds;
529         bsa.in = args->readfds;
530         bsa.ou = args->writefds;
531         bsa.ex = args->exceptfds;
532         bsa.tv = (struct timeval *)args->timeout;
533
534         /*
535          * Store current time for computation of the amount of
536          * time left.
537          */
538         if (args->timeout) {
539                 if ((error = copyin((caddr_t)args->timeout, &utv,
540                     sizeof(utv))))
541                         goto select_out;
542 #ifdef DEBUG
543                 if (ldebug(select))
544                         kprintf(LMSG("incoming timeout (%ld/%ld)"),
545                             utv.tv_sec, utv.tv_usec);
546 #endif
547
548                 if (itimerfix(&utv)) {
549                         /*
550                          * The timeval was invalid.  Convert it to something
551                          * valid that will act as it does under Linux.
552                          */
553                         sg = stackgap_init();
554                         tvp = stackgap_alloc(&sg, sizeof(utv));
555                         utv.tv_sec += utv.tv_usec / 1000000;
556                         utv.tv_usec %= 1000000;
557                         if (utv.tv_usec < 0) {
558                                 utv.tv_sec -= 1;
559                                 utv.tv_usec += 1000000;
560                         }
561                         if (utv.tv_sec < 0)
562                                 timevalclear(&utv);
563                         if ((error = copyout(&utv, tvp, sizeof(utv))))
564                                 goto select_out;
565                         bsa.tv = tvp;
566                 }
567                 microtime(&tv0);
568         }
569
570         error = sys_select(&bsa);
571         args->sysmsg_result = bsa.sysmsg_result;
572 #ifdef DEBUG
573         if (ldebug(select))
574                 kprintf(LMSG("real select returns %d"), error);
575 #endif
576         if (error) {
577                 /*
578                  * See fs/select.c in the Linux kernel.  Without this,
579                  * Maelstrom doesn't work.
580                  */
581                 if (error == ERESTART)
582                         error = EINTR;
583                 goto select_out;
584         }
585
586         if (args->timeout) {
587                 if (args->sysmsg_result) {
588                         /*
589                          * Compute how much time was left of the timeout,
590                          * by subtracting the current time and the time
591                          * before we started the call, and subtracting
592                          * that result from the user-supplied value.
593                          */
594                         microtime(&tv1);
595                         timevalsub(&tv1, &tv0);
596                         timevalsub(&utv, &tv1);
597                         if (utv.tv_sec < 0)
598                                 timevalclear(&utv);
599                 } else
600                         timevalclear(&utv);
601 #ifdef DEBUG
602                 if (ldebug(select))
603                         kprintf(LMSG("outgoing timeout (%ld/%ld)"),
604                             utv.tv_sec, utv.tv_usec);
605 #endif
606                 if ((error = copyout(&utv, (caddr_t)args->timeout,
607                     sizeof(utv))))
608                         goto select_out;
609         }
610
611 select_out:
612 #ifdef DEBUG
613         if (ldebug(select))
614                 kprintf(LMSG("select_out -> %d"), error);
615 #endif
616         return error;
617 }
618
619 /*
620  * MPSAFE
621  */
622 int     
623 sys_linux_mremap(struct linux_mremap_args *args)
624 {
625         struct munmap_args bsd_args; 
626         int error = 0;
627
628 #ifdef DEBUG
629         if (ldebug(mremap))
630                 kprintf(ARGS(mremap, "%p, %08lx, %08lx, %08lx"),
631                     (void *)args->addr, 
632                     (unsigned long)args->old_len, 
633                     (unsigned long)args->new_len,
634                     (unsigned long)args->flags);
635 #endif
636         if (args->flags & ~(LINUX_MREMAP_FIXED | LINUX_MREMAP_MAYMOVE)) {
637                 args->sysmsg_resultp = NULL;
638                 return (EINVAL);
639         }
640
641         /*
642          * Check for the page alignment.
643          * Linux defines PAGE_MASK to be FreeBSD ~PAGE_MASK.
644          */
645         if (args->addr & PAGE_MASK) {
646                 args->sysmsg_resultp = NULL;
647                 return (EINVAL);
648         }
649
650         args->new_len = round_page(args->new_len);
651         args->old_len = round_page(args->old_len);
652
653         if (args->new_len > args->old_len) {
654                 args->sysmsg_result = 0;
655                 return ENOMEM;
656         }
657
658         if (args->new_len < args->old_len) {
659                 bsd_args.sysmsg_result = 0;
660                 bsd_args.addr = (caddr_t)(args->addr + args->new_len);
661                 bsd_args.len = args->old_len - args->new_len;
662                 error = sys_munmap(&bsd_args);
663         }
664
665         args->sysmsg_resultp = error ? NULL : (void *)args->addr;
666         return error;
667 }
668
669 #define LINUX_MS_ASYNC          0x0001
670 #define LINUX_MS_INVALIDATE     0x0002
671 #define LINUX_MS_SYNC           0x0004
672
673 /*
674  * MPSAFE
675  */
676 int
677 sys_linux_msync(struct linux_msync_args *args)
678 {
679         struct msync_args bsd_args;
680         int error;
681
682         bsd_args.addr = (caddr_t)args->addr;
683         bsd_args.len = args->len;
684         bsd_args.flags = args->fl & ~LINUX_MS_SYNC;
685         bsd_args.sysmsg_result = 0;
686
687         error = sys_msync(&bsd_args);
688         args->sysmsg_result = bsd_args.sysmsg_result;
689         return(error);
690 }
691
692 /*
693  * MPSAFE
694  */
695 int
696 sys_linux_time(struct linux_time_args *args)
697 {
698         struct timeval tv;
699         l_time_t tm;
700         int error;
701
702 #ifdef DEBUG
703         if (ldebug(time))
704                 kprintf(ARGS(time, "*"));
705 #endif
706
707         microtime(&tv);
708         tm = tv.tv_sec;
709         if (args->tm && (error = copyout(&tm, (caddr_t)args->tm, sizeof(tm))))
710                 return error;
711         args->sysmsg_lresult = tm;
712         return 0;
713 }
714
715 struct l_times_argv {
716         l_long          tms_utime;
717         l_long          tms_stime;
718         l_long          tms_cutime;
719         l_long          tms_cstime;
720 };
721
722 #define CLK_TCK 100     /* Linux uses 100 */
723
724 #define CONVTCK(r)      (r.tv_sec * CLK_TCK + r.tv_usec / (1000000 / CLK_TCK))
725
726 /*
727  * MPALMOSTSAFE
728  */
729 int
730 sys_linux_times(struct linux_times_args *args)
731 {
732         struct thread *td = curthread;
733         struct proc *p = td->td_proc;
734         struct timeval tv;
735         struct l_times_argv tms;
736         struct rusage ru;
737         int error;
738
739 #ifdef DEBUG
740         if (ldebug(times))
741                 kprintf(ARGS(times, "*"));
742 #endif
743
744         get_mplock();
745         calcru_proc(p, &ru);
746         rel_mplock();
747
748         tms.tms_utime = CONVTCK(ru.ru_utime);
749         tms.tms_stime = CONVTCK(ru.ru_stime);
750
751         tms.tms_cutime = CONVTCK(p->p_cru.ru_utime);
752         tms.tms_cstime = CONVTCK(p->p_cru.ru_stime);
753
754         if ((error = copyout(&tms, (caddr_t)args->buf, sizeof(tms))))
755                 return error;
756
757         microuptime(&tv);
758         args->sysmsg_result = (int)CONVTCK(tv);
759         return 0;
760 }
761
762 /*
763  * MPALMOSTSAFE
764  */
765 int
766 sys_linux_newuname(struct linux_newuname_args *args)
767 {
768         struct thread *td = curthread;
769         struct l_new_utsname utsname;
770         char *osrelease, *osname;
771
772 #ifdef DEBUG
773         if (ldebug(newuname))
774                 kprintf(ARGS(newuname, "*"));
775 #endif
776
777         get_mplock();
778         osname = linux_get_osname(td);
779         osrelease = linux_get_osrelease(td);
780
781         bzero(&utsname, sizeof(utsname));
782         strncpy(utsname.sysname, osname, LINUX_MAX_UTSNAME-1);
783         strncpy(utsname.nodename, hostname, LINUX_MAX_UTSNAME-1);
784         strncpy(utsname.release, osrelease, LINUX_MAX_UTSNAME-1);
785         strncpy(utsname.version, version, LINUX_MAX_UTSNAME-1);
786         strncpy(utsname.machine, machine, LINUX_MAX_UTSNAME-1);
787         strncpy(utsname.domainname, domainname, LINUX_MAX_UTSNAME-1);
788         rel_mplock();
789
790         return (copyout(&utsname, (caddr_t)args->buf, sizeof(utsname)));
791 }
792
793 /* XXX: why would this be i386-only? most of these are wrong! */
794 #if defined(__i386__)
795 struct l_utimbuf {
796         l_time_t l_actime;
797         l_time_t l_modtime;
798 };
799
800 /*
801  * MPALMOSTSAFE
802  */
803 int
804 sys_linux_utime(struct linux_utime_args *args)
805 {
806         struct timeval tv[2];
807         struct l_utimbuf lut;
808         struct nlookupdata nd;
809         char *path;
810         int error;
811
812         error = linux_copyin_path(args->fname, &path, LINUX_PATH_EXISTS);
813         if (error)
814                 return (error);
815 #ifdef DEBUG
816         if (ldebug(utime))
817                 kprintf(ARGS(utime, "%s, *"), path);
818 #endif
819
820         if (args->times) {
821                 error = copyin(args->times, &lut, sizeof(lut));
822                 if (error)
823                         goto cleanup;
824                 tv[0].tv_sec = lut.l_actime;
825                 tv[0].tv_usec = 0;
826                 tv[1].tv_sec = lut.l_modtime;
827                 tv[1].tv_usec = 0;
828         }
829         get_mplock();
830         error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW);
831         if (error == 0)
832                 error = kern_utimes(&nd, args->times ? tv : NULL);
833         nlookup_done(&nd);
834         rel_mplock();
835 cleanup:
836         linux_free_path(&path);
837         return (error);
838 }
839
840 int
841 sys_linux_utimes(struct linux_utimes_args *args)
842 {
843         l_timeval ltv[2];
844         struct timeval tv[2], *tvp = NULL;
845         struct nlookupdata nd;
846         char *path;
847         int error;
848
849         error = linux_copyin_path(args->fname, &path, LINUX_PATH_EXISTS);
850         if (error)
851                 return (error);
852 #ifdef DEBUG
853         if (ldebug(utimes))
854                 kprintf(ARGS(utimes, "%s, *"), path);
855 #endif
856
857         if (args->tptr) {
858                 error = copyin(args->tptr, ltv, sizeof(ltv));
859                 if (error)
860                         goto cleanup;
861                 tv[0].tv_sec = ltv[0].tv_sec;
862                 tv[0].tv_usec = ltv[0].tv_usec;
863                 tv[1].tv_sec = ltv[1].tv_sec;
864                 tv[1].tv_usec = ltv[1].tv_usec;
865                 tvp = tv;
866         }
867         get_mplock();
868         error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW);
869         if (error == 0)
870                 error = kern_utimes(&nd, tvp);
871         nlookup_done(&nd);
872         rel_mplock();
873 cleanup:
874         linux_free_path(&path);
875         return (error);
876 }
877
878 int
879 sys_linux_futimesat(struct linux_futimesat_args *args)
880 {
881         l_timeval ltv[2];
882         struct timeval tv[2], *tvp = NULL;
883         struct file *fp;
884         struct nlookupdata nd;
885         char *path;
886         int dfd,error;
887
888         error = linux_copyin_path(args->fname, &path, LINUX_PATH_EXISTS);
889         if (error)
890                 return (error);
891 #ifdef DEBUG
892         if (ldebug(futimesat))
893                 kprintf(ARGS(futimesat, "%s, *"), path);
894 #endif
895         if (args->tptr) {
896                 error = copyin(args->tptr, ltv, sizeof(ltv));
897                 if (error)
898                         goto cleanup;
899                 tv[0].tv_sec = ltv[0].tv_sec;
900                 tv[0].tv_usec = ltv[0].tv_usec;
901                 tv[1].tv_sec = ltv[1].tv_sec;
902                 tv[1].tv_usec = ltv[1].tv_usec;
903                 tvp = tv;
904         }
905         dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
906         get_mplock();
907         error = nlookup_init_at(&nd, &fp, dfd, path, UIO_SYSSPACE, NLC_FOLLOW);
908         if (error == 0)
909                 error = kern_utimes(&nd, tvp);
910         nlookup_done_at(&nd, fp);
911         rel_mplock();
912 cleanup:
913         linux_free_path(&path);
914         return (error);
915 }
916
917
918 int
919 sys_linux_utimensat(struct linux_utimensat_args *args)
920 {
921         struct l_timespec ltv[2];
922         struct timeval tv[2], *tvp = NULL;
923         struct file *fp;
924         struct nlookupdata nd;
925         char *path;
926         int dfd, flags, error = 0;
927
928         if (args->flag & ~LINUX_AT_SYMLINK_NOFOLLOW)
929                 return (EINVAL);
930
931         if (args->dfd == LINUX_AT_FDCWD && args->fname == NULL)
932                 return (EINVAL);
933
934         if (args->fname) {
935                 error = linux_copyin_path(args->fname, &path, LINUX_PATH_EXISTS);
936                 if (error)
937                         return (error);
938         }
939 #ifdef DEBUG
940         if (ldebug(utimensat))
941                 kprintf(ARGS(utimensat, "%s, *"), path);
942 #endif
943         if (args->tptr) {
944                 error = copyin(args->tptr, ltv, sizeof(ltv));
945                 if (error)
946                         goto cleanup;
947
948                 if (ltv[0].tv_sec == LINUX_UTIME_NOW) {
949                         microtime(&tv[0]);
950                 } else if (ltv[0].tv_sec == LINUX_UTIME_OMIT) {
951                         /* XXX: this is not right, but will do for now */
952                         microtime(&tv[0]);
953                 } else {
954                         tv[0].tv_sec = ltv[0].tv_sec;
955                         /* XXX: we lose precision here, as we don't have ns */
956                         tv[0].tv_usec = ltv[0].tv_nsec/1000;
957                 }
958                 if (ltv[1].tv_sec == LINUX_UTIME_NOW) {
959                         microtime(&tv[1]);
960                 } else if (ltv[1].tv_sec == LINUX_UTIME_OMIT) {
961                         /* XXX: this is not right, but will do for now */
962                         microtime(&tv[1]);
963                 } else {
964                         tv[1].tv_sec = ltv[1].tv_sec;
965                         /* XXX: we lose precision here, as we don't have ns */
966                         tv[1].tv_usec = ltv[1].tv_nsec/1000;
967                 }
968                 tvp = tv;
969         }
970
971         dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
972         flags = (args->flag & LINUX_AT_SYMLINK_NOFOLLOW) ? 0 : NLC_FOLLOW;
973
974         get_mplock();
975         if (args->fname) {
976                 error = nlookup_init_at(&nd, &fp, dfd, path, UIO_SYSSPACE, flags);
977                 if (error == 0)
978                         error = kern_utimes(&nd, tvp);
979                 nlookup_done_at(&nd, fp);
980         } else {
981                 /* Thank you, Linux, for another non-standard "feature" */
982                 KKASSERT(dfd != AT_FDCWD);
983                 error = kern_futimes(dfd, tvp);
984         }
985         rel_mplock();
986 cleanup:
987         if (args->fname)
988                 linux_free_path(&path);
989
990         return (error);
991 }
992 #endif /* __i386__ */
993
994 #define __WCLONE 0x80000000
995
996 /*
997  * MPALMOSTSAFE
998  */
999 int
1000 sys_linux_waitpid(struct linux_waitpid_args *args)
1001 {
1002         int error, options, status;
1003
1004 #ifdef DEBUG
1005         if (ldebug(waitpid))
1006                 kprintf(ARGS(waitpid, "%d, %p, %d"),
1007                     args->pid, (void *)args->status, args->options);
1008 #endif
1009         options = args->options & (WNOHANG | WUNTRACED);
1010         /* WLINUXCLONE should be equal to __WCLONE, but we make sure */
1011         if (args->options & __WCLONE)
1012                 options |= WLINUXCLONE;
1013
1014         error = kern_wait(args->pid, args->status ? &status : NULL, options,
1015                           NULL, &args->sysmsg_result);
1016
1017         if (error == 0 && args->status) {
1018                 status &= 0xffff;
1019                 if (WIFSIGNALED(status))
1020                         status = (status & 0xffffff80) |
1021                             BSD_TO_LINUX_SIGNAL(WTERMSIG(status));
1022                 else if (WIFSTOPPED(status))
1023                         status = (status & 0xffff00ff) |
1024                             (BSD_TO_LINUX_SIGNAL(WSTOPSIG(status)) << 8);
1025                 error = copyout(&status, args->status, sizeof(status));
1026         }
1027
1028         return (error);
1029 }
1030
1031 /*
1032  * MPALMOSTSAFE
1033  */
1034 int
1035 sys_linux_wait4(struct linux_wait4_args *args)
1036 {
1037         struct thread *td = curthread;
1038         struct lwp *lp = td->td_lwp;
1039         struct rusage rusage;
1040         int error, options, status;
1041
1042 #ifdef DEBUG
1043         if (ldebug(wait4))
1044                 kprintf(ARGS(wait4, "%d, %p, %d, %p"),
1045                     args->pid, (void *)args->status, args->options,
1046                     (void *)args->rusage);
1047 #endif
1048         options = args->options & (WNOHANG | WUNTRACED);
1049         /* WLINUXCLONE should be equal to __WCLONE, but we make sure */
1050         if (args->options & __WCLONE)
1051                 options |= WLINUXCLONE;
1052
1053         error = kern_wait(args->pid, args->status ? &status : NULL, options,
1054                           args->rusage ? &rusage : NULL, &args->sysmsg_result);
1055
1056         if (error == 0) {
1057                 spin_lock(&lp->lwp_spin);
1058                 lwp_delsig(lp, SIGCHLD);
1059                 spin_unlock(&lp->lwp_spin);
1060         }
1061
1062         if (error == 0 && args->status) {
1063                 status &= 0xffff;
1064                 if (WIFSIGNALED(status))
1065                         status = (status & 0xffffff80) |
1066                             BSD_TO_LINUX_SIGNAL(WTERMSIG(status));
1067                 else if (WIFSTOPPED(status))
1068                         status = (status & 0xffff00ff) |
1069                             (BSD_TO_LINUX_SIGNAL(WSTOPSIG(status)) << 8);
1070                 error = copyout(&status, args->status, sizeof(status));
1071         }
1072         if (error == 0 && args->rusage)
1073                 error = copyout(&rusage, args->rusage, sizeof(rusage));
1074
1075         return (error);
1076 }
1077
1078 /*
1079  * MPALMOSTSAFE
1080  */
1081 int
1082 sys_linux_mknod(struct linux_mknod_args *args)
1083 {
1084         struct nlookupdata nd;
1085         char *path;
1086         int error;
1087
1088         error = linux_copyin_path(args->path, &path, LINUX_PATH_CREATE);
1089         if (error)
1090                 return (error);
1091 #ifdef DEBUG
1092         if (ldebug(mknod))
1093                 kprintf(ARGS(mknod, "%s, %d, %d"),
1094                     path, args->mode, args->dev);
1095 #endif
1096         get_mplock();
1097         error = nlookup_init(&nd, path, UIO_SYSSPACE, 0);
1098         if (error == 0) {
1099                 if (args->mode & S_IFIFO) {
1100                         error = kern_mkfifo(&nd, args->mode);
1101                 } else {
1102                         error = kern_mknod(&nd, args->mode,
1103                                            umajor(args->dev),
1104                                            uminor(args->dev));
1105                 }
1106         }
1107         nlookup_done(&nd);
1108         rel_mplock();
1109
1110         linux_free_path(&path);
1111         return(error);
1112 }
1113
1114 int
1115 sys_linux_mknodat(struct linux_mknodat_args *args)
1116 {
1117         struct nlookupdata nd;
1118         struct file *fp;
1119         char *path;
1120         int dfd, error;
1121
1122         error = linux_copyin_path(args->path, &path, LINUX_PATH_CREATE);
1123         if (error)
1124                 return (error);
1125 #ifdef DEBUG
1126         if (ldebug(mknod))
1127                 kprintf(ARGS(mknod, "%s, %d, %d"),
1128                     path, args->mode, args->dev);
1129 #endif
1130         get_mplock();
1131         dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
1132         error = nlookup_init_at(&nd, &fp, dfd, path, UIO_SYSSPACE, 0);
1133         if (error == 0) {
1134                 if (args->mode & S_IFIFO) {
1135                         error = kern_mkfifo(&nd, args->mode);
1136                 } else {
1137                         error = kern_mknod(&nd, args->mode,
1138                                            umajor(args->dev),
1139                                            uminor(args->dev));
1140                 }
1141         }
1142         nlookup_done_at(&nd, fp);
1143         rel_mplock();
1144
1145         linux_free_path(&path);
1146         return(error);
1147 }
1148
1149 /*
1150  * UGH! This is just about the dumbest idea I've ever heard!!
1151  *
1152  * MPSAFE
1153  */
1154 int
1155 sys_linux_personality(struct linux_personality_args *args)
1156 {
1157 #ifdef DEBUG
1158         if (ldebug(personality))
1159                 kprintf(ARGS(personality, "%d"), args->per);
1160 #endif
1161         if (args->per != 0)
1162                 return EINVAL;
1163
1164         /* Yes Jim, it's still a Linux... */
1165         args->sysmsg_result = 0;
1166         return 0;
1167 }
1168
1169 /*
1170  * Wrappers for get/setitimer for debugging..
1171  *
1172  * MPSAFE
1173  */
1174 int
1175 sys_linux_setitimer(struct linux_setitimer_args *args)
1176 {
1177         struct setitimer_args bsa;
1178         struct itimerval foo;
1179         int error;
1180
1181 #ifdef DEBUG
1182         if (ldebug(setitimer))
1183                 kprintf(ARGS(setitimer, "%p, %p"),
1184                     (void *)args->itv, (void *)args->oitv);
1185 #endif
1186         bsa.which = args->which;
1187         bsa.itv = (struct itimerval *)args->itv;
1188         bsa.oitv = (struct itimerval *)args->oitv;
1189         bsa.sysmsg_result = 0;
1190         if (args->itv) {
1191             if ((error = copyin((caddr_t)args->itv, &foo, sizeof(foo))))
1192                 return error;
1193 #ifdef DEBUG
1194             if (ldebug(setitimer)) {
1195                 kprintf("setitimer: value: sec: %ld, usec: %ld\n",
1196                     foo.it_value.tv_sec, foo.it_value.tv_usec);
1197                 kprintf("setitimer: interval: sec: %ld, usec: %ld\n",
1198                     foo.it_interval.tv_sec, foo.it_interval.tv_usec);
1199             }
1200 #endif
1201         }
1202         error = sys_setitimer(&bsa);
1203         args->sysmsg_result = bsa.sysmsg_result;
1204         return(error);
1205 }
1206
1207 /*
1208  * MPSAFE
1209  */
1210 int
1211 sys_linux_getitimer(struct linux_getitimer_args *args)
1212 {
1213         struct getitimer_args bsa;
1214         int error;
1215 #ifdef DEBUG
1216         if (ldebug(getitimer))
1217                 kprintf(ARGS(getitimer, "%p"), (void *)args->itv);
1218 #endif
1219         bsa.which = args->which;
1220         bsa.itv = (struct itimerval *)args->itv;
1221         bsa.sysmsg_result = 0;
1222         error = sys_getitimer(&bsa);
1223         args->sysmsg_result = bsa.sysmsg_result;
1224         return(error);
1225 }
1226
1227 /*
1228  * MPSAFE
1229  */
1230 int
1231 sys_linux_nice(struct linux_nice_args *args)
1232 {
1233         struct setpriority_args bsd_args;
1234         int error;
1235
1236         bsd_args.which = PRIO_PROCESS;
1237         bsd_args.who = 0;       /* current process */
1238         bsd_args.prio = args->inc;
1239         bsd_args.sysmsg_result = 0;
1240         error = sys_setpriority(&bsd_args);
1241         args->sysmsg_result = bsd_args.sysmsg_result;
1242         return(error);
1243 }
1244
1245 /*
1246  * MPALMOSTSAFE
1247  */
1248 int
1249 sys_linux_setgroups(struct linux_setgroups_args *args)
1250 {
1251         struct thread *td = curthread;
1252         struct proc *p = td->td_proc;
1253         struct ucred *newcred, *oldcred;
1254         l_gid_t linux_gidset[NGROUPS];
1255         gid_t *bsd_gidset;
1256         int ngrp, error;
1257
1258         ngrp = args->gidsetsize;
1259         oldcred = td->td_ucred;
1260
1261         /*
1262          * cr_groups[0] holds egid. Setting the whole set from
1263          * the supplied set will cause egid to be changed too.
1264          * Keep cr_groups[0] unchanged to prevent that.
1265          */
1266
1267         if ((error = priv_check_cred(oldcred, PRIV_CRED_SETGROUPS, 0)) != 0)
1268                 return (error);
1269
1270         if ((u_int)ngrp >= NGROUPS)
1271                 return (EINVAL);
1272
1273         get_mplock();
1274         newcred = crdup(oldcred);
1275         if (ngrp > 0) {
1276                 error = copyin((caddr_t)args->grouplist, linux_gidset,
1277                                ngrp * sizeof(l_gid_t));
1278                 if (error) {
1279                         crfree(newcred);
1280                         rel_mplock();
1281                         return (error);
1282                 }
1283
1284                 newcred->cr_ngroups = ngrp + 1;
1285
1286                 bsd_gidset = newcred->cr_groups;
1287                 ngrp--;
1288                 while (ngrp >= 0) {
1289                         bsd_gidset[ngrp + 1] = linux_gidset[ngrp];
1290                         ngrp--;
1291                 }
1292         } else {
1293                 newcred->cr_ngroups = 1;
1294         }
1295
1296         setsugid();
1297         oldcred = p->p_ucred;   /* reload, deal with threads race */
1298         p->p_ucred = newcred;
1299         crfree(oldcred);
1300         rel_mplock();
1301         return (0);
1302 }
1303
1304 /*
1305  * MPSAFE
1306  */
1307 int
1308 sys_linux_getgroups(struct linux_getgroups_args *args)
1309 {
1310         struct thread *td = curthread;
1311         struct ucred *cred;
1312         l_gid_t linux_gidset[NGROUPS];
1313         gid_t *bsd_gidset;
1314         int bsd_gidsetsz, ngrp, error;
1315
1316         cred = td->td_ucred;
1317         bsd_gidset = cred->cr_groups;
1318         bsd_gidsetsz = cred->cr_ngroups - 1;
1319
1320         /*
1321          * cr_groups[0] holds egid. Returning the whole set
1322          * here will cause a duplicate. Exclude cr_groups[0]
1323          * to prevent that.
1324          */
1325
1326         if ((ngrp = args->gidsetsize) == 0) {
1327                 args->sysmsg_result = bsd_gidsetsz;
1328                 return (0);
1329         }
1330
1331         if ((u_int)ngrp < bsd_gidsetsz)
1332                 return (EINVAL);
1333
1334         ngrp = 0;
1335         while (ngrp < bsd_gidsetsz) {
1336                 linux_gidset[ngrp] = bsd_gidset[ngrp + 1];
1337                 ngrp++;
1338         }
1339
1340         if ((error = copyout(linux_gidset, args->grouplist,
1341                              ngrp * sizeof(l_gid_t)))) {
1342                 return (error);
1343         }
1344
1345         args->sysmsg_result = ngrp;
1346         return (0);
1347 }
1348
1349 /*
1350  * MPSAFE
1351  */
1352 int
1353 sys_linux_setrlimit(struct linux_setrlimit_args *args)
1354 {
1355         struct l_rlimit linux_rlim;
1356         struct rlimit rlim;
1357         u_int which;
1358         int error;
1359
1360 #ifdef DEBUG
1361         if (ldebug(setrlimit))
1362                 kprintf(ARGS(setrlimit, "%d, %p"),
1363                     args->resource, (void *)args->rlim);
1364 #endif
1365         if (args->resource >= LINUX_RLIM_NLIMITS)
1366                 return (EINVAL);
1367         which = linux_to_bsd_resource[args->resource];
1368         if (which == -1)
1369                 return (EINVAL);
1370
1371         error = copyin(args->rlim, &linux_rlim, sizeof(linux_rlim));
1372         if (error)
1373                 return (error);
1374         rlim.rlim_cur = (rlim_t)linux_rlim.rlim_cur;
1375         rlim.rlim_max = (rlim_t)linux_rlim.rlim_max;
1376
1377         error = kern_setrlimit(which, &rlim);
1378
1379         return(error);
1380 }
1381
1382 /*
1383  * MPSAFE
1384  */
1385 int
1386 sys_linux_old_getrlimit(struct linux_old_getrlimit_args *args)
1387 {
1388         struct l_rlimit linux_rlim;
1389         struct rlimit rlim;
1390         u_int which;
1391         int error;
1392
1393 #ifdef DEBUG
1394         if (ldebug(old_getrlimit))
1395                 kprintf(ARGS(old_getrlimit, "%d, %p"),
1396                     args->resource, (void *)args->rlim);
1397 #endif
1398         if (args->resource >= LINUX_RLIM_NLIMITS)
1399                 return (EINVAL);
1400         which = linux_to_bsd_resource[args->resource];
1401         if (which == -1)
1402                 return (EINVAL);
1403
1404         error = kern_getrlimit(which, &rlim);
1405
1406         if (error == 0) {
1407                 linux_rlim.rlim_cur = (l_ulong)rlim.rlim_cur;
1408                 if (linux_rlim.rlim_cur == ULONG_MAX)
1409                         linux_rlim.rlim_cur = LONG_MAX;
1410                 linux_rlim.rlim_max = (l_ulong)rlim.rlim_max;
1411                 if (linux_rlim.rlim_max == ULONG_MAX)
1412                         linux_rlim.rlim_max = LONG_MAX;
1413                 error = copyout(&linux_rlim, args->rlim, sizeof(linux_rlim));
1414         }
1415         return (error);
1416 }
1417
1418 /*
1419  * MPSAFE
1420  */
1421 int
1422 sys_linux_getrlimit(struct linux_getrlimit_args *args)
1423 {
1424         struct l_rlimit linux_rlim;
1425         struct rlimit rlim;
1426         u_int which;
1427         int error;
1428
1429 #ifdef DEBUG
1430         if (ldebug(getrlimit))
1431                 kprintf(ARGS(getrlimit, "%d, %p"),
1432                     args->resource, (void *)args->rlim);
1433 #endif
1434         if (args->resource >= LINUX_RLIM_NLIMITS)
1435                 return (EINVAL);
1436         which = linux_to_bsd_resource[args->resource];
1437         if (which == -1)
1438                 return (EINVAL);
1439
1440         error = kern_getrlimit(which, &rlim);
1441
1442         if (error == 0) {
1443                 linux_rlim.rlim_cur = (l_ulong)rlim.rlim_cur;
1444                 linux_rlim.rlim_max = (l_ulong)rlim.rlim_max;
1445                 error = copyout(&linux_rlim, args->rlim, sizeof(linux_rlim));
1446         }
1447         return (error);
1448 }
1449
1450 /*
1451  * MPSAFE
1452  */
1453 int
1454 sys_linux_sched_setscheduler(struct linux_sched_setscheduler_args *args)
1455 {
1456         struct sched_setscheduler_args bsd;
1457         int error;
1458
1459 #ifdef DEBUG
1460         if (ldebug(sched_setscheduler))
1461                 kprintf(ARGS(sched_setscheduler, "%d, %d, %p"),
1462                     args->pid, args->policy, (const void *)args->param);
1463 #endif
1464
1465         switch (args->policy) {
1466         case LINUX_SCHED_OTHER:
1467                 bsd.policy = SCHED_OTHER;
1468                 break;
1469         case LINUX_SCHED_FIFO:
1470                 bsd.policy = SCHED_FIFO;
1471                 break;
1472         case LINUX_SCHED_RR:
1473                 bsd.policy = SCHED_RR;
1474                 break;
1475         default:
1476                 return EINVAL;
1477         }
1478
1479         bsd.pid = args->pid;
1480         bsd.param = (struct sched_param *)args->param;
1481         bsd.sysmsg_result = 0;
1482
1483         error = sys_sched_setscheduler(&bsd);
1484         args->sysmsg_result = bsd.sysmsg_result;
1485         return(error);
1486 }
1487
1488 /*
1489  * MPSAFE
1490  */
1491 int
1492 sys_linux_sched_getscheduler(struct linux_sched_getscheduler_args *args)
1493 {
1494         struct sched_getscheduler_args bsd;
1495         int error;
1496
1497 #ifdef DEBUG
1498         if (ldebug(sched_getscheduler))
1499                 kprintf(ARGS(sched_getscheduler, "%d"), args->pid);
1500 #endif
1501
1502         bsd.sysmsg_result = 0;
1503         bsd.pid = args->pid;
1504         error = sys_sched_getscheduler(&bsd);
1505         args->sysmsg_result = bsd.sysmsg_result;
1506
1507         switch (args->sysmsg_result) {
1508         case SCHED_OTHER:
1509                 args->sysmsg_result = LINUX_SCHED_OTHER;
1510                 break;
1511         case SCHED_FIFO:
1512                 args->sysmsg_result = LINUX_SCHED_FIFO;
1513                 break;
1514         case SCHED_RR:
1515                 args->sysmsg_result = LINUX_SCHED_RR;
1516                 break;
1517         }
1518         return error;
1519 }
1520
1521 /*
1522  * MPSAFE
1523  */
1524 int
1525 sys_linux_sched_get_priority_max(struct linux_sched_get_priority_max_args *args)
1526 {
1527         struct sched_get_priority_max_args bsd;
1528         int error;
1529
1530 #ifdef DEBUG
1531         if (ldebug(sched_get_priority_max))
1532                 kprintf(ARGS(sched_get_priority_max, "%d"), args->policy);
1533 #endif
1534
1535         switch (args->policy) {
1536         case LINUX_SCHED_OTHER:
1537                 bsd.policy = SCHED_OTHER;
1538                 break;
1539         case LINUX_SCHED_FIFO:
1540                 bsd.policy = SCHED_FIFO;
1541                 break;
1542         case LINUX_SCHED_RR:
1543                 bsd.policy = SCHED_RR;
1544                 break;
1545         default:
1546                 return EINVAL;
1547         }
1548         bsd.sysmsg_result = 0;
1549
1550         error = sys_sched_get_priority_max(&bsd);
1551         args->sysmsg_result = bsd.sysmsg_result;
1552         return(error);
1553 }
1554
1555 /*
1556  * MPSAFE
1557  */
1558 int
1559 sys_linux_sched_get_priority_min(struct linux_sched_get_priority_min_args *args)
1560 {
1561         struct sched_get_priority_min_args bsd;
1562         int error;
1563
1564 #ifdef DEBUG
1565         if (ldebug(sched_get_priority_min))
1566                 kprintf(ARGS(sched_get_priority_min, "%d"), args->policy);
1567 #endif
1568
1569         switch (args->policy) {
1570         case LINUX_SCHED_OTHER:
1571                 bsd.policy = SCHED_OTHER;
1572                 break;
1573         case LINUX_SCHED_FIFO:
1574                 bsd.policy = SCHED_FIFO;
1575                 break;
1576         case LINUX_SCHED_RR:
1577                 bsd.policy = SCHED_RR;
1578                 break;
1579         default:
1580                 return EINVAL;
1581         }
1582         bsd.sysmsg_result = 0;
1583
1584         error = sys_sched_get_priority_min(&bsd);
1585         args->sysmsg_result = bsd.sysmsg_result;
1586         return(error);
1587 }
1588
1589 #define REBOOT_CAD_ON   0x89abcdef
1590 #define REBOOT_CAD_OFF  0
1591 #define REBOOT_HALT     0xcdef0123
1592 #define REBOOT_RESTART  0x01234567
1593 #define REBOOT_RESTART2 0xA1B2C3D4
1594 #define REBOOT_POWEROFF 0x4321FEDC
1595 #define REBOOT_MAGIC1   0xfee1dead
1596 #define REBOOT_MAGIC2   0x28121969
1597 #define REBOOT_MAGIC2A  0x05121996
1598 #define REBOOT_MAGIC2B  0x16041998
1599
1600 /*
1601  * MPSAFE
1602  */
1603 int
1604 sys_linux_reboot(struct linux_reboot_args *args)
1605 {
1606         struct reboot_args bsd_args;
1607         int error;
1608
1609 #ifdef DEBUG
1610         if (ldebug(reboot))
1611                 kprintf(ARGS(reboot, "0x%x"), args->cmd);
1612 #endif
1613
1614         if ((args->magic1 != REBOOT_MAGIC1) ||
1615             ((args->magic2 != REBOOT_MAGIC2) &&
1616             (args->magic2 != REBOOT_MAGIC2A) &&
1617             (args->magic2 != REBOOT_MAGIC2B)))
1618                 return EINVAL;
1619
1620         switch (args->cmd) {
1621         case REBOOT_CAD_ON:
1622         case REBOOT_CAD_OFF:
1623                 return (priv_check(curthread, PRIV_REBOOT));
1624                 /* NOTREACHED */
1625         case REBOOT_HALT:
1626                 bsd_args.opt = RB_HALT;
1627                 break;
1628         case REBOOT_RESTART:
1629         case REBOOT_RESTART2:
1630                 bsd_args.opt = 0;
1631                 break;
1632         case REBOOT_POWEROFF:
1633                 bsd_args.opt = RB_POWEROFF;
1634                 break;
1635         default:
1636                 return EINVAL;
1637                 /* NOTREACHED */
1638         }
1639
1640         bsd_args.sysmsg_result = 0;
1641
1642         error = sys_reboot(&bsd_args);
1643         args->sysmsg_result = bsd_args.sysmsg_result;
1644         return(error);
1645 }
1646
1647 /*
1648  * The FreeBSD native getpid(2), getgid(2) and getuid(2) also modify
1649  * p->p_retval[1] when COMPAT_43 or COMPAT_SUNOS is defined. This
1650  * globbers registers that are assumed to be preserved. The following
1651  * lightweight syscalls fixes this. See also linux_getgid16() and
1652  * linux_getuid16() in linux_uid16.c.
1653  *
1654  * linux_getpid() - MP SAFE
1655  * linux_getgid() - MP SAFE
1656  * linux_getuid() - MP SAFE
1657  */
1658
1659 /*
1660  * MPALMOSTSAFE
1661  */
1662 int
1663 sys_linux_getpid(struct linux_getpid_args *args)
1664 {
1665         struct linux_emuldata *em;
1666         struct proc *p = curproc;
1667
1668
1669         EMUL_LOCK();
1670         em = emuldata_get(p);
1671         if (em == NULL) /* this should never happen */
1672                 args->sysmsg_result = p->p_pid;
1673         else
1674                 args->sysmsg_result = em->s->group_pid;
1675         EMUL_UNLOCK();
1676
1677         return (0);
1678 }
1679
1680 /*
1681  * MPALMOSTSAFE
1682  */
1683 int
1684 sys_linux_getppid(struct linux_getppid_args *args)
1685 {
1686         struct linux_emuldata *em;
1687         struct proc *parent;
1688         struct proc *p;
1689         pid_t group_pid;
1690
1691         EMUL_LOCK();
1692         em = emuldata_get(curproc);
1693         KKASSERT(em != NULL);
1694         group_pid = em->s->group_pid;
1695         EMUL_UNLOCK();
1696
1697         p = pfind(group_pid);
1698         /* We are not allowed to fail */
1699         if (p == NULL)
1700                 goto out;
1701
1702         parent = p->p_pptr;
1703         if (parent->p_sysent == &elf_linux_sysvec) {
1704                 EMUL_LOCK();
1705                 em = emuldata_get(parent);
1706                 args->sysmsg_result = em->s->group_pid;
1707                 EMUL_UNLOCK();
1708         } else {
1709                 args->sysmsg_result = parent->p_pid;
1710         }
1711         PRELE(p);
1712
1713 out:
1714         return (0);
1715 }
1716
1717 /*
1718  * MPSAFE
1719  */
1720 int
1721 sys_linux_getgid(struct linux_getgid_args *args)
1722 {
1723         struct thread *td = curthread;
1724
1725         args->sysmsg_result = td->td_ucred->cr_rgid;
1726         return (0);
1727 }
1728
1729 /*
1730  * MPSAFE
1731  */
1732 int
1733 sys_linux_getuid(struct linux_getuid_args *args)
1734 {
1735         struct thread *td = curthread;
1736
1737         args->sysmsg_result = td->td_ucred->cr_ruid;
1738         return (0);
1739 }
1740
1741 /*
1742  * MPSAFE
1743  */
1744 int
1745 sys_linux_getsid(struct linux_getsid_args *args)
1746 {
1747         struct getsid_args bsd;
1748         int error;
1749
1750         bsd.sysmsg_result = 0;
1751         bsd.pid = args->pid;
1752         error = sys_getsid(&bsd);
1753         args->sysmsg_result = bsd.sysmsg_result;
1754         return(error);
1755 }
1756
1757 /*
1758  * MPSAFE
1759  */
1760 int
1761 linux_nosys(struct nosys_args *args)
1762 {
1763         /* XXX */
1764         return (ENOSYS);
1765 }
1766
1767 int
1768 sys_linux_mq_open(struct linux_mq_open_args *args)
1769 {
1770         struct mq_open_args moa;
1771         int error, oflag;
1772
1773         oflag = 0;
1774         if (args->oflag & LINUX_O_RDONLY)
1775                 oflag |= O_RDONLY;
1776         if (args->oflag & LINUX_O_WRONLY)
1777                 oflag |= O_WRONLY;
1778         if (args->oflag & LINUX_O_RDWR)
1779                 oflag |= O_RDWR;
1780
1781         if (args->oflag & LINUX_O_NONBLOCK)
1782                 oflag |= O_NONBLOCK;
1783         if (args->oflag & LINUX_O_CREAT)
1784                 oflag |= O_CREAT;
1785         if (args->oflag & LINUX_O_EXCL)
1786                 oflag |= O_EXCL;
1787
1788         moa.name = args->name;
1789         moa.oflag = oflag;
1790         moa.mode = args->mode;
1791         moa.attr = args->attr;
1792
1793         error = sys_mq_open(&moa);
1794
1795         return (error);
1796 }
1797
1798 int
1799 sys_linux_mq_getsetattr(struct linux_mq_getsetattr_args *args)
1800 {
1801         struct mq_getattr_args gaa;
1802         struct mq_setattr_args saa;
1803         int error;
1804
1805         gaa.mqdes = args->mqd;
1806         gaa.mqstat = args->oattr;
1807
1808         saa.mqdes = args->mqd;
1809         saa.mqstat = args->attr;
1810         saa.mqstat = args->oattr;
1811
1812         if (args->attr != NULL) {
1813                 error = sys_mq_setattr(&saa);
1814         } else {
1815                 error = sys_mq_getattr(&gaa);
1816         }
1817
1818         return error;
1819 }
1820
1821 /*
1822  * Get affinity of a process.
1823  */
1824 int
1825 sys_linux_sched_getaffinity(struct linux_sched_getaffinity_args *args)
1826 {
1827         cpumask_t mask;
1828         struct proc *p;
1829         struct lwp *lp;
1830         int error = 0;
1831
1832 #ifdef DEBUG
1833         if (ldebug(sched_getaffinity))
1834                 kprintf(ARGS(sched_getaffinity, "%d, %d, *"), args->pid,
1835                     args->len);
1836 #endif
1837         if (args->len < sizeof(cpumask_t))
1838                 return (EINVAL);
1839 #if 0
1840         if ((error = priv_check(curthread, PRIV_SCHED_CPUSET)) != 0)
1841                 return (EPERM);
1842 #endif
1843         /* Get the mplock to ensure that the proc is not running */
1844         get_mplock();
1845         if (args->pid == 0) {
1846                 p = curproc;
1847                 PHOLD(p);
1848         } else {
1849                 p = pfind(args->pid);
1850                 if (p == NULL) {
1851                         error = ESRCH;
1852                         goto done;
1853                 }
1854         }
1855
1856         lp = FIRST_LWP_IN_PROC(p);
1857         /*
1858          * XXX: if lwp_cpumask is ever changed to support more than
1859          *      32 processors, this needs to be changed to a bcopy.
1860          */
1861         mask = lp->lwp_cpumask;
1862         if ((error = copyout(&mask, args->user_mask_ptr, sizeof(cpumask_t))))
1863                 error = EFAULT;
1864 done:
1865         rel_mplock();
1866 #if 0
1867         if (error == 0)
1868                 args->sysmsg_iresult = sizeof(cpumask_t);
1869 #endif
1870         if (p)
1871                 PRELE(p);
1872         return (error);
1873 }
1874
1875 /*
1876  *  Set affinity of a process.
1877  */
1878 int
1879 sys_linux_sched_setaffinity(struct linux_sched_setaffinity_args *args)
1880 {
1881 #ifdef DEBUG
1882         if (ldebug(sched_setaffinity))
1883                 kprintf(ARGS(sched_setaffinity, "%d, %d, *"), args->pid,
1884                     args->len);
1885 #endif
1886         /*
1887          * From Linux man page:
1888          * sched_setaffinity() sets the CPU affinity mask of the process
1889          * whose ID is pid to the value specified by mask. If pid is zero, 
1890          * then the calling process is used. The argument cpusetsize is 
1891          * the length (in bytes) of the data pointed to by mask. Normally
1892          * this argument would be specified as sizeof(cpu_set_t).
1893          *
1894          * If the process specified by pid is not currently running on one
1895          * of the CPUs specified in mask, then that process is migrated to
1896          * one of the CPUs specified in mask.
1897          */
1898         /*
1899          * About our implementation: I don't think that it is too important
1900          * to have a working implementation, but if it was ever needed,
1901          * the best approach would be to implement the whole mechanism
1902          * properly in kern_usched.
1903          * The idea has to be to change the affinity mask AND migrate the
1904          * lwp to one of the new valid CPUs for the lwp, in case the current
1905          * CPU isn't anymore in the affinity mask passed in.
1906          * For now, we'll just signal success even if we didn't do anything.
1907          */
1908         return 0;
1909 }
1910
1911 int
1912 sys_linux_gettid(struct linux_gettid_args *args)
1913 {
1914         args->sysmsg_iresult = curproc->p_pid;
1915         return 0;
1916 }
1917
1918 int
1919 sys_linux_getcpu(struct linux_getcpu_args *args)
1920 {
1921         struct globaldata *gd;
1922         l_uint node = 0;
1923         int error;
1924
1925         gd = mycpu;
1926         error = copyout(&gd->gd_cpuid, args->pcpu, sizeof(gd->gd_cpuid));
1927         if (error)
1928                 return (error);
1929         /*
1930          * XXX: this should be the NUMA node, but since we don't implement it,
1931          *      just return 0 for it.
1932          */
1933         error = copyout(&node, args->pnode, sizeof(node));
1934         return (error);
1935 }