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