suser_* to priv_* conversion
[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 withough 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/signal2.h>
52 #include <sys/stat.h>
53 #include <sys/sysctl.h>
54 #include <sys/sysproto.h>
55 #include <sys/time.h>
56 #include <sys/unistd.h>
57 #include <sys/vmmeter.h>
58 #include <sys/vnode.h>
59 #include <sys/wait.h>
60 #include <sys/thread2.h>
61
62 #include <vm/vm.h>
63 #include <vm/pmap.h>
64 #include <vm/vm_kern.h>
65 #include <vm/vm_map.h>
66 #include <vm/vm_extern.h>
67 #include <vm/vm_object.h>
68 #include <vm/vm_zone.h>
69 #include <vm/swap_pager.h>
70
71 #include <machine/frame.h>
72 #include <machine/limits.h>
73 #include <machine/psl.h>
74 #include <machine/sysarch.h>
75 #ifdef __i386__
76 #include <machine/segments.h>
77 #endif
78
79 #include <sys/sched.h>
80
81 #include <emulation/linux/linux_sysproto.h>
82 #include <arch_linux/linux.h>
83 #include <arch_linux/linux_proto.h>
84 #include "linux_mib.h"
85 #include "linux_util.h"
86
87 #define BSD_TO_LINUX_SIGNAL(sig)        \
88         (((sig) <= LINUX_SIGTBLSZ) ? bsd_to_linux_signal[_SIG_IDX(sig)] : sig)
89
90 static unsigned int linux_to_bsd_resource[LINUX_RLIM_NLIMITS] = {
91         RLIMIT_CPU, RLIMIT_FSIZE, RLIMIT_DATA, RLIMIT_STACK,
92         RLIMIT_CORE, RLIMIT_RSS, RLIMIT_NPROC, RLIMIT_NOFILE,
93         RLIMIT_MEMLOCK, -1
94 };
95
96 struct l_sysinfo {
97         l_long          uptime;         /* Seconds since boot */
98         l_ulong         loads[3];       /* 1, 5, and 15 minute load averages */
99         l_ulong         totalram;       /* Total usable main memory size */
100         l_ulong         freeram;        /* Available memory size */
101         l_ulong         sharedram;      /* Amount of shared memory */
102         l_ulong         bufferram;      /* Memory used by buffers */
103         l_ulong         totalswap;      /* Total swap space size */
104         l_ulong         freeswap;       /* swap space still available */
105         l_ushort        procs;          /* Number of current processes */
106         char            _f[22];         /* Pads structure to 64 bytes */
107 };
108
109 int
110 sys_linux_sysinfo(struct linux_sysinfo_args *args)
111 {
112         struct l_sysinfo sysinfo;
113         vm_object_t object;
114         int i;
115         struct timespec ts;
116
117         /* Uptime is copied out of print_uptime() in kern_shutdown.c */
118         getnanouptime(&ts);
119         i = 0;
120         if (ts.tv_sec >= 86400) {
121                 ts.tv_sec %= 86400;
122                 i = 1;
123         }
124         if (i || ts.tv_sec >= 3600) {
125                 ts.tv_sec %= 3600;
126                 i = 1;
127         }
128         if (i || ts.tv_sec >= 60) {
129                 ts.tv_sec %= 60;
130                 i = 1;
131         }
132         sysinfo.uptime=ts.tv_sec;
133
134         /* Use the information from the mib to get our load averages */
135         for (i = 0; i < 3; i++)
136                 sysinfo.loads[i] = averunnable.ldavg[i];
137
138         sysinfo.totalram = Maxmem * PAGE_SIZE;
139         sysinfo.freeram = sysinfo.totalram - vmstats.v_wire_count * PAGE_SIZE;
140
141         sysinfo.sharedram = 0;
142         for (object = TAILQ_FIRST(&vm_object_list); object != NULL;
143              object = TAILQ_NEXT(object, object_list))
144                 if (object->shadow_count > 1)
145                         sysinfo.sharedram += object->resident_page_count;
146
147         sysinfo.sharedram *= PAGE_SIZE;
148         sysinfo.bufferram = 0;
149
150         if (swapblist == NULL) {
151                 sysinfo.totalswap= 0;
152                 sysinfo.freeswap = 0;
153         } else {
154                 sysinfo.totalswap = swapblist->bl_blocks * 1024;
155                 sysinfo.freeswap = swapblist->bl_root->u.bmu_avail * PAGE_SIZE;
156         }
157
158         sysinfo.procs = 20; /* Hack */
159
160         return copyout(&sysinfo, (caddr_t)args->info, sizeof(sysinfo));
161 }
162
163 int
164 sys_linux_alarm(struct linux_alarm_args *args)
165 {
166         struct thread *td = curthread;
167         struct proc *p = td->td_proc;
168         struct itimerval it, old_it;
169         struct timeval tv;
170
171         KKASSERT(p);
172
173 #ifdef DEBUG
174         if (ldebug(alarm))
175                 kprintf(ARGS(alarm, "%u"), args->secs);
176 #endif
177
178         if (args->secs > 100000000)
179                 return EINVAL;
180
181         it.it_value.tv_sec = (long)args->secs;
182         it.it_value.tv_usec = 0;
183         it.it_interval.tv_sec = 0;
184         it.it_interval.tv_usec = 0;
185         crit_enter();
186         old_it = p->p_realtimer;
187         getmicrouptime(&tv);
188         if (timevalisset(&old_it.it_value))
189                 callout_stop(&p->p_ithandle);
190         if (it.it_value.tv_sec != 0) {
191                 callout_reset(&p->p_ithandle, tvtohz_high(&it.it_value),
192                              realitexpire, p);
193                 timevaladd(&it.it_value, &tv);
194         }
195         p->p_realtimer = it;
196         crit_exit();
197         if (timevalcmp(&old_it.it_value, &tv, >)) {
198                 timevalsub(&old_it.it_value, &tv);
199                 if (old_it.it_value.tv_usec != 0)
200                         old_it.it_value.tv_sec++;
201                 args->sysmsg_result = old_it.it_value.tv_sec;
202         }
203         return 0;
204 }
205
206 int
207 sys_linux_brk(struct linux_brk_args *args)
208 {
209         struct thread *td = curthread;
210         struct proc *p = td->td_proc;
211         struct vmspace *vm;
212         vm_offset_t new, old;
213         struct obreak_args bsd_args;
214
215         KKASSERT(p);
216         vm = p->p_vmspace;
217 #ifdef DEBUG
218         if (ldebug(brk))
219                 kprintf(ARGS(brk, "%p"), (void *)args->dsend);
220 #endif
221         old = (vm_offset_t)vm->vm_daddr + ctob(vm->vm_dsize);
222         new = (vm_offset_t)args->dsend;
223         bsd_args.sysmsg_result = 0;
224         bsd_args.nsize = (char *) new;
225         bsd_args.sysmsg_result = 0;
226         if (((caddr_t)new > vm->vm_daddr) && !sys_obreak(&bsd_args))
227                 args->sysmsg_result = (long)new;
228         else
229                 args->sysmsg_result = (long)old;
230
231         return 0;
232 }
233
234 int
235 sys_linux_uselib(struct linux_uselib_args *args)
236 {
237         struct thread *td = curthread;
238         struct proc *p;
239         struct nlookupdata nd;
240         struct vnode *vp;
241         struct exec *a_out;
242         struct vattr attr;
243         vm_offset_t vmaddr;
244         unsigned long file_offset;
245         vm_offset_t buffer;
246         unsigned long bss_size;
247         int error;
248         int locked;
249         char *path;
250
251         KKASSERT(td->td_proc);
252         p = td->td_proc;
253
254         error = linux_copyin_path(args->library, &path, LINUX_PATH_EXISTS);
255         if (error)
256                 return (error);
257 #ifdef DEBUG
258         if (ldebug(uselib))
259                 kprintf(ARGS(uselib, "%s"), path);
260 #endif
261
262         a_out = NULL;
263         locked = 0;
264         vp = NULL;
265
266         error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW);
267         if (error == 0)
268                 error = nlookup(&nd);
269         if (error == 0)
270                 error = cache_vget(&nd.nl_nch, nd.nl_cred, LK_EXCLUSIVE, &vp);
271         if (error)
272                 goto cleanup;
273         /*
274          * From here on down, we have a locked vnode that must be unlocked.
275          */
276         locked = 1;
277
278         /* Writable? */
279         if (vp->v_writecount) {
280                 error = ETXTBSY;
281                 goto cleanup;
282         }
283
284         /* Executable? */
285         error = VOP_GETATTR(vp, &attr);
286         if (error)
287                 goto cleanup;
288
289         if ((vp->v_mount->mnt_flag & MNT_NOEXEC) ||
290             ((attr.va_mode & 0111) == 0) || (attr.va_type != VREG)) {
291                 error = ENOEXEC;
292                 goto cleanup;
293         }
294
295         /* Sensible size? */
296         if (attr.va_size == 0) {
297                 error = ENOEXEC;
298                 goto cleanup;
299         }
300
301         /* Can we access it? */
302         error = VOP_ACCESS(vp, VEXEC, p->p_ucred);
303         if (error)
304                 goto cleanup;
305
306         error = VOP_OPEN(vp, FREAD, p->p_ucred, NULL);
307         if (error)
308                 goto cleanup;
309
310         /*
311          * Lock no longer needed
312          */
313         vn_unlock(vp);
314         locked = 0;
315
316         /* Pull in executable header into kernel_map */
317         error = vm_mmap(&kernel_map, (vm_offset_t *)&a_out, PAGE_SIZE,
318             VM_PROT_READ, VM_PROT_READ, 0, (caddr_t)vp, 0);
319         if (error)
320                 goto cleanup;
321
322         /* Is it a Linux binary ? */
323         if (((a_out->a_magic >> 16) & 0xff) != 0x64) {
324                 error = ENOEXEC;
325                 goto cleanup;
326         }
327
328         /*
329          * While we are here, we should REALLY do some more checks
330          */
331
332         /* Set file/virtual offset based on a.out variant. */
333         switch ((int)(a_out->a_magic & 0xffff)) {
334         case 0413:      /* ZMAGIC */
335                 file_offset = 1024;
336                 break;
337         case 0314:      /* QMAGIC */
338                 file_offset = 0;
339                 break;
340         default:
341                 error = ENOEXEC;
342                 goto cleanup;
343         }
344
345         bss_size = round_page(a_out->a_bss);
346
347         /* Check various fields in header for validity/bounds. */
348         if (a_out->a_text & PAGE_MASK || a_out->a_data & PAGE_MASK) {
349                 error = ENOEXEC;
350                 goto cleanup;
351         }
352
353         /* text + data can't exceed file size */
354         if (a_out->a_data + a_out->a_text > attr.va_size) {
355                 error = EFAULT;
356                 goto cleanup;
357         }
358
359         /*
360          * text/data/bss must not exceed limits
361          * XXX - this is not complete. it should check current usage PLUS
362          * the resources needed by this library.
363          */
364         if (a_out->a_text > maxtsiz ||
365             a_out->a_data + bss_size > p->p_rlimit[RLIMIT_DATA].rlim_cur) {
366                 error = ENOMEM;
367                 goto cleanup;
368         }
369
370         /* prevent more writers */
371         vp->v_flag |= VTEXT;
372
373         /*
374          * Check if file_offset page aligned. Currently we cannot handle
375          * misalinged file offsets, and so we read in the entire image
376          * (what a waste).
377          */
378         if (file_offset & PAGE_MASK) {
379 #ifdef DEBUG
380                 kprintf("uselib: Non page aligned binary %lu\n", file_offset);
381 #endif
382                 /* Map text+data read/write/execute */
383
384                 /* a_entry is the load address and is page aligned */
385                 vmaddr = trunc_page(a_out->a_entry);
386
387                 /* get anon user mapping, read+write+execute */
388                 error = vm_map_find(&p->p_vmspace->vm_map, NULL, 0,
389                                     &vmaddr, a_out->a_text + a_out->a_data,
390                                     FALSE,
391                                     VM_MAPTYPE_NORMAL,
392                                     VM_PROT_ALL, VM_PROT_ALL,
393                                     0);
394                 if (error)
395                         goto cleanup;
396
397                 /* map file into kernel_map */
398                 error = vm_mmap(&kernel_map, &buffer,
399                     round_page(a_out->a_text + a_out->a_data + file_offset),
400                     VM_PROT_READ, VM_PROT_READ, 0, (caddr_t)vp,
401                     trunc_page(file_offset));
402                 if (error)
403                         goto cleanup;
404
405                 /* copy from kernel VM space to user space */
406                 error = copyout((caddr_t)(uintptr_t)(buffer + file_offset),
407                     (caddr_t)vmaddr, a_out->a_text + a_out->a_data);
408
409                 /* release temporary kernel space */
410                 vm_map_remove(&kernel_map, buffer, buffer +
411                     round_page(a_out->a_text + a_out->a_data + file_offset));
412
413                 if (error)
414                         goto cleanup;
415         } else {
416 #ifdef DEBUG
417                 kprintf("uselib: Page aligned binary %lu\n", file_offset);
418 #endif
419                 /*
420                  * for QMAGIC, a_entry is 20 bytes beyond the load address
421                  * to skip the executable header
422                  */
423                 vmaddr = trunc_page(a_out->a_entry);
424
425                 /*
426                  * Map it all into the process's space as a single
427                  * copy-on-write "data" segment.
428                  */
429                 error = vm_mmap(&p->p_vmspace->vm_map, &vmaddr,
430                     a_out->a_text + a_out->a_data, VM_PROT_ALL, VM_PROT_ALL,
431                     MAP_PRIVATE | MAP_FIXED, (caddr_t)vp, file_offset);
432                 if (error)
433                         goto cleanup;
434         }
435 #ifdef DEBUG
436         kprintf("mem=%08lx = %08lx %08lx\n", (long)vmaddr, ((long*)vmaddr)[0],
437             ((long*)vmaddr)[1]);
438 #endif
439         if (bss_size != 0) {
440                 /* Calculate BSS start address */
441                 vmaddr = trunc_page(a_out->a_entry) + a_out->a_text +
442                     a_out->a_data;
443
444                 /* allocate some 'anon' space */
445                 error = vm_map_find(&p->p_vmspace->vm_map, NULL, 0,
446                                     &vmaddr, bss_size,
447                                     FALSE,
448                                     VM_MAPTYPE_NORMAL,
449                                     VM_PROT_ALL, VM_PROT_ALL,
450                                     0);
451                 if (error)
452                         goto cleanup;
453         }
454
455 cleanup:
456         /* Unlock/release vnode */
457         if (vp) {
458                 if (locked)
459                         vn_unlock(vp);
460                 vrele(vp);
461         }
462         /* Release the kernel mapping. */
463         if (a_out) {
464                 vm_map_remove(&kernel_map, (vm_offset_t)a_out,
465                     (vm_offset_t)a_out + PAGE_SIZE);
466         }
467         nlookup_done(&nd);
468         linux_free_path(&path);
469         return (error);
470 }
471
472 int
473 sys_linux_select(struct linux_select_args *args)
474 {
475         struct select_args bsa;
476         struct timeval tv0, tv1, utv, *tvp;
477         caddr_t sg;
478         int error;
479
480 #ifdef DEBUG
481         if (ldebug(select))
482                 kprintf(ARGS(select, "%d, %p, %p, %p, %p"), args->nfds,
483                     (void *)args->readfds, (void *)args->writefds,
484                     (void *)args->exceptfds, (void *)args->timeout);
485 #endif
486
487         error = 0;
488         bsa.sysmsg_result = 0;
489         bsa.nd = args->nfds;
490         bsa.in = args->readfds;
491         bsa.ou = args->writefds;
492         bsa.ex = args->exceptfds;
493         bsa.tv = (struct timeval *)args->timeout;
494
495         /*
496          * Store current time for computation of the amount of
497          * time left.
498          */
499         if (args->timeout) {
500                 if ((error = copyin((caddr_t)args->timeout, &utv,
501                     sizeof(utv))))
502                         goto select_out;
503 #ifdef DEBUG
504                 if (ldebug(select))
505                         kprintf(LMSG("incoming timeout (%ld/%ld)"),
506                             utv.tv_sec, utv.tv_usec);
507 #endif
508
509                 if (itimerfix(&utv)) {
510                         /*
511                          * The timeval was invalid.  Convert it to something
512                          * valid that will act as it does under Linux.
513                          */
514                         sg = stackgap_init();
515                         tvp = stackgap_alloc(&sg, sizeof(utv));
516                         utv.tv_sec += utv.tv_usec / 1000000;
517                         utv.tv_usec %= 1000000;
518                         if (utv.tv_usec < 0) {
519                                 utv.tv_sec -= 1;
520                                 utv.tv_usec += 1000000;
521                         }
522                         if (utv.tv_sec < 0)
523                                 timevalclear(&utv);
524                         if ((error = copyout(&utv, tvp, sizeof(utv))))
525                                 goto select_out;
526                         bsa.tv = tvp;
527                 }
528                 microtime(&tv0);
529         }
530
531         error = sys_select(&bsa);
532         args->sysmsg_result = bsa.sysmsg_result;
533 #ifdef DEBUG
534         if (ldebug(select))
535                 kprintf(LMSG("real select returns %d"), error);
536 #endif
537         if (error) {
538                 /*
539                  * See fs/select.c in the Linux kernel.  Without this,
540                  * Maelstrom doesn't work.
541                  */
542                 if (error == ERESTART)
543                         error = EINTR;
544                 goto select_out;
545         }
546
547         if (args->timeout) {
548                 if (args->sysmsg_result) {
549                         /*
550                          * Compute how much time was left of the timeout,
551                          * by subtracting the current time and the time
552                          * before we started the call, and subtracting
553                          * that result from the user-supplied value.
554                          */
555                         microtime(&tv1);
556                         timevalsub(&tv1, &tv0);
557                         timevalsub(&utv, &tv1);
558                         if (utv.tv_sec < 0)
559                                 timevalclear(&utv);
560                 } else
561                         timevalclear(&utv);
562 #ifdef DEBUG
563                 if (ldebug(select))
564                         kprintf(LMSG("outgoing timeout (%ld/%ld)"),
565                             utv.tv_sec, utv.tv_usec);
566 #endif
567                 if ((error = copyout(&utv, (caddr_t)args->timeout,
568                     sizeof(utv))))
569                         goto select_out;
570         }
571
572 select_out:
573 #ifdef DEBUG
574         if (ldebug(select))
575                 kprintf(LMSG("select_out -> %d"), error);
576 #endif
577         return error;
578 }
579
580 int     
581 sys_linux_mremap(struct linux_mremap_args *args)
582 {
583         struct munmap_args bsd_args; 
584         int error = 0;
585
586 #ifdef DEBUG
587         if (ldebug(mremap))
588                 kprintf(ARGS(mremap, "%p, %08lx, %08lx, %08lx"),
589                     (void *)args->addr, 
590                     (unsigned long)args->old_len, 
591                     (unsigned long)args->new_len,
592                     (unsigned long)args->flags);
593 #endif
594         args->new_len = round_page(args->new_len);
595         args->old_len = round_page(args->old_len);
596
597         if (args->new_len > args->old_len) {
598                 args->sysmsg_result = 0;
599                 return ENOMEM;
600         }
601
602         if (args->new_len < args->old_len) {
603                 bsd_args.sysmsg_result = 0;
604                 bsd_args.addr = (caddr_t)(args->addr + args->new_len);
605                 bsd_args.len = args->old_len - args->new_len;
606                 error = sys_munmap(&bsd_args);
607         }
608
609         args->sysmsg_resultp = error ? NULL : (void *)args->addr;
610         return error;
611 }
612
613 #define LINUX_MS_ASYNC          0x0001
614 #define LINUX_MS_INVALIDATE     0x0002
615 #define LINUX_MS_SYNC           0x0004
616
617 int
618 sys_linux_msync(struct linux_msync_args *args)
619 {
620         struct msync_args bsd_args;
621         int error;
622
623         bsd_args.addr = (caddr_t)args->addr;
624         bsd_args.len = args->len;
625         bsd_args.flags = args->fl & ~LINUX_MS_SYNC;
626         bsd_args.sysmsg_result = 0;
627
628         error = sys_msync(&bsd_args);
629         args->sysmsg_result = bsd_args.sysmsg_result;
630         return(error);
631 }
632
633 int
634 sys_linux_time(struct linux_time_args *args)
635 {
636         struct timeval tv;
637         l_time_t tm;
638         int error;
639
640 #ifdef DEBUG
641         if (ldebug(time))
642                 kprintf(ARGS(time, "*"));
643 #endif
644
645         microtime(&tv);
646         tm = tv.tv_sec;
647         if (args->tm && (error = copyout(&tm, (caddr_t)args->tm, sizeof(tm))))
648                 return error;
649         args->sysmsg_lresult = tm;
650         return 0;
651 }
652
653 struct l_times_argv {
654         l_long          tms_utime;
655         l_long          tms_stime;
656         l_long          tms_cutime;
657         l_long          tms_cstime;
658 };
659
660 #define CLK_TCK 100     /* Linux uses 100 */
661
662 #define CONVTCK(r)      (r.tv_sec * CLK_TCK + r.tv_usec / (1000000 / CLK_TCK))
663
664 int
665 sys_linux_times(struct linux_times_args *args)
666 {
667         struct thread *td = curthread;
668         struct proc *p = td->td_proc;
669         struct timeval tv;
670         struct l_times_argv tms;
671         struct rusage ru;
672         int error;
673
674         KKASSERT(p);
675 #ifdef DEBUG
676         if (ldebug(times))
677                 kprintf(ARGS(times, "*"));
678 #endif
679
680         calcru_proc(p, &ru);
681
682         tms.tms_utime = CONVTCK(ru.ru_utime);
683         tms.tms_stime = CONVTCK(ru.ru_stime);
684
685         tms.tms_cutime = CONVTCK(p->p_cru.ru_utime);
686         tms.tms_cstime = CONVTCK(p->p_cru.ru_stime);
687
688         if ((error = copyout(&tms, (caddr_t)args->buf, sizeof(tms))))
689                 return error;
690
691         microuptime(&tv);
692         args->sysmsg_result = (int)CONVTCK(tv);
693         return 0;
694 }
695
696 int
697 sys_linux_newuname(struct linux_newuname_args *args)
698 {
699         struct thread *td = curthread;
700         struct l_new_utsname utsname;
701         char *osrelease, *osname;
702
703 #ifdef DEBUG
704         if (ldebug(newuname))
705                 kprintf(ARGS(newuname, "*"));
706 #endif
707
708         osname = linux_get_osname(td);
709         osrelease = linux_get_osrelease(td);
710
711         bzero(&utsname, sizeof(utsname));
712         strncpy(utsname.sysname, osname, LINUX_MAX_UTSNAME-1);
713         strncpy(utsname.nodename, hostname, LINUX_MAX_UTSNAME-1);
714         strncpy(utsname.release, osrelease, LINUX_MAX_UTSNAME-1);
715         strncpy(utsname.version, version, LINUX_MAX_UTSNAME-1);
716         strncpy(utsname.machine, machine, LINUX_MAX_UTSNAME-1);
717         strncpy(utsname.domainname, domainname, LINUX_MAX_UTSNAME-1);
718
719         return (copyout(&utsname, (caddr_t)args->buf, sizeof(utsname)));
720 }
721
722 #if defined(__i386__)
723 struct l_utimbuf {
724         l_time_t l_actime;
725         l_time_t l_modtime;
726 };
727
728 int
729 sys_linux_utime(struct linux_utime_args *args)
730 {
731         struct timeval tv[2];
732         struct l_utimbuf lut;
733         struct nlookupdata nd;
734         char *path;
735         int error;
736
737         error = linux_copyin_path(args->fname, &path, LINUX_PATH_EXISTS);
738         if (error)
739                 return (error);
740 #ifdef DEBUG
741         if (ldebug(utime))
742                 kprintf(ARGS(utime, "%s, *"), path);
743 #endif
744
745         if (args->times) {
746                 error = copyin(args->times, &lut, sizeof(lut));
747                 if (error)
748                         goto cleanup;
749                 tv[0].tv_sec = lut.l_actime;
750                 tv[0].tv_usec = 0;
751                 tv[1].tv_sec = lut.l_modtime;
752                 tv[1].tv_usec = 0;
753         }
754         error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW);
755         if (error == 0)
756                 error = kern_utimes(&nd, args->times ? tv : NULL);
757         nlookup_done(&nd);
758 cleanup:
759         linux_free_path(&path);
760         return (error);
761 }
762 #endif /* __i386__ */
763
764 #define __WCLONE 0x80000000
765
766 int
767 sys_linux_waitpid(struct linux_waitpid_args *args)
768 {
769         int error, options, status;
770
771 #ifdef DEBUG
772         if (ldebug(waitpid))
773                 kprintf(ARGS(waitpid, "%d, %p, %d"),
774                     args->pid, (void *)args->status, args->options);
775 #endif
776         options = args->options & (WNOHANG | WUNTRACED);
777         /* WLINUXCLONE should be equal to __WCLONE, but we make sure */
778         if (args->options & __WCLONE)
779                 options |= WLINUXCLONE;
780
781         error = kern_wait(args->pid, args->status ? &status : NULL, options,
782             NULL, &args->sysmsg_result);
783
784         if (error == 0 && args->status) {
785                 status &= 0xffff;
786                 if (WIFSIGNALED(status))
787                         status = (status & 0xffffff80) |
788                             BSD_TO_LINUX_SIGNAL(WTERMSIG(status));
789                 else if (WIFSTOPPED(status))
790                         status = (status & 0xffff00ff) |
791                             (BSD_TO_LINUX_SIGNAL(WSTOPSIG(status)) << 8);
792                 error = copyout(&status, args->status, sizeof(status));
793         }
794
795         return (error);
796 }
797
798 int
799 sys_linux_wait4(struct linux_wait4_args *args)
800 {
801         struct thread *td = curthread;
802         struct lwp *lp = td->td_lwp;
803         struct rusage rusage;
804         int error, options, status;
805
806         KKASSERT(lp);
807
808 #ifdef DEBUG
809         if (ldebug(wait4))
810                 kprintf(ARGS(wait4, "%d, %p, %d, %p"),
811                     args->pid, (void *)args->status, args->options,
812                     (void *)args->rusage);
813 #endif
814         options = args->options & (WNOHANG | WUNTRACED);
815         /* WLINUXCLONE should be equal to __WCLONE, but we make sure */
816         if (args->options & __WCLONE)
817                 options |= WLINUXCLONE;
818
819         error = kern_wait(args->pid, args->status ? &status : NULL, options,
820             args->rusage ? &rusage : NULL, &args->sysmsg_result);
821
822         if (error == 0)
823                 lwp_delsig(lp, SIGCHLD);
824
825         if (error == 0 && args->status) {
826                 status &= 0xffff;
827                 if (WIFSIGNALED(status))
828                         status = (status & 0xffffff80) |
829                             BSD_TO_LINUX_SIGNAL(WTERMSIG(status));
830                 else if (WIFSTOPPED(status))
831                         status = (status & 0xffff00ff) |
832                             (BSD_TO_LINUX_SIGNAL(WSTOPSIG(status)) << 8);
833                 error = copyout(&status, args->status, sizeof(status));
834         }
835         if (error == 0 && args->rusage)
836                 error = copyout(&rusage, args->rusage, sizeof(rusage));
837
838         return (error);
839 }
840
841 int
842 sys_linux_mknod(struct linux_mknod_args *args)
843 {
844         struct nlookupdata nd;
845         char *path;
846         int error;
847
848         error = linux_copyin_path(args->path, &path, LINUX_PATH_CREATE);
849         if (error)
850                 return (error);
851 #ifdef DEBUG
852         if (ldebug(mknod))
853                 kprintf(ARGS(mknod, "%s, %d, %d"),
854                     path, args->mode, args->dev);
855 #endif
856         error = nlookup_init(&nd, path, UIO_SYSSPACE, 0);
857         if (error == 0) {
858                 if (args->mode & S_IFIFO) {
859                         error = kern_mkfifo(&nd, args->mode);
860                 } else {
861                         error = kern_mknod(&nd, args->mode,
862                                            umajor(args->dev),
863                                            uminor(args->dev));
864                 }
865         }
866         nlookup_done(&nd);
867
868         linux_free_path(&path);
869         return(error);
870 }
871
872 /*
873  * UGH! This is just about the dumbest idea I've ever heard!!
874  */
875 int
876 sys_linux_personality(struct linux_personality_args *args)
877 {
878 #ifdef DEBUG
879         if (ldebug(personality))
880                 kprintf(ARGS(personality, "%d"), args->per);
881 #endif
882         if (args->per != 0)
883                 return EINVAL;
884
885         /* Yes Jim, it's still a Linux... */
886         args->sysmsg_result = 0;
887         return 0;
888 }
889
890 /*
891  * Wrappers for get/setitimer for debugging..
892  */
893 int
894 sys_linux_setitimer(struct linux_setitimer_args *args)
895 {
896         struct setitimer_args bsa;
897         struct itimerval foo;
898         int error;
899
900 #ifdef DEBUG
901         if (ldebug(setitimer))
902                 kprintf(ARGS(setitimer, "%p, %p"),
903                     (void *)args->itv, (void *)args->oitv);
904 #endif
905         bsa.which = args->which;
906         bsa.itv = (struct itimerval *)args->itv;
907         bsa.oitv = (struct itimerval *)args->oitv;
908         bsa.sysmsg_result = 0;
909         if (args->itv) {
910             if ((error = copyin((caddr_t)args->itv, &foo, sizeof(foo))))
911                 return error;
912 #ifdef DEBUG
913             if (ldebug(setitimer)) {
914                 kprintf("setitimer: value: sec: %ld, usec: %ld\n",
915                     foo.it_value.tv_sec, foo.it_value.tv_usec);
916                 kprintf("setitimer: interval: sec: %ld, usec: %ld\n",
917                     foo.it_interval.tv_sec, foo.it_interval.tv_usec);
918             }
919 #endif
920         }
921         error = sys_setitimer(&bsa);
922         args->sysmsg_result = bsa.sysmsg_result;
923         return(error);
924 }
925
926 int
927 sys_linux_getitimer(struct linux_getitimer_args *args)
928 {
929         struct getitimer_args bsa;
930         int error;
931 #ifdef DEBUG
932         if (ldebug(getitimer))
933                 kprintf(ARGS(getitimer, "%p"), (void *)args->itv);
934 #endif
935         bsa.which = args->which;
936         bsa.itv = (struct itimerval *)args->itv;
937         bsa.sysmsg_result = 0;
938         error = sys_getitimer(&bsa);
939         args->sysmsg_result = bsa.sysmsg_result;
940         return(error);
941 }
942
943 int
944 sys_linux_nice(struct linux_nice_args *args)
945 {
946         struct setpriority_args bsd_args;
947         int error;
948
949         bsd_args.which = PRIO_PROCESS;
950         bsd_args.who = 0;       /* current process */
951         bsd_args.prio = args->inc;
952         bsd_args.sysmsg_result = 0;
953         error = sys_setpriority(&bsd_args);
954         args->sysmsg_result = bsd_args.sysmsg_result;
955         return(error);
956 }
957
958 int
959 sys_linux_setgroups(struct linux_setgroups_args *args)
960 {
961         struct thread *td = curthread;
962         struct proc *p = td->td_proc;
963         struct ucred *newcred, *oldcred;
964         l_gid_t linux_gidset[NGROUPS];
965         gid_t *bsd_gidset;
966         int ngrp, error;
967
968         KKASSERT(p);
969
970         ngrp = args->gidsetsize;
971         oldcred = p->p_ucred;
972
973         /*
974          * cr_groups[0] holds egid. Setting the whole set from
975          * the supplied set will cause egid to be changed too.
976          * Keep cr_groups[0] unchanged to prevent that.
977          */
978
979         if ((error = priv_check_cred(oldcred, PRIV_ROOT, PRISON_ROOT)) != 0)
980                 return (error);
981
982         if (ngrp >= NGROUPS)
983                 return (EINVAL);
984
985         newcred = crdup(oldcred);
986         if (ngrp > 0) {
987                 error = copyin((caddr_t)args->grouplist, linux_gidset,
988                                ngrp * sizeof(l_gid_t));
989                 if (error)
990                         return (error);
991
992                 newcred->cr_ngroups = ngrp + 1;
993
994                 bsd_gidset = newcred->cr_groups;
995                 ngrp--;
996                 while (ngrp >= 0) {
997                         bsd_gidset[ngrp + 1] = linux_gidset[ngrp];
998                         ngrp--;
999                 }
1000         } else {
1001                 newcred->cr_ngroups = 1;
1002         }
1003
1004         setsugid();
1005         p->p_ucred = newcred;
1006         crfree(oldcred);
1007         return (0);
1008 }
1009
1010 int
1011 sys_linux_getgroups(struct linux_getgroups_args *args)
1012 {
1013         struct thread *td = curthread;
1014         struct proc *p = td->td_proc;
1015         struct ucred *cred;
1016         l_gid_t linux_gidset[NGROUPS];
1017         gid_t *bsd_gidset;
1018         int bsd_gidsetsz, ngrp, error;
1019
1020         KKASSERT(p);
1021
1022         cred = p->p_ucred;
1023         bsd_gidset = cred->cr_groups;
1024         bsd_gidsetsz = cred->cr_ngroups - 1;
1025
1026         /*
1027          * cr_groups[0] holds egid. Returning the whole set
1028          * here will cause a duplicate. Exclude cr_groups[0]
1029          * to prevent that.
1030          */
1031
1032         if ((ngrp = args->gidsetsize) == 0) {
1033                 args->sysmsg_result = bsd_gidsetsz;
1034                 return (0);
1035         }
1036
1037         if (ngrp < bsd_gidsetsz)
1038                 return (EINVAL);
1039
1040         ngrp = 0;
1041         while (ngrp < bsd_gidsetsz) {
1042                 linux_gidset[ngrp] = bsd_gidset[ngrp + 1];
1043                 ngrp++;
1044         }
1045
1046         if ((error = copyout(linux_gidset, (caddr_t)args->grouplist,
1047             ngrp * sizeof(l_gid_t))))
1048                 return (error);
1049
1050         args->sysmsg_result = ngrp;
1051         return (0);
1052 }
1053
1054 int
1055 sys_linux_setrlimit(struct linux_setrlimit_args *args)
1056 {
1057         struct l_rlimit linux_rlim;
1058         struct rlimit rlim;
1059         u_int which;
1060         int error;
1061
1062 #ifdef DEBUG
1063         if (ldebug(setrlimit))
1064                 kprintf(ARGS(setrlimit, "%d, %p"),
1065                     args->resource, (void *)args->rlim);
1066 #endif
1067         if (args->resource >= LINUX_RLIM_NLIMITS)
1068                 return (EINVAL);
1069         which = linux_to_bsd_resource[args->resource];
1070         if (which == -1)
1071                 return (EINVAL);
1072
1073         error = copyin(args->rlim, &linux_rlim, sizeof(linux_rlim));
1074         if (error)
1075                 return (error);
1076         rlim.rlim_cur = (rlim_t)linux_rlim.rlim_cur;
1077         rlim.rlim_max = (rlim_t)linux_rlim.rlim_max;
1078
1079         error = kern_setrlimit(which, &rlim);
1080
1081         return(error);
1082 }
1083
1084 int
1085 sys_linux_old_getrlimit(struct linux_old_getrlimit_args *args)
1086 {
1087         struct l_rlimit linux_rlim;
1088         struct rlimit rlim;
1089         u_int which;
1090         int error;
1091
1092 #ifdef DEBUG
1093         if (ldebug(old_getrlimit))
1094                 kprintf(ARGS(old_getrlimit, "%d, %p"),
1095                     args->resource, (void *)args->rlim);
1096 #endif
1097         if (args->resource >= LINUX_RLIM_NLIMITS)
1098                 return (EINVAL);
1099         which = linux_to_bsd_resource[args->resource];
1100         if (which == -1)
1101                 return (EINVAL);
1102
1103         error = kern_getrlimit(which, &rlim);
1104
1105         if (error == 0) {
1106                 linux_rlim.rlim_cur = (l_ulong)rlim.rlim_cur;
1107                 if (linux_rlim.rlim_cur == ULONG_MAX)
1108                         linux_rlim.rlim_cur = LONG_MAX;
1109                 linux_rlim.rlim_max = (l_ulong)rlim.rlim_max;
1110                 if (linux_rlim.rlim_max == ULONG_MAX)
1111                         linux_rlim.rlim_max = LONG_MAX;
1112                 error = copyout(&linux_rlim, args->rlim, sizeof(linux_rlim));
1113         }
1114         return (error);
1115 }
1116
1117 int
1118 sys_linux_getrlimit(struct linux_getrlimit_args *args)
1119 {
1120         struct l_rlimit linux_rlim;
1121         struct rlimit rlim;
1122         u_int which;
1123         int error;
1124
1125 #ifdef DEBUG
1126         if (ldebug(getrlimit))
1127                 kprintf(ARGS(getrlimit, "%d, %p"),
1128                     args->resource, (void *)args->rlim);
1129 #endif
1130         if (args->resource >= LINUX_RLIM_NLIMITS)
1131                 return (EINVAL);
1132         which = linux_to_bsd_resource[args->resource];
1133         if (which == -1)
1134                 return (EINVAL);
1135
1136         error = kern_getrlimit(which, &rlim);
1137
1138         if (error == 0) {
1139                 linux_rlim.rlim_cur = (l_ulong)rlim.rlim_cur;
1140                 linux_rlim.rlim_max = (l_ulong)rlim.rlim_max;
1141                 error = copyout(&linux_rlim, args->rlim, sizeof(linux_rlim));
1142         }
1143         return (error);
1144 }
1145
1146 int
1147 sys_linux_sched_setscheduler(struct linux_sched_setscheduler_args *args)
1148 {
1149         struct sched_setscheduler_args bsd;
1150         int error;
1151
1152 #ifdef DEBUG
1153         if (ldebug(sched_setscheduler))
1154                 kprintf(ARGS(sched_setscheduler, "%d, %d, %p"),
1155                     args->pid, args->policy, (const void *)args->param);
1156 #endif
1157
1158         switch (args->policy) {
1159         case LINUX_SCHED_OTHER:
1160                 bsd.policy = SCHED_OTHER;
1161                 break;
1162         case LINUX_SCHED_FIFO:
1163                 bsd.policy = SCHED_FIFO;
1164                 break;
1165         case LINUX_SCHED_RR:
1166                 bsd.policy = SCHED_RR;
1167                 break;
1168         default:
1169                 return EINVAL;
1170         }
1171
1172         bsd.pid = args->pid;
1173         bsd.param = (struct sched_param *)args->param;
1174         bsd.sysmsg_result = 0;
1175
1176         error = sys_sched_setscheduler(&bsd);
1177         args->sysmsg_result = bsd.sysmsg_result;
1178         return(error);
1179 }
1180
1181 int
1182 sys_linux_sched_getscheduler(struct linux_sched_getscheduler_args *args)
1183 {
1184         struct sched_getscheduler_args bsd;
1185         int error;
1186
1187 #ifdef DEBUG
1188         if (ldebug(sched_getscheduler))
1189                 kprintf(ARGS(sched_getscheduler, "%d"), args->pid);
1190 #endif
1191
1192         bsd.sysmsg_result = 0;
1193         bsd.pid = args->pid;
1194         error = sys_sched_getscheduler(&bsd);
1195         args->sysmsg_result = bsd.sysmsg_result;
1196
1197         switch (args->sysmsg_result) {
1198         case SCHED_OTHER:
1199                 args->sysmsg_result = LINUX_SCHED_OTHER;
1200                 break;
1201         case SCHED_FIFO:
1202                 args->sysmsg_result = LINUX_SCHED_FIFO;
1203                 break;
1204         case SCHED_RR:
1205                 args->sysmsg_result = LINUX_SCHED_RR;
1206                 break;
1207         }
1208         return error;
1209 }
1210
1211 int
1212 sys_linux_sched_get_priority_max(struct linux_sched_get_priority_max_args *args)
1213 {
1214         struct sched_get_priority_max_args bsd;
1215         int error;
1216
1217 #ifdef DEBUG
1218         if (ldebug(sched_get_priority_max))
1219                 kprintf(ARGS(sched_get_priority_max, "%d"), args->policy);
1220 #endif
1221
1222         switch (args->policy) {
1223         case LINUX_SCHED_OTHER:
1224                 bsd.policy = SCHED_OTHER;
1225                 break;
1226         case LINUX_SCHED_FIFO:
1227                 bsd.policy = SCHED_FIFO;
1228                 break;
1229         case LINUX_SCHED_RR:
1230                 bsd.policy = SCHED_RR;
1231                 break;
1232         default:
1233                 return EINVAL;
1234         }
1235         bsd.sysmsg_result = 0;
1236
1237         error = sys_sched_get_priority_max(&bsd);
1238         args->sysmsg_result = bsd.sysmsg_result;
1239         return(error);
1240 }
1241
1242 int
1243 sys_linux_sched_get_priority_min(struct linux_sched_get_priority_min_args *args)
1244 {
1245         struct sched_get_priority_min_args bsd;
1246         int error;
1247
1248 #ifdef DEBUG
1249         if (ldebug(sched_get_priority_min))
1250                 kprintf(ARGS(sched_get_priority_min, "%d"), args->policy);
1251 #endif
1252
1253         switch (args->policy) {
1254         case LINUX_SCHED_OTHER:
1255                 bsd.policy = SCHED_OTHER;
1256                 break;
1257         case LINUX_SCHED_FIFO:
1258                 bsd.policy = SCHED_FIFO;
1259                 break;
1260         case LINUX_SCHED_RR:
1261                 bsd.policy = SCHED_RR;
1262                 break;
1263         default:
1264                 return EINVAL;
1265         }
1266         bsd.sysmsg_result = 0;
1267
1268         error = sys_sched_get_priority_min(&bsd);
1269         args->sysmsg_result = bsd.sysmsg_result;
1270         return(error);
1271 }
1272
1273 #define REBOOT_CAD_ON   0x89abcdef
1274 #define REBOOT_CAD_OFF  0
1275 #define REBOOT_HALT     0xcdef0123
1276
1277 int
1278 sys_linux_reboot(struct linux_reboot_args *args)
1279 {
1280         struct reboot_args bsd_args;
1281         int error;
1282
1283 #ifdef DEBUG
1284         if (ldebug(reboot))
1285                 kprintf(ARGS(reboot, "0x%x"), args->cmd);
1286 #endif
1287         if (args->cmd == REBOOT_CAD_ON || args->cmd == REBOOT_CAD_OFF)
1288                 return (0);
1289         bsd_args.opt = (args->cmd == REBOOT_HALT) ? RB_HALT : 0;
1290         bsd_args.sysmsg_result = 0;
1291
1292         error = sys_reboot(&bsd_args);
1293         args->sysmsg_result = bsd_args.sysmsg_result;
1294         return(error);
1295 }
1296
1297 /*
1298  * The FreeBSD native getpid(2), getgid(2) and getuid(2) also modify
1299  * p->p_retval[1] when COMPAT_43 or COMPAT_SUNOS is defined. This
1300  * globbers registers that are assumed to be preserved. The following
1301  * lightweight syscalls fixes this. See also linux_getgid16() and
1302  * linux_getuid16() in linux_uid16.c.
1303  *
1304  * linux_getpid() - MP SAFE
1305  * linux_getgid() - MP SAFE
1306  * linux_getuid() - MP SAFE
1307  */
1308
1309 int
1310 sys_linux_getpid(struct linux_getpid_args *args)
1311 {
1312         struct thread *td = curthread;
1313         struct proc *p = td->td_proc;
1314
1315         KKASSERT(p);
1316
1317         args->sysmsg_result = p->p_pid;
1318         return (0);
1319 }
1320
1321 int
1322 sys_linux_getgid(struct linux_getgid_args *args)
1323 {
1324         struct thread *td = curthread;
1325         struct proc *p = td->td_proc;
1326
1327         KKASSERT(p);
1328
1329         args->sysmsg_result = p->p_ucred->cr_rgid;
1330         return (0);
1331 }
1332
1333 int
1334 sys_linux_getuid(struct linux_getuid_args *args)
1335 {
1336         struct thread *td = curthread;
1337         struct proc *p = td->td_proc;
1338
1339         KKASSERT(p);
1340
1341         args->sysmsg_result = p->p_ucred->cr_ruid;
1342         return (0);
1343 }
1344
1345 int
1346 sys_linux_getsid(struct linux_getsid_args *args)
1347 {
1348         struct getsid_args bsd;
1349         int error;
1350
1351         bsd.sysmsg_result = 0;
1352         bsd.pid = args->pid;
1353         error = sys_getsid(&bsd);
1354         args->sysmsg_result = bsd.sysmsg_result;
1355         return(error);
1356 }
1357
1358 int
1359 linux_nosys(struct nosys_args *args)
1360 {
1361         /* XXX */
1362         return (ENOSYS);
1363 }