| Commit | Line | Data |
|---|---|---|
| 984263bc MD |
1 | /*- |
| 2 | * Copyright (c) 1994-1995 Søren Schmidt | |
| 3 | * All rights reserved. | |
| 4 | * | |
| 5 | * Redistribution and use in source and binary forms, with or without | |
| 6 | * modification, are permitted provided that the following conditions | |
| 7 | * are met: | |
| 8 | * 1. Redistributions of source code must retain the above copyright | |
| 9 | * notice, this list of conditions and the following disclaimer | |
| 10 | * in this position and unchanged. | |
| 11 | * 2. Redistributions in binary form must reproduce the above copyright | |
| 12 | * notice, this list of conditions and the following disclaimer in the | |
| 13 | * documentation and/or other materials provided with the distribution. | |
| 14 | * 3. The name of the author may not be used to endorse or promote products | |
| 15 | * derived from this software withough specific prior written permission | |
| 16 | * | |
| 17 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | |
| 18 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |
| 19 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | |
| 20 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | |
| 21 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | |
| 22 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
| 23 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
| 24 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
| 25 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | |
| 26 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| 27 | * | |
| 28 | * $FreeBSD: src/sys/compat/linux/linux_misc.c,v 1.85.2.9 2002/09/24 08:11:41 mdodd Exp $ | |
| 3eb2971d | 29 | * $DragonFly: src/sys/emulation/linux/linux_misc.c,v 1.39 2007/06/26 19:31:03 dillon Exp $ |
| 984263bc MD |
30 | */ |
| 31 | ||
| 32 | #include "opt_compat.h" | |
| 33 | ||
| 34 | #include <sys/param.h> | |
| 35 | #include <sys/systm.h> | |
| 36 | #include <sys/fcntl.h> | |
| 37 | #include <sys/imgact_aout.h> | |
| 38 | #include <sys/kernel.h> | |
| 9697c509 | 39 | #include <sys/kern_syscall.h> |
| 984263bc MD |
40 | #include <sys/lock.h> |
| 41 | #include <sys/mman.h> | |
| 42 | #include <sys/mount.h> | |
| 984263bc MD |
43 | #include <sys/poll.h> |
| 44 | #include <sys/proc.h> | |
| 895c1f85 | 45 | #include <sys/priv.h> |
| fad57d0e | 46 | #include <sys/nlookup.h> |
| 984263bc MD |
47 | #include <sys/blist.h> |
| 48 | #include <sys/reboot.h> | |
| 49 | #include <sys/resourcevar.h> | |
| 50 | #include <sys/signalvar.h> | |
| b1b4e5a6 | 51 | #include <sys/signal2.h> |
| 984263bc MD |
52 | #include <sys/stat.h> |
| 53 | #include <sys/sysctl.h> | |
| 54 | #include <sys/sysproto.h> | |
| 55 | #include <sys/time.h> | |
| 56 | #include <sys/unistd.h> | |
| 57 | #include <sys/vmmeter.h> | |
| 58 | #include <sys/vnode.h> | |
| 59 | #include <sys/wait.h> | |
| 0563a974 | 60 | #include <sys/thread2.h> |
| 984263bc MD |
61 | |
| 62 | #include <vm/vm.h> | |
| 63 | #include <vm/pmap.h> | |
| 64 | #include <vm/vm_kern.h> | |
| 65 | #include <vm/vm_map.h> | |
| 66 | #include <vm/vm_extern.h> | |
| 67 | #include <vm/vm_object.h> | |
| 68 | #include <vm/vm_zone.h> | |
| 69 | #include <vm/swap_pager.h> | |
| 70 | ||
| 71 | #include <machine/frame.h> | |
| 72 | #include <machine/limits.h> | |
| 73 | #include <machine/psl.h> | |
| 74 | #include <machine/sysarch.h> | |
| 75 | #ifdef __i386__ | |
| 76 | #include <machine/segments.h> | |
| 77 | #endif | |
| 78 | ||
| 3eb2971d | 79 | #include <sys/sched.h> |
| 984263bc | 80 | |
| 0d88b32b | 81 | #include <emulation/linux/linux_sysproto.h> |
| 932f49b9 MD |
82 | #include <arch_linux/linux.h> |
| 83 | #include <arch_linux/linux_proto.h> | |
| 1f2de5d4 MD |
84 | #include "linux_mib.h" |
| 85 | #include "linux_util.h" | |
| 984263bc | 86 | |
| 984263bc MD |
87 | #define BSD_TO_LINUX_SIGNAL(sig) \ |
| 88 | (((sig) <= LINUX_SIGTBLSZ) ? bsd_to_linux_signal[_SIG_IDX(sig)] : sig) | |
| 984263bc | 89 | |
| 984263bc MD |
90 | static unsigned int linux_to_bsd_resource[LINUX_RLIM_NLIMITS] = { |
| 91 | RLIMIT_CPU, RLIMIT_FSIZE, RLIMIT_DATA, RLIMIT_STACK, | |
| 92 | RLIMIT_CORE, RLIMIT_RSS, RLIMIT_NPROC, RLIMIT_NOFILE, | |
| 93 | RLIMIT_MEMLOCK, -1 | |
| 94 | }; | |
| 984263bc MD |
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 | }; | |
| 237fd8ef | 108 | |
| 984263bc | 109 | int |
| 753fd850 | 110 | sys_linux_sysinfo(struct linux_sysinfo_args *args) |
| 984263bc MD |
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 | ||
| 31c33cf2 | 138 | sysinfo.totalram = Maxmem * PAGE_SIZE; |
| 12e4aaff | 139 | sysinfo.freeram = sysinfo.totalram - vmstats.v_wire_count * PAGE_SIZE; |
| 984263bc MD |
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 | } | |
| 984263bc | 162 | |
| 984263bc | 163 | int |
| 753fd850 | 164 | sys_linux_alarm(struct linux_alarm_args *args) |
| 984263bc | 165 | { |
| dadab5e9 MD |
166 | struct thread *td = curthread; |
| 167 | struct proc *p = td->td_proc; | |
| 984263bc MD |
168 | struct itimerval it, old_it; |
| 169 | struct timeval tv; | |
| 984263bc | 170 | |
| dadab5e9 MD |
171 | KKASSERT(p); |
| 172 | ||
| 984263bc MD |
173 | #ifdef DEBUG |
| 174 | if (ldebug(alarm)) | |
| 26be20a0 | 175 | kprintf(ARGS(alarm, "%u"), args->secs); |
| 984263bc MD |
176 | #endif |
| 177 | ||
| 178 | if (args->secs > 100000000) | |
| 179 | return EINVAL; | |
| 180 | ||
| 181 | it.it_value.tv_sec = (long)args->secs; | |
| 182 | it.it_value.tv_usec = 0; | |
| 183 | it.it_interval.tv_sec = 0; | |
| 184 | it.it_interval.tv_usec = 0; | |
| 0563a974 | 185 | crit_enter(); |
| 984263bc MD |
186 | old_it = p->p_realtimer; |
| 187 | getmicrouptime(&tv); | |
| 188 | if (timevalisset(&old_it.it_value)) | |
| 8fbf9130 | 189 | callout_stop(&p->p_ithandle); |
| 984263bc | 190 | if (it.it_value.tv_sec != 0) { |
| 8fbf9130 JS |
191 | callout_reset(&p->p_ithandle, tvtohz_high(&it.it_value), |
| 192 | realitexpire, p); | |
| 984263bc MD |
193 | timevaladd(&it.it_value, &tv); |
| 194 | } | |
| 195 | p->p_realtimer = it; | |
| 0563a974 | 196 | crit_exit(); |
| 984263bc MD |
197 | if (timevalcmp(&old_it.it_value, &tv, >)) { |
| 198 | timevalsub(&old_it.it_value, &tv); | |
| 199 | if (old_it.it_value.tv_usec != 0) | |
| 200 | old_it.it_value.tv_sec++; | |
| c7114eea | 201 | args->sysmsg_result = old_it.it_value.tv_sec; |
| 984263bc MD |
202 | } |
| 203 | return 0; | |
| 204 | } | |
| 984263bc MD |
205 | |
| 206 | int | |
| 753fd850 | 207 | sys_linux_brk(struct linux_brk_args *args) |
| 984263bc | 208 | { |
| dadab5e9 MD |
209 | struct thread *td = curthread; |
| 210 | struct proc *p = td->td_proc; | |
| 211 | struct vmspace *vm; | |
| 984263bc | 212 | vm_offset_t new, old; |
| 90b9818c | 213 | struct obreak_args bsd_args; |
| 984263bc | 214 | |
| dadab5e9 MD |
215 | KKASSERT(p); |
| 216 | vm = p->p_vmspace; | |
| 984263bc MD |
217 | #ifdef DEBUG |
| 218 | if (ldebug(brk)) | |
| 26be20a0 | 219 | kprintf(ARGS(brk, "%p"), (void *)args->dsend); |
| 984263bc MD |
220 | #endif |
| 221 | old = (vm_offset_t)vm->vm_daddr + ctob(vm->vm_dsize); | |
| 222 | new = (vm_offset_t)args->dsend; | |
| c7114eea | 223 | bsd_args.sysmsg_result = 0; |
| 90b9818c | 224 | bsd_args.nsize = (char *) new; |
| c7114eea | 225 | bsd_args.sysmsg_result = 0; |
| 753fd850 | 226 | if (((caddr_t)new > vm->vm_daddr) && !sys_obreak(&bsd_args)) |
| c7114eea | 227 | args->sysmsg_result = (long)new; |
| 984263bc | 228 | else |
| c7114eea | 229 | args->sysmsg_result = (long)old; |
| 984263bc MD |
230 | |
| 231 | return 0; | |
| 232 | } | |
| 233 | ||
| 234 | int | |
| 753fd850 | 235 | sys_linux_uselib(struct linux_uselib_args *args) |
| 984263bc | 236 | { |
| dadab5e9 MD |
237 | struct thread *td = curthread; |
| 238 | struct proc *p; | |
| fad57d0e | 239 | struct nlookupdata nd; |
| 984263bc MD |
240 | struct vnode *vp; |
| 241 | struct exec *a_out; | |
| 242 | struct vattr attr; | |
| 243 | vm_offset_t vmaddr; | |
| 244 | unsigned long file_offset; | |
| 245 | vm_offset_t buffer; | |
| 246 | unsigned long bss_size; | |
| 247 | int error; | |
| 984263bc | 248 | int locked; |
| 136178b3 | 249 | char *path; |
| 984263bc | 250 | |
| dadab5e9 MD |
251 | KKASSERT(td->td_proc); |
| 252 | p = td->td_proc; | |
| 253 | ||
| 136178b3 DRJ |
254 | error = linux_copyin_path(args->library, &path, LINUX_PATH_EXISTS); |
| 255 | if (error) | |
| 256 | return (error); | |
| 984263bc MD |
257 | #ifdef DEBUG |
| 258 | if (ldebug(uselib)) | |
| 26be20a0 | 259 | kprintf(ARGS(uselib, "%s"), path); |
| 984263bc MD |
260 | #endif |
| 261 | ||
| 262 | a_out = NULL; | |
| 263 | locked = 0; | |
| 264 | vp = NULL; | |
| 265 | ||
| fad57d0e | 266 | error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW); |
| 3a907475 | 267 | nd.nl_flags |= NLC_EXEC; |
| fad57d0e MD |
268 | if (error == 0) |
| 269 | error = nlookup(&nd); | |
| 270 | if (error == 0) | |
| 28623bf9 | 271 | error = cache_vget(&nd.nl_nch, nd.nl_cred, LK_EXCLUSIVE, &vp); |
| 984263bc MD |
272 | if (error) |
| 273 | goto cleanup; | |
| 984263bc MD |
274 | /* |
| 275 | * From here on down, we have a locked vnode that must be unlocked. | |
| 276 | */ | |
| fad57d0e | 277 | locked = 1; |
| 984263bc MD |
278 | |
| 279 | /* Writable? */ | |
| 280 | if (vp->v_writecount) { | |
| 281 | error = ETXTBSY; | |
| 282 | goto cleanup; | |
| 283 | } | |
| 284 | ||
| 285 | /* Executable? */ | |
| 87de5057 | 286 | error = VOP_GETATTR(vp, &attr); |
| 984263bc MD |
287 | if (error) |
| 288 | goto cleanup; | |
| 289 | ||
| 290 | if ((vp->v_mount->mnt_flag & MNT_NOEXEC) || | |
| 291 | ((attr.va_mode & 0111) == 0) || (attr.va_type != VREG)) { | |
| 292 | error = ENOEXEC; | |
| 293 | goto cleanup; | |
| 294 | } | |
| 295 | ||
| 296 | /* Sensible size? */ | |
| 297 | if (attr.va_size == 0) { | |
| 298 | error = ENOEXEC; | |
| 299 | goto cleanup; | |
| 300 | } | |
| 301 | ||
| 87de5057 | 302 | error = VOP_OPEN(vp, FREAD, p->p_ucred, NULL); |
| 984263bc MD |
303 | if (error) |
| 304 | goto cleanup; | |
| 305 | ||
| 306 | /* | |
| 307 | * Lock no longer needed | |
| 308 | */ | |
| a11aaa81 | 309 | vn_unlock(vp); |
| 984263bc MD |
310 | locked = 0; |
| 311 | ||
| 312 | /* Pull in executable header into kernel_map */ | |
| e4846942 | 313 | error = vm_mmap(&kernel_map, (vm_offset_t *)&a_out, PAGE_SIZE, |
| 984263bc MD |
314 | VM_PROT_READ, VM_PROT_READ, 0, (caddr_t)vp, 0); |
| 315 | if (error) | |
| 316 | goto cleanup; | |
| 317 | ||
| 318 | /* Is it a Linux binary ? */ | |
| 319 | if (((a_out->a_magic >> 16) & 0xff) != 0x64) { | |
| 320 | error = ENOEXEC; | |
| 321 | goto cleanup; | |
| 322 | } | |
| 323 | ||
| 324 | /* | |
| 325 | * While we are here, we should REALLY do some more checks | |
| 326 | */ | |
| 327 | ||
| 328 | /* Set file/virtual offset based on a.out variant. */ | |
| 329 | switch ((int)(a_out->a_magic & 0xffff)) { | |
| 330 | case 0413: /* ZMAGIC */ | |
| 331 | file_offset = 1024; | |
| 332 | break; | |
| 333 | case 0314: /* QMAGIC */ | |
| 334 | file_offset = 0; | |
| 335 | break; | |
| 336 | default: | |
| 337 | error = ENOEXEC; | |
| 338 | goto cleanup; | |
| 339 | } | |
| 340 | ||
| 341 | bss_size = round_page(a_out->a_bss); | |
| 342 | ||
| 343 | /* Check various fields in header for validity/bounds. */ | |
| 344 | if (a_out->a_text & PAGE_MASK || a_out->a_data & PAGE_MASK) { | |
| 345 | error = ENOEXEC; | |
| 346 | goto cleanup; | |
| 347 | } | |
| 348 | ||
| 349 | /* text + data can't exceed file size */ | |
| 350 | if (a_out->a_data + a_out->a_text > attr.va_size) { | |
| 351 | error = EFAULT; | |
| 352 | goto cleanup; | |
| 353 | } | |
| 354 | ||
| 355 | /* | |
| 356 | * text/data/bss must not exceed limits | |
| 357 | * XXX - this is not complete. it should check current usage PLUS | |
| 358 | * the resources needed by this library. | |
| 359 | */ | |
| 360 | if (a_out->a_text > maxtsiz || | |
| 361 | a_out->a_data + bss_size > p->p_rlimit[RLIMIT_DATA].rlim_cur) { | |
| 362 | error = ENOMEM; | |
| 363 | goto cleanup; | |
| 364 | } | |
| 365 | ||
| 366 | /* prevent more writers */ | |
| 367 | vp->v_flag |= VTEXT; | |
| 368 | ||
| 369 | /* | |
| 370 | * Check if file_offset page aligned. Currently we cannot handle | |
| 371 | * misalinged file offsets, and so we read in the entire image | |
| 372 | * (what a waste). | |
| 373 | */ | |
| 374 | if (file_offset & PAGE_MASK) { | |
| 375 | #ifdef DEBUG | |
| 26be20a0 | 376 | kprintf("uselib: Non page aligned binary %lu\n", file_offset); |
| 984263bc MD |
377 | #endif |
| 378 | /* Map text+data read/write/execute */ | |
| 379 | ||
| 380 | /* a_entry is the load address and is page aligned */ | |
| 381 | vmaddr = trunc_page(a_out->a_entry); | |
| 382 | ||
| 383 | /* get anon user mapping, read+write+execute */ | |
| 384 | error = vm_map_find(&p->p_vmspace->vm_map, NULL, 0, | |
| 1b874851 MD |
385 | &vmaddr, a_out->a_text + a_out->a_data, |
| 386 | FALSE, | |
| 387 | VM_MAPTYPE_NORMAL, | |
| 388 | VM_PROT_ALL, VM_PROT_ALL, | |
| 389 | 0); | |
| 984263bc MD |
390 | if (error) |
| 391 | goto cleanup; | |
| 392 | ||
| 393 | /* map file into kernel_map */ | |
| e4846942 | 394 | error = vm_mmap(&kernel_map, &buffer, |
| 984263bc MD |
395 | round_page(a_out->a_text + a_out->a_data + file_offset), |
| 396 | VM_PROT_READ, VM_PROT_READ, 0, (caddr_t)vp, | |
| 397 | trunc_page(file_offset)); | |
| 398 | if (error) | |
| 399 | goto cleanup; | |
| 400 | ||
| 401 | /* copy from kernel VM space to user space */ | |
| 402 | error = copyout((caddr_t)(uintptr_t)(buffer + file_offset), | |
| 403 | (caddr_t)vmaddr, a_out->a_text + a_out->a_data); | |
| 404 | ||
| 405 | /* release temporary kernel space */ | |
| e4846942 | 406 | vm_map_remove(&kernel_map, buffer, buffer + |
| 984263bc MD |
407 | round_page(a_out->a_text + a_out->a_data + file_offset)); |
| 408 | ||
| 409 | if (error) | |
| 410 | goto cleanup; | |
| 411 | } else { | |
| 412 | #ifdef DEBUG | |
| 26be20a0 | 413 | kprintf("uselib: Page aligned binary %lu\n", file_offset); |
| 984263bc MD |
414 | #endif |
| 415 | /* | |
| 416 | * for QMAGIC, a_entry is 20 bytes beyond the load address | |
| 417 | * to skip the executable header | |
| 418 | */ | |
| 419 | vmaddr = trunc_page(a_out->a_entry); | |
| 420 | ||
| 421 | /* | |
| 422 | * Map it all into the process's space as a single | |
| 423 | * copy-on-write "data" segment. | |
| 424 | */ | |
| 425 | error = vm_mmap(&p->p_vmspace->vm_map, &vmaddr, | |
| 426 | a_out->a_text + a_out->a_data, VM_PROT_ALL, VM_PROT_ALL, | |
| 427 | MAP_PRIVATE | MAP_FIXED, (caddr_t)vp, file_offset); | |
| 428 | if (error) | |
| 429 | goto cleanup; | |
| 430 | } | |
| 431 | #ifdef DEBUG | |
| 26be20a0 | 432 | kprintf("mem=%08lx = %08lx %08lx\n", (long)vmaddr, ((long*)vmaddr)[0], |
| 984263bc MD |
433 | ((long*)vmaddr)[1]); |
| 434 | #endif | |
| 435 | if (bss_size != 0) { | |
| 436 | /* Calculate BSS start address */ | |
| 437 | vmaddr = trunc_page(a_out->a_entry) + a_out->a_text + | |
| 438 | a_out->a_data; | |
| 439 | ||
| 440 | /* allocate some 'anon' space */ | |
| 441 | error = vm_map_find(&p->p_vmspace->vm_map, NULL, 0, | |
| 1b874851 MD |
442 | &vmaddr, bss_size, |
| 443 | FALSE, | |
| 444 | VM_MAPTYPE_NORMAL, | |
| 445 | VM_PROT_ALL, VM_PROT_ALL, | |
| 446 | 0); | |
| 984263bc MD |
447 | if (error) |
| 448 | goto cleanup; | |
| 449 | } | |
| 450 | ||
| 451 | cleanup: | |
| fad57d0e MD |
452 | /* Unlock/release vnode */ |
| 453 | if (vp) { | |
| 454 | if (locked) | |
| a11aaa81 | 455 | vn_unlock(vp); |
| fad57d0e MD |
456 | vrele(vp); |
| 457 | } | |
| 984263bc | 458 | /* Release the kernel mapping. */ |
| fad57d0e | 459 | if (a_out) { |
| e4846942 | 460 | vm_map_remove(&kernel_map, (vm_offset_t)a_out, |
| 984263bc | 461 | (vm_offset_t)a_out + PAGE_SIZE); |
| fad57d0e MD |
462 | } |
| 463 | nlookup_done(&nd); | |
| 136178b3 | 464 | linux_free_path(&path); |
| fad57d0e | 465 | return (error); |
| 984263bc MD |
466 | } |
| 467 | ||
| 468 | int | |
| 753fd850 | 469 | sys_linux_select(struct linux_select_args *args) |
| 984263bc MD |
470 | { |
| 471 | struct select_args bsa; | |
| 472 | struct timeval tv0, tv1, utv, *tvp; | |
| 473 | caddr_t sg; | |
| 474 | int error; | |
| 475 | ||
| 476 | #ifdef DEBUG | |
| 477 | if (ldebug(select)) | |
| 26be20a0 | 478 | kprintf(ARGS(select, "%d, %p, %p, %p, %p"), args->nfds, |
| 984263bc MD |
479 | (void *)args->readfds, (void *)args->writefds, |
| 480 | (void *)args->exceptfds, (void *)args->timeout); | |
| 481 | #endif | |
| 482 | ||
| 483 | error = 0; | |
| c7114eea | 484 | bsa.sysmsg_result = 0; |
| 984263bc MD |
485 | bsa.nd = args->nfds; |
| 486 | bsa.in = args->readfds; | |
| 487 | bsa.ou = args->writefds; | |
| 488 | bsa.ex = args->exceptfds; | |
| 489 | bsa.tv = (struct timeval *)args->timeout; | |
| 490 | ||
| 491 | /* | |
| 492 | * Store current time for computation of the amount of | |
| 493 | * time left. | |
| 494 | */ | |
| 495 | if (args->timeout) { | |
| 496 | if ((error = copyin((caddr_t)args->timeout, &utv, | |
| 497 | sizeof(utv)))) | |
| 498 | goto select_out; | |
| 499 | #ifdef DEBUG | |
| 500 | if (ldebug(select)) | |
| 26be20a0 | 501 | kprintf(LMSG("incoming timeout (%ld/%ld)"), |
| 984263bc MD |
502 | utv.tv_sec, utv.tv_usec); |
| 503 | #endif | |
| 504 | ||
| 505 | if (itimerfix(&utv)) { | |
| 506 | /* | |
| 507 | * The timeval was invalid. Convert it to something | |
| 508 | * valid that will act as it does under Linux. | |
| 509 | */ | |
| 510 | sg = stackgap_init(); | |
| 511 | tvp = stackgap_alloc(&sg, sizeof(utv)); | |
| 512 | utv.tv_sec += utv.tv_usec / 1000000; | |
| 513 | utv.tv_usec %= 1000000; | |
| 514 | if (utv.tv_usec < 0) { | |
| 515 | utv.tv_sec -= 1; | |
| 516 | utv.tv_usec += 1000000; | |
| 517 | } | |
| 518 | if (utv.tv_sec < 0) | |
| 519 | timevalclear(&utv); | |
| 520 | if ((error = copyout(&utv, tvp, sizeof(utv)))) | |
| 521 | goto select_out; | |
| 522 | bsa.tv = tvp; | |
| 523 | } | |
| 524 | microtime(&tv0); | |
| 525 | } | |
| 526 | ||
| 753fd850 | 527 | error = sys_select(&bsa); |
| c7114eea | 528 | args->sysmsg_result = bsa.sysmsg_result; |
| 984263bc MD |
529 | #ifdef DEBUG |
| 530 | if (ldebug(select)) | |
| 26be20a0 | 531 | kprintf(LMSG("real select returns %d"), error); |
| 984263bc MD |
532 | #endif |
| 533 | if (error) { | |
| 534 | /* | |
| 535 | * See fs/select.c in the Linux kernel. Without this, | |
| 536 | * Maelstrom doesn't work. | |
| 537 | */ | |
| 538 | if (error == ERESTART) | |
| 539 | error = EINTR; | |
| 540 | goto select_out; | |
| 541 | } | |
| 542 | ||
| 543 | if (args->timeout) { | |
| c7114eea | 544 | if (args->sysmsg_result) { |
| 984263bc MD |
545 | /* |
| 546 | * Compute how much time was left of the timeout, | |
| 547 | * by subtracting the current time and the time | |
| 548 | * before we started the call, and subtracting | |
| 549 | * that result from the user-supplied value. | |
| 550 | */ | |
| 551 | microtime(&tv1); | |
| 552 | timevalsub(&tv1, &tv0); | |
| 553 | timevalsub(&utv, &tv1); | |
| 554 | if (utv.tv_sec < 0) | |
| 555 | timevalclear(&utv); | |
| 556 | } else | |
| 557 | timevalclear(&utv); | |
| 558 | #ifdef DEBUG | |
| 559 | if (ldebug(select)) | |
| 26be20a0 | 560 | kprintf(LMSG("outgoing timeout (%ld/%ld)"), |
| 984263bc MD |
561 | utv.tv_sec, utv.tv_usec); |
| 562 | #endif | |
| 563 | if ((error = copyout(&utv, (caddr_t)args->timeout, | |
| 564 | sizeof(utv)))) | |
| 565 | goto select_out; | |
| 566 | } | |
| 567 | ||
| 568 | select_out: | |
| 569 | #ifdef DEBUG | |
| 570 | if (ldebug(select)) | |
| 26be20a0 | 571 | kprintf(LMSG("select_out -> %d"), error); |
| 984263bc MD |
572 | #endif |
| 573 | return error; | |
| 574 | } | |
| 575 | ||
| 576 | int | |
| 753fd850 | 577 | sys_linux_mremap(struct linux_mremap_args *args) |
| 984263bc | 578 | { |
| 90b9818c | 579 | struct munmap_args bsd_args; |
| 984263bc | 580 | int error = 0; |
| dadab5e9 | 581 | |
| 984263bc MD |
582 | #ifdef DEBUG |
| 583 | if (ldebug(mremap)) | |
| 26be20a0 | 584 | kprintf(ARGS(mremap, "%p, %08lx, %08lx, %08lx"), |
| 984263bc MD |
585 | (void *)args->addr, |
| 586 | (unsigned long)args->old_len, | |
| 587 | (unsigned long)args->new_len, | |
| 588 | (unsigned long)args->flags); | |
| 589 | #endif | |
| 590 | args->new_len = round_page(args->new_len); | |
| 591 | args->old_len = round_page(args->old_len); | |
| 592 | ||
| 593 | if (args->new_len > args->old_len) { | |
| c7114eea | 594 | args->sysmsg_result = 0; |
| 984263bc MD |
595 | return ENOMEM; |
| 596 | } | |
| 597 | ||
| 598 | if (args->new_len < args->old_len) { | |
| c7114eea | 599 | bsd_args.sysmsg_result = 0; |
| 984263bc MD |
600 | bsd_args.addr = (caddr_t)(args->addr + args->new_len); |
| 601 | bsd_args.len = args->old_len - args->new_len; | |
| 753fd850 | 602 | error = sys_munmap(&bsd_args); |
| 984263bc MD |
603 | } |
| 604 | ||
| c7114eea | 605 | args->sysmsg_resultp = error ? NULL : (void *)args->addr; |
| 984263bc MD |
606 | return error; |
| 607 | } | |
| 608 | ||
| 609 | #define LINUX_MS_ASYNC 0x0001 | |
| 610 | #define LINUX_MS_INVALIDATE 0x0002 | |
| 611 | #define LINUX_MS_SYNC 0x0004 | |
| 612 | ||
| 613 | int | |
| 753fd850 | 614 | sys_linux_msync(struct linux_msync_args *args) |
| 984263bc MD |
615 | { |
| 616 | struct msync_args bsd_args; | |
| 90b9818c | 617 | int error; |
| 984263bc MD |
618 | |
| 619 | bsd_args.addr = (caddr_t)args->addr; | |
| 620 | bsd_args.len = args->len; | |
| 621 | bsd_args.flags = args->fl & ~LINUX_MS_SYNC; | |
| c7114eea | 622 | bsd_args.sysmsg_result = 0; |
| 984263bc | 623 | |
| 753fd850 | 624 | error = sys_msync(&bsd_args); |
| c7114eea | 625 | args->sysmsg_result = bsd_args.sysmsg_result; |
| 90b9818c | 626 | return(error); |
| 984263bc MD |
627 | } |
| 628 | ||
| 984263bc | 629 | int |
| 753fd850 | 630 | sys_linux_time(struct linux_time_args *args) |
| 984263bc MD |
631 | { |
| 632 | struct timeval tv; | |
| 633 | l_time_t tm; | |
| 634 | int error; | |
| 635 | ||
| 636 | #ifdef DEBUG | |
| 637 | if (ldebug(time)) | |
| 26be20a0 | 638 | kprintf(ARGS(time, "*")); |
| 984263bc MD |
639 | #endif |
| 640 | ||
| 641 | microtime(&tv); | |
| 642 | tm = tv.tv_sec; | |
| 643 | if (args->tm && (error = copyout(&tm, (caddr_t)args->tm, sizeof(tm)))) | |
| 644 | return error; | |
| c7114eea | 645 | args->sysmsg_lresult = tm; |
| 984263bc MD |
646 | return 0; |
| 647 | } | |
| 984263bc MD |
648 | |
| 649 | struct l_times_argv { | |
| 650 | l_long tms_utime; | |
| 651 | l_long tms_stime; | |
| 652 | l_long tms_cutime; | |
| 653 | l_long tms_cstime; | |
| 654 | }; | |
| 655 | ||
| 984263bc | 656 | #define CLK_TCK 100 /* Linux uses 100 */ |
| 984263bc MD |
657 | |
| 658 | #define CONVTCK(r) (r.tv_sec * CLK_TCK + r.tv_usec / (1000000 / CLK_TCK)) | |
| 659 | ||
| 660 | int | |
| 753fd850 | 661 | sys_linux_times(struct linux_times_args *args) |
| 984263bc | 662 | { |
| dadab5e9 MD |
663 | struct thread *td = curthread; |
| 664 | struct proc *p = td->td_proc; | |
| 984263bc MD |
665 | struct timeval tv; |
| 666 | struct l_times_argv tms; | |
| 667 | struct rusage ru; | |
| 668 | int error; | |
| 669 | ||
| dadab5e9 | 670 | KKASSERT(p); |
| 984263bc MD |
671 | #ifdef DEBUG |
| 672 | if (ldebug(times)) | |
| 26be20a0 | 673 | kprintf(ARGS(times, "*")); |
| 984263bc MD |
674 | #endif |
| 675 | ||
| fde7ac71 | 676 | calcru_proc(p, &ru); |
| 984263bc MD |
677 | |
| 678 | tms.tms_utime = CONVTCK(ru.ru_utime); | |
| 679 | tms.tms_stime = CONVTCK(ru.ru_stime); | |
| 680 | ||
| fde7ac71 SS |
681 | tms.tms_cutime = CONVTCK(p->p_cru.ru_utime); |
| 682 | tms.tms_cstime = CONVTCK(p->p_cru.ru_stime); | |
| 984263bc MD |
683 | |
| 684 | if ((error = copyout(&tms, (caddr_t)args->buf, sizeof(tms)))) | |
| 685 | return error; | |
| 686 | ||
| 687 | microuptime(&tv); | |
| c7114eea | 688 | args->sysmsg_result = (int)CONVTCK(tv); |
| 984263bc MD |
689 | return 0; |
| 690 | } | |
| 691 | ||
| 692 | int | |
| 753fd850 | 693 | sys_linux_newuname(struct linux_newuname_args *args) |
| 984263bc | 694 | { |
| dadab5e9 | 695 | struct thread *td = curthread; |
| 984263bc MD |
696 | struct l_new_utsname utsname; |
| 697 | char *osrelease, *osname; | |
| 698 | ||
| 699 | #ifdef DEBUG | |
| 700 | if (ldebug(newuname)) | |
| 26be20a0 | 701 | kprintf(ARGS(newuname, "*")); |
| 984263bc MD |
702 | #endif |
| 703 | ||
| dadab5e9 MD |
704 | osname = linux_get_osname(td); |
| 705 | osrelease = linux_get_osrelease(td); | |
| 984263bc MD |
706 | |
| 707 | bzero(&utsname, sizeof(utsname)); | |
| 708 | strncpy(utsname.sysname, osname, LINUX_MAX_UTSNAME-1); | |
| 709 | strncpy(utsname.nodename, hostname, LINUX_MAX_UTSNAME-1); | |
| 710 | strncpy(utsname.release, osrelease, LINUX_MAX_UTSNAME-1); | |
| 711 | strncpy(utsname.version, version, LINUX_MAX_UTSNAME-1); | |
| 712 | strncpy(utsname.machine, machine, LINUX_MAX_UTSNAME-1); | |
| 713 | strncpy(utsname.domainname, domainname, LINUX_MAX_UTSNAME-1); | |
| 714 | ||
| 715 | return (copyout(&utsname, (caddr_t)args->buf, sizeof(utsname))); | |
| 716 | } | |
| 717 | ||
| 718 | #if defined(__i386__) | |
| 719 | struct l_utimbuf { | |
| 720 | l_time_t l_actime; | |
| 721 | l_time_t l_modtime; | |
| 722 | }; | |
| 723 | ||
| 724 | int | |
| 753fd850 | 725 | sys_linux_utime(struct linux_utime_args *args) |
| 984263bc | 726 | { |
| 136178b3 | 727 | struct timeval tv[2]; |
| 984263bc | 728 | struct l_utimbuf lut; |
| fad57d0e | 729 | struct nlookupdata nd; |
| 136178b3 | 730 | char *path; |
| 984263bc | 731 | int error; |
| 984263bc | 732 | |
| 136178b3 DRJ |
733 | error = linux_copyin_path(args->fname, &path, LINUX_PATH_EXISTS); |
| 734 | if (error) | |
| 735 | return (error); | |
| 984263bc MD |
736 | #ifdef DEBUG |
| 737 | if (ldebug(utime)) | |
| 26be20a0 | 738 | kprintf(ARGS(utime, "%s, *"), path); |
| 984263bc MD |
739 | #endif |
| 740 | ||
| 741 | if (args->times) { | |
| 136178b3 DRJ |
742 | error = copyin(args->times, &lut, sizeof(lut)); |
| 743 | if (error) | |
| 744 | goto cleanup; | |
| 984263bc MD |
745 | tv[0].tv_sec = lut.l_actime; |
| 746 | tv[0].tv_usec = 0; | |
| 747 | tv[1].tv_sec = lut.l_modtime; | |
| 748 | tv[1].tv_usec = 0; | |
| 136178b3 | 749 | } |
| fad57d0e MD |
750 | error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW); |
| 751 | if (error == 0) | |
| 752 | error = kern_utimes(&nd, args->times ? tv : NULL); | |
| 753 | nlookup_done(&nd); | |
| 136178b3 DRJ |
754 | cleanup: |
| 755 | linux_free_path(&path); | |
| 756 | return (error); | |
| 984263bc MD |
757 | } |
| 758 | #endif /* __i386__ */ | |
| 759 | ||
| 760 | #define __WCLONE 0x80000000 | |
| 761 | ||
| 984263bc | 762 | int |
| 753fd850 | 763 | sys_linux_waitpid(struct linux_waitpid_args *args) |
| 984263bc | 764 | { |
| 9697c509 | 765 | int error, options, status; |
| 984263bc MD |
766 | |
| 767 | #ifdef DEBUG | |
| 768 | if (ldebug(waitpid)) | |
| 26be20a0 | 769 | kprintf(ARGS(waitpid, "%d, %p, %d"), |
| 984263bc MD |
770 | args->pid, (void *)args->status, args->options); |
| 771 | #endif | |
| 9697c509 | 772 | options = args->options & (WNOHANG | WUNTRACED); |
| 984263bc MD |
773 | /* WLINUXCLONE should be equal to __WCLONE, but we make sure */ |
| 774 | if (args->options & __WCLONE) | |
| 9697c509 DRJ |
775 | options |= WLINUXCLONE; |
| 776 | ||
| 777 | error = kern_wait(args->pid, args->status ? &status : NULL, options, | |
| 778 | NULL, &args->sysmsg_result); | |
| 779 | ||
| 780 | if (error == 0 && args->status) { | |
| 781 | status &= 0xffff; | |
| 782 | if (WIFSIGNALED(status)) | |
| 783 | status = (status & 0xffffff80) | | |
| 784 | BSD_TO_LINUX_SIGNAL(WTERMSIG(status)); | |
| 785 | else if (WIFSTOPPED(status)) | |
| 786 | status = (status & 0xffff00ff) | | |
| 787 | (BSD_TO_LINUX_SIGNAL(WSTOPSIG(status)) << 8); | |
| 788 | error = copyout(&status, args->status, sizeof(status)); | |
| 984263bc MD |
789 | } |
| 790 | ||
| 9697c509 | 791 | return (error); |
| 984263bc | 792 | } |
| 984263bc MD |
793 | |
| 794 | int | |
| 753fd850 | 795 | sys_linux_wait4(struct linux_wait4_args *args) |
| 984263bc | 796 | { |
| dadab5e9 | 797 | struct thread *td = curthread; |
| aa6c3de6 | 798 | struct lwp *lp = td->td_lwp; |
| 9697c509 DRJ |
799 | struct rusage rusage; |
| 800 | int error, options, status; | |
| 984263bc | 801 | |
| aa6c3de6 | 802 | KKASSERT(lp); |
| dadab5e9 | 803 | |
| 984263bc MD |
804 | #ifdef DEBUG |
| 805 | if (ldebug(wait4)) | |
| 26be20a0 | 806 | kprintf(ARGS(wait4, "%d, %p, %d, %p"), |
| 984263bc MD |
807 | args->pid, (void *)args->status, args->options, |
| 808 | (void *)args->rusage); | |
| 809 | #endif | |
| 9697c509 | 810 | options = args->options & (WNOHANG | WUNTRACED); |
| 984263bc MD |
811 | /* WLINUXCLONE should be equal to __WCLONE, but we make sure */ |
| 812 | if (args->options & __WCLONE) | |
| 9697c509 DRJ |
813 | options |= WLINUXCLONE; |
| 814 | ||
| 815 | error = kern_wait(args->pid, args->status ? &status : NULL, options, | |
| 816 | args->rusage ? &rusage : NULL, &args->sysmsg_result); | |
| 817 | ||
| 818 | if (error == 0) | |
| aa6c3de6 | 819 | lwp_delsig(lp, SIGCHLD); |
| 9697c509 DRJ |
820 | |
| 821 | if (error == 0 && args->status) { | |
| 822 | status &= 0xffff; | |
| 823 | if (WIFSIGNALED(status)) | |
| 824 | status = (status & 0xffffff80) | | |
| 825 | BSD_TO_LINUX_SIGNAL(WTERMSIG(status)); | |
| 826 | else if (WIFSTOPPED(status)) | |
| 827 | status = (status & 0xffff00ff) | | |
| 828 | (BSD_TO_LINUX_SIGNAL(WSTOPSIG(status)) << 8); | |
| 829 | error = copyout(&status, args->status, sizeof(status)); | |
| 984263bc | 830 | } |
| 9697c509 DRJ |
831 | if (error == 0 && args->rusage) |
| 832 | error = copyout(&rusage, args->rusage, sizeof(rusage)); | |
| 984263bc | 833 | |
| 9697c509 | 834 | return (error); |
| 984263bc MD |
835 | } |
| 836 | ||
| 837 | int | |
| 753fd850 | 838 | sys_linux_mknod(struct linux_mknod_args *args) |
| 984263bc | 839 | { |
| fad57d0e | 840 | struct nlookupdata nd; |
| 136178b3 | 841 | char *path; |
| 90b9818c | 842 | int error; |
| 984263bc | 843 | |
| 136178b3 DRJ |
844 | error = linux_copyin_path(args->path, &path, LINUX_PATH_CREATE); |
| 845 | if (error) | |
| 846 | return (error); | |
| 984263bc MD |
847 | #ifdef DEBUG |
| 848 | if (ldebug(mknod)) | |
| 26be20a0 | 849 | kprintf(ARGS(mknod, "%s, %d, %d"), |
| 136178b3 | 850 | path, args->mode, args->dev); |
| 984263bc | 851 | #endif |
| fad57d0e MD |
852 | error = nlookup_init(&nd, path, UIO_SYSSPACE, 0); |
| 853 | if (error == 0) { | |
| 854 | if (args->mode & S_IFIFO) { | |
| 855 | error = kern_mkfifo(&nd, args->mode); | |
| 856 | } else { | |
| 0e9b9130 MD |
857 | error = kern_mknod(&nd, args->mode, |
| 858 | umajor(args->dev), | |
| 859 | uminor(args->dev)); | |
| fad57d0e | 860 | } |
| 984263bc | 861 | } |
| fad57d0e | 862 | nlookup_done(&nd); |
| 136178b3 DRJ |
863 | |
| 864 | linux_free_path(&path); | |
| 90b9818c | 865 | return(error); |
| 984263bc MD |
866 | } |
| 867 | ||
| 868 | /* | |
| 869 | * UGH! This is just about the dumbest idea I've ever heard!! | |
| 870 | */ | |
| 871 | int | |
| 753fd850 | 872 | sys_linux_personality(struct linux_personality_args *args) |
| 984263bc MD |
873 | { |
| 874 | #ifdef DEBUG | |
| 875 | if (ldebug(personality)) | |
| 26be20a0 | 876 | kprintf(ARGS(personality, "%d"), args->per); |
| 984263bc | 877 | #endif |
| 984263bc MD |
878 | if (args->per != 0) |
| 879 | return EINVAL; | |
| 984263bc MD |
880 | |
| 881 | /* Yes Jim, it's still a Linux... */ | |
| c7114eea | 882 | args->sysmsg_result = 0; |
| 984263bc MD |
883 | return 0; |
| 884 | } | |
| 885 | ||
| 886 | /* | |
| 887 | * Wrappers for get/setitimer for debugging.. | |
| 888 | */ | |
| 889 | int | |
| 753fd850 | 890 | sys_linux_setitimer(struct linux_setitimer_args *args) |
| 984263bc MD |
891 | { |
| 892 | struct setitimer_args bsa; | |
| 893 | struct itimerval foo; | |
| 894 | int error; | |
| 895 | ||
| 896 | #ifdef DEBUG | |
| 897 | if (ldebug(setitimer)) | |
| 26be20a0 | 898 | kprintf(ARGS(setitimer, "%p, %p"), |
| 984263bc MD |
899 | (void *)args->itv, (void *)args->oitv); |
| 900 | #endif | |
| 901 | bsa.which = args->which; | |
| 902 | bsa.itv = (struct itimerval *)args->itv; | |
| 903 | bsa.oitv = (struct itimerval *)args->oitv; | |
| c7114eea | 904 | bsa.sysmsg_result = 0; |
| 984263bc MD |
905 | if (args->itv) { |
| 906 | if ((error = copyin((caddr_t)args->itv, &foo, sizeof(foo)))) | |
| 907 | return error; | |
| 908 | #ifdef DEBUG | |
| 909 | if (ldebug(setitimer)) { | |
| 26be20a0 | 910 | kprintf("setitimer: value: sec: %ld, usec: %ld\n", |
| 984263bc | 911 | foo.it_value.tv_sec, foo.it_value.tv_usec); |
| 26be20a0 | 912 | kprintf("setitimer: interval: sec: %ld, usec: %ld\n", |
| 984263bc MD |
913 | foo.it_interval.tv_sec, foo.it_interval.tv_usec); |
| 914 | } | |
| 915 | #endif | |
| 916 | } | |
| 753fd850 | 917 | error = sys_setitimer(&bsa); |
| c7114eea | 918 | args->sysmsg_result = bsa.sysmsg_result; |
| 90b9818c | 919 | return(error); |
| 984263bc MD |
920 | } |
| 921 | ||
| 922 | int | |
| 753fd850 | 923 | sys_linux_getitimer(struct linux_getitimer_args *args) |
| 984263bc MD |
924 | { |
| 925 | struct getitimer_args bsa; | |
| 90b9818c | 926 | int error; |
| 984263bc MD |
927 | #ifdef DEBUG |
| 928 | if (ldebug(getitimer)) | |
| 26be20a0 | 929 | kprintf(ARGS(getitimer, "%p"), (void *)args->itv); |
| 984263bc MD |
930 | #endif |
| 931 | bsa.which = args->which; | |
| 932 | bsa.itv = (struct itimerval *)args->itv; | |
| c7114eea | 933 | bsa.sysmsg_result = 0; |
| 753fd850 | 934 | error = sys_getitimer(&bsa); |
| c7114eea | 935 | args->sysmsg_result = bsa.sysmsg_result; |
| 90b9818c | 936 | return(error); |
| 984263bc MD |
937 | } |
| 938 | ||
| 984263bc | 939 | int |
| 753fd850 | 940 | sys_linux_nice(struct linux_nice_args *args) |
| 984263bc MD |
941 | { |
| 942 | struct setpriority_args bsd_args; | |
| 90b9818c | 943 | int error; |
| 984263bc MD |
944 | |
| 945 | bsd_args.which = PRIO_PROCESS; | |
| 946 | bsd_args.who = 0; /* current process */ | |
| 947 | bsd_args.prio = args->inc; | |
| c7114eea | 948 | bsd_args.sysmsg_result = 0; |
| 753fd850 | 949 | error = sys_setpriority(&bsd_args); |
| c7114eea | 950 | args->sysmsg_result = bsd_args.sysmsg_result; |
| 90b9818c | 951 | return(error); |
| 984263bc | 952 | } |
| 984263bc MD |
953 | |
| 954 | int | |
| 753fd850 | 955 | sys_linux_setgroups(struct linux_setgroups_args *args) |
| 984263bc | 956 | { |
| dadab5e9 MD |
957 | struct thread *td = curthread; |
| 958 | struct proc *p = td->td_proc; | |
| 984263bc MD |
959 | struct ucred *newcred, *oldcred; |
| 960 | l_gid_t linux_gidset[NGROUPS]; | |
| 961 | gid_t *bsd_gidset; | |
| 962 | int ngrp, error; | |
| 963 | ||
| dadab5e9 MD |
964 | KKASSERT(p); |
| 965 | ||
| 984263bc MD |
966 | ngrp = args->gidsetsize; |
| 967 | oldcred = p->p_ucred; | |
| 968 | ||
| 969 | /* | |
| 970 | * cr_groups[0] holds egid. Setting the whole set from | |
| 971 | * the supplied set will cause egid to be changed too. | |
| 972 | * Keep cr_groups[0] unchanged to prevent that. | |
| 973 | */ | |
| 974 | ||
| 895c1f85 | 975 | if ((error = priv_check_cred(oldcred, PRIV_ROOT, PRISON_ROOT)) != 0) |
| 984263bc MD |
976 | return (error); |
| 977 | ||
| 978 | if (ngrp >= NGROUPS) | |
| 979 | return (EINVAL); | |
| 980 | ||
| 981 | newcred = crdup(oldcred); | |
| 982 | if (ngrp > 0) { | |
| 983 | error = copyin((caddr_t)args->grouplist, linux_gidset, | |
| 984 | ngrp * sizeof(l_gid_t)); | |
| 985 | if (error) | |
| 986 | return (error); | |
| 987 | ||
| 988 | newcred->cr_ngroups = ngrp + 1; | |
| 989 | ||
| 990 | bsd_gidset = newcred->cr_groups; | |
| 991 | ngrp--; | |
| 992 | while (ngrp >= 0) { | |
| 993 | bsd_gidset[ngrp + 1] = linux_gidset[ngrp]; | |
| 994 | ngrp--; | |
| 995 | } | |
| 41c20dac | 996 | } else { |
| 984263bc | 997 | newcred->cr_ngroups = 1; |
| 41c20dac | 998 | } |
| 984263bc | 999 | |
| 41c20dac | 1000 | setsugid(); |
| 984263bc MD |
1001 | p->p_ucred = newcred; |
| 1002 | crfree(oldcred); | |
| 1003 | return (0); | |
| 1004 | } | |
| 1005 | ||
| 1006 | int | |
| 753fd850 | 1007 | sys_linux_getgroups(struct linux_getgroups_args *args) |
| 984263bc | 1008 | { |
| dadab5e9 MD |
1009 | struct thread *td = curthread; |
| 1010 | struct proc *p = td->td_proc; | |
| 984263bc MD |
1011 | struct ucred *cred; |
| 1012 | l_gid_t linux_gidset[NGROUPS]; | |
| 1013 | gid_t *bsd_gidset; | |
| 1014 | int bsd_gidsetsz, ngrp, error; | |
| 1015 | ||
| dadab5e9 MD |
1016 | KKASSERT(p); |
| 1017 | ||
| 984263bc MD |
1018 | cred = p->p_ucred; |
| 1019 | bsd_gidset = cred->cr_groups; | |
| 1020 | bsd_gidsetsz = cred->cr_ngroups - 1; | |
| 1021 | ||
| 1022 | /* | |
| 1023 | * cr_groups[0] holds egid. Returning the whole set | |
| 1024 | * here will cause a duplicate. Exclude cr_groups[0] | |
| 1025 | * to prevent that. | |
| 1026 | */ | |
| 1027 | ||
| 1028 | if ((ngrp = args->gidsetsize) == 0) { | |
| c7114eea | 1029 | args->sysmsg_result = bsd_gidsetsz; |
| 984263bc MD |
1030 | return (0); |
| 1031 | } | |
| 1032 | ||
| 1033 | if (ngrp < bsd_gidsetsz) | |
| 1034 | return (EINVAL); | |
| 1035 | ||
| 1036 | ngrp = 0; | |
| 1037 | while (ngrp < bsd_gidsetsz) { | |
| 1038 | linux_gidset[ngrp] = bsd_gidset[ngrp + 1]; | |
| 1039 | ngrp++; | |
| 1040 | } | |
| 1041 | ||
| 1042 | if ((error = copyout(linux_gidset, (caddr_t)args->grouplist, | |
| 1043 | ngrp * sizeof(l_gid_t)))) | |
| 1044 | return (error); | |
| 1045 | ||
| c7114eea | 1046 | args->sysmsg_result = ngrp; |
| 984263bc MD |
1047 | return (0); |
| 1048 | } | |
| 1049 | ||
| 984263bc | 1050 | int |
| 753fd850 | 1051 | sys_linux_setrlimit(struct linux_setrlimit_args *args) |
| 984263bc | 1052 | { |
| 9697c509 DRJ |
1053 | struct l_rlimit linux_rlim; |
| 1054 | struct rlimit rlim; | |
| 1055 | u_int which; | |
| 984263bc | 1056 | int error; |
| 984263bc MD |
1057 | |
| 1058 | #ifdef DEBUG | |
| 1059 | if (ldebug(setrlimit)) | |
| 26be20a0 | 1060 | kprintf(ARGS(setrlimit, "%d, %p"), |
| 984263bc MD |
1061 | args->resource, (void *)args->rlim); |
| 1062 | #endif | |
| 984263bc MD |
1063 | if (args->resource >= LINUX_RLIM_NLIMITS) |
| 1064 | return (EINVAL); | |
| 9697c509 DRJ |
1065 | which = linux_to_bsd_resource[args->resource]; |
| 1066 | if (which == -1) | |
| 984263bc MD |
1067 | return (EINVAL); |
| 1068 | ||
| 9697c509 | 1069 | error = copyin(args->rlim, &linux_rlim, sizeof(linux_rlim)); |
| 984263bc MD |
1070 | if (error) |
| 1071 | return (error); | |
| 9697c509 DRJ |
1072 | rlim.rlim_cur = (rlim_t)linux_rlim.rlim_cur; |
| 1073 | rlim.rlim_max = (rlim_t)linux_rlim.rlim_max; | |
| 1074 | ||
| 1075 | error = kern_setrlimit(which, &rlim); | |
| 984263bc | 1076 | |
| 90b9818c | 1077 | return(error); |
| 984263bc MD |
1078 | } |
| 1079 | ||
| 1080 | int | |
| 753fd850 | 1081 | sys_linux_old_getrlimit(struct linux_old_getrlimit_args *args) |
| 984263bc | 1082 | { |
| 9697c509 DRJ |
1083 | struct l_rlimit linux_rlim; |
| 1084 | struct rlimit rlim; | |
| 1085 | u_int which; | |
| 984263bc | 1086 | int error; |
| 984263bc MD |
1087 | |
| 1088 | #ifdef DEBUG | |
| 1089 | if (ldebug(old_getrlimit)) | |
| 26be20a0 | 1090 | kprintf(ARGS(old_getrlimit, "%d, %p"), |
| 984263bc MD |
1091 | args->resource, (void *)args->rlim); |
| 1092 | #endif | |
| 984263bc MD |
1093 | if (args->resource >= LINUX_RLIM_NLIMITS) |
| 1094 | return (EINVAL); | |
| 9697c509 DRJ |
1095 | which = linux_to_bsd_resource[args->resource]; |
| 1096 | if (which == -1) | |
| 984263bc MD |
1097 | return (EINVAL); |
| 1098 | ||
| 9697c509 DRJ |
1099 | error = kern_getrlimit(which, &rlim); |
| 1100 | ||
| 1101 | if (error == 0) { | |
| 1102 | linux_rlim.rlim_cur = (l_ulong)rlim.rlim_cur; | |
| 1103 | if (linux_rlim.rlim_cur == ULONG_MAX) | |
| 1104 | linux_rlim.rlim_cur = LONG_MAX; | |
| 1105 | linux_rlim.rlim_max = (l_ulong)rlim.rlim_max; | |
| 1106 | if (linux_rlim.rlim_max == ULONG_MAX) | |
| 1107 | linux_rlim.rlim_max = LONG_MAX; | |
| 4be82aca | 1108 | error = copyout(&linux_rlim, args->rlim, sizeof(linux_rlim)); |
| 9697c509 DRJ |
1109 | } |
| 1110 | return (error); | |
| 984263bc MD |
1111 | } |
| 1112 | ||
| 1113 | int | |
| 753fd850 | 1114 | sys_linux_getrlimit(struct linux_getrlimit_args *args) |
| 984263bc | 1115 | { |
| 9697c509 DRJ |
1116 | struct l_rlimit linux_rlim; |
| 1117 | struct rlimit rlim; | |
| 1118 | u_int which; | |
| 984263bc | 1119 | int error; |
| 984263bc MD |
1120 | |
| 1121 | #ifdef DEBUG | |
| 1122 | if (ldebug(getrlimit)) | |
| 26be20a0 | 1123 | kprintf(ARGS(getrlimit, "%d, %p"), |
| 984263bc MD |
1124 | args->resource, (void *)args->rlim); |
| 1125 | #endif | |
| 984263bc MD |
1126 | if (args->resource >= LINUX_RLIM_NLIMITS) |
| 1127 | return (EINVAL); | |
| 9697c509 DRJ |
1128 | which = linux_to_bsd_resource[args->resource]; |
| 1129 | if (which == -1) | |
| 984263bc MD |
1130 | return (EINVAL); |
| 1131 | ||
| 9697c509 | 1132 | error = kern_getrlimit(which, &rlim); |
| 984263bc | 1133 | |
| 9697c509 DRJ |
1134 | if (error == 0) { |
| 1135 | linux_rlim.rlim_cur = (l_ulong)rlim.rlim_cur; | |
| 1136 | linux_rlim.rlim_max = (l_ulong)rlim.rlim_max; | |
| 4be82aca | 1137 | error = copyout(&linux_rlim, args->rlim, sizeof(linux_rlim)); |
| 9697c509 DRJ |
1138 | } |
| 1139 | return (error); | |
| 984263bc | 1140 | } |
| 984263bc MD |
1141 | |
| 1142 | int | |
| 753fd850 | 1143 | sys_linux_sched_setscheduler(struct linux_sched_setscheduler_args *args) |
| 984263bc MD |
1144 | { |
| 1145 | struct sched_setscheduler_args bsd; | |
| 90b9818c | 1146 | int error; |
| 984263bc MD |
1147 | |
| 1148 | #ifdef DEBUG | |
| 1149 | if (ldebug(sched_setscheduler)) | |
| 26be20a0 | 1150 | kprintf(ARGS(sched_setscheduler, "%d, %d, %p"), |
| 984263bc MD |
1151 | args->pid, args->policy, (const void *)args->param); |
| 1152 | #endif | |
| 1153 | ||
| 1154 | switch (args->policy) { | |
| 1155 | case LINUX_SCHED_OTHER: | |
| 1156 | bsd.policy = SCHED_OTHER; | |
| 1157 | break; | |
| 1158 | case LINUX_SCHED_FIFO: | |
| 1159 | bsd.policy = SCHED_FIFO; | |
| 1160 | break; | |
| 1161 | case LINUX_SCHED_RR: | |
| 1162 | bsd.policy = SCHED_RR; | |
| 1163 | break; | |
| 1164 | default: | |
| 1165 | return EINVAL; | |
| 1166 | } | |
| 1167 | ||
| 1168 | bsd.pid = args->pid; | |
| 1169 | bsd.param = (struct sched_param *)args->param; | |
| c7114eea | 1170 | bsd.sysmsg_result = 0; |
| 90b9818c | 1171 | |
| 753fd850 | 1172 | error = sys_sched_setscheduler(&bsd); |
| c7114eea | 1173 | args->sysmsg_result = bsd.sysmsg_result; |
| 90b9818c | 1174 | return(error); |
| 984263bc MD |
1175 | } |
| 1176 | ||
| 1177 | int | |
| 753fd850 | 1178 | sys_linux_sched_getscheduler(struct linux_sched_getscheduler_args *args) |
| 984263bc MD |
1179 | { |
| 1180 | struct sched_getscheduler_args bsd; | |
| 1181 | int error; | |
| 1182 | ||
| 1183 | #ifdef DEBUG | |
| 1184 | if (ldebug(sched_getscheduler)) | |
| 26be20a0 | 1185 | kprintf(ARGS(sched_getscheduler, "%d"), args->pid); |
| 984263bc MD |
1186 | #endif |
| 1187 | ||
| c7114eea | 1188 | bsd.sysmsg_result = 0; |
| 984263bc | 1189 | bsd.pid = args->pid; |
| 753fd850 | 1190 | error = sys_sched_getscheduler(&bsd); |
| c7114eea | 1191 | args->sysmsg_result = bsd.sysmsg_result; |
| 984263bc | 1192 | |
| c7114eea | 1193 | switch (args->sysmsg_result) { |
| 984263bc | 1194 | case SCHED_OTHER: |
| c7114eea | 1195 | args->sysmsg_result = LINUX_SCHED_OTHER; |
| 984263bc MD |
1196 | break; |
| 1197 | case SCHED_FIFO: | |
| c7114eea | 1198 | args->sysmsg_result = LINUX_SCHED_FIFO; |
| 984263bc MD |
1199 | break; |
| 1200 | case SCHED_RR: | |
| c7114eea | 1201 | args->sysmsg_result = LINUX_SCHED_RR; |
| 984263bc MD |
1202 | break; |
| 1203 | } | |
| 984263bc MD |
1204 | return error; |
| 1205 | } | |
| 1206 | ||
| 1207 | int | |
| 753fd850 | 1208 | sys_linux_sched_get_priority_max(struct linux_sched_get_priority_max_args *args) |
| 984263bc MD |
1209 | { |
| 1210 | struct sched_get_priority_max_args bsd; | |
| 90b9818c | 1211 | int error; |
| 984263bc MD |
1212 | |
| 1213 | #ifdef DEBUG | |
| 1214 | if (ldebug(sched_get_priority_max)) | |
| 26be20a0 | 1215 | kprintf(ARGS(sched_get_priority_max, "%d"), args->policy); |
| 984263bc MD |
1216 | #endif |
| 1217 | ||
| 1218 | switch (args->policy) { | |
| 1219 | case LINUX_SCHED_OTHER: | |
| 1220 | bsd.policy = SCHED_OTHER; | |
| 1221 | break; | |
| 1222 | case LINUX_SCHED_FIFO: | |
| 1223 | bsd.policy = SCHED_FIFO; | |
| 1224 | break; | |
| 1225 | case LINUX_SCHED_RR: | |
| 1226 | bsd.policy = SCHED_RR; | |
| 1227 | break; | |
| 1228 | default: | |
| 1229 | return EINVAL; | |
| 1230 | } | |
| c7114eea | 1231 | bsd.sysmsg_result = 0; |
| 90b9818c | 1232 | |
| 753fd850 | 1233 | error = sys_sched_get_priority_max(&bsd); |
| c7114eea | 1234 | args->sysmsg_result = bsd.sysmsg_result; |
| 90b9818c | 1235 | return(error); |
| 984263bc MD |
1236 | } |
| 1237 | ||
| 1238 | int | |
| 753fd850 | 1239 | sys_linux_sched_get_priority_min(struct linux_sched_get_priority_min_args *args) |
| 984263bc MD |
1240 | { |
| 1241 | struct sched_get_priority_min_args bsd; | |
| 90b9818c | 1242 | int error; |
| 984263bc MD |
1243 | |
| 1244 | #ifdef DEBUG | |
| 1245 | if (ldebug(sched_get_priority_min)) | |
| 26be20a0 | 1246 | kprintf(ARGS(sched_get_priority_min, "%d"), args->policy); |
| 984263bc MD |
1247 | #endif |
| 1248 | ||
| 1249 | switch (args->policy) { | |
| 1250 | case LINUX_SCHED_OTHER: | |
| 1251 | bsd.policy = SCHED_OTHER; | |
| 1252 | break; | |
| 1253 | case LINUX_SCHED_FIFO: | |
| 1254 | bsd.policy = SCHED_FIFO; | |
| 1255 | break; | |
| 1256 | case LINUX_SCHED_RR: | |
| 1257 | bsd.policy = SCHED_RR; | |
| 1258 | break; | |
| 1259 | default: | |
| 1260 | return EINVAL; | |
| 1261 | } | |
| c7114eea | 1262 | bsd.sysmsg_result = 0; |
| 90b9818c | 1263 | |
| 753fd850 | 1264 | error = sys_sched_get_priority_min(&bsd); |
| c7114eea | 1265 | args->sysmsg_result = bsd.sysmsg_result; |
| 90b9818c | 1266 | return(error); |
| 984263bc MD |
1267 | } |
| 1268 | ||
| 1269 | #define REBOOT_CAD_ON 0x89abcdef | |
| 1270 | #define REBOOT_CAD_OFF 0 | |
| 1271 | #define REBOOT_HALT 0xcdef0123 | |
| 1272 | ||
| 1273 | int | |
| 753fd850 | 1274 | sys_linux_reboot(struct linux_reboot_args *args) |
| 984263bc MD |
1275 | { |
| 1276 | struct reboot_args bsd_args; | |
| 90b9818c | 1277 | int error; |
| 984263bc MD |
1278 | |
| 1279 | #ifdef DEBUG | |
| 1280 | if (ldebug(reboot)) | |
| 26be20a0 | 1281 | kprintf(ARGS(reboot, "0x%x"), args->cmd); |
| 984263bc MD |
1282 | #endif |
| 1283 | if (args->cmd == REBOOT_CAD_ON || args->cmd == REBOOT_CAD_OFF) | |
| 1284 | return (0); | |
| 1285 | bsd_args.opt = (args->cmd == REBOOT_HALT) ? RB_HALT : 0; | |
| c7114eea | 1286 | bsd_args.sysmsg_result = 0; |
| 90b9818c | 1287 | |
| 753fd850 | 1288 | error = sys_reboot(&bsd_args); |
| c7114eea | 1289 | args->sysmsg_result = bsd_args.sysmsg_result; |
| 90b9818c | 1290 | return(error); |
| 984263bc MD |
1291 | } |
| 1292 | ||
| 984263bc MD |
1293 | /* |
| 1294 | * The FreeBSD native getpid(2), getgid(2) and getuid(2) also modify | |
| 1295 | * p->p_retval[1] when COMPAT_43 or COMPAT_SUNOS is defined. This | |
| 1296 | * globbers registers that are assumed to be preserved. The following | |
| 1297 | * lightweight syscalls fixes this. See also linux_getgid16() and | |
| 1298 | * linux_getuid16() in linux_uid16.c. | |
| 1299 | * | |
| 1300 | * linux_getpid() - MP SAFE | |
| 1301 | * linux_getgid() - MP SAFE | |
| 1302 | * linux_getuid() - MP SAFE | |
| 1303 | */ | |
| 1304 | ||
| 1305 | int | |
| 753fd850 | 1306 | sys_linux_getpid(struct linux_getpid_args *args) |
| 984263bc | 1307 | { |
| dadab5e9 MD |
1308 | struct thread *td = curthread; |
| 1309 | struct proc *p = td->td_proc; | |
| 1310 | ||
| 1311 | KKASSERT(p); | |
| 984263bc | 1312 | |
| c7114eea | 1313 | args->sysmsg_result = p->p_pid; |
| 984263bc MD |
1314 | return (0); |
| 1315 | } | |
| 1316 | ||
| 1317 | int | |
| 753fd850 | 1318 | sys_linux_getgid(struct linux_getgid_args *args) |
| 984263bc | 1319 | { |
| dadab5e9 MD |
1320 | struct thread *td = curthread; |
| 1321 | struct proc *p = td->td_proc; | |
| 1322 | ||
| 1323 | KKASSERT(p); | |
| 984263bc | 1324 | |
| c7114eea | 1325 | args->sysmsg_result = p->p_ucred->cr_rgid; |
| 984263bc MD |
1326 | return (0); |
| 1327 | } | |
| 1328 | ||
| 1329 | int | |
| 753fd850 | 1330 | sys_linux_getuid(struct linux_getuid_args *args) |
| 984263bc | 1331 | { |
| dadab5e9 MD |
1332 | struct thread *td = curthread; |
| 1333 | struct proc *p = td->td_proc; | |
| 1334 | ||
| 1335 | KKASSERT(p); | |
| 984263bc | 1336 | |
| c7114eea | 1337 | args->sysmsg_result = p->p_ucred->cr_ruid; |
| 984263bc MD |
1338 | return (0); |
| 1339 | } | |
| 1340 | ||
| 984263bc | 1341 | int |
| 753fd850 | 1342 | sys_linux_getsid(struct linux_getsid_args *args) |
| 984263bc MD |
1343 | { |
| 1344 | struct getsid_args bsd; | |
| 90b9818c MD |
1345 | int error; |
| 1346 | ||
| c7114eea | 1347 | bsd.sysmsg_result = 0; |
| 984263bc | 1348 | bsd.pid = args->pid; |
| 753fd850 | 1349 | error = sys_getsid(&bsd); |
| c7114eea | 1350 | args->sysmsg_result = bsd.sysmsg_result; |
| 90b9818c | 1351 | return(error); |
| 984263bc | 1352 | } |
| 90b9818c | 1353 | |
| 0d88b32b SS |
1354 | int |
| 1355 | linux_nosys(struct nosys_args *args) | |
| 1356 | { | |
| 1357 | /* XXX */ | |
| 1358 | return (ENOSYS); | |
| 1359 | } |