1 /* $NetBSD: linux32_unistd.c,v 1.22 2008/04/15 21:13:34 njoly Exp $ */ 2 3 /*- 4 * Copyright (c) 2006 Emmanuel Dreyfus, all rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 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. All advertising materials mentioning features or use of this software 15 * must display the following acknowledgement: 16 * This product includes software developed by Emmanuel Dreyfus 17 * 4. The name of the author may not be used to endorse or promote 18 * products derived from this software without specific prior written 19 * permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE THE AUTHOR AND CONTRIBUTORS ``AS IS'' 22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 23 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS 25 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31 * POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 #include <sys/cdefs.h> 35 36 __KERNEL_RCSID(0, "$NetBSD: linux32_unistd.c,v 1.22 2008/04/15 21:13:34 njoly Exp $"); 37 38 #include <sys/types.h> 39 #include <sys/param.h> 40 #include <sys/fstypes.h> 41 #include <sys/signal.h> 42 #include <sys/dirent.h> 43 #include <sys/kernel.h> 44 #include <sys/fcntl.h> 45 #include <sys/select.h> 46 #include <sys/proc.h> 47 #include <sys/ucred.h> 48 #include <sys/swap.h> 49 50 #include <machine/types.h> 51 52 #include <sys/syscallargs.h> 53 54 #include <compat/netbsd32/netbsd32.h> 55 #include <compat/netbsd32/netbsd32_conv.h> 56 57 #include <compat/linux/common/linux_types.h> 58 #include <compat/linux/common/linux_signal.h> 59 #include <compat/linux/common/linux_machdep.h> 60 #include <compat/linux/common/linux_misc.h> 61 #include <compat/linux/common/linux_oldolduname.h> 62 #include <compat/linux/linux_syscallargs.h> 63 64 #include <compat/linux32/common/linux32_types.h> 65 #include <compat/linux32/common/linux32_signal.h> 66 #include <compat/linux32/common/linux32_machdep.h> 67 #include <compat/linux32/common/linux32_sysctl.h> 68 #include <compat/linux32/common/linux32_socketcall.h> 69 #include <compat/linux32/linux32_syscallargs.h> 70 71 static int linux32_select1(struct lwp *, register_t *, 72 int, fd_set *, fd_set *, fd_set *, struct timeval *); 73 74 int 75 linux32_sys_brk(struct lwp *l, const struct linux32_sys_brk_args *uap, register_t *retval) 76 { 77 /* { 78 syscallarg(netbsd32_charp) nsize; 79 } */ 80 struct linux_sys_brk_args ua; 81 82 NETBSD32TOP_UAP(nsize, char); 83 return linux_sys_brk(l, &ua, retval); 84 } 85 86 int 87 linux32_sys_llseek(struct lwp *l, const struct linux32_sys_llseek_args *uap, register_t *retval) 88 { 89 /* { 90 syscallcarg(int) fd; 91 syscallarg(u_int32_t) ohigh; 92 syscallarg(u_int32_t) olow; 93 syscallarg(netbsd32_caddr_t) res; 94 syscallcarg(int) whence; 95 } */ 96 struct linux_sys_llseek_args ua; 97 98 NETBSD32TO64_UAP(fd); 99 NETBSD32TO64_UAP(ohigh); 100 NETBSD32TO64_UAP(olow); 101 NETBSD32TOP_UAP(res, char); 102 NETBSD32TO64_UAP(whence); 103 104 return linux_sys_llseek(l, &ua, retval); 105 } 106 107 int 108 linux32_sys_select(struct lwp *l, const struct linux32_sys_select_args *uap, register_t *retval) 109 { 110 /* { 111 syscallarg(int) nfds; 112 syscallarg(netbsd32_fd_setp_t) readfds; 113 syscallarg(netbsd32_fd_setp_t) writefds; 114 syscallarg(netbsd32_fd_setp_t) exceptfds; 115 syscallarg(netbsd32_timevalp_t) timeout; 116 } */ 117 118 return linux32_select1(l, retval, SCARG(uap, nfds), 119 SCARG_P32(uap, readfds), 120 SCARG_P32(uap, writefds), 121 SCARG_P32(uap, exceptfds), 122 SCARG_P32(uap, timeout)); 123 } 124 125 int 126 linux32_sys_oldselect(struct lwp *l, const struct linux32_sys_oldselect_args *uap, register_t *retval) 127 { 128 /* { 129 syscallarg(linux32_oldselectp_t) lsp; 130 } */ 131 struct linux32_oldselect lsp32; 132 int error; 133 134 if ((error = copyin(SCARG_P32(uap, lsp), &lsp32, sizeof(lsp32))) != 0) 135 return error; 136 137 return linux32_select1(l, retval, lsp32.nfds, 138 NETBSD32PTR64(lsp32.readfds), NETBSD32PTR64(lsp32.writefds), 139 NETBSD32PTR64(lsp32.exceptfds), NETBSD32PTR64(lsp32.timeout)); 140 } 141 142 static int 143 linux32_select1(l, retval, nfds, readfds, writefds, exceptfds, timeout) 144 struct lwp *l; 145 register_t *retval; 146 int nfds; 147 fd_set *readfds, *writefds, *exceptfds; 148 struct timeval *timeout; 149 { 150 struct timeval tv0, tv1, utv, *tv = NULL; 151 struct netbsd32_timeval utv32; 152 int error; 153 154 timerclear(&utv); /* XXX GCC4 */ 155 156 /* 157 * Store current time for computation of the amount of 158 * time left. 159 */ 160 if (timeout) { 161 if ((error = copyin(timeout, &utv32, sizeof(utv32)))) 162 return error; 163 164 netbsd32_to_timeval(&utv32, &utv); 165 166 if (itimerfix(&utv)) { 167 /* 168 * The timeval was invalid. Convert it to something 169 * valid that will act as it does under Linux. 170 */ 171 utv.tv_sec += utv.tv_usec / 1000000; 172 utv.tv_usec %= 1000000; 173 if (utv.tv_usec < 0) { 174 utv.tv_sec -= 1; 175 utv.tv_usec += 1000000; 176 } 177 if (utv.tv_sec < 0) 178 timerclear(&utv); 179 } 180 microtime(&tv0); 181 tv = &utv; 182 } 183 184 error = selcommon(l, retval, nfds, 185 readfds, writefds, exceptfds, tv, NULL); 186 187 if (error) { 188 /* 189 * See fs/select.c in the Linux kernel. Without this, 190 * Maelstrom doesn't work. 191 */ 192 if (error == ERESTART) 193 error = EINTR; 194 return error; 195 } 196 197 if (timeout) { 198 if (*retval) { 199 /* 200 * Compute how much time was left of the timeout, 201 * by subtracting the current time and the time 202 * before we started the call, and subtracting 203 * that result from the user-supplied value. 204 */ 205 microtime(&tv1); 206 timersub(&tv1, &tv0, &tv1); 207 timersub(&utv, &tv1, &utv); 208 if (utv.tv_sec < 0) 209 timerclear(&utv); 210 } else { 211 timerclear(&utv); 212 } 213 214 netbsd32_from_timeval(&utv, &utv32); 215 216 if ((error = copyout(&utv32, timeout, sizeof(utv32)))) 217 return error; 218 } 219 220 return 0; 221 } 222 223 int 224 linux32_sys_pipe(struct lwp *l, const struct linux32_sys_pipe_args *uap, register_t *retval) 225 { 226 /* { 227 syscallarg(netbsd32_intp) fd; 228 } */ 229 int error; 230 int pfds[2]; 231 232 if ((error = sys_pipe(l, 0, retval))) 233 return error; 234 235 pfds[0] = (int)retval[0]; 236 pfds[1] = (int)retval[1]; 237 238 if ((error = copyout(pfds, SCARG_P32(uap, fd), 2 * sizeof (int))) != 0) 239 return error; 240 241 retval[0] = 0; 242 retval[1] = 0; 243 244 return 0; 245 } 246 247 248 int 249 linux32_sys_unlink(struct lwp *l, const struct linux32_sys_unlink_args *uap, register_t *retval) 250 { 251 /* { 252 syscallarg(const netbsd32_charp) path; 253 } */ 254 struct linux_sys_unlink_args ua; 255 256 NETBSD32TOP_UAP(path, const char); 257 258 return linux_sys_unlink(l, &ua, retval); 259 } 260 261 int 262 linux32_sys_creat(struct lwp *l, const struct linux32_sys_creat_args *uap, register_t *retval) 263 { 264 /* { 265 syscallarg(const netbsd32_charp) path; 266 syscallarg(int) mode; 267 } */ 268 struct sys_open_args ua; 269 270 NETBSD32TOP_UAP(path, const char); 271 SCARG(&ua, flags) = O_CREAT | O_TRUNC | O_WRONLY; 272 NETBSD32TO64_UAP(mode); 273 274 return sys_open(l, &ua, retval); 275 } 276 277 int 278 linux32_sys_mknod(struct lwp *l, const struct linux32_sys_mknod_args *uap, register_t *retval) 279 { 280 /* { 281 syscallarg(const netbsd32_charp) path; 282 syscallarg(int) mode; 283 syscallarg(int) dev; 284 } */ 285 struct linux_sys_mknod_args ua; 286 287 NETBSD32TOP_UAP(path, const char); 288 NETBSD32TO64_UAP(mode); 289 NETBSD32TO64_UAP(dev); 290 291 return linux_sys_mknod(l, &ua, retval); 292 } 293 294 int 295 linux32_sys_break(struct lwp *l, const struct linux32_sys_break_args *uap, register_t *retval) 296 { 297 #if 0 298 /* { 299 syscallarg(const netbsd32_charp) nsize; 300 } */ 301 #endif 302 303 return ENOSYS; 304 } 305 306 int 307 linux32_sys_rename(struct lwp *l, const struct linux32_sys_rename_args *uap, register_t *retval) 308 { 309 /* { 310 syscallarg(const netbsd32_charp) from; 311 syscallarg(const netbsd32_charp) to; 312 } */ 313 struct sys___posix_rename_args ua; 314 315 NETBSD32TOP_UAP(from, const char); 316 NETBSD32TOP_UAP(to, const char); 317 318 return sys___posix_rename(l, &ua, retval); 319 } 320 321 int 322 linux32_sys_swapon(struct lwp *l, const struct linux32_sys_swapon_args *uap, register_t *retval) 323 { 324 /* { 325 syscallarg(const netbsd32_charp) name; 326 } */ 327 struct sys_swapctl_args ua; 328 329 SCARG(&ua, cmd) = SWAP_ON; 330 SCARG(&ua, arg) = SCARG_P32(uap, name); 331 SCARG(&ua, misc) = 0; /* priority */ 332 return (sys_swapctl(l, &ua, retval)); 333 } 334 335 int 336 linux32_sys_swapoff(struct lwp *l, const struct linux32_sys_swapoff_args *uap, register_t *retval) 337 { 338 /* { 339 syscallarg(const netbsd32_charp) path; 340 } */ 341 struct sys_swapctl_args ua; 342 343 SCARG(&ua, cmd) = SWAP_OFF; 344 SCARG(&ua, arg) = SCARG_P32(uap, path); 345 SCARG(&ua, misc) = 0; /* priority */ 346 return (sys_swapctl(l, &ua, retval)); 347 } 348 349 350 int 351 linux32_sys_reboot(struct lwp *l, const struct linux32_sys_reboot_args *uap, register_t *retval) 352 { 353 /* { 354 syscallarg(int) magic1; 355 syscallarg(int) magic2; 356 syscallarg(int) cmd; 357 syscallarg(netbsd32_voidp) arg; 358 } */ 359 struct linux_sys_reboot_args ua; 360 361 NETBSD32TO64_UAP(magic1); 362 NETBSD32TO64_UAP(magic2); 363 NETBSD32TO64_UAP(cmd); 364 NETBSD32TOP_UAP(arg, void); 365 366 return linux_sys_reboot(l, &ua, retval); 367 } 368 369 int 370 linux32_sys_truncate(struct lwp *l, const struct linux32_sys_truncate_args *uap, register_t *retval) 371 { 372 /* { 373 syscallarg(const netbsd32_charp) path; 374 syscallarg(netbsd32_charp) buf; 375 syscallarg(int) count; 376 } */ 377 struct compat_43_sys_truncate_args ua; 378 379 NETBSD32TOP_UAP(path, const char); 380 NETBSD32TO64_UAP(length); 381 382 return compat_43_sys_truncate(l, &ua, retval); 383 } 384 385 int 386 linux32_sys_setresuid(struct lwp *l, const struct linux32_sys_setresuid_args *uap, register_t *retval) 387 { 388 /* { 389 syscallarg(uid_t) ruid; 390 syscallarg(uid_t) euid; 391 syscallarg(uid_t) suid; 392 } */ 393 struct linux_sys_setresuid_args ua; 394 395 SCARG(&ua, ruid) = (SCARG(uap, ruid) == -1) ? -1 : SCARG(uap, ruid); 396 SCARG(&ua, euid) = (SCARG(uap, euid) == -1) ? -1 : SCARG(uap, euid); 397 SCARG(&ua, suid) = (SCARG(uap, suid) == -1) ? -1 : SCARG(uap, suid); 398 399 return linux_sys_setresuid(l, &ua, retval); 400 } 401 402 int 403 linux32_sys_setresgid(struct lwp *l, const struct linux32_sys_setresgid_args *uap, register_t *retval) 404 { 405 /* { 406 syscallarg(gid_t) rgid; 407 syscallarg(gid_t) egid; 408 syscallarg(gid_t) sgid; 409 } */ 410 struct linux_sys_setresgid_args ua; 411 412 SCARG(&ua, rgid) = (SCARG(uap, rgid) == -1) ? -1 : SCARG(uap, rgid); 413 SCARG(&ua, egid) = (SCARG(uap, egid) == -1) ? -1 : SCARG(uap, egid); 414 SCARG(&ua, sgid) = (SCARG(uap, sgid) == -1) ? -1 : SCARG(uap, sgid); 415 416 return linux_sys_setresgid(l, &ua, retval); 417 } 418 419 int 420 linux32_sys_nice(struct lwp *l, const struct linux32_sys_nice_args *uap, register_t *retval) 421 { 422 /* { 423 syscallarg(int) incr; 424 } */ 425 struct sys_setpriority_args bsa; 426 427 SCARG(&bsa, which) = PRIO_PROCESS; 428 SCARG(&bsa, who) = 0; 429 SCARG(&bsa, prio) = SCARG(uap, incr); 430 431 return sys_setpriority(l, &bsa, retval); 432 } 433 434 int 435 linux32_sys_alarm(struct lwp *l, const struct linux32_sys_alarm_args *uap, register_t *retval) 436 { 437 /* { 438 syscallarg(unsigned int) secs; 439 } */ 440 struct linux_sys_alarm_args ua; 441 442 NETBSD32TO64_UAP(secs); 443 444 return linux_sys_alarm(l, &ua, retval); 445 } 446 447 int 448 linux32_sys_fdatasync(struct lwp *l, const struct linux32_sys_fdatasync_args *uap, register_t *retval) 449 { 450 /* { 451 syscallarg(int) fd; 452 } */ 453 struct linux_sys_fdatasync_args ua; 454 455 NETBSD32TO64_UAP(fd); 456 457 return linux_sys_fdatasync(l, &ua, retval); 458 } 459 460 int 461 linux32_sys_setfsuid(struct lwp *l, const struct linux32_sys_setfsuid_args *uap, register_t *retval) 462 { 463 /* { 464 syscallarg(uid_t) uid; 465 } */ 466 struct linux_sys_setfsuid_args ua; 467 468 NETBSD32TO64_UAP(uid); 469 470 return linux_sys_setfsuid(l, &ua, retval); 471 } 472 473 int 474 linux32_sys_setfsgid(struct lwp *l, const struct linux32_sys_setfsgid_args *uap, register_t *retval) 475 { 476 /* { 477 syscallarg(gid_t) gid; 478 } */ 479 struct linux_sys_setfsgid_args ua; 480 481 NETBSD32TO64_UAP(gid); 482 483 return linux_sys_setfsgid(l, &ua, retval); 484 } 485 486 /* 487 * pread(2). 488 */ 489 int 490 linux32_sys_pread(struct lwp *l, 491 const struct linux32_sys_pread_args *uap, register_t *retval) 492 { 493 /* { 494 syscallarg(int) fd; 495 syscallarg(netbsd32_voidp) buf; 496 syscallarg(netbsd32_size_t) nbyte; 497 syscallarg(linux32_off_t) offset; 498 } */ 499 struct sys_pread_args pra; 500 501 SCARG(&pra, fd) = SCARG(uap, fd); 502 SCARG(&pra, buf) = SCARG_P32(uap, buf); 503 SCARG(&pra, nbyte) = SCARG(uap, nbyte); 504 SCARG(&pra, offset) = SCARG(uap, offset); 505 506 return sys_pread(l, &pra, retval); 507 } 508 509 /* 510 * pwrite(2). 511 */ 512 int 513 linux32_sys_pwrite(struct lwp *l, 514 const struct linux32_sys_pwrite_args *uap, register_t *retval) 515 { 516 /* { 517 syscallarg(int) fd; 518 syscallarg(const netbsd32_voidp) buf; 519 syscallarg(netbsd32_size_t) nbyte; 520 syscallarg(linux32_off_t) offset; 521 } */ 522 struct sys_pwrite_args pra; 523 524 SCARG(&pra, fd) = SCARG(uap, fd); 525 SCARG(&pra, buf) = SCARG_P32(uap, buf); 526 SCARG(&pra, nbyte) = SCARG(uap, nbyte); 527 SCARG(&pra, offset) = SCARG(uap, offset); 528 529 return sys_pwrite(l, &pra, retval); 530 } 531 532