Created
May 1, 2024 19:48
-
-
Save DerekSelander/fbd4fba1a00c99b138250d7868f959b0 to your computer and use it in GitHub Desktop.
j's filemon
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <fcntl.h> | |
#include <stdlib.h> | |
#include <sys/ioctl.h> // for _IOW, a macro required by FSEVENTS_CLONE | |
#include <sys/types.h> // for uint32_t and friends, on which fsevents.h relies | |
#include <unistd.h> | |
#include <string.h> // memset | |
//#include <sys/_types.h> // for uint32_t and friends, on which fsevents.h relies | |
#include <sys/stat.h> // for mkdir | |
#include <libgen.h> // for basename | |
#include <sys/sysctl.h> // for sysctl, KERN_PROC, etc. | |
#include <errno.h> | |
/* | |
* Copyright (c) 2000-2014 Apple Inc. All rights reserved. | |
* | |
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@ | |
* | |
* This file contains Original Code and/or Modifications of Original Code | |
* as defined in and that are subject to the Apple Public Source License | |
* Version 2.0 (the 'License'). You may not use this file except in | |
* compliance with the License. The rights granted to you under the License | |
* may not be used to create, or enable the creation or redistribution of, | |
* unlawful or unlicensed copies of an Apple operating system, or to | |
* circumvent, violate, or enable the circumvention or violation of, any | |
* terms of an Apple operating system software license agreement. | |
* | |
* Please obtain a copy of the License at | |
* http://www.opensource.apple.com/apsl/ and read it before using this file. | |
* | |
* The Original Code and all software distributed under the License are | |
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. | |
* Please see the License for the specific language governing rights and | |
* limitations under the License. | |
* | |
* @APPLE_OSREFERENCE_LICENSE_HEADER_END@ | |
*/ | |
#ifndef FSEVENT_H | |
#define FSEVENT_H 1 | |
// Event types that you can ask to listen for | |
#define FSE_INVALID -1 | |
#define FSE_CREATE_FILE 0 | |
#define FSE_DELETE 1 | |
#define FSE_STAT_CHANGED 2 | |
#define FSE_RENAME 3 | |
#define FSE_CONTENT_MODIFIED 4 | |
#define FSE_EXCHANGE 5 | |
#define FSE_FINDER_INFO_CHANGED 6 | |
#define FSE_CREATE_DIR 7 | |
#define FSE_CHOWN 8 | |
#define FSE_XATTR_MODIFIED 9 | |
#define FSE_XATTR_REMOVED 10 | |
#define FSE_DOCID_CREATED 11 | |
#define FSE_DOCID_CHANGED 12 | |
#define FSE_UNMOUNT_PENDING 13 // iOS-only: client must respond via FSEVENTS_UNMOUNT_PENDING_ACK | |
#define FSE_CLONE 14 | |
#define FSE_MAX_EVENTS 15 | |
#define FSE_ALL_EVENTS 998 | |
#define FSE_EVENTS_DROPPED 999 | |
// | |
// These defines only apply if you've asked for extended | |
// type info. In that case the type field's low 12-bits | |
// contain the basic types defined above and the top 4 | |
// bits contain flags that indicate if an event had other | |
// events combined with it or if it represents a directory | |
// that has dropped events below it. | |
// | |
#define FSE_TYPE_MASK 0x0fff | |
#define FSE_FLAG_MASK 0xf000 | |
#define FSE_FLAG_SHIFT 12 | |
#define FSE_GET_FLAGS(type) (((type) >> 12) & 0x000f) | |
#define FSE_COMBINED_EVENTS 0x0001 | |
#define FSE_CONTAINS_DROPPED_EVENTS 0x0002 | |
// Actions for each event type | |
#define FSE_IGNORE 0 | |
#define FSE_REPORT 1 | |
#define FSE_ASK 2 // Not implemented yet | |
// The types of each of the arguments for an event | |
// Each type is followed by the size and then the | |
// data. FSE_ARG_VNODE is just a path string | |
#define FSE_ARG_VNODE 0x0001 // next arg is a vnode pointer | |
#define FSE_ARG_STRING 0x0002 // next arg is length followed by string ptr | |
#define FSE_ARG_PATH 0x0003 // next arg is a full path | |
#define FSE_ARG_INT32 0x0004 // next arg is a 32-bit int | |
#define FSE_ARG_INT64 0x0005 // next arg is a 64-bit int | |
#define FSE_ARG_RAW 0x0006 // next arg is a length followed by a void ptr | |
#define FSE_ARG_INO 0x0007 // next arg is the inode number (ino_t) | |
#define FSE_ARG_UID 0x0008 // next arg is the file's uid (uid_t) | |
#define FSE_ARG_DEV 0x0009 // next arg is the file's dev_t | |
#define FSE_ARG_MODE 0x000a // next arg is the file's mode (as an int32, file type only) | |
#define FSE_ARG_GID 0x000b // next arg is the file's gid (gid_t) | |
#define FSE_ARG_FINFO 0x000c // next arg is a packed finfo (dev, ino, mode, uid, gid) | |
#define FSE_ARG_DONE 0xb33f // no more arguments | |
#define FSE_MAX_ARGS 12 | |
// | |
// These are special bits that be set in the 32-bit mode | |
// field that /dev/fsevents provides. | |
// | |
#define FSE_MODE_HLINK (1U << 31) // notification is for a hard-link | |
#define FSE_MODE_LAST_HLINK (1U << 30) // link count == 0 on a hard-link delete | |
#define FSE_REMOTE_DIR_EVENT (1U << 29) // this is a remotely generated directory-level granularity event | |
#define FSE_TRUNCATED_PATH (1U << 28) // the path for this item had to be truncated | |
#define FSE_MODE_CLONE (1U << 27) // notification is for a clone | |
// ioctl's on /dev/fsevents | |
typedef struct fsevent_clone_args { | |
int8_t *event_list; | |
int32_t num_events; | |
int32_t event_queue_depth; | |
int32_t *fd; | |
} fsevent_clone_args; | |
#define FSEVENTS_CLONE _IOW('s', 1, fsevent_clone_args) | |
// ioctl's on the cloned fd | |
#pragma pack(push, 4) | |
typedef struct fsevent_dev_filter_args { | |
uint32_t num_devices; | |
dev_t *devices; | |
} fsevent_dev_filter_args; | |
#pragma pack(pop) | |
#define FSEVENTS_DEVICE_FILTER _IOW('s', 100, fsevent_dev_filter_args) | |
#define FSEVENTS_WANT_COMPACT_EVENTS _IO('s', 101) | |
#define FSEVENTS_WANT_EXTENDED_INFO _IO('s', 102) | |
#define FSEVENTS_GET_CURRENT_ID _IOR('s', 103, uint64_t) | |
#define FSEVENTS_UNMOUNT_PENDING_ACK _IOW('s', 104, dev_t) | |
#ifdef BSD_KERNEL_PRIVATE | |
void fsevents_init(void); | |
void fsevent_unmount(struct mount *mp, vfs_context_t ctx); | |
struct vnode_attr; | |
void create_fsevent_from_kevent(vnode_t vp, uint32_t kevents, struct vnode_attr *vap); | |
// misc utility functions for fsevent info and pathbuffers... | |
typedef struct fse_info { | |
ino64_t ino; | |
dev_t dev; | |
int32_t mode;// note: this is not a mode_t (it's 32-bits, not 16) | |
uid_t uid; | |
gid_t gid; | |
uint64_t nlink;// only filled in if the vnode is marked as a hardlink | |
} fse_info; | |
int get_fse_info(struct vnode *vp, fse_info *fse, vfs_context_t ctx); | |
int vnode_get_fse_info_from_vap(vnode_t vp, fse_info *fse, struct vnode_attr *vap); | |
char *get_pathbuff(void); | |
void release_pathbuff(char *path); | |
#endif /* BSD_KERNEL_PRIVATE */ | |
#ifdef KERNEL_PRIVATE | |
int need_fsevent(int type, vnode_t vp); | |
int add_fsevent(int type, vfs_context_t, ...); | |
#endif /* KERNEL_PRIVATE */ | |
#endif /* FSEVENT_H */ | |
//-- Begin: copied from "bsd/vfs/vfs_events.c" | |
#pragma pack(1) | |
typedef struct kfs_event_a { | |
uint16_t type; | |
uint16_t refcount; | |
pid_t pid; | |
} kfs_event_a; | |
typedef struct kfs_event_arg { | |
uint16_t type; | |
uint16_t pathlen; | |
char data[0]; | |
} kfs_event_arg; | |
#pragma pack() | |
/* | |
* Copyright (c) 2000-2006 Apple Computer, Inc. All rights reserved. | |
* | |
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@ | |
* | |
* This file contains Original Code and/or Modifications of Original Code | |
* as defined in and that are subject to the Apple Public Source License | |
* Version 2.0 (the 'License'). You may not use this file except in | |
* compliance with the License. The rights granted to you under the License | |
* may not be used to create, or enable the creation or redistribution of, | |
* unlawful or unlicensed copies of an Apple operating system, or to | |
* circumvent, violate, or enable the circumvention or violation of, any | |
* terms of an Apple operating system software license agreement. | |
* | |
* Please obtain a copy of the License at | |
* http://www.opensource.apple.com/apsl/ and read it before using this file. | |
* | |
* The Original Code and all software distributed under the License are | |
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. | |
* Please see the License for the specific language governing rights and | |
* limitations under the License. | |
* | |
* @APPLE_OSREFERENCE_LICENSE_HEADER_END@ | |
*/ | |
#ifndef FSEVENT_H | |
#define FSEVENT_H 1 | |
// Event types that you can ask to listen for | |
#define FSE_INVALID -1 | |
#define FSE_CREATE_FILE 0 | |
#define FSE_DELETE 1 | |
#define FSE_STAT_CHANGED 2 | |
#define FSE_RENAME 3 | |
#define FSE_CONTENT_MODIFIED 4 | |
#define FSE_EXCHANGE 5 | |
#define FSE_FINDER_INFO_CHANGED 6 | |
#define FSE_CREATE_DIR 7 | |
#define FSE_CHOWN 8 | |
#define FSE_XATTR_MODIFIED 9 | |
#define FSE_XATTR_REMOVED 10 | |
#define FSE_MAX_EVENTS 11 | |
#define FSE_ALL_EVENTS 998 | |
#define FSE_EVENTS_DROPPED 999 | |
// | |
// These defines only apply if you've asked for extended | |
// type info. In that case the type field's low 12-bits | |
// contain the basic types defined above and the top 4 | |
// bits contain flags that indicate if an event had other | |
// events combined with it or if it represents a directory | |
// that has dropped events below it. | |
// | |
#define FSE_TYPE_MASK 0x0fff | |
#define FSE_FLAG_MASK 0xf000 | |
#define FSE_FLAG_SHIFT 12 | |
#define FSE_GET_FLAGS(type) (((type) >> 12) & 0x000f) | |
#define FSE_COMBINED_EVENTS 0x0001 | |
#define FSE_CONTAINS_DROPPED_EVENTS 0x0002 | |
// Actions for each event type | |
#define FSE_IGNORE 0 | |
#define FSE_REPORT 1 | |
#define FSE_ASK 2 // Not implemented yet | |
// The types of each of the arguments for an event | |
// Each type is followed by the size and then the | |
// data. FSE_ARG_VNODE is just a path string | |
#define FSE_ARG_VNODE 0x0001 // next arg is a vnode pointer | |
#define FSE_ARG_STRING 0x0002 // next arg is length followed by string ptr | |
#define FSE_ARG_PATH 0x0003 // next arg is a full path | |
#define FSE_ARG_INT32 0x0004 // next arg is a 32-bit int | |
#define FSE_ARG_INT64 0x0005 // next arg is a 64-bit int | |
#define FSE_ARG_RAW 0x0006 // next arg is a length followed by a void ptr | |
#define FSE_ARG_INO 0x0007 // next arg is the inode number (ino_t) | |
#define FSE_ARG_UID 0x0008 // next arg is the file's uid (uid_t) | |
#define FSE_ARG_DEV 0x0009 // next arg is the file's dev_t | |
#define FSE_ARG_MODE 0x000a // next arg is the file's mode (as an int32, file type only) | |
#define FSE_ARG_GID 0x000b // next arg is the file's gid (gid_t) | |
#define FSE_ARG_FINFO 0x000c // next arg is a packed finfo (dev, ino, mode, uid, gid) | |
#define FSE_ARG_DONE 0xb33f // no more arguments | |
#define FSE_MAX_ARGS 12 | |
// | |
// These are special bits that be set in the 32-bit mode | |
// field that /dev/fsevents provides. | |
// | |
#define FSE_MODE_HLINK (1 << 31) // notification is for a hard-link | |
#define FSE_MODE_LAST_HLINK (1 << 30) // link count == 0 on a hard-link delete | |
#define FSE_REMOTE_DIR_EVENT (1 << 29) // this is a remotely generated directory-level granularity event | |
#define FSE_TRUNCATED_PATH (1 << 28) // the path for this item had to be truncated | |
// ioctl's on /dev/fsevents | |
#if __LP64__ | |
typedef struct fsevent_clone_args { | |
int8_t *event_list; | |
int32_t num_events; | |
int32_t event_queue_depth; | |
int32_t *fd; | |
} fsevent_clone_args; | |
#else | |
typedef struct fsevent_clone_args { | |
int8_t *event_list; | |
int32_t pad1; | |
int32_t num_events; | |
int32_t event_queue_depth; | |
int32_t *fd; | |
int32_t pad2; | |
} fsevent_clone_args; | |
#endif | |
#define FSEVENTS_CLONE _IOW('s', 1, fsevent_clone_args) | |
// ioctl's on the cloned fd | |
#if __LP64__ | |
#pragma pack(push, 4) | |
typedef struct fsevent_dev_filter_args { | |
uint32_t num_devices; | |
dev_t *devices; | |
} fsevent_dev_filter_args; | |
#pragma pack(pop) | |
#else | |
typedef struct fsevent_dev_filter_args { | |
uint32_t num_devices; | |
dev_t *devices; | |
int32_t pad1; | |
} fsevent_dev_filter_args; | |
#endif | |
#define FSEVENTS_DEVICE_FILTER _IOW('s', 100, fsevent_dev_filter_args) | |
#define FSEVENTS_WANT_COMPACT_EVENTS _IO('s', 101) | |
#define FSEVENTS_WANT_EXTENDED_INFO _IO('s', 102) | |
#define FSEVENTS_GET_CURRENT_ID _IOR('s', 103, uint64_t) | |
#ifdef KERNEL | |
void fsevents_init(void); | |
int need_fsevent(int type, vnode_t vp); | |
int add_fsevent(int type, vfs_context_t, ...); | |
void fsevent_unmount(struct mount *mp); | |
struct vnode_attr; | |
void create_fsevent_from_kevent(vnode_t vp, uint32_t kevents, struct vnode_attr *vap); | |
// misc utility functions for fsevent info and pathbuffers... | |
typedef struct fse_info { | |
ino64_t ino; | |
dev_t dev; | |
int32_t mode; // note: this is not a mode_t (it's 32-bits, not 16) | |
uid_t uid; | |
gid_t gid; | |
uint64_t nlink; // only filled in if the vnode is marked as a hardlink | |
} fse_info; | |
int get_fse_info(struct vnode *vp, fse_info *fse, vfs_context_t ctx); | |
int vnode_get_fse_info_from_vap(vnode_t vp, fse_info *fse, struct vnode_attr *vap); | |
char *get_pathbuff(void); | |
void release_pathbuff(char *path); | |
#endif /* KERNEL */ | |
#endif /* FSEVENT_H */ | |
//#include <sys/fsevents.h> | |
//#include "fsevents.h" | |
/* $NetBSD: filemon.h,v 1.2 2020/01/22 22:10:36 sjg Exp $ */ | |
/*- | |
* Copyright (c) 2019 The NetBSD Foundation, Inc. | |
* All rights reserved. | |
* | |
* This code is derived from software contributed to The NetBSD Foundation | |
* by Taylor R. Campbell. | |
* | |
* Redistribution and use in source and binary forms, with or without | |
* modification, are permitted provided that the following conditions | |
* are met: | |
* 1. Redistributions of source code must retain the above copyright | |
* notice, this list of conditions and the following disclaimer. | |
* 2. Redistributions in binary form must reproduce the above copyright | |
* notice, this list of conditions and the following disclaimer in the | |
* documentation and/or other materials provided with the distribution. | |
* | |
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | |
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | |
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | |
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
* POSSIBILITY OF SUCH DAMAGE. | |
*/ | |
#ifndef FILEMON_H_ | |
#define FILEMON_H_ | |
#include <sys/types.h> | |
struct filemon; | |
const char * | |
filemon_path(void); | |
struct filemon * | |
filemon_open(void); | |
int filemon_close(struct filemon *); | |
int filemon_setfd(struct filemon *, int); | |
void filemon_setpid_parent(struct filemon *, pid_t); | |
int filemon_setpid_child(const struct filemon *, pid_t); | |
int filemon_readfd(const struct filemon *); | |
int filemon_process(struct filemon *); | |
#endif /* FILEMON_H_ */ | |
//#include "colors.h" | |
#define BOLD "\033[1;1m" | |
#define RED "\033[0;31m" | |
#define M0 "\e[0;30m" | |
#define CYAN "\e[0;36m" | |
#define M1 "\e[0;31m" | |
#define GREY "\e[0;37m" | |
#define M8 "\e[0;38m" | |
#define M9 "\e[0;39m" | |
#define GREEN "\e[0;32m" | |
#define YELLOW "\e[0;33m" | |
#define BLUE "\e[0;34m" | |
#define PINK "\e[0;35m" | |
#define NORMAL "\e[0;0m" | |
#include <signal.h> // for kill | |
/** | |
* | |
* Filemon: A simple but useful fsevents client utilty for OS X and iOS | |
* | |
* Author: Jonathan Levin, TWTR: @Morpheus______ http://NewOSXBook.com/ | |
* | |
* For details, q.v. MOXiI 1st Ed, chapter 3 (pp 74-78), or MOXiI II, Volume I, Chapter 5 | |
* | |
* Source is wide open, so you are free to use and abuse, but leaving credit to the original | |
* author and the book website (http://NewOSXBook.com/) would be appreciated. | |
* | |
* New in 2.0: | |
* | |
* - Supports filters: Process IDs, names or events | |
* - Supports auto-stop and auto-link | |
* - Color | |
* | |
* 2.0.1 - Fixed linking and filter self out | |
* - Can link from elsewhere in the path | |
* | |
*/ | |
int g_dumpArgs =0; | |
#define BUFSIZE 1024 *1024 | |
#define COLOR_OP YELLOW | |
#define COLOR_PROC BLUE | |
#define COLOR_PATH CYAN | |
// Utility functions | |
static char * | |
typeToString (uint32_t Type) | |
{ | |
switch (Type) | |
{ | |
case FSE_CREATE_FILE: return ("Created "); | |
case FSE_DELETE: return ("Deleted "); | |
case FSE_STAT_CHANGED: return ("Changed stat "); | |
case FSE_RENAME: return ("Renamed "); | |
case FSE_CONTENT_MODIFIED: return ("Modified "); | |
case FSE_CREATE_DIR: return ("Created dir "); | |
case FSE_CHOWN: return ("Chowned "); | |
case FSE_EXCHANGE: return ("Exchanged "); /* 5 */ | |
case FSE_FINDER_INFO_CHANGED: return ("Finder Info "); /* 6 */ | |
case FSE_XATTR_MODIFIED: return ("Changed xattr "); /* 9 */ | |
case FSE_XATTR_REMOVED: return ("Removed xattr "); /* 10 */ | |
case FSE_DOCID_CREATED: return ("DocID created "); // 11 | |
case FSE_DOCID_CHANGED: return ("DocID changed "); // 11 | |
default : return ("?! "); | |
} | |
} | |
int lastPID = 0; | |
static char * | |
getProcName(long pid) | |
{ | |
static char procName[4096]; | |
size_t len = 1000; | |
int rc; | |
int mib[4]; | |
// minor optimization | |
if (pid != lastPID) | |
{ | |
memset(procName, '\0', 4096); | |
mib[0] = CTL_KERN; | |
mib[1] = KERN_PROC; | |
mib[2] = KERN_PROC_PID; | |
mib[3] = pid; | |
if ((rc = sysctl(mib, 4, procName, &len, NULL,0)) < 0) | |
{ | |
perror("trace facility failure, KERN_PROC_PID\n"); | |
exit(1); | |
} | |
//printf ("GOT PID: %d and rc: %d - %s\n", mib[3], rc, ((struct kinfo_proc *)procName)->kp_proc.p_comm); | |
lastPID = pid; | |
} | |
return (((struct kinfo_proc *)procName)->kp_proc.p_comm); | |
} | |
int | |
doArg(char *arg, int Print) | |
{ | |
// Dump an arg value | |
unsigned short *argType = (unsigned short *) arg; | |
unsigned short *argLen = (unsigned short *) (arg + 2); | |
uint32_t *argVal = (uint32_t *) (arg+4); | |
uint64_t *argVal64 = (uint64_t *) (arg+4); | |
dev_t *dev; | |
char *str; | |
switch (*argType) | |
{ | |
case FSE_ARG_INT64: // This is a timestamp field on the FSEvent | |
if (g_dumpArgs) printf ("Arg64: %lld ", *argVal64); | |
break; | |
case FSE_ARG_STRING: | |
str = (char *)argVal; | |
if (Print) printf("%s ", str); | |
break; | |
case FSE_ARG_DEV: | |
dev = (dev_t *) argVal; | |
if (g_dumpArgs) printf ("DEV: %d,%d ", major(*dev), minor(*dev)); break; | |
case FSE_ARG_MODE: | |
if (g_dumpArgs) printf("MODE: %x ", *argVal); break; | |
case FSE_ARG_PATH: | |
printf ("PATH: " ); break; | |
case FSE_ARG_INO: | |
if (g_dumpArgs) printf ("INODE: %d ", *argVal); break; | |
case FSE_ARG_UID: | |
if (g_dumpArgs) printf ("UID: %d ", *argVal); break; | |
case FSE_ARG_GID: | |
if (g_dumpArgs) printf ("GID: %d ", *argVal); break; | |
#define FSE_ARG_FINFO 0x000c // next arg is a packed finfo (dev, ino, mode, uid, gid) | |
case FSE_ARG_FINFO: | |
printf ("FINFO\n"); break; | |
case FSE_ARG_DONE: if (Print)printf("\n");return 2; | |
default: | |
printf ("(ARG of type %hd, len %hd)\n", *argType, *argLen); | |
exit(0); | |
} | |
return (4 + *argLen); | |
} | |
#define COLOR_OPTION "-c" | |
#define COLOR_LONG_OPTION "--color" | |
#define FILTER_PROC_OPTION "-p" | |
#define FILTER_PROC_LONG_OPTION "--proc" | |
#define FILTER_FILE_OPTION "-f" | |
#define FILTER_FILE_LONG_OPTION "--file" | |
#define FILTER_EVENT_OPTION "-e" | |
#define FILTER_EVENT_LONG_OPTION "--event" | |
#define STOP_OPTION "-s" | |
#define STOP_LONG_OPTION "--stop" | |
#define LINK_OPTION "-l" | |
#define LINK_LONG_OPTION "--link" | |
void | |
usage() | |
{ | |
fprintf(stderr,"Usage: %s [options]\n", getprogname()); | |
fprintf(stderr,"Where [options] are optional, and may be any of:\n"); | |
fprintf(stderr,"\t" FILTER_PROC_OPTION "|" FILTER_PROC_LONG_OPTION " pid/procname: filter only this process or PID\n"); | |
fprintf(stderr,"\t" FILTER_FILE_OPTION "|" FILTER_FILE_LONG_OPTION " string[,string]: filter only paths containing this string (/ will catch everything)\n"); | |
fprintf(stderr,"\t" FILTER_EVENT_OPTION "|" FILTER_EVENT_LONG_OPTION " event[,event]: filter only these events\n"); | |
fprintf(stderr,"\t" STOP_OPTION "|" STOP_LONG_OPTION ": auto-stop the process generating event\n"); | |
fprintf(stderr,"\t" LINK_OPTION "|" LINK_LONG_OPTION ": auto-create a hard link to file (prevents deletion by program :-)\n"); | |
fprintf(stderr,"\t" COLOR_OPTION "|" COLOR_LONG_OPTION " (or set JCOLOR=1 first)\n"); | |
fprintf(stderr,"\tThis is J's filemon, compiled on " __DATE__ "\n"); | |
} | |
// And.. Ze Main | |
#define MAX_FILTERS 10 | |
int | |
interesting_process (int pid, char *Filters[], int NumFilters) | |
{ | |
// filter myself out | |
if (pid == getpid()) return 0; | |
// Otherwise, if no user defined filters, get all | |
if (!NumFilters) return 1; | |
return 0; | |
} | |
int | |
interesting_file (char *FileName, char *Filters[], int NumFilters) | |
{ | |
// if no filters - everything is interesting | |
if (!NumFilters) return 1; | |
while (NumFilters > 0) | |
{ | |
// fprintf(stderr,"Checking %s vs %s\n", FileName, Filters[NumFilters-1]); | |
if (strstr(FileName, Filters[NumFilters-1])) return 1; | |
NumFilters--; | |
} | |
return 0; | |
} | |
int | |
main (int argc, char **argv) | |
{ | |
#ifdef ARM | |
// It's smarter to do with statfs() | |
char *filemonDir = "/private/var/tmp/filemon"; | |
mkdir (filemonDir, 0777); | |
#endif | |
int fsed, cloned_fsed; | |
int i; | |
int rc; | |
fsevent_clone_args clone_args; | |
unsigned short *arg_type; | |
char *buf = malloc(BUFSIZE); | |
int autostop = 0; | |
int autolink = 0; | |
char *fileFilters[MAX_FILTERS]= { 0 }; | |
char *procFilters[MAX_FILTERS]= { 0 }; | |
int numFileFilters = 0; | |
int numProcFilters = 0; | |
int color = 0; | |
if (getenv("JCOLOR")) color++; | |
//if (argc > 1) { if (strcmp(argv[1],"-v") == 0) g_dumpArgs++; } | |
int arg = 1; | |
for (arg = 1; arg < argc; arg++) | |
{ | |
if (strcmp(argv[arg], "-h") == 0) { usage(); exit(1);} | |
if ((strcmp(argv[arg], FILTER_PROC_OPTION) == 0) || | |
(strcmp(argv[arg], FILTER_PROC_LONG_OPTION) == 0)) | |
{ | |
if (arg == argc -1) | |
{ | |
fprintf(stderr, "%s: Option requires an argument\n", | |
argv[arg]); | |
exit(2); | |
} | |
numProcFilters++; | |
arg++; continue; | |
} | |
if ((strcmp(argv[arg], FILTER_EVENT_OPTION) == 0) || | |
(strcmp(argv[arg], FILTER_EVENT_LONG_OPTION) == 0)) | |
{ | |
if (arg == argc -1) | |
{ | |
fprintf(stderr, "%s: Option requires an argument\n", | |
argv[arg]); | |
exit(2); | |
} | |
arg++; continue; | |
} | |
if ((strcmp(argv[arg], FILTER_FILE_OPTION) == 0) || | |
(strcmp(argv[arg], FILTER_FILE_LONG_OPTION) == 0)) | |
{ | |
if (arg == argc -1) | |
{ | |
fprintf(stderr, "%s: Option requires an argument\n", | |
argv[arg]); | |
exit(2); | |
} | |
// Got it - add filters, separate by "," | |
char *begin = argv[arg+1]; | |
char *sep = strchr (begin, ','); | |
while (sep) | |
{ | |
*sep = '\0'; | |
fprintf(stderr,"Adding File filter %d: %s\n", numFileFilters, begin); | |
fileFilters[numFileFilters++] = strdup(begin); | |
begin = sep + 1; | |
sep = strchr (begin, ','); | |
} | |
fprintf(stderr,"Adding File filter %d: %s\n", numFileFilters, begin); | |
fileFilters[numFileFilters++] = strdup(begin); | |
arg++; continue; | |
} | |
if ((strcmp(argv[arg], COLOR_OPTION) == 0) || (strcmp(argv[arg], COLOR_LONG_OPTION) == 0)) | |
{ | |
color++; | |
continue; | |
} | |
if ((strcmp(argv[arg], STOP_OPTION) == 0) || (strcmp(argv[arg], STOP_LONG_OPTION) == 0)) | |
{ | |
autostop++; | |
continue; | |
} | |
if ((strcmp(argv[arg], LINK_OPTION) == 0) || (strcmp(argv[arg], LINK_LONG_OPTION) == 0)) | |
{ | |
autolink++; | |
continue; | |
} | |
fprintf(stderr, "%s: Unknown option\n", argv[arg]); exit(3); | |
} | |
// This is for your own good: If autostop is allowed on everything, there is a chance a kill -STOP will be | |
// sent to your own terminal app or SSH. | |
if (autostop && (!numFileFilters && !numProcFilters)) | |
{ | |
fprintf(stderr,"Error: Cannot allow auto-stopping of processes without either a file or process filter.\nIf you are sure you want to do this, set a null filter\n"); exit(4); | |
} | |
// Open the device | |
fsed = open ("/dev/fsevents", O_RDONLY); | |
int8_t events[FSE_MAX_EVENTS]; | |
if (geteuid()) | |
{ | |
fprintf(stderr,"Opening /dev/fsevents requires root permissions\n"); | |
} | |
if (fsed < 0) | |
{ | |
perror ("open"); | |
exit(1); | |
} | |
// Prepare event mask list. In our simple example, we want everything | |
// (i.e. all events, so we say "FSE_REPORT" all). Otherwise, we | |
// would have to specifically toggle FSE_IGNORE for each: | |
// | |
// e.g. | |
// events[FSE_XATTR_MODIFIED] = FSE_IGNORE; | |
// events[FSE_XATTR_REMOVED] = FSE_IGNORE; | |
// etc.. | |
for (i = 0; i < FSE_MAX_EVENTS; i++) | |
{ | |
events[i] = FSE_REPORT; | |
} | |
// But in v2.0, we allow user to specify events | |
// Get ready to clone the descriptor: | |
memset(&clone_args, '\0', sizeof(clone_args)); | |
clone_args.fd = &cloned_fsed; // This is the descriptor we get back | |
clone_args.event_queue_depth = 100; // Makes all the difference | |
clone_args.event_list = events; | |
clone_args.num_events = FSE_MAX_EVENTS; | |
// Do it. | |
rc = ioctl (fsed, FSEVENTS_CLONE, &clone_args); | |
if (rc < 0) { perror ("ioctl"); exit(2);} | |
// We no longer need original.. | |
close (fsed); | |
// And now we simply read, ad infinitum (aut nauseam) | |
while ((rc = read (cloned_fsed, buf, BUFSIZE)) > 0) | |
{ | |
// rc returns the count of bytes for one or more events: | |
int offInBuf = 0; | |
while (offInBuf < rc) { | |
// printf("----%d/%d bytes\n",offInBuf,rc); | |
struct kfs_event_a *fse = (struct kfs_event_a *)(buf + offInBuf); | |
struct kfs_event_arg *fse_arg; | |
// if (offInBuf) { printf ("Next event: %d\n", offInBuf);}; | |
if (fse->type == FSE_EVENTS_DROPPED) | |
{ | |
printf("Some events dropped\n"); | |
break; | |
} | |
if (!fse->pid){ printf ("%x %x\n", fse->type, fse->refcount); } | |
int print = 0; | |
char *procName = getProcName(fse->pid); | |
offInBuf+= sizeof(struct kfs_event_a); | |
fse_arg = (struct kfs_event_arg *) &buf[offInBuf]; | |
if (interesting_process(fse->pid, procFilters, numProcFilters) | |
&& interesting_file (fse_arg->data, fileFilters, numFileFilters)) | |
{ | |
printf ("%5d %s%s%s\t%s%s%s ", fse->pid, | |
color ? COLOR_PROC: "" , procName, color ? NORMAL : "", | |
color ? COLOR_OP : "", typeToString(fse->type), color ? NORMAL : "" ); | |
// The path name is null terminated, so that's cool | |
printf ("%s%s%s\t", | |
color ? COLOR_PATH : "" , fse_arg->data, color ? NORMAL :""); | |
// Fix: Don't autolink own files | |
if (fse->type == FSE_CREATE_FILE && autolink && (fse->pid != getpid()) && | |
!strstr(fse_arg->data, "filemon")) | |
{ | |
int fileLen = strlen(fse_arg->data); | |
char *linkName = malloc (fileLen + 20); | |
#ifndef ARM | |
strcpy(linkName, fse_arg->data); | |
#else | |
if (strncmp(fse_arg->data, "/private/var",12) == 0) | |
{ | |
// Might be in some subdir which will go away | |
strcpy(linkName, filemonDir); | |
strcat(linkName,"/"); | |
strcat (linkName, basename(fse_arg->data)); | |
} | |
#endif | |
// Don't need to worry about buffer boundaries here.. | |
snprintf(linkName + strlen(linkName), fileLen + 20, ".filemon.%d", autolink); | |
int rc = link (fse_arg->data, linkName); | |
if (rc) { fprintf(stderr,"%sWarning: Unable to autolink %s%s - file must have been deleted already\n", | |
color ? RED : "", | |
fse_arg->data, | |
color ? NORMAL : "");} | |
else { fprintf(stderr,"%sAuto-linked %s to %s%s\n", | |
color ? GREEN : "", | |
fse_arg->data, linkName, | |
color ? NORMAL :""); | |
autolink++; | |
} | |
free (linkName); | |
} | |
// Autostop only if this is a file creation, and interesting | |
if (autostop && fse->type == FSE_CREATE_FILE ) { | |
fprintf(stderr, "%sAuto-stopping process %s (%d) on file operation%s\n", | |
color ? RED : "", | |
procName, | |
fse->pid, | |
color ? NORMAL : ""); | |
kill (fse->pid, SIGSTOP); | |
} | |
print = 1; | |
} | |
offInBuf += sizeof(kfs_event_arg) + fse_arg->pathlen ; | |
int arg_len = doArg(buf + offInBuf,print); | |
offInBuf += arg_len; | |
while (arg_len >2 && offInBuf < rc) | |
{ | |
arg_len = doArg(buf + offInBuf, print); | |
offInBuf += arg_len; | |
} | |
} | |
memset (buf,'\0', BUFSIZE); | |
if (rc > offInBuf) { printf ("*** Warning: Some events may be lost\n"); } | |
} | |
} // end main |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment