Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/bmake/filemon/filemon_ktrace.c
39507 views
1
/* $NetBSD: filemon_ktrace.c,v 1.15 2021/07/31 09:30:17 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
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 != 0) {
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 != 0) {
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 > 0) {
522
nread = fread(F->p, 1, F->resid, F->in);
523
if (nread == 0) {
524
if (feof(F->in) != 0)
525
return 0;
526
assert(ferror(F->in) != 0);
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 > 0) /* 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(
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 != 0 && 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 != 0 && 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
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
/*ARGSUSED*/
756
static struct filemon_state *
757
filemon_sys_chdir(struct filemon *F, const struct filemon_key *key,
758
const struct ktr_syscall *call)
759
{
760
return syscall_enter(key, call, 1, &show_chdir);
761
}
762
763
/* TODO: monitor fchdir as well */
764
765
/*ARGSUSED*/
766
static struct filemon_state *
767
filemon_sys_execve(struct filemon *F, const struct filemon_key *key,
768
const struct ktr_syscall *call)
769
{
770
return syscall_enter(key, call, 1, &show_execve);
771
}
772
773
static struct filemon_state *
774
filemon_sys_exit(struct filemon *F, const struct filemon_key *key,
775
const struct ktr_syscall *call)
776
{
777
const register_t *args = (const void *)&call[1];
778
int status = (int)args[0];
779
780
if (F->out != NULL) {
781
fprintf(F->out, "X %jd %d\n", (intmax_t)key->pid, status);
782
if (key->pid == F->child) {
783
fprintf(F->out, "# Bye bye\n");
784
F->child = 0;
785
}
786
}
787
return NULL;
788
}
789
790
/*ARGSUSED*/
791
static struct filemon_state *
792
filemon_sys_fork(struct filemon *F, const struct filemon_key *key,
793
const struct ktr_syscall *call)
794
{
795
return syscall_enter(key, call, 0, &show_fork);
796
}
797
798
/*ARGSUSED*/
799
static struct filemon_state *
800
filemon_sys_link(struct filemon *F, const struct filemon_key *key,
801
const struct ktr_syscall *call)
802
{
803
return syscall_enter(key, call, 2, &show_link);
804
}
805
806
/*ARGSUSED*/
807
static struct filemon_state *
808
filemon_sys_open(struct filemon *F, const struct filemon_key *key,
809
const struct ktr_syscall *call)
810
{
811
const register_t *args = (const void *)&call[1];
812
int flags;
813
814
if (call->ktr_argsize < 2)
815
return NULL;
816
flags = (int)args[1];
817
818
if ((flags & O_RDWR) == O_RDWR)
819
return syscall_enter(key, call, 1, &show_open_readwrite);
820
else if ((flags & O_WRONLY) == O_WRONLY)
821
return syscall_enter(key, call, 1, &show_open_write);
822
else if ((flags & O_RDONLY) == O_RDONLY)
823
return syscall_enter(key, call, 1, &show_open_read);
824
else
825
return NULL; /* XXX Do we care if no read or write? */
826
}
827
828
/*ARGSUSED*/
829
static struct filemon_state *
830
filemon_sys_openat(struct filemon *F, const struct filemon_key *key,
831
const struct ktr_syscall *call)
832
{
833
const register_t *args = (const void *)&call[1];
834
int flags, fd;
835
836
/*
837
* XXX: In the .meta log, the base directory is missing, which makes
838
* all references to relative pathnames useless.
839
*/
840
841
if (call->ktr_argsize < 3)
842
return NULL;
843
fd = (int)args[0];
844
flags = (int)args[2];
845
846
if (fd == AT_CWD) {
847
if ((flags & O_RDWR) == O_RDWR)
848
return syscall_enter(key, call, 1,
849
&show_open_readwrite);
850
else if ((flags & O_WRONLY) == O_WRONLY)
851
return syscall_enter(key, call, 1, &show_open_write);
852
else if ((flags & O_RDONLY) == O_RDONLY)
853
return syscall_enter(key, call, 1, &show_open_read);
854
else
855
return NULL;
856
} else {
857
if ((flags & O_RDWR) == O_RDWR)
858
return syscall_enter(key, call, 1,
859
&show_openat_readwrite);
860
else if ((flags & O_WRONLY) == O_WRONLY)
861
return syscall_enter(key, call, 1, &show_openat_write);
862
else if ((flags & O_RDONLY) == O_RDONLY)
863
return syscall_enter(key, call, 1, &show_openat_read);
864
else
865
return NULL;
866
}
867
}
868
869
/* TODO: monitor the other *at syscalls as well, not only openat. */
870
871
/*ARGSUSED*/
872
static struct filemon_state *
873
filemon_sys_symlink(struct filemon *F, const struct filemon_key *key,
874
const struct ktr_syscall *call)
875
{
876
return syscall_enter(key, call, 2, &show_symlink);
877
}
878
879
/*ARGSUSED*/
880
static struct filemon_state *
881
filemon_sys_unlink(struct filemon *F, const struct filemon_key *key,
882
const struct ktr_syscall *call)
883
{
884
return syscall_enter(key, call, 1, &show_unlink);
885
}
886
887
/*ARGSUSED*/
888
static struct filemon_state *
889
filemon_sys_rename(struct filemon *F, const struct filemon_key *key,
890
const struct ktr_syscall *call)
891
{
892
return syscall_enter(key, call, 2, &show_rename);
893
}
894
895