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 600 put_fd(proc, "fd", m_out->m_lc_vfs_fcntl.fd); 601 put_fcntl_cmd(proc, "cmd", m_out->m_lc_vfs_fcntl.cmd); 602 603 switch (m_out->m_lc_vfs_fcntl.cmd) { 604 case F_DUPFD: 605 case F_DUPFD_CLOEXEC: 606 put_fd(proc, "fd2", m_out->m_lc_vfs_fcntl.arg_int); 607 break; 608 case F_SETFD: 609 put_fd_flags(proc, "flags", m_out->m_lc_vfs_fcntl.arg_int); 610 break; 611 case F_SETFL: 612 /* 613 * One of those difficult cases: the access mode is ignored, so 614 * we don't want to print O_RDONLY if it is not given. On the 615 * other hand, fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_..) is 616 * a fairly common construction, in which case we don't want to 617 * print eg O_..|0x2 if the access mode is O_RDWR. Thus, we 618 * compromise: show the access mode if any of its bits are set. 619 */ 620 put_open_flags(proc, "flags", m_out->m_lc_vfs_fcntl.arg_int, 621 m_out->m_lc_vfs_fcntl.arg_int & O_ACCMODE /*full*/); 622 break; 623 case F_SETLK: 624 case F_SETLKW: 625 put_struct_flock(proc, "lkp", 0, 626 m_out->m_lc_vfs_fcntl.arg_ptr); 627 break; 628 case F_FREESP: 629 put_struct_flock(proc, "lkp", PF_ALT, 630 m_out->m_lc_vfs_fcntl.arg_ptr); 631 break; 632 case F_SETNOSIGPIPE: 633 put_value(proc, "arg", "%d", m_out->m_lc_vfs_fcntl.arg_int); 634 break; 635 } 636 637 return (m_out->m_lc_vfs_fcntl.cmd != F_GETLK) ? CT_DONE : CT_NOTDONE; 638 } 639 640 static void 641 vfs_fcntl_in(struct trace_proc * proc, const message * m_out, 642 const message * m_in, int failed) 643 { 644 645 switch (m_out->m_lc_vfs_fcntl.cmd) { 646 case F_GETFD: 647 if (failed) 648 break; 649 put_fd_flags(proc, NULL, m_in->m_type); 650 return; 651 case F_GETFL: 652 if (failed) 653 break; 654 put_open_flags(proc, NULL, m_in->m_type, TRUE /*full*/); 655 return; 656 case F_GETLK: 657 put_struct_flock(proc, "lkp", failed | PF_FULL, 658 m_out->m_lc_vfs_fcntl.arg_ptr); 659 put_equals(proc); 660 break; 661 } 662 663 put_result(proc); 664 } 665 666 static int 667 vfs_pipe2_out(struct trace_proc * __unused proc, 668 const message * __unused m_out) 669 { 670 671 return CT_NOTDONE; 672 } 673 674 static void 675 vfs_pipe2_in(struct trace_proc * proc, const message * m_out, 676 const message * m_in, int failed) 677 { 678 679 if (!failed) { 680 put_open(proc, "fd", PF_NONAME, "[", ", "); 681 put_fd(proc, "rfd", m_in->m_lc_vfs_pipe2.fd0); 682 put_fd(proc, "wfd", m_in->m_lc_vfs_pipe2.fd1); 683 put_close(proc, "]"); 684 } else 685 put_field(proc, "fd", "&.."); 686 put_open_flags(proc, "flags", m_out->m_lc_vfs_pipe2.flags, 687 FALSE /*full*/); 688 put_equals(proc); 689 put_result(proc); 690 } 691 692 static int 693 vfs_umask_out(struct trace_proc * proc, const message * m_out) 694 { 695 696 put_mode(proc, NULL, m_out->m_lc_vfs_umask.mask); 697 698 return CT_DONE; 699 } 700 701 static void 702 vfs_umask_in(struct trace_proc * proc, const message * __unused m_out, 703 const message * m_in, int failed) 704 { 705 706 if (!failed) 707 put_mode(proc, NULL, m_in->m_type); 708 else 709 put_result(proc); 710 711 } 712 713 static void 714 put_dirent_type(struct trace_proc * proc, const char * name, unsigned int type) 715 { 716 const char *text = NULL; 717 718 if (!valuesonly) { 719 switch (type) { 720 TEXT(DT_UNKNOWN); 721 TEXT(DT_FIFO); 722 TEXT(DT_CHR); 723 TEXT(DT_DIR); 724 TEXT(DT_BLK); 725 TEXT(DT_REG); 726 TEXT(DT_LNK); 727 TEXT(DT_SOCK); 728 TEXT(DT_WHT); 729 } 730 } 731 732 if (text != NULL) 733 put_field(proc, name, text); 734 else 735 put_value(proc, name, "%u", type); 736 } 737 738 static void 739 put_struct_dirent(struct trace_proc * proc, const char *name, int flags, 740 vir_bytes addr) 741 { 742 struct dirent dirent; 743 744 if (!put_open_struct(proc, name, flags, addr, &dirent, sizeof(dirent))) 745 return; 746 747 if (verbose > 0) 748 put_value(proc, "d_fileno", "%"PRIu64, dirent.d_fileno); 749 if (verbose > 1) { 750 put_value(proc, "d_reclen", "%u", dirent.d_reclen); 751 put_value(proc, "d_namlen", "%u", dirent.d_namlen); 752 } 753 if (verbose >= 1 + (dirent.d_type == DT_UNKNOWN)) 754 put_dirent_type(proc, "d_type", dirent.d_type); 755 put_buf(proc, "d_name", PF_LOCADDR, (vir_bytes)dirent.d_name, 756 MIN(dirent.d_namlen, sizeof(dirent.d_name))); 757 758 put_close_struct(proc, verbose > 1); 759 } 760 761 static void 762 put_dirent_array(struct trace_proc * proc, const char * name, int flags, 763 vir_bytes addr, ssize_t size) 764 { 765 struct dirent dirent; 766 unsigned count, max; 767 ssize_t off, chunk; 768 769 if ((flags & PF_FAILED) || valuesonly > 1 || size < 0) { 770 put_ptr(proc, name, addr); 771 772 return; 773 } 774 775 if (size == 0) { 776 put_field(proc, name, "[]"); 777 778 return; 779 } 780 781 if (verbose == 0) 782 max = 0; /* TODO: should we set this to 1 instead? */ 783 else if (verbose == 1) 784 max = 3; /* low; just to give an indication where we are */ 785 else 786 max = INT_MAX; 787 788 /* 789 * TODO: as is, this is highly inefficient, as we are typically copying 790 * in the same pieces of memory in repeatedly.. 791 */ 792 count = 0; 793 for (off = 0; off < size; off += chunk) { 794 chunk = size - off; 795 if ((size_t)chunk > sizeof(dirent)) 796 chunk = (ssize_t)sizeof(dirent); 797 if ((size_t)chunk < _DIRENT_MINSIZE(&dirent)) 798 break; 799 800 if (mem_get_data(proc->pid, addr + off, &dirent, chunk) < 0) { 801 if (off == 0) { 802 put_ptr(proc, name, addr); 803 804 return; 805 } 806 807 break; 808 } 809 810 if (off == 0) 811 put_open(proc, name, PF_NONAME, "[", ", "); 812 813 if (count < max) 814 put_struct_dirent(proc, NULL, PF_LOCADDR, 815 (vir_bytes)&dirent); 816 817 if (chunk > dirent.d_reclen) 818 chunk = dirent.d_reclen; 819 count++; 820 } 821 822 if (off < size) 823 put_tail(proc, 0, 0); 824 else if (count > max) 825 put_tail(proc, count, max); 826 put_close(proc, "]"); 827 } 828 829 static int 830 vfs_getdents_out(struct trace_proc * proc, const message * m_out) 831 { 832 833 put_fd(proc, "fd", m_out->m_lc_vfs_readwrite.fd); 834 835 return CT_NOTDONE; 836 } 837 838 static void 839 vfs_getdents_in(struct trace_proc * proc, const message * m_out, 840 const message * m_in, int failed) 841 { 842 843 put_dirent_array(proc, "buf", failed, m_out->m_lc_vfs_readwrite.buf, 844 m_in->m_type); 845 put_value(proc, "len", "%zu", m_out->m_lc_vfs_readwrite.len); 846 put_equals(proc); 847 put_result(proc); 848 } 849 850 static void 851 put_fd_set(struct trace_proc * proc, const char * name, vir_bytes addr, 852 int nfds) 853 { 854 fd_set set; 855 size_t off; 856 unsigned int i, j, words, count, max; 857 858 if (addr == 0 || nfds < 0) { 859 put_ptr(proc, name, addr); 860 861 return; 862 } 863 864 /* 865 * Each process may define its own FD_SETSIZE, so our fd_set may be of 866 * a different size than theirs. Thus, we copy at a granularity known 867 * to be valid in any case: a single word of bits. We make the 868 * assumption that fd_set consists purely of bits, so that we can use 869 * the second (and so on) bit word as an fd_set by itself. 870 */ 871 words = (nfds + NFDBITS - 1) / NFDBITS; 872 873 count = 0; 874 875 if (verbose == 0) 876 max = 16; 877 else if (verbose == 1) 878 max = FD_SETSIZE; 879 else 880 max = INT_MAX; 881 882 /* TODO: copy in more at once, but stick to fd_mask boundaries. */ 883 for (off = 0, i = 0; i < words; i++, off += sizeof(fd_mask)) { 884 if (mem_get_data(proc->pid, addr + off, &set, 885 sizeof(fd_mask)) != 0) { 886 if (count == 0) { 887 put_ptr(proc, name, addr); 888 889 return; 890 } 891 892 break; 893 } 894 895 for (j = 0; j < NFDBITS; j++) { 896 if (FD_ISSET(j, &set)) { 897 if (count == 0) 898 put_open(proc, name, PF_NONAME, "[", 899 " "); 900 901 if (count < max) 902 put_fd(proc, NULL, i * NFDBITS + j); 903 904 count++; 905 } 906 } 907 } 908 909 /* 910 * The empty set should print as "[]". If copying any part failed, it 911 * should print as "[x, ..(?)]" where x is the set printed so far, if 912 * any. If copying never failed, and we did not print all fds in the 913 * set, print the remaining count n as "[x, ..(+n)]" at the end. 914 */ 915 if (count == 0) 916 put_open(proc, name, PF_NONAME, "[", " "); 917 918 if (i < words) 919 put_tail(proc, 0, 0); 920 else if (count > max) 921 put_tail(proc, count, max); 922 923 put_close(proc, "]"); 924 } 925 926 static int 927 vfs_select_out(struct trace_proc * proc, const message * m_out) 928 { 929 int nfds; 930 931 nfds = m_out->m_lc_vfs_select.nfds; 932 933 put_fd(proc, "nfds", nfds); /* not really a file descriptor.. */ 934 put_fd_set(proc, "readfds", 935 (vir_bytes)m_out->m_lc_vfs_select.readfds, nfds); 936 put_fd_set(proc, "writefds", 937 (vir_bytes)m_out->m_lc_vfs_select.writefds, nfds); 938 put_fd_set(proc, "errorfds", 939 (vir_bytes)m_out->m_lc_vfs_select.errorfds, nfds); 940 put_struct_timeval(proc, "timeout", 0, m_out->m_lc_vfs_select.timeout); 941 942 return CT_DONE; 943 } 944 945 static void 946 vfs_select_in(struct trace_proc * proc, const message * m_out, 947 const message * __unused m_in, int failed) 948 { 949 vir_bytes readfds, writefds, errorfds; 950 int nfds; 951 952 put_result(proc); 953 if (failed) 954 return; 955 956 nfds = m_out->m_lc_vfs_select.nfds; 957 958 readfds = (vir_bytes)m_out->m_lc_vfs_select.readfds; 959 writefds = (vir_bytes)m_out->m_lc_vfs_select.writefds; 960 errorfds = (vir_bytes)m_out->m_lc_vfs_select.errorfds; 961 962 if (readfds == 0 && writefds == 0 && errorfds == 0) 963 return; 964 965 /* Omit names, because it looks weird. */ 966 put_open(proc, NULL, PF_NONAME, "(", ", "); 967 if (readfds != 0) 968 put_fd_set(proc, "readfds", readfds, nfds); 969 if (writefds != 0) 970 put_fd_set(proc, "writefds", writefds, nfds); 971 if (errorfds != 0) 972 put_fd_set(proc, "errorfds", errorfds, nfds); 973 put_close(proc, ")"); 974 } 975 976 static int 977 vfs_fchdir_out(struct trace_proc * proc, const message * m_out) 978 { 979 980 put_fd(proc, "fd", m_out->m_lc_vfs_fchdir.fd); 981 982 return CT_DONE; 983 } 984 985 static int 986 vfs_fsync_out(struct trace_proc * proc, const message * m_out) 987 { 988 989 put_fd(proc, "fd", m_out->m_lc_vfs_fsync.fd); 990 991 return CT_DONE; 992 } 993 994 static int 995 vfs_truncate_out(struct trace_proc * proc, const message * m_out) 996 { 997 998 put_buf(proc, "path", PF_PATH, m_out->m_lc_vfs_truncate.name, 999 m_out->m_lc_vfs_truncate.len); 1000 put_value(proc, "length", "%"PRId64, m_out->m_lc_vfs_truncate.offset); 1001 1002 return CT_DONE; 1003 } 1004 1005 static int 1006 vfs_ftruncate_out(struct trace_proc * proc, const message * m_out) 1007 { 1008 1009 put_fd(proc, "fd", m_out->m_lc_vfs_truncate.fd); 1010 put_value(proc, "length", "%"PRId64, m_out->m_lc_vfs_truncate.offset); 1011 1012 return CT_DONE; 1013 } 1014 1015 static int 1016 vfs_fchmod_out(struct trace_proc * proc, const message * m_out) 1017 { 1018 1019 put_fd(proc, "fd", m_out->m_lc_vfs_fchmod.fd); 1020 put_mode(proc, "mode", m_out->m_lc_vfs_fchmod.mode); 1021 1022 return CT_DONE; 1023 } 1024 1025 static int 1026 vfs_fchown_out(struct trace_proc * proc, const message * m_out) 1027 { 1028 1029 put_fd(proc, "fd", m_out->m_lc_vfs_chown.fd); 1030 /* -1 means "keep the current value" so print as signed */ 1031 put_value(proc, "owner", "%d", m_out->m_lc_vfs_chown.owner); 1032 put_value(proc, "group", "%d", m_out->m_lc_vfs_chown.group); 1033 1034 return CT_DONE; 1035 } 1036 1037 static const char * 1038 vfs_utimens_name(const message * m_out) 1039 { 1040 int has_path, has_flags; 1041 1042 has_path = (m_out->m_vfs_utimens.name != NULL); 1043 has_flags = (m_out->m_vfs_utimens.flags != 0); 1044 1045 if (has_path && m_out->m_vfs_utimens.flags == AT_SYMLINK_NOFOLLOW) 1046 return "lutimens"; 1047 if (has_path && !has_flags) 1048 return "utimens"; 1049 else if (!has_path && !has_flags) 1050 return "futimens"; 1051 else 1052 return "utimensat"; 1053 } 1054 1055 static const struct flags at_flags[] = { 1056 FLAG(AT_EACCESS), 1057 FLAG(AT_SYMLINK_NOFOLLOW), 1058 FLAG(AT_SYMLINK_FOLLOW), 1059 FLAG(AT_REMOVEDIR), 1060 }; 1061 1062 static void 1063 put_utimens_timespec(struct trace_proc * proc, const char * name, 1064 time_t sec, long nsec) 1065 { 1066 1067 /* No field names. */ 1068 put_open(proc, name, PF_NONAME, "{", ", "); 1069 1070 put_time(proc, "tv_sec", sec); 1071 1072 if (!valuesonly && nsec == UTIME_NOW) 1073 put_field(proc, "tv_nsec", "UTIME_NOW"); 1074 else if (!valuesonly && nsec == UTIME_OMIT) 1075 put_field(proc, "tv_nsec", "UTIME_OMIT"); 1076 else 1077 put_value(proc, "tv_nsec", "%ld", nsec); 1078 1079 put_close(proc, "}"); 1080 } 1081 1082 static int 1083 vfs_utimens_out(struct trace_proc * proc, const message * m_out) 1084 { 1085 int has_path, has_flags; 1086 1087 /* Here we do not care about the utimens/lutimens distinction. */ 1088 has_path = (m_out->m_vfs_utimens.name != NULL); 1089 has_flags = !!(m_out->m_vfs_utimens.flags & ~AT_SYMLINK_NOFOLLOW); 1090 1091 if (has_path && has_flags) 1092 put_field(proc, "fd", "AT_CWD"); /* utimensat */ 1093 else if (!has_path) 1094 put_fd(proc, "fd", m_out->m_vfs_utimens.fd); /* futimes */ 1095 if (has_path || has_flags) /* lutimes, utimes, utimensat */ 1096 put_buf(proc, "path", PF_PATH, 1097 (vir_bytes)m_out->m_vfs_utimens.name, 1098 m_out->m_vfs_utimens.len); 1099 1100 put_open(proc, "times", 0, "[", ", "); 1101 put_utimens_timespec(proc, "atime", m_out->m_vfs_utimens.atime, 1102 m_out->m_vfs_utimens.ansec); 1103 put_utimens_timespec(proc, "mtime", m_out->m_vfs_utimens.mtime, 1104 m_out->m_vfs_utimens.mnsec); 1105 put_close(proc, "]"); 1106 1107 if (has_flags) 1108 put_flags(proc, "flag", at_flags, COUNT(at_flags), "0x%x", 1109 m_out->m_vfs_utimens.flags); 1110 1111 return CT_DONE; 1112 } 1113 1114 static const struct flags statvfs_flags[] = { 1115 FLAG(ST_WAIT), 1116 FLAG(ST_NOWAIT), 1117 }; 1118 1119 static const struct flags st_flags[] = { 1120 FLAG(ST_RDONLY), 1121 FLAG(ST_SYNCHRONOUS), 1122 FLAG(ST_NOEXEC), 1123 FLAG(ST_NOSUID), 1124 FLAG(ST_NODEV), 1125 FLAG(ST_UNION), 1126 FLAG(ST_ASYNC), 1127 FLAG(ST_NOCOREDUMP), 1128 FLAG(ST_RELATIME), 1129 FLAG(ST_IGNORE), 1130 FLAG(ST_NOATIME), 1131 FLAG(ST_SYMPERM), 1132 FLAG(ST_NODEVMTIME), 1133 FLAG(ST_SOFTDEP), 1134 FLAG(ST_LOG), 1135 FLAG(ST_EXTATTR), 1136 FLAG(ST_EXRDONLY), 1137 FLAG(ST_EXPORTED), 1138 FLAG(ST_DEFEXPORTED), 1139 FLAG(ST_EXPORTANON), 1140 FLAG(ST_EXKERB), 1141 FLAG(ST_EXNORESPORT), 1142 FLAG(ST_EXPUBLIC), 1143 FLAG(ST_LOCAL), 1144 FLAG(ST_QUOTA), 1145 FLAG(ST_ROOTFS), 1146 FLAG(ST_NOTRUNC), 1147 }; 1148 1149 static void 1150 put_struct_statvfs(struct trace_proc * proc, const char * name, int flags, 1151 vir_bytes addr) 1152 { 1153 struct statvfs buf; 1154 1155 if (!put_open_struct(proc, name, flags, addr, &buf, sizeof(buf))) 1156 return; 1157 1158 put_flags(proc, "f_flag", st_flags, COUNT(st_flags), "0x%x", 1159 buf.f_flag); 1160 put_value(proc, "f_bsize", "%lu", buf.f_bsize); 1161 if (verbose > 0 || buf.f_bsize != buf.f_frsize) 1162 put_value(proc, "f_frsize", "%lu", buf.f_frsize); 1163 if (verbose > 1) 1164 put_value(proc, "f_iosize", "%lu", buf.f_iosize); 1165 1166 put_value(proc, "f_blocks", "%"PRIu64, buf.f_blocks); 1167 put_value(proc, "f_bfree", "%"PRIu64, buf.f_bfree); 1168 if (verbose > 1) { 1169 put_value(proc, "f_bavail", "%"PRIu64, buf.f_bavail); 1170 put_value(proc, "f_bresvd", "%"PRIu64, buf.f_bresvd); 1171 } 1172 1173 if (verbose > 0) { 1174 put_value(proc, "f_files", "%"PRIu64, buf.f_files); 1175 put_value(proc, "f_ffree", "%"PRIu64, buf.f_ffree); 1176 } 1177 if (verbose > 1) { 1178 put_value(proc, "f_favail", "%"PRIu64, buf.f_favail); 1179 put_value(proc, "f_fresvd", "%"PRIu64, buf.f_fresvd); 1180 } 1181 1182 if (verbose > 1) { 1183 put_value(proc, "f_syncreads", "%"PRIu64, buf.f_syncreads); 1184 put_value(proc, "f_syncwrites", "%"PRIu64, buf.f_syncwrites); 1185 put_value(proc, "f_asyncreads", "%"PRIu64, buf.f_asyncreads); 1186 put_value(proc, "f_asyncwrites", "%"PRIu64, buf.f_asyncwrites); 1187 1188 put_value(proc, "f_fsidx", "<%"PRId32",%"PRId32">", 1189 buf.f_fsidx.__fsid_val[0], buf.f_fsidx.__fsid_val[1]); 1190 } 1191 put_dev(proc, "f_fsid", buf.f_fsid); /* MINIX3 interpretation! */ 1192 1193 if (verbose > 0) 1194 put_value(proc, "f_namemax", "%lu", buf.f_namemax); 1195 if (verbose > 1) 1196 put_value(proc, "f_owner", "%u", buf.f_owner); 1197 1198 put_buf(proc, "f_fstypename", PF_STRING | PF_LOCADDR, 1199 (vir_bytes)&buf.f_fstypename, sizeof(buf.f_fstypename)); 1200 if (verbose > 0) 1201 put_buf(proc, "f_mntfromname", PF_STRING | PF_LOCADDR, 1202 (vir_bytes)&buf.f_mntfromname, sizeof(buf.f_mntfromname)); 1203 put_buf(proc, "f_mntonname", PF_STRING | PF_LOCADDR, 1204 (vir_bytes)&buf.f_mntonname, sizeof(buf.f_mntonname)); 1205 1206 put_close_struct(proc, verbose > 1); 1207 } 1208 1209 static void 1210 put_statvfs_array(struct trace_proc * proc, const char * name, int flags, 1211 vir_bytes addr, int count) 1212 { 1213 struct statvfs buf; 1214 int i, max; 1215 1216 if ((flags & PF_FAILED) || valuesonly || count < 0) { 1217 put_ptr(proc, name, addr); 1218 1219 return; 1220 } 1221 1222 if (count == 0) { 1223 put_field(proc, name, "[]"); 1224 1225 return; 1226 } 1227 1228 if (verbose == 0) 1229 max = 0; 1230 else if (verbose == 1) 1231 max = 1; /* TODO: is this reasonable? */ 1232 else 1233 max = INT_MAX; 1234 1235 if (max > count) 1236 max = count; 1237 1238 for (i = 0; i < max; i++) { 1239 if (mem_get_data(proc->pid, addr + i * sizeof(buf), &buf, 1240 sizeof(buf)) < 0) { 1241 if (i == 0) { 1242 put_ptr(proc, name, addr); 1243 1244 return; 1245 } 1246 1247 break; 1248 } 1249 1250 if (i == 0) 1251 put_open(proc, name, PF_NONAME, "[", ", "); 1252 1253 put_struct_statvfs(proc, NULL, PF_LOCADDR, (vir_bytes)&buf); 1254 } 1255 1256 if (i == 0) 1257 put_open(proc, name, PF_NONAME, "[", ", "); 1258 if (i < max) 1259 put_tail(proc, 0, 0); 1260 else if (count > i) 1261 put_tail(proc, count, i); 1262 put_close(proc, "]"); 1263 } 1264 1265 static int 1266 vfs_getvfsstat_out(struct trace_proc * proc, const message * m_out) 1267 { 1268 1269 if (m_out->m_lc_vfs_getvfsstat.buf == 0) { 1270 put_ptr(proc, "buf", m_out->m_lc_vfs_getvfsstat.buf); 1271 put_value(proc, "bufsize", "%zu", 1272 m_out->m_lc_vfs_getvfsstat.len); 1273 put_flags(proc, "flags", statvfs_flags, COUNT(statvfs_flags), 1274 "%d", m_out->m_lc_vfs_getvfsstat.flags); 1275 return CT_DONE; 1276 } else 1277 return CT_NOTDONE; 1278 } 1279 1280 static void 1281 vfs_getvfsstat_in(struct trace_proc * proc, const message * m_out, 1282 const message * m_in, int failed) 1283 { 1284 1285 if (m_out->m_lc_vfs_getvfsstat.buf != 0) { 1286 put_statvfs_array(proc, "buf", failed, 1287 m_out->m_lc_vfs_getvfsstat.buf, m_in->m_type); 1288 put_value(proc, "bufsize", "%zu", 1289 m_out->m_lc_vfs_getvfsstat.len); 1290 put_flags(proc, "flags", statvfs_flags, COUNT(statvfs_flags), 1291 "%d", m_out->m_lc_vfs_getvfsstat.flags); 1292 put_equals(proc); 1293 } 1294 put_result(proc); 1295 } 1296 1297 static int 1298 vfs_statvfs1_out(struct trace_proc * proc, const message * m_out) 1299 { 1300 1301 put_buf(proc, "path", PF_PATH, m_out->m_lc_vfs_statvfs1.name, 1302 m_out->m_lc_vfs_statvfs1.len); 1303 1304 return CT_NOTDONE; 1305 } 1306 1307 static void 1308 vfs_statvfs1_in(struct trace_proc * proc, const message * m_out, 1309 const message * __unused m_in, int failed) 1310 { 1311 1312 put_struct_statvfs(proc, "buf", failed, m_out->m_lc_vfs_statvfs1.buf); 1313 put_flags(proc, "flags", statvfs_flags, COUNT(statvfs_flags), "%d", 1314 m_out->m_lc_vfs_statvfs1.flags); 1315 put_equals(proc); 1316 put_result(proc); 1317 } 1318 1319 /* This function is shared between statvfs1 and fstatvfs1. */ 1320 static int 1321 vfs_fstatvfs1_out(struct trace_proc * proc, const message * m_out) 1322 { 1323 1324 put_fd(proc, "fd", m_out->m_lc_vfs_statvfs1.fd); 1325 1326 return CT_NOTDONE; 1327 } 1328 1329 static int 1330 vfs_svrctl_out(struct trace_proc * proc, const message * m_out) 1331 { 1332 1333 put_ioctl_req(proc, "request", m_out->m_lc_svrctl.request, 1334 TRUE /*is_svrctl*/); 1335 return put_ioctl_arg_out(proc, "arg", m_out->m_lc_svrctl.request, 1336 m_out->m_lc_svrctl.arg, TRUE /*is_svrctl*/); 1337 } 1338 1339 static void 1340 vfs_svrctl_in(struct trace_proc * proc, const message * m_out, 1341 const message * __unused m_in, int failed) 1342 { 1343 1344 put_ioctl_arg_in(proc, "arg", failed, m_out->m_lc_svrctl.request, 1345 m_out->m_lc_svrctl.arg, TRUE /*is_svrctl*/); 1346 } 1347 1348 static int 1349 vfs_gcov_flush_out(struct trace_proc * proc, const message * m_out) 1350 { 1351 1352 put_ptr(proc, "buff", m_out->m_lc_vfs_gcov.buff_p); 1353 put_value(proc, "buff_sz", "%zu", m_out->m_lc_vfs_gcov.buff_sz); 1354 put_value(proc, "server_pid", "%d", m_out->m_lc_vfs_gcov.pid); 1355 1356 return CT_DONE; 1357 } 1358 1359 #define VFS_CALL(c) [((VFS_ ## c) - VFS_BASE)] 1360 1361 static const struct call_handler vfs_map[] = { 1362 VFS_CALL(READ) = HANDLER("read", vfs_read_out, vfs_read_in), 1363 VFS_CALL(WRITE) = HANDLER("write", vfs_write_out, default_in), 1364 VFS_CALL(LSEEK) = HANDLER("lseek", vfs_lseek_out, vfs_lseek_in), 1365 VFS_CALL(OPEN) = HANDLER("open", vfs_open_out, vfs_open_in), 1366 VFS_CALL(CREAT) = HANDLER("open", vfs_creat_out, vfs_open_in), 1367 VFS_CALL(CLOSE) = HANDLER("close", vfs_close_out, default_in), 1368 VFS_CALL(LINK) = HANDLER("link", vfs_link_out, default_in), 1369 VFS_CALL(UNLINK) = HANDLER("unlink", vfs_path_out, default_in), 1370 VFS_CALL(CHDIR) = HANDLER("chdir", vfs_path_out, default_in), 1371 VFS_CALL(MKDIR) = HANDLER("mkdir", vfs_path_mode_out, default_in), 1372 VFS_CALL(MKNOD) = HANDLER("mknod", vfs_mknod_out, default_in), 1373 VFS_CALL(CHMOD) = HANDLER("chmod", vfs_path_mode_out, default_in), 1374 VFS_CALL(CHOWN) = HANDLER("chown", vfs_chown_out, default_in), 1375 VFS_CALL(MOUNT) = HANDLER("mount", vfs_mount_out, default_in), 1376 VFS_CALL(UMOUNT) = HANDLER("umount", vfs_umount_out, vfs_umount_in), 1377 VFS_CALL(ACCESS) = HANDLER("access", vfs_access_out, default_in), 1378 VFS_CALL(SYNC) = HANDLER("sync", default_out, default_in), 1379 VFS_CALL(RENAME) = HANDLER("rename", vfs_link_out, default_in), 1380 VFS_CALL(RMDIR) = HANDLER("rmdir", vfs_path_out, default_in), 1381 VFS_CALL(SYMLINK) = HANDLER("symlink", vfs_link_out, default_in), 1382 VFS_CALL(READLINK) = HANDLER("readlink", vfs_readlink_out, 1383 vfs_readlink_in), 1384 VFS_CALL(STAT) = HANDLER("stat", vfs_stat_out, vfs_stat_in), 1385 VFS_CALL(FSTAT) = HANDLER("fstat", vfs_fstat_out, vfs_fstat_in), 1386 VFS_CALL(LSTAT) = HANDLER("lstat", vfs_stat_out, vfs_stat_in), 1387 VFS_CALL(IOCTL) = HANDLER("ioctl", vfs_ioctl_out, vfs_ioctl_in), 1388 VFS_CALL(FCNTL) = HANDLER("fcntl", vfs_fcntl_out, vfs_fcntl_in), 1389 VFS_CALL(PIPE2) = HANDLER("pipe2", vfs_pipe2_out, vfs_pipe2_in), 1390 VFS_CALL(UMASK) = HANDLER("umask", vfs_umask_out, vfs_umask_in), 1391 VFS_CALL(CHROOT) = HANDLER("chroot", vfs_path_out, default_in), 1392 VFS_CALL(GETDENTS) = HANDLER("getdents", vfs_getdents_out, 1393 vfs_getdents_in), 1394 VFS_CALL(SELECT) = HANDLER("select", vfs_select_out, vfs_select_in), 1395 VFS_CALL(FCHDIR) = HANDLER("fchdir", vfs_fchdir_out, default_in), 1396 VFS_CALL(FSYNC) = HANDLER("fsync", vfs_fsync_out, default_in), 1397 VFS_CALL(TRUNCATE) = HANDLER("truncate", vfs_truncate_out, default_in), 1398 VFS_CALL(FTRUNCATE) = HANDLER("ftruncate", vfs_ftruncate_out, 1399 default_in), 1400 VFS_CALL(FCHMOD) = HANDLER("fchmod", vfs_fchmod_out, default_in), 1401 VFS_CALL(FCHOWN) = HANDLER("fchown", vfs_fchown_out, default_in), 1402 VFS_CALL(UTIMENS) = HANDLER_NAME(vfs_utimens_name, vfs_utimens_out, 1403 default_in), 1404 VFS_CALL(GETVFSSTAT) = HANDLER("getvfsstat", vfs_getvfsstat_out, 1405 vfs_getvfsstat_in), 1406 VFS_CALL(STATVFS1) = HANDLER("statvfs1", vfs_statvfs1_out, 1407 vfs_statvfs1_in), 1408 VFS_CALL(FSTATVFS1) = HANDLER("fstatvfs1", vfs_fstatvfs1_out, 1409 vfs_statvfs1_in), 1410 VFS_CALL(SVRCTL) = HANDLER("vfs_svrctl", vfs_svrctl_out, 1411 vfs_svrctl_in), 1412 VFS_CALL(GCOV_FLUSH) = HANDLER("gcov_flush", vfs_gcov_flush_out, 1413 default_in), 1414 }; 1415 1416 const struct calls vfs_calls = { 1417 .endpt = VFS_PROC_NR, 1418 .base = VFS_BASE, 1419 .map = vfs_map, 1420 .count = COUNT(vfs_map) 1421 }; 1422