コード例 #1
0
ファイル: fanotify04.c プロジェクト: sathnaga/ltp
static void check_mark(char *file, unsigned long long flag, char *flagstr,
		       int expect, void (*test_event)(char *))
{
	if (fanotify_mark(fd_notify, FAN_MARK_ADD | flag, FAN_OPEN, AT_FDCWD,
			    file) != expect) {
		tst_res(TFAIL,
		    "fanotify_mark (%d, FAN_MARK_ADD | %s, FAN_OPEN, AT_FDCWD, "
		    "'%s') %s", fd_notify, flagstr, file, expect_str_fail(expect));
	} else {
		tst_res(TPASS,
		    "fanotify_mark (%d, FAN_MARK_ADD | %s, FAN_OPEN, AT_FDCWD, "
		    "'%s') %s", fd_notify, flagstr, file, expect_str_pass(expect));

		/* If we expected failure there's nothing to clean up */
		if (expect == -1)
			return;

		if (test_event)
			test_event(file);

		if (fanotify_mark(fd_notify, FAN_MARK_REMOVE | flag,
				    FAN_OPEN, AT_FDCWD, file) < 0) {
			tst_brk(TBROK | TERRNO,
			    "fanotify_mark (%d, FAN_MARK_REMOVE | %s, "
			    "FAN_OPEN, AT_FDCWD, '%s') failed",
			    fd_notify, flagstr, file);
		}
	}
}
コード例 #2
0
ファイル: fanotify04.c プロジェクト: MohdVara/ltp
int main(int ac, char **av)
{
	int lc;
	const char *msg;

	if ((msg = parse_opts(ac, av, NULL, NULL)) != NULL)
		tst_brkm(TBROK, NULL, "OPTION PARSING ERROR - %s", msg);

	setup();

	for (lc = 0; TEST_LOOPING(lc); lc++) {
		/* Check ONLYDIR on a directory */
		CHECK_MARK(".", FAN_MARK_ONLYDIR, 0, NULL);

		/* Check ONLYDIR without a directory */
		CHECK_MARK(fname, FAN_MARK_ONLYDIR, -1, NULL);

		/* Check DONT_FOLLOW for a symlink */
		CHECK_MARK(sname, FAN_MARK_DONT_FOLLOW, 0, test_open_symlink);

		/* Check without DONT_FOLLOW for a symlink */
		CHECK_MARK(sname, 0, 0, test_open_file);

		/* Verify FAN_MARK_FLUSH destroys all inode marks */
		if (fanotify_mark(fd_notify, FAN_MARK_ADD,
				    FAN_OPEN, AT_FDCWD, fname) < 0) {
			tst_brkm(TBROK | TERRNO, cleanup,
			    "fanotify_mark (%d, FAN_MARK_ADD, FAN_OPEN, "
			    "AT_FDCWD, '%s') failed", fd_notify, fname);
		}
		if (fanotify_mark(fd_notify, FAN_MARK_ADD,
				    FAN_OPEN | FAN_ONDIR, AT_FDCWD, dir) < 0) {
			tst_brkm(TBROK | TERRNO, cleanup,
			    "fanotify_mark (%d, FAN_MARK_ADD, FAN_OPEN | "
			    "FAN_ONDIR, AT_FDCWD, '%s') failed", fd_notify,
			    dir);
		}
		open_file(fname);
		verify_event(S_IFREG);
		open_dir(dir);
		verify_event(S_IFDIR);
		if (fanotify_mark(fd_notify, FAN_MARK_FLUSH,
				    0, AT_FDCWD, ".") < 0) {
			tst_brkm(TBROK | TERRNO, cleanup,
			    "fanotify_mark (%d, FAN_MARK_FLUSH, 0, "
			    "AT_FDCWD, '.') failed", fd_notify);
		}

		open_dir(dir);
		verify_no_event();
	}

	cleanup();
	tst_exit();
}
コード例 #3
0
static void setup(void)
{
	tst_sig(NOFORK, DEF_HANDLER, cleanup);

	TEST_PAUSE;

	tst_tmpdir();

	fd_notify = fanotify_init(FAN_CLASS_NOTIF | FAN_NONBLOCK, O_RDONLY);
	if (fd_notify < 0) {
		if (errno == ENOSYS) {
			tst_brkm(TCONF, cleanup,
				 "fanotify is not configured in this kernel.");
		} else {
			tst_brkm(TBROK | TERRNO, cleanup,
				 "fanotify_init failed");
		}
	}

	if (fanotify_mark(fd_notify, FAN_MARK_MOUNT | FAN_MARK_ADD, FAN_OPEN,
			    AT_FDCWD, ".") < 0) {
		tst_brkm(TBROK | TERRNO, cleanup,
			 "fanotify_mark (%d, FAN_MARK_MOUNT | FAN_MARK_ADD, "
			 "FAN_OPEN, AT_FDCWD, \".\") failed",
			 fd_notify);
	}
}
コード例 #4
0
ファイル: tst-fanotify.c プロジェクト: Drakey83/steamlink-sdk
static int
do_test (void)
{
  int fd, ret;

  fd = fanotify_init (0, 0);
  if (fd < 0)
    {
      switch (errno)
	{
	case ENOSYS:
	  puts ("SKIP: missing support for fanotify (check CONFIG_FANOTIFY=y)");
	  return 0;
	case EPERM:
	  puts ("SKIP: missing proper permissions for runtime test");
	  return 0;
	}

      perror ("fanotify_init (0, 0) failed");
      return 1;
    }

  ret = fanotify_mark (fd, FAN_MARK_ADD | FAN_MARK_MOUNT, FAN_ACCESS
		       | FAN_MODIFY | FAN_OPEN | FAN_CLOSE | FAN_ONDIR
		       | FAN_EVENT_ON_CHILD, AT_FDCWD, ".");
  if (ret)
    {
      perror ("fanotify_mark (...) failed");
      return 1;
    }

  puts ("All OK");
  return 0;
}
コード例 #5
0
ファイル: watcher.c プロジェクト: rawler/fsopt
int main(int argc, char** argv) {
	int fan_fd, len;
	char buf[sizeof(struct fanotify_event_metadata)*1024];
	struct fanotify_event_metadata *metadata;
        
	if (argc != 3) {
		printf("Usage: %s <root-dir> <procfs>\n", argv[0]);
		return 1;
	}
        procfs = argv[2];

        fan_fd = fanotify_init(0, 0);
	if (fan_fd == -1) {
		perror("fanotify_init");
		return 1;
	}

        fanotify_mark(fan_fd, FAN_MARK_ADD | FAN_MARK_MOUNT, FAN_ACCESS, AT_FDCWD, argv[1]);
        if (fan_fd == -1) {
		perror("fanotify_mark");
                return 1;
        }
	while (1) {
		len = read(fan_fd, buf, sizeof(buf));
		metadata = (struct fanotify_event_metadata*)&buf;
		while (FAN_EVENT_OK(metadata, len)) {
			print_filename(metadata->fd);
			close(metadata->fd);
			metadata = FAN_EVENT_NEXT(metadata, len);
		}
	}
}
コード例 #6
0
static int onas_ddd_watch_hierarchy(const char* pathname, size_t len, int fd, uint64_t mask, uint32_t type) {

	if (!pathname || fd <= 0 || !type) return CL_ENULLARG;

	if (type == (ONAS_IN | ONAS_FAN)) return CL_EARG;

	struct onas_hnode *hnode = NULL;
	struct onas_element *elem = NULL;
	int wd = 0;

	if(onas_ht_get(ddd_ht, pathname, len, &elem) != CL_SUCCESS) return CL_EARG;

	hnode = elem->data;

	if (type & ONAS_IN) {
		wd = inotify_add_watch(fd, pathname, (uint32_t) mask);

		if (wd < 0) return CL_EARG;

		if (wd >= wdlt_len) {
			onas_ddd_grow_wdlt();
		}

		/* Link the hash node to the watch descriptor lookup table */
		hnode->wd = wd;
		wdlt[wd] = hnode->pathname;

		hnode->watched |= ONAS_INWATCH;
	} else if (type & ONAS_FAN) {
		if(fanotify_mark(fd, FAN_MARK_ADD, mask, AT_FDCWD, hnode->pathname) < 0) return CL_EARG;
		hnode->watched |= ONAS_FANWATCH;
	} else {
		return CL_EARG;
	}

	struct onas_lnode *curr = hnode->childhead;

	while (curr->next != hnode->childtail) {
		curr = curr->next;

		size_t size = len + strlen(curr->dirname) + 2;
		char *child_path = (char *) cli_malloc(size);
		if (child_path == NULL)
			return CL_EMEM;
		if (hnode->pathname[len-1] == '/')
			snprintf(child_path, --size, "%s%s", hnode->pathname, curr->dirname);
		else
			snprintf(child_path, size, "%s/%s", hnode->pathname, curr->dirname);

		if(onas_ddd_watch_hierarchy(child_path, strlen(child_path), fd, mask, type)) {
			return CL_EARG;
		}
		free(child_path);
	}

	return CL_SUCCESS;
}
コード例 #7
0
ファイル: fanotify09.c プロジェクト: kraj/ltp
static void create_fanotify_groups(unsigned int ondir)
{
	unsigned int i, onchild;
	int ret;

	for (i = 0; i < NUM_GROUPS; i++) {
		fd_notify[i] = SAFE_FANOTIFY_INIT(FAN_CLASS_NOTIF |
						  FAN_NONBLOCK,
						  O_RDONLY);

		/* Add mount mark for each group without MODIFY event */
		onchild = (i == 0) ? FAN_EVENT_ON_CHILD | ondir : 0;
		ret = fanotify_mark(fd_notify[i],
				    FAN_MARK_ADD | FAN_MARK_MOUNT,
				    FAN_CLOSE_NOWRITE | onchild,
				    AT_FDCWD, ".");
		if (ret < 0) {
			tst_brk(TBROK | TERRNO,
				"fanotify_mark(%d, FAN_MARK_ADD | "
				"FAN_MARK_MOUNT, FAN_MODIFY%s, AT_FDCWD,"
				" '.') failed", fd_notify[i],
				ondir ? " | FAN_ONDIR" : "");
		}
		/*
		 * Add inode mark on parent for each group with MODIFY
		 * event, but only one group requests events on child.
		 * The one mark with FAN_EVENT_ON_CHILD is needed for
		 * setting the DCACHE_FSNOTIFY_PARENT_WATCHED dentry
		 * flag.
		 */
		ret = fanotify_mark(fd_notify[i], FAN_MARK_ADD,
				    FAN_MODIFY | ondir | onchild,
				    AT_FDCWD, ".");
		if (ret < 0) {
			tst_brk(TBROK | TERRNO,
				"fanotify_mark(%d, FAN_MARK_ADD, "
				"FAN_MODIFY%s%s, AT_FDCWD, '.') failed",
				fd_notify[i],
				ondir ? " | FAN_ONDIR" : "",
				onchild ? " | FAN_EVENT_ON_CHILD" : "");
		}
	}
}
コード例 #8
0
ファイル: fanotify04.c プロジェクト: sathnaga/ltp
void test01(void)
{
	/* Check ONLYDIR on a directory */
	CHECK_MARK(".", FAN_MARK_ONLYDIR, 0, NULL);

	/* Check ONLYDIR without a directory */
	CHECK_MARK(fname, FAN_MARK_ONLYDIR, -1, NULL);

	/* Check DONT_FOLLOW for a symlink */
	CHECK_MARK(sname, FAN_MARK_DONT_FOLLOW, 0, test_open_symlink);

	/* Check without DONT_FOLLOW for a symlink */
	CHECK_MARK(sname, 0, 0, test_open_file);

	/* Verify FAN_MARK_FLUSH destroys all inode marks */
	if (fanotify_mark(fd_notify, FAN_MARK_ADD,
			    FAN_OPEN, AT_FDCWD, fname) < 0) {
		tst_brk(TBROK | TERRNO,
		    "fanotify_mark (%d, FAN_MARK_ADD, FAN_OPEN, "
		    "AT_FDCWD, '%s') failed", fd_notify, fname);
	}
	if (fanotify_mark(fd_notify, FAN_MARK_ADD,
			    FAN_OPEN | FAN_ONDIR, AT_FDCWD, dir) < 0) {
		tst_brk(TBROK | TERRNO,
		    "fanotify_mark (%d, FAN_MARK_ADD, FAN_OPEN | "
		    "FAN_ONDIR, AT_FDCWD, '%s') failed", fd_notify,
		    dir);
	}
	open_file(fname);
	verify_event(S_IFREG);
	open_dir(dir);
	verify_event(S_IFDIR);
	if (fanotify_mark(fd_notify, FAN_MARK_FLUSH,
			    0, AT_FDCWD, ".") < 0) {
		tst_brk(TBROK | TERRNO,
		    "fanotify_mark (%d, FAN_MARK_FLUSH, 0, "
		    "AT_FDCWD, '.') failed", fd_notify);
	}

	open_dir(dir);
	verify_no_event();
}
コード例 #9
0
ファイル: facron-conf-entry.c プロジェクト: Keruspe/facron
void
facron_conf_entry_apply (const FacronConfEntry *entry,
                         int                    fanotify_fd,
                         int                    flag,
                         bool                   notice)
{
    if (notice)
        fprintf (stderr, "Notice: tracking \"%s\"\n", entry->path);

    for (int i = 0; i < MAX_MASK_LEN && entry->mask[i]; ++i)
        fanotify_mark (fanotify_fd, flag, entry->mask[i], AT_FDCWD, entry->path);
}
コード例 #10
0
static int onas_ddd_unwatch_hierarchy(const char* pathname, size_t len, int fd, uint32_t type) {

	if (!pathname || fd <= 0 || !type) return CL_ENULLARG;

	if (type == (ONAS_IN | ONAS_FAN)) return CL_EARG;

	struct onas_hnode *hnode = NULL;
	struct onas_element *elem = NULL;
	int wd = 0;

	if(onas_ht_get(ddd_ht, pathname, len, &elem)) return CL_EARG;

	hnode = elem->data;

	if (type & ONAS_IN) {
		wd = hnode->wd;

		if(!inotify_rm_watch(fd, wd)) return CL_EARG;

		/* Unlink the hash node from the watch descriptor lookup table */
		hnode->wd = 0;
		wdlt[wd] = NULL;

		hnode->watched = ONAS_STOPWATCH;
	} else if (type & ONAS_FAN) {
		if(fanotify_mark(fd, FAN_MARK_REMOVE, 0, AT_FDCWD, hnode->pathname) < 0) return CL_EARG;
		hnode->watched = ONAS_STOPWATCH;
	} else {
		return CL_EARG;
	}

	struct onas_lnode *curr = hnode->childhead;

	while (curr->next != hnode->childtail) {
		curr = curr->next;

		size_t size = len + strlen(curr->dirname) + 2;
		char *child_path = (char *) cli_malloc(size);
		if (child_path == NULL)
			return CL_EMEM;
		if (hnode->pathname[len-1] == '/')
			snprintf(child_path, --size, "%s%s", hnode->pathname, curr->dirname);
		else
			snprintf(child_path, size, "%s/%s", hnode->pathname, curr->dirname);

		onas_ddd_unwatch_hierarchy(child_path, strlen(child_path), fd, type);
		free(child_path);
	}

	return CL_SUCCESS;
}
コード例 #11
0
static void changeMarkMount(int fanotifyfd, const char* mountpoint, const unsigned int flags)
{
    const uint64_t mask = FAN_OPEN_PERM | FAN_CLOSE_WRITE;

    int dfd = openMountPoint(mountpoint);
    errno = 0;
    int ret = fanotify_mark(fanotifyfd, flags, mask, dfd, NULL);
    int error = errno;
    close(dfd);
    if (ret < 0)
    {
        PRINT(" error: " << ret<<" errno "<<error<<" strerror "<<strerror(error) << " on "<<fanotifyfd);
        exit(11);
    }
}
コード例 #12
0
void
GonkDiskSpaceWatcher::DoStop()
{
  NS_ASSERTION(XRE_GetIOMessageLoop() == MessageLoopForIO::current(),
               "Not on the correct message loop");

  if (mFd != -1) {
    mReadWatcher.StopWatchingFileDescriptor();
    fanotify_mark(mFd, FAN_MARK_FLUSH, 0, 0, kWatchedPath);
    close(mFd);
    mFd = -1;
  }

  // Dispatch the cleanup to the main thread.
  nsCOMPtr<nsIRunnable> runnable = new DiskSpaceCleaner();
  NS_DispatchToMainThread(runnable);
}
コード例 #13
0
ファイル: fanotify.c プロジェクト: CarterTsai/rr
int main(void) {
  struct fanotify_event_metadata* event;
  int file_fd;
  int fd = fanotify_init(0, O_RDONLY);

  if (fd == -1 && errno == EPERM) {
    atomic_puts("fanotify requires CAP_SYS_ADMIN (in the root namespace) but "
                "we don't have those privileges; skipping tests");
    atomic_puts("EXIT-SUCCESS");
    return 0;
  }

  if (fd == -1 && errno == ENOSYS) {
    atomic_puts("fanotify is not available in this kernel; skipping tests");
    atomic_puts("EXIT-SUCCESS");
    return 0;
  }

  test_assert(fd >= 0);

  file_fd = open("foo", O_WRONLY | O_CREAT, 0777);
  test_assert(file_fd >= 0);
  test_assert(0 == close(file_fd));

  test_assert(0 == fanotify_mark(fd, FAN_MARK_ADD, FAN_OPEN, AT_FDCWD, "foo"));

  file_fd = open("foo", O_WRONLY | O_CREAT, 0777);
  test_assert(file_fd >= 0);
  test_assert(0 == close(file_fd));

  ALLOCATE_GUARD(event, 'x');
  test_assert(sizeof(*event) == read(fd, event, sizeof(*event)));
  VERIFY_GUARD(event);
  test_assert(event->event_len == sizeof(*event));
  test_assert(event->vers == FANOTIFY_METADATA_VERSION);
  test_assert(event->mask == FAN_OPEN);
  test_assert(event->fd >= 0);
  test_assert(event->pid == getpid());

  test_assert(0 == unlink("foo"));

  atomic_puts("EXIT-SUCCESS");
  return 0;
}
コード例 #14
0
ファイル: m_fanotify.c プロジェクト: OpenAtWork/sauvegarde
/**
 * Inits and starts fanotify notifications
 * @param opt : a filled options_t * structure that contains all options
 *        by default, read into the file or selected in the command line.
 */
gint start_fanotify(options_t *opt)
{
    gint fanotify_fd = -1;
    GSList *head = NULL;

    /** Leaving only FAN_CLOSE_WRITE for some tests */
    /* Setup fanotify notifications (FAN) mask. All these defined in linux/fanotify.h. */
    static uint64_t event_mask =
      (FAN_CLOSE_WRITE   |      /* Writtable file closed                                      */
       FAN_ONDIR         |      /* We want to be reported of events in the directory          */
       FAN_EVENT_ON_CHILD);     /* We want to be reported of events in files of the directory */

    unsigned int mark_flags = FAN_MARK_ADD | FAN_MARK_MOUNT;

    if (opt != NULL)
        {
            /* Create new fanotify device */
            if ((fanotify_fd = fanotify_init(FAN_CLOEXEC, O_RDONLY | O_CLOEXEC | O_LARGEFILE)) < 0)
                {
                    print_error(__FILE__, __LINE__, _("Couldn't setup new fanotify device: %s\n"), strerror(errno));
                }
            else
                {
                    head = opt->dirname_list;

                    while (head != NULL)
                        {
                            if (fanotify_mark(fanotify_fd, mark_flags, event_mask, AT_FDCWD, head->data) < 0)
                                {
                                  print_error(__FILE__, __LINE__, _("Couldn't add monitor in directory %s: %s\n"), head->data , strerror(errno));
                                }
                            else
                                {
                                    print_debug(_("Started monitoring directory %s\n"), head->data);
                                }

                            head = g_slist_next(head);
                        }
                }
        }

    return fanotify_fd;
}
コード例 #15
0
ファイル: FileSystem.c プロジェクト: ColumPaget/Movgrab
int FileNotifyInit(const char *Path, int Flags)
{
char *Token=NULL, *ptr;
int fd;

fd=fanotify_init(Flags, O_RDWR);
if (fd==-1) return(fd);

ptr=GetToken(Path,":",&Token,0);
while (ptr)
{
	fanotify_mark(fd, FAN_MARK_ADD, FAN_CLOSE_WRITE, -1, NULL);

	ptr=GetToken(ptr,":",&Token,0);
}

DestroyString(Token);

return(fd);
}
コード例 #16
0
void
GonkDiskSpaceWatcher::DoStart()
{
  NS_ASSERTION(XRE_GetIOMessageLoop() == MessageLoopForIO::current(),
               "Not on the correct message loop");

  mFd = fanotify_init(FAN_CLASS_NOTIF, FAN_CLOEXEC | O_LARGEFILE);
  if (mFd == -1) {
    if (errno == ENOSYS) {
      // Don't change these printf_stderr since we need these logs even
      // in opt builds.
      printf_stderr("Warning: No fanotify support in this device's kernel.\n");
#if ANDROID_VERSION >= 19
      MOZ_CRASH("Fanotify support must be enabled in the kernel.");
#endif
    } else {
      printf_stderr("Error calling fanotify_init()");
    }
    return;
  }

  if (fanotify_mark(mFd, FAN_MARK_ADD | FAN_MARK_MOUNT, FAN_CLOSE,
                    0, kWatchedPath) < 0) {
    NS_WARNING("Error calling fanotify_mark");
    close(mFd);
    mFd = -1;
    return;
  }

  if (!MessageLoopForIO::current()->WatchFileDescriptor(
    mFd, /* persistent = */ true,
    MessageLoopForIO::WATCH_READ,
    &mReadWatcher, gHalDiskSpaceWatcher)) {
      NS_WARNING("Unable to watch fanotify fd.");
      close(mFd);
      mFd = -1;
  }
}
コード例 #17
0
ファイル: fanotify03.c プロジェクト: MohdVara/ltp
static void setup(void)
{
	int fd;

	tst_sig(FORK, DEF_HANDLER, cleanup);

	TEST_PAUSE;

	tst_tmpdir();
	sprintf(fname, "fname_%d", getpid());
	fd = SAFE_OPEN(cleanup, fname, O_CREAT | O_RDWR, 0644);
	SAFE_WRITE(cleanup, 1, fd, fname, 1);
	SAFE_CLOSE(cleanup, fd);

	if ((fd_notify = fanotify_init(FAN_CLASS_CONTENT, O_RDONLY)) < 0) {
		if (errno == ENOSYS) {
			tst_brkm(TCONF, cleanup,
				 "fanotify is not configured in this kernel.");
		} else {
			tst_brkm(TBROK | TERRNO, cleanup,
				 "fanotify_init failed");
		}
	}

	if (fanotify_mark(fd_notify, FAN_MARK_ADD, FAN_ACCESS_PERM |
			    FAN_OPEN_PERM, AT_FDCWD, fname) < 0) {
		if (errno == EINVAL) {
			tst_brkm(TCONF | TERRNO, cleanup,
				 "CONFIG_FANOTIFY_ACCESS_PERMISSIONS not "
				 "configured in kernel?");
		} else {
			tst_brkm(TBROK | TERRNO, cleanup,
				 "fanotify_mark (%d, FAN_MARK_ADD, FAN_ACCESS_PERM | "
				 "FAN_OPEN_PERM, AT_FDCWD, %s) failed.", fd_notify, fname);
		}
	}

}
コード例 #18
0
ファイル: m_fanotify.c プロジェクト: OpenAtWork/sauvegarde
/**
 * Stops fanotify notifications
 * @param opt is the options of the program
 * @param fanotify_fd is the file descriptor of the file which is
 *        concerned by the event.
 */
void stop_fanotify(options_t *opt, int fanotify_fd)
{
    GSList *head = NULL;
    /* Setup fanotify notifications (FAN) mask. All these defined in linux/fanotify.h.    */
    static uint64_t event_mask =
      (FAN_CLOSE_WRITE   |  /* Writtable file closed                                      */
       FAN_ONDIR         |  /* We want to be reported of events in the directory          */
       FAN_EVENT_ON_CHILD); /* We want to be reported of events in files of the directory */

    if (opt != NULL)
        {
            head = opt->dirname_list;

            while (head != NULL)
                {
                    fanotify_mark(fanotify_fd, FAN_MARK_REMOVE, event_mask, AT_FDCWD, head->data);
                    head = g_slist_next(head);
                }

        }

    close(fanotify_fd);
}
コード例 #19
0
ファイル: fanotify.c プロジェクト: tsuyopon/cpp
int main(int argc, char *argv[]) {
    char buf;
    int fd, poll_num;
    nfds_t nfds;
    struct pollfd fds[2];

    /* マウントポイントが指定されたか確認する */
    if (argc != 2) {
        fprintf(stderr, "Usage: %s MOUNT\n", argv[0]);
        exit(EXIT_FAILURE);
    }
    printf("Press enter key to terminate.\n");

    /* fanotify API にアクセスするためのファイルディスクリプターを作成する */
    fd = fanotify_init(FAN_CLOEXEC | FAN_CLASS_CONTENT | FAN_NONBLOCK, O_RDONLY | O_LARGEFILE);
    if (fd == -1) {
        perror("fanotify_init");
        exit(EXIT_FAILURE);
    }

    /* 指定されたマウントに対して以下を監視するようにマークを付ける:
       - ファイルのオープン前のアクセス許可イベント
       - 書き込み可能なファイルディスクリプターのクローズ後の
         通知イベント */
    if (fanotify_mark(fd, FAN_MARK_ADD | FAN_MARK_MOUNT,
                      FAN_OPEN_PERM | FAN_CLOSE_WRITE, AT_FDCWD,
                      argv[1]) == -1) {
        perror("fanotify_mark");
        exit(EXIT_FAILURE);
    }

    /* ポーリングの準備(コンソール入力とfanotifyからの入力音2つ */
    nfds = 2;

    /* コンソールの入力 */
    fds[0].fd = STDIN_FILENO;
    fds[0].events = POLLIN;

    /* fanotify の入力 */
    fds[1].fd = fd;
    fds[1].events = POLLIN;

    /* イベントの発生を待つループ */
    printf("Listening for events.\n");
    while (1) {
        poll_num = poll(fds, nfds, -1);
        if (poll_num == -1) {
            if (errno == EINTR)     /* シグナルに割り込まれた場合 */
                continue;           /* poll() を再開する */

            perror("poll");         /* 予期しないエラー */
            exit(EXIT_FAILURE);
        }

        if (poll_num > 0) {

			// コンソール上から改行入力があればwhileループから抜けて処理を終了する。
            if (fds[0].revents & POLLIN) {
                /* コンソールからの入力がある場合: 空の標準入力であれば終了 */
                while (read(STDIN_FILENO, &buf, 1) > 0 && buf != '\n')
                    continue;
                break;
            }

            if (fds[1].revents & POLLIN) {
                /* fanotify イベントがある場合 */
                handle_events(fd);
            }
        }
    }

    printf("Listening for events stopped.\n");
    exit(EXIT_SUCCESS);
}
コード例 #20
0
ファイル: fanotify01.c プロジェクト: 1587/ltp
int main(int ac, char **av)
{
	int lc;

	tst_parse_opts(ac, av, NULL, NULL);

	setup();

	for (lc = 0; TEST_LOOPING(lc); lc++) {
		int ret, len, i = 0, test_num = 0;

		tst_count = 0;

		if (fanotify_mark(fd_notify, FAN_MARK_ADD, FAN_ACCESS | FAN_MODIFY |
				    FAN_CLOSE | FAN_OPEN, AT_FDCWD, fname) < 0) {
			tst_brkm(TBROK | TERRNO, cleanup,
			    "fanotify_mark (%d, FAN_MARK_ADD, FAN_ACCESS | "
			    "FAN_MODIFY | FAN_CLOSE | FAN_OPEN, AT_FDCWD, %s) "
			    "failed", fd_notify, fname);
		}

		/*
		 * generate sequence of events
		 */
		fd = SAFE_OPEN(cleanup, fname, O_RDONLY);
		event_set[tst_count] = FAN_OPEN;
		tst_count++;

		SAFE_READ(cleanup, 0, fd, buf, BUF_SIZE);
		event_set[tst_count] = FAN_ACCESS;
		tst_count++;

		SAFE_CLOSE(cleanup, fd);
		event_set[tst_count] = FAN_CLOSE_NOWRITE;
		tst_count++;

		/*
		 * Get list of events so far. We get events here to avoid
		 * merging of following events with the previous ones.
		 */
		ret = SAFE_READ(cleanup, 0, fd_notify, event_buf, EVENT_BUF_LEN);
		len = ret;

		fd = SAFE_OPEN(cleanup, fname, O_RDWR | O_CREAT, 0700);
		event_set[tst_count] = FAN_OPEN;
		tst_count++;

		SAFE_WRITE(cleanup, 1, fd, fname, strlen(fname));
		event_set[tst_count] = FAN_MODIFY;
		tst_count++;

		SAFE_CLOSE(cleanup, fd);
		event_set[tst_count] = FAN_CLOSE_WRITE;
		tst_count++;

		/*
		 * get another list of events
		 */
		ret = SAFE_READ(cleanup, 0, fd_notify, event_buf + len,
				EVENT_BUF_LEN - len);
		len += ret;

		/*
		 * Ignore mask testing
		 */

		/* Ignore access events */
		if (fanotify_mark(fd_notify,
				    FAN_MARK_ADD | FAN_MARK_IGNORED_MASK,
				    FAN_ACCESS, AT_FDCWD, fname) < 0) {
			tst_brkm(TBROK | TERRNO, cleanup,
			     "fanotify_mark (%d, FAN_MARK_ADD | "
			     "FAN_MARK_IGNORED_MASK, FAN_ACCESS, "
			     "AT_FDCWD, %s) failed", fd_notify, fname);
		}

		fd = SAFE_OPEN(cleanup, fname, O_RDWR);
		event_set[tst_count] = FAN_OPEN;
		tst_count++;

		/* This event should be ignored */
		SAFE_READ(cleanup, 0, fd, buf, BUF_SIZE);

		/*
		 * get another list of events to verify the last one got ignored
		 */
		ret = SAFE_READ(cleanup, 0, fd_notify, event_buf + len,
				EVENT_BUF_LEN - len);
		len += ret;

		lseek(fd, 0, SEEK_SET);
		/* Generate modify event to clear ignore mask */
		SAFE_WRITE(cleanup, 1, fd, fname, 1);
		event_set[tst_count] = FAN_MODIFY;
		tst_count++;

		/*
		 * This event shouldn't be ignored because previous modification
		 * should have removed the ignore mask
		 */
		SAFE_READ(cleanup, 0, fd, buf, BUF_SIZE);
		event_set[tst_count] = FAN_ACCESS;
		tst_count++;

		SAFE_CLOSE(cleanup, fd);
		event_set[tst_count] = FAN_CLOSE_WRITE;
		tst_count++;

		/* Read events to verify previous access was properly generated */
		ret = SAFE_READ(cleanup, 0, fd_notify, event_buf + len,
				EVENT_BUF_LEN - len);
		len += ret;

		/*
		 * Now ignore open & close events regardless of file
		 * modifications
		 */
		if (fanotify_mark(fd_notify,
				    FAN_MARK_ADD | FAN_MARK_IGNORED_MASK | FAN_MARK_IGNORED_SURV_MODIFY,
				    FAN_OPEN | FAN_CLOSE, AT_FDCWD, fname) < 0) {
			tst_brkm(TBROK | TERRNO, cleanup,
			     "fanotify_mark (%d, FAN_MARK_ADD | "
			     "FAN_MARK_IGNORED_MASK | "
			     "FAN_MARK_IGNORED_SURV_MODIFY, FAN_OPEN | "
			     "FAN_CLOSE, AT_FDCWD, %s) failed", fd_notify,
			     fname);
		}

		/* This event should be ignored */
		fd = SAFE_OPEN(cleanup, fname, O_RDWR);

		SAFE_WRITE(cleanup, 1, fd, fname, 1);
		event_set[tst_count] = FAN_MODIFY;
		tst_count++;

		/* This event should be still ignored */
		SAFE_CLOSE(cleanup, fd);

		/* This event should still be ignored */
		fd = SAFE_OPEN(cleanup, fname, O_RDWR);

		/* Read events to verify open & close were ignored */
		ret = SAFE_READ(cleanup, 0, fd_notify, event_buf + len,
				EVENT_BUF_LEN - len);
		len += ret;

		/* Now remove open and close from ignored mask */
		if (fanotify_mark(fd_notify,
				    FAN_MARK_REMOVE | FAN_MARK_IGNORED_MASK,
				    FAN_OPEN | FAN_CLOSE, AT_FDCWD, fname) < 0) {
			tst_brkm(TBROK | TERRNO, cleanup,
			     "fanotify_mark (%d, FAN_MARK_REMOVE | "
			     "FAN_MARK_IGNORED_MASK, FAN_OPEN | "
			     "FAN_CLOSE, AT_FDCWD, %s) failed", fd_notify,
			     fname);
		}

		SAFE_CLOSE(cleanup, fd);
		event_set[tst_count] = FAN_CLOSE_WRITE;
		tst_count++;

		/* Read events to verify close was generated */
		ret = SAFE_READ(cleanup, 0, fd_notify, event_buf + len,
				EVENT_BUF_LEN - len);
		len += ret;

		if (TST_TOTAL != tst_count) {
			tst_brkm(TBROK, cleanup,
				 "TST_TOTAL (%d) and tst_count (%d) are not "
				 "equal", TST_TOTAL, tst_count);
		}
		tst_count = 0;

		/*
		 * check events
		 */
		while (i < len) {
			struct fanotify_event_metadata *event;

			event = (struct fanotify_event_metadata *)&event_buf[i];
			if (test_num >= TST_TOTAL) {
				tst_resm(TFAIL,
					 "get unnecessary event: mask=%llx "
					 "pid=%u fd=%u",
					 (unsigned long long)event->mask,
					 (unsigned)event->pid, event->fd);
			} else if (!(event->mask & event_set[test_num])) {
				tst_resm(TFAIL,
					 "get event: mask=%llx (expected %llx) "
					 "pid=%u fd=%u",
					 (unsigned long long)event->mask,
					 event_set[test_num],
					 (unsigned)event->pid, event->fd);
			} else if (event->pid != getpid()) {
				tst_resm(TFAIL,
					 "get event: mask=%llx pid=%u "
					 "(expected %u) fd=%u",
					 (unsigned long long)event->mask,
					 (unsigned)event->pid,
					 (unsigned)getpid(),
					 event->fd);
			} else {
				if (event->fd == -2)
					goto pass;
				ret = read(event->fd, buf, BUF_SIZE);
				if (ret != strlen(fname)) {
					tst_resm(TFAIL,
						 "cannot read from returned fd "
						 "of event: mask=%llx pid=%u "
						 "fd=%u ret=%d (errno=%d)",
						 (unsigned long long)event->mask,
						 (unsigned)event->pid,
						 event->fd, ret, errno);
				} else if (memcmp(buf, fname, strlen(fname))) {
					tst_resm(TFAIL,
						 "wrong data read from returned fd "
						 "of event: mask=%llx pid=%u "
						 "fd=%u",
						 (unsigned long long)event->mask,
						 (unsigned)event->pid,
						 event->fd);
				} else {
pass:
					tst_resm(TPASS,
					    "get event: mask=%llx pid=%u fd=%u",
					    (unsigned long long)event->mask,
					    (unsigned)event->pid, event->fd);
				}
			}
			/*
			 * We have verified the data now so close fd and
			 * invalidate it so that we don't check it again
			 * unnecessarily
			 */
			close(event->fd);
			event->fd = -2;
			event->mask &= ~event_set[test_num];
			/* No events left in current mask? Go for next event */
			if (event->mask == 0) {
				i += event->event_len;
			}
			test_num++;
		}
		for (; test_num < TST_TOTAL; test_num++) {
			tst_resm(TFAIL, "didn't get event: mask=%llx",
				 event_set[test_num]);

		}
		/* Remove mark to clear FAN_MARK_IGNORED_SURV_MODIFY */
		if (fanotify_mark(fd_notify, FAN_MARK_REMOVE, FAN_ACCESS | FAN_MODIFY |
				    FAN_CLOSE | FAN_OPEN, AT_FDCWD, fname) < 0) {
			tst_brkm(TBROK | TERRNO, cleanup,
			    "fanotify_mark (%d, FAN_MARK_REMOVE, FAN_ACCESS | "
			    "FAN_MODIFY | FAN_CLOSE | FAN_OPEN, AT_FDCWD, %s) "
			    "failed", fd_notify, fname);
		}

	}

	cleanup();
	tst_exit();
}
コード例 #21
0
ファイル: fan.c プロジェクト: alepharchives/clamav-devel
void *fan_th(void *arg)
{
	struct thrarg *tharg = (struct thrarg *) arg;
	sigset_t sigset;
        struct sigaction act;
	const struct optstruct *pt;
	short int scan;
	int sizelimit = 0, extinfo;
	STATBUF sb;
        uint64_t fan_mask = FAN_ACCESS | FAN_EVENT_ON_CHILD;
	int fan_fd;
        fd_set rfds;
	char buf[4096];
	ssize_t bread;
	struct fanotify_event_metadata *fmd;
	char fname[1024];
	int ret, len;
	char err[128];

    /* ignore all signals except SIGUSR1 */
    sigfillset(&sigset);
    sigdelset(&sigset, SIGUSR1);
    /* The behavior of a process is undefined after it ignores a 
     * SIGFPE, SIGILL, SIGSEGV, or SIGBUS signal */
    sigdelset(&sigset, SIGFPE);
    sigdelset(&sigset, SIGILL);
    sigdelset(&sigset, SIGSEGV);
#ifdef SIGBUS    
    sigdelset(&sigset, SIGBUS);
#endif
    pthread_sigmask(SIG_SETMASK, &sigset, NULL);
    memset(&act, 0, sizeof(struct sigaction));
    act.sa_handler = fan_exit;
    sigfillset(&(act.sa_mask));
    sigaction(SIGUSR1, &act, NULL);
    sigaction(SIGSEGV, &act, NULL);

    fan_fd = fanotify_init(0, O_RDONLY);
    if(fan_fd < 0) {
	logg("!ScanOnAccess: fanotify_init failed: %s\n", cli_strerror(errno, err, sizeof(err)));
	if(errno == EPERM)
	    logg("ScanOnAccess: clamd must be started by root\n");
	return NULL;
    }

    if((pt = optget(tharg->opts, "OnAccessIncludePath"))->enabled) {
	while(pt) {
	    if(fanotify_mark(fan_fd, FAN_MARK_ADD, fan_mask, fan_fd, pt->strarg) != 0) {
		logg("!ScanOnAccess: Can't include path '%s'\n", pt->strarg);
		return NULL;
	    } else
		logg("ScanOnAccess: Protecting directory '%s'\n", pt->strarg);
	    pt = (struct optstruct *) pt->nextarg;
	}
    } else {
	logg("!ScanOnAccess: Please specify at least one path with OnAccessIncludePath\n");
	return NULL;
    }

    if((pt = optget(tharg->opts, "OnAccessExcludePath"))->enabled) {
	while(pt) {
            if(fanotify_mark(fan_fd, FAN_MARK_REMOVE, fan_mask, fan_fd, pt->strarg) != 0) {
		logg("!ScanOnAccess: Can't exclude path %s\n", pt->strarg);
		return NULL;
	    } else
		logg("ScanOnAccess: Excluded path %s\n", pt->strarg);
	    pt = (struct optstruct *) pt->nextarg;
	}
    }

    sizelimit = optget(tharg->opts, "OnAccessMaxFileSize")->numarg;
    if(sizelimit)
	logg("ScanOnAccess: Max file size limited to %d bytes\n", sizelimit);
    else
	logg("ScanOnAccess: File size limit disabled\n");

    extinfo = optget(tharg->opts, "ExtendedDetectionInfo")->enabled;

    FD_ZERO(&rfds);
    FD_SET(fan_fd, &rfds);
    do {
        ret = select(fan_fd + 1, &rfds, NULL, NULL, NULL);
    } while(ret == -1 && errno == EINTR);

    while((bread = read(fan_fd, buf, sizeof(buf))) > 0) {
	fmd = (struct fanotify_event_metadata *) buf;
	while(FAN_EVENT_OK(fmd, bread)) {
	    scan = 1;
	    if(fmd->fd >= 0) {
		sprintf(fname, "/proc/self/fd/%d", fmd->fd);
		len = readlink(fname, fname, sizeof(fname) - 1);
		if(len == -1) {
		    close(fmd->fd);
		    logg("!ScanOnAccess: Internal error (readlink() failed)\n");
		    return NULL;
		}
		fname[len] = 0;

		if(fan_checkowner(fmd->pid, tharg->opts)) {
		    scan = 0;
		    logg("*ScanOnAccess: %s skipped (excluded UID)\n", fname);
		}

		if(sizelimit) {
		    if(FSTAT(fmd->fd, &sb) != 0 || sb.st_size > sizelimit) {
			scan = 0;
			/* logg("*ScanOnAccess: %s skipped (size > %d)\n", fname, sizelimit); */
		    }
		}

		if(fan_scanfile(fan_fd, fname, fmd, scan, extinfo, tharg) == -1) {
		    close(fmd->fd);
		    return NULL;
		}

		if(close(fmd->fd) == -1) {
		    printf("!ScanOnAccess: Internal error (close(%d) failed)\n", fmd->fd);
		    close(fmd->fd);
		    return NULL;
		}
	    }
	    fmd = FAN_EVENT_NEXT(fmd, bread);
	}
	do {
	    ret = select(fan_fd + 1, &rfds, NULL, NULL, NULL);
	} while(ret == -1 && errno == EINTR);
    }

    if(bread < 0)
	logg("!ScanOnAccess: Internal error (failed to read data)\n");

    return NULL;
}
コード例 #22
0
void ScannerThread::handleFanotifyEvent()
{
    char buf[(FAN_EVENT_METADATA_LEN / 2) * 3];
    ssize_t len;
    int fanotifyfd = m_fanotifyfd;


    setState(ScannerThread::BEFORE_READ);
    len = ::read(fanotifyfd, buf, sizeof(buf));
    setState(ScannerThread::AFTER_READ);
    if (len <= 0)
    {
        // nothing actually there - maybe another thread got it
        if (errno != EINTR && errno != EAGAIN)
        {
            PRINT(m_thread<<" no event or error: " << len << " (" << errno <<" "<<strerror(errno)<< ")");
        }
        return;
    }

    struct fanotify_event_metadata* metadata = reinterpret_cast<struct fanotify_event_metadata*>(buf);

    for (; FAN_EVENT_OK(metadata, len); metadata = FAN_EVENT_NEXT(metadata, len))
    {
        if (metadata->vers < 2)
        {
            PRINT("fanotify kernel version too old");
            throw "FIXME"; // TODO: Throw proper exception
        }

        if (metadata->vers != FANOTIFY_METADATA_VERSION)
        {
            // TODO?
            PRINT("fanotify wrong protocol version " << metadata->vers);
            throw "FIXME2"; // TODO: Throw proper exception
        }

        if ((metadata->mask & FAN_ALL_PERM_EVENTS) == 0)
        {
            close(metadata->fd);
            continue;
        }

        std::string path = getPath(metadata->fd);

        //~ {
            //~ struct stat fstatbuf;
            //~ int ret = ::fstat(metadata->fd, &fstatbuf);
            //~ if (ret < 0)
            //~ {
                //~ PRINT("Failed to fstat for "<<metadata->pid <<" "<<path);
            //~ }
        //~ }

        {
            struct fanotify_response response_struct;
            ssize_t ret;

            response_struct.fd = metadata->fd;
            response_struct.response = FAN_ALLOW;

            PRINT(m_thread<< " Responding to fanotify event for "<<metadata->pid << " "<<path);
            setState(ScannerThread::BEFORE_WRITE);
            ret = ::write(fanotifyfd, &response_struct, sizeof(response_struct));
            setState(ScannerThread::AFTER_WRITE);
            if (ret != sizeof(response_struct))
            {
                PRINT(m_thread<<" response error " << ret << " (" << errno <<" "<<strerror(errno)<< ")");
            }
        }


        {
            unsigned int flags = FAN_MARK_ADD | FAN_MARK_IGNORED_MASK;
            int ret = fanotify_mark(fanotifyfd,flags, FAN_OPEN_PERM, metadata->fd, NULL);
            if (ret < 0)
            {
                PRINT(m_thread<<" adding cache mark failed: " << ret);
            }
        }

        if (metadata->fd >= 0)
        {
            ::close(metadata->fd);
        }
    }
}
コード例 #23
0
ファイル: onaccess_fan.c プロジェクト: Distrotech/clamav
void *onas_fan_th(void *arg)
{
	struct thrarg *tharg = (struct thrarg *) arg;
	sigset_t sigset;
        struct sigaction act;
	const struct optstruct *pt;
	short int scan;
	int sizelimit = 0, extinfo;
	STATBUF sb;
        uint64_t fan_mask = FAN_EVENT_ON_CHILD | FAN_CLOSE;
        fd_set rfds;
	char buf[4096];
	ssize_t bread;
	struct fanotify_event_metadata *fmd;
	char fname[1024];
	int ret, len;
	char err[128];

	pthread_attr_t ddd_attr;
	struct ddd_thrarg *ddd_tharg = NULL;

	ddd_pid = 0;

    /* ignore all signals except SIGUSR1 */
    sigfillset(&sigset);
    sigdelset(&sigset, SIGUSR1);
    /* The behavior of a process is undefined after it ignores a 
     * SIGFPE, SIGILL, SIGSEGV, or SIGBUS signal */
    sigdelset(&sigset, SIGFPE);
    sigdelset(&sigset, SIGILL);
    sigdelset(&sigset, SIGSEGV);
#ifdef SIGBUS    
    sigdelset(&sigset, SIGBUS);
#endif
    pthread_sigmask(SIG_SETMASK, &sigset, NULL);
    memset(&act, 0, sizeof(struct sigaction));
    act.sa_handler = onas_fan_exit;
    sigfillset(&(act.sa_mask));
    sigaction(SIGUSR1, &act, NULL);
    sigaction(SIGSEGV, &act, NULL);

    /* Initialize fanotify */
    onas_fan_fd = fanotify_init(FAN_CLASS_CONTENT | FAN_UNLIMITED_QUEUE | FAN_UNLIMITED_MARKS, O_LARGEFILE | O_RDONLY);
    if(onas_fan_fd < 0) {
	logg("!ScanOnAccess: fanotify_init failed: %s\n", cli_strerror(errno, err, sizeof(err)));
	if(errno == EPERM)
	    logg("ScanOnAccess: clamd must be started by root\n");
	return NULL;
    }

    if (!tharg) {
	logg("!Unable to start on-access scanner. Bad thread args.\n");
	return NULL;
    }


    if (optget(tharg->opts, "OnAccessPrevention")->enabled && !optget(tharg->opts, "OnAccessMountPath")->enabled) {
	    logg("ScanOnAccess: preventing access attempts on malicious files.\n");
	    fan_mask |= FAN_ACCESS_PERM | FAN_OPEN_PERM;
    } else {
	    logg("ScanOnAccess: notifying only for access attempts.\n");
	    fan_mask |= FAN_ACCESS | FAN_OPEN;
    }

    if ((pt = optget(tharg->opts, "OnAccessMountPath"))->enabled) {
	    while(pt) {
		    if(fanotify_mark(onas_fan_fd, FAN_MARK_ADD | FAN_MARK_MOUNT, fan_mask, onas_fan_fd, pt->strarg) != 0) {
			    logg("!ScanOnAccess: Can't include mountpoint '%s'\n", pt->strarg);
			    return NULL;
		    } else
			    logg("ScanOnAccess: Protecting '%s' and rest of mount.\n", pt->strarg);
		    pt = (struct optstruct *) pt->nextarg;
	    }

    } else if (!optget(tharg->opts, "OnAccessDisableDDD")->enabled) {
	    do {
		    if(pthread_attr_init(&ddd_attr)) break;
		    pthread_attr_setdetachstate(&ddd_attr, PTHREAD_CREATE_JOINABLE);

		    if(!(ddd_tharg = (struct ddd_thrarg *) malloc(sizeof(struct ddd_thrarg)))) break;

		    ddd_tharg->fan_fd = onas_fan_fd;
		    ddd_tharg->fan_mask = fan_mask;
		    ddd_tharg->opts = tharg->opts;
		    ddd_tharg->engine = tharg->engine;
		    ddd_tharg->options = tharg->options;

		    if(!pthread_create(&ddd_pid, &ddd_attr, onas_ddd_th, ddd_tharg)) break;

		    free(ddd_tharg);
		    ddd_tharg=NULL;
	    } while(0);
	    if (!ddd_tharg) logg("!Unable to start dynamic directory determination.\n");

    } else {
	    if((pt = optget(tharg->opts, "OnAccessIncludePath"))->enabled) {
		    while(pt) {
			    if(fanotify_mark(onas_fan_fd, FAN_MARK_ADD, fan_mask, onas_fan_fd, pt->strarg) != 0) {
				    logg("!ScanOnAccess: Can't include path '%s'\n", pt->strarg);
				    return NULL;
			    } else
				    logg("ScanOnAccess: Protecting directory '%s'\n", pt->strarg);
			    pt = (struct optstruct *) pt->nextarg;
		    }
	    } else {
		    logg("!ScanOnAccess: Please specify at least one path with OnAccessIncludePath\n");
		    return NULL;
	    }
    }

    /* Load other options. */
    sizelimit = optget(tharg->opts, "OnAccessMaxFileSize")->numarg;
    if(sizelimit)
	logg("ScanOnAccess: Max file size limited to %d bytes\n", sizelimit);
    else
	logg("ScanOnAccess: File size limit disabled\n");

    extinfo = optget(tharg->opts, "ExtendedDetectionInfo")->enabled;

    FD_ZERO(&rfds);
    FD_SET(onas_fan_fd, &rfds);
    do {
	if (reload) sleep(1);
        ret = select(onas_fan_fd + 1, &rfds, NULL, NULL, NULL);
    } while((ret == -1 && errno == EINTR) || reload);


    time_t start = time(NULL) - 30;
    while(((bread = read(onas_fan_fd, buf, sizeof(buf))) > 0) || errno == EOVERFLOW) {

	if (errno == EOVERFLOW) {
		if (time(NULL) - start >= 30) {
			logg("!ScanOnAccess: Internal error (failed to read data) ... %s\n", strerror(errno));
			logg("!ScanOnAccess: File too large for fanotify ... recovering and continuing scans...\n");
			start = time(NULL);
		}

		errno = 0;
		continue;
	}

	fmd = (struct fanotify_event_metadata *) buf;
	while(FAN_EVENT_OK(fmd, bread)) {
	    scan = 1;
	    if(fmd->fd >= 0) {
		sprintf(fname, "/proc/self/fd/%d", fmd->fd);
		len = readlink(fname, fname, sizeof(fname) - 1);
		if(len == -1) {
		    close(fmd->fd);
		    logg("!ScanOnAccess: Internal error (readlink() failed)\n");
		    return NULL;
		}
		fname[len] = 0;

		if(onas_fan_checkowner(fmd->pid, tharg->opts)) {
		    scan = 0;
		    logg("*ScanOnAccess: %s skipped (excluded UID)\n", fname);
		}

		if(sizelimit) {
		    if(FSTAT(fmd->fd, &sb) != 0 || sb.st_size > sizelimit) {
			scan = 0;
			/* logg("*ScanOnAccess: %s skipped (size > %d)\n", fname, sizelimit); */
		    }
		}

		if(onas_fan_scanfile(onas_fan_fd, fname, fmd, scan, extinfo, tharg) == -1) {
		    close(fmd->fd);
		    return NULL;
		}

		if(close(fmd->fd) == -1) {
		    printf("!ScanOnAccess: Internal error (close(%d) failed)\n", fmd->fd);
		    close(fmd->fd);
		    return NULL;
		}
	    }
	    fmd = FAN_EVENT_NEXT(fmd, bread);
	}
	do {
	    if (reload) sleep(1);
	    ret = select(onas_fan_fd + 1, &rfds, NULL, NULL, NULL);
	} while((ret == -1 && errno == EINTR) || reload);
    }

    if(bread < 0)
	logg("!ScanOnAccess: Internal error (failed to read data) ... %s\n", strerror(errno));

    return NULL;
}
コード例 #24
0
ファイル: fanotify.c プロジェクト: lebinhe/systemtap
int main()
{
    fd = creat(fname, S_IREAD|S_IWRITE);
    close(fd);

    /* Note that the fanotify calls require root access or the
     * CAP_SYS_ADMIN capability. */

    fd_notify = fanotify_init(FAN_CLASS_NOTIF, O_RDONLY);
    //staptest// fanotify_init (FAN_CLASS_NOTIF, O_RDONLY) = NNNN

    fanotify_mark(fd_notify, FAN_MARK_ADD,
		  FAN_ACCESS|FAN_MODIFY|FAN_CLOSE|FAN_OPEN, AT_FDCWD, fname);
    //staptest// fanotify_mark (NNNN, FAN_MARK_ADD, FAN_ACCESS|FAN_MODIFY|FAN_CLOSE_WRITE|FAN_CLOSE_NOWRITE|FAN_OPEN, AT_FDCWD, "testfile") = NNNN

    // Now, modify the test file.
    fd = open(fname, O_WRONLY);
    //staptest// [[[[open (!!!!openat (AT_FDCWD, ]]]]"testfile", O_WRONLY) = NNNN

    write(fd, fname, strlen(fname) + 1);
    //staptest// write (NNNN, "testfile", NNNN) = NNNN

    close(fd);
    //staptest// close (NNNN) = 0

    // Read list of events.
    read(fd_notify, event_buf, EVENT_BUF_LEN);
    //staptest// read (NNNN, XXXX, NNNN) = NNNN

    // A real program would process the list of events. We're not
    // going to bother.

    close(fd_notify);
    //staptest// close (NNNN) = NNNN

    /* Limit testing. */
    fanotify_init(-1, O_RDONLY);
    //staptest// fanotify_init (XXXX|FAN_[^ ]+|XXXX, O_RDONLY) = -NNNN

    // Here's we're passing an invalid flags value (we hope) to make
    // sure this fails.
    fanotify_init(0x80000000, -1);
    //staptest// fanotify_init (FAN_CLASS_NOTIF|0x80000000, O_[^ ]+|XXXX) = -NNNN

    fanotify_mark(-1, FAN_MARK_REMOVE, FAN_ACCESS, AT_FDCWD, fname);
    //staptest// fanotify_mark (-1, FAN_MARK_REMOVE, FAN_ACCESS, AT_FDCWD, "testfile") = -NNNN

    fanotify_mark(-1, -1, FAN_MODIFY, AT_FDCWD, fname);
    //staptest// fanotify_mark (-1, FAN_[^ ]+|XXXX, FAN_MODIFY, AT_FDCWD, "testfile") = -NNNN

    fanotify_mark(-1, FAN_MARK_FLUSH, -1, AT_FDCWD, fname);
    //staptest// fanotify_mark (-1, FAN_MARK_FLUSH, FAN_[^ ]+|XXXX, AT_FDCWD, "testfile") = -NNNN

    fanotify_mark(-1, FAN_MARK_ADD|FAN_MARK_DONT_FOLLOW, FAN_CLOSE_WRITE, -1LL, fname);
    //staptest// fanotify_mark (-1, FAN_MARK_ADD|FAN_MARK_DONT_FOLLOW, FAN_CLOSE_WRITE, -1, "testfile") = -NNNN

    fanotify_mark(-1, FAN_MARK_ADD|FAN_MARK_MOUNT, FAN_CLOSE_NOWRITE, AT_FDCWD, (char *)-1);
#ifdef __s390__
    //staptest// fanotify_mark (-1, FAN_MARK_ADD|FAN_MARK_MOUNT, FAN_CLOSE_NOWRITE, AT_FDCWD, [7]?[f]+) = -NNNN
#else
    //staptest// fanotify_mark (-1, FAN_MARK_ADD|FAN_MARK_MOUNT, FAN_CLOSE_NOWRITE, AT_FDCWD, [f]+) = -NNNN
#endif

    return 0;
}
コード例 #25
0
int main(int ac, char **av)
{
	int lc;

	tst_parse_opts(ac, av, NULL, NULL);

	setup();

	for (lc = 0; TEST_LOOPING(lc); lc++) {
		int ret, len, i = 0, test_num = 0;

		tst_count = 0;

		if (fanotify_mark(fd_notify, FAN_MARK_ADD, FAN_ACCESS |
				    FAN_MODIFY | FAN_CLOSE | FAN_OPEN |
				    FAN_EVENT_ON_CHILD | FAN_ONDIR, AT_FDCWD,
				  ".") < 0) {
			tst_brkm(TBROK | TERRNO, cleanup,
			    "fanotify_mark (%d, FAN_MARK_ADD, FAN_ACCESS | "
			    "FAN_MODIFY | FAN_CLOSE | FAN_OPEN | "
			    "FAN_EVENT_ON_CHILD | FAN_ONDIR, AT_FDCWD, '.') "
			    "failed", fd_notify);
		}

		/*
		 * generate sequence of events
		 */
		fd = SAFE_OPEN(cleanup, fname, O_RDWR | O_CREAT, 0700);
		event_set[tst_count] = FAN_OPEN;
		tst_count++;

		SAFE_WRITE(cleanup, 1, fd, fname, strlen(fname));
		event_set[tst_count] = FAN_MODIFY;
		tst_count++;

		SAFE_CLOSE(cleanup, fd);
		event_set[tst_count] = FAN_CLOSE_WRITE;
		tst_count++;

		/*
		 * Get list of events so far. We get events here to avoid
		 * merging of following events with the previous ones.
		 */
		ret = SAFE_READ(cleanup, 0, fd_notify, event_buf,
				EVENT_BUF_LEN);
		len = ret;

		fd = SAFE_OPEN(cleanup, fname, O_RDONLY);
		event_set[tst_count] = FAN_OPEN;
		tst_count++;

		SAFE_READ(cleanup, 0, fd, buf, BUF_SIZE);
		event_set[tst_count] = FAN_ACCESS;
		tst_count++;

		SAFE_CLOSE(cleanup, fd);
		event_set[tst_count] = FAN_CLOSE_NOWRITE;
		tst_count++;

		/*
		 * get next events
		 */
		ret = SAFE_READ(cleanup, 0, fd_notify, event_buf + len,
				EVENT_BUF_LEN - len);
		len += ret;

		/*
		 * now remove child mark
		 */
		if (fanotify_mark(fd_notify, FAN_MARK_REMOVE,
				    FAN_EVENT_ON_CHILD, AT_FDCWD, ".") < 0) {
			tst_brkm(TBROK | TERRNO, cleanup,
			    "fanotify_mark (%d, FAN_MARK REMOVE, "
			    "FAN_EVENT_ON_CHILD, AT_FDCWD, '.') failed",
			    fd_notify);
		}

		/*
		 * Do something to verify events didn't get generated
		 */
		fd = SAFE_OPEN(cleanup, fname, O_RDONLY);

		SAFE_CLOSE(cleanup, fd);

		fd = SAFE_OPEN(cleanup, ".", O_RDONLY | O_DIRECTORY);
		event_set[tst_count] = FAN_OPEN;
		tst_count++;

		SAFE_CLOSE(cleanup, fd);
		event_set[tst_count] = FAN_CLOSE_NOWRITE;
		tst_count++;

		/*
		 * Check events got generated only for the directory
		 */
		ret = SAFE_READ(cleanup, 0, fd_notify, event_buf + len,
				EVENT_BUF_LEN - len);
		len += ret;

		if (TST_TOTAL != tst_count) {
			tst_brkm(TBROK, cleanup,
				 "TST_TOTAL and tst_count are not equal");
		}
		tst_count = 0;

		/*
		 * check events
		 */
		while (i < len) {
			struct fanotify_event_metadata *event;

			event = (struct fanotify_event_metadata *)&event_buf[i];
			if (test_num >= TST_TOTAL) {
				tst_resm(TFAIL,
					 "get unnecessary event: mask=%llx "
					 "pid=%u fd=%u",
					 (unsigned long long)event->mask,
					 (unsigned)event->pid, event->fd);
			} else if (!(event->mask & event_set[test_num])) {
				tst_resm(TFAIL,
					 "get event: mask=%llx (expected %llx) "
					 "pid=%u fd=%u",
					 (unsigned long long)event->mask,
					 event_set[test_num],
					 (unsigned)event->pid, event->fd);
			} else if (event->pid != getpid()) {
				tst_resm(TFAIL,
					 "get event: mask=%llx pid=%u "
					 "(expected %u) fd=%u",
					 (unsigned long long)event->mask,
					 (unsigned)event->pid,
					 (unsigned)getpid(),
					 event->fd);
			} else {
				tst_resm(TPASS,
					    "get event: mask=%llx pid=%u fd=%u",
					    (unsigned long long)event->mask,
					    (unsigned)event->pid, event->fd);
			}
			event->mask &= ~event_set[test_num];
			/* No events left in current mask? Go for next event */
			if (event->mask == 0) {
				i += event->event_len;
				close(event->fd);
			}
			test_num++;
		}
		for (; test_num < TST_TOTAL; test_num++) {
			tst_resm(TFAIL, "didn't get event: mask=%llx",
				 event_set[test_num]);

		}
	}

	cleanup();
	tst_exit();
}
コード例 #26
0
ファイル: fanotify_example.c プロジェクト: gwtony/c-example
int main(int argc, char *argv[]) {
    char buf;
    int fd, poll_num;
    nfds_t nfds;
    struct pollfd fds[2];

    /* Check mount point is supplied */
    if (argc != 2) {
        fprintf(stderr, "Usage: %s MOUNT\n", argv[0]);
        exit(EXIT_FAILURE);
    }

    printf("Press enter key to terminate.\n");

    /* Create the file descriptor for accessing the fanotify API */
    fd = fanotify_init(FAN_CLOEXEC | FAN_CLASS_CONTENT | FAN_NONBLOCK,
                       O_RDONLY | O_LARGEFILE);
    if (fd == -1) {
        perror("fanotify_init");
        exit(EXIT_FAILURE);
    }

    /* Mark the mount for:
       - permission events before opening files
       - notification events after closing a write-enabled
         file descriptor */
    if (fanotify_mark(fd, FAN_MARK_ADD | FAN_MARK_MOUNT,
                      FAN_OPEN_PERM | FAN_CLOSE_WRITE, AT_FDCWD,
                      argv[1]) == -1) {
        perror("fanotify_mark");
        exit(EXIT_FAILURE);
    }

    /* Prepare for polling */
    nfds = 2;

    /* Console input */
    fds[0].fd = STDIN_FILENO;
    fds[0].events = POLLIN;

    /* Fanotify input */
    fds[1].fd = fd;
    fds[1].events = POLLIN;

    /* This is the loop to wait for incoming events */
    printf("Listening for events.\n");

    while (1) {
        poll_num = poll(fds, nfds, -1);
        if (poll_num == -1) {
            if (errno == EINTR)     /* Interrupted by a signal */
                continue;           /* Restart poll() */

            perror("poll");         /* Unexpected error */
            exit(EXIT_FAILURE);
        }

        if (poll_num > 0) {
            if (fds[0].revents & POLLIN) {

                /* Console input is available: empty stdin and quit */
                while (read(STDIN_FILENO, &buf, 1) > 0 && buf != '\n')
                    continue;
                break;
            }

            if (fds[1].revents & POLLIN) {

                /* Fanotify events are available */
                handle_events(fd);
            }
        }
    }

    printf("Listening for events stopped.\n");
    exit(EXIT_SUCCESS);
}