1 /* $NetBSD: filemon_ktrace.c,v 1.14 2021/02/01 21:34:41 rillig Exp $ */ 2 3 /* 4 * Copyright (c) 2019 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Taylor R. Campbell. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #define _KERNTYPES /* register_t */ 33 34 #include "filemon.h" 35 36 #include <sys/param.h> 37 #include <sys/types.h> 38 #include <sys/rbtree.h> 39 #include <sys/syscall.h> 40 #include <sys/time.h> 41 #include <sys/uio.h> 42 #include <sys/wait.h> 43 44 #include <sys/ktrace.h> 45 46 #include <assert.h> 47 #include <err.h> 48 #include <errno.h> 49 #include <fcntl.h> 50 #include <stdbool.h> 51 #include <stddef.h> 52 #include <stdio.h> 53 #include <stdlib.h> 54 #include <string.h> 55 #include <unistd.h> 56 57 #ifndef AT_CWD 58 #define AT_CWD -1 59 #endif 60 61 struct filemon; 62 struct filemon_key; 63 struct filemon_state; 64 65 typedef struct filemon_state *filemon_syscall_t(struct filemon *, 66 const struct filemon_key *, const struct ktr_syscall *); 67 68 static filemon_syscall_t filemon_sys_chdir; 69 static filemon_syscall_t filemon_sys_execve; 70 static filemon_syscall_t filemon_sys_exit; 71 static filemon_syscall_t filemon_sys_fork; 72 static filemon_syscall_t filemon_sys_link; 73 static filemon_syscall_t filemon_sys_open; 74 static filemon_syscall_t filemon_sys_openat; 75 static filemon_syscall_t filemon_sys_symlink; 76 static filemon_syscall_t filemon_sys_unlink; 77 static filemon_syscall_t filemon_sys_rename; 78 79 static filemon_syscall_t *const filemon_syscalls[] = { 80 [SYS_chdir] = &filemon_sys_chdir, 81 [SYS_execve] = &filemon_sys_execve, 82 [SYS_exit] = &filemon_sys_exit, 83 [SYS_fork] = &filemon_sys_fork, 84 [SYS_link] = &filemon_sys_link, 85 [SYS_open] = &filemon_sys_open, 86 [SYS_openat] = &filemon_sys_openat, 87 [SYS_symlink] = &filemon_sys_symlink, 88 [SYS_unlink] = &filemon_sys_unlink, 89 [SYS_rename] = &filemon_sys_rename, 90 }; 91 92 struct filemon { 93 int ktrfd; /* kernel writes ktrace events here */ 94 FILE *in; /* we read ktrace events from here */ 95 FILE *out; /* we write filemon events to here */ 96 rb_tree_t active; 97 pid_t child; 98 99 /* I/O state machine. */ 100 enum { 101 FILEMON_START = 0, 102 FILEMON_HEADER, 103 FILEMON_PAYLOAD, 104 FILEMON_ERROR, 105 } state; 106 unsigned char *p; 107 size_t resid; 108 109 /* I/O buffer. */ 110 struct ktr_header hdr; 111 union { 112 struct ktr_syscall syscall; 113 struct ktr_sysret sysret; 114 char namei[PATH_MAX]; 115 unsigned char buf[4096]; 116 } payload; 117 }; 118 119 struct filemon_state { 120 struct filemon_key { 121 pid_t pid; 122 lwpid_t lid; 123 } key; 124 struct rb_node node; 125 int syscode; 126 void (*show)(struct filemon *, const struct filemon_state *, 127 const struct ktr_sysret *); 128 unsigned i; 129 unsigned npath; 130 char *path[/*npath*/]; 131 }; 132 133 /*ARGSUSED*/ 134 static int 135 compare_filemon_states(void *cookie, const void *na, const void *nb) 136 { 137 const struct filemon_state *Sa = na; 138 const struct filemon_state *Sb = nb; 139 140 if (Sa->key.pid < Sb->key.pid) 141 return -1; 142 if (Sa->key.pid > Sb->key.pid) 143 return +1; 144 if (Sa->key.lid < Sb->key.lid) 145 return -1; 146 if (Sa->key.lid > Sb->key.lid) 147 return +1; 148 return 0; 149 } 150 151 /*ARGSUSED*/ 152 static int 153 compare_filemon_key(void *cookie, const void *n, const void *k) 154 { 155 const struct filemon_state *S = n; 156 const struct filemon_key *key = k; 157 158 if (S->key.pid < key->pid) 159 return -1; 160 if (S->key.pid > key->pid) 161 return +1; 162 if (S->key.lid < key->lid) 163 return -1; 164 if (S->key.lid > key->lid) 165 return +1; 166 return 0; 167 } 168 169 static const rb_tree_ops_t filemon_rb_ops = { 170 .rbto_compare_nodes = &compare_filemon_states, 171 .rbto_compare_key = &compare_filemon_key, 172 .rbto_node_offset = offsetof(struct filemon_state, node), 173 .rbto_context = NULL, 174 }; 175 176 /* 177 * filemon_path() 178 * 179 * Return a pointer to a constant string denoting the `path' of 180 * the filemon. 181 */ 182 const char * 183 filemon_path(void) 184 { 185 186 return "ktrace"; 187 } 188 189 /* 190 * filemon_open() 191 * 192 * Allocate a filemon descriptor. Returns NULL and sets errno on 193 * failure. 194 */ 195 struct filemon * 196 filemon_open(void) 197 { 198 struct filemon *F; 199 int ktrpipe[2]; 200 int error; 201 202 /* Allocate and zero a struct filemon object. */ 203 F = calloc(1, sizeof *F); 204 if (F == NULL) 205 return NULL; 206 207 /* Create a pipe for ktrace events. */ 208 if (pipe2(ktrpipe, O_CLOEXEC|O_NONBLOCK) == -1) { 209 error = errno; 210 goto fail0; 211 } 212 213 /* Create a file stream for reading the ktrace events. */ 214 if ((F->in = fdopen(ktrpipe[0], "r")) == NULL) { 215 error = errno; 216 goto fail1; 217 } 218 ktrpipe[0] = -1; /* claimed by fdopen */ 219 220 /* 221 * Set the fd for writing ktrace events and initialize the 222 * rbtree. The rest can be safely initialized to zero. 223 */ 224 F->ktrfd = ktrpipe[1]; 225 rb_tree_init(&F->active, &filemon_rb_ops); 226 227 /* Success! */ 228 return F; 229 230 (void)fclose(F->in); 231 fail1: (void)close(ktrpipe[0]); 232 (void)close(ktrpipe[1]); 233 fail0: free(F); 234 errno = error; 235 return NULL; 236 } 237 238 /* 239 * filemon_closefd(F) 240 * 241 * Internal subroutine to try to flush and close the output file. 242 * If F is not open for output, do nothing. Never leaves F open 243 * for output even on failure. Returns 0 on success; sets errno 244 * and return -1 on failure. 245 */ 246 static int 247 filemon_closefd(struct filemon *F) 248 { 249 int error = 0; 250 251 /* If we're not open, nothing to do. */ 252 if (F->out == NULL) 253 return 0; 254 255 /* 256 * Flush it, close it, and null it unconditionally, but be 257 * careful to return the earliest error in errno. 258 */ 259 if (fflush(F->out) == EOF && error == 0) 260 error = errno; 261 if (fclose(F->out) == EOF && error == 0) 262 error = errno; 263 F->out = NULL; 264 265 /* Set errno and return -1 if anything went wrong. */ 266 if (error != 0) { 267 errno = error; 268 return -1; 269 } 270 271 /* Success! */ 272 return 0; 273 } 274 275 /* 276 * filemon_setfd(F, fd) 277 * 278 * Cause filemon activity on F to be sent to fd. Claims ownership 279 * of fd; caller should not use fd afterward, and any duplicates 280 * of fd may see their file positions changed. 281 */ 282 int 283 filemon_setfd(struct filemon *F, int fd) 284 { 285 286 /* 287 * Close an existing output file if done. Fail now if there's 288 * an error closing. 289 */ 290 if ((filemon_closefd(F)) == -1) 291 return -1; 292 assert(F->out == NULL); 293 294 /* Open a file stream and claim ownership of the fd. */ 295 if ((F->out = fdopen(fd, "a")) == NULL) 296 return -1; 297 298 /* 299 * Print the opening output. Any failure will be deferred 300 * until closing. For hysterical raisins, we show the parent 301 * pid, not the child pid. 302 */ 303 fprintf(F->out, "# filemon version 4\n"); 304 fprintf(F->out, "# Target pid %jd\n", (intmax_t)getpid()); 305 fprintf(F->out, "V 4\n"); 306 307 /* Success! */ 308 return 0; 309 } 310 311 /* 312 * filemon_setpid_parent(F, pid) 313 * 314 * Set the traced pid, from the parent. Never fails. 315 */ 316 void 317 filemon_setpid_parent(struct filemon *F, pid_t pid) 318 { 319 320 F->child = pid; 321 } 322 323 /* 324 * filemon_setpid_child(F, pid) 325 * 326 * Set the traced pid, from the child. Returns 0 on success; sets 327 * errno and returns -1 on failure. 328 */ 329 int 330 filemon_setpid_child(const struct filemon *F, pid_t pid) 331 { 332 int ops, trpoints; 333 334 ops = KTROP_SET|KTRFLAG_DESCEND; 335 trpoints = KTRFACv2; 336 trpoints |= KTRFAC_SYSCALL|KTRFAC_NAMEI|KTRFAC_SYSRET; 337 trpoints |= KTRFAC_INHERIT; 338 if (fktrace(F->ktrfd, ops, trpoints, pid) == -1) 339 return -1; 340 341 return 0; 342 } 343 344 /* 345 * filemon_close(F) 346 * 347 * Close F for output if necessary, and free a filemon descriptor. 348 * Returns 0 on success; sets errno and returns -1 on failure, but 349 * frees the filemon descriptor either way; 350 */ 351 int 352 filemon_close(struct filemon *F) 353 { 354 struct filemon_state *S; 355 int error = 0; 356 357 /* Close for output. */ 358 if (filemon_closefd(F) == -1 && error == 0) 359 error = errno; 360 361 /* Close the ktrace pipe. */ 362 if (fclose(F->in) == EOF && error == 0) 363 error = errno; 364 if (close(F->ktrfd) == -1 && error == 0) 365 error = errno; 366 367 /* Free any active records. */ 368 while ((S = RB_TREE_MIN(&F->active)) != NULL) { 369 rb_tree_remove_node(&F->active, S); 370 free(S); 371 } 372 373 /* Free the filemon descriptor. */ 374 free(F); 375 376 /* Set errno and return -1 if anything went wrong. */ 377 if (error != 0) { 378 errno = error; 379 return -1; 380 } 381 382 /* Success! */ 383 return 0; 384 } 385 386 /* 387 * filemon_readfd(F) 388 * 389 * Returns a file descriptor which will select/poll ready for read 390 * when there are filemon events to be processed by 391 * filemon_process, or -1 if anything has gone wrong. 392 */ 393 int 394 filemon_readfd(const struct filemon *F) 395 { 396 397 if (F->state == FILEMON_ERROR) 398 return -1; 399 return fileno(F->in); 400 } 401 402 /* 403 * filemon_dispatch(F) 404 * 405 * Internal subroutine to dispatch a filemon ktrace event. 406 * Silently ignore events that we don't recognize. 407 */ 408 static void 409 filemon_dispatch(struct filemon *F) 410 { 411 const struct filemon_key key = { 412 .pid = F->hdr.ktr_pid, 413 .lid = F->hdr.ktr_lid, 414 }; 415 struct filemon_state *S; 416 417 switch (F->hdr.ktr_type) { 418 case KTR_SYSCALL: { 419 struct ktr_syscall *call = &F->payload.syscall; 420 struct filemon_state *S1; 421 422 /* Validate the syscall code. */ 423 if (call->ktr_code < 0 || 424 (size_t)call->ktr_code >= __arraycount(filemon_syscalls) || 425 filemon_syscalls[call->ktr_code] == NULL) 426 break; 427 428 /* 429 * Invoke the syscall-specific logic to create a new 430 * active state. 431 */ 432 S = (*filemon_syscalls[call->ktr_code])(F, &key, call); 433 if (S == NULL) 434 break; 435 436 /* 437 * Insert the active state, or ignore it if there 438 * already is one. 439 * 440 * Collisions shouldn't happen because the states are 441 * keyed by <pid,lid>, in which syscalls should happen 442 * sequentially in CALL/RET pairs, but let's be 443 * defensive. 444 */ 445 S1 = rb_tree_insert_node(&F->active, S); 446 if (S1 != S) { 447 /* XXX Which one to drop? */ 448 free(S); 449 break; 450 } 451 break; 452 } 453 case KTR_NAMEI: 454 /* Find an active syscall state, or drop it. */ 455 S = rb_tree_find_node(&F->active, &key); 456 if (S == NULL) 457 break; 458 /* Find the position of the next path, or drop it. */ 459 if (S->i >= S->npath) 460 break; 461 /* Record the path. */ 462 S->path[S->i++] = strndup(F->payload.namei, 463 sizeof F->payload.namei); 464 break; 465 case KTR_SYSRET: { 466 struct ktr_sysret *ret = &F->payload.sysret; 467 unsigned i; 468 469 /* Find and remove an active syscall state, or drop it. */ 470 S = rb_tree_find_node(&F->active, &key); 471 if (S == NULL) 472 break; 473 rb_tree_remove_node(&F->active, S); 474 475 /* 476 * If the active syscall state matches this return, 477 * invoke the syscall-specific logic to show a filemon 478 * event. 479 */ 480 /* XXX What to do if syscall code doesn't match? */ 481 if (S->i == S->npath && S->syscode == ret->ktr_code) 482 S->show(F, S, ret); 483 484 /* Free the state now that it is no longer active. */ 485 for (i = 0; i < S->i; i++) 486 free(S->path[i]); 487 free(S); 488 break; 489 } 490 default: 491 /* Ignore all other ktrace events. */ 492 break; 493 } 494 } 495 496 /* 497 * filemon_process(F) 498 * 499 * Process all pending events after filemon_readfd(F) has 500 * selected/polled ready for read. 501 * 502 * Returns -1 on failure, 0 on end of events, and anything else if 503 * there may be more events. 504 * 505 * XXX What about fairness to other activities in the event loop? 506 * If we stop while there's events buffered in F->in, then select 507 * or poll may not return ready even though there's work queued up 508 * in the buffer of F->in, but if we don't stop then ktrace events 509 * may overwhelm all other activity in the event loop. 510 */ 511 int 512 filemon_process(struct filemon *F) 513 { 514 size_t nread; 515 516 top: /* If the child has exited, nothing to do. */ 517 /* XXX What if one thread calls exit while another is running? */ 518 if (F->child == 0) 519 return 0; 520 521 /* If we're waiting for input, read some. */ 522 if (F->resid > 0) { 523 nread = fread(F->p, 1, F->resid, F->in); 524 if (nread == 0) { 525 if (feof(F->in) != 0) 526 return 0; 527 assert(ferror(F->in) != 0); 528 /* 529 * If interrupted or would block, there may be 530 * more events. Otherwise fail. 531 */ 532 if (errno == EAGAIN || errno == EINTR) 533 return 1; 534 F->state = FILEMON_ERROR; 535 F->p = NULL; 536 F->resid = 0; 537 return -1; 538 } 539 assert(nread <= F->resid); 540 F->p += nread; 541 F->resid -= nread; 542 if (F->resid > 0) /* may be more events */ 543 return 1; 544 } 545 546 /* Process a state transition now that we've read a buffer. */ 547 switch (F->state) { 548 case FILEMON_START: /* just started filemon; read header next */ 549 F->state = FILEMON_HEADER; 550 F->p = (void *)&F->hdr; 551 F->resid = sizeof F->hdr; 552 goto top; 553 case FILEMON_HEADER: /* read header */ 554 /* Sanity-check ktrace header; then read payload. */ 555 if (F->hdr.ktr_len < 0 || 556 (size_t)F->hdr.ktr_len > sizeof F->payload) { 557 F->state = FILEMON_ERROR; 558 F->p = NULL; 559 F->resid = 0; 560 errno = EIO; 561 return -1; 562 } 563 F->state = FILEMON_PAYLOAD; 564 F->p = (void *)&F->payload; 565 F->resid = (size_t)F->hdr.ktr_len; 566 goto top; 567 case FILEMON_PAYLOAD: /* read header and payload */ 568 /* Dispatch ktrace event; then read next header. */ 569 filemon_dispatch(F); 570 F->state = FILEMON_HEADER; 571 F->p = (void *)&F->hdr; 572 F->resid = sizeof F->hdr; 573 goto top; 574 default: /* paranoia */ 575 F->state = FILEMON_ERROR; 576 /*FALLTHROUGH*/ 577 case FILEMON_ERROR: /* persistent error indicator */ 578 F->p = NULL; 579 F->resid = 0; 580 errno = EIO; 581 return -1; 582 } 583 } 584 585 static struct filemon_state * 586 syscall_enter( 587 const struct filemon_key *key, const struct ktr_syscall *call, 588 unsigned npath, 589 void (*show)(struct filemon *, const struct filemon_state *, 590 const struct ktr_sysret *)) 591 { 592 struct filemon_state *S; 593 unsigned i; 594 595 S = calloc(1, offsetof(struct filemon_state, path[npath])); 596 if (S == NULL) 597 return NULL; 598 S->key = *key; 599 S->show = show; 600 S->syscode = call->ktr_code; 601 S->i = 0; 602 S->npath = npath; 603 for (i = 0; i < npath; i++) 604 S->path[i] = NULL; /* paranoia */ 605 606 return S; 607 } 608 609 static void 610 show_paths(struct filemon *F, const struct filemon_state *S, 611 const struct ktr_sysret *ret, const char *prefix) 612 { 613 unsigned i; 614 615 /* Caller must ensure all paths have been specified. */ 616 assert(S->i == S->npath); 617 618 /* 619 * Ignore it if it failed or yielded EJUSTRETURN (-2), or if 620 * we're not producing output. 621 */ 622 if (ret->ktr_error != 0 && ret->ktr_error != -2) 623 return; 624 if (F->out == NULL) 625 return; 626 627 /* 628 * Print the prefix, pid, and paths -- with the paths quoted if 629 * there's more than one. 630 */ 631 fprintf(F->out, "%s %jd", prefix, (intmax_t)S->key.pid); 632 for (i = 0; i < S->npath; i++) { 633 const char *q = S->npath > 1 ? "'" : ""; 634 fprintf(F->out, " %s%s%s", q, S->path[i], q); 635 } 636 fprintf(F->out, "\n"); 637 } 638 639 static void 640 show_retval(struct filemon *F, const struct filemon_state *S, 641 const struct ktr_sysret *ret, const char *prefix) 642 { 643 644 /* 645 * Ignore it if it failed or yielded EJUSTRETURN (-2), or if 646 * we're not producing output. 647 */ 648 if (ret->ktr_error != 0 && ret->ktr_error != -2) 649 return; 650 if (F->out == NULL) 651 return; 652 653 fprintf(F->out, "%s %jd %jd\n", prefix, (intmax_t)S->key.pid, 654 (intmax_t)ret->ktr_retval); 655 } 656 657 static void 658 show_chdir(struct filemon *F, const struct filemon_state *S, 659 const struct ktr_sysret *ret) 660 { 661 show_paths(F, S, ret, "C"); 662 } 663 664 static void 665 show_execve(struct filemon *F, const struct filemon_state *S, 666 const struct ktr_sysret *ret) 667 { 668 show_paths(F, S, ret, "E"); 669 } 670 671 static void 672 show_fork(struct filemon *F, const struct filemon_state *S, 673 const struct ktr_sysret *ret) 674 { 675 show_retval(F, S, ret, "F"); 676 } 677 678 static void 679 show_link(struct filemon *F, const struct filemon_state *S, 680 const struct ktr_sysret *ret) 681 { 682 show_paths(F, S, ret, "L"); /* XXX same as symlink */ 683 } 684 685 static void 686 show_open_read(struct filemon *F, const struct filemon_state *S, 687 const struct ktr_sysret *ret) 688 { 689 show_paths(F, S, ret, "R"); 690 } 691 692 static void 693 show_open_write(struct filemon *F, const struct filemon_state *S, 694 const struct ktr_sysret *ret) 695 { 696 show_paths(F, S, ret, "W"); 697 } 698 699 static void 700 show_open_readwrite(struct filemon *F, const struct filemon_state *S, 701 const struct ktr_sysret *ret) 702 { 703 show_paths(F, S, ret, "R"); 704 show_paths(F, S, ret, "W"); 705 } 706 707 static void 708 show_openat_read(struct filemon *F, const struct filemon_state *S, 709 const struct ktr_sysret *ret) 710 { 711 if (S->path[0][0] != '/') 712 show_paths(F, S, ret, "A"); 713 show_paths(F, S, ret, "R"); 714 } 715 716 static void 717 show_openat_write(struct filemon *F, const struct filemon_state *S, 718 const struct ktr_sysret *ret) 719 { 720 if (S->path[0][0] != '/') 721 show_paths(F, S, ret, "A"); 722 show_paths(F, S, ret, "W"); 723 } 724 725 static void 726 show_openat_readwrite(struct filemon *F, const struct filemon_state *S, 727 const struct ktr_sysret *ret) 728 { 729 if (S->path[0][0] != '/') 730 show_paths(F, S, ret, "A"); 731 show_paths(F, S, ret, "R"); 732 show_paths(F, S, ret, "W"); 733 } 734 735 static void 736 show_symlink(struct filemon *F, const struct filemon_state *S, 737 const struct ktr_sysret *ret) 738 { 739 show_paths(F, S, ret, "L"); /* XXX same as link */ 740 } 741 742 static void 743 show_unlink(struct filemon *F, const struct filemon_state *S, 744 const struct ktr_sysret *ret) 745 { 746 show_paths(F, S, ret, "D"); 747 } 748 749 static void 750 show_rename(struct filemon *F, const struct filemon_state *S, 751 const struct ktr_sysret *ret) 752 { 753 show_paths(F, S, ret, "M"); 754 } 755 756 /*ARGSUSED*/ 757 static struct filemon_state * 758 filemon_sys_chdir(struct filemon *F, const struct filemon_key *key, 759 const struct ktr_syscall *call) 760 { 761 return syscall_enter(key, call, 1, &show_chdir); 762 } 763 764 /* TODO: monitor fchdir as well */ 765 766 /*ARGSUSED*/ 767 static struct filemon_state * 768 filemon_sys_execve(struct filemon *F, const struct filemon_key *key, 769 const struct ktr_syscall *call) 770 { 771 return syscall_enter(key, call, 1, &show_execve); 772 } 773 774 static struct filemon_state * 775 filemon_sys_exit(struct filemon *F, const struct filemon_key *key, 776 const struct ktr_syscall *call) 777 { 778 const register_t *args = (const void *)&call[1]; 779 int status = (int)args[0]; 780 781 if (F->out != NULL) { 782 fprintf(F->out, "X %jd %d\n", (intmax_t)key->pid, status); 783 if (key->pid == F->child) { 784 fprintf(F->out, "# Bye bye\n"); 785 F->child = 0; 786 } 787 } 788 return NULL; 789 } 790 791 /*ARGSUSED*/ 792 static struct filemon_state * 793 filemon_sys_fork(struct filemon *F, const struct filemon_key *key, 794 const struct ktr_syscall *call) 795 { 796 return syscall_enter(key, call, 0, &show_fork); 797 } 798 799 /*ARGSUSED*/ 800 static struct filemon_state * 801 filemon_sys_link(struct filemon *F, const struct filemon_key *key, 802 const struct ktr_syscall *call) 803 { 804 return syscall_enter(key, call, 2, &show_link); 805 } 806 807 /*ARGSUSED*/ 808 static struct filemon_state * 809 filemon_sys_open(struct filemon *F, const struct filemon_key *key, 810 const struct ktr_syscall *call) 811 { 812 const register_t *args = (const void *)&call[1]; 813 int flags; 814 815 if (call->ktr_argsize < 2) 816 return NULL; 817 flags = (int)args[1]; 818 819 if ((flags & O_RDWR) == O_RDWR) 820 return syscall_enter(key, call, 1, &show_open_readwrite); 821 else if ((flags & O_WRONLY) == O_WRONLY) 822 return syscall_enter(key, call, 1, &show_open_write); 823 else if ((flags & O_RDONLY) == O_RDONLY) 824 return syscall_enter(key, call, 1, &show_open_read); 825 else 826 return NULL; /* XXX Do we care if no read or write? */ 827 } 828 829 /*ARGSUSED*/ 830 static struct filemon_state * 831 filemon_sys_openat(struct filemon *F, const struct filemon_key *key, 832 const struct ktr_syscall *call) 833 { 834 const register_t *args = (const void *)&call[1]; 835 int flags, fd; 836 837 /* 838 * XXX: In the .meta log, the base directory is missing, which makes 839 * all references to relative pathnames useless. 840 */ 841 842 if (call->ktr_argsize < 3) 843 return NULL; 844 fd = (int)args[0]; 845 flags = (int)args[2]; 846 847 if (fd == AT_CWD) { 848 if ((flags & O_RDWR) == O_RDWR) 849 return syscall_enter(key, call, 1, 850 &show_open_readwrite); 851 else if ((flags & O_WRONLY) == O_WRONLY) 852 return syscall_enter(key, call, 1, &show_open_write); 853 else if ((flags & O_RDONLY) == O_RDONLY) 854 return syscall_enter(key, call, 1, &show_open_read); 855 else 856 return NULL; 857 } else { 858 if ((flags & O_RDWR) == O_RDWR) 859 return syscall_enter(key, call, 1, 860 &show_openat_readwrite); 861 else if ((flags & O_WRONLY) == O_WRONLY) 862 return syscall_enter(key, call, 1, &show_openat_write); 863 else if ((flags & O_RDONLY) == O_RDONLY) 864 return syscall_enter(key, call, 1, &show_openat_read); 865 else 866 return NULL; 867 } 868 } 869 870 /* TODO: monitor the other *at syscalls as well, not only openat. */ 871 872 /*ARGSUSED*/ 873 static struct filemon_state * 874 filemon_sys_symlink(struct filemon *F, const struct filemon_key *key, 875 const struct ktr_syscall *call) 876 { 877 return syscall_enter(key, call, 2, &show_symlink); 878 } 879 880 /*ARGSUSED*/ 881 static struct filemon_state * 882 filemon_sys_unlink(struct filemon *F, const struct filemon_key *key, 883 const struct ktr_syscall *call) 884 { 885 return syscall_enter(key, call, 1, &show_unlink); 886 } 887 888 /*ARGSUSED*/ 889 static struct filemon_state * 890 filemon_sys_rename(struct filemon *F, const struct filemon_key *key, 891 const struct ktr_syscall *call) 892 { 893 return syscall_enter(key, call, 2, &show_rename); 894 } 895