Skip to content

Instantly share code, notes, and snippets.

@furandon-pig
Created December 24, 2021 12:55
Show Gist options
  • Save furandon-pig/b9223fafa5b1311baa8e6c3ba622e2d6 to your computer and use it in GitHub Desktop.
Save furandon-pig/b9223fafa5b1311baa8e6c3ba622e2d6 to your computer and use it in GitHub Desktop.
NetBSDのfilemon機能で取得可能なファイルイベントをハンドリングするサンプルです。
/*
* NetBSD filemonのファイル書き込みの監視サンプル。
*
* $ gcc -Wall -Werror -g -o nbsd_filemon_watch_any_event nbsd_filemon_watch_any_event.c
*/
#include <dev/filemon/filemon.h>
#include <sys/wait.h>
#include <sys/ioctl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <unistd.h>
extern char *optarg;
extern int optind;
void exec_handler_command(char *path, char *cmd)
{
int status;
switch(fork()) {
case -1:
fprintf(stderr, "cannot fork");
break;
case 0:
if (cmd) {
char *script[] = { cmd, path, NULL };
execvp(script[0], script);
}
default:
wait(&status);
}
}
int main(int argc, char *argv[])
{
int ch;
char *c_cmd = NULL; // chdir
char *d_cmd = NULL; // unlink
char *e_cmd = NULL; // exec
char *f_cmd = NULL; // fork,vfork
char *l_cmd = NULL; // link,sumlink
char *m_cmd = NULL; // rename
char *r_cmd = NULL; // open(RDONLY)
char *w_cmd = NULL; // open(RDWR)
char *x_cmd = NULL; // exit
char *path = NULL;
while ((ch = getopt(argc, argv, "c:d:e:f:l:m:r:w:x:")) != -1) {
switch (ch) {
case 'c': c_cmd = optarg; break;
case 'd': d_cmd = optarg; break;
case 'e': e_cmd = optarg; break;
case 'f': f_cmd = optarg; break;
case 'l': l_cmd = optarg; break;
case 'm': m_cmd = optarg; break;
case 'r': r_cmd = optarg; break;
case 'w': w_cmd = optarg; break;
case 'x': x_cmd = optarg; break;
case '?':
default:
break;
}
}
argc -= optind;
argv += optind;
#if DEBUG
if (c_cmd) printf("C: chdir %s\n", c_cmd);
if (d_cmd) printf("D: unlink %s\n", d_cmd);
if (e_cmd) printf("E: exec %s\n", e_cmd);
if (f_cmd) printf("F: fork,vfork %s\n", f_cmd);
if (l_cmd) printf("L: link,symlink %s\n", l_cmd);
if (m_cmd) printf("M: rename %s\n", m_cmd);
if (r_cmd) printf("R: open(RDONLY) %s\n", r_cmd);
if (w_cmd) printf("W: open(RDWR) %s\n", w_cmd);
if (x_cmd) printf("X: exit %s\n", x_cmd);
#endif
pid_t pid;
int filemon_fd, temp_fd;
int status;
char temp_path[] = "/tmp/filemonXXXXXXXX";
FILE *fp = NULL;
char buf[BUFSIZ];
int read_line = 0;
int count = 0;
int is_done = 0;
filemon_fd = open("/dev/filemon", O_RDWR);
temp_fd = mkstemp(temp_path);
// give filemon the temp file to use
ioctl(filemon_fd, FILEMON_SET_FD, &temp_fd);
// children do not need these one they exec
fcntl(filemon_fd, F_SETFD, FD_CLOEXEC);
fcntl(temp_fd, F_SETFD, FD_CLOEXEC);
pid = fork();
switch(pid) {
case -1:
fprintf(stderr, "cannot fork");
break;
case 0:
printf("filemon: %s\n", temp_path);
pid = getpid();
// tell filemon to monitor this process
ioctl(filemon_fd, FILEMON_SET_PID, &pid);
execvp(argv[0], argv);
_exit(1);
break;
default:
lseek(temp_fd, SEEK_SET, 0);
is_done = 1;
while (is_done) {
fp = fopen(temp_path, "r");
if (fp) {
count = 0;
while (fgets(buf, BUFSIZ-1, fp)) {
if (count++ < read_line) {
continue;
}
// "W 521 cal.txt" => "cal.txt"
path = buf;
//path = strchr(buf, ' ');
//path = strchr(++path, ' ');
switch (buf[0]) {
case 'C': exec_handler_command(path, c_cmd); break;
case 'D': exec_handler_command(path, d_cmd); break;
case 'E': exec_handler_command(path, e_cmd); break;
case 'F': exec_handler_command(path, f_cmd); break;
case 'L': exec_handler_command(path, l_cmd); break;
case 'M': exec_handler_command(path, m_cmd); break;
case 'R': exec_handler_command(path, r_cmd); break;
case 'W': exec_handler_command(path, w_cmd); break;
case 'X': exec_handler_command(path, x_cmd); break;
default: break;
}
if (buf[0] == '#') {
is_done = 0;
break;
}
}
read_line += count - read_line;
fclose(fp);
usleep(700000);
}
}
wait(&status);
close(filemon_fd);
close(temp_fd);
break;
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment