filemon for iOS

  • 1808
  • 0
  • 2012-12-27

摘要: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