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