摘要:filemon for iOS
/**
* filemon.c : A simple FSEvents monitor for iOS and OS X.
* Will compile neatly and run on both (tested on iOS 6.0.1)
*
* (Command line utility.. If you want the GUI, drop me a line)
*
* Comments and suggestions more than welcome!
*/
#include
#include
#include
#include // for _IOW, a macro required by FSEVENTS_CLONE
#include // for uint32_t and friends, on which fsevents.h relies
//#include // for uint32_t and friends, on which fsevents.h relies
#include // for sysctl, KERN_PROC, etc.
#include
//#include would have been nice, but it's no longer available, as Apple
// now wraps this with FSEventStream. So instead - rip what we need from the kernel headers..
// Actions for each event type
#define FSE_IGNORE 0
#define FSE_REPORT 1
#define FSE_ASK 2 // Not implemented yet
#define FSEVENTS_CLONE _IOW('s', 1, fsevent_clone_args)
#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
// 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
#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
// copied from bsd/vfs/vfs_events.c
#pragma pack(1) // to be on the safe side. Not really necessary.. struct fields are aligned.
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()
#define BUFSIZE 64 *1024
// Utility functions
const char *
typeToString (uint32_t Type)
{
switch (Type)
{
case FSE_CREATE_FILE: return ("Created ");
case FSE_DELETE: return ("Deleted ");
case FSE_STAT_CHANGED: return ("Stat changed ");
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 changed for "); /* 6 */
case FSE_XATTR_MODIFIED: return ("Extended attributes changed for "); /* 9 */
case FSE_XATTR_REMOVED: return ("Extended attributesremoved for "); /* 10 */
default : return ("Not yet ");
}
}
char *
getProcName(long pid)
{
static char procName[4096];
int len = 1000;
int rc;
int mib[4];
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);
return (((struct kinfo_proc *)procName)->kp_proc.p_comm);
}
int
doArg(char *arg)
{
// Dump an arg value
// Quick and dirty, but does the trick..
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
printf ("Arg64: %lld\n", *argVal64);
break;
case FSE_ARG_STRING: // This is a filename, for move/rename (Type 3)
str = (char *)argVal;
printf("%s ", str);
break;
case FSE_ARG_DEV: // Device, corresponding to block device on which fs is mounted
dev = (dev_t *) argVal;
printf ("DEV: %d,%d ", major(*dev), minor(*dev)); break;
case FSE_ARG_MODE: // mode bits, etc
printf("MODE: %x ", *argVal); break;
case FSE_ARG_PATH: // Not really used... Implement this later..
printf ("PATH: " ); break;
case FSE_ARG_INO: // Inode number (unique up to device)
printf ("INODE: %d ", *argVal); break;
case FSE_ARG_UID: // UID of operation performer
printf ("UID: %d ", *argVal); break;
case FSE_ARG_GID: // Ditto, GID
printf ("GID: %d ", *argVal); break;
case FSE_ARG_FINFO: // Not handling this yet.. Not really used, either..
printf ("FINFO\n"); break;
case FSE_ARG_DONE: printf("\n");return 2;
default:
printf ("(ARG of type %hd, len %hd)\n", *argType, *argLen);
}
return (4 + *argLen);
}
// And.. Ze Main
void
main (int argc, char **argv)
{
int fsed, cloned_fsed;
int i;
int rc;
fsevent_clone_args clone_args;
unsigned short *arg_type;
char buf[BUFSIZE];
// 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;
}
// 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 = 10;
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) {
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);};
printf ("%s (PID:%d) %s ", getProcName(fse->pid), fse->pid , typeToString(fse->type) );
offInBuf+= sizeof(struct kfs_event_a);
fse_arg = (struct kfs_event_arg *) &buf[offInBuf];
printf ("%s\n", fse_arg->data);
offInBuf += sizeof(kfs_event_arg) + fse_arg->pathlen ;
int arg_len = doArg(buf + offInBuf);
offInBuf += arg_len;
while (arg_len >2)
{
arg_len = doArg(buf + offInBuf);
offInBuf += arg_len;
}
}
if (rc > offInBuf) { printf ("***Warning: Some events may be lost\n"); }
}
}
------------------------------
文章的授權使用CC BY-ND2.5協議。凡是標示“轉載”的文章,均來源於網絡並儘可能標註作者。如果有侵犯您的權益,請及時聯繫刪除或者署名、授權。
Gtalk/Email: cmd4shell [at] gmail.com