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