xref: /freebsd/sys/dev/filemon/filemon_wrapper.c (revision e8e8c939350bdf3c228a411caa9660c607c27a11)
1 /*-
2  * Copyright (c) 2011, David E. O'Brien.
3  * Copyright (c) 2009-2011, Juniper Networks, Inc.
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY JUNIPER NETWORKS AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED. IN NO EVENT SHALL JUNIPER NETWORKS OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27 
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
30 
31 #include <sys/sx.h>
32 
33 #include "opt_compat.h"
34 
35 #if __FreeBSD_version > 800032
36 #define FILEMON_HAS_LINKAT
37 #endif
38 
39 #if __FreeBSD_version < 900044	/* r225617 (2011-09-16) failed to bump
40 				   __FreeBSD_version.  This really should
41 				   be based on "900045".  "900044" is r225469
42 				   (2011-09-10) so this code is broken for
43 				   9-CURRENT September 10th-16th. */
44 #define sys_chdir	chdir
45 #define sys_execve	execve
46 #define sys_fork	fork
47 #define sys_link	link
48 #define sys_open	open
49 #define sys_rename	rename
50 #define sys_stat	stat
51 #define sys_symlink	symlink
52 #define sys_unlink	unlink
53 #define sys_vfork	vfork
54 #define sys_sys_exit	sys_exit
55 #ifdef FILEMON_HAS_LINKAT
56 #define sys_linkat	linkat
57 #endif
58 #endif	/* __FreeBSD_version */
59 
60 static void
61 filemon_output(struct filemon *filemon, char *msg, size_t len)
62 {
63 	struct uio auio;
64 	struct iovec aiov;
65 
66 	if (filemon->fp == NULL)
67 		return;
68 
69 	aiov.iov_base = msg;
70 	aiov.iov_len = len;
71 	auio.uio_iov = &aiov;
72 	auio.uio_iovcnt = 1;
73 	auio.uio_resid = len;
74 	auio.uio_segflg = UIO_SYSSPACE;
75 	auio.uio_rw = UIO_WRITE;
76 	auio.uio_td = curthread;
77 	auio.uio_offset = (off_t) -1;
78 
79 	bwillwrite();
80 
81 	fo_write(filemon->fp, &auio, curthread->td_ucred, 0, curthread);
82 }
83 
84 static struct filemon *
85 filemon_pid_check(struct proc *p)
86 {
87 	struct filemon *filemon;
88 
89 	sx_slock(&proctree_lock);
90 	while (p != initproc) {
91 		TAILQ_FOREACH(filemon, &filemons_inuse, link) {
92 			if (p->p_pid == filemon->pid) {
93 				sx_sunlock(&proctree_lock);
94 				return (filemon);
95 			}
96 		}
97 		p = proc_realparent(p);
98 	}
99 	sx_sunlock(&proctree_lock);
100 	return (NULL);
101 }
102 
103 static void
104 filemon_comment(struct filemon *filemon)
105 {
106 	int len;
107 	struct timeval now;
108 
109 	/* Load timestamp before locking.  Less accurate but less contention. */
110 	getmicrotime(&now);
111 
112 	/* Grab a read lock on the filemon inuse list. */
113 	filemon_lock_read();
114 
115 	/* Lock the found filemon structure. */
116 	filemon_filemon_lock(filemon);
117 
118 	len = snprintf(filemon->msgbufr, sizeof(filemon->msgbufr),
119 	    "# filemon version %d\n# Target pid %d\n# Start %ju.%06ju\nV %d\n",
120 	    FILEMON_VERSION, curproc->p_pid, (uintmax_t)now.tv_sec,
121 	    (uintmax_t)now.tv_usec, FILEMON_VERSION);
122 
123 	filemon_output(filemon, filemon->msgbufr, len);
124 
125 	/* Unlock the found filemon structure. */
126 	filemon_filemon_unlock(filemon);
127 
128 	/* Release the read lock. */
129 	filemon_unlock_read();
130 }
131 
132 static int
133 filemon_wrapper_chdir(struct thread *td, struct chdir_args *uap)
134 {
135 	int ret;
136 	size_t done;
137 	size_t len;
138 	struct filemon *filemon;
139 
140 	if ((ret = sys_chdir(td, uap)) == 0) {
141 		/* Grab a read lock on the filemon inuse list. */
142 		filemon_lock_read();
143 
144 		if ((filemon = filemon_pid_check(curproc)) != NULL) {
145 			/* Lock the found filemon structure. */
146 			filemon_filemon_lock(filemon);
147 
148 			copyinstr(uap->path, filemon->fname1,
149 			    sizeof(filemon->fname1), &done);
150 
151 			len = snprintf(filemon->msgbufr,
152 			    sizeof(filemon->msgbufr), "C %d %s\n",
153 			    curproc->p_pid, filemon->fname1);
154 
155 			filemon_output(filemon, filemon->msgbufr, len);
156 
157 			/* Unlock the found filemon structure. */
158 			filemon_filemon_unlock(filemon);
159 		}
160 
161 		/* Release the read lock. */
162 		filemon_unlock_read();
163 	}
164 
165 	return (ret);
166 }
167 
168 static int
169 filemon_wrapper_execve(struct thread *td, struct execve_args *uap)
170 {
171 	char fname[MAXPATHLEN];
172 	int ret;
173 	size_t done;
174 	size_t len;
175 	struct filemon *filemon;
176 
177 	copyinstr(uap->fname, fname, sizeof(fname), &done);
178 
179 	if ((ret = sys_execve(td, uap)) == 0) {
180 		/* Grab a read lock on the filemon inuse list. */
181 		filemon_lock_read();
182 
183 		if ((filemon = filemon_pid_check(curproc)) != NULL) {
184 			/* Lock the found filemon structure. */
185 			filemon_filemon_lock(filemon);
186 
187 			len = snprintf(filemon->msgbufr,
188 			    sizeof(filemon->msgbufr), "E %d %s\n",
189 			    curproc->p_pid, fname);
190 
191 			filemon_output(filemon, filemon->msgbufr, len);
192 
193 			/* Unlock the found filemon structure. */
194 			filemon_filemon_unlock(filemon);
195 		}
196 
197 		/* Release the read lock. */
198 		filemon_unlock_read();
199 	}
200 
201 	return (ret);
202 }
203 
204 #if defined(COMPAT_IA32) || defined(COMPAT_FREEBSD32) || defined(COMPAT_ARCH32)
205 static int
206 filemon_wrapper_freebsd32_execve(struct thread *td,
207     struct freebsd32_execve_args *uap)
208 {
209 	char fname[MAXPATHLEN];
210 	int ret;
211 	size_t done;
212 	size_t len;
213 	struct filemon *filemon;
214 
215 	copyinstr(uap->fname, fname, sizeof(fname), &done);
216 
217 	if ((ret = freebsd32_execve(td, uap)) == 0) {
218 		/* Grab a read lock on the filemon inuse list. */
219 		filemon_lock_read();
220 
221 		if ((filemon = filemon_pid_check(curproc)) != NULL) {
222 			/* Lock the found filemon structure. */
223 			filemon_filemon_lock(filemon);
224 
225 			len = snprintf(filemon->msgbufr,
226 			    sizeof(filemon->msgbufr), "E %d %s\n",
227 			    curproc->p_pid, fname);
228 
229 			filemon_output(filemon, filemon->msgbufr, len);
230 
231 			/* Unlock the found filemon structure. */
232 			filemon_filemon_unlock(filemon);
233 		}
234 
235 		/* Release the read lock. */
236 		filemon_unlock_read();
237 	}
238 
239 	return (ret);
240 }
241 #endif
242 
243 static int
244 filemon_wrapper_fork(struct thread *td, struct fork_args *uap)
245 {
246 	int ret;
247 	size_t len;
248 	struct filemon *filemon;
249 
250 	if ((ret = sys_fork(td, uap)) == 0) {
251 		/* Grab a read lock on the filemon inuse list. */
252 		filemon_lock_read();
253 
254 		if ((filemon = filemon_pid_check(curproc)) != NULL) {
255 			/* Lock the found filemon structure. */
256 			filemon_filemon_lock(filemon);
257 
258 			len = snprintf(filemon->msgbufr,
259 			    sizeof(filemon->msgbufr), "F %d %ld\n",
260 			    curproc->p_pid, (long)curthread->td_retval[0]);
261 
262 			filemon_output(filemon, filemon->msgbufr, len);
263 
264 			/* Unlock the found filemon structure. */
265 			filemon_filemon_unlock(filemon);
266 		}
267 
268 		/* Release the read lock. */
269 		filemon_unlock_read();
270 	}
271 
272 	return (ret);
273 }
274 
275 static int
276 filemon_wrapper_open(struct thread *td, struct open_args *uap)
277 {
278 	int ret;
279 	size_t done;
280 	size_t len;
281 	struct filemon *filemon;
282 
283 	if ((ret = sys_open(td, uap)) == 0) {
284 		/* Grab a read lock on the filemon inuse list. */
285 		filemon_lock_read();
286 
287 		if ((filemon = filemon_pid_check(curproc)) != NULL) {
288 			/* Lock the found filemon structure. */
289 			filemon_filemon_lock(filemon);
290 
291 			copyinstr(uap->path, filemon->fname1,
292 			    sizeof(filemon->fname1), &done);
293 
294 			if (uap->flags & O_RDWR) {
295 				/*
296 				 * We'll get the W record below, but need
297 				 * to also output an R to distingish from
298 				 * O_WRONLY.
299 				 */
300 				len = snprintf(filemon->msgbufr,
301 				    sizeof(filemon->msgbufr), "R %d %s\n",
302 				    curproc->p_pid, filemon->fname1);
303 				filemon_output(filemon, filemon->msgbufr, len);
304 			}
305 
306 
307 			len = snprintf(filemon->msgbufr,
308 			    sizeof(filemon->msgbufr), "%c %d %s\n",
309 			    (uap->flags & O_ACCMODE) ? 'W':'R',
310 			    curproc->p_pid, filemon->fname1);
311 			filemon_output(filemon, filemon->msgbufr, len);
312 
313 			/* Unlock the found filemon structure. */
314 			filemon_filemon_unlock(filemon);
315 		}
316 
317 		/* Release the read lock. */
318 		filemon_unlock_read();
319 	}
320 
321 	return (ret);
322 }
323 
324 static int
325 filemon_wrapper_openat(struct thread *td, struct openat_args *uap)
326 {
327 	int ret;
328 	size_t done;
329 	size_t len;
330 	struct filemon *filemon;
331 
332 	if ((ret = sys_openat(td, uap)) == 0) {
333 		/* Grab a read lock on the filemon inuse list. */
334 		filemon_lock_read();
335 
336 		if ((filemon = filemon_pid_check(curproc)) != NULL) {
337 			/* Lock the found filemon structure. */
338 			filemon_filemon_lock(filemon);
339 
340 			copyinstr(uap->path, filemon->fname1,
341 			    sizeof(filemon->fname1), &done);
342 
343 			filemon->fname2[0] = '\0';
344 			if (filemon->fname1[0] != '/' && uap->fd != AT_FDCWD) {
345 				/*
346 				 * rats - we cannot do too much about this.
347 				 * the trace should show a dir we read
348 				 * recently.. output an A record as a clue
349 				 * until we can do better.
350 				 */
351 				len = snprintf(filemon->msgbufr,
352 				    sizeof(filemon->msgbufr), "A %d %s\n",
353 				    curproc->p_pid, filemon->fname1);
354 				filemon_output(filemon, filemon->msgbufr, len);
355 			}
356 			if (uap->flag & O_RDWR) {
357 				/*
358 				 * We'll get the W record below, but need
359 				 * to also output an R to distingish from
360 				 * O_WRONLY.
361 				 */
362 				len = snprintf(filemon->msgbufr,
363 				    sizeof(filemon->msgbufr), "R %d %s%s\n",
364 				    curproc->p_pid, filemon->fname2, filemon->fname1);
365 				filemon_output(filemon, filemon->msgbufr, len);
366 			}
367 
368 
369 			len = snprintf(filemon->msgbufr,
370 			    sizeof(filemon->msgbufr), "%c %d %s%s\n",
371 			    (uap->flag & O_ACCMODE) ? 'W':'R',
372 			    curproc->p_pid, filemon->fname2, filemon->fname1);
373 			filemon_output(filemon, filemon->msgbufr, len);
374 
375 			/* Unlock the found filemon structure. */
376 			filemon_filemon_unlock(filemon);
377 		}
378 
379 		/* Release the read lock. */
380 		filemon_unlock_read();
381 	}
382 
383 	return (ret);
384 }
385 
386 static int
387 filemon_wrapper_rename(struct thread *td, struct rename_args *uap)
388 {
389 	int ret;
390 	size_t done;
391 	size_t len;
392 	struct filemon *filemon;
393 
394 	if ((ret = sys_rename(td, uap)) == 0) {
395 		/* Grab a read lock on the filemon inuse list. */
396 		filemon_lock_read();
397 
398 		if ((filemon = filemon_pid_check(curproc)) != NULL) {
399 			/* Lock the found filemon structure. */
400 			filemon_filemon_lock(filemon);
401 
402 			copyinstr(uap->from, filemon->fname1,
403 			    sizeof(filemon->fname1), &done);
404 			copyinstr(uap->to, filemon->fname2,
405 			    sizeof(filemon->fname2), &done);
406 
407 			len = snprintf(filemon->msgbufr,
408 			    sizeof(filemon->msgbufr), "M %d '%s' '%s'\n",
409 			    curproc->p_pid, filemon->fname1, filemon->fname2);
410 
411 			filemon_output(filemon, filemon->msgbufr, len);
412 
413 			/* Unlock the found filemon structure. */
414 			filemon_filemon_unlock(filemon);
415 		}
416 
417 		/* Release the read lock. */
418 		filemon_unlock_read();
419 	}
420 
421 	return (ret);
422 }
423 
424 static int
425 filemon_wrapper_link(struct thread *td, struct link_args *uap)
426 {
427 	int ret;
428 	size_t done;
429 	size_t len;
430 	struct filemon *filemon;
431 
432 	if ((ret = sys_link(td, uap)) == 0) {
433 		/* Grab a read lock on the filemon inuse list. */
434 		filemon_lock_read();
435 
436 		if ((filemon = filemon_pid_check(curproc)) != NULL) {
437 			/* Lock the found filemon structure. */
438 			filemon_filemon_lock(filemon);
439 
440 			copyinstr(uap->path, filemon->fname1,
441 			    sizeof(filemon->fname1), &done);
442 			copyinstr(uap->link, filemon->fname2,
443 			    sizeof(filemon->fname2), &done);
444 
445 			len = snprintf(filemon->msgbufr,
446 			    sizeof(filemon->msgbufr), "L %d '%s' '%s'\n",
447 			    curproc->p_pid, filemon->fname1, filemon->fname2);
448 
449 			filemon_output(filemon, filemon->msgbufr, len);
450 
451 			/* Unlock the found filemon structure. */
452 			filemon_filemon_unlock(filemon);
453 		}
454 
455 		/* Release the read lock. */
456 		filemon_unlock_read();
457 	}
458 
459 	return (ret);
460 }
461 
462 static int
463 filemon_wrapper_symlink(struct thread *td, struct symlink_args *uap)
464 {
465 	int ret;
466 	size_t done;
467 	size_t len;
468 	struct filemon *filemon;
469 
470 	if ((ret = sys_symlink(td, uap)) == 0) {
471 		/* Grab a read lock on the filemon inuse list. */
472 		filemon_lock_read();
473 
474 		if ((filemon = filemon_pid_check(curproc)) != NULL) {
475 			/* Lock the found filemon structure. */
476 			filemon_filemon_lock(filemon);
477 
478 			copyinstr(uap->path, filemon->fname1,
479 			    sizeof(filemon->fname1), &done);
480 			copyinstr(uap->link, filemon->fname2,
481 			    sizeof(filemon->fname2), &done);
482 
483 			len = snprintf(filemon->msgbufr,
484 			    sizeof(filemon->msgbufr), "L %d '%s' '%s'\n",
485 			    curproc->p_pid, filemon->fname1, filemon->fname2);
486 
487 			filemon_output(filemon, filemon->msgbufr, len);
488 
489 			/* Unlock the found filemon structure. */
490 			filemon_filemon_unlock(filemon);
491 		}
492 
493 		/* Release the read lock. */
494 		filemon_unlock_read();
495 	}
496 
497 	return (ret);
498 }
499 
500 #ifdef FILEMON_HAS_LINKAT
501 static int
502 filemon_wrapper_linkat(struct thread *td, struct linkat_args *uap)
503 {
504 	int ret;
505 	size_t done;
506 	size_t len;
507 	struct filemon *filemon;
508 
509 	if ((ret = sys_linkat(td, uap)) == 0) {
510 		/* Grab a read lock on the filemon inuse list. */
511 		filemon_lock_read();
512 
513 		if ((filemon = filemon_pid_check(curproc)) != NULL) {
514 			/* Lock the found filemon structure. */
515 			filemon_filemon_lock(filemon);
516 
517 			copyinstr(uap->path1, filemon->fname1,
518 			    sizeof(filemon->fname1), &done);
519 			copyinstr(uap->path2, filemon->fname2,
520 			    sizeof(filemon->fname2), &done);
521 
522 			len = snprintf(filemon->msgbufr,
523 			    sizeof(filemon->msgbufr), "L %d '%s' '%s'\n",
524 			    curproc->p_pid, filemon->fname1, filemon->fname2);
525 
526 			filemon_output(filemon, filemon->msgbufr, len);
527 
528 			/* Unlock the found filemon structure. */
529 			filemon_filemon_unlock(filemon);
530 		}
531 
532 		/* Release the read lock. */
533 		filemon_unlock_read();
534 	}
535 
536 	return (ret);
537 }
538 #endif
539 
540 static int
541 filemon_wrapper_stat(struct thread *td, struct stat_args *uap)
542 {
543 	int ret;
544 	size_t done;
545 	size_t len;
546 	struct filemon *filemon;
547 
548 	if ((ret = sys_stat(td, uap)) == 0) {
549 		/* Grab a read lock on the filemon inuse list. */
550 		filemon_lock_read();
551 
552 		if ((filemon = filemon_pid_check(curproc)) != NULL) {
553 			/* Lock the found filemon structure. */
554 			filemon_filemon_lock(filemon);
555 
556 			copyinstr(uap->path, filemon->fname1,
557 			    sizeof(filemon->fname1), &done);
558 
559 			len = snprintf(filemon->msgbufr,
560 			    sizeof(filemon->msgbufr), "S %d %s\n",
561 			    curproc->p_pid, filemon->fname1);
562 
563 			filemon_output(filemon, filemon->msgbufr, len);
564 
565 			/* Unlock the found filemon structure. */
566 			filemon_filemon_unlock(filemon);
567 		}
568 
569 		/* Release the read lock. */
570 		filemon_unlock_read();
571 	}
572 
573 	return (ret);
574 }
575 
576 #if defined(COMPAT_IA32) || defined(COMPAT_FREEBSD32) || defined(COMPAT_ARCH32)
577 static int
578 filemon_wrapper_freebsd32_stat(struct thread *td,
579     struct freebsd32_stat_args *uap)
580 {
581 	int ret;
582 	size_t done;
583 	size_t len;
584 	struct filemon *filemon;
585 
586 	if ((ret = freebsd32_stat(td, uap)) == 0) {
587 		/* Grab a read lock on the filemon inuse list. */
588 		filemon_lock_read();
589 
590 		if ((filemon = filemon_pid_check(curproc)) != NULL) {
591 			/* Lock the found filemon structure. */
592 			filemon_filemon_lock(filemon);
593 
594 			copyinstr(uap->path, filemon->fname1,
595 			    sizeof(filemon->fname1), &done);
596 
597 			len = snprintf(filemon->msgbufr,
598 			    sizeof(filemon->msgbufr), "S %d %s\n",
599 			    curproc->p_pid, filemon->fname1);
600 
601 			filemon_output(filemon, filemon->msgbufr, len);
602 
603 			/* Unlock the found filemon structure. */
604 			filemon_filemon_unlock(filemon);
605 		}
606 
607 		/* Release the read lock. */
608 		filemon_unlock_read();
609 	}
610 
611 	return (ret);
612 }
613 #endif
614 
615 static void
616 filemon_wrapper_sys_exit(struct thread *td, struct sys_exit_args *uap)
617 {
618 	size_t len;
619 	struct filemon *filemon;
620 	struct timeval now;
621 
622 	/* Get timestamp before locking. */
623 	getmicrotime(&now);
624 
625 	/* Grab a read lock on the filemon inuse list. */
626 	filemon_lock_read();
627 
628 	if ((filemon = filemon_pid_check(curproc)) != NULL) {
629 		/* Lock the found filemon structure. */
630 		filemon_filemon_lock(filemon);
631 
632 		len = snprintf(filemon->msgbufr, sizeof(filemon->msgbufr),
633 		    "X %d %d\n", curproc->p_pid, uap->rval);
634 
635 		filemon_output(filemon, filemon->msgbufr, len);
636 
637 		/* Check if the monitored process is about to exit. */
638 		if (filemon->pid == curproc->p_pid) {
639 			len = snprintf(filemon->msgbufr,
640 			    sizeof(filemon->msgbufr),
641 			    "# Stop %ju.%06ju\n# Bye bye\n",
642 			    (uintmax_t)now.tv_sec, (uintmax_t)now.tv_usec);
643 
644 			filemon_output(filemon, filemon->msgbufr, len);
645 			filemon->pid = -1;
646 		}
647 
648 		/* Unlock the found filemon structure. */
649 		filemon_filemon_unlock(filemon);
650 	}
651 
652 	/* Release the read lock. */
653 	filemon_unlock_read();
654 
655 	sys_sys_exit(td, uap);
656 }
657 
658 static int
659 filemon_wrapper_unlink(struct thread *td, struct unlink_args *uap)
660 {
661 	int ret;
662 	size_t done;
663 	size_t len;
664 	struct filemon *filemon;
665 
666 	if ((ret = sys_unlink(td, uap)) == 0) {
667 		/* Grab a read lock on the filemon inuse list. */
668 		filemon_lock_read();
669 
670 		if ((filemon = filemon_pid_check(curproc)) != NULL) {
671 			/* Lock the found filemon structure. */
672 			filemon_filemon_lock(filemon);
673 
674 			copyinstr(uap->path, filemon->fname1,
675 			    sizeof(filemon->fname1), &done);
676 
677 			len = snprintf(filemon->msgbufr,
678 			    sizeof(filemon->msgbufr), "D %d %s\n",
679 			    curproc->p_pid, filemon->fname1);
680 
681 			filemon_output(filemon, filemon->msgbufr, len);
682 
683 			/* Unlock the found filemon structure. */
684 			filemon_filemon_unlock(filemon);
685 		}
686 
687 		/* Release the read lock. */
688 		filemon_unlock_read();
689 	}
690 
691 	return (ret);
692 }
693 
694 static int
695 filemon_wrapper_vfork(struct thread *td, struct vfork_args *uap)
696 {
697 	int ret;
698 	size_t len;
699 	struct filemon *filemon;
700 
701 	if ((ret = sys_vfork(td, uap)) == 0) {
702 		/* Grab a read lock on the filemon inuse list. */
703 		filemon_lock_read();
704 
705 		if ((filemon = filemon_pid_check(curproc)) != NULL) {
706 			/* Lock the found filemon structure. */
707 			filemon_filemon_lock(filemon);
708 
709 			len = snprintf(filemon->msgbufr,
710 			    sizeof(filemon->msgbufr), "F %d %ld\n",
711 			    curproc->p_pid, (long)curthread->td_retval[0]);
712 
713 			filemon_output(filemon, filemon->msgbufr, len);
714 
715 			/* Unlock the found filemon structure. */
716 			filemon_filemon_unlock(filemon);
717 		}
718 
719 		/* Release the read lock. */
720 		filemon_unlock_read();
721 	}
722 
723 	return (ret);
724 }
725 
726 static void
727 filemon_wrapper_install(void)
728 {
729 #if defined(__LP64__)
730 	struct sysent *sv_table = elf64_freebsd_sysvec.sv_table;
731 #else
732 	struct sysent *sv_table = elf32_freebsd_sysvec.sv_table;
733 #endif
734 
735 	sv_table[SYS_chdir].sy_call = (sy_call_t *) filemon_wrapper_chdir;
736 	sv_table[SYS_exit].sy_call = (sy_call_t *) filemon_wrapper_sys_exit;
737 	sv_table[SYS_execve].sy_call = (sy_call_t *) filemon_wrapper_execve;
738 	sv_table[SYS_fork].sy_call = (sy_call_t *) filemon_wrapper_fork;
739 	sv_table[SYS_open].sy_call = (sy_call_t *) filemon_wrapper_open;
740 	sv_table[SYS_openat].sy_call = (sy_call_t *) filemon_wrapper_openat;
741 	sv_table[SYS_rename].sy_call = (sy_call_t *) filemon_wrapper_rename;
742 	sv_table[SYS_stat].sy_call = (sy_call_t *) filemon_wrapper_stat;
743 	sv_table[SYS_unlink].sy_call = (sy_call_t *) filemon_wrapper_unlink;
744 	sv_table[SYS_vfork].sy_call = (sy_call_t *) filemon_wrapper_vfork;
745 	sv_table[SYS_link].sy_call = (sy_call_t *) filemon_wrapper_link;
746 	sv_table[SYS_symlink].sy_call = (sy_call_t *) filemon_wrapper_symlink;
747 #ifdef FILEMON_HAS_LINKAT
748 	sv_table[SYS_linkat].sy_call = (sy_call_t *) filemon_wrapper_linkat;
749 #endif
750 
751 #if defined(COMPAT_IA32) || defined(COMPAT_FREEBSD32) || defined(COMPAT_ARCH32)
752 	sv_table = ia32_freebsd_sysvec.sv_table;
753 
754 	sv_table[FREEBSD32_SYS_chdir].sy_call = (sy_call_t *) filemon_wrapper_chdir;
755 	sv_table[FREEBSD32_SYS_exit].sy_call = (sy_call_t *) filemon_wrapper_sys_exit;
756 	sv_table[FREEBSD32_SYS_freebsd32_execve].sy_call = (sy_call_t *) filemon_wrapper_freebsd32_execve;
757 	sv_table[FREEBSD32_SYS_fork].sy_call = (sy_call_t *) filemon_wrapper_fork;
758 	sv_table[FREEBSD32_SYS_open].sy_call = (sy_call_t *) filemon_wrapper_open;
759 	sv_table[FREEBSD32_SYS_openat].sy_call = (sy_call_t *) filemon_wrapper_openat;
760 	sv_table[FREEBSD32_SYS_rename].sy_call = (sy_call_t *) filemon_wrapper_rename;
761 	sv_table[FREEBSD32_SYS_freebsd32_stat].sy_call = (sy_call_t *) filemon_wrapper_freebsd32_stat;
762 	sv_table[FREEBSD32_SYS_unlink].sy_call = (sy_call_t *) filemon_wrapper_unlink;
763 	sv_table[FREEBSD32_SYS_vfork].sy_call = (sy_call_t *) filemon_wrapper_vfork;
764 	sv_table[FREEBSD32_SYS_link].sy_call = (sy_call_t *) filemon_wrapper_link;
765 	sv_table[FREEBSD32_SYS_symlink].sy_call = (sy_call_t *) filemon_wrapper_symlink;
766 #ifdef FILEMON_HAS_LINKAT
767 	sv_table[FREEBSD32_SYS_linkat].sy_call = (sy_call_t *) filemon_wrapper_linkat;
768 #endif
769 #endif	/* COMPAT_ARCH32 */
770 }
771 
772 static void
773 filemon_wrapper_deinstall(void)
774 {
775 #if defined(__LP64__)
776 	struct sysent *sv_table = elf64_freebsd_sysvec.sv_table;
777 #else
778 	struct sysent *sv_table = elf32_freebsd_sysvec.sv_table;
779 #endif
780 
781 	sv_table[SYS_chdir].sy_call = (sy_call_t *)sys_chdir;
782 	sv_table[SYS_exit].sy_call = (sy_call_t *)sys_sys_exit;
783 	sv_table[SYS_execve].sy_call = (sy_call_t *)sys_execve;
784 	sv_table[SYS_fork].sy_call = (sy_call_t *)sys_fork;
785 	sv_table[SYS_open].sy_call = (sy_call_t *)sys_open;
786 	sv_table[SYS_openat].sy_call = (sy_call_t *)sys_openat;
787 	sv_table[SYS_rename].sy_call = (sy_call_t *)sys_rename;
788 	sv_table[SYS_stat].sy_call = (sy_call_t *)sys_stat;
789 	sv_table[SYS_unlink].sy_call = (sy_call_t *)sys_unlink;
790 	sv_table[SYS_vfork].sy_call = (sy_call_t *)sys_vfork;
791 	sv_table[SYS_link].sy_call = (sy_call_t *)sys_link;
792 	sv_table[SYS_symlink].sy_call = (sy_call_t *)sys_symlink;
793 #ifdef FILEMON_HAS_LINKAT
794 	sv_table[SYS_linkat].sy_call = (sy_call_t *)sys_linkat;
795 #endif
796 
797 #if defined(COMPAT_IA32) || defined(COMPAT_FREEBSD32) || defined(COMPAT_ARCH32)
798 	sv_table = ia32_freebsd_sysvec.sv_table;
799 
800 	sv_table[FREEBSD32_SYS_chdir].sy_call = (sy_call_t *)sys_chdir;
801 	sv_table[FREEBSD32_SYS_exit].sy_call = (sy_call_t *)sys_sys_exit;
802 	sv_table[FREEBSD32_SYS_freebsd32_execve].sy_call = (sy_call_t *)freebsd32_execve;
803 	sv_table[FREEBSD32_SYS_fork].sy_call = (sy_call_t *)sys_fork;
804 	sv_table[FREEBSD32_SYS_open].sy_call = (sy_call_t *)sys_open;
805 	sv_table[FREEBSD32_SYS_openat].sy_call = (sy_call_t *)sys_openat;
806 	sv_table[FREEBSD32_SYS_rename].sy_call = (sy_call_t *)sys_rename;
807 	sv_table[FREEBSD32_SYS_freebsd32_stat].sy_call = (sy_call_t *)freebsd32_stat;
808 	sv_table[FREEBSD32_SYS_unlink].sy_call = (sy_call_t *)sys_unlink;
809 	sv_table[FREEBSD32_SYS_vfork].sy_call = (sy_call_t *)sys_vfork;
810 	sv_table[FREEBSD32_SYS_link].sy_call = (sy_call_t *)sys_link;
811 	sv_table[FREEBSD32_SYS_symlink].sy_call = (sy_call_t *)sys_symlink;
812 #ifdef FILEMON_HAS_LINKAT
813 	sv_table[FREEBSD32_SYS_linkat].sy_call = (sy_call_t *)sys_linkat;
814 #endif
815 #endif	/* COMPAT_ARCH32 */
816 }
817