1 /*- 2 * SPDX-License-Identifier: BSD-3-Clause 3 * 4 * Copyright (c) 1994-1995 Søren Schmidt 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer 12 * in this position and unchanged. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. The name of the author may not be used to endorse or promote products 17 * derived from this software without specific prior written permission 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include <sys/cdefs.h> 32 __FBSDID("$FreeBSD$"); 33 34 #include "opt_compat.h" 35 36 #include <sys/param.h> 37 #include <sys/capsicum.h> 38 #include <sys/dirent.h> 39 #include <sys/file.h> 40 #include <sys/filedesc.h> 41 #include <sys/proc.h> 42 #include <sys/malloc.h> 43 #include <sys/mount.h> 44 #include <sys/namei.h> 45 #include <sys/stat.h> 46 #include <sys/syscallsubr.h> 47 #include <sys/systm.h> 48 #include <sys/tty.h> 49 #include <sys/vnode.h> 50 #include <sys/conf.h> 51 #include <sys/fcntl.h> 52 53 #ifdef COMPAT_LINUX32 54 #include <machine/../linux32/linux.h> 55 #include <machine/../linux32/linux32_proto.h> 56 #else 57 #include <machine/../linux/linux.h> 58 #include <machine/../linux/linux_proto.h> 59 #endif 60 61 #include <compat/linux/linux_util.h> 62 #include <compat/linux/linux_file.h> 63 64 65 static void 66 translate_vnhook_major_minor(struct vnode *vp, struct stat *sb) 67 { 68 int major, minor; 69 70 if (vp->v_type == VCHR && vp->v_rdev != NULL && 71 linux_driver_get_major_minor(devtoname(vp->v_rdev), 72 &major, &minor) == 0) { 73 sb->st_rdev = (major << 8 | minor); 74 } 75 } 76 77 static int 78 linux_kern_statat(struct thread *td, int flag, int fd, char *path, 79 enum uio_seg pathseg, struct stat *sbp) 80 { 81 82 return (kern_statat(td, flag, fd, path, pathseg, sbp, 83 translate_vnhook_major_minor)); 84 } 85 86 static int 87 linux_kern_stat(struct thread *td, char *path, enum uio_seg pathseg, 88 struct stat *sbp) 89 { 90 91 return (linux_kern_statat(td, 0, AT_FDCWD, path, pathseg, sbp)); 92 } 93 94 static int 95 linux_kern_lstat(struct thread *td, char *path, enum uio_seg pathseg, 96 struct stat *sbp) 97 { 98 99 return (linux_kern_statat(td, AT_SYMLINK_NOFOLLOW, AT_FDCWD, path, 100 pathseg, sbp)); 101 } 102 103 static void 104 translate_fd_major_minor(struct thread *td, int fd, struct stat *buf) 105 { 106 struct file *fp; 107 struct vnode *vp; 108 cap_rights_t rights; 109 int major, minor; 110 111 /* 112 * No capability rights required here. 113 */ 114 if ((!S_ISCHR(buf->st_mode) && !S_ISBLK(buf->st_mode)) || 115 fget(td, fd, cap_rights_init(&rights), &fp) != 0) 116 return; 117 vp = fp->f_vnode; 118 if (vp != NULL && vp->v_rdev != NULL && 119 linux_driver_get_major_minor(devtoname(vp->v_rdev), 120 &major, &minor) == 0) { 121 buf->st_rdev = (major << 8 | minor); 122 } else if (fp->f_type == DTYPE_PTS) { 123 struct tty *tp = fp->f_data; 124 125 /* Convert the numbers for the slave device. */ 126 if (linux_driver_get_major_minor(devtoname(tp->t_dev), 127 &major, &minor) == 0) { 128 buf->st_rdev = (major << 8 | minor); 129 } 130 } 131 fdrop(fp, td); 132 } 133 134 static int 135 newstat_copyout(struct stat *buf, void *ubuf) 136 { 137 struct l_newstat tbuf; 138 139 bzero(&tbuf, sizeof(tbuf)); 140 tbuf.st_dev = minor(buf->st_dev) | (major(buf->st_dev) << 8); 141 tbuf.st_ino = buf->st_ino; 142 tbuf.st_mode = buf->st_mode; 143 tbuf.st_nlink = buf->st_nlink; 144 tbuf.st_uid = buf->st_uid; 145 tbuf.st_gid = buf->st_gid; 146 tbuf.st_rdev = buf->st_rdev; 147 tbuf.st_size = buf->st_size; 148 tbuf.st_atim.tv_sec = buf->st_atim.tv_sec; 149 tbuf.st_atim.tv_nsec = buf->st_atim.tv_nsec; 150 tbuf.st_mtim.tv_sec = buf->st_mtim.tv_sec; 151 tbuf.st_mtim.tv_nsec = buf->st_mtim.tv_nsec; 152 tbuf.st_ctim.tv_sec = buf->st_ctim.tv_sec; 153 tbuf.st_ctim.tv_nsec = buf->st_ctim.tv_nsec; 154 tbuf.st_blksize = buf->st_blksize; 155 tbuf.st_blocks = buf->st_blocks; 156 157 return (copyout(&tbuf, ubuf, sizeof(tbuf))); 158 } 159 160 int 161 linux_newstat(struct thread *td, struct linux_newstat_args *args) 162 { 163 struct stat buf; 164 char *path; 165 int error; 166 167 LCONVPATHEXIST(td, args->path, &path); 168 169 #ifdef DEBUG 170 if (ldebug(newstat)) 171 printf(ARGS(newstat, "%s, *"), path); 172 #endif 173 174 error = linux_kern_stat(td, path, UIO_SYSSPACE, &buf); 175 LFREEPATH(path); 176 if (error) 177 return (error); 178 return (newstat_copyout(&buf, args->buf)); 179 } 180 181 int 182 linux_newlstat(struct thread *td, struct linux_newlstat_args *args) 183 { 184 struct stat sb; 185 char *path; 186 int error; 187 188 LCONVPATHEXIST(td, args->path, &path); 189 190 #ifdef DEBUG 191 if (ldebug(newlstat)) 192 printf(ARGS(newlstat, "%s, *"), path); 193 #endif 194 195 error = linux_kern_lstat(td, path, UIO_SYSSPACE, &sb); 196 LFREEPATH(path); 197 if (error) 198 return (error); 199 return (newstat_copyout(&sb, args->buf)); 200 } 201 202 int 203 linux_newfstat(struct thread *td, struct linux_newfstat_args *args) 204 { 205 struct stat buf; 206 int error; 207 208 #ifdef DEBUG 209 if (ldebug(newfstat)) 210 printf(ARGS(newfstat, "%d, *"), args->fd); 211 #endif 212 213 error = kern_fstat(td, args->fd, &buf); 214 translate_fd_major_minor(td, args->fd, &buf); 215 if (!error) 216 error = newstat_copyout(&buf, args->buf); 217 218 return (error); 219 } 220 221 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) 222 static int 223 stat_copyout(struct stat *buf, void *ubuf) 224 { 225 struct l_stat lbuf; 226 227 bzero(&lbuf, sizeof(lbuf)); 228 lbuf.st_dev = buf->st_dev; 229 lbuf.st_ino = buf->st_ino; 230 lbuf.st_mode = buf->st_mode; 231 lbuf.st_nlink = buf->st_nlink; 232 lbuf.st_uid = buf->st_uid; 233 lbuf.st_gid = buf->st_gid; 234 lbuf.st_rdev = buf->st_rdev; 235 if (buf->st_size < (quad_t)1 << 32) 236 lbuf.st_size = buf->st_size; 237 else 238 lbuf.st_size = -2; 239 lbuf.st_atim.tv_sec = buf->st_atim.tv_sec; 240 lbuf.st_atim.tv_nsec = buf->st_atim.tv_nsec; 241 lbuf.st_mtim.tv_sec = buf->st_mtim.tv_sec; 242 lbuf.st_mtim.tv_nsec = buf->st_mtim.tv_nsec; 243 lbuf.st_ctim.tv_sec = buf->st_ctim.tv_sec; 244 lbuf.st_ctim.tv_nsec = buf->st_ctim.tv_nsec; 245 lbuf.st_blksize = buf->st_blksize; 246 lbuf.st_blocks = buf->st_blocks; 247 lbuf.st_flags = buf->st_flags; 248 lbuf.st_gen = buf->st_gen; 249 250 return (copyout(&lbuf, ubuf, sizeof(lbuf))); 251 } 252 253 int 254 linux_stat(struct thread *td, struct linux_stat_args *args) 255 { 256 struct stat buf; 257 char *path; 258 int error; 259 260 LCONVPATHEXIST(td, args->path, &path); 261 262 #ifdef DEBUG 263 if (ldebug(stat)) 264 printf(ARGS(stat, "%s, *"), path); 265 #endif 266 error = linux_kern_stat(td, path, UIO_SYSSPACE, &buf); 267 if (error) { 268 LFREEPATH(path); 269 return (error); 270 } 271 LFREEPATH(path); 272 return (stat_copyout(&buf, args->up)); 273 } 274 275 int 276 linux_lstat(struct thread *td, struct linux_lstat_args *args) 277 { 278 struct stat buf; 279 char *path; 280 int error; 281 282 LCONVPATHEXIST(td, args->path, &path); 283 284 #ifdef DEBUG 285 if (ldebug(lstat)) 286 printf(ARGS(lstat, "%s, *"), path); 287 #endif 288 error = linux_kern_lstat(td, path, UIO_SYSSPACE, &buf); 289 if (error) { 290 LFREEPATH(path); 291 return (error); 292 } 293 LFREEPATH(path); 294 return (stat_copyout(&buf, args->up)); 295 } 296 #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ 297 298 struct l_statfs { 299 l_long f_type; 300 l_long f_bsize; 301 l_long f_blocks; 302 l_long f_bfree; 303 l_long f_bavail; 304 l_long f_files; 305 l_long f_ffree; 306 l_fsid_t f_fsid; 307 l_long f_namelen; 308 l_long f_frsize; 309 l_long f_flags; 310 l_long f_spare[4]; 311 }; 312 313 #define LINUX_CODA_SUPER_MAGIC 0x73757245L 314 #define LINUX_EXT2_SUPER_MAGIC 0xEF53L 315 #define LINUX_HPFS_SUPER_MAGIC 0xf995e849L 316 #define LINUX_ISOFS_SUPER_MAGIC 0x9660L 317 #define LINUX_MSDOS_SUPER_MAGIC 0x4d44L 318 #define LINUX_NCP_SUPER_MAGIC 0x564cL 319 #define LINUX_NFS_SUPER_MAGIC 0x6969L 320 #define LINUX_NTFS_SUPER_MAGIC 0x5346544EL 321 #define LINUX_PROC_SUPER_MAGIC 0x9fa0L 322 #define LINUX_UFS_SUPER_MAGIC 0x00011954L /* XXX - UFS_MAGIC in Linux */ 323 #define LINUX_ZFS_SUPER_MAGIC 0x2FC12FC1 324 #define LINUX_DEVFS_SUPER_MAGIC 0x1373L 325 #define LINUX_SHMFS_MAGIC 0x01021994 326 327 static long 328 bsd_to_linux_ftype(const char *fstypename) 329 { 330 int i; 331 static struct {const char *bsd_name; long linux_type;} b2l_tbl[] = { 332 {"ufs", LINUX_UFS_SUPER_MAGIC}, 333 {"zfs", LINUX_ZFS_SUPER_MAGIC}, 334 {"cd9660", LINUX_ISOFS_SUPER_MAGIC}, 335 {"nfs", LINUX_NFS_SUPER_MAGIC}, 336 {"ext2fs", LINUX_EXT2_SUPER_MAGIC}, 337 {"procfs", LINUX_PROC_SUPER_MAGIC}, 338 {"msdosfs", LINUX_MSDOS_SUPER_MAGIC}, 339 {"ntfs", LINUX_NTFS_SUPER_MAGIC}, 340 {"nwfs", LINUX_NCP_SUPER_MAGIC}, 341 {"hpfs", LINUX_HPFS_SUPER_MAGIC}, 342 {"coda", LINUX_CODA_SUPER_MAGIC}, 343 {"devfs", LINUX_DEVFS_SUPER_MAGIC}, 344 {"tmpfs", LINUX_SHMFS_MAGIC}, 345 {NULL, 0L}}; 346 347 for (i = 0; b2l_tbl[i].bsd_name != NULL; i++) 348 if (strcmp(b2l_tbl[i].bsd_name, fstypename) == 0) 349 return (b2l_tbl[i].linux_type); 350 351 return (0L); 352 } 353 354 static int 355 bsd_to_linux_statfs(struct statfs *bsd_statfs, struct l_statfs *linux_statfs) 356 { 357 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) 358 uint64_t tmp; 359 360 #define LINUX_HIBITS 0xffffffff00000000ULL 361 362 tmp = bsd_statfs->f_blocks | bsd_statfs->f_bfree | bsd_statfs->f_files | 363 bsd_statfs->f_bsize; 364 if ((bsd_statfs->f_bavail != -1 && (bsd_statfs->f_bavail & LINUX_HIBITS)) || 365 (bsd_statfs->f_ffree != -1 && (bsd_statfs->f_ffree & LINUX_HIBITS)) || 366 (tmp & LINUX_HIBITS)) 367 return (EOVERFLOW); 368 #undef LINUX_HIBITS 369 #endif 370 linux_statfs->f_type = bsd_to_linux_ftype(bsd_statfs->f_fstypename); 371 linux_statfs->f_bsize = bsd_statfs->f_bsize; 372 linux_statfs->f_blocks = bsd_statfs->f_blocks; 373 linux_statfs->f_bfree = bsd_statfs->f_bfree; 374 linux_statfs->f_bavail = bsd_statfs->f_bavail; 375 linux_statfs->f_ffree = bsd_statfs->f_ffree; 376 linux_statfs->f_files = bsd_statfs->f_files; 377 linux_statfs->f_fsid.val[0] = bsd_statfs->f_fsid.val[0]; 378 linux_statfs->f_fsid.val[1] = bsd_statfs->f_fsid.val[1]; 379 linux_statfs->f_namelen = MAXNAMLEN; 380 linux_statfs->f_frsize = bsd_statfs->f_bsize; 381 linux_statfs->f_flags = 0; 382 memset(linux_statfs->f_spare, 0, sizeof(linux_statfs->f_spare)); 383 384 return (0); 385 } 386 387 int 388 linux_statfs(struct thread *td, struct linux_statfs_args *args) 389 { 390 struct l_statfs linux_statfs; 391 struct statfs *bsd_statfs; 392 char *path; 393 int error; 394 395 LCONVPATHEXIST(td, args->path, &path); 396 397 #ifdef DEBUG 398 if (ldebug(statfs)) 399 printf(ARGS(statfs, "%s, *"), path); 400 #endif 401 bsd_statfs = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK); 402 error = kern_statfs(td, path, UIO_SYSSPACE, bsd_statfs); 403 LFREEPATH(path); 404 if (error == 0) 405 error = bsd_to_linux_statfs(bsd_statfs, &linux_statfs); 406 free(bsd_statfs, M_STATFS); 407 if (error != 0) 408 return (error); 409 return (copyout(&linux_statfs, args->buf, sizeof(linux_statfs))); 410 } 411 412 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) 413 static void 414 bsd_to_linux_statfs64(struct statfs *bsd_statfs, struct l_statfs64 *linux_statfs) 415 { 416 417 linux_statfs->f_type = bsd_to_linux_ftype(bsd_statfs->f_fstypename); 418 linux_statfs->f_bsize = bsd_statfs->f_bsize; 419 linux_statfs->f_blocks = bsd_statfs->f_blocks; 420 linux_statfs->f_bfree = bsd_statfs->f_bfree; 421 linux_statfs->f_bavail = bsd_statfs->f_bavail; 422 linux_statfs->f_ffree = bsd_statfs->f_ffree; 423 linux_statfs->f_files = bsd_statfs->f_files; 424 linux_statfs->f_fsid.val[0] = bsd_statfs->f_fsid.val[0]; 425 linux_statfs->f_fsid.val[1] = bsd_statfs->f_fsid.val[1]; 426 linux_statfs->f_namelen = MAXNAMLEN; 427 linux_statfs->f_frsize = bsd_statfs->f_bsize; 428 linux_statfs->f_flags = 0; 429 memset(linux_statfs->f_spare, 0, sizeof(linux_statfs->f_spare)); 430 } 431 432 int 433 linux_statfs64(struct thread *td, struct linux_statfs64_args *args) 434 { 435 struct l_statfs64 linux_statfs; 436 struct statfs *bsd_statfs; 437 char *path; 438 int error; 439 440 if (args->bufsize != sizeof(struct l_statfs64)) 441 return EINVAL; 442 443 LCONVPATHEXIST(td, args->path, &path); 444 445 #ifdef DEBUG 446 if (ldebug(statfs64)) 447 printf(ARGS(statfs64, "%s, *"), path); 448 #endif 449 bsd_statfs = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK); 450 error = kern_statfs(td, path, UIO_SYSSPACE, bsd_statfs); 451 LFREEPATH(path); 452 if (error == 0) 453 bsd_to_linux_statfs64(bsd_statfs, &linux_statfs); 454 free(bsd_statfs, M_STATFS); 455 if (error != 0) 456 return (error); 457 return (copyout(&linux_statfs, args->buf, sizeof(linux_statfs))); 458 } 459 460 int 461 linux_fstatfs64(struct thread *td, struct linux_fstatfs64_args *args) 462 { 463 struct l_statfs64 linux_statfs; 464 struct statfs *bsd_statfs; 465 int error; 466 467 #ifdef DEBUG 468 if (ldebug(fstatfs64)) 469 printf(ARGS(fstatfs64, "%d, *"), args->fd); 470 #endif 471 if (args->bufsize != sizeof(struct l_statfs64)) 472 return (EINVAL); 473 474 bsd_statfs = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK); 475 error = kern_fstatfs(td, args->fd, bsd_statfs); 476 if (error == 0) 477 bsd_to_linux_statfs64(bsd_statfs, &linux_statfs); 478 free(bsd_statfs, M_STATFS); 479 if (error != 0) 480 return (error); 481 return (copyout(&linux_statfs, args->buf, sizeof(linux_statfs))); 482 } 483 #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ 484 485 int 486 linux_fstatfs(struct thread *td, struct linux_fstatfs_args *args) 487 { 488 struct l_statfs linux_statfs; 489 struct statfs *bsd_statfs; 490 int error; 491 492 #ifdef DEBUG 493 if (ldebug(fstatfs)) 494 printf(ARGS(fstatfs, "%d, *"), args->fd); 495 #endif 496 bsd_statfs = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK); 497 error = kern_fstatfs(td, args->fd, bsd_statfs); 498 if (error == 0) 499 error = bsd_to_linux_statfs(bsd_statfs, &linux_statfs); 500 free(bsd_statfs, M_STATFS); 501 if (error != 0) 502 return (error); 503 return (copyout(&linux_statfs, args->buf, sizeof(linux_statfs))); 504 } 505 506 struct l_ustat 507 { 508 l_daddr_t f_tfree; 509 l_ino_t f_tinode; 510 char f_fname[6]; 511 char f_fpack[6]; 512 }; 513 514 int 515 linux_ustat(struct thread *td, struct linux_ustat_args *args) 516 { 517 #ifdef DEBUG 518 if (ldebug(ustat)) 519 printf(ARGS(ustat, "%ju, *"), (uintmax_t)args->dev); 520 #endif 521 522 return (EOPNOTSUPP); 523 } 524 525 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) 526 527 static int 528 stat64_copyout(struct stat *buf, void *ubuf) 529 { 530 struct l_stat64 lbuf; 531 532 bzero(&lbuf, sizeof(lbuf)); 533 lbuf.st_dev = minor(buf->st_dev) | (major(buf->st_dev) << 8); 534 lbuf.st_ino = buf->st_ino; 535 lbuf.st_mode = buf->st_mode; 536 lbuf.st_nlink = buf->st_nlink; 537 lbuf.st_uid = buf->st_uid; 538 lbuf.st_gid = buf->st_gid; 539 lbuf.st_rdev = buf->st_rdev; 540 lbuf.st_size = buf->st_size; 541 lbuf.st_atim.tv_sec = buf->st_atim.tv_sec; 542 lbuf.st_atim.tv_nsec = buf->st_atim.tv_nsec; 543 lbuf.st_mtim.tv_sec = buf->st_mtim.tv_sec; 544 lbuf.st_mtim.tv_nsec = buf->st_mtim.tv_nsec; 545 lbuf.st_ctim.tv_sec = buf->st_ctim.tv_sec; 546 lbuf.st_ctim.tv_nsec = buf->st_ctim.tv_nsec; 547 lbuf.st_blksize = buf->st_blksize; 548 lbuf.st_blocks = buf->st_blocks; 549 550 /* 551 * The __st_ino field makes all the difference. In the Linux kernel 552 * it is conditionally compiled based on STAT64_HAS_BROKEN_ST_INO, 553 * but without the assignment to __st_ino the runtime linker refuses 554 * to mmap(2) any shared libraries. I guess it's broken alright :-) 555 */ 556 lbuf.__st_ino = buf->st_ino; 557 558 return (copyout(&lbuf, ubuf, sizeof(lbuf))); 559 } 560 561 int 562 linux_stat64(struct thread *td, struct linux_stat64_args *args) 563 { 564 struct stat buf; 565 char *filename; 566 int error; 567 568 LCONVPATHEXIST(td, args->filename, &filename); 569 570 #ifdef DEBUG 571 if (ldebug(stat64)) 572 printf(ARGS(stat64, "%s, *"), filename); 573 #endif 574 575 error = linux_kern_stat(td, filename, UIO_SYSSPACE, &buf); 576 LFREEPATH(filename); 577 if (error) 578 return (error); 579 return (stat64_copyout(&buf, args->statbuf)); 580 } 581 582 int 583 linux_lstat64(struct thread *td, struct linux_lstat64_args *args) 584 { 585 struct stat sb; 586 char *filename; 587 int error; 588 589 LCONVPATHEXIST(td, args->filename, &filename); 590 591 #ifdef DEBUG 592 if (ldebug(lstat64)) 593 printf(ARGS(lstat64, "%s, *"), args->filename); 594 #endif 595 596 error = linux_kern_lstat(td, filename, UIO_SYSSPACE, &sb); 597 LFREEPATH(filename); 598 if (error) 599 return (error); 600 return (stat64_copyout(&sb, args->statbuf)); 601 } 602 603 int 604 linux_fstat64(struct thread *td, struct linux_fstat64_args *args) 605 { 606 struct stat buf; 607 int error; 608 609 #ifdef DEBUG 610 if (ldebug(fstat64)) 611 printf(ARGS(fstat64, "%d, *"), args->fd); 612 #endif 613 614 error = kern_fstat(td, args->fd, &buf); 615 translate_fd_major_minor(td, args->fd, &buf); 616 if (!error) 617 error = stat64_copyout(&buf, args->statbuf); 618 619 return (error); 620 } 621 622 int 623 linux_fstatat64(struct thread *td, struct linux_fstatat64_args *args) 624 { 625 char *path; 626 int error, dfd, flag; 627 struct stat buf; 628 629 if (args->flag & ~LINUX_AT_SYMLINK_NOFOLLOW) 630 return (EINVAL); 631 flag = (args->flag & LINUX_AT_SYMLINK_NOFOLLOW) ? 632 AT_SYMLINK_NOFOLLOW : 0; 633 634 dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; 635 LCONVPATHEXIST_AT(td, args->pathname, &path, dfd); 636 637 #ifdef DEBUG 638 if (ldebug(fstatat64)) 639 printf(ARGS(fstatat64, "%i, %s, %i"), args->dfd, path, args->flag); 640 #endif 641 642 error = linux_kern_statat(td, flag, dfd, path, UIO_SYSSPACE, &buf); 643 if (!error) 644 error = stat64_copyout(&buf, args->statbuf); 645 LFREEPATH(path); 646 647 return (error); 648 } 649 650 #else /* __amd64__ && !COMPAT_LINUX32 */ 651 652 int 653 linux_newfstatat(struct thread *td, struct linux_newfstatat_args *args) 654 { 655 char *path; 656 int error, dfd, flag; 657 struct stat buf; 658 659 if (args->flag & ~LINUX_AT_SYMLINK_NOFOLLOW) 660 return (EINVAL); 661 flag = (args->flag & LINUX_AT_SYMLINK_NOFOLLOW) ? 662 AT_SYMLINK_NOFOLLOW : 0; 663 664 dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; 665 LCONVPATHEXIST_AT(td, args->pathname, &path, dfd); 666 667 #ifdef DEBUG 668 if (ldebug(newfstatat)) 669 printf(ARGS(newfstatat, "%i, %s, %i"), args->dfd, path, args->flag); 670 #endif 671 672 error = linux_kern_statat(td, flag, dfd, path, UIO_SYSSPACE, &buf); 673 if (error == 0) 674 error = newstat_copyout(&buf, args->statbuf); 675 LFREEPATH(path); 676 677 return (error); 678 } 679 680 #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ 681 682 int 683 linux_syncfs(struct thread *td, struct linux_syncfs_args *args) 684 { 685 cap_rights_t rights; 686 struct mount *mp; 687 struct vnode *vp; 688 int error, save; 689 690 error = fgetvp(td, args->fd, cap_rights_init(&rights, CAP_FSYNC), &vp); 691 if (error != 0) 692 /* 693 * Linux syncfs() returns only EBADF, however fgetvp() 694 * can return EINVAL in case of file descriptor does 695 * not represent a vnode. XXX. 696 */ 697 return (error); 698 699 mp = vp->v_mount; 700 mtx_lock(&mountlist_mtx); 701 error = vfs_busy(mp, MBF_MNTLSTLOCK); 702 if (error != 0) { 703 /* See comment above. */ 704 mtx_unlock(&mountlist_mtx); 705 goto out; 706 } 707 if ((mp->mnt_flag & MNT_RDONLY) == 0 && 708 vn_start_write(NULL, &mp, V_NOWAIT) == 0) { 709 save = curthread_pflags_set(TDP_SYNCIO); 710 vfs_msync(mp, MNT_NOWAIT); 711 VFS_SYNC(mp, MNT_NOWAIT); 712 curthread_pflags_restore(save); 713 vn_finished_write(mp); 714 } 715 vfs_unbusy(mp); 716 717 out: 718 vrele(vp); 719 return (error); 720 } 721