diff --git a/mon_dtracepipe.c b/mon_dtracepipe.c new file mode 100644 index 0000000..ee0ac74 --- /dev/null +++ b/mon_dtracepipe.c @@ -0,0 +1,225 @@ +/* + clsync - file tree sync utility based on inotify/kqueue + + Copyright (C) 2013-2014 Dmitry Yu Okunev 0x8E30679C + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ +#include "common.h" +#include "malloc.h" +#include "error.h" +#include "indexes.h" +#include "sync.h" +#include "mon_dtracepipe.h" + +#define DTRACE_SCRIPT "BEGIN\ +{\ + dir = $1;\ + dirlen = strlen(dir);\ +}\ +\ +syscall::open*:entry\ +/\ +arg1 & (O_WRONLY|O_RDWR) &&\ + substr(copyinstr(arg0),0,dirlen)==dir\ +/\ +{\ + printf("%s\n",copyinstr(arg0));\ +}\ +\ +syscall::mkdir*:entry\ +/\ + substr(copyinstr(arg0),0,dirlen)==dir\ +/\ +{\ + printf("%s\n",copyinstr(arg0));\ +}" + +struct mondata { + FILE *pipe; +}; +typedef struct mondata mondata_t; + +#define DTRACEPIPE_INIT_ERROR {\ + free(ctx_p->fsmondata);\ + ctx_p->fsmondata = NULL;\ + return -1;\ +} + +int dtracepipe_init(ctx_t *ctx_p) { + char cmd[BUFSIZ]; + + ctx_p->fsmondata = xcalloc(sizeof(mondata_t), 1); + mondata_t *mondata = ctx_p->fsmondata; + + if (snprintf(cmd, "%s -n '%s' '%s'", DTRACE_PATH, DTRACE_SCRIPT, ) >= BUFSIZ) { + errno = EMSGSIZE; + error("Too long cmd."); + DTRACEPIPE_INIT_ERROR; + } + + FILE *pipe = popen(cmd, "r"); + if (pipe == NULL) { + error("Cannot popen(\""DTRACE_PATH"\", \"r\")"); + DTRACEPIPE_INIT_ERROR; + } + + if (setvbuf(pipe, NULL, _IONBF, 0)) { + error("Cannot set unbuffered mode for pipe of \""DTRACE_PATH"\" process"); + DTRACEPIPE_INIT_ERROR; + } + + mondata->pipe = pipe; + + return 0; +} + +char *dtracepipe_wait_line = NULL; +size_t dtracepipe_wait_line_siz; +int dtracepipe_wait(struct ctx *ctx_p, struct indexes *indexes_p, struct timeval *timeout_p) { + mondata_t *mondata = ctx_p->fsmondata; + struct timeval timeout_abs, tv_abs; + int dontwait = 0; + struct dtracepipe_event *event_p = &mondata->event; + + if (timeout_p->tv_sec == 0 && timeout_p->tv_usec == 0) + dontwait = 1; + + if (!dontwait) { + gettimeofday(&tv_abs, NULL); + timeradd(&tv_abs, timeout_p, &timeout_abs); + } + + int pipe_fd = fileno(mondata->pipe); + + while (42) { + int path_count; + + // Checking if there already a recond in mondata + if (*event_p->path) { + debug(2, "we have an event. return 1."); + return 1; + } + + // Getting a record + { + debug(3, "select() with timeout %li.%06li secs (dontwait == %u).", timeout_p->tv_sec, timeout_p->tv_usec, dontwait); + fd_set rfds; + FD_ZERO(&rfds); + FD_SET(pipe_fd, &rfds); + int rc = select(pipe_fd+1, &rfds, NULL, NULL, timeout_p); + + if (rc == 0 || rc == -1) + return rc; + + line_len = getline(&dtracepipe_wait_line, &dtracepipe_wait_line_siz, mondata->pipe); + if (line_len == -1) { + error("Cannot read line from \""DTRACE_PATH"\" pipe [using getline()]"); + return -1; + } + + if (!dontwait) { + debug(5, "old timeout_p->: tv_sec == %lu; tv_usec == %lu", timeout_p->tv_sec, timeout_p->tv_usec); + gettimeofday(&tv_abs, NULL); + if (timercmp(&timeout_abs, &tv_abs, <)) + timersub(&timeout_abs, &tv_abs, timeout_p); + else + memset(timeout_p, 0, sizeof(*timeout_p)); + debug(5, "new timeout_p->: tv_sec == %lu; tv_usec == %lu", timeout_p->tv_sec, timeout_p->tv_usec); + } + } + + // Parsing the record + path_count = 0; + debug(3, "parsing the event"); + while (au_parsed < au_len) { + + if (au_fetch_tok(&tok, &au_buf[au_parsed], au_len - au_parsed) == -1) + return -1; + au_parsed += tok.len; + + switch (tok.id) { + case AUT_HEADER32: + case AUT_HEADER32_EX: + case AUT_HEADER64: + case AUT_HEADER64_EX: { + event_p->type = tok.tt.hdr32.e_type; + path_count = 0; + break; + } + case AUT_PATH: { + char *ptr; + int dir_wd, dir_iswatched; + + ptr = memrchr(tok.tt.path.path, '/', tok.tt.path.len); + +#ifdef PARANOID + if (ptr == NULL) + critical("relative path received from au_fetch_tok(): \"%s\" (len: %u)", tok.tt.path.path, tok.tt.path.len); +#endif + + debug(6, "Event on \"%s\".", tok.tt.path.path); + *ptr = 0; + dir_wd = indexes_fpath2wd(indexes_p, tok.tt.path.path); + dir_iswatched = (dir_wd != -1); + debug(7, "Directory is \"%s\". dir_wd == %i; dir_iswatched == %u", tok.tt.path.path, dir_wd, dir_iswatched); + *ptr = '/'; + + if (dir_iswatched) { + debug(5, "Event on \"%s\" is watched. Pushing. path_count == %u", tok.tt.path.path, path_count); + switch (path_count) { + case 0: + memcpy(event_p->path, tok.tt.path.path, tok.tt.path.len+1); + break; + case 1: + memcpy(event_p->path_to, tok.tt.path.path, tok.tt.path.len+1); + break; +#ifdef PARANOID + default: + warning("To many paths on BSM event: \"%s\" (already count: %u)", tok.tt.path.path, path_count); + break; +#endif + } + } + path_count++; + break; + } + default: + continue; + } + } + + // Cleanup + debug(4, "clean up"); + free(au_buf); + au_buf = NULL; + au_len = 0; + au_parsed = 0; + } + return -1; +} +int dtracepipe_handle(struct ctx *ctx_p, struct indexes *indexes_p) { + return -1; +} +int dtracepipe_add_watch_dir(struct ctx *ctx_p, struct indexes *indexes_p, const char *const accpath) { + return -1; +} +int dtracepipe_deinit(ctx_t *ctx_p) { + mondata_t *mondata = ctx_p->fsmondata; + + free(dtracepipe_wait_line); + free(mondata); + + return -1; +} diff --git a/mon_dtracepipe.h b/mon_dtracepipe.h new file mode 100644 index 0000000..d346e8c --- /dev/null +++ b/mon_dtracepipe.h @@ -0,0 +1,25 @@ +/* + clsync - file tree sync utility based on inotify/kqueue + + Copyright (C) 2013-2014 Dmitry Yu Okunev 0x8E30679C + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ + +extern int dtracepipe_init(ctx_t *ctx_p); +extern int dtracepipe_wait(struct ctx *ctx_p, struct indexes *indexes_p, struct timeval *tv_p); +extern int dtracepipe_handle(struct ctx *ctx_p, struct indexes *indexes_p); +extern int dtracepipe_add_watch_dir(struct ctx *ctx_p, struct indexes *indexes_p, const char *const accpath); +extern int dtracepipe_deinit(ctx_t *ctx_p); +