xref: /freebsd/sys/compat/linux/linux_misc.c (revision eba4802243eef298fb77a495b6a99477cdd48917)
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$
29  */
30 
31 #include "opt_compat.h"
32 
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/sysproto.h>
36 #include <sys/kernel.h>
37 #include <sys/mman.h>
38 #include <sys/proc.h>
39 #include <sys/fcntl.h>
40 #include <sys/imgact_aout.h>
41 #include <sys/mount.h>
42 #include <sys/namei.h>
43 #include <sys/resourcevar.h>
44 #include <sys/stat.h>
45 #include <sys/sysctl.h>
46 #include <sys/unistd.h>
47 #include <sys/vnode.h>
48 #include <sys/wait.h>
49 #include <sys/time.h>
50 #include <sys/signalvar.h>
51 
52 #include <vm/vm.h>
53 #include <vm/pmap.h>
54 #include <vm/vm_kern.h>
55 #include <vm/vm_map.h>
56 #include <vm/vm_extern.h>
57 
58 #include <machine/frame.h>
59 #include <machine/limits.h>
60 #include <machine/psl.h>
61 #include <machine/sysarch.h>
62 #ifdef __i386__
63 #include <machine/segments.h>
64 #endif
65 
66 #include <posix4/sched.h>
67 
68 #include <machine/../linux/linux.h>
69 #include <machine/../linux/linux_proto.h>
70 #include <compat/linux/linux_mib.h>
71 #include <compat/linux/linux_util.h>
72 
73 #ifdef __alpha__
74 #define BSD_TO_LINUX_SIGNAL(sig)       (sig)
75 #else
76 #define BSD_TO_LINUX_SIGNAL(sig)	\
77 	(((sig) <= LINUX_SIGTBLSZ) ? bsd_to_linux_signal[_SIG_IDX(sig)] : sig)
78 #endif
79 
80 struct linux_rlimit {
81 	unsigned long rlim_cur;
82 	unsigned long rlim_max;
83 };
84 
85 #ifndef __alpha__
86 static unsigned int linux_to_bsd_resource[LINUX_RLIM_NLIMITS] =
87 { RLIMIT_CPU, RLIMIT_FSIZE, RLIMIT_DATA, RLIMIT_STACK,
88   RLIMIT_CORE, RLIMIT_RSS, RLIMIT_NPROC, RLIMIT_NOFILE,
89   RLIMIT_MEMLOCK, -1
90 };
91 #endif /*!__alpha__*/
92 
93 #ifndef __alpha__
94 int
95 linux_alarm(struct proc *p, struct linux_alarm_args *args)
96 {
97     struct itimerval it, old_it;
98     struct timeval tv;
99     int s;
100 
101 #ifdef DEBUG
102     printf("Linux-emul(%ld): alarm(%u)\n", (long)p->p_pid, args->secs);
103 #endif
104     if (args->secs > 100000000)
105 	return EINVAL;
106     it.it_value.tv_sec = (long)args->secs;
107     it.it_value.tv_usec = 0;
108     it.it_interval.tv_sec = 0;
109     it.it_interval.tv_usec = 0;
110     s = splsoftclock();
111     old_it = p->p_realtimer;
112     getmicrouptime(&tv);
113     if (timevalisset(&old_it.it_value))
114 	callout_stop(&p->p_itcallout);
115     if (it.it_value.tv_sec != 0) {
116 	callout_reset(&p->p_itcallout, tvtohz(&it.it_value), realitexpire, p);
117 	timevaladd(&it.it_value, &tv);
118     }
119     p->p_realtimer = it;
120     splx(s);
121     if (timevalcmp(&old_it.it_value, &tv, >)) {
122 	timevalsub(&old_it.it_value, &tv);
123 	if (old_it.it_value.tv_usec != 0)
124 	    old_it.it_value.tv_sec++;
125 	p->p_retval[0] = old_it.it_value.tv_sec;
126     }
127     return 0;
128 }
129 #endif /*!__alpha__*/
130 
131 int
132 linux_brk(struct proc *p, struct linux_brk_args *args)
133 {
134 #if 0
135     struct vmspace *vm = p->p_vmspace;
136     vm_offset_t new, old;
137     int error;
138 
139     if ((vm_offset_t)args->dsend < (vm_offset_t)vm->vm_daddr)
140 	return EINVAL;
141     if (((caddr_t)args->dsend - (caddr_t)vm->vm_daddr)
142 	> p->p_rlimit[RLIMIT_DATA].rlim_cur)
143 	return ENOMEM;
144 
145     old = round_page((vm_offset_t)vm->vm_daddr) + ctob(vm->vm_dsize);
146     new = round_page((vm_offset_t)args->dsend);
147     p->p_retval[0] = old;
148     if ((new-old) > 0) {
149 	if (swap_pager_full)
150 	    return ENOMEM;
151 	error = vm_map_find(&vm->vm_map, NULL, 0, &old, (new-old), FALSE,
152 			VM_PROT_ALL, VM_PROT_ALL, 0);
153 	if (error)
154 	    return error;
155 	vm->vm_dsize += btoc((new-old));
156 	p->p_retval[0] = (int)(vm->vm_daddr + ctob(vm->vm_dsize));
157     }
158     return 0;
159 #else
160     struct vmspace *vm = p->p_vmspace;
161     vm_offset_t new, old;
162     struct obreak_args /* {
163 	char * nsize;
164     } */ tmp;
165 
166 #ifdef DEBUG
167     printf("Linux-emul(%ld): brk(%p)\n", (long)p->p_pid, (void *)args->dsend);
168 #endif
169     old = (vm_offset_t)vm->vm_daddr + ctob(vm->vm_dsize);
170     new = (vm_offset_t)args->dsend;
171     tmp.nsize = (char *) new;
172     if (((caddr_t)new > vm->vm_daddr) && !obreak(p, &tmp))
173 	p->p_retval[0] = (long)new;
174     else
175 	p->p_retval[0] = (long)old;
176 
177     return 0;
178 #endif
179 }
180 
181 int
182 linux_uselib(struct proc *p, struct linux_uselib_args *args)
183 {
184     struct nameidata ni;
185     struct vnode *vp;
186     struct exec *a_out;
187     struct vattr attr;
188     vm_offset_t vmaddr;
189     unsigned long file_offset;
190     vm_offset_t buffer;
191     unsigned long bss_size;
192     int error;
193     caddr_t sg;
194     int locked;
195 
196     sg = stackgap_init();
197     CHECKALTEXIST(p, &sg, args->library);
198 
199 #ifdef DEBUG
200     printf("Linux-emul(%ld): uselib(%s)\n", (long)p->p_pid, args->library);
201 #endif
202 
203     a_out = NULL;
204     locked = 0;
205     vp = NULL;
206 
207     NDINIT(&ni, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, args->library, p);
208     error = namei(&ni);
209     if (error)
210 	goto cleanup;
211 
212     vp = ni.ni_vp;
213     /*
214      * XXX This looks like a bogus check - a LOCKLEAF namei should not succeed
215      * without returning a vnode.
216      */
217     if (vp == NULL) {
218 	error = ENOEXEC;	/* ?? */
219 	goto cleanup;
220     }
221     NDFREE(&ni, NDF_ONLY_PNBUF);
222 
223     /*
224      * From here on down, we have a locked vnode that must be unlocked.
225      */
226     locked++;
227 
228     /*
229      * Writable?
230      */
231     if (vp->v_writecount) {
232 	error = ETXTBSY;
233 	goto cleanup;
234     }
235 
236     /*
237      * Executable?
238      */
239     error = VOP_GETATTR(vp, &attr, p->p_ucred, p);
240     if (error)
241 	goto cleanup;
242 
243     if ((vp->v_mount->mnt_flag & MNT_NOEXEC) ||
244 	((attr.va_mode & 0111) == 0) ||
245 	(attr.va_type != VREG)) {
246 	    error = ENOEXEC;
247 	    goto cleanup;
248     }
249 
250     /*
251      * Sensible size?
252      */
253     if (attr.va_size == 0) {
254 	error = ENOEXEC;
255 	goto cleanup;
256     }
257 
258     /*
259      * Can we access it?
260      */
261     error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p);
262     if (error)
263 	goto cleanup;
264 
265     error = VOP_OPEN(vp, FREAD, p->p_ucred, p);
266     if (error)
267 	goto cleanup;
268 
269     /*
270      * Lock no longer needed
271      */
272     VOP_UNLOCK(vp, 0, p);
273     locked = 0;
274 
275     /*
276      * Pull in executable header into kernel_map
277      */
278     error = vm_mmap(kernel_map, (vm_offset_t *)&a_out, PAGE_SIZE,
279 	    	    VM_PROT_READ, VM_PROT_READ, 0, (caddr_t)vp, 0);
280     if (error)
281 	goto cleanup;
282 
283     /*
284      * Is it a Linux binary ?
285      */
286     if (((a_out->a_magic >> 16) & 0xff) != 0x64) {
287 	error = ENOEXEC;
288 	goto cleanup;
289     }
290 
291     /* While we are here, we should REALLY do some more checks */
292 
293     /*
294      * Set file/virtual offset based on a.out variant.
295      */
296     switch ((int)(a_out->a_magic & 0xffff)) {
297     case 0413:	/* ZMAGIC */
298 	file_offset = 1024;
299 	break;
300     case 0314:	/* QMAGIC */
301 	file_offset = 0;
302 	break;
303     default:
304 	error = ENOEXEC;
305 	goto cleanup;
306     }
307 
308     bss_size = round_page(a_out->a_bss);
309 
310     /*
311      * Check various fields in header for validity/bounds.
312      */
313     if (a_out->a_text & PAGE_MASK || a_out->a_data & PAGE_MASK) {
314 	error = ENOEXEC;
315 	goto cleanup;
316     }
317 
318     /* text + data can't exceed file size */
319     if (a_out->a_data + a_out->a_text > attr.va_size) {
320 	error = EFAULT;
321 	goto cleanup;
322     }
323 
324     /*
325      * text/data/bss must not exceed limits
326      * XXX: this is not complete. it should check current usage PLUS
327      * the resources needed by this library.
328      */
329     if (a_out->a_text > MAXTSIZ ||
330 	a_out->a_data + bss_size > p->p_rlimit[RLIMIT_DATA].rlim_cur) {
331 	error = ENOMEM;
332 	goto cleanup;
333     }
334 
335     /*
336      * prevent more writers
337      */
338     vp->v_flag |= VTEXT;
339 
340     /*
341      * Check if file_offset page aligned,.
342      * Currently we cannot handle misalinged file offsets,
343      * and so we read in the entire image (what a waste).
344      */
345     if (file_offset & PAGE_MASK) {
346 #ifdef DEBUG
347 printf("uselib: Non page aligned binary %lu\n", file_offset);
348 #endif
349 	/*
350 	 * Map text+data read/write/execute
351 	 */
352 
353 	/* a_entry is the load address and is page aligned */
354 	vmaddr = trunc_page(a_out->a_entry);
355 
356 	/* get anon user mapping, read+write+execute */
357 	error = vm_map_find(&p->p_vmspace->vm_map, NULL, 0, &vmaddr,
358 		    	    a_out->a_text + a_out->a_data, FALSE,
359 			    VM_PROT_ALL, VM_PROT_ALL, 0);
360 	if (error)
361 	    goto cleanup;
362 
363 	/* map file into kernel_map */
364 	error = vm_mmap(kernel_map, &buffer,
365 			round_page(a_out->a_text + a_out->a_data + file_offset),
366 		   	VM_PROT_READ, VM_PROT_READ, 0,
367 			(caddr_t)vp, trunc_page(file_offset));
368 	if (error)
369 	    goto cleanup;
370 
371 	/* copy from kernel VM space to user space */
372 	error = copyout((caddr_t)(void *)(uintptr_t)(buffer + file_offset),
373 			(caddr_t)vmaddr, a_out->a_text + a_out->a_data);
374 
375 	/* release temporary kernel space */
376 	vm_map_remove(kernel_map, buffer,
377 		      buffer + round_page(a_out->a_text + a_out->a_data + file_offset));
378 
379 	if (error)
380 	    goto cleanup;
381     }
382     else {
383 #ifdef DEBUG
384 printf("uselib: Page aligned binary %lu\n", file_offset);
385 #endif
386 	/*
387 	 * for QMAGIC, a_entry is 20 bytes beyond the load address
388 	 * to skip the executable header
389 	 */
390 	vmaddr = trunc_page(a_out->a_entry);
391 
392 	/*
393 	 * Map it all into the process's space as a single copy-on-write
394 	 * "data" segment.
395 	 */
396 	error = vm_mmap(&p->p_vmspace->vm_map, &vmaddr,
397 		   	a_out->a_text + a_out->a_data,
398 			VM_PROT_ALL, VM_PROT_ALL, MAP_PRIVATE | MAP_FIXED,
399 			(caddr_t)vp, file_offset);
400 	if (error)
401 	    goto cleanup;
402     }
403 #ifdef DEBUG
404 printf("mem=%08lx = %08lx %08lx\n", vmaddr, ((long*)vmaddr)[0], ((long*)vmaddr)[1]);
405 #endif
406     if (bss_size != 0) {
407         /*
408 	 * Calculate BSS start address
409 	 */
410 	vmaddr = trunc_page(a_out->a_entry) + a_out->a_text + a_out->a_data;
411 
412 	/*
413 	 * allocate some 'anon' space
414 	 */
415 	error = vm_map_find(&p->p_vmspace->vm_map, NULL, 0, &vmaddr,
416 			    bss_size, FALSE,
417 			    VM_PROT_ALL, VM_PROT_ALL, 0);
418 	if (error)
419 	    goto cleanup;
420     }
421 
422 cleanup:
423     /*
424      * Unlock vnode if needed
425      */
426     if (locked)
427 	VOP_UNLOCK(vp, 0, p);
428 
429     /*
430      * Release the kernel mapping.
431      */
432     if (a_out)
433 	vm_map_remove(kernel_map, (vm_offset_t)a_out, (vm_offset_t)a_out + PAGE_SIZE);
434 
435     return error;
436 }
437 
438 int
439 linux_newselect(struct proc *p, struct linux_newselect_args *args)
440 {
441     struct select_args bsa;
442     struct timeval tv0, tv1, utv, *tvp;
443     caddr_t sg;
444     int error;
445 
446 #ifdef DEBUG
447     printf("Linux-emul(%ld): newselect(%d, %p, %p, %p, %p)\n",
448   	(long)p->p_pid, args->nfds, (void *)args->readfds,
449 	(void *)args->writefds, (void *)args->exceptfds,
450 	(void *)args->timeout);
451 #endif
452     error = 0;
453     bsa.nd = args->nfds;
454     bsa.in = args->readfds;
455     bsa.ou = args->writefds;
456     bsa.ex = args->exceptfds;
457     bsa.tv = args->timeout;
458 
459     /*
460      * Store current time for computation of the amount of
461      * time left.
462      */
463     if (args->timeout) {
464 	if ((error = copyin(args->timeout, &utv, sizeof(utv))))
465 	    goto select_out;
466 #ifdef DEBUG
467 	printf("Linux-emul(%ld): incoming timeout (%ld/%ld)\n",
468 	    (long)p->p_pid, utv.tv_sec, utv.tv_usec);
469 #endif
470 	if (itimerfix(&utv)) {
471 	    /*
472 	     * The timeval was invalid.  Convert it to something
473 	     * valid that will act as it does under Linux.
474 	     */
475 	    sg = stackgap_init();
476 	    tvp = stackgap_alloc(&sg, sizeof(utv));
477 	    utv.tv_sec += utv.tv_usec / 1000000;
478 	    utv.tv_usec %= 1000000;
479 	    if (utv.tv_usec < 0) {
480 		utv.tv_sec -= 1;
481 		utv.tv_usec += 1000000;
482 	    }
483 	    if (utv.tv_sec < 0)
484 		timevalclear(&utv);
485 	    if ((error = copyout(&utv, tvp, sizeof(utv))))
486 		goto select_out;
487 	    bsa.tv = tvp;
488 	}
489 	microtime(&tv0);
490     }
491 
492     error = select(p, &bsa);
493 #ifdef DEBUG
494     printf("Linux-emul(%ld): real select returns %d\n", (long)p->p_pid, error);
495 #endif
496 
497     if (error) {
498 	/*
499 	 * See fs/select.c in the Linux kernel.  Without this,
500 	 * Maelstrom doesn't work.
501 	 */
502 	if (error == ERESTART)
503 	    error = EINTR;
504 	goto select_out;
505     }
506 
507     if (args->timeout) {
508 	if (p->p_retval[0]) {
509 	    /*
510 	     * Compute how much time was left of the timeout,
511 	     * by subtracting the current time and the time
512 	     * before we started the call, and subtracting
513 	     * that result from the user-supplied value.
514 	     */
515 	    microtime(&tv1);
516 	    timevalsub(&tv1, &tv0);
517 	    timevalsub(&utv, &tv1);
518 	    if (utv.tv_sec < 0)
519 		timevalclear(&utv);
520 	} else
521 	    timevalclear(&utv);
522 #ifdef DEBUG
523 	printf("Linux-emul(%ld): outgoing timeout (%ld/%ld)\n",
524 	    (long)p->p_pid, utv.tv_sec, utv.tv_usec);
525 #endif
526 	if ((error = copyout(&utv, args->timeout, sizeof(utv))))
527 	    goto select_out;
528     }
529 
530 select_out:
531 #ifdef DEBUG
532     printf("Linux-emul(%ld): newselect_out -> %d\n", (long)p->p_pid, error);
533 #endif
534     return error;
535 }
536 
537 int
538 linux_getpgid(struct proc *p, struct linux_getpgid_args *args)
539 {
540     struct proc *curp;
541 
542 #ifdef DEBUG
543     printf("Linux-emul(%ld): getpgid(%d)\n", (long)p->p_pid, args->pid);
544 #endif
545     if (args->pid != p->p_pid) {
546 	if (!(curp = pfind(args->pid)))
547 	    return ESRCH;
548     }
549     else
550 	curp = p;
551     p->p_retval[0] = curp->p_pgid;
552     return 0;
553 }
554 
555 int
556 linux_mremap(struct proc *p, struct linux_mremap_args *args)
557 {
558 	struct munmap_args /* {
559 		void *addr;
560 		size_t len;
561 	} */ bsd_args;
562 	int error = 0;
563 
564 #ifdef DEBUG
565 	printf("Linux-emul(%ld): mremap(%p, %08lx, %08lx, %08lx)\n",
566 	    (long)p->p_pid, (void *)args->addr,
567 	    (unsigned long)args->old_len,
568 	    (unsigned long)args->new_len,
569 	    (unsigned long)args->flags);
570 #endif
571 	args->new_len = round_page(args->new_len);
572 	args->old_len = round_page(args->old_len);
573 
574 	if (args->new_len > args->old_len) {
575 		p->p_retval[0] = 0;
576 		return ENOMEM;
577 	}
578 
579 	if (args->new_len < args->old_len) {
580 		bsd_args.addr = args->addr + args->new_len;
581 		bsd_args.len = args->old_len - args->new_len;
582 		error = munmap(p, &bsd_args);
583 	}
584 
585 	p->p_retval[0] = error ? 0 : (u_long)args->addr;
586 	return error;
587 }
588 
589 int
590 linux_msync(struct proc *p, struct linux_msync_args *args)
591 {
592 	struct msync_args bsd_args;
593 
594 	bsd_args.addr = args->addr;
595 	bsd_args.len = args->len;
596 	bsd_args.flags = 0;	/* XXX ignore */
597 
598 	return msync(p, &bsd_args);
599 }
600 
601 #ifndef __alpha__
602 int
603 linux_time(struct proc *p, struct linux_time_args *args)
604 {
605     struct timeval tv;
606     linux_time_t tm;
607     int error;
608 
609 #ifdef DEBUG
610     printf("Linux-emul(%ld): time(*)\n", (long)p->p_pid);
611 #endif
612     microtime(&tv);
613     tm = tv.tv_sec;
614     if (args->tm && (error = copyout(&tm, args->tm, sizeof(linux_time_t))))
615 	return error;
616     p->p_retval[0] = tm;
617     return 0;
618 }
619 #endif	/*!__alpha__*/
620 
621 struct linux_times_argv {
622     long    tms_utime;
623     long    tms_stime;
624     long    tms_cutime;
625     long    tms_cstime;
626 };
627 
628 #define CLK_TCK 100	/* Linux uses 100 */
629 #define CONVTCK(r)	(r.tv_sec * CLK_TCK + r.tv_usec / (1000000 / CLK_TCK))
630 
631 int
632 linux_times(struct proc *p, struct linux_times_args *args)
633 {
634     struct timeval tv;
635     struct linux_times_argv tms;
636     struct rusage ru;
637     int error;
638 
639 #ifdef DEBUG
640     printf("Linux-emul(%ld): times(*)\n", (long)p->p_pid);
641 #endif
642     calcru(p, &ru.ru_utime, &ru.ru_stime, NULL);
643 
644     tms.tms_utime = CONVTCK(ru.ru_utime);
645     tms.tms_stime = CONVTCK(ru.ru_stime);
646 
647     tms.tms_cutime = CONVTCK(p->p_stats->p_cru.ru_utime);
648     tms.tms_cstime = CONVTCK(p->p_stats->p_cru.ru_stime);
649 
650     if ((error = copyout((caddr_t)&tms, (caddr_t)args->buf,
651 	    	    sizeof(struct linux_times_argv))))
652 	return error;
653 
654     microuptime(&tv);
655     p->p_retval[0] = (int)CONVTCK(tv);
656     return 0;
657 }
658 
659 int
660 linux_newuname(struct proc *p, struct linux_newuname_args *args)
661 {
662 	struct linux_new_utsname utsname;
663 	char *osrelease, *osname;
664 
665 #ifdef DEBUG
666 	printf("Linux-emul(%ld): newuname(*)\n", (long)p->p_pid);
667 #endif
668 
669 	osname = linux_get_osname(p);
670 	osrelease = linux_get_osrelease(p);
671 
672 	bzero(&utsname, sizeof(struct linux_new_utsname));
673 	strncpy(utsname.sysname, osname, LINUX_MAX_UTSNAME-1);
674 	strncpy(utsname.nodename, hostname, LINUX_MAX_UTSNAME-1);
675 	strncpy(utsname.release, osrelease, LINUX_MAX_UTSNAME-1);
676 	strncpy(utsname.version, version, LINUX_MAX_UTSNAME-1);
677 	strncpy(utsname.machine, machine, LINUX_MAX_UTSNAME-1);
678 	strncpy(utsname.domainname, domainname, LINUX_MAX_UTSNAME-1);
679 
680 	return (copyout((caddr_t)&utsname, (caddr_t)args->buf,
681 			sizeof(struct linux_new_utsname)));
682 }
683 
684 struct linux_utimbuf {
685 	linux_time_t l_actime;
686 	linux_time_t l_modtime;
687 };
688 
689 int
690 linux_utime(struct proc *p, struct linux_utime_args *args)
691 {
692     struct utimes_args /* {
693 	char	*path;
694 	struct	timeval *tptr;
695     } */ bsdutimes;
696     struct timeval tv[2], *tvp;
697     struct linux_utimbuf lut;
698     int error;
699     caddr_t sg;
700 
701     sg = stackgap_init();
702     CHECKALTEXIST(p, &sg, args->fname);
703 
704 #ifdef DEBUG
705     printf("Linux-emul(%ld): utime(%s, *)\n", (long)p->p_pid, args->fname);
706 #endif
707     if (args->times) {
708 	if ((error = copyin(args->times, &lut, sizeof lut)))
709 	    return error;
710 	tv[0].tv_sec = lut.l_actime;
711 	tv[0].tv_usec = 0;
712 	tv[1].tv_sec = lut.l_modtime;
713 	tv[1].tv_usec = 0;
714 	/* so that utimes can copyin */
715 	tvp = (struct timeval *)stackgap_alloc(&sg, sizeof(tv));
716 	if (tvp == NULL)
717 		return (ENAMETOOLONG);
718 	if ((error = copyout(tv, tvp, sizeof(tv))))
719 	    return error;
720 	bsdutimes.tptr = tvp;
721     } else
722 	bsdutimes.tptr = NULL;
723 
724     bsdutimes.path = args->fname;
725     return utimes(p, &bsdutimes);
726 }
727 
728 #define __WCLONE 0x80000000
729 
730 #ifndef __alpha__
731 int
732 linux_waitpid(struct proc *p, struct linux_waitpid_args *args)
733 {
734     struct wait_args /* {
735 	int pid;
736 	int *status;
737 	int options;
738 	struct	rusage *rusage;
739     } */ tmp;
740     int error, tmpstat;
741 
742 #ifdef DEBUG
743     printf("Linux-emul(%ld): waitpid(%d, %p, %d)\n",
744 	(long)p->p_pid, args->pid, (void *)args->status, args->options);
745 #endif
746     tmp.pid = args->pid;
747     tmp.status = args->status;
748     tmp.options = (args->options & (WNOHANG | WUNTRACED));
749     /* WLINUXCLONE should be equal to __WCLONE, but we make sure */
750     if (args->options & __WCLONE)
751 	tmp.options |= WLINUXCLONE;
752     tmp.rusage = NULL;
753 
754     if ((error = wait4(p, &tmp)) != 0)
755 	return error;
756 
757     if (args->status) {
758 	if ((error = copyin(args->status, &tmpstat, sizeof(int))) != 0)
759 	    return error;
760 	tmpstat &= 0xffff;
761 	if (WIFSIGNALED(tmpstat))
762 	    tmpstat = (tmpstat & 0xffffff80) |
763 		      BSD_TO_LINUX_SIGNAL(WTERMSIG(tmpstat));
764 	else if (WIFSTOPPED(tmpstat))
765 	    tmpstat = (tmpstat & 0xffff00ff) |
766 		      (BSD_TO_LINUX_SIGNAL(WSTOPSIG(tmpstat)) << 8);
767 	return copyout(&tmpstat, args->status, sizeof(int));
768     } else
769 	return 0;
770 }
771 #endif	/*!__alpha__*/
772 
773 int
774 linux_wait4(struct proc *p, struct linux_wait4_args *args)
775 {
776     struct wait_args /* {
777 	int pid;
778 	int *status;
779 	int options;
780 	struct	rusage *rusage;
781     } */ tmp;
782     int error, tmpstat;
783 
784 #ifdef DEBUG
785     printf("Linux-emul(%ld): wait4(%d, %p, %d, %p)\n",
786 	(long)p->p_pid, args->pid, (void *)args->status, args->options,
787 	(void *)args->rusage);
788 #endif
789     tmp.pid = args->pid;
790     tmp.status = args->status;
791     tmp.options = (args->options & (WNOHANG | WUNTRACED));
792     /* WLINUXCLONE should be equal to __WCLONE, but we make sure */
793     if (args->options & __WCLONE)
794 	tmp.options |= WLINUXCLONE;
795     tmp.rusage = args->rusage;
796 
797     if ((error = wait4(p, &tmp)) != 0)
798 	return error;
799 
800     SIGDELSET(p->p_siglist, SIGCHLD);
801 
802     if (args->status) {
803 	if ((error = copyin(args->status, &tmpstat, sizeof(int))) != 0)
804 	    return error;
805 	tmpstat &= 0xffff;
806 	if (WIFSIGNALED(tmpstat))
807 	    tmpstat = (tmpstat & 0xffffff80) |
808 		  BSD_TO_LINUX_SIGNAL(WTERMSIG(tmpstat));
809 	else if (WIFSTOPPED(tmpstat))
810 	    tmpstat = (tmpstat & 0xffff00ff) |
811 		  (BSD_TO_LINUX_SIGNAL(WSTOPSIG(tmpstat)) << 8);
812 	return copyout(&tmpstat, args->status, sizeof(int));
813     } else
814 	return 0;
815 }
816 
817 int
818 linux_mknod(struct proc *p, struct linux_mknod_args *args)
819 {
820 	caddr_t sg;
821 	struct mknod_args bsd_mknod;
822 	struct mkfifo_args bsd_mkfifo;
823 
824 	sg = stackgap_init();
825 
826 	CHECKALTCREAT(p, &sg, args->path);
827 
828 #ifdef DEBUG
829 	printf("Linux-emul(%ld): mknod(%s, %d, %d)\n",
830 	   (long)p->p_pid, args->path, args->mode, args->dev);
831 #endif
832 
833 	if (args->mode & S_IFIFO) {
834 		bsd_mkfifo.path = args->path;
835 		bsd_mkfifo.mode = args->mode;
836 		return mkfifo(p, &bsd_mkfifo);
837 	} else {
838 		bsd_mknod.path = args->path;
839 		bsd_mknod.mode = args->mode;
840 		bsd_mknod.dev = args->dev;
841 		return mknod(p, &bsd_mknod);
842 	}
843 }
844 
845 /*
846  * UGH! This is just about the dumbest idea I've ever heard!!
847  */
848 int
849 linux_personality(struct proc *p, struct linux_personality_args *args)
850 {
851 #ifdef DEBUG
852 	printf("Linux-emul(%ld): personality(%d)\n",
853 	   (long)p->p_pid, args->per);
854 #endif
855 #ifndef __alpha__
856 	if (args->per != 0)
857 		return EINVAL;
858 #endif
859 
860 	/* Yes Jim, it's still a Linux... */
861 	p->p_retval[0] = 0;
862 	return 0;
863 }
864 
865 /*
866  * Wrappers for get/setitimer for debugging..
867  */
868 int
869 linux_setitimer(struct proc *p, struct linux_setitimer_args *args)
870 {
871 	struct setitimer_args bsa;
872 	struct itimerval foo;
873 	int error;
874 
875 #ifdef DEBUG
876 	printf("Linux-emul(%ld): setitimer(%p, %p)\n",
877 	    (long)p->p_pid, (void *)args->itv, (void *)args->oitv);
878 #endif
879 	bsa.which = args->which;
880 	bsa.itv = args->itv;
881 	bsa.oitv = args->oitv;
882 	if (args->itv) {
883 	    if ((error = copyin((caddr_t)args->itv, (caddr_t)&foo,
884 			sizeof(foo))))
885 		return error;
886 #ifdef DEBUG
887 	    printf("setitimer: value: sec: %ld, usec: %ld\n",
888 		foo.it_value.tv_sec, foo.it_value.tv_usec);
889 	    printf("setitimer: interval: sec: %ld, usec: %ld\n",
890 		foo.it_interval.tv_sec, foo.it_interval.tv_usec);
891 #endif
892 	}
893 	return setitimer(p, &bsa);
894 }
895 
896 int
897 linux_getitimer(struct proc *p, struct linux_getitimer_args *args)
898 {
899 	struct getitimer_args bsa;
900 #ifdef DEBUG
901 	printf("Linux-emul(%ld): getitimer(%p)\n",
902 	    (long)p->p_pid, (void *)args->itv);
903 #endif
904 	bsa.which = args->which;
905 	bsa.itv = args->itv;
906 	return getitimer(p, &bsa);
907 }
908 
909 #ifndef __alpha__
910 int
911 linux_nice(struct proc *p, struct linux_nice_args *args)
912 {
913 	struct setpriority_args	bsd_args;
914 
915 	bsd_args.which = PRIO_PROCESS;
916 	bsd_args.who = 0;	/* current process */
917 	bsd_args.prio = args->inc;
918 	return setpriority(p, &bsd_args);
919 }
920 #endif	/*!__alpha__*/
921 
922 int
923 linux_setgroups(p, uap)
924 	struct proc *p;
925 	struct linux_setgroups_args *uap;
926 {
927 	struct pcred *pc;
928 	linux_gid_t linux_gidset[NGROUPS];
929 	gid_t *bsd_gidset;
930 	int ngrp, error;
931 
932 	pc = p->p_cred;
933 	ngrp = uap->gidsetsize;
934 
935 	/*
936 	 * cr_groups[0] holds egid. Setting the whole set from
937 	 * the supplied set will cause egid to be changed too.
938 	 * Keep cr_groups[0] unchanged to prevent that.
939 	 */
940 
941 	if ((error = suser(p)) != 0)
942 		return (error);
943 
944 	if (ngrp >= NGROUPS)
945 		return (EINVAL);
946 
947 	pc->pc_ucred = crcopy(pc->pc_ucred);
948 	if (ngrp > 0) {
949 		error = copyin((caddr_t)uap->gidset, (caddr_t)linux_gidset,
950 			       ngrp * sizeof(linux_gid_t));
951 		if (error)
952 			return (error);
953 
954 		pc->pc_ucred->cr_ngroups = ngrp + 1;
955 
956 		bsd_gidset = pc->pc_ucred->cr_groups;
957 		ngrp--;
958 		while (ngrp >= 0) {
959 			bsd_gidset[ngrp + 1] = linux_gidset[ngrp];
960 			ngrp--;
961 		}
962 	}
963 	else
964 		pc->pc_ucred->cr_ngroups = 1;
965 
966 	setsugid(p);
967 	return (0);
968 }
969 
970 int
971 linux_getgroups(p, uap)
972 	struct proc *p;
973 	struct linux_getgroups_args *uap;
974 {
975 	struct pcred *pc;
976 	linux_gid_t linux_gidset[NGROUPS];
977 	gid_t *bsd_gidset;
978 	int bsd_gidsetsz, ngrp, error;
979 
980 	pc = p->p_cred;
981 	bsd_gidset = pc->pc_ucred->cr_groups;
982 	bsd_gidsetsz = pc->pc_ucred->cr_ngroups - 1;
983 
984 	/*
985 	 * cr_groups[0] holds egid. Returning the whole set
986 	 * here will cause a duplicate. Exclude cr_groups[0]
987 	 * to prevent that.
988 	 */
989 
990 	if ((ngrp = uap->gidsetsize) == 0) {
991 		p->p_retval[0] = bsd_gidsetsz;
992 		return (0);
993 	}
994 
995 	if (ngrp < bsd_gidsetsz)
996 		return (EINVAL);
997 
998 	ngrp = 0;
999 	while (ngrp < bsd_gidsetsz) {
1000 		linux_gidset[ngrp] = bsd_gidset[ngrp + 1];
1001 		ngrp++;
1002 	}
1003 
1004 	if ((error = copyout((caddr_t)linux_gidset, (caddr_t)uap->gidset,
1005 	    ngrp * sizeof(linux_gid_t))))
1006 		return (error);
1007 
1008 	p->p_retval[0] = ngrp;
1009 	return (0);
1010 }
1011 
1012 #ifndef __alpha__
1013 int
1014 linux_setrlimit(p, uap)
1015 	struct proc *p;
1016 	struct linux_setrlimit_args *uap;
1017 {
1018 	struct __setrlimit_args bsd;
1019 	struct linux_rlimit rlim;
1020 	int error;
1021 	caddr_t sg = stackgap_init();
1022 
1023 #ifdef DEBUG
1024 	printf("Linux-emul(%ld): setrlimit(%d, %p)\n", (long)p->p_pid,
1025 	    uap->resource, (void *)uap->rlim);
1026 #endif
1027 
1028 	if (uap->resource >= LINUX_RLIM_NLIMITS)
1029 		return (EINVAL);
1030 
1031 	bsd.which = linux_to_bsd_resource[uap->resource];
1032 	if (bsd.which == -1)
1033 		return (EINVAL);
1034 
1035 	error = copyin(uap->rlim, &rlim, sizeof(rlim));
1036 	if (error)
1037 		return (error);
1038 
1039 	bsd.rlp = stackgap_alloc(&sg, sizeof(struct rlimit));
1040 	bsd.rlp->rlim_cur = (rlim_t)rlim.rlim_cur;
1041 	bsd.rlp->rlim_max = (rlim_t)rlim.rlim_max;
1042 	return (setrlimit(p, &bsd));
1043 }
1044 
1045 int
1046 linux_getrlimit(p, uap)
1047 	struct proc *p;
1048 	struct linux_getrlimit_args *uap;
1049 {
1050 	struct __getrlimit_args bsd;
1051 	struct linux_rlimit rlim;
1052 	int error;
1053 	caddr_t sg = stackgap_init();
1054 
1055 #ifdef DEBUG
1056 	printf("Linux-emul(%ld): getrlimit(%d, %p)\n", (long)p->p_pid,
1057 	    uap->resource, (void *)uap->rlim);
1058 #endif
1059 
1060 	if (uap->resource >= LINUX_RLIM_NLIMITS)
1061 		return (EINVAL);
1062 
1063 	bsd.which = linux_to_bsd_resource[uap->resource];
1064 	if (bsd.which == -1)
1065 		return (EINVAL);
1066 
1067 	bsd.rlp = stackgap_alloc(&sg, sizeof(struct rlimit));
1068 	error = getrlimit(p, &bsd);
1069 	if (error)
1070 		return (error);
1071 
1072 	rlim.rlim_cur = (unsigned long)bsd.rlp->rlim_cur;
1073 	if (rlim.rlim_cur == ULONG_MAX)
1074 		rlim.rlim_cur = LONG_MAX;
1075 	rlim.rlim_max = (unsigned long)bsd.rlp->rlim_max;
1076 	if (rlim.rlim_max == ULONG_MAX)
1077 		rlim.rlim_max = LONG_MAX;
1078 	return (copyout(&rlim, uap->rlim, sizeof(rlim)));
1079 }
1080 #endif /*!__alpha__*/
1081 
1082 int
1083 linux_sched_setscheduler(p, uap)
1084 	struct proc *p;
1085 	struct linux_sched_setscheduler_args *uap;
1086 {
1087 	struct sched_setscheduler_args bsd;
1088 
1089 #ifdef DEBUG
1090 	printf("Linux-emul(%ld): sched_setscheduler(%d, %d, %p)\n",
1091 	    (long)p->p_pid, uap->pid, uap->policy, (const void *)uap->param);
1092 #endif
1093 
1094 	switch (uap->policy) {
1095 	case LINUX_SCHED_OTHER:
1096 		bsd.policy = SCHED_OTHER;
1097 		break;
1098 	case LINUX_SCHED_FIFO:
1099 		bsd.policy = SCHED_FIFO;
1100 		break;
1101 	case LINUX_SCHED_RR:
1102 		bsd.policy = SCHED_RR;
1103 		break;
1104 	default:
1105 		return EINVAL;
1106 	}
1107 
1108 	bsd.pid = uap->pid;
1109 	bsd.param = uap->param;
1110 	return sched_setscheduler(p, &bsd);
1111 }
1112 
1113 int
1114 linux_sched_getscheduler(p, uap)
1115 	struct proc *p;
1116 	struct linux_sched_getscheduler_args *uap;
1117 {
1118 	struct sched_getscheduler_args bsd;
1119 	int error;
1120 
1121 #ifdef DEBUG
1122 	printf("Linux-emul(%ld): sched_getscheduler(%d)\n",
1123 	       (long)p->p_pid, uap->pid);
1124 #endif
1125 
1126 	bsd.pid = uap->pid;
1127 	error = sched_getscheduler(p, &bsd);
1128 
1129 	switch (p->p_retval[0]) {
1130 	case SCHED_OTHER:
1131 		p->p_retval[0] = LINUX_SCHED_OTHER;
1132 		break;
1133 	case SCHED_FIFO:
1134 		p->p_retval[0] = LINUX_SCHED_FIFO;
1135 		break;
1136 	case SCHED_RR:
1137 		p->p_retval[0] = LINUX_SCHED_RR;
1138 		break;
1139 	}
1140 
1141 	return error;
1142 }
1143