1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 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 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 __FBSDID("$FreeBSD$"); 31 32 #include <sys/param.h> 33 #include <sys/capsicum.h> 34 #include <sys/dirent.h> 35 #include <sys/file.h> 36 #include <sys/filedesc.h> 37 #include <sys/proc.h> 38 #include <sys/malloc.h> 39 #include <sys/mount.h> 40 #include <sys/namei.h> 41 #include <sys/stat.h> 42 #include <sys/syscallsubr.h> 43 #include <sys/systm.h> 44 #include <sys/tty.h> 45 #include <sys/vnode.h> 46 #include <sys/conf.h> 47 #include <sys/fcntl.h> 48 49 #ifdef COMPAT_LINUX32 50 #include <machine/../linux32/linux.h> 51 #include <machine/../linux32/linux32_proto.h> 52 #else 53 #include <machine/../linux/linux.h> 54 #include <machine/../linux/linux_proto.h> 55 #endif 56 57 #include <compat/linux/linux_util.h> 58 #include <compat/linux/linux_file.h> 59 60 static void 61 translate_vnhook_major_minor(struct vnode *vp, struct stat *sb) 62 { 63 int major, minor; 64 65 if (vn_isdisk(vp)) { 66 sb->st_mode &= ~S_IFMT; 67 sb->st_mode |= S_IFBLK; 68 } 69 70 /* 71 * Return the same st_dev for every devfs instance. The reason 72 * for this is to work around an idiosyncrasy of glibc getttynam() 73 * implementation: it checks whether st_dev returned for fd 0 74 * is the same as st_dev returned for the target of /proc/self/fd/0 75 * symlink, and with linux chroots having their own devfs instance, 76 * the check will fail if you chroot into it. 77 */ 78 if (rootdevmp != NULL && vp->v_mount->mnt_vfc == rootdevmp->mnt_vfc) 79 sb->st_dev = rootdevmp->mnt_stat.f_fsid.val[0]; 80 81 if (linux_vn_get_major_minor(vp, &major, &minor) == 0) 82 sb->st_rdev = (major << 8 | minor); 83 } 84 85 static int 86 linux_kern_statat(struct thread *td, int flag, int fd, const char *path, 87 enum uio_seg pathseg, struct stat *sbp) 88 { 89 90 return (kern_statat(td, flag, fd, path, pathseg, sbp, 91 translate_vnhook_major_minor)); 92 } 93 94 #ifdef LINUX_LEGACY_SYSCALLS 95 static int 96 linux_kern_stat(struct thread *td, const char *path, enum uio_seg pathseg, 97 struct stat *sbp) 98 { 99 100 return (linux_kern_statat(td, 0, AT_FDCWD, path, pathseg, sbp)); 101 } 102 103 static int 104 linux_kern_lstat(struct thread *td, const char *path, enum uio_seg pathseg, 105 struct stat *sbp) 106 { 107 108 return (linux_kern_statat(td, AT_SYMLINK_NOFOLLOW, AT_FDCWD, path, 109 pathseg, sbp)); 110 } 111 #endif 112 113 static void 114 translate_fd_major_minor(struct thread *td, int fd, struct stat *buf) 115 { 116 struct file *fp; 117 struct vnode *vp; 118 struct mount *mp; 119 int major, minor; 120 121 /* 122 * No capability rights required here. 123 */ 124 if ((!S_ISCHR(buf->st_mode) && !S_ISBLK(buf->st_mode)) || 125 fget(td, fd, &cap_no_rights, &fp) != 0) 126 return; 127 vp = fp->f_vnode; 128 if (vp != NULL && vn_isdisk(vp)) { 129 buf->st_mode &= ~S_IFMT; 130 buf->st_mode |= S_IFBLK; 131 } 132 if (vp != NULL && rootdevmp != NULL) { 133 mp = vp->v_mount; 134 __compiler_membar(); 135 if (mp != NULL && mp->mnt_vfc == rootdevmp->mnt_vfc) 136 buf->st_dev = rootdevmp->mnt_stat.f_fsid.val[0]; 137 } 138 if (linux_vn_get_major_minor(vp, &major, &minor) == 0) { 139 buf->st_rdev = (major << 8 | minor); 140 } else if (fp->f_type == DTYPE_PTS) { 141 struct tty *tp = fp->f_data; 142 143 /* Convert the numbers for the slave device. */ 144 if (linux_driver_get_major_minor(devtoname(tp->t_dev), 145 &major, &minor) == 0) { 146 buf->st_rdev = (major << 8 | minor); 147 } 148 } 149 fdrop(fp, td); 150 } 151 152 /* 153 * l_dev_t has the same encoding as dev_t in the latter's low 16 bits, so 154 * truncation of a dev_t to 16 bits gives the same result as unpacking 155 * using major() and minor() and repacking in the l_dev_t format. This 156 * detail is hidden in dev_to_ldev(). Overflow in conversions of dev_t's 157 * are not checked for, as for other fields. 158 * 159 * dev_to_ldev() is only used for translating st_dev. When we convert 160 * st_rdev for copying it out, it isn't really a dev_t, but has already 161 * been translated to an l_dev_t in a nontrivial way. Translating it 162 * again would be illogical but would have no effect since the low 16 163 * bits have the same encoding. 164 * 165 * The nontrivial translation for st_rdev renumbers some devices, but not 166 * ones that can be mounted on, so it is consistent with the translation 167 * for st_dev except when the renumbering or truncation causes conflicts. 168 */ 169 #define dev_to_ldev(d) ((uint16_t)(d)) 170 171 static int 172 newstat_copyout(struct stat *buf, void *ubuf) 173 { 174 struct l_newstat tbuf; 175 176 bzero(&tbuf, sizeof(tbuf)); 177 tbuf.st_dev = dev_to_ldev(buf->st_dev); 178 tbuf.st_ino = buf->st_ino; 179 tbuf.st_mode = buf->st_mode; 180 tbuf.st_nlink = buf->st_nlink; 181 tbuf.st_uid = buf->st_uid; 182 tbuf.st_gid = buf->st_gid; 183 tbuf.st_rdev = buf->st_rdev; 184 tbuf.st_size = buf->st_size; 185 tbuf.st_atim.tv_sec = buf->st_atim.tv_sec; 186 tbuf.st_atim.tv_nsec = buf->st_atim.tv_nsec; 187 tbuf.st_mtim.tv_sec = buf->st_mtim.tv_sec; 188 tbuf.st_mtim.tv_nsec = buf->st_mtim.tv_nsec; 189 tbuf.st_ctim.tv_sec = buf->st_ctim.tv_sec; 190 tbuf.st_ctim.tv_nsec = buf->st_ctim.tv_nsec; 191 tbuf.st_blksize = buf->st_blksize; 192 tbuf.st_blocks = buf->st_blocks; 193 194 return (copyout(&tbuf, ubuf, sizeof(tbuf))); 195 } 196 197 static int 198 statx_copyout(struct stat *buf, void *ubuf) 199 { 200 struct l_statx tbuf; 201 202 bzero(&tbuf, sizeof(tbuf)); 203 tbuf.stx_mask = STATX_ALL; 204 tbuf.stx_blksize = buf->st_blksize; 205 tbuf.stx_attributes = 0; 206 tbuf.stx_nlink = buf->st_nlink; 207 tbuf.stx_uid = buf->st_uid; 208 tbuf.stx_gid = buf->st_gid; 209 tbuf.stx_mode = buf->st_mode; 210 tbuf.stx_ino = buf->st_ino; 211 tbuf.stx_size = buf->st_size; 212 tbuf.stx_blocks = buf->st_blocks; 213 214 tbuf.stx_atime.tv_sec = buf->st_atim.tv_sec; 215 tbuf.stx_atime.tv_nsec = buf->st_atim.tv_nsec; 216 tbuf.stx_btime.tv_sec = buf->st_birthtim.tv_sec; 217 tbuf.stx_btime.tv_nsec = buf->st_birthtim.tv_nsec; 218 tbuf.stx_ctime.tv_sec = buf->st_ctim.tv_sec; 219 tbuf.stx_ctime.tv_nsec = buf->st_ctim.tv_nsec; 220 tbuf.stx_mtime.tv_sec = buf->st_mtim.tv_sec; 221 tbuf.stx_mtime.tv_nsec = buf->st_mtim.tv_nsec; 222 223 tbuf.stx_rdev_major = buf->st_rdev >> 8; 224 tbuf.stx_rdev_minor = buf->st_rdev & 0xff; 225 tbuf.stx_dev_major = buf->st_dev >> 8; 226 tbuf.stx_dev_minor = buf->st_dev & 0xff; 227 228 return (copyout(&tbuf, ubuf, sizeof(tbuf))); 229 } 230 231 #ifdef LINUX_LEGACY_SYSCALLS 232 int 233 linux_newstat(struct thread *td, struct linux_newstat_args *args) 234 { 235 struct stat buf; 236 char *path; 237 int error; 238 239 if (!LUSECONVPATH(td)) { 240 error = linux_kern_stat(td, args->path, UIO_USERSPACE, &buf); 241 } else { 242 LCONVPATHEXIST(args->path, &path); 243 error = linux_kern_stat(td, path, UIO_SYSSPACE, &buf); 244 LFREEPATH(path); 245 } 246 if (error) 247 return (error); 248 return (newstat_copyout(&buf, args->buf)); 249 } 250 251 int 252 linux_newlstat(struct thread *td, struct linux_newlstat_args *args) 253 { 254 struct stat sb; 255 char *path; 256 int error; 257 258 if (!LUSECONVPATH(td)) { 259 error = linux_kern_lstat(td, args->path, UIO_USERSPACE, &sb); 260 } else { 261 LCONVPATHEXIST(args->path, &path); 262 error = linux_kern_lstat(td, path, UIO_SYSSPACE, &sb); 263 LFREEPATH(path); 264 } 265 if (error) 266 return (error); 267 return (newstat_copyout(&sb, args->buf)); 268 } 269 #endif 270 271 int 272 linux_newfstat(struct thread *td, struct linux_newfstat_args *args) 273 { 274 struct stat buf; 275 int error; 276 277 error = kern_fstat(td, args->fd, &buf); 278 translate_fd_major_minor(td, args->fd, &buf); 279 if (!error) 280 error = newstat_copyout(&buf, args->buf); 281 282 return (error); 283 } 284 285 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) 286 static int 287 stat_copyout(struct stat *buf, void *ubuf) 288 { 289 struct l_stat lbuf; 290 291 bzero(&lbuf, sizeof(lbuf)); 292 lbuf.st_dev = dev_to_ldev(buf->st_dev); 293 lbuf.st_ino = buf->st_ino; 294 lbuf.st_mode = buf->st_mode; 295 lbuf.st_nlink = buf->st_nlink; 296 lbuf.st_uid = buf->st_uid; 297 lbuf.st_gid = buf->st_gid; 298 lbuf.st_rdev = buf->st_rdev; 299 lbuf.st_size = MIN(buf->st_size, INT32_MAX); 300 lbuf.st_atim.tv_sec = buf->st_atim.tv_sec; 301 lbuf.st_atim.tv_nsec = buf->st_atim.tv_nsec; 302 lbuf.st_mtim.tv_sec = buf->st_mtim.tv_sec; 303 lbuf.st_mtim.tv_nsec = buf->st_mtim.tv_nsec; 304 lbuf.st_ctim.tv_sec = buf->st_ctim.tv_sec; 305 lbuf.st_ctim.tv_nsec = buf->st_ctim.tv_nsec; 306 lbuf.st_blksize = buf->st_blksize; 307 lbuf.st_blocks = buf->st_blocks; 308 lbuf.st_flags = buf->st_flags; 309 lbuf.st_gen = buf->st_gen; 310 311 return (copyout(&lbuf, ubuf, sizeof(lbuf))); 312 } 313 314 int 315 linux_stat(struct thread *td, struct linux_stat_args *args) 316 { 317 struct stat buf; 318 char *path; 319 int error; 320 321 if (!LUSECONVPATH(td)) { 322 error = linux_kern_stat(td, args->path, UIO_USERSPACE, &buf); 323 } else { 324 LCONVPATHEXIST(args->path, &path); 325 error = linux_kern_stat(td, path, UIO_SYSSPACE, &buf); 326 LFREEPATH(path); 327 } 328 if (error) { 329 return (error); 330 } 331 return (stat_copyout(&buf, args->up)); 332 } 333 334 int 335 linux_lstat(struct thread *td, struct linux_lstat_args *args) 336 { 337 struct stat buf; 338 char *path; 339 int error; 340 341 if (!LUSECONVPATH(td)) { 342 error = linux_kern_lstat(td, args->path, UIO_USERSPACE, &buf); 343 } else { 344 LCONVPATHEXIST(args->path, &path); 345 error = linux_kern_lstat(td, path, UIO_SYSSPACE, &buf); 346 LFREEPATH(path); 347 } 348 if (error) { 349 return (error); 350 } 351 return (stat_copyout(&buf, args->up)); 352 } 353 #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ 354 355 struct l_statfs { 356 l_long f_type; 357 l_long f_bsize; 358 l_long f_blocks; 359 l_long f_bfree; 360 l_long f_bavail; 361 l_long f_files; 362 l_long f_ffree; 363 l_fsid_t f_fsid; 364 l_long f_namelen; 365 l_long f_frsize; 366 l_long f_flags; 367 l_long f_spare[4]; 368 }; 369 370 #define LINUX_CODA_SUPER_MAGIC 0x73757245L 371 #define LINUX_EXT2_SUPER_MAGIC 0xEF53L 372 #define LINUX_HPFS_SUPER_MAGIC 0xf995e849L 373 #define LINUX_ISOFS_SUPER_MAGIC 0x9660L 374 #define LINUX_MSDOS_SUPER_MAGIC 0x4d44L 375 #define LINUX_NCP_SUPER_MAGIC 0x564cL 376 #define LINUX_NFS_SUPER_MAGIC 0x6969L 377 #define LINUX_NTFS_SUPER_MAGIC 0x5346544EL 378 #define LINUX_PROC_SUPER_MAGIC 0x9fa0L 379 #define LINUX_UFS_SUPER_MAGIC 0x00011954L /* XXX - UFS_MAGIC in Linux */ 380 #define LINUX_ZFS_SUPER_MAGIC 0x2FC12FC1 381 #define LINUX_DEVFS_SUPER_MAGIC 0x1373L 382 #define LINUX_SHMFS_MAGIC 0x01021994 383 384 static long 385 bsd_to_linux_ftype(const char *fstypename) 386 { 387 int i; 388 static struct {const char *bsd_name; long linux_type;} b2l_tbl[] = { 389 {"ufs", LINUX_UFS_SUPER_MAGIC}, 390 {"zfs", LINUX_ZFS_SUPER_MAGIC}, 391 {"cd9660", LINUX_ISOFS_SUPER_MAGIC}, 392 {"nfs", LINUX_NFS_SUPER_MAGIC}, 393 {"ext2fs", LINUX_EXT2_SUPER_MAGIC}, 394 {"procfs", LINUX_PROC_SUPER_MAGIC}, 395 {"msdosfs", LINUX_MSDOS_SUPER_MAGIC}, 396 {"ntfs", LINUX_NTFS_SUPER_MAGIC}, 397 {"nwfs", LINUX_NCP_SUPER_MAGIC}, 398 {"hpfs", LINUX_HPFS_SUPER_MAGIC}, 399 {"coda", LINUX_CODA_SUPER_MAGIC}, 400 {"devfs", LINUX_DEVFS_SUPER_MAGIC}, 401 {"tmpfs", LINUX_SHMFS_MAGIC}, 402 {NULL, 0L}}; 403 404 for (i = 0; b2l_tbl[i].bsd_name != NULL; i++) 405 if (strcmp(b2l_tbl[i].bsd_name, fstypename) == 0) 406 return (b2l_tbl[i].linux_type); 407 408 return (0L); 409 } 410 411 static int 412 bsd_to_linux_mnt_flags(int f_flags) 413 { 414 int flags = LINUX_ST_VALID; 415 416 if (f_flags & MNT_RDONLY) 417 flags |= LINUX_ST_RDONLY; 418 if (f_flags & MNT_NOEXEC) 419 flags |= LINUX_ST_NOEXEC; 420 if (f_flags & MNT_NOSUID) 421 flags |= LINUX_ST_NOSUID; 422 if (f_flags & MNT_NOATIME) 423 flags |= LINUX_ST_NOATIME; 424 if (f_flags & MNT_NOSYMFOLLOW) 425 flags |= LINUX_ST_NOSYMFOLLOW; 426 if (f_flags & MNT_SYNCHRONOUS) 427 flags |= LINUX_ST_SYNCHRONOUS; 428 429 return (flags); 430 } 431 432 static int 433 bsd_to_linux_statfs(struct statfs *bsd_statfs, struct l_statfs *linux_statfs) 434 { 435 436 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) 437 statfs_scale_blocks(bsd_statfs, INT32_MAX); 438 #endif 439 linux_statfs->f_type = bsd_to_linux_ftype(bsd_statfs->f_fstypename); 440 linux_statfs->f_bsize = bsd_statfs->f_bsize; 441 linux_statfs->f_blocks = bsd_statfs->f_blocks; 442 linux_statfs->f_bfree = bsd_statfs->f_bfree; 443 linux_statfs->f_bavail = bsd_statfs->f_bavail; 444 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) 445 linux_statfs->f_ffree = MIN(bsd_statfs->f_ffree, INT32_MAX); 446 linux_statfs->f_files = MIN(bsd_statfs->f_files, INT32_MAX); 447 #else 448 linux_statfs->f_ffree = bsd_statfs->f_ffree; 449 linux_statfs->f_files = bsd_statfs->f_files; 450 #endif 451 linux_statfs->f_fsid.val[0] = bsd_statfs->f_fsid.val[0]; 452 linux_statfs->f_fsid.val[1] = bsd_statfs->f_fsid.val[1]; 453 linux_statfs->f_namelen = MAXNAMLEN; 454 linux_statfs->f_frsize = bsd_statfs->f_bsize; 455 linux_statfs->f_flags = bsd_to_linux_mnt_flags(bsd_statfs->f_flags); 456 memset(linux_statfs->f_spare, 0, sizeof(linux_statfs->f_spare)); 457 458 return (0); 459 } 460 461 int 462 linux_statfs(struct thread *td, struct linux_statfs_args *args) 463 { 464 struct l_statfs linux_statfs; 465 struct statfs *bsd_statfs; 466 char *path; 467 int error; 468 469 if (!LUSECONVPATH(td)) { 470 bsd_statfs = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK); 471 error = kern_statfs(td, args->path, UIO_USERSPACE, bsd_statfs); 472 } else { 473 LCONVPATHEXIST(args->path, &path); 474 bsd_statfs = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK); 475 error = kern_statfs(td, path, UIO_SYSSPACE, bsd_statfs); 476 LFREEPATH(path); 477 } 478 if (error == 0) 479 error = bsd_to_linux_statfs(bsd_statfs, &linux_statfs); 480 free(bsd_statfs, M_STATFS); 481 if (error != 0) 482 return (error); 483 return (copyout(&linux_statfs, args->buf, sizeof(linux_statfs))); 484 } 485 486 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) 487 static void 488 bsd_to_linux_statfs64(struct statfs *bsd_statfs, struct l_statfs64 *linux_statfs) 489 { 490 491 linux_statfs->f_type = bsd_to_linux_ftype(bsd_statfs->f_fstypename); 492 linux_statfs->f_bsize = bsd_statfs->f_bsize; 493 linux_statfs->f_blocks = bsd_statfs->f_blocks; 494 linux_statfs->f_bfree = bsd_statfs->f_bfree; 495 linux_statfs->f_bavail = bsd_statfs->f_bavail; 496 linux_statfs->f_ffree = bsd_statfs->f_ffree; 497 linux_statfs->f_files = bsd_statfs->f_files; 498 linux_statfs->f_fsid.val[0] = bsd_statfs->f_fsid.val[0]; 499 linux_statfs->f_fsid.val[1] = bsd_statfs->f_fsid.val[1]; 500 linux_statfs->f_namelen = MAXNAMLEN; 501 linux_statfs->f_frsize = bsd_statfs->f_bsize; 502 linux_statfs->f_flags = bsd_to_linux_mnt_flags(bsd_statfs->f_flags); 503 memset(linux_statfs->f_spare, 0, sizeof(linux_statfs->f_spare)); 504 } 505 506 int 507 linux_statfs64(struct thread *td, struct linux_statfs64_args *args) 508 { 509 struct l_statfs64 linux_statfs; 510 struct statfs *bsd_statfs; 511 char *path; 512 int error; 513 514 if (args->bufsize != sizeof(struct l_statfs64)) 515 return (EINVAL); 516 517 if (!LUSECONVPATH(td)) { 518 bsd_statfs = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK); 519 error = kern_statfs(td, args->path, UIO_USERSPACE, bsd_statfs); 520 } else { 521 LCONVPATHEXIST(args->path, &path); 522 bsd_statfs = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK); 523 error = kern_statfs(td, path, UIO_SYSSPACE, bsd_statfs); 524 LFREEPATH(path); 525 } 526 if (error == 0) 527 bsd_to_linux_statfs64(bsd_statfs, &linux_statfs); 528 free(bsd_statfs, M_STATFS); 529 if (error != 0) 530 return (error); 531 return (copyout(&linux_statfs, args->buf, sizeof(linux_statfs))); 532 } 533 534 int 535 linux_fstatfs64(struct thread *td, struct linux_fstatfs64_args *args) 536 { 537 struct l_statfs64 linux_statfs; 538 struct statfs *bsd_statfs; 539 int error; 540 541 if (args->bufsize != sizeof(struct l_statfs64)) 542 return (EINVAL); 543 544 bsd_statfs = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK); 545 error = kern_fstatfs(td, args->fd, bsd_statfs); 546 if (error == 0) 547 bsd_to_linux_statfs64(bsd_statfs, &linux_statfs); 548 free(bsd_statfs, M_STATFS); 549 if (error != 0) 550 return (error); 551 return (copyout(&linux_statfs, args->buf, sizeof(linux_statfs))); 552 } 553 #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ 554 555 int 556 linux_fstatfs(struct thread *td, struct linux_fstatfs_args *args) 557 { 558 struct l_statfs linux_statfs; 559 struct statfs *bsd_statfs; 560 int error; 561 562 bsd_statfs = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK); 563 error = kern_fstatfs(td, args->fd, bsd_statfs); 564 if (error == 0) 565 error = bsd_to_linux_statfs(bsd_statfs, &linux_statfs); 566 free(bsd_statfs, M_STATFS); 567 if (error != 0) 568 return (error); 569 return (copyout(&linux_statfs, args->buf, sizeof(linux_statfs))); 570 } 571 572 struct l_ustat 573 { 574 l_daddr_t f_tfree; 575 l_ino_t f_tinode; 576 char f_fname[6]; 577 char f_fpack[6]; 578 }; 579 580 #ifdef LINUX_LEGACY_SYSCALLS 581 int 582 linux_ustat(struct thread *td, struct linux_ustat_args *args) 583 { 584 585 return (EOPNOTSUPP); 586 } 587 #endif 588 589 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) 590 591 static int 592 stat64_copyout(struct stat *buf, void *ubuf) 593 { 594 struct l_stat64 lbuf; 595 596 bzero(&lbuf, sizeof(lbuf)); 597 lbuf.st_dev = dev_to_ldev(buf->st_dev); 598 lbuf.st_ino = buf->st_ino; 599 lbuf.st_mode = buf->st_mode; 600 lbuf.st_nlink = buf->st_nlink; 601 lbuf.st_uid = buf->st_uid; 602 lbuf.st_gid = buf->st_gid; 603 lbuf.st_rdev = buf->st_rdev; 604 lbuf.st_size = buf->st_size; 605 lbuf.st_atim.tv_sec = buf->st_atim.tv_sec; 606 lbuf.st_atim.tv_nsec = buf->st_atim.tv_nsec; 607 lbuf.st_mtim.tv_sec = buf->st_mtim.tv_sec; 608 lbuf.st_mtim.tv_nsec = buf->st_mtim.tv_nsec; 609 lbuf.st_ctim.tv_sec = buf->st_ctim.tv_sec; 610 lbuf.st_ctim.tv_nsec = buf->st_ctim.tv_nsec; 611 lbuf.st_blksize = buf->st_blksize; 612 lbuf.st_blocks = buf->st_blocks; 613 614 /* 615 * The __st_ino field makes all the difference. In the Linux kernel 616 * it is conditionally compiled based on STAT64_HAS_BROKEN_ST_INO, 617 * but without the assignment to __st_ino the runtime linker refuses 618 * to mmap(2) any shared libraries. I guess it's broken alright :-) 619 */ 620 lbuf.__st_ino = buf->st_ino; 621 622 return (copyout(&lbuf, ubuf, sizeof(lbuf))); 623 } 624 625 int 626 linux_stat64(struct thread *td, struct linux_stat64_args *args) 627 { 628 struct stat buf; 629 char *filename; 630 int error; 631 632 if (!LUSECONVPATH(td)) { 633 error = linux_kern_stat(td, args->filename, UIO_USERSPACE, &buf); 634 } else { 635 LCONVPATHEXIST(args->filename, &filename); 636 error = linux_kern_stat(td, filename, UIO_SYSSPACE, &buf); 637 LFREEPATH(filename); 638 } 639 if (error) 640 return (error); 641 return (stat64_copyout(&buf, args->statbuf)); 642 } 643 644 int 645 linux_lstat64(struct thread *td, struct linux_lstat64_args *args) 646 { 647 struct stat sb; 648 char *filename; 649 int error; 650 651 if (!LUSECONVPATH(td)) { 652 error = linux_kern_lstat(td, args->filename, UIO_USERSPACE, &sb); 653 } else { 654 LCONVPATHEXIST(args->filename, &filename); 655 error = linux_kern_lstat(td, filename, UIO_SYSSPACE, &sb); 656 LFREEPATH(filename); 657 } 658 if (error) 659 return (error); 660 return (stat64_copyout(&sb, args->statbuf)); 661 } 662 663 int 664 linux_fstat64(struct thread *td, struct linux_fstat64_args *args) 665 { 666 struct stat buf; 667 int error; 668 669 error = kern_fstat(td, args->fd, &buf); 670 translate_fd_major_minor(td, args->fd, &buf); 671 if (!error) 672 error = stat64_copyout(&buf, args->statbuf); 673 674 return (error); 675 } 676 677 int 678 linux_fstatat64(struct thread *td, struct linux_fstatat64_args *args) 679 { 680 char *path; 681 int error, dfd, flag, unsupported; 682 struct stat buf; 683 684 unsupported = args->flag & ~(LINUX_AT_SYMLINK_NOFOLLOW | LINUX_AT_EMPTY_PATH); 685 if (unsupported != 0) { 686 linux_msg(td, "fstatat64 unsupported flag 0x%x", unsupported); 687 return (EINVAL); 688 } 689 flag = (args->flag & LINUX_AT_SYMLINK_NOFOLLOW) ? 690 AT_SYMLINK_NOFOLLOW : 0; 691 flag |= (args->flag & LINUX_AT_EMPTY_PATH) ? 692 AT_EMPTY_PATH : 0; 693 694 dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; 695 if (!LUSECONVPATH(td)) { 696 error = linux_kern_statat(td, flag, dfd, args->pathname, 697 UIO_USERSPACE, &buf); 698 } else { 699 LCONVPATHEXIST_AT(args->pathname, &path, dfd); 700 error = linux_kern_statat(td, flag, dfd, path, UIO_SYSSPACE, &buf); 701 LFREEPATH(path); 702 } 703 if (error == 0) 704 error = stat64_copyout(&buf, args->statbuf); 705 706 return (error); 707 } 708 709 #else /* __amd64__ && !COMPAT_LINUX32 */ 710 711 int 712 linux_newfstatat(struct thread *td, struct linux_newfstatat_args *args) 713 { 714 char *path; 715 int error, dfd, flag, unsupported; 716 struct stat buf; 717 718 unsupported = args->flag & ~(LINUX_AT_SYMLINK_NOFOLLOW | LINUX_AT_EMPTY_PATH); 719 if (unsupported != 0) { 720 linux_msg(td, "fstatat unsupported flag 0x%x", unsupported); 721 return (EINVAL); 722 } 723 724 flag = (args->flag & LINUX_AT_SYMLINK_NOFOLLOW) ? 725 AT_SYMLINK_NOFOLLOW : 0; 726 flag |= (args->flag & LINUX_AT_EMPTY_PATH) ? 727 AT_EMPTY_PATH : 0; 728 729 dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; 730 if (!LUSECONVPATH(td)) { 731 error = linux_kern_statat(td, flag, dfd, args->pathname, 732 UIO_USERSPACE, &buf); 733 } else { 734 LCONVPATHEXIST_AT(args->pathname, &path, dfd); 735 error = linux_kern_statat(td, flag, dfd, path, UIO_SYSSPACE, &buf); 736 LFREEPATH(path); 737 } 738 if (error == 0) 739 error = newstat_copyout(&buf, args->statbuf); 740 741 return (error); 742 } 743 744 #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ 745 746 int 747 linux_syncfs(struct thread *td, struct linux_syncfs_args *args) 748 { 749 struct mount *mp; 750 struct vnode *vp; 751 int error, save; 752 753 error = fgetvp(td, args->fd, &cap_fsync_rights, &vp); 754 if (error != 0) 755 /* 756 * Linux syncfs() returns only EBADF, however fgetvp() 757 * can return EINVAL in case of file descriptor does 758 * not represent a vnode. XXX. 759 */ 760 return (error); 761 762 mp = vp->v_mount; 763 mtx_lock(&mountlist_mtx); 764 error = vfs_busy(mp, MBF_MNTLSTLOCK); 765 if (error != 0) { 766 /* See comment above. */ 767 mtx_unlock(&mountlist_mtx); 768 goto out; 769 } 770 if ((mp->mnt_flag & MNT_RDONLY) == 0 && 771 vn_start_write(NULL, &mp, V_NOWAIT) == 0) { 772 save = curthread_pflags_set(TDP_SYNCIO); 773 vfs_periodic(mp, MNT_NOWAIT); 774 VFS_SYNC(mp, MNT_NOWAIT); 775 curthread_pflags_restore(save); 776 vn_finished_write(mp); 777 } 778 vfs_unbusy(mp); 779 780 out: 781 vrele(vp); 782 return (error); 783 } 784 785 int 786 linux_statx(struct thread *td, struct linux_statx_args *args) 787 { 788 char *path; 789 int error, dirfd, flags, unsupported; 790 struct stat buf; 791 792 unsupported = args->flags & ~(LINUX_AT_SYMLINK_NOFOLLOW | 793 LINUX_AT_EMPTY_PATH | LINUX_AT_NO_AUTOMOUNT); 794 if (unsupported != 0) { 795 linux_msg(td, "statx unsupported flags 0x%x", unsupported); 796 return (EINVAL); 797 } 798 799 flags = (args->flags & LINUX_AT_SYMLINK_NOFOLLOW) ? 800 AT_SYMLINK_NOFOLLOW : 0; 801 flags |= (args->flags & LINUX_AT_EMPTY_PATH) ? 802 AT_EMPTY_PATH : 0; 803 804 dirfd = (args->dirfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dirfd; 805 if (!LUSECONVPATH(td)) { 806 error = linux_kern_statat(td, flags, dirfd, args->pathname, 807 UIO_USERSPACE, &buf); 808 } else { 809 LCONVPATHEXIST_AT(args->pathname, &path, dirfd); 810 error = linux_kern_statat(td, flags, dirfd, path, UIO_SYSSPACE, &buf); 811 LFREEPATH(path); 812 } 813 if (error == 0) 814 error = statx_copyout(&buf, args->statxbuf); 815 816 return (error); 817 } 818