Exemple #1
0
int
main(int argc, char **argv)
{
    int32_t arg_id;
    int     fd, clonefd = -1;
    int     i, j, eoff, off, ret;

    kfs_event_arg_t *kea;
    struct           fsevent_clone_args fca;
    char             buffer[FSEVENT_BUFSIZ];
    struct passwd   *p;
    struct group    *g;
    mode_t           va_mode;
    u_int32_t        va_type;
    u_int32_t        is_fse_arg_vnode = 0;
    char             fileModeString[11 + 1];
    int8_t           event_list[] = { // action to take for each event
                         FSE_REPORT,  // FSE_CREATE_FILE,
                         FSE_REPORT,  // FSE_DELETE,
                         FSE_REPORT,  // FSE_STAT_CHANGED,
                         FSE_REPORT,  // FSE_RENAME,
                         FSE_REPORT,  // FSE_CONTENT_MODIFIED,
                         FSE_REPORT,  // FSE_EXCHANGE,
                         FSE_REPORT,  // FSE_FINDER_INFO_CHANGED,
                         FSE_REPORT,  // FSE_CREATE_DIR,
                         FSE_REPORT,  // FSE_CHOWN,
                         FSE_REPORT,  // FSE_XATTR_MODIFIED,
                         FSE_REPORT,  // FSE_XATTR_REMOVED,
                     };

    if (argc != 1) {
        fprintf(stderr, "%s (%s)\n", PROGNAME, PROGVERS);
        fprintf(stderr, "File system change logger for Mac OS X. Usage:\n");
        fprintf(stderr, "\n\t%s\n\n", PROGNAME);
        fprintf(stderr, "%s does not take any arguments. "
                        "It must be run as root.\n\n", PROGNAME);
        printf("Please report bugs using the following contact information:\n"
           "<URL:http://www.osxbook.com/software/bugs/>\n");

        exit(1);
        exit(1);
    }

    if (geteuid() != 0) {
        fprintf(stderr, "You must be root to run %s. Try again using 'sudo'.\n",
                PROGNAME);
        exit(1);
    }

    setbuf(stdout, NULL);

    if ((fd = open(DEV_FSEVENTS, O_RDONLY)) < 0) {
        perror("open");
        exit(1);
    }

    fca.event_list = (int8_t *)event_list;
    fca.num_events = sizeof(event_list)/sizeof(int8_t);
    fca.event_queue_depth = EVENT_QUEUE_SIZE;
    fca.fd = &clonefd; 
    if ((ret = ioctl(fd, FSEVENTS_CLONE, (char *)&fca)) < 0) {
        perror("ioctl");
        close(fd);
        exit(1);
    }

    close(fd);

    if ((ret = ioctl(clonefd, FSEVENTS_WANT_EXTENDED_INFO, NULL)) < 0) {
        perror("ioctl");
        close(clonefd);
        exit(1);
    }
   // char string2[20]="red dwarf";
   // char string1[20]="";
   //  strcpy(string1, string2);
    char lastpath[300] = "blank";
    char currentpath[300];
    while (1) { // event processing loop
        ret = read(clonefd, buffer, FSEVENT_BUFSIZ);

        off = 0;

        while (off < ret) { // process one or more events received

            struct kfs_event *kfse = (struct kfs_event *)((char *)buffer + off);

            off += sizeof(int32_t) + sizeof(pid_t); // type + pid

            if (kfse->type == FSE_EVENTS_DROPPED) { // special event
                fprintf(stderr, "  %-14s = %s\n", "type", "EVENTS DROPPED");
                exit(1);
            }

            int32_t atype = kfse->type & FSE_TYPE_MASK;
            uint32_t aflags = FSE_GET_FLAGS(kfse->type);

            if ((atype < FSE_MAX_EVENTS) && (atype >= -1)) {

                if (aflags & FSE_COMBINED_EVENTS) {
                    fprintf(stderr,"%s", ", combined events");
                    exit(1);
                }
                if (aflags & FSE_CONTAINS_DROPPED_EVENTS) {
                    fprintf(stderr,"%s", ", contains dropped events");
                    exit(1);
                }
            } else { // should never happen
                printf("This may be a program bug (type = %d).\n", atype);
                exit(1);
            }

            kea = kfse->args; 
            i = 0;

            while (off < ret) {  // process arguments

                i++;

                if (kea->type == FSE_ARG_DONE) { // no more arguments
                    // printf("    %s (%#x)\n", "FSE_ARG_DONE", kea->type);
                    off += sizeof(u_int16_t);
                    break;
                }

                eoff = sizeof(kea->type) + sizeof(kea->len) + kea->len;
                off += eoff;

                arg_id = (kea->type > FSE_MAX_ARGS) ? 0 : kea->type;
                // printf("    %-16s%4hd  ", kfseArgNames[arg_id], kea->len);
                
                
                // switch kfseNames[atype]
                // printf("%d ", kfse->pid);
                
                if (kea->type == FSE_ARG_STRING) { // handle based on argument type
                    strcpy (currentpath,(char *)&(kea->data.str));
                    //  OR atype == FSE_RENAME
                    // strcmp(currentpath, lastpath) != 0
                    if (    atype == FSE_RENAME || 
                            atype == FSE_CREATE_FILE || 
                            atype == FSE_CREATE_DIR || 
                            strcmp(currentpath, lastpath) != 0) {
                        printf("%d\t%s\t%s\t%s\n", kfse->pid, get_proc_name(kfse->pid), kfseNames[atype], currentpath);
                    }
                    strcpy (lastpath,currentpath);
                }

                kea = (kfs_event_arg_t *)((char *)kea + eoff); // next
            } // for each argument
        } // for each event
    } // forever

    close(clonefd);

    exit(0);
}
int
main(int argc, char **argv)
{
    int32_t arg_id;
    int     fd, clonefd = -1;
    int     i, j, eoff, off, ret;
    FILE*   onf;
    char    msg[MAX_SEND];
    int     c;
    int     mlen          = 0;
    int     udp           = 0;
    int     det           = 0;
    char    fname[MAX_FILENAME] = "";
    char    raddr[MAX_IP] = "127.0.0.1";
    int     rport         = 12345;

    kfs_event_arg_t *kea;
    struct           fsevent_clone_args fca;
    char             buffer[FSEVENT_BUFSIZ];
    struct passwd   *p;
    struct group    *g;
    mode_t           va_mode;
    u_int32_t        va_type;
    u_int32_t        is_fse_arg_vnode = 0;
    char             fileModeString[11 + 1];
    int8_t           event_list[] = { // action to take for each event
                         FSE_REPORT,  // FSE_CREATE_FILE,
                         FSE_REPORT,  // FSE_DELETE,
                         FSE_REPORT,  // FSE_STAT_CHANGED,
                         FSE_REPORT,  // FSE_RENAME,
                         FSE_REPORT,  // FSE_CONTENT_MODIFIED,
                         FSE_REPORT,  // FSE_EXCHANGE,
                         FSE_REPORT,  // FSE_FINDER_INFO_CHANGED,
                         FSE_REPORT,  // FSE_CREATE_DIR,
                         FSE_REPORT,  // FSE_CHOWN,
                         FSE_REPORT,  // FSE_XATTR_MODIFIED,
                         FSE_REPORT,  // FSE_XATTR_REMOVED,
                     };

    // Print usage if not root
    if (geteuid() != 0){
        usage();
        exit(1);
    }

    onf = stdout;
    opterr = 0;
    while ((c = getopt (argc, argv, "huf:s:p:")) != -1)
        switch (c){
            case 'f':
                strncpy(fname,optarg,MAX_FILENAME - 1);
                    
                onf = fopen(fname,"w");
                if (onf == NULL){
                    fprintf(stderr, "Cannot open output file %s.\n\n",optarg);
                    usage();
                    exit(1);
                }
                break;
            case 'u':
                udp = 1;
                break;
            case 's':
                strncpy(raddr,optarg,MAX_IP);
                break;
            case 'p':
                rport = atoi( optarg );
                break;
            case 'h':
            case '?':
                if (optopt == 'f'){
                    fprintf(stderr, "Output filename required.\n");
                    usage();
                    exit(1);
                }
                usage();
                exit(1);
        }

    setbuf(onf, NULL);

    //Set UDP Socket
    set_dest(raddr, rport);
    set_sock();

    if ((fd = open(DEV_FSEVENTS, O_RDONLY)) < 0) {
        perror("open");
        exit(1);
    }

    fca.event_list = (int8_t *)event_list;
    fca.num_events = sizeof(event_list)/sizeof(int8_t);
    fca.event_queue_depth = EVENT_QUEUE_SIZE;
    fca.fd = &clonefd; 
    if ((ret = ioctl(fd, FSEVENTS_CLONE, (char *)&fca)) < 0) {
        perror("ioctl");
        close(fd);
        exit(1);
    }

    close(fd);

    //YAML comments lines start with '#'. Use this for debug and status statements
    snprintf(msg, MAX_DATA,"#fsevents device cloned (fd %d)\n#fslogger ready\n",clonefd);
    if (udp){
        send_packet(msg, strlen(msg));
    } else {
        fprintf(onf,"%s",msg);
        // Since we use setbuf this might not be necessary. Let's do it anyway.
        fflush(onf);
    }

    if ((ret = ioctl(clonefd, FSEVENTS_WANT_EXTENDED_INFO, NULL)) < 0) {
        perror("ioctl");
        close(clonefd);
        exit(1);
    }

    while (1) { // event processing loop

        if ((ret = read(clonefd, buffer, FSEVENT_BUFSIZ)) > 0){
            snprintf(msg, MAX_DATA, "# => received %d bytes\n", ret);
            if (udp){
                send_packet(msg, strlen(msg));
            } else {
                fprintf(onf,"%s", msg);
                fflush(onf);
            }
        }

        off = 0;

        while (off < ret) { // process one or more events received
        
            // Start message over
            mlen = 0;

            struct kfs_event *kfse = (struct kfs_event *)((char *)buffer + off);

            off += sizeof(int32_t) + sizeof(pid_t); // type + pid

            //Use snprintf for formatting to permit concantenting the message together
            mlen += snprintf(msg + mlen, MAX_DATA, "---\n");

            if (kfse->type == FSE_EVENTS_DROPPED) { // special event
                mlen += snprintf(msg + mlen, MAX_DATA, "Event:\n");
                mlen += snprintf(msg + mlen, MAX_DATA, " %s: %s\n", "type", "EVENTS_DROPPED");
                mlen += snprintf(msg + mlen, MAX_DATA, " %s: %d\n", "pid", kfse->pid);
                // Special event with continue. So send data then restart loop
                if (udp){
                    send_packet(msg, strlen(msg));
                } else {
                    fprintf(onf,"%s", msg);
                    fflush(onf);
                }

                off += sizeof(u_int16_t); // FSE_ARG_DONE: sizeof(type)
                continue;
            }

            int32_t atype = kfse->type & FSE_TYPE_MASK;
            uint32_t aflags = FSE_GET_FLAGS(kfse->type);

            if ((atype < FSE_MAX_EVENTS) && (atype >= -1)) {
                mlen += snprintf(msg + mlen, MAX_DATA, "Event:\n");
                mlen += snprintf(msg + mlen, MAX_DATA, " %s: %s", "type", kfseNames[atype]);
                if (aflags & FSE_COMBINED_EVENTS) {
                    mlen += snprintf(msg + mlen, MAX_DATA,"%s", ", combined events");
                }
                if (aflags & FSE_CONTAINS_DROPPED_EVENTS) {
                    mlen += snprintf(msg + mlen, MAX_DATA, "%s", ", contains dropped events");
                }
                mlen += snprintf(msg + mlen,MAX_DATA, "%s","\n");


            } else { // should never happen
                mlen += snprintf(msg + mlen, MAX_DATA, "# This may be a program bug (type = %d).\n", atype);
                // Special event with exit. So send data
                if (udp){
                    send_packet(msg, strlen(msg));
                } else {
                    fprintf(onf,"%s", msg);
                    fflush(onf);
                }
                exit(1);
            }

            mlen += snprintf(msg + mlen, MAX_DATA, " %s: %d\n", "pid", kfse->pid);
            mlen += snprintf(msg + mlen, MAX_DATA, " %s: %s\n", "pname", get_proc_name(kfse->pid));

            mlen += snprintf(msg + mlen, MAX_DATA, "%s", "Details:\n");

            kea = kfse->args; 
            i = 0;

            //while ((off < ret) && (i <= FSE_MAX_ARGS)) { // process arguments
            while (off < ret) {

                i++;

                if (kea->type == FSE_ARG_DONE) { // no more arguments
                    mlen += snprintf(msg + mlen, MAX_DATA, " %s:\n", "FSE_ARG_DONE");
                    // Added Length for FSE_ARG_DONE to be consistent with other values
                    mlen += snprintf(msg + mlen, MAX_DATA, "   %s: %d\n", "len", 0);
                    // Added Type for FSE_ARG_DONE to be consistent with other values
                    mlen += snprintf(msg + mlen, MAX_DATA, "   %s: %d\n", "type", kea->type);

                    //This should be the only time to send data for a YAML doc which is a full FSEVENT
                    if (udp){
                        send_packet(msg, strlen(msg));
                    } else {
                        fprintf(onf,"%s", msg);
                        fflush(onf);
                    }
                    det = 0;
                    off += sizeof(u_int16_t);
                    break;
                }

                eoff = sizeof(kea->type) + sizeof(kea->len) + kea->len;
                off += eoff;

                arg_id = (kea->type > FSE_MAX_ARGS) ? 0 : kea->type;
                // Do no put detail marker on timestamp
                if (arg_id == 5){
                    mlen += snprintf(msg + mlen, MAX_DATA, " %s:\n", kfseArgNames[arg_id]);
                } else {
                    mlen += snprintf(msg + mlen, MAX_DATA, " %s_%d:\n", kfseArgNames[arg_id],det);
                }
                mlen += snprintf(msg + mlen, MAX_DATA, "   %s: %d\n", "len", kea->len);

                switch (kea->type) { // handle based on argument type

                case FSE_ARG_VNODE:  // a vnode (string) pointer
                    is_fse_arg_vnode = 1;
                    mlen += snprintf(msg + mlen, MAX_DATA, "   %s: %s\n", "path", (char *)&(kea->data.vp));
                    break;

                case FSE_ARG_STRING: // a string pointer
                    // Added double quotes to protect strings with ":"s 
                    // Actually, to handle "\" it needs to be a single quote
                    mlen += snprintf(msg + mlen, MAX_DATA, "   %s: \'%s\'\n", "string", (char *)&(kea->data.str)-4);
                    break;

                case FSE_ARG_INT32:
                    mlen += snprintf(msg + mlen, MAX_DATA, "   %s: %d\n", "int32", kea->data.int32);
                    break;

                case FSE_ARG_RAW: // a void pointer
                    mlen += snprintf(msg + mlen, MAX_DATA, "   %s: ", "ptr");
                    for (j = 0; j < kea->len; j++)
                        mlen += snprintf(msg + mlen, MAX_DATA, "%02x ", ((char *)kea->data.ptr)[j]);
                    mlen += snprintf(msg + mlen, MAX_DATA, "%s", "\n");
                    break;

                case FSE_ARG_INO: // an inode number
                    mlen += snprintf(msg + mlen, MAX_DATA, "   %s: %d\n", "ino", (int)kea->data.ino);
                    break;

                case FSE_ARG_UID: // a user ID
                    p = getpwuid(kea->data.uid);
                    mlen += snprintf(msg + mlen, MAX_DATA, "   %s: %d (%s)\n", "uid", kea->data.uid, (p) ? p->pw_name : "?");
                    break;

                case FSE_ARG_DEV: // a file system ID or a device number
                    if (is_fse_arg_vnode) {
                        mlen += snprintf(msg + mlen, MAX_DATA, "   %s: %#08x\n", "fsid", kea->data.dev);
                        is_fse_arg_vnode = 0;
                    } else {
                        mlen += snprintf(msg + mlen, MAX_DATA, "   %s: %#08x (major %u, minor %u)\n", "dev", kea->data.dev, major(kea->data.dev), minor(kea->data.dev));
                    }
                    break;

                case FSE_ARG_MODE: // a combination of file mode and file type
                    va_mode = (kea->data.mode & 0x0000ffff);
                    va_type = (kea->data.mode & 0xfffff000);
                    strmode(va_mode, fileModeString);
                    va_type = iftovt_tab[(va_type & S_IFMT) >> 12];
                    mlen += snprintf(msg + mlen, MAX_DATA, "   %s: %s (%#08x, vnode type %s)", "mode", fileModeString, kea->data.mode, (va_type < VTYPE_MAX) ?  vtypeNames[va_type] : "?");
                    if (kea->data.mode & FSE_MODE_HLINK) {
                        mlen += snprintf(msg + mlen, MAX_DATA, "%s", ", hard link");
                    }
                    if (kea->data.mode & FSE_MODE_LAST_HLINK) {
                        mlen += snprintf(msg + mlen, MAX_DATA, "%s", ", link count zero now");
                    }
                    mlen += snprintf(msg + mlen, MAX_DATA, "%s", "\n");
                    break;

                case FSE_ARG_GID: // a group ID
                    g = getgrgid(kea->data.gid);
                    mlen += snprintf(msg + mlen, MAX_DATA, "   %s: %d (%s)\n", "gid", kea->data.gid, (g) ? g->gr_name : "?");
                    // This is usually the last value before everything repeats. Inc det
                    det += 1;
                    break;

                case FSE_ARG_INT64: // timestamp
                    mlen += snprintf(msg + mlen, MAX_DATA, "   %s: %llu\n", "tstamp", kea->data.timestamp);
                    break;

                default:
                    mlen += snprintf(msg + mlen, MAX_DATA, "   %s = ?\n", "unknown");
                    break;
                }

                kea = (kfs_event_arg_t *)((char *)kea + eoff); // next
            } // for each argument
        } // for each event
    } // forever

    close(clonefd);

    // Only close output file if it is not stdout
    if (argc == 2) {
        fclose(onf);
    }

    exit(0);
}