filemon_ktrace.c revision 1.8 1 /* $NetBSD: filemon_ktrace.c,v 1.8 2020/11/29 09:27:40 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 static int
134 compare_filemon_states(void *cookie, const void *na, const void *nb)
135 {
136 const struct filemon_state *Sa = na;
137 const struct filemon_state *Sb = nb;
138
139 if (Sa->key.pid < Sb->key.pid)
140 return -1;
141 if (Sa->key.pid > Sb->key.pid)
142 return +1;
143 if (Sa->key.lid < Sb->key.lid)
144 return -1;
145 if (Sa->key.lid > Sb->key.lid)
146 return +1;
147 return 0;
148 }
149
150 static int
151 compare_filemon_key(void *cookie, const void *n, const void *k)
152 {
153 const struct filemon_state *S = n;
154 const struct filemon_key *key = k;
155
156 if (S->key.pid < key->pid)
157 return -1;
158 if (S->key.pid > key->pid)
159 return +1;
160 if (S->key.lid < key->lid)
161 return -1;
162 if (S->key.lid > key->lid)
163 return +1;
164 return 0;
165 }
166
167 static const rb_tree_ops_t filemon_rb_ops = {
168 .rbto_compare_nodes = &compare_filemon_states,
169 .rbto_compare_key = &compare_filemon_key,
170 .rbto_node_offset = offsetof(struct filemon_state, node),
171 .rbto_context = NULL,
172 };
173
174 /*
175 * filemon_path()
176 *
177 * Return a pointer to a constant string denoting the `path' of
178 * the filemon.
179 */
180 const char *
181 filemon_path(void)
182 {
183
184 return "ktrace";
185 }
186
187 /*
188 * filemon_open()
189 *
190 * Allocate a filemon descriptor. Returns NULL and sets errno on
191 * failure.
192 */
193 struct filemon *
194 filemon_open(void)
195 {
196 struct filemon *F;
197 int ktrpipe[2];
198 int error;
199
200 /* Allocate and zero a struct filemon object. */
201 F = calloc(1, sizeof *F);
202 if (F == NULL)
203 return NULL;
204
205 /* Create a pipe for ktrace events. */
206 if (pipe2(ktrpipe, O_CLOEXEC|O_NONBLOCK) == -1) {
207 error = errno;
208 goto fail0;
209 }
210
211 /* Create a file stream for reading the ktrace events. */
212 if ((F->in = fdopen(ktrpipe[0], "r")) == NULL) {
213 error = errno;
214 goto fail1;
215 }
216 ktrpipe[0] = -1; /* claimed by fdopen */
217
218 /*
219 * Set the fd for writing ktrace events and initialize the
220 * rbtree. The rest can be safely initialized to zero.
221 */
222 F->ktrfd = ktrpipe[1];
223 rb_tree_init(&F->active, &filemon_rb_ops);
224
225 /* Success! */
226 return F;
227
228 (void)fclose(F->in);
229 fail1: (void)close(ktrpipe[0]);
230 (void)close(ktrpipe[1]);
231 fail0: free(F);
232 errno = error;
233 return NULL;
234 }
235
236 /*
237 * filemon_closefd(F)
238 *
239 * Internal subroutine to try to flush and close the output file.
240 * If F is not open for output, do nothing. Never leaves F open
241 * for output even on failure. Returns 0 on success; sets errno
242 * and return -1 on failure.
243 */
244 static int
245 filemon_closefd(struct filemon *F)
246 {
247 int error = 0;
248
249 /* If we're not open, nothing to do. */
250 if (F->out == NULL)
251 return 0;
252
253 /*
254 * Flush it, close it, and null it unconditionally, but be
255 * careful to return the earliest error in errno.
256 */
257 if (fflush(F->out) == EOF && error == 0)
258 error = errno;
259 if (fclose(F->out) == EOF && error == 0)
260 error = errno;
261 F->out = NULL;
262
263 /* Set errno and return -1 if anything went wrong. */
264 if (error != 0) {
265 errno = error;
266 return -1;
267 }
268
269 /* Success! */
270 return 0;
271 }
272
273 /*
274 * filemon_setfd(F, fd)
275 *
276 * Cause filemon activity on F to be sent to fd. Claims ownership
277 * of fd; caller should not use fd afterward, and any duplicates
278 * of fd may see their file positions changed.
279 */
280 int
281 filemon_setfd(struct filemon *F, int fd)
282 {
283
284 /*
285 * Close an existing output file if done. Fail now if there's
286 * an error closing.
287 */
288 if ((filemon_closefd(F)) == -1)
289 return -1;
290 assert(F->out == NULL);
291
292 /* Open a file stream and claim ownership of the fd. */
293 if ((F->out = fdopen(fd, "a")) == NULL)
294 return -1;
295
296 /*
297 * Print the opening output. Any failure will be deferred
298 * until closing. For hysterical raisins, we show the parent
299 * pid, not the child pid.
300 */
301 fprintf(F->out, "# filemon version 4\n");
302 fprintf(F->out, "# Target pid %jd\n", (intmax_t)getpid());
303 fprintf(F->out, "V 4\n");
304
305 /* Success! */
306 return 0;
307 }
308
309 /*
310 * filemon_setpid_parent(F, pid)
311 *
312 * Set the traced pid, from the parent. Never fails.
313 */
314 void
315 filemon_setpid_parent(struct filemon *F, pid_t pid)
316 {
317
318 F->child = pid;
319 }
320
321 /*
322 * filemon_setpid_child(F, pid)
323 *
324 * Set the traced pid, from the child. Returns 0 on success; sets
325 * errno and returns -1 on failure.
326 */
327 int
328 filemon_setpid_child(const struct filemon *F, pid_t pid)
329 {
330 int ops, trpoints;
331
332 ops = KTROP_SET|KTRFLAG_DESCEND;
333 trpoints = KTRFACv2;
334 trpoints |= KTRFAC_SYSCALL|KTRFAC_NAMEI|KTRFAC_SYSRET;
335 trpoints |= KTRFAC_INHERIT;
336 if (fktrace(F->ktrfd, ops, trpoints, pid) == -1)
337 return -1;
338
339 return 0;
340 }
341
342 /*
343 * filemon_close(F)
344 *
345 * Close F for output if necessary, and free a filemon descriptor.
346 * Returns 0 on success; sets errno and returns -1 on failure, but
347 * frees the filemon descriptor either way;
348 */
349 int
350 filemon_close(struct filemon *F)
351 {
352 struct filemon_state *S;
353 int error = 0;
354
355 /* Close for output. */
356 if (filemon_closefd(F) == -1 && error == 0)
357 error = errno;
358
359 /* Close the ktrace pipe. */
360 if (fclose(F->in) == EOF && error == 0)
361 error = errno;
362 if (close(F->ktrfd) == -1 && error == 0)
363 error = errno;
364
365 /* Free any active records. */
366 while ((S = RB_TREE_MIN(&F->active)) != NULL) {
367 rb_tree_remove_node(&F->active, S);
368 free(S);
369 }
370
371 /* Free the filemon descriptor. */
372 free(F);
373
374 /* Set errno and return -1 if anything went wrong. */
375 if (error != 0) {
376 errno = error;
377 return -1;
378 }
379
380 /* Success! */
381 return 0;
382 }
383
384 /*
385 * filemon_readfd(F)
386 *
387 * Returns a file descriptor which will select/poll ready for read
388 * when there are filemon events to be processed by
389 * filemon_process, or -1 if anything has gone wrong.
390 */
391 int
392 filemon_readfd(const struct filemon *F)
393 {
394
395 if (F->state == FILEMON_ERROR)
396 return -1;
397 return fileno(F->in);
398 }
399
400 /*
401 * filemon_dispatch(F)
402 *
403 * Internal subroutine to dispatch a filemon ktrace event.
404 * Silently ignore events that we don't recognize.
405 */
406 static void
407 filemon_dispatch(struct filemon *F)
408 {
409 const struct filemon_key key = {
410 .pid = F->hdr.ktr_pid,
411 .lid = F->hdr.ktr_lid,
412 };
413 struct filemon_state *S;
414
415 switch (F->hdr.ktr_type) {
416 case KTR_SYSCALL: {
417 struct ktr_syscall *call = &F->payload.syscall;
418 struct filemon_state *S1;
419
420 /* Validate the syscall code. */
421 if (call->ktr_code < 0 ||
422 (size_t)call->ktr_code >= __arraycount(filemon_syscalls) ||
423 filemon_syscalls[call->ktr_code] == NULL)
424 break;
425
426 /*
427 * Invoke the syscall-specific logic to create a new
428 * active state.
429 */
430 S = (*filemon_syscalls[call->ktr_code])(F, &key, call);
431 if (S == NULL)
432 break;
433
434 /*
435 * Insert the active state, or ignore it if there
436 * already is one.
437 *
438 * Collisions shouldn't happen because the states are
439 * keyed by <pid,lid>, in which syscalls should happen
440 * sequentially in CALL/RET pairs, but let's be
441 * defensive.
442 */
443 S1 = rb_tree_insert_node(&F->active, S);
444 if (S1 != S) {
445 /* XXX Which one to drop? */
446 free(S);
447 break;
448 }
449 break;
450 }
451 case KTR_NAMEI:
452 /* Find an active syscall state, or drop it. */
453 S = rb_tree_find_node(&F->active, &key);
454 if (S == NULL)
455 break;
456 /* Find the position of the next path, or drop it. */
457 if (S->i >= S->npath)
458 break;
459 /* Record the path. */
460 S->path[S->i++] = strndup(F->payload.namei,
461 sizeof F->payload.namei);
462 break;
463 case KTR_SYSRET: {
464 struct ktr_sysret *ret = &F->payload.sysret;
465 unsigned i;
466
467 /* Find and remove an active syscall state, or drop it. */
468 S = rb_tree_find_node(&F->active, &key);
469 if (S == NULL)
470 break;
471 rb_tree_remove_node(&F->active, S);
472
473 /*
474 * If the active syscall state matches this return,
475 * invoke the syscall-specific logic to show a filemon
476 * event.
477 */
478 /* XXX What to do if syscall code doesn't match? */
479 if (S->i == S->npath && S->syscode == ret->ktr_code)
480 S->show(F, S, ret);
481
482 /* Free the state now that it is no longer active. */
483 for (i = 0; i < S->i; i++)
484 free(S->path[i]);
485 free(S);
486 break;
487 }
488 default:
489 /* Ignore all other ktrace events. */
490 break;
491 }
492 }
493
494 /*
495 * filemon_process(F)
496 *
497 * Process all pending events after filemon_readfd(F) has
498 * selected/polled ready for read.
499 *
500 * Returns -1 on failure, 0 on end of events, and anything else if
501 * there may be more events.
502 *
503 * XXX What about fairness to other activities in the event loop?
504 * If we stop while there's events buffered in F->in, then select
505 * or poll may not return ready even though there's work queued up
506 * in the buffer of F->in, but if we don't stop then ktrace events
507 * may overwhelm all other activity in the event loop.
508 */
509 int
510 filemon_process(struct filemon *F)
511 {
512 size_t nread;
513
514 top: /* If the child has exited, nothing to do. */
515 /* XXX What if one thread calls exit while another is running? */
516 if (F->child == 0)
517 return 0;
518
519 /* If we're waiting for input, read some. */
520 if (F->resid) {
521 nread = fread(F->p, 1, F->resid, F->in);
522 if (nread == 0) {
523 if (feof(F->in))
524 return 0;
525 assert(ferror(F->in));
526 /*
527 * If interrupted or would block, there may be
528 * more events. Otherwise fail.
529 */
530 if (errno == EAGAIN || errno == EINTR)
531 return 1;
532 F->state = FILEMON_ERROR;
533 F->p = NULL;
534 F->resid = 0;
535 return -1;
536 }
537 assert(nread <= F->resid);
538 F->p += nread;
539 F->resid -= nread;
540 if (F->resid) /* may be more events */
541 return 1;
542 }
543
544 /* Process a state transition now that we've read a buffer. */
545 switch (F->state) {
546 case FILEMON_START: /* just started filemon; read header next */
547 F->state = FILEMON_HEADER;
548 F->p = (void *)&F->hdr;
549 F->resid = sizeof F->hdr;
550 goto top;
551 case FILEMON_HEADER: /* read header */
552 /* Sanity-check ktrace header; then read payload. */
553 if (F->hdr.ktr_len < 0 ||
554 (size_t)F->hdr.ktr_len > sizeof F->payload) {
555 F->state = FILEMON_ERROR;
556 F->p = NULL;
557 F->resid = 0;
558 errno = EIO;
559 return -1;
560 }
561 F->state = FILEMON_PAYLOAD;
562 F->p = (void *)&F->payload;
563 F->resid = (size_t)F->hdr.ktr_len;
564 goto top;
565 case FILEMON_PAYLOAD: /* read header and payload */
566 /* Dispatch ktrace event; then read next header. */
567 filemon_dispatch(F);
568 F->state = FILEMON_HEADER;
569 F->p = (void *)&F->hdr;
570 F->resid = sizeof F->hdr;
571 goto top;
572 default: /* paranoia */
573 F->state = FILEMON_ERROR;
574 /*FALLTHROUGH*/
575 case FILEMON_ERROR: /* persistent error indicator */
576 F->p = NULL;
577 F->resid = 0;
578 errno = EIO;
579 return -1;
580 }
581 }
582
583 static struct filemon_state *
584 syscall_enter(struct filemon *F,
585 const struct filemon_key *key, const struct ktr_syscall *call,
586 unsigned npath,
587 void (*show)(struct filemon *, const struct filemon_state *,
588 const struct ktr_sysret *))
589 {
590 struct filemon_state *S;
591 unsigned i;
592
593 S = calloc(1, offsetof(struct filemon_state, path[npath]));
594 if (S == NULL)
595 return NULL;
596 S->key = *key;
597 S->show = show;
598 S->syscode = call->ktr_code;
599 S->i = 0;
600 S->npath = npath;
601 for (i = 0; i < npath; i++)
602 S->path[i] = NULL; /* paranoia */
603
604 return S;
605 }
606
607 static void
608 show_paths(struct filemon *F, const struct filemon_state *S,
609 const struct ktr_sysret *ret, const char *prefix)
610 {
611 unsigned i;
612
613 /* Caller must ensure all paths have been specified. */
614 assert(S->i == S->npath);
615
616 /*
617 * Ignore it if it failed or yielded EJUSTRETURN (-2), or if
618 * we're not producing output.
619 */
620 if (ret->ktr_error && ret->ktr_error != -2)
621 return;
622 if (F->out == NULL)
623 return;
624
625 /*
626 * Print the prefix, pid, and paths -- with the paths quoted if
627 * there's more than one.
628 */
629 fprintf(F->out, "%s %jd", prefix, (intmax_t)S->key.pid);
630 for (i = 0; i < S->npath; i++) {
631 const char *q = S->npath > 1 ? "'" : "";
632 fprintf(F->out, " %s%s%s", q, S->path[i], q);
633 }
634 fprintf(F->out, "\n");
635 }
636
637 static void
638 show_retval(struct filemon *F, const struct filemon_state *S,
639 const struct ktr_sysret *ret, const char *prefix)
640 {
641
642 /*
643 * Ignore it if it failed or yielded EJUSTRETURN (-2), or if
644 * we're not producing output.
645 */
646 if (ret->ktr_error && ret->ktr_error != -2)
647 return;
648 if (F->out == NULL)
649 return;
650
651 fprintf(F->out, "%s %jd %jd\n", prefix, (intmax_t)S->key.pid,
652 (intmax_t)ret->ktr_retval);
653 }
654
655 static void
656 show_chdir(struct filemon *F, const struct filemon_state *S,
657 const struct ktr_sysret *ret)
658 {
659 show_paths(F, S, ret, "C");
660 }
661
662 static void
663 show_execve(struct filemon *F, const struct filemon_state *S,
664 const struct ktr_sysret *ret)
665 {
666 return show_paths(F, S, ret, "E");
667 }
668
669 static void
670 show_fork(struct filemon *F, const struct filemon_state *S,
671 const struct ktr_sysret *ret)
672 {
673 show_retval(F, S, ret, "F");
674 }
675
676 static void
677 show_link(struct filemon *F, const struct filemon_state *S,
678 const struct ktr_sysret *ret)
679 {
680 show_paths(F, S, ret, "L"); /* XXX same as symlink */
681 }
682
683 static void
684 show_open_read(struct filemon *F, const struct filemon_state *S,
685 const struct ktr_sysret *ret)
686 {
687 show_paths(F, S, ret, "R");
688 }
689
690 static void
691 show_open_write(struct filemon *F, const struct filemon_state *S,
692 const struct ktr_sysret *ret)
693 {
694 show_paths(F, S, ret, "W");
695 }
696
697 static void
698 show_open_readwrite(struct filemon *F, const struct filemon_state *S,
699 const struct ktr_sysret *ret)
700 {
701 show_paths(F, S, ret, "R");
702 show_paths(F, S, ret, "W");
703 }
704
705 static void
706 show_openat_read(struct filemon *F, const struct filemon_state *S,
707 const struct ktr_sysret *ret)
708 {
709 if (S->path[0][0] != '/')
710 show_paths(F, S, ret, "A");
711 show_paths(F, S, ret, "R");
712 }
713
714 static void
715 show_openat_write(struct filemon *F, const struct filemon_state *S,
716 const struct ktr_sysret *ret)
717 {
718 if (S->path[0][0] != '/')
719 show_paths(F, S, ret, "A");
720 show_paths(F, S, ret, "W");
721 }
722
723 static void
724 show_openat_readwrite(struct filemon *F, const struct filemon_state *S,
725 const struct ktr_sysret *ret)
726 {
727 if (S->path[0][0] != '/')
728 show_paths(F, S, ret, "A");
729 show_paths(F, S, ret, "R");
730 show_paths(F, S, ret, "W");
731 }
732
733 static void
734 show_symlink(struct filemon *F, const struct filemon_state *S,
735 const struct ktr_sysret *ret)
736 {
737 show_paths(F, S, ret, "L"); /* XXX same as link */
738 }
739
740 static void
741 show_unlink(struct filemon *F, const struct filemon_state *S,
742 const struct ktr_sysret *ret)
743 {
744 show_paths(F, S, ret, "D");
745 }
746
747 static void
748 show_rename(struct filemon *F, const struct filemon_state *S,
749 const struct ktr_sysret *ret)
750 {
751 show_paths(F, S, ret, "M");
752 }
753
754 static struct filemon_state *
755 filemon_sys_chdir(struct filemon *F, const struct filemon_key *key,
756 const struct ktr_syscall *call)
757 {
758 return syscall_enter(F, key, call, 1, &show_chdir);
759 }
760
761 static struct filemon_state *
762 filemon_sys_execve(struct filemon *F, const struct filemon_key *key,
763 const struct ktr_syscall *call)
764 {
765 return syscall_enter(F, key, call, 1, &show_execve);
766 }
767
768 static struct filemon_state *
769 filemon_sys_exit(struct filemon *F, const struct filemon_key *key,
770 const struct ktr_syscall *call)
771 {
772 const register_t *args = (const void *)&call[1];
773 int status = (int)args[0];
774
775 if (F->out) {
776 fprintf(F->out, "X %jd %d\n", (intmax_t)key->pid, status);
777 if (key->pid == F->child) {
778 fprintf(F->out, "# Bye bye\n");
779 F->child = 0;
780 }
781 }
782 return NULL;
783 }
784
785 static struct filemon_state *
786 filemon_sys_fork(struct filemon *F, const struct filemon_key *key,
787 const struct ktr_syscall *call)
788 {
789 return syscall_enter(F, key, call, 0, &show_fork);
790 }
791
792 static struct filemon_state *
793 filemon_sys_link(struct filemon *F, const struct filemon_key *key,
794 const struct ktr_syscall *call)
795 {
796 return syscall_enter(F, key, call, 2, &show_link);
797 }
798
799 static struct filemon_state *
800 filemon_sys_open(struct filemon *F, const struct filemon_key *key,
801 const struct ktr_syscall *call)
802 {
803 const register_t *args = (const void *)&call[1];
804 int flags;
805
806 if (call->ktr_argsize < 2)
807 return NULL;
808 flags = (int)args[1];
809
810 if ((flags & O_RDWR) == O_RDWR)
811 return syscall_enter(F, key, call, 1, &show_open_readwrite);
812 else if ((flags & O_WRONLY) == O_WRONLY)
813 return syscall_enter(F, key, call, 1, &show_open_write);
814 else if ((flags & O_RDONLY) == O_RDONLY)
815 return syscall_enter(F, key, call, 1, &show_open_read);
816 else
817 return NULL; /* XXX Do we care if no read or write? */
818 }
819
820 static struct filemon_state *
821 filemon_sys_openat(struct filemon *F, const struct filemon_key *key,
822 const struct ktr_syscall *call)
823 {
824 const register_t *args = (const void *)&call[1];
825 int flags, fd;
826
827 if (call->ktr_argsize < 3)
828 return NULL;
829 fd = (int)args[0];
830 flags = (int)args[2];
831
832 if (fd == AT_CWD) {
833 if ((flags & O_RDWR) == O_RDWR)
834 return syscall_enter(F, key, call, 1,
835 &show_open_readwrite);
836 else if ((flags & O_WRONLY) == O_WRONLY)
837 return syscall_enter(F, key, call, 1,
838 &show_open_write);
839 else if ((flags & O_RDONLY) == O_RDONLY)
840 return syscall_enter(F, key, call, 1, &show_open_read);
841 else
842 return NULL;
843 } else {
844 if ((flags & O_RDWR) == O_RDWR)
845 return syscall_enter(F, key, call, 1,
846 &show_openat_readwrite);
847 else if ((flags & O_WRONLY) == O_WRONLY)
848 return syscall_enter(F, key, call, 1,
849 &show_openat_write);
850 else if ((flags & O_RDONLY) == O_RDONLY)
851 return syscall_enter(F, key, call, 1,
852 &show_openat_read);
853 else
854 return NULL;
855 }
856 }
857
858 static struct filemon_state *
859 filemon_sys_symlink(struct filemon *F, const struct filemon_key *key,
860 const struct ktr_syscall *call)
861 {
862 return syscall_enter(F, key, call, 2, &show_symlink);
863 }
864
865 static struct filemon_state *
866 filemon_sys_unlink(struct filemon *F, const struct filemon_key *key,
867 const struct ktr_syscall *call)
868 {
869 return syscall_enter(F, key, call, 1, &show_unlink);
870 }
871
872 static struct filemon_state *
873 filemon_sys_rename(struct filemon *F, const struct filemon_key *key,
874 const struct ktr_syscall *call)
875 {
876 return syscall_enter(F, key, call, 2, &show_rename);
877 }
878