1 /* $NetBSD: linux_misc_notalpha.c,v 1.97 2007/11/25 00:35:26 elad Exp $ */ 2 3 /*- 4 * Copyright (c) 1995, 1998 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Frank van der Linden and Eric Haszlakiewicz; by Jason R. Thorpe 9 * of the Numerical Aerospace Simulation Facility, NASA Ames Research Center. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. All advertising materials mentioning features or use of this software 20 * must display the following acknowledgement: 21 * This product includes software developed by the NetBSD 22 * Foundation, Inc. and its contributors. 23 * 4. Neither the name of The NetBSD Foundation nor the names of its 24 * contributors may be used to endorse or promote products derived 25 * from this software without specific prior written permission. 26 * 27 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 29 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 30 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 31 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 37 * POSSIBILITY OF SUCH DAMAGE. 38 */ 39 40 #include <sys/cdefs.h> 41 __KERNEL_RCSID(0, "$NetBSD: linux_misc_notalpha.c,v 1.97 2007/11/25 00:35:26 elad Exp $"); 42 43 #include <sys/param.h> 44 #include <sys/systm.h> 45 #include <sys/kernel.h> 46 #include <sys/mman.h> 47 #include <sys/mount.h> 48 #include <sys/malloc.h> 49 #include <sys/mbuf.h> 50 #include <sys/namei.h> 51 #include <sys/proc.h> 52 #include <sys/prot.h> 53 #include <sys/ptrace.h> 54 #include <sys/resource.h> 55 #include <sys/resourcevar.h> 56 #include <sys/time.h> 57 #include <sys/vfs_syscalls.h> 58 #include <sys/wait.h> 59 #include <sys/kauth.h> 60 61 #include <sys/syscallargs.h> 62 63 #include <compat/linux/common/linux_types.h> 64 #include <compat/linux/common/linux_fcntl.h> 65 #include <compat/linux/common/linux_misc.h> 66 #include <compat/linux/common/linux_mmap.h> 67 #include <compat/linux/common/linux_signal.h> 68 #include <compat/linux/common/linux_util.h> 69 #include <compat/linux/common/linux_ipc.h> 70 #include <compat/linux/common/linux_sem.h> 71 72 #include <compat/linux/linux_syscallargs.h> 73 74 /* 75 * This file contains routines which are used 76 * on every linux architechture except the Alpha. 77 */ 78 79 /* Used on: arm, i386, m68k, mips, ppc, sparc, sparc64 */ 80 /* Not used on: alpha */ 81 82 #ifdef DEBUG_LINUX 83 #define DPRINTF(a) uprintf a 84 #else 85 #define DPRINTF(a) 86 #endif 87 88 #ifndef COMPAT_LINUX32 89 #if !defined(__m68k__) && !defined(__amd64__) 90 static void bsd_to_linux_statfs64(const struct statvfs *, 91 struct linux_statfs64 *); 92 #endif 93 94 /* 95 * Alarm. This is a libc call which uses setitimer(2) in NetBSD. 96 * Fiddle with the timers to make it work. 97 */ 98 int 99 linux_sys_alarm(l, v, retval) 100 struct lwp *l; 101 void *v; 102 register_t *retval; 103 { 104 struct linux_sys_alarm_args /* { 105 syscallarg(unsigned int) secs; 106 } */ *uap = v; 107 struct proc *p = l->l_proc; 108 struct timeval now; 109 struct itimerval *itp, it; 110 struct ptimer *ptp; 111 int s; 112 113 if (p->p_timers && p->p_timers->pts_timers[ITIMER_REAL]) 114 itp = &p->p_timers->pts_timers[ITIMER_REAL]->pt_time; 115 else 116 itp = NULL; 117 s = splclock(); 118 /* 119 * Clear any pending timer alarms. 120 */ 121 if (itp) { 122 callout_stop(&p->p_timers->pts_timers[ITIMER_REAL]->pt_ch); 123 timerclear(&itp->it_interval); 124 getmicrotime(&now); 125 if (timerisset(&itp->it_value) && 126 timercmp(&itp->it_value, &now, >)) 127 timersub(&itp->it_value, &now, &itp->it_value); 128 /* 129 * Return how many seconds were left (rounded up) 130 */ 131 retval[0] = itp->it_value.tv_sec; 132 if (itp->it_value.tv_usec) 133 retval[0]++; 134 } else { 135 retval[0] = 0; 136 } 137 138 /* 139 * alarm(0) just resets the timer. 140 */ 141 if (SCARG(uap, secs) == 0) { 142 if (itp) 143 timerclear(&itp->it_value); 144 splx(s); 145 return 0; 146 } 147 148 /* 149 * Check the new alarm time for sanity, and set it. 150 */ 151 timerclear(&it.it_interval); 152 it.it_value.tv_sec = SCARG(uap, secs); 153 it.it_value.tv_usec = 0; 154 if (itimerfix(&it.it_value) || itimerfix(&it.it_interval)) { 155 splx(s); 156 return (EINVAL); 157 } 158 159 if (p->p_timers == NULL) 160 timers_alloc(p); 161 ptp = p->p_timers->pts_timers[ITIMER_REAL]; 162 if (ptp == NULL) { 163 ptp = pool_get(&ptimer_pool, PR_WAITOK); 164 ptp->pt_ev.sigev_notify = SIGEV_SIGNAL; 165 ptp->pt_ev.sigev_signo = SIGALRM; 166 ptp->pt_overruns = 0; 167 ptp->pt_proc = p; 168 ptp->pt_type = CLOCK_REALTIME; 169 ptp->pt_entry = CLOCK_REALTIME; 170 callout_init(&ptp->pt_ch, 0); 171 p->p_timers->pts_timers[ITIMER_REAL] = ptp; 172 } 173 174 if (timerisset(&it.it_value)) { 175 /* 176 * Don't need to check hzto() return value, here. 177 * callout_reset() does it for us. 178 */ 179 getmicrotime(&now); 180 timeradd(&it.it_value, &now, &it.it_value); 181 callout_reset(&ptp->pt_ch, hzto(&it.it_value), 182 realtimerexpire, ptp); 183 } 184 ptp->pt_time = it; 185 splx(s); 186 187 return 0; 188 } 189 #endif /* !COMPAT_LINUX32 */ 190 191 #if !defined(__amd64__) 192 int 193 linux_sys_nice(l, v, retval) 194 struct lwp *l; 195 void *v; 196 register_t *retval; 197 { 198 struct linux_sys_nice_args /* { 199 syscallarg(int) incr; 200 } */ *uap = v; 201 struct sys_setpriority_args bsa; 202 203 SCARG(&bsa, which) = PRIO_PROCESS; 204 SCARG(&bsa, who) = 0; 205 SCARG(&bsa, prio) = SCARG(uap, incr); 206 return sys_setpriority(l, &bsa, retval); 207 } 208 #endif /* !__amd64__ */ 209 210 #ifndef COMPAT_LINUX32 211 #ifndef __amd64__ 212 /* 213 * The old Linux readdir was only able to read one entry at a time, 214 * even though it had a 'count' argument. In fact, the emulation 215 * of the old call was better than the original, because it did handle 216 * the count arg properly. Don't bother with it anymore now, and use 217 * it to distinguish between old and new. The difference is that the 218 * newer one actually does multiple entries, and the reclen field 219 * really is the reclen, not the namelength. 220 */ 221 int 222 linux_sys_readdir(l, v, retval) 223 struct lwp *l; 224 void *v; 225 register_t *retval; 226 { 227 struct linux_sys_readdir_args /* { 228 syscallarg(int) fd; 229 syscallarg(struct linux_dirent *) dent; 230 syscallarg(unsigned int) count; 231 } */ *uap = v; 232 233 SCARG(uap, count) = 1; 234 return linux_sys_getdents(l, uap, retval); 235 } 236 #endif /* !amd64 */ 237 238 /* 239 * I wonder why Linux has gettimeofday() _and_ time().. Still, we 240 * need to deal with it. 241 */ 242 int 243 linux_sys_time(struct lwp *l, void *v, register_t *retval) 244 { 245 struct linux_sys_time_args /* { 246 linux_time_t *t; 247 } */ *uap = v; 248 struct timeval atv; 249 linux_time_t tt; 250 int error; 251 252 microtime(&atv); 253 254 tt = atv.tv_sec; 255 if (SCARG(uap, t) && (error = copyout(&tt, SCARG(uap, t), sizeof tt))) 256 return error; 257 258 retval[0] = tt; 259 return 0; 260 } 261 262 /* 263 * utime(). Do conversion to things that utimes() understands, 264 * and pass it on. 265 */ 266 int 267 linux_sys_utime(l, v, retval) 268 struct lwp *l; 269 void *v; 270 register_t *retval; 271 { 272 struct linux_sys_utime_args /* { 273 syscallarg(const char *) path; 274 syscallarg(struct linux_utimbuf *)times; 275 } */ *uap = v; 276 int error; 277 struct timeval tv[2], *tvp; 278 struct linux_utimbuf lut; 279 280 if (SCARG(uap, times) != NULL) { 281 if ((error = copyin(SCARG(uap, times), &lut, sizeof lut))) 282 return error; 283 tv[0].tv_usec = tv[1].tv_usec = 0; 284 tv[0].tv_sec = lut.l_actime; 285 tv[1].tv_sec = lut.l_modtime; 286 tvp = tv; 287 } else 288 tvp = NULL; 289 290 return do_sys_utimes(l, NULL, SCARG(uap, path), FOLLOW, 291 tvp, UIO_SYSSPACE); 292 } 293 294 #ifndef __amd64__ 295 /* 296 * waitpid(2). Just forward on to linux_sys_wait4 with a NULL rusage. 297 */ 298 int 299 linux_sys_waitpid(l, v, retval) 300 struct lwp *l; 301 void *v; 302 register_t *retval; 303 { 304 struct linux_sys_waitpid_args /* { 305 syscallarg(int) pid; 306 syscallarg(int *) status; 307 syscallarg(int) options; 308 } */ *uap = v; 309 struct linux_sys_wait4_args linux_w4a; 310 311 SCARG(&linux_w4a, pid) = SCARG(uap, pid); 312 SCARG(&linux_w4a, status) = SCARG(uap, status); 313 SCARG(&linux_w4a, options) = SCARG(uap, options); 314 SCARG(&linux_w4a, rusage) = NULL; 315 316 return linux_sys_wait4(l, &linux_w4a, retval); 317 } 318 #endif /* !amd64 */ 319 320 int 321 linux_sys_setresgid(struct lwp *l, void *v, register_t *retval) 322 { 323 struct linux_sys_setresgid_args /* { 324 syscallarg(gid_t) rgid; 325 syscallarg(gid_t) egid; 326 syscallarg(gid_t) sgid; 327 } */ *uap = v; 328 329 /* 330 * Note: These checks are a little different than the NetBSD 331 * setregid(2) call performs. This precisely follows the 332 * behavior of the Linux kernel. 333 */ 334 return do_setresgid(l, SCARG(uap,rgid), SCARG(uap, egid), 335 SCARG(uap, sgid), 336 ID_R_EQ_R | ID_R_EQ_E | ID_R_EQ_S | 337 ID_E_EQ_R | ID_E_EQ_E | ID_E_EQ_S | 338 ID_S_EQ_R | ID_S_EQ_E | ID_S_EQ_S ); 339 } 340 341 int 342 linux_sys_getresgid(struct lwp *l, void *v, register_t *retval) 343 { 344 struct linux_sys_getresgid_args /* { 345 syscallarg(gid_t *) rgid; 346 syscallarg(gid_t *) egid; 347 syscallarg(gid_t *) sgid; 348 } */ *uap = v; 349 kauth_cred_t pc = l->l_cred; 350 int error; 351 gid_t gid; 352 353 /* 354 * Linux copies these values out to userspace like so: 355 * 356 * 1. Copy out rgid. 357 * 2. If that succeeds, copy out egid. 358 * 3. If both of those succeed, copy out sgid. 359 */ 360 gid = kauth_cred_getgid(pc); 361 if ((error = copyout(&gid, SCARG(uap, rgid), sizeof(gid_t))) != 0) 362 return (error); 363 364 gid = kauth_cred_getegid(pc); 365 if ((error = copyout(&gid, SCARG(uap, egid), sizeof(gid_t))) != 0) 366 return (error); 367 368 gid = kauth_cred_getsvgid(pc); 369 370 return (copyout(&gid, SCARG(uap, sgid), sizeof(gid_t))); 371 } 372 373 #ifndef __amd64__ 374 /* 375 * I wonder why Linux has settimeofday() _and_ stime().. Still, we 376 * need to deal with it. 377 */ 378 int 379 linux_sys_stime(struct lwp *l, void *v, register_t *retval) 380 { 381 struct linux_sys_time_args /* { 382 linux_time_t *t; 383 } */ *uap = v; 384 struct timespec ats; 385 linux_time_t tt; 386 int error; 387 388 if ((error = copyin(&tt, SCARG(uap, t), sizeof tt)) != 0) 389 return error; 390 391 ats.tv_sec = tt; 392 ats.tv_nsec = 0; 393 394 if ((error = settime(l->l_proc, &ats))) 395 return (error); 396 397 return 0; 398 } 399 #endif /* !amd64 */ 400 401 #if !defined(__m68k__) && !defined(__amd64__) 402 /* 403 * Convert NetBSD statvfs structure to Linux statfs64 structure. 404 * See comments in bsd_to_linux_statfs() for further background. 405 * We can safely pass correct bsize and frsize here, since Linux glibc 406 * statvfs() doesn't use statfs64(). 407 */ 408 static void 409 bsd_to_linux_statfs64(bsp, lsp) 410 const struct statvfs *bsp; 411 struct linux_statfs64 *lsp; 412 { 413 int i, div; 414 415 for (i = 0; i < linux_fstypes_cnt; i++) { 416 if (strcmp(bsp->f_fstypename, linux_fstypes[i].bsd) == 0) { 417 lsp->l_ftype = linux_fstypes[i].linux; 418 break; 419 } 420 } 421 422 if (i == linux_fstypes_cnt) { 423 DPRINTF(("unhandled fstype in linux emulation: %s\n", 424 bsp->f_fstypename)); 425 lsp->l_ftype = LINUX_DEFAULT_SUPER_MAGIC; 426 } 427 428 div = bsp->f_frsize ? (bsp->f_bsize / bsp->f_frsize) : 1; 429 if (div == 0) 430 div = 1; 431 lsp->l_fbsize = bsp->f_bsize; 432 lsp->l_ffrsize = bsp->f_frsize; 433 lsp->l_fblocks = bsp->f_blocks / div; 434 lsp->l_fbfree = bsp->f_bfree / div; 435 lsp->l_fbavail = bsp->f_bavail / div; 436 lsp->l_ffiles = bsp->f_files; 437 lsp->l_fffree = bsp->f_ffree / div; 438 /* Linux sets the fsid to 0..., we don't */ 439 lsp->l_ffsid.val[0] = bsp->f_fsidx.__fsid_val[0]; 440 lsp->l_ffsid.val[1] = bsp->f_fsidx.__fsid_val[1]; 441 lsp->l_fnamelen = bsp->f_namemax; 442 (void)memset(lsp->l_fspare, 0, sizeof(lsp->l_fspare)); 443 } 444 445 /* 446 * Implement the fs stat functions. Straightforward. 447 */ 448 int 449 linux_sys_statfs64(l, v, retval) 450 struct lwp *l; 451 void *v; 452 register_t *retval; 453 { 454 struct linux_sys_statfs64_args /* { 455 syscallarg(const char *) path; 456 syscallarg(size_t) sz; 457 syscallarg(struct linux_statfs64 *) sp; 458 } */ *uap = v; 459 struct statvfs *sb; 460 struct linux_statfs64 ltmp; 461 int error; 462 463 if (SCARG(uap, sz) != sizeof ltmp) 464 return (EINVAL); 465 466 sb = STATVFSBUF_GET(); 467 error = do_sys_pstatvfs(l, SCARG(uap, path), ST_WAIT, sb); 468 if (error == 0) { 469 bsd_to_linux_statfs64(sb, <mp); 470 error = copyout(<mp, SCARG(uap, sp), sizeof ltmp); 471 } 472 STATVFSBUF_PUT(sb); 473 return error; 474 } 475 476 int 477 linux_sys_fstatfs64(l, v, retval) 478 struct lwp *l; 479 void *v; 480 register_t *retval; 481 { 482 struct linux_sys_fstatfs64_args /* { 483 syscallarg(int) fd; 484 syscallarg(size_t) sz; 485 syscallarg(struct linux_statfs64 *) sp; 486 } */ *uap = v; 487 struct statvfs *sb; 488 struct linux_statfs64 ltmp; 489 int error; 490 491 if (SCARG(uap, sz) != sizeof ltmp) 492 return (EINVAL); 493 494 sb = STATVFSBUF_GET(); 495 error = do_sys_fstatvfs(l, SCARG(uap, fd), ST_WAIT, sb); 496 if (error == 0) { 497 bsd_to_linux_statfs64(sb, <mp); 498 error = copyout(<mp, SCARG(uap, sp), sizeof ltmp); 499 } 500 STATVFSBUF_PUT(sb); 501 return error; 502 } 503 #endif /* !__m68k__ && !__amd64__ */ 504 #endif /* !COMPAT_LINUX32 */ 505