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