1 2 #include "inc.h" 3 4 #include <fcntl.h> 5 #include <unistd.h> 6 #include <dirent.h> 7 #include <sys/mount.h> 8 #include <sys/resource.h> 9 10 /* 11 * This function should always be used when printing a file descriptor. It 12 * currently offers no benefit, but will in the future allow for features such 13 * as color highlighting and tracking of specific open files (TODO). 14 */ 15 void 16 put_fd(struct trace_proc * proc, const char * name, int fd) 17 { 18 19 put_value(proc, name, "%d", fd); 20 } 21 22 static int 23 vfs_read_out(struct trace_proc * proc, const message *m_out) 24 { 25 26 put_fd(proc, "fd", m_out->m_lc_vfs_readwrite.fd); 27 28 return CT_NOTDONE; 29 } 30 31 static void 32 vfs_read_in(struct trace_proc * proc, const message *m_out, 33 const message *m_in, int failed) 34 { 35 36 put_buf(proc, "buf", failed, m_out->m_lc_vfs_readwrite.buf, 37 m_in->m_type); 38 put_value(proc, "len", "%zu", m_out->m_lc_vfs_readwrite.len); 39 put_equals(proc); 40 put_result(proc); 41 } 42 43 static int 44 vfs_write_out(struct trace_proc * proc, const message *m_out) 45 { 46 47 put_fd(proc, "fd", m_out->m_lc_vfs_readwrite.fd); 48 put_buf(proc, "buf", 0, m_out->m_lc_vfs_readwrite.buf, 49 m_out->m_lc_vfs_readwrite.len); 50 put_value(proc, "len", "%zu", m_out->m_lc_vfs_readwrite.len); 51 52 return CT_DONE; 53 } 54 55 static void 56 put_lseek_whence(struct trace_proc * proc, const char * name, int whence) 57 { 58 const char *text = NULL; 59 60 if (!valuesonly) { 61 switch (whence) { 62 TEXT(SEEK_SET); 63 TEXT(SEEK_CUR); 64 TEXT(SEEK_END); 65 } 66 } 67 68 if (text != NULL) 69 put_field(proc, name, text); 70 else 71 put_value(proc, name, "%d", whence); 72 } 73 74 static int 75 vfs_lseek_out(struct trace_proc * proc, const message * m_out) 76 { 77 78 put_fd(proc, "fd", m_out->m_lc_vfs_lseek.fd); 79 put_value(proc, "offset", "%"PRId64, m_out->m_lc_vfs_lseek.offset); 80 put_lseek_whence(proc, "whence", m_out->m_lc_vfs_lseek.whence); 81 82 return CT_DONE; 83 } 84 85 static void 86 vfs_lseek_in(struct trace_proc * proc, const message * __unused m_out, 87 const message * m_in, int failed) 88 { 89 90 if (!failed) 91 put_value(proc, NULL, "%"PRId64, m_in->m_vfs_lc_lseek.offset); 92 else 93 put_result(proc); 94 } 95 96 static const struct flags open_flags[] = { 97 FLAG_MASK(O_ACCMODE, O_RDONLY), 98 FLAG_MASK(O_ACCMODE, O_WRONLY), 99 FLAG_MASK(O_ACCMODE, O_RDWR), 100 #define ACCMODE_ENTRIES 3 /* the first N entries are for O_ACCMODE */ 101 FLAG(O_NONBLOCK), 102 FLAG(O_APPEND), 103 FLAG(O_SHLOCK), 104 FLAG(O_EXLOCK), 105 FLAG(O_ASYNC), 106 FLAG(O_SYNC), 107 FLAG(O_NOFOLLOW), 108 FLAG(O_CREAT), 109 FLAG(O_TRUNC), 110 FLAG(O_EXCL), 111 FLAG(O_NOCTTY), 112 FLAG(O_DSYNC), 113 FLAG(O_RSYNC), 114 FLAG(O_ALT_IO), 115 FLAG(O_DIRECT), 116 FLAG(O_DIRECTORY), 117 FLAG(O_CLOEXEC), 118 FLAG(O_SEARCH), 119 FLAG(O_NOSIGPIPE), 120 }; 121 122 static void 123 put_open_flags(struct trace_proc * proc, const char * name, int value, 124 int full) 125 { 126 const struct flags *fp; 127 unsigned int num; 128 129 fp = open_flags; 130 num = COUNT(open_flags); 131 132 /* 133 * If we're not printing a full open()-style set of flags, but instead 134 * just a loose set of flags, then skip the access mode altogether, 135 * otherwise we'd be printing O_RDONLY when no access mode is given. 136 */ 137 if (!full) { 138 fp += ACCMODE_ENTRIES; 139 num -= ACCMODE_ENTRIES; 140 } 141 142 put_flags(proc, name, fp, num, "0x%x", value); 143 } 144 145 static const struct flags mode_flags[] = { 146 FLAG_MASK(S_IFMT, S_IFIFO), 147 FLAG_MASK(S_IFMT, S_IFCHR), 148 FLAG_MASK(S_IFMT, S_IFDIR), 149 FLAG_MASK(S_IFMT, S_IFBLK), 150 FLAG_MASK(S_IFMT, S_IFREG), 151 FLAG_MASK(S_IFMT, S_IFLNK), 152 FLAG_MASK(S_IFMT, S_IFSOCK), 153 FLAG_MASK(S_IFMT, S_IFWHT), 154 FLAG(S_ARCH1), 155 FLAG(S_ARCH2), 156 FLAG(S_ISUID), 157 FLAG(S_ISGID), 158 FLAG(S_ISTXT), 159 }; 160 161 /* Do not use %04o instead of 0%03o; it is octal even if greater than 0777. */ 162 #define put_mode(p, n, v) \ 163 put_flags(p, n, mode_flags, COUNT(mode_flags), "0%03o", v) 164 165 static void 166 put_path(struct trace_proc * proc, const message * m_out) 167 { 168 size_t len; 169 170 if ((len = m_out->m_lc_vfs_path.len) <= M_PATH_STRING_MAX) 171 put_buf(proc, "path", PF_LOCADDR | PF_PATH, 172 (vir_bytes)m_out->m_lc_vfs_path.buf, len); 173 else 174 put_buf(proc, "path", PF_PATH, m_out->m_lc_vfs_path.name, len); 175 } 176 177 static int 178 vfs_open_out(struct trace_proc * proc, const message * m_out) 179 { 180 181 put_path(proc, m_out); 182 put_open_flags(proc, "flags", m_out->m_lc_vfs_path.flags, 183 TRUE /*full*/); 184 185 return CT_DONE; 186 } 187 188 /* This function is shared between creat and open. */ 189 static void 190 vfs_open_in(struct trace_proc * proc, const message * __unused m_out, 191 const message * m_in, int failed) 192 { 193 194 if (!failed) 195 put_fd(proc, NULL, m_in->m_type); 196 else 197 put_result(proc); 198 } 199 200 static int 201 vfs_creat_out(struct trace_proc * proc, const message * m_out) 202 { 203 204 put_buf(proc, "path", PF_PATH, m_out->m_lc_vfs_creat.name, 205 m_out->m_lc_vfs_creat.len); 206 put_open_flags(proc, "flags", m_out->m_lc_vfs_creat.flags, 207 TRUE /*full*/); 208 put_mode(proc, "mode", m_out->m_lc_vfs_creat.mode); 209 210 return CT_DONE; 211 } 212 213 static int 214 vfs_close_out(struct trace_proc * proc, const message * m_out) 215 { 216 217 put_fd(proc, "fd", m_out->m_lc_vfs_close.fd); 218 219 return CT_DONE; 220 } 221 222 /* This function is used for link, rename, and symlink. */ 223 static int 224 vfs_link_out(struct trace_proc * proc, const message * m_out) 225 { 226 227 put_buf(proc, "path1", PF_PATH, m_out->m_lc_vfs_link.name1, 228 m_out->m_lc_vfs_link.len1); 229 put_buf(proc, "path2", PF_PATH, m_out->m_lc_vfs_link.name2, 230 m_out->m_lc_vfs_link.len2); 231 232 return CT_DONE; 233 } 234 235 static int 236 vfs_path_out(struct trace_proc * proc, const message * m_out) 237 { 238 239 put_path(proc, m_out); 240 241 return CT_DONE; 242 } 243 244 static int 245 vfs_path_mode_out(struct trace_proc * proc, const message * m_out) 246 { 247 248 put_path(proc, m_out); 249 put_mode(proc, "mode", m_out->m_lc_vfs_path.mode); 250 251 return CT_DONE; 252 } 253 254 void 255 put_dev(struct trace_proc * proc, const char * name, dev_t dev) 256 { 257 devmajor_t major; 258 devminor_t minor; 259 260 major = major(dev); 261 minor = minor(dev); 262 263 /* The value 0 ("no device") should print as "0". */ 264 if (dev != 0 && makedev(major, minor) == dev && !valuesonly) 265 put_value(proc, name, "<%d,%d>", major, minor); 266 else 267 put_value(proc, name, "%"PRIu64, dev); 268 } 269 270 static int 271 vfs_mknod_out(struct trace_proc * proc, const message * m_out) 272 { 273 274 put_buf(proc, "path", PF_PATH, m_out->m_lc_vfs_mknod.name, 275 m_out->m_lc_vfs_mknod.len); 276 put_mode(proc, "mode", m_out->m_lc_vfs_mknod.mode); 277 put_dev(proc, "dev", m_out->m_lc_vfs_mknod.device); 278 279 return CT_DONE; 280 } 281 282 static int 283 vfs_chown_out(struct trace_proc * proc, const message * m_out) 284 { 285 286 put_buf(proc, "path", PF_PATH, m_out->m_lc_vfs_chown.name, 287 m_out->m_lc_vfs_chown.len); 288 /* -1 means "keep the current value" so print as signed */ 289 put_value(proc, "owner", "%d", m_out->m_lc_vfs_chown.owner); 290 put_value(proc, "group", "%d", m_out->m_lc_vfs_chown.group); 291 292 return CT_DONE; 293 } 294 295 /* TODO: expand this to the full ST_ set. */ 296 static const struct flags mount_flags[] = { 297 FLAG(MNT_RDONLY), 298 }; 299 300 static int 301 vfs_mount_out(struct trace_proc * proc, const message * m_out) 302 { 303 304 put_buf(proc, "special", PF_PATH, m_out->m_lc_vfs_mount.dev, 305 m_out->m_lc_vfs_mount.devlen); 306 put_buf(proc, "path", PF_PATH, m_out->m_lc_vfs_mount.path, 307 m_out->m_lc_vfs_mount.pathlen); 308 put_flags(proc, "flags", mount_flags, COUNT(mount_flags), "0x%x", 309 m_out->m_lc_vfs_mount.flags); 310 put_buf(proc, "type", PF_STRING, m_out->m_lc_vfs_mount.type, 311 m_out->m_lc_vfs_mount.typelen); 312 put_buf(proc, "label", PF_STRING, m_out->m_lc_vfs_mount.label, 313 m_out->m_lc_vfs_mount.labellen); 314 315 return CT_DONE; 316 } 317 318 static int 319 vfs_umount_out(struct trace_proc * proc, const message * m_out) 320 { 321 322 put_buf(proc, "path", PF_PATH, m_out->m_lc_vfs_umount.name, 323 m_out->m_lc_vfs_umount.namelen); 324 325 return CT_DONE; 326 } 327 328 static void 329 vfs_umount_in(struct trace_proc * proc, const message * m_out, 330 const message * __unused m_in, int failed) 331 { 332 333 put_result(proc); 334 335 if (!failed) { 336 put_open(proc, NULL, 0, "(", ", "); 337 put_buf(proc, "label", PF_STRING, m_out->m_lc_vfs_umount.label, 338 m_out->m_lc_vfs_umount.labellen); 339 340 put_close(proc, ")"); 341 } 342 } 343 344 345 static const struct flags access_flags[] = { 346 FLAG_ZERO(F_OK), 347 FLAG(R_OK), 348 FLAG(W_OK), 349 FLAG(X_OK), 350 }; 351 352 static int 353 vfs_access_out(struct trace_proc * proc, const message * m_out) 354 { 355 356 put_path(proc, m_out); 357 put_flags(proc, "mode", access_flags, COUNT(access_flags), "0x%x", 358 m_out->m_lc_vfs_path.mode); 359 360 return CT_DONE; 361 } 362 363 static int 364 vfs_readlink_out(struct trace_proc * proc, const message * m_out) 365 { 366 367 put_buf(proc, "path", PF_PATH, m_out->m_lc_vfs_readlink.name, 368 m_out->m_lc_vfs_readlink.namelen); 369 370 return CT_NOTDONE; 371 } 372 373 static void 374 vfs_readlink_in(struct trace_proc * proc, const message * m_out, 375 const message * m_in, int failed) 376 { 377 378 /* The call does not return a string, so do not use PF_STRING here. */ 379 put_buf(proc, "buf", failed, m_out->m_lc_vfs_readlink.buf, 380 m_in->m_type); 381 put_value(proc, "bufsize", "%zd", m_out->m_lc_vfs_readlink.bufsize); 382 put_equals(proc); 383 put_result(proc); 384 } 385 386 static void 387 put_struct_stat(struct trace_proc * proc, const char * name, int flags, 388 vir_bytes addr) 389 { 390 struct stat buf; 391 int is_special; 392 393 if (!put_open_struct(proc, name, flags, addr, &buf, sizeof(buf))) 394 return; 395 396 /* 397 * The combination of struct stat's frequent usage and large number of 398 * fields makes this structure a pain to print. For now, the idea is 399 * that for verbosity level 0, we print the mode, and the target device 400 * for block/char special files or the file size for all other files. 401 * For higher verbosity levels, largely maintain the structure's own 402 * order of fields. Violate this general structure printing rule for 403 * some fields though, because the actual field order in struct stat is 404 * downright ridiculous. Like elsewhere, for verbosity level 1 print 405 * all fields with meaningful values, and for verbosity level 2 just 406 * print everything, including fields that are known to be not yet 407 * supported and fields that contain known values. 408 */ 409 is_special = (S_ISBLK(buf.st_mode) || S_ISCHR(buf.st_mode)); 410 411 if (verbose > 0) { 412 put_dev(proc, "st_dev", buf.st_dev); 413 put_value(proc, "st_ino", "%"PRId64, buf.st_ino); 414 } 415 put_mode(proc, "st_mode", buf.st_mode); 416 if (verbose > 0) { 417 put_value(proc, "st_nlink", "%u", buf.st_nlink); 418 put_value(proc, "st_uid", "%u", buf.st_uid); 419 put_value(proc, "st_gid", "%u", buf.st_gid); 420 } 421 if (is_special || verbose > 1) 422 put_dev(proc, "st_rdev", buf.st_rdev); 423 if (verbose > 0) { 424 /* 425 * TODO: print the nanosecond part, but possibly only if we are 426 * not actually interpreting the time as a date (another TODO), 427 * and/or possibly only with verbose > 1 (largely unsupported). 428 */ 429 put_time(proc, "st_atime", buf.st_atime); 430 put_time(proc, "st_mtime", buf.st_mtime); 431 put_time(proc, "st_ctime", buf.st_ctime); 432 } 433 if (verbose > 1) /* not yet supported on MINIX3 */ 434 put_time(proc, "st_birthtime", buf.st_birthtime); 435 if (!is_special || verbose > 1) 436 put_value(proc, "st_size", "%"PRId64, buf.st_size); 437 if (verbose > 0) { 438 put_value(proc, "st_blocks", "%"PRId64, buf.st_blocks); 439 put_value(proc, "st_blksize", "%"PRId32, buf.st_blksize); 440 } 441 if (verbose > 1) { 442 put_value(proc, "st_flags", "%"PRIu32, buf.st_flags); 443 put_value(proc, "st_gen", "%"PRIu32, buf.st_gen); 444 } 445 446 put_close_struct(proc, verbose > 1); 447 } 448 449 static int 450 vfs_stat_out(struct trace_proc * proc, const message * m_out) 451 { 452 453 put_buf(proc, "path", PF_PATH, m_out->m_lc_vfs_stat.name, 454 m_out->m_lc_vfs_stat.len); 455 456 return CT_NOTDONE; 457 } 458 459 static void 460 vfs_stat_in(struct trace_proc * proc, const message * m_out, 461 const message * __unused m_in, int failed) 462 { 463 464 put_struct_stat(proc, "buf", failed, m_out->m_lc_vfs_stat.buf); 465 put_equals(proc); 466 put_result(proc); 467 } 468 469 static int 470 vfs_fstat_out(struct trace_proc * proc, const message * m_out) 471 { 472 473 put_fd(proc, "fd", m_out->m_lc_vfs_fstat.fd); 474 475 return CT_NOTDONE; 476 } 477 478 static void 479 vfs_fstat_in(struct trace_proc * proc, const message * m_out, 480 const message * __unused m_in, int failed) 481 { 482 483 put_struct_stat(proc, "buf", failed, m_out->m_lc_vfs_fstat.buf); 484 put_equals(proc); 485 put_result(proc); 486 } 487 488 static int 489 vfs_ioctl_out(struct trace_proc * proc, const message * m_out) 490 { 491 492 put_fd(proc, "fd", m_out->m_lc_vfs_ioctl.fd); 493 put_ioctl_req(proc, "req", m_out->m_lc_vfs_ioctl.req, 494 FALSE /*is_svrctl*/); 495 return put_ioctl_arg_out(proc, "arg", m_out->m_lc_vfs_ioctl.req, 496 (vir_bytes)m_out->m_lc_vfs_ioctl.arg, FALSE /*is_svrctl*/); 497 } 498 499 static void 500 vfs_ioctl_in(struct trace_proc * proc, const message * m_out, 501 const message * __unused m_in, int failed) 502 { 503 504 put_ioctl_arg_in(proc, "arg", failed, m_out->m_lc_vfs_ioctl.req, 505 (vir_bytes)m_out->m_lc_vfs_ioctl.arg, FALSE /*is_svrctl*/); 506 } 507 508 static void 509 put_fcntl_cmd(struct trace_proc * proc, const char * name, int cmd) 510 { 511 const char *text = NULL; 512 513 if (!valuesonly) { 514 switch (cmd) { 515 TEXT(F_DUPFD); 516 TEXT(F_GETFD); 517 TEXT(F_SETFD); 518 TEXT(F_GETFL); 519 TEXT(F_SETFL); 520 TEXT(F_GETOWN); 521 TEXT(F_SETOWN); 522 TEXT(F_GETLK); 523 TEXT(F_SETLK); 524 TEXT(F_SETLKW); 525 TEXT(F_CLOSEM); 526 TEXT(F_MAXFD); 527 TEXT(F_DUPFD_CLOEXEC); 528 TEXT(F_GETNOSIGPIPE); 529 TEXT(F_SETNOSIGPIPE); 530 TEXT(F_FREESP); 531 TEXT(F_FLUSH_FS_CACHE); 532 } 533 } 534 535 if (text != NULL) 536 put_field(proc, name, text); 537 else 538 put_value(proc, name, "%d", cmd); 539 } 540 541 static const struct flags fd_flags[] = { 542 FLAG(FD_CLOEXEC), 543 }; 544 545 #define put_fd_flags(p, n, v) \ 546 put_flags(p, n, fd_flags, COUNT(fd_flags), "0x%x", v) 547 548 static void 549 put_flock_type(struct trace_proc * proc, const char * name, int type) 550 { 551 const char *text = NULL; 552 553 if (!valuesonly) { 554 switch (type) { 555 TEXT(F_RDLCK); 556 TEXT(F_UNLCK); 557 TEXT(F_WRLCK); 558 } 559 } 560 561 if (text != NULL) 562 put_field(proc, name, text); 563 else 564 put_value(proc, name, "%d", type); 565 } 566 567 /* 568 * With PF_FULL, also print l_pid, unless l_type is F_UNLCK in which case 569 * only that type is printed. With PF_ALT, print only l_whence/l_start/l_len. 570 */ 571 static void 572 put_struct_flock(struct trace_proc * proc, const char * name, int flags, 573 vir_bytes addr) 574 { 575 struct flock flock; 576 int limited; 577 578 if (!put_open_struct(proc, name, flags, addr, &flock, sizeof(flock))) 579 return; 580 581 limited = ((flags & PF_FULL) && flock.l_type == F_UNLCK); 582 583 if (!(flags & PF_ALT)) 584 put_flock_type(proc, "l_type", flock.l_type); 585 if (!limited) { 586 put_lseek_whence(proc, "l_whence", flock.l_whence); 587 put_value(proc, "l_start", "%"PRId64, flock.l_start); 588 put_value(proc, "l_len", "%"PRId64, flock.l_len); 589 if (flags & PF_FULL) 590 put_value(proc, "l_pid", "%d", flock.l_pid); 591 } 592 593 put_close_struct(proc, TRUE /*all*/); 594 } 595 596 static int 597 vfs_fcntl_out(struct trace_proc * proc, const message * m_out) 598 { 599 int full; 600 601 put_fd(proc, "fd", m_out->m_lc_vfs_fcntl.fd); 602 put_fcntl_cmd(proc, "cmd", m_out->m_lc_vfs_fcntl.cmd); 603 604 switch (m_out->m_lc_vfs_fcntl.cmd) { 605 case F_DUPFD: 606 case F_DUPFD_CLOEXEC: 607 put_fd(proc, "fd2", m_out->m_lc_vfs_fcntl.arg_int); 608 break; 609 case F_SETFD: 610 put_fd_flags(proc, "flags", m_out->m_lc_vfs_fcntl.arg_int); 611 break; 612 case F_SETFL: 613 /* 614 * One of those difficult cases: the access mode is ignored, so 615 * we don't want to print O_RDONLY if it is not given. On the 616 * other hand, fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_..) is 617 * a fairly common construction, in which case we don't want to 618 * print eg O_..|0x2 if the access mode is O_RDWR. Thus, we 619 * compromise: show the access mode if any of its bits are set. 620 */ 621 put_open_flags(proc, "flags", m_out->m_lc_vfs_fcntl.arg_int, 622 m_out->m_lc_vfs_fcntl.arg_int & O_ACCMODE /*full*/); 623 break; 624 case F_SETLK: 625 case F_SETLKW: 626 put_struct_flock(proc, "lkp", 0, 627 m_out->m_lc_vfs_fcntl.arg_ptr); 628 break; 629 case F_FREESP: 630 put_struct_flock(proc, "lkp", PF_ALT, 631 m_out->m_lc_vfs_fcntl.arg_ptr); 632 break; 633 case F_SETNOSIGPIPE: 634 put_value(proc, "arg", "%d", m_out->m_lc_vfs_fcntl.arg_int); 635 break; 636 } 637 638 return (m_out->m_lc_vfs_fcntl.cmd != F_GETLK) ? CT_DONE : CT_NOTDONE; 639 } 640 641 static void 642 vfs_fcntl_in(struct trace_proc * proc, const message * m_out, 643 const message * m_in, int failed) 644 { 645 646 switch (m_out->m_lc_vfs_fcntl.cmd) { 647 case F_GETFD: 648 if (failed) 649 break; 650 put_fd_flags(proc, NULL, m_in->m_type); 651 return; 652 case F_GETFL: 653 if (failed) 654 break; 655 put_open_flags(proc, NULL, m_in->m_type, TRUE /*full*/); 656 return; 657 case F_GETLK: 658 put_struct_flock(proc, "lkp", failed | PF_FULL, 659 m_out->m_lc_vfs_fcntl.arg_ptr); 660 put_equals(proc); 661 break; 662 } 663 664 put_result(proc); 665 } 666 667 static int 668 vfs_pipe2_out(struct trace_proc * __unused proc, 669 const message * __unused m_out) 670 { 671 672 return CT_NOTDONE; 673 } 674 675 static void 676 vfs_pipe2_in(struct trace_proc * proc, const message * m_out, 677 const message * m_in, int failed) 678 { 679 680 if (!failed) { 681 put_open(proc, "fd", PF_NONAME, "[", ", "); 682 put_fd(proc, "rfd", m_in->m_lc_vfs_pipe2.fd0); 683 put_fd(proc, "wfd", m_in->m_lc_vfs_pipe2.fd1); 684 put_close(proc, "]"); 685 } else 686 put_field(proc, "fd", "&.."); 687 put_open_flags(proc, "flags", m_out->m_lc_vfs_pipe2.flags, 688 FALSE /*full*/); 689 put_equals(proc); 690 put_result(proc); 691 } 692 693 static int 694 vfs_umask_out(struct trace_proc * proc, const message * m_out) 695 { 696 697 put_mode(proc, NULL, m_out->m_lc_vfs_umask.mask); 698 699 return CT_DONE; 700 } 701 702 static void 703 vfs_umask_in(struct trace_proc * proc, const message * __unused m_out, 704 const message * m_in, int failed) 705 { 706 707 if (!failed) 708 put_mode(proc, NULL, m_in->m_type); 709 else 710 put_result(proc); 711 712 } 713 714 static void 715 put_dirent_type(struct trace_proc * proc, const char * name, unsigned int type) 716 { 717 const char *text = NULL; 718 719 if (!valuesonly) { 720 switch (type) { 721 TEXT(DT_UNKNOWN); 722 TEXT(DT_FIFO); 723 TEXT(DT_CHR); 724 TEXT(DT_DIR); 725 TEXT(DT_BLK); 726 TEXT(DT_REG); 727 TEXT(DT_LNK); 728 TEXT(DT_SOCK); 729 TEXT(DT_WHT); 730 } 731 } 732 733 if (text != NULL) 734 put_field(proc, name, text); 735 else 736 put_value(proc, name, "%u", type); 737 } 738 739 static void 740 put_struct_dirent(struct trace_proc * proc, const char *name, int flags, 741 vir_bytes addr) 742 { 743 struct dirent dirent; 744 745 if (!put_open_struct(proc, name, flags, addr, &dirent, sizeof(dirent))) 746 return; 747 748 if (verbose > 0) 749 put_value(proc, "d_fileno", "%"PRIu64, dirent.d_fileno); 750 if (verbose > 1) { 751 put_value(proc, "d_reclen", "%u", dirent.d_reclen); 752 put_value(proc, "d_namlen", "%u", dirent.d_namlen); 753 } 754 if (verbose >= 1 + (dirent.d_type == DT_UNKNOWN)) 755 put_dirent_type(proc, "d_type", dirent.d_type); 756 put_buf(proc, "d_name", PF_LOCADDR, (vir_bytes)dirent.d_name, 757 MIN(dirent.d_namlen, sizeof(dirent.d_name))); 758 759 put_close_struct(proc, verbose > 1); 760 } 761 762 static void 763 put_dirent_array(struct trace_proc * proc, const char * name, int flags, 764 vir_bytes addr, ssize_t size) 765 { 766 struct dirent dirent; 767 unsigned count, max; 768 ssize_t off, chunk; 769 770 if ((flags & PF_FAILED) || valuesonly > 1 || size < 0) { 771 put_ptr(proc, name, addr); 772 773 return; 774 } 775 776 if (size == 0) { 777 put_field(proc, name, "[]"); 778 779 return; 780 } 781 782 if (verbose == 0) 783 max = 0; /* TODO: should we set this to 1 instead? */ 784 else if (verbose == 1) 785 max = 3; /* low; just to give an indication where we are */ 786 else 787 max = INT_MAX; 788 789 /* 790 * TODO: as is, this is highly inefficient, as we are typically copying 791 * in the same pieces of memory in repeatedly.. 792 */ 793 count = 0; 794 for (off = 0; off < size; off += chunk) { 795 chunk = size - off; 796 if (chunk > sizeof(dirent)) 797 chunk = sizeof(dirent); 798 if (chunk < _DIRENT_MINSIZE(&dirent)) 799 break; 800 801 if (mem_get_data(proc->pid, addr + off, &dirent, chunk) < 0) { 802 if (off == 0) { 803 put_ptr(proc, name, addr); 804 805 return; 806 } 807 808 break; 809 } 810 811 if (off == 0) 812 put_open(proc, name, PF_NONAME, "[", ", "); 813 814 if (count < max) 815 put_struct_dirent(proc, NULL, PF_LOCADDR, 816 (vir_bytes)&dirent); 817 818 if (chunk > dirent.d_reclen) 819 chunk = dirent.d_reclen; 820 count++; 821 } 822 823 if (off < size) 824 put_tail(proc, 0, 0); 825 else if (count > max) 826 put_tail(proc, count, max); 827 put_close(proc, "]"); 828 } 829 830 static int 831 vfs_getdents_out(struct trace_proc * proc, const message * m_out) 832 { 833 834 put_fd(proc, "fd", m_out->m_lc_vfs_readwrite.fd); 835 836 return CT_NOTDONE; 837 } 838 839 static void 840 vfs_getdents_in(struct trace_proc * proc, const message * m_out, 841 const message * m_in, int failed) 842 { 843 844 put_dirent_array(proc, "buf", failed, m_out->m_lc_vfs_readwrite.buf, 845 m_in->m_type); 846 put_value(proc, "len", "%zu", m_out->m_lc_vfs_readwrite.len); 847 put_equals(proc); 848 put_result(proc); 849 } 850 851 static void 852 put_fd_set(struct trace_proc * proc, const char * name, vir_bytes addr, 853 int nfds) 854 { 855 fd_set set; 856 size_t off; 857 unsigned int i, j, words, count, max; 858 859 if (addr == 0 || nfds < 0) { 860 put_ptr(proc, name, addr); 861 862 return; 863 } 864 865 /* 866 * Each process may define its own FD_SETSIZE, so our fd_set may be of 867 * a different size than theirs. Thus, we copy at a granularity known 868 * to be valid in any case: a single word of bits. We make the 869 * assumption that fd_set consists purely of bits, so that we can use 870 * the second (and so on) bit word as an fd_set by itself. 871 */ 872 words = (nfds + NFDBITS - 1) / NFDBITS; 873 874 count = 0; 875 876 if (verbose == 0) 877 max = 16; 878 else if (verbose == 1) 879 max = FD_SETSIZE; 880 else 881 max = INT_MAX; 882 883 /* TODO: copy in more at once, but stick to fd_mask boundaries. */ 884 for (off = 0, i = 0; i < words; i++, off += sizeof(fd_mask)) { 885 if (mem_get_data(proc->pid, addr + off, &set, 886 sizeof(fd_mask)) != 0) { 887 if (count == 0) { 888 put_ptr(proc, name, addr); 889 890 return; 891 } 892 893 break; 894 } 895 896 for (j = 0; j < NFDBITS; j++) { 897 if (FD_ISSET(j, &set)) { 898 if (count == 0) 899 put_open(proc, name, PF_NONAME, "[", 900 " "); 901 902 if (count < max) 903 put_fd(proc, NULL, i * NFDBITS + j); 904 905 count++; 906 } 907 } 908 } 909 910 /* 911 * The empty set should print as "[]". If copying any part failed, it 912 * should print as "[x, ..(?)]" where x is the set printed so far, if 913 * any. If copying never failed, and we did not print all fds in the 914 * set, print the remaining count n as "[x, ..(+n)]" at the end. 915 */ 916 if (count == 0) 917 put_open(proc, name, PF_NONAME, "[", " "); 918 919 if (i < words) 920 put_tail(proc, 0, 0); 921 else if (count > max) 922 put_tail(proc, count, max); 923 924 put_close(proc, "]"); 925 } 926 927 static int 928 vfs_select_out(struct trace_proc * proc, const message * m_out) 929 { 930 int nfds; 931 932 nfds = m_out->m_lc_vfs_select.nfds; 933 934 put_fd(proc, "nfds", nfds); /* not really a file descriptor.. */ 935 put_fd_set(proc, "readfds", 936 (vir_bytes)m_out->m_lc_vfs_select.readfds, nfds); 937 put_fd_set(proc, "writefds", 938 (vir_bytes)m_out->m_lc_vfs_select.writefds, nfds); 939 put_fd_set(proc, "errorfds", 940 (vir_bytes)m_out->m_lc_vfs_select.errorfds, nfds); 941 put_struct_timeval(proc, "timeout", 0, m_out->m_lc_vfs_select.timeout); 942 943 return CT_DONE; 944 } 945 946 static void 947 vfs_select_in(struct trace_proc * proc, const message * m_out, 948 const message * __unused m_in, int failed) 949 { 950 vir_bytes readfds, writefds, errorfds; 951 int nfds; 952 953 put_result(proc); 954 if (failed) 955 return; 956 957 nfds = m_out->m_lc_vfs_select.nfds; 958 959 readfds = (vir_bytes)m_out->m_lc_vfs_select.readfds; 960 writefds = (vir_bytes)m_out->m_lc_vfs_select.writefds; 961 errorfds = (vir_bytes)m_out->m_lc_vfs_select.errorfds; 962 963 if (readfds == 0 && writefds == 0 && errorfds == 0) 964 return; 965 966 /* Omit names, because it looks weird. */ 967 put_open(proc, NULL, PF_NONAME, "(", ", "); 968 if (readfds != 0) 969 put_fd_set(proc, "readfds", readfds, nfds); 970 if (writefds != 0) 971 put_fd_set(proc, "writefds", writefds, nfds); 972 if (errorfds != 0) 973 put_fd_set(proc, "errorfds", errorfds, nfds); 974 put_close(proc, ")"); 975 } 976 977 static int 978 vfs_fchdir_out(struct trace_proc * proc, const message * m_out) 979 { 980 981 put_fd(proc, "fd", m_out->m_lc_vfs_fchdir.fd); 982 983 return CT_DONE; 984 } 985 986 static int 987 vfs_fsync_out(struct trace_proc * proc, const message * m_out) 988 { 989 990 put_fd(proc, "fd", m_out->m_lc_vfs_fsync.fd); 991 992 return CT_DONE; 993 } 994 995 static int 996 vfs_truncate_out(struct trace_proc * proc, const message * m_out) 997 { 998 999 put_buf(proc, "path", PF_PATH, m_out->m_lc_vfs_truncate.name, 1000 m_out->m_lc_vfs_truncate.len); 1001 put_value(proc, "length", "%"PRId64, m_out->m_lc_vfs_truncate.offset); 1002 1003 return CT_DONE; 1004 } 1005 1006 static int 1007 vfs_ftruncate_out(struct trace_proc * proc, const message * m_out) 1008 { 1009 1010 put_fd(proc, "fd", m_out->m_lc_vfs_truncate.fd); 1011 put_value(proc, "length", "%"PRId64, m_out->m_lc_vfs_truncate.offset); 1012 1013 return CT_DONE; 1014 } 1015 1016 static int 1017 vfs_fchmod_out(struct trace_proc * proc, const message * m_out) 1018 { 1019 1020 put_fd(proc, "fd", m_out->m_lc_vfs_fchmod.fd); 1021 put_mode(proc, "mode", m_out->m_lc_vfs_fchmod.mode); 1022 1023 return CT_DONE; 1024 } 1025 1026 static int 1027 vfs_fchown_out(struct trace_proc * proc, const message * m_out) 1028 { 1029 1030 put_fd(proc, "fd", m_out->m_lc_vfs_chown.fd); 1031 /* -1 means "keep the current value" so print as signed */ 1032 put_value(proc, "owner", "%d", m_out->m_lc_vfs_chown.owner); 1033 put_value(proc, "group", "%d", m_out->m_lc_vfs_chown.group); 1034 1035 return CT_DONE; 1036 } 1037 1038 static const char * 1039 vfs_utimens_name(const message * m_out) 1040 { 1041 int has_path, has_flags; 1042 1043 has_path = (m_out->m_vfs_utimens.name != NULL); 1044 has_flags = (m_out->m_vfs_utimens.flags != 0); 1045 1046 if (has_path && m_out->m_vfs_utimens.flags == AT_SYMLINK_NOFOLLOW) 1047 return "lutimens"; 1048 if (has_path && !has_flags) 1049 return "utimens"; 1050 else if (!has_path && !has_flags) 1051 return "futimens"; 1052 else 1053 return "utimensat"; 1054 } 1055 1056 static const struct flags at_flags[] = { 1057 FLAG(AT_EACCESS), 1058 FLAG(AT_SYMLINK_NOFOLLOW), 1059 FLAG(AT_SYMLINK_FOLLOW), 1060 FLAG(AT_REMOVEDIR), 1061 }; 1062 1063 static void 1064 put_utimens_timespec(struct trace_proc * proc, const char * name, 1065 time_t sec, long nsec) 1066 { 1067 1068 /* No field names. */ 1069 put_open(proc, name, PF_NONAME, "{", ", "); 1070 1071 put_time(proc, "tv_sec", sec); 1072 1073 if (!valuesonly && nsec == UTIME_NOW) 1074 put_field(proc, "tv_nsec", "UTIME_NOW"); 1075 else if (!valuesonly && nsec == UTIME_OMIT) 1076 put_field(proc, "tv_nsec", "UTIME_OMIT"); 1077 else 1078 put_value(proc, "tv_nsec", "%ld", nsec); 1079 1080 put_close(proc, "}"); 1081 } 1082 1083 static int 1084 vfs_utimens_out(struct trace_proc * proc, const message * m_out) 1085 { 1086 int has_path, has_flags; 1087 1088 /* Here we do not care about the utimens/lutimens distinction. */ 1089 has_path = (m_out->m_vfs_utimens.name != NULL); 1090 has_flags = !!(m_out->m_vfs_utimens.flags & ~AT_SYMLINK_NOFOLLOW); 1091 1092 if (has_path && has_flags) 1093 put_field(proc, "fd", "AT_CWD"); /* utimensat */ 1094 else if (!has_path) 1095 put_fd(proc, "fd", m_out->m_vfs_utimens.fd); /* futimes */ 1096 if (has_path || has_flags) /* lutimes, utimes, utimensat */ 1097 put_buf(proc, "path", PF_PATH, 1098 (vir_bytes)m_out->m_vfs_utimens.name, 1099 m_out->m_vfs_utimens.len); 1100 1101 put_open(proc, "times", 0, "[", ", "); 1102 put_utimens_timespec(proc, "atime", m_out->m_vfs_utimens.atime, 1103 m_out->m_vfs_utimens.ansec); 1104 put_utimens_timespec(proc, "mtime", m_out->m_vfs_utimens.mtime, 1105 m_out->m_vfs_utimens.mnsec); 1106 put_close(proc, "]"); 1107 1108 if (has_flags) 1109 put_flags(proc, "flag", at_flags, COUNT(at_flags), "0x%x", 1110 m_out->m_vfs_utimens.flags); 1111 1112 return CT_DONE; 1113 } 1114 1115 static const struct flags statvfs_flags[] = { 1116 FLAG(ST_WAIT), 1117 FLAG(ST_NOWAIT), 1118 }; 1119 1120 static const struct flags st_flags[] = { 1121 FLAG(ST_RDONLY), 1122 FLAG(ST_SYNCHRONOUS), 1123 FLAG(ST_NOEXEC), 1124 FLAG(ST_NOSUID), 1125 FLAG(ST_NODEV), 1126 FLAG(ST_UNION), 1127 FLAG(ST_ASYNC), 1128 FLAG(ST_NOCOREDUMP), 1129 FLAG(ST_RELATIME), 1130 FLAG(ST_IGNORE), 1131 FLAG(ST_NOATIME), 1132 FLAG(ST_SYMPERM), 1133 FLAG(ST_NODEVMTIME), 1134 FLAG(ST_SOFTDEP), 1135 FLAG(ST_LOG), 1136 FLAG(ST_EXTATTR), 1137 FLAG(ST_EXRDONLY), 1138 FLAG(ST_EXPORTED), 1139 FLAG(ST_DEFEXPORTED), 1140 FLAG(ST_EXPORTANON), 1141 FLAG(ST_EXKERB), 1142 FLAG(ST_EXNORESPORT), 1143 FLAG(ST_EXPUBLIC), 1144 FLAG(ST_LOCAL), 1145 FLAG(ST_QUOTA), 1146 FLAG(ST_ROOTFS), 1147 FLAG(ST_NOTRUNC), 1148 }; 1149 1150 static void 1151 put_struct_statvfs(struct trace_proc * proc, const char * name, int flags, 1152 vir_bytes addr) 1153 { 1154 struct statvfs buf; 1155 1156 if (!put_open_struct(proc, name, flags, addr, &buf, sizeof(buf))) 1157 return; 1158 1159 put_flags(proc, "f_flag", st_flags, COUNT(st_flags), "0x%x", 1160 buf.f_flag); 1161 put_value(proc, "f_bsize", "%lu", buf.f_bsize); 1162 if (verbose > 0 || buf.f_bsize != buf.f_frsize) 1163 put_value(proc, "f_frsize", "%lu", buf.f_frsize); 1164 if (verbose > 1) 1165 put_value(proc, "f_iosize", "%lu", buf.f_iosize); 1166 1167 put_value(proc, "f_blocks", "%"PRIu64, buf.f_blocks); 1168 put_value(proc, "f_bfree", "%"PRIu64, buf.f_bfree); 1169 if (verbose > 1) { 1170 put_value(proc, "f_bavail", "%"PRIu64, buf.f_bavail); 1171 put_value(proc, "f_bresvd", "%"PRIu64, buf.f_bresvd); 1172 } 1173 1174 if (verbose > 0) { 1175 put_value(proc, "f_files", "%"PRIu64, buf.f_files); 1176 put_value(proc, "f_ffree", "%"PRIu64, buf.f_ffree); 1177 } 1178 if (verbose > 1) { 1179 put_value(proc, "f_favail", "%"PRIu64, buf.f_favail); 1180 put_value(proc, "f_fresvd", "%"PRIu64, buf.f_fresvd); 1181 } 1182 1183 if (verbose > 1) { 1184 put_value(proc, "f_syncreads", "%"PRIu64, buf.f_syncreads); 1185 put_value(proc, "f_syncwrites", "%"PRIu64, buf.f_syncwrites); 1186 put_value(proc, "f_asyncreads", "%"PRIu64, buf.f_asyncreads); 1187 put_value(proc, "f_asyncwrites", "%"PRIu64, buf.f_asyncwrites); 1188 1189 put_value(proc, "f_fsidx", "<%"PRId32",%"PRId32">", 1190 buf.f_fsidx.__fsid_val[0], buf.f_fsidx.__fsid_val[1]); 1191 } 1192 put_dev(proc, "f_fsid", buf.f_fsid); /* MINIX3 interpretation! */ 1193 1194 if (verbose > 0) 1195 put_value(proc, "f_namemax", "%lu", buf.f_namemax); 1196 if (verbose > 1) 1197 put_value(proc, "f_owner", "%u", buf.f_owner); 1198 1199 put_buf(proc, "f_fstypename", PF_STRING | PF_LOCADDR, 1200 (vir_bytes)&buf.f_fstypename, sizeof(buf.f_fstypename)); 1201 if (verbose > 0) 1202 put_buf(proc, "f_mntfromname", PF_STRING | PF_LOCADDR, 1203 (vir_bytes)&buf.f_mntfromname, sizeof(buf.f_mntfromname)); 1204 put_buf(proc, "f_mntonname", PF_STRING | PF_LOCADDR, 1205 (vir_bytes)&buf.f_mntonname, sizeof(buf.f_mntonname)); 1206 1207 put_close_struct(proc, verbose > 1); 1208 } 1209 1210 static void 1211 put_statvfs_array(struct trace_proc * proc, const char * name, int flags, 1212 vir_bytes addr, int count) 1213 { 1214 struct statvfs buf; 1215 int i, max; 1216 1217 if ((flags & PF_FAILED) || valuesonly || count < 0) { 1218 put_ptr(proc, name, addr); 1219 1220 return; 1221 } 1222 1223 if (count == 0) { 1224 put_field(proc, name, "[]"); 1225 1226 return; 1227 } 1228 1229 if (verbose == 0) 1230 max = 0; 1231 else if (verbose == 1) 1232 max = 1; /* TODO: is this reasonable? */ 1233 else 1234 max = INT_MAX; 1235 1236 if (max > count) 1237 max = count; 1238 1239 for (i = 0; i < max; i++) { 1240 if (mem_get_data(proc->pid, addr + i * sizeof(buf), &buf, 1241 sizeof(buf)) < 0) { 1242 if (i == 0) { 1243 put_ptr(proc, name, addr); 1244 1245 return; 1246 } 1247 1248 break; 1249 } 1250 1251 if (i == 0) 1252 put_open(proc, name, PF_NONAME, "[", ", "); 1253 1254 put_struct_statvfs(proc, NULL, PF_LOCADDR, (vir_bytes)&buf); 1255 } 1256 1257 if (i == 0) 1258 put_open(proc, name, PF_NONAME, "[", ", "); 1259 if (i < max) 1260 put_tail(proc, 0, 0); 1261 else if (count > i) 1262 put_tail(proc, count, i); 1263 put_close(proc, "]"); 1264 } 1265 1266 static int 1267 vfs_getvfsstat_out(struct trace_proc * proc, const message * m_out) 1268 { 1269 1270 if (m_out->m_lc_vfs_getvfsstat.buf == 0) { 1271 put_ptr(proc, "buf", m_out->m_lc_vfs_getvfsstat.buf); 1272 put_value(proc, "bufsize", "%zu", 1273 m_out->m_lc_vfs_getvfsstat.len); 1274 put_flags(proc, "flags", statvfs_flags, COUNT(statvfs_flags), 1275 "%d", m_out->m_lc_vfs_getvfsstat.flags); 1276 return CT_DONE; 1277 } else 1278 return CT_NOTDONE; 1279 } 1280 1281 static void 1282 vfs_getvfsstat_in(struct trace_proc * proc, const message * m_out, 1283 const message * m_in, int failed) 1284 { 1285 1286 if (m_out->m_lc_vfs_getvfsstat.buf != 0) { 1287 put_statvfs_array(proc, "buf", failed, 1288 m_out->m_lc_vfs_getvfsstat.buf, m_in->m_type); 1289 put_value(proc, "bufsize", "%zu", 1290 m_out->m_lc_vfs_getvfsstat.len); 1291 put_flags(proc, "flags", statvfs_flags, COUNT(statvfs_flags), 1292 "%d", m_out->m_lc_vfs_getvfsstat.flags); 1293 put_equals(proc); 1294 } 1295 put_result(proc); 1296 } 1297 1298 static int 1299 vfs_statvfs1_out(struct trace_proc * proc, const message * m_out) 1300 { 1301 1302 put_buf(proc, "path", PF_PATH, m_out->m_lc_vfs_statvfs1.name, 1303 m_out->m_lc_vfs_statvfs1.len); 1304 1305 return CT_NOTDONE; 1306 } 1307 1308 static void 1309 vfs_statvfs1_in(struct trace_proc * proc, const message * m_out, 1310 const message * __unused m_in, int failed) 1311 { 1312 1313 put_struct_statvfs(proc, "buf", failed, m_out->m_lc_vfs_statvfs1.buf); 1314 put_flags(proc, "flags", statvfs_flags, COUNT(statvfs_flags), "%d", 1315 m_out->m_lc_vfs_statvfs1.flags); 1316 put_equals(proc); 1317 put_result(proc); 1318 } 1319 1320 /* This function is shared between statvfs1 and fstatvfs1. */ 1321 static int 1322 vfs_fstatvfs1_out(struct trace_proc * proc, const message * m_out) 1323 { 1324 1325 put_fd(proc, "fd", m_out->m_lc_vfs_statvfs1.fd); 1326 1327 return CT_NOTDONE; 1328 } 1329 1330 static int 1331 vfs_svrctl_out(struct trace_proc * proc, const message * m_out) 1332 { 1333 1334 put_ioctl_req(proc, "request", m_out->m_lc_svrctl.request, 1335 TRUE /*is_svrctl*/); 1336 return put_ioctl_arg_out(proc, "arg", m_out->m_lc_svrctl.request, 1337 m_out->m_lc_svrctl.arg, TRUE /*is_svrctl*/); 1338 } 1339 1340 static void 1341 vfs_svrctl_in(struct trace_proc * proc, const message * m_out, 1342 const message * __unused m_in, int failed) 1343 { 1344 1345 put_ioctl_arg_in(proc, "arg", failed, m_out->m_lc_svrctl.request, 1346 m_out->m_lc_svrctl.arg, TRUE /*is_svrctl*/); 1347 } 1348 1349 static int 1350 vfs_gcov_flush_out(struct trace_proc * proc, const message * m_out) 1351 { 1352 1353 put_ptr(proc, "buff", m_out->m_lc_vfs_gcov.buff_p); 1354 put_value(proc, "buff_sz", "%zu", m_out->m_lc_vfs_gcov.buff_sz); 1355 put_value(proc, "server_pid", "%d", m_out->m_lc_vfs_gcov.pid); 1356 1357 return CT_DONE; 1358 } 1359 1360 #define VFS_CALL(c) [((VFS_ ## c) - VFS_BASE)] 1361 1362 static const struct call_handler vfs_map[] = { 1363 VFS_CALL(READ) = HANDLER("read", vfs_read_out, vfs_read_in), 1364 VFS_CALL(WRITE) = HANDLER("write", vfs_write_out, default_in), 1365 VFS_CALL(LSEEK) = HANDLER("lseek", vfs_lseek_out, vfs_lseek_in), 1366 VFS_CALL(OPEN) = HANDLER("open", vfs_open_out, vfs_open_in), 1367 VFS_CALL(CREAT) = HANDLER("open", vfs_creat_out, vfs_open_in), 1368 VFS_CALL(CLOSE) = HANDLER("close", vfs_close_out, default_in), 1369 VFS_CALL(LINK) = HANDLER("link", vfs_link_out, default_in), 1370 VFS_CALL(UNLINK) = HANDLER("unlink", vfs_path_out, default_in), 1371 VFS_CALL(CHDIR) = HANDLER("chdir", vfs_path_out, default_in), 1372 VFS_CALL(MKDIR) = HANDLER("mkdir", vfs_path_mode_out, default_in), 1373 VFS_CALL(MKNOD) = HANDLER("mknod", vfs_mknod_out, default_in), 1374 VFS_CALL(CHMOD) = HANDLER("chmod", vfs_path_mode_out, default_in), 1375 VFS_CALL(CHOWN) = HANDLER("chown", vfs_chown_out, default_in), 1376 VFS_CALL(MOUNT) = HANDLER("mount", vfs_mount_out, default_in), 1377 VFS_CALL(UMOUNT) = HANDLER("umount", vfs_umount_out, vfs_umount_in), 1378 VFS_CALL(ACCESS) = HANDLER("access", vfs_access_out, default_in), 1379 VFS_CALL(SYNC) = HANDLER("sync", default_out, default_in), 1380 VFS_CALL(RENAME) = HANDLER("rename", vfs_link_out, default_in), 1381 VFS_CALL(RMDIR) = HANDLER("rmdir", vfs_path_out, default_in), 1382 VFS_CALL(SYMLINK) = HANDLER("symlink", vfs_link_out, default_in), 1383 VFS_CALL(READLINK) = HANDLER("readlink", vfs_readlink_out, 1384 vfs_readlink_in), 1385 VFS_CALL(STAT) = HANDLER("stat", vfs_stat_out, vfs_stat_in), 1386 VFS_CALL(FSTAT) = HANDLER("fstat", vfs_fstat_out, vfs_fstat_in), 1387 VFS_CALL(LSTAT) = HANDLER("lstat", vfs_stat_out, vfs_stat_in), 1388 VFS_CALL(IOCTL) = HANDLER("ioctl", vfs_ioctl_out, vfs_ioctl_in), 1389 VFS_CALL(FCNTL) = HANDLER("fcntl", vfs_fcntl_out, vfs_fcntl_in), 1390 VFS_CALL(PIPE2) = HANDLER("pipe2", vfs_pipe2_out, vfs_pipe2_in), 1391 VFS_CALL(UMASK) = HANDLER("umask", vfs_umask_out, vfs_umask_in), 1392 VFS_CALL(CHROOT) = HANDLER("chroot", vfs_path_out, default_in), 1393 VFS_CALL(GETDENTS) = HANDLER("getdents", vfs_getdents_out, 1394 vfs_getdents_in), 1395 VFS_CALL(SELECT) = HANDLER("select", vfs_select_out, vfs_select_in), 1396 VFS_CALL(FCHDIR) = HANDLER("fchdir", vfs_fchdir_out, default_in), 1397 VFS_CALL(FSYNC) = HANDLER("fsync", vfs_fsync_out, default_in), 1398 VFS_CALL(TRUNCATE) = HANDLER("truncate", vfs_truncate_out, default_in), 1399 VFS_CALL(FTRUNCATE) = HANDLER("ftruncate", vfs_ftruncate_out, 1400 default_in), 1401 VFS_CALL(FCHMOD) = HANDLER("fchmod", vfs_fchmod_out, default_in), 1402 VFS_CALL(FCHOWN) = HANDLER("fchown", vfs_fchown_out, default_in), 1403 VFS_CALL(UTIMENS) = HANDLER_NAME(vfs_utimens_name, vfs_utimens_out, 1404 default_in), 1405 VFS_CALL(GETVFSSTAT) = HANDLER("getvfsstat", vfs_getvfsstat_out, 1406 vfs_getvfsstat_in), 1407 VFS_CALL(STATVFS1) = HANDLER("statvfs1", vfs_statvfs1_out, 1408 vfs_statvfs1_in), 1409 VFS_CALL(FSTATVFS1) = HANDLER("fstatvfs1", vfs_fstatvfs1_out, 1410 vfs_statvfs1_in), 1411 VFS_CALL(SVRCTL) = HANDLER("vfs_svrctl", vfs_svrctl_out, 1412 vfs_svrctl_in), 1413 VFS_CALL(GCOV_FLUSH) = HANDLER("gcov_flush", vfs_gcov_flush_out, 1414 default_in), 1415 }; 1416 1417 const struct calls vfs_calls = { 1418 .endpt = VFS_PROC_NR, 1419 .base = VFS_BASE, 1420 .map = vfs_map, 1421 .count = COUNT(vfs_map) 1422 }; 1423