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