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