[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/compat/linux/linux_misc.c

Version: -  FREEBSD  -  FREEBSD7  -  FREEBSD71  -  FREEBSD70  -  FREEBSD6  -  FREEBSD64  -  FREEBSD63  -  FREEBSD62  -  FREEBSD61  -  FREEBSD60  -  FREEBSD5  -  FREEBSD55  -  FREEBSD54  -  FREEBSD53  -  FREEBSD52  -  FREEBSD51  -  FREEBSD50  -  FREEBSD4  -  FREEBSD3  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  OPENSOLARIS  -  minix-3-1-1  -  TRUSTEDBSD-SEBSD  -  FREEBSD-LIBC  -  FREEBSD7-LIBC  -  FREEBSD6-LIBC  -  GLIBC27 
SearchContext: -  none  -  excerpts  -  bigexcerpts 

  1 /*-
  2  * Copyright (c) 2002 Doug Rabson
  3  * Copyright (c) 1994-1995 Søren Schmidt
  4  * All rights reserved.
  5  *
  6  * Redistribution and use in source and binary forms, with or without
  7  * modification, are permitted provided that the following conditions
  8  * are met:
  9  * 1. Redistributions of source code must retain the above copyright
 10  *    notice, this list of conditions and the following disclaimer
 11  *    in this position and unchanged.
 12  * 2. Redistributions in binary form must reproduce the above copyright
 13  *    notice, this list of conditions and the following disclaimer in the
 14  *    documentation and/or other materials provided with the distribution.
 15  * 3. The name of the author may not be used to endorse or promote products
 16  *    derived from this software without specific prior written permission
 17  *
 18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 23  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 28  */
 29 
 30 #include <sys/cdefs.h>
 31 __FBSDID("$FreeBSD: src/sys/compat/linux/linux_misc.c,v 1.231 2008/12/29 12:58:45 ed Exp $");
 32 
 33 #include "opt_compat.h"
 34 #include "opt_mac.h"
 35 
 36 #include <sys/param.h>
 37 #include <sys/blist.h>
 38 #include <sys/fcntl.h>
 39 #if defined(__i386__)
 40 #include <sys/imgact_aout.h>
 41 #endif
 42 #include <sys/jail.h>
 43 #include <sys/kernel.h>
 44 #include <sys/limits.h>
 45 #include <sys/lock.h>
 46 #include <sys/malloc.h>
 47 #include <sys/mman.h>
 48 #include <sys/mount.h>
 49 #include <sys/mutex.h>
 50 #include <sys/namei.h>
 51 #include <sys/priv.h>
 52 #include <sys/proc.h>
 53 #include <sys/reboot.h>
 54 #include <sys/resourcevar.h>
 55 #include <sys/sched.h>
 56 #include <sys/signalvar.h>
 57 #include <sys/stat.h>
 58 #include <sys/syscallsubr.h>
 59 #include <sys/sysctl.h>
 60 #include <sys/sysproto.h>
 61 #include <sys/systm.h>
 62 #include <sys/time.h>
 63 #include <sys/vmmeter.h>
 64 #include <sys/vnode.h>
 65 #include <sys/wait.h>
 66 #include <sys/cpuset.h>
 67 #include <sys/vimage.h>
 68 
 69 #include <security/mac/mac_framework.h>
 70 
 71 #include <vm/vm.h>
 72 #include <vm/pmap.h>
 73 #include <vm/vm_kern.h>
 74 #include <vm/vm_map.h>
 75 #include <vm/vm_extern.h>
 76 #include <vm/vm_object.h>
 77 #include <vm/swap_pager.h>
 78 
 79 #ifdef COMPAT_LINUX32
 80 #include <machine/../linux32/linux.h>
 81 #include <machine/../linux32/linux32_proto.h>
 82 #else
 83 #include <machine/../linux/linux.h>
 84 #include <machine/../linux/linux_proto.h>
 85 #endif
 86 
 87 #include <compat/linux/linux_file.h>
 88 #include <compat/linux/linux_mib.h>
 89 #include <compat/linux/linux_signal.h>
 90 #include <compat/linux/linux_util.h>
 91 #include <compat/linux/linux_sysproto.h>
 92 #include <compat/linux/linux_emul.h>
 93 #include <compat/linux/linux_misc.h>
 94 
 95 #ifdef __i386__
 96 #include <machine/cputypes.h>
 97 #endif
 98 
 99 #define BSD_TO_LINUX_SIGNAL(sig)        \
100         (((sig) <= LINUX_SIGTBLSZ) ? bsd_to_linux_signal[_SIG_IDX(sig)] : sig)
101 
102 static unsigned int linux_to_bsd_resource[LINUX_RLIM_NLIMITS] = {
103         RLIMIT_CPU, RLIMIT_FSIZE, RLIMIT_DATA, RLIMIT_STACK,
104         RLIMIT_CORE, RLIMIT_RSS, RLIMIT_NPROC, RLIMIT_NOFILE,
105         RLIMIT_MEMLOCK, RLIMIT_AS 
106 };
107 
108 struct l_sysinfo {
109         l_long          uptime;         /* Seconds since boot */
110         l_ulong         loads[3];       /* 1, 5, and 15 minute load averages */
111 #define LINUX_SYSINFO_LOADS_SCALE 65536
112         l_ulong         totalram;       /* Total usable main memory size */
113         l_ulong         freeram;        /* Available memory size */
114         l_ulong         sharedram;      /* Amount of shared memory */
115         l_ulong         bufferram;      /* Memory used by buffers */
116         l_ulong         totalswap;      /* Total swap space size */
117         l_ulong         freeswap;       /* swap space still available */
118         l_ushort        procs;          /* Number of current processes */
119         l_ushort        pads;
120         l_ulong         totalbig;
121         l_ulong         freebig;
122         l_uint          mem_unit;
123         char            _f[20-2*sizeof(l_long)-sizeof(l_int)];  /* padding */
124 };
125 int
126 linux_sysinfo(struct thread *td, struct linux_sysinfo_args *args)
127 {
128         struct l_sysinfo sysinfo;
129         vm_object_t object;
130         int i, j;
131         struct timespec ts;
132 
133         getnanouptime(&ts);
134         if (ts.tv_nsec != 0)
135                 ts.tv_sec++;
136         sysinfo.uptime = ts.tv_sec;
137 
138         /* Use the information from the mib to get our load averages */
139         for (i = 0; i < 3; i++)
140                 sysinfo.loads[i] = averunnable.ldavg[i] *
141                     LINUX_SYSINFO_LOADS_SCALE / averunnable.fscale;
142 
143         sysinfo.totalram = physmem * PAGE_SIZE;
144         sysinfo.freeram = sysinfo.totalram - cnt.v_wire_count * PAGE_SIZE;
145 
146         sysinfo.sharedram = 0;
147         mtx_lock(&vm_object_list_mtx);
148         TAILQ_FOREACH(object, &vm_object_list, object_list)
149                 if (object->shadow_count > 1)
150                         sysinfo.sharedram += object->resident_page_count;
151         mtx_unlock(&vm_object_list_mtx);
152 
153         sysinfo.sharedram *= PAGE_SIZE;
154         sysinfo.bufferram = 0;
155 
156         swap_pager_status(&i, &j);
157         sysinfo.totalswap = i * PAGE_SIZE;
158         sysinfo.freeswap = (i - j) * PAGE_SIZE;
159 
160         sysinfo.procs = nprocs;
161 
162         /* The following are only present in newer Linux kernels. */
163         sysinfo.totalbig = 0;
164         sysinfo.freebig = 0;
165         sysinfo.mem_unit = 1;
166 
167         return copyout(&sysinfo, args->info, sizeof(sysinfo));
168 }
169 
170 int
171 linux_alarm(struct thread *td, struct linux_alarm_args *args)
172 {
173         struct itimerval it, old_it;
174         u_int secs;
175         int error;
176 
177 #ifdef DEBUG
178         if (ldebug(alarm))
179                 printf(ARGS(alarm, "%u"), args->secs);
180 #endif
181         
182         secs = args->secs;
183 
184         if (secs > INT_MAX)
185                 secs = INT_MAX;
186 
187         it.it_value.tv_sec = (long) secs;
188         it.it_value.tv_usec = 0;
189         it.it_interval.tv_sec = 0;
190         it.it_interval.tv_usec = 0;
191         error = kern_setitimer(td, ITIMER_REAL, &it, &old_it);
192         if (error)
193                 return (error);
194         if (timevalisset(&old_it.it_value)) {
195                 if (old_it.it_value.tv_usec != 0)
196                         old_it.it_value.tv_sec++;
197                 td->td_retval[0] = old_it.it_value.tv_sec;
198         }
199         return (0);
200 }
201 
202 int
203 linux_brk(struct thread *td, struct linux_brk_args *args)
204 {
205         struct vmspace *vm = td->td_proc->p_vmspace;
206         vm_offset_t new, old;
207         struct obreak_args /* {
208                 char * nsize;
209         } */ tmp;
210 
211 #ifdef DEBUG
212         if (ldebug(brk))
213                 printf(ARGS(brk, "%p"), (void *)(uintptr_t)args->dsend);
214 #endif
215         old = (vm_offset_t)vm->vm_daddr + ctob(vm->vm_dsize);
216         new = (vm_offset_t)args->dsend;
217         tmp.nsize = (char *)new;
218         if (((caddr_t)new > vm->vm_daddr) && !obreak(td, &tmp))
219                 td->td_retval[0] = (long)new;
220         else
221                 td->td_retval[0] = (long)old;
222 
223         return 0;
224 }
225 
226 #if defined(__i386__)
227 /* XXX: what about amd64/linux32? */
228 
229 int
230 linux_uselib(struct thread *td, struct linux_uselib_args *args)
231 {
232         struct nameidata ni;
233         struct vnode *vp;
234         struct exec *a_out;
235         struct vattr attr;
236         vm_offset_t vmaddr;
237         unsigned long file_offset;
238         vm_offset_t buffer;
239         unsigned long bss_size;
240         char *library;
241         int error;
242         int locked, vfslocked;
243 
244         LCONVPATHEXIST(td, args->library, &library);
245 
246 #ifdef DEBUG
247         if (ldebug(uselib))
248                 printf(ARGS(uselib, "%s"), library);
249 #endif
250 
251         a_out = NULL;
252         vfslocked = 0;
253         locked = 0;
254         vp = NULL;
255 
256         NDINIT(&ni, LOOKUP, ISOPEN | FOLLOW | LOCKLEAF | MPSAFE | AUDITVNODE1,
257             UIO_SYSSPACE, library, td);
258         error = namei(&ni);
259         LFREEPATH(library);
260         if (error)
261                 goto cleanup;
262 
263         vp = ni.ni_vp;
264         vfslocked = NDHASGIANT(&ni);
265         NDFREE(&ni, NDF_ONLY_PNBUF);
266 
267         /*
268          * From here on down, we have a locked vnode that must be unlocked.
269          * XXX: The code below largely duplicates exec_check_permissions().
270          */
271         locked = 1;
272 
273         /* Writable? */
274         if (vp->v_writecount) {
275                 error = ETXTBSY;
276                 goto cleanup;
277         }
278 
279         /* Executable? */
280         error = VOP_GETATTR(vp, &attr, td->td_ucred);
281         if (error)
282                 goto cleanup;
283 
284         if ((vp->v_mount->mnt_flag & MNT_NOEXEC) ||
285             ((attr.va_mode & 0111) == 0) || (attr.va_type != VREG)) {
286                 /* EACCESS is what exec(2) returns. */
287                 error = ENOEXEC;
288                 goto cleanup;
289         }
290 
291         /* Sensible size? */
292         if (attr.va_size == 0) {
293                 error = ENOEXEC;
294                 goto cleanup;
295         }
296 
297         /* Can we access it? */
298         error = VOP_ACCESS(vp, VEXEC, td->td_ucred, td);
299         if (error)
300                 goto cleanup;
301 
302         /*
303          * XXX: This should use vn_open() so that it is properly authorized,
304          * and to reduce code redundancy all over the place here.
305          * XXX: Not really, it duplicates far more of exec_check_permissions()
306          * than vn_open().
307          */
308 #ifdef MAC
309         error = mac_vnode_check_open(td->td_ucred, vp, VREAD);
310         if (error)
311                 goto cleanup;
312 #endif
313         error = VOP_OPEN(vp, FREAD, td->td_ucred, td, NULL);
314         if (error)
315                 goto cleanup;
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, OBJT_VNODE, 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         PROC_LOCK(td->td_proc);
366         if (a_out->a_text > maxtsiz ||
367             a_out->a_data + bss_size > lim_cur(td->td_proc, RLIMIT_DATA)) {
368                 PROC_UNLOCK(td->td_proc);
369                 error = ENOMEM;
370                 goto cleanup;
371         }
372         PROC_UNLOCK(td->td_proc);
373 
374         /*
375          * Prevent more writers.
376          * XXX: Note that if any of the VM operations fail below we don't
377          * clear this flag.
378          */
379         vp->v_vflag |= VV_TEXT;
380 
381         /*
382          * Lock no longer needed
383          */
384         locked = 0;
385         VOP_UNLOCK(vp, 0);
386         VFS_UNLOCK_GIANT(vfslocked);
387 
388         /*
389          * Check if file_offset page aligned. Currently we cannot handle
390          * misalinged file offsets, and so we read in the entire image
391          * (what a waste).
392          */
393         if (file_offset & PAGE_MASK) {
394 #ifdef DEBUG
395                 printf("uselib: Non page aligned binary %lu\n", file_offset);
396 #endif
397                 /* Map text+data read/write/execute */
398 
399                 /* a_entry is the load address and is page aligned */
400                 vmaddr = trunc_page(a_out->a_entry);
401 
402                 /* get anon user mapping, read+write+execute */
403                 error = vm_map_find(&td->td_proc->p_vmspace->vm_map, NULL, 0,
404                     &vmaddr, a_out->a_text + a_out->a_data, FALSE, VM_PROT_ALL,
405                     VM_PROT_ALL, 0);
406                 if (error)
407                         goto cleanup;
408 
409                 /* map file into kernel_map */
410                 error = vm_mmap(kernel_map, &buffer,
411                     round_page(a_out->a_text + a_out->a_data + file_offset),
412                     VM_PROT_READ, VM_PROT_READ, 0, OBJT_VNODE, vp,
413                     trunc_page(file_offset));
414                 if (error)
415                         goto cleanup;
416 
417                 /* copy from kernel VM space to user space */
418                 error = copyout(PTRIN(buffer + file_offset),
419                     (void *)vmaddr, a_out->a_text + a_out->a_data);
420 
421                 /* release temporary kernel space */
422                 vm_map_remove(kernel_map, buffer, buffer +
423                     round_page(a_out->a_text + a_out->a_data + file_offset));
424 
425                 if (error)
426                         goto cleanup;
427         } else {
428 #ifdef DEBUG
429                 printf("uselib: Page aligned binary %lu\n", file_offset);
430 #endif
431                 /*
432                  * for QMAGIC, a_entry is 20 bytes beyond the load address
433                  * to skip the executable header
434                  */
435                 vmaddr = trunc_page(a_out->a_entry);
436 
437                 /*
438                  * Map it all into the process's space as a single
439                  * copy-on-write "data" segment.
440                  */
441                 error = vm_mmap(&td->td_proc->p_vmspace->vm_map, &vmaddr,
442                     a_out->a_text + a_out->a_data, VM_PROT_ALL, VM_PROT_ALL,
443                     MAP_PRIVATE | MAP_FIXED, OBJT_VNODE, vp, file_offset);
444                 if (error)
445                         goto cleanup;
446         }
447 #ifdef DEBUG
448         printf("mem=%08lx = %08lx %08lx\n", (long)vmaddr, ((long *)vmaddr)[0],
449             ((long *)vmaddr)[1]);
450 #endif
451         if (bss_size != 0) {
452                 /* Calculate BSS start address */
453                 vmaddr = trunc_page(a_out->a_entry) + a_out->a_text +
454                     a_out->a_data;
455 
456                 /* allocate some 'anon' space */
457                 error = vm_map_find(&td->td_proc->p_vmspace->vm_map, NULL, 0,
458                     &vmaddr, bss_size, FALSE, VM_PROT_ALL, VM_PROT_ALL, 0);
459                 if (error)
460                         goto cleanup;
461         }
462 
463 cleanup:
464         /* Unlock vnode if needed */
465         if (locked) {
466                 VOP_UNLOCK(vp, 0);
467                 VFS_UNLOCK_GIANT(vfslocked);
468         }
469 
470         /* Release the kernel mapping. */
471         if (a_out)
472                 vm_map_remove(kernel_map, (vm_offset_t)a_out,
473                     (vm_offset_t)a_out + PAGE_SIZE);
474 
475         return error;
476 }
477 
478 #endif  /* __i386__ */
479 
480 int
481 linux_select(struct thread *td, struct linux_select_args *args)
482 {
483         l_timeval ltv;
484         struct timeval tv0, tv1, utv, *tvp;
485         int error;
486 
487 #ifdef DEBUG
488         if (ldebug(select))
489                 printf(ARGS(select, "%d, %p, %p, %p, %p"), args->nfds,
490                     (void *)args->readfds, (void *)args->writefds,
491                     (void *)args->exceptfds, (void *)args->timeout);
492 #endif
493 
494         /*
495          * Store current time for computation of the amount of
496          * time left.
497          */
498         if (args->timeout) {
499                 if ((error = copyin(args->timeout, &ltv, sizeof(ltv))))
500                         goto select_out;
501                 utv.tv_sec = ltv.tv_sec;
502                 utv.tv_usec = ltv.tv_usec;
503 #ifdef DEBUG
504                 if (ldebug(select))
505                         printf(LMSG("incoming timeout (%jd/%ld)"),
506                             (intmax_t)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                         utv.tv_sec += utv.tv_usec / 1000000;
515                         utv.tv_usec %= 1000000;
516                         if (utv.tv_usec < 0) {
517                                 utv.tv_sec -= 1;
518                                 utv.tv_usec += 1000000;
519                         }
520                         if (utv.tv_sec < 0)
521                                 timevalclear(&utv);
522                 }
523                 microtime(&tv0);
524                 tvp = &utv;
525         } else
526                 tvp = NULL;
527 
528         error = kern_select(td, args->nfds, args->readfds, args->writefds,
529             args->exceptfds, tvp);
530 
531 #ifdef DEBUG
532         if (ldebug(select))
533                 printf(LMSG("real select returns %d"), error);
534 #endif
535         if (error)
536                 goto select_out;
537 
538         if (args->timeout) {
539                 if (td->td_retval[0]) {
540                         /*
541                          * Compute how much time was left of the timeout,
542                          * by subtracting the current time and the time
543                          * before we started the call, and subtracting
544                          * that result from the user-supplied value.
545                          */
546                         microtime(&tv1);
547                         timevalsub(&tv1, &tv0);
548                         timevalsub(&utv, &tv1);
549                         if (utv.tv_sec < 0)
550                                 timevalclear(&utv);
551                 } else
552                         timevalclear(&utv);
553 #ifdef DEBUG
554                 if (ldebug(select))
555                         printf(LMSG("outgoing timeout (%jd/%ld)"),
556                             (intmax_t)utv.tv_sec, utv.tv_usec);
557 #endif
558                 ltv.tv_sec = utv.tv_sec;
559                 ltv.tv_usec = utv.tv_usec;
560                 if ((error = copyout(&ltv, args->timeout, sizeof(ltv))))
561                         goto select_out;
562         }
563 
564 select_out:
565 #ifdef DEBUG
566         if (ldebug(select))
567                 printf(LMSG("select_out -> %d"), error);
568 #endif
569         return error;
570 }
571 
572 int
573 linux_mremap(struct thread *td, struct linux_mremap_args *args)
574 {
575         struct munmap_args /* {
576                 void *addr;
577                 size_t len;
578         } */ bsd_args;
579         int error = 0;
580 
581 #ifdef DEBUG
582         if (ldebug(mremap))
583                 printf(ARGS(mremap, "%p, %08lx, %08lx, %08lx"),
584                     (void *)(uintptr_t)args->addr,
585                     (unsigned long)args->old_len,
586                     (unsigned long)args->new_len,
587                     (unsigned long)args->flags);
588 #endif
589 
590         if (args->flags & ~(LINUX_MREMAP_FIXED | LINUX_MREMAP_MAYMOVE)) {
591                 td->td_retval[0] = 0;
592                 return (EINVAL);
593         }
594 
595         /*
596          * Check for the page alignment.
597          * Linux defines PAGE_MASK to be FreeBSD ~PAGE_MASK.
598          */
599         if (args->addr & PAGE_MASK) {
600                 td->td_retval[0] = 0;
601                 return (EINVAL);
602         }
603 
604         args->new_len = round_page(args->new_len);
605         args->old_len = round_page(args->old_len);
606 
607         if (args->new_len > args->old_len) {
608                 td->td_retval[0] = 0;
609                 return ENOMEM;
610         }
611 
612         if (args->new_len < args->old_len) {
613                 bsd_args.addr =
614                     (caddr_t)((uintptr_t)args->addr + args->new_len);
615                 bsd_args.len = args->old_len - args->new_len;
616                 error = munmap(td, &bsd_args);
617         }
618 
619         td->td_retval[0] = error ? 0 : (uintptr_t)args->addr;
620         return error;
621 }
622 
623 #define LINUX_MS_ASYNC       0x0001
624 #define LINUX_MS_INVALIDATE  0x0002
625 #define LINUX_MS_SYNC        0x0004
626 
627 int
628 linux_msync(struct thread *td, struct linux_msync_args *args)
629 {
630         struct msync_args bsd_args;
631 
632         bsd_args.addr = (caddr_t)(uintptr_t)args->addr;
633         bsd_args.len = (uintptr_t)args->len;
634         bsd_args.flags = args->fl & ~LINUX_MS_SYNC;
635 
636         return msync(td, &bsd_args);
637 }
638 
639 int
640 linux_time(struct thread *td, struct linux_time_args *args)
641 {
642         struct timeval tv;
643         l_time_t tm;
644         int error;
645 
646 #ifdef DEBUG
647         if (ldebug(time))
648                 printf(ARGS(time, "*"));
649 #endif
650 
651         microtime(&tv);
652         tm = tv.tv_sec;
653         if (args->tm && (error = copyout(&tm, args->tm, sizeof(tm))))
654                 return error;
655         td->td_retval[0] = tm;
656         return 0;
657 }
658 
659 struct l_times_argv {
660         l_long  tms_utime;
661         l_long  tms_stime;
662         l_long  tms_cutime;
663         l_long  tms_cstime;
664 };
665 
666 #define CLK_TCK 100                     /* Linux uses 100 */
667 
668 #define CONVTCK(r)      (r.tv_sec * CLK_TCK + r.tv_usec / (1000000 / CLK_TCK))
669 
670 int
671 linux_times(struct thread *td, struct linux_times_args *args)
672 {
673         struct timeval tv, utime, stime, cutime, cstime;
674         struct l_times_argv tms;
675         struct proc *p;
676         int error;
677 
678 #ifdef DEBUG
679         if (ldebug(times))
680                 printf(ARGS(times, "*"));
681 #endif
682 
683         if (args->buf != NULL) {
684                 p = td->td_proc;
685                 PROC_LOCK(p);
686                 PROC_SLOCK(p);
687                 calcru(p, &utime, &stime);
688                 PROC_SUNLOCK(p);
689                 calccru(p, &cutime, &cstime);
690                 PROC_UNLOCK(p);
691 
692                 tms.tms_utime = CONVTCK(utime);
693                 tms.tms_stime = CONVTCK(stime);
694 
695                 tms.tms_cutime = CONVTCK(cutime);
696                 tms.tms_cstime = CONVTCK(cstime);
697 
698                 if ((error = copyout(&tms, args->buf, sizeof(tms))))
699                         return error;
700         }
701 
702         microuptime(&tv);
703         td->td_retval[0] = (int)CONVTCK(tv);
704         return 0;
705 }
706 
707 int
708 linux_newuname(struct thread *td, struct linux_newuname_args *args)
709 {
710         INIT_VPROCG(TD_TO_VPROCG(td));
711         struct l_new_utsname utsname;
712         char osname[LINUX_MAX_UTSNAME];
713         char osrelease[LINUX_MAX_UTSNAME];
714         char *p;
715 
716 #ifdef DEBUG
717         if (ldebug(newuname))
718                 printf(ARGS(newuname, "*"));
719 #endif
720 
721         linux_get_osname(td, osname);
722         linux_get_osrelease(td, osrelease);
723 
724         bzero(&utsname, sizeof(utsname));
725         strlcpy(utsname.sysname, osname, LINUX_MAX_UTSNAME);
726         getcredhostname(td->td_ucred, utsname.nodename, LINUX_MAX_UTSNAME);
727         strlcpy(utsname.release, osrelease, LINUX_MAX_UTSNAME);
728         strlcpy(utsname.version, version, LINUX_MAX_UTSNAME);
729         for (p = utsname.version; *p != '\0'; ++p)
730                 if (*p == '\n') {
731                         *p = '\0';
732                         break;
733                 }
734 #ifdef __i386__
735         {
736                 const char *class;
737 
738                 switch (cpu_class) {
739                 case CPUCLASS_686:
740                         class = "i686";
741                         break;
742                 case CPUCLASS_586:
743                         class = "i586";
744                         break;
745                 case CPUCLASS_486:
746                         class = "i486";
747                         break;
748                 default:
749                         class = "i386";
750                 }
751                 strlcpy(utsname.machine, class, LINUX_MAX_UTSNAME);
752         }
753 #elif defined(__amd64__)        /* XXX: Linux can change 'personality'. */
754 #ifdef COMPAT_LINUX32
755         strlcpy(utsname.machine, "i686", LINUX_MAX_UTSNAME);
756 #else
757         strlcpy(utsname.machine, "x86_64", LINUX_MAX_UTSNAME);
758 #endif /* COMPAT_LINUX32 */
759 #else /* something other than i386 or amd64 - assume we and Linux agree */
760         strlcpy(utsname.machine, machine, LINUX_MAX_UTSNAME);
761 #endif /* __i386__ */
762         mtx_lock(&hostname_mtx);
763         strlcpy(utsname.domainname, V_domainname, LINUX_MAX_UTSNAME);
764         mtx_unlock(&hostname_mtx);
765 
766         return (copyout(&utsname, args->buf, sizeof(utsname)));
767 }
768 
769 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
770 struct l_utimbuf {
771         l_time_t l_actime;
772         l_time_t l_modtime;
773 };
774 
775 int
776 linux_utime(struct thread *td, struct linux_utime_args *args)
777 {
778         struct timeval tv[2], *tvp;
779         struct l_utimbuf lut;
780         char *fname;
781         int error;
782 
783         LCONVPATHEXIST(td, args->fname, &fname);
784 
785 #ifdef DEBUG
786         if (ldebug(utime))
787                 printf(ARGS(utime, "%s, *"), fname);
788 #endif
789 
790         if (args->times) {
791                 if ((error = copyin(args->times, &lut, sizeof lut))) {
792                         LFREEPATH(fname);
793                         return error;
794                 }
795                 tv[0].tv_sec = lut.l_actime;
796                 tv[0].tv_usec = 0;
797                 tv[1].tv_sec = lut.l_modtime;
798                 tv[1].tv_usec = 0;
799                 tvp = tv;
800         } else
801                 tvp = NULL;
802 
803         error = kern_utimes(td, fname, UIO_SYSSPACE, tvp, UIO_SYSSPACE);
804         LFREEPATH(fname);
805         return (error);
806 }
807 
808 int
809 linux_utimes(struct thread *td, struct linux_utimes_args *args)
810 {
811         l_timeval ltv[2];
812         struct timeval tv[2], *tvp = NULL;
813         char *fname;
814         int error;
815 
816         LCONVPATHEXIST(td, args->fname, &fname);
817 
818 #ifdef DEBUG
819         if (ldebug(utimes))
820                 printf(ARGS(utimes, "%s, *"), fname);
821 #endif
822 
823         if (args->tptr != NULL) {
824                 if ((error = copyin(args->tptr, ltv, sizeof ltv))) {
825                         LFREEPATH(fname);
826                         return (error);
827                 }
828                 tv[0].tv_sec = ltv[0].tv_sec;
829                 tv[0].tv_usec = ltv[0].tv_usec;
830                 tv[1].tv_sec = ltv[1].tv_sec;
831                 tv[1].tv_usec = ltv[1].tv_usec;
832                 tvp = tv;
833         }
834 
835         error = kern_utimes(td, fname, UIO_SYSSPACE, tvp, UIO_SYSSPACE);
836         LFREEPATH(fname);
837         return (error);
838 }
839 
840 int
841 linux_futimesat(struct thread *td, struct linux_futimesat_args *args)
842 {
843         l_timeval ltv[2];
844         struct timeval tv[2], *tvp = NULL;
845         char *fname;
846         int error, dfd;
847 
848         dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
849         LCONVPATHEXIST_AT(td, args->filename, &fname, dfd);
850 
851 #ifdef DEBUG
852         if (ldebug(futimesat))
853                 printf(ARGS(futimesat, "%s, *"), fname);
854 #endif
855 
856         if (args->utimes != NULL) {
857                 if ((error = copyin(args->utimes, ltv, sizeof ltv))) {
858                         LFREEPATH(fname);
859                         return (error);
860                 }
861                 tv[0].tv_sec = ltv[0].tv_sec;
862                 tv[0].tv_usec = ltv[0].tv_usec;
863                 tv[1].tv_sec = ltv[1].tv_sec;
864                 tv[1].tv_usec = ltv[1].tv_usec;
865                 tvp = tv;
866         }
867 
868         error = kern_utimesat(td, dfd, fname, UIO_SYSSPACE, tvp, UIO_SYSSPACE);
869         LFREEPATH(fname);
870         return (error);
871 }
872 #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
873 
874 #define __WCLONE 0x80000000
875 
876 int
877 linux_waitpid(struct thread *td, struct linux_waitpid_args *args)
878 {
879         int error, options, tmpstat;
880 
881 #ifdef DEBUG
882         if (ldebug(waitpid))
883                 printf(ARGS(waitpid, "%d, %p, %d"),
884                     args->pid, (void *)args->status, args->options);
885 #endif
886         /*
887          * this is necessary because the test in kern_wait doesn't work
888          * because we mess with the options here
889          */
890         if (args->options & ~(WUNTRACED | WNOHANG | WCONTINUED | __WCLONE))
891                 return (EINVAL);
892 
893         options = (args->options & (WNOHANG | WUNTRACED));
894         /* WLINUXCLONE should be equal to __WCLONE, but we make sure */
895         if (args->options & __WCLONE)
896                 options |= WLINUXCLONE;
897 
898         error = kern_wait(td, args->pid, &tmpstat, options, NULL);
899         if (error)
900                 return error;
901 
902         if (args->status) {
903                 tmpstat &= 0xffff;
904                 if (WIFSIGNALED(tmpstat))
905                         tmpstat = (tmpstat & 0xffffff80) |
906                             BSD_TO_LINUX_SIGNAL(WTERMSIG(tmpstat));
907                 else if (WIFSTOPPED(tmpstat))
908                         tmpstat = (tmpstat & 0xffff00ff) |
909                             (BSD_TO_LINUX_SIGNAL(WSTOPSIG(tmpstat)) << 8);
910                 return copyout(&tmpstat, args->status, sizeof(int));
911         }
912 
913         return 0;
914 }
915 
916 int
917 linux_wait4(struct thread *td, struct linux_wait4_args *args)
918 {
919         int error, options, tmpstat;
920         struct rusage ru, *rup;
921         struct proc *p;
922 
923 #ifdef DEBUG
924         if (ldebug(wait4))
925                 printf(ARGS(wait4, "%d, %p, %d, %p"),
926                     args->pid, (void *)args->status, args->options,
927                     (void *)args->rusage);
928 #endif
929 
930         options = (args->options & (WNOHANG | WUNTRACED));
931         /* WLINUXCLONE should be equal to __WCLONE, but we make sure */
932         if (args->options & __WCLONE)
933                 options |= WLINUXCLONE;
934 
935         if (args->rusage != NULL)
936                 rup = &ru;
937         else
938                 rup = NULL;
939         error = kern_wait(td, args->pid, &tmpstat, options, rup);
940         if (error)
941                 return error;
942 
943         p = td->td_proc;
944         PROC_LOCK(p);
945         sigqueue_delete(&p->p_sigqueue, SIGCHLD);
946         PROC_UNLOCK(p);
947 
948         if (args->status) {
949                 tmpstat &= 0xffff;
950                 if (WIFSIGNALED(tmpstat))
951                         tmpstat = (tmpstat & 0xffffff80) |
952                             BSD_TO_LINUX_SIGNAL(WTERMSIG(tmpstat));
953                 else if (WIFSTOPPED(tmpstat))
954                         tmpstat = (tmpstat & 0xffff00ff) |
955                             (BSD_TO_LINUX_SIGNAL(WSTOPSIG(tmpstat)) << 8);
956                 error = copyout(&tmpstat, args->status, sizeof(int));
957         }
958         if (args->rusage != NULL && error == 0)