1 /*
2 clsync - file tree sync utility based on inotify/kqueue
3
4 Copyright (C) 2013-2014 Dmitry Yu Okunev <dyokunev@ut.mephi.ru> 0x8E30679C
5
6 This program is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19 #include "common.h"
20 #include "malloc.h"
21 #include "error.h"
22 #include "indexes.h"
23 #include "sync.h"
24 #include "mon_dtracepipe.h"
25
26 #define DTRACE_SCRIPT "BEGIN\
27 {\
28 dir = $1;\
29 dirlen = strlen(dir);\
30 }\
31 \
32 syscall::open*:entry\
33 /\
34 arg1 & (O_WRONLY|O_RDWR) &&\
35 substr(copyinstr(arg0),0,dirlen)==dir\
36 /\
37 {\
38 printf("%s\n",copyinstr(arg0));\
39 }\
40 \
41 syscall::mkdir*:entry\
42 /\
43 substr(copyinstr(arg0),0,dirlen)==dir\
44 /\
45 {\
46 printf("%s\n",copyinstr(arg0));\
47 }"
48
49 struct mondata {
50 FILE *pipe;
51 };
52 typedef struct mondata mondata_t;
53
54 #define DTRACEPIPE_INIT_ERROR {\
55 free(ctx_p->fsmondata);\
56 ctx_p->fsmondata = NULL;\
57 return -1;\
58 }
59
dtracepipe_init(ctx_t * ctx_p)60 int dtracepipe_init(ctx_t *ctx_p) {
61 char cmd[BUFSIZ];
62
63 ctx_p->fsmondata = xcalloc(sizeof(mondata_t), 1);
64 mondata_t *mondata = ctx_p->fsmondata;
65
66 if (snprintf(cmd, "%s -n '%s' '%s'", DTRACE_PATH, DTRACE_SCRIPT, ) >= BUFSIZ) {
67 errno = EMSGSIZE;
68 error("Too long cmd.");
69 DTRACEPIPE_INIT_ERROR;
70 }
71
72 FILE *pipe = popen(cmd, "r");
73 if (pipe == NULL) {
74 error("Cannot popen(\""DTRACE_PATH"\", \"r\")");
75 DTRACEPIPE_INIT_ERROR;
76 }
77
78 if (setvbuf(pipe, NULL, _IONBF, 0)) {
79 error("Cannot set unbuffered mode for pipe of \""DTRACE_PATH"\" process");
80 DTRACEPIPE_INIT_ERROR;
81 }
82
83 mondata->pipe = pipe;
84
85 return 0;
86 }
87
88 char *dtracepipe_wait_line = NULL;
89 size_t dtracepipe_wait_line_siz;
dtracepipe_wait(struct ctx * ctx_p,struct indexes * indexes_p,struct timeval * timeout_p)90 int dtracepipe_wait(struct ctx *ctx_p, struct indexes *indexes_p, struct timeval *timeout_p) {
91 mondata_t *mondata = ctx_p->fsmondata;
92 struct timeval timeout_abs, tv_abs;
93 int dontwait = 0;
94 struct dtracepipe_event *event_p = &mondata->event;
95
96 if (timeout_p->tv_sec == 0 && timeout_p->tv_usec == 0)
97 dontwait = 1;
98
99 if (!dontwait) {
100 gettimeofday(&tv_abs, NULL);
101 timeradd(&tv_abs, timeout_p, &timeout_abs);
102 }
103
104 int pipe_fd = fileno(mondata->pipe);
105
106 while (42) {
107 int path_count;
108
109 // Checking if there already a recond in mondata
110 if (*event_p->path) {
111 debug(2, "we have an event. return 1.");
112 return 1;
113 }
114
115 // Getting a record
116 {
117 debug(3, "select() with timeout %li.%06li secs (dontwait == %u).", timeout_p->tv_sec, timeout_p->tv_usec, dontwait);
118 fd_set rfds;
119 FD_ZERO(&rfds);
120 FD_SET(pipe_fd, &rfds);
121 int rc = select(pipe_fd+1, &rfds, NULL, NULL, timeout_p);
122
123 if (rc == 0 || rc == -1)
124 return rc;
125
126 line_len = getline(&dtracepipe_wait_line, &dtracepipe_wait_line_siz, mondata->pipe);
127 if (line_len == -1) {
128 error("Cannot read line from \""DTRACE_PATH"\" pipe [using getline()]");
129 return -1;
130 }
131
132 if (!dontwait) {
133 debug(5, "old timeout_p->: tv_sec == %lu; tv_usec == %lu", timeout_p->tv_sec, timeout_p->tv_usec);
134 gettimeofday(&tv_abs, NULL);
135 if (timercmp(&timeout_abs, &tv_abs, <))
136 timersub(&timeout_abs, &tv_abs, timeout_p);
137 else
138 memset(timeout_p, 0, sizeof(*timeout_p));
139 debug(5, "new timeout_p->: tv_sec == %lu; tv_usec == %lu", timeout_p->tv_sec, timeout_p->tv_usec);
140 }
141 }
142
143 // Parsing the record
144 path_count = 0;
145 debug(3, "parsing the event");
146 while (au_parsed < au_len) {
147
148 if (au_fetch_tok(&tok, &au_buf[au_parsed], au_len - au_parsed) == -1)
149 return -1;
150 au_parsed += tok.len;
151
152 switch (tok.id) {
153 case AUT_HEADER32:
154 case AUT_HEADER32_EX:
155 case AUT_HEADER64:
156 case AUT_HEADER64_EX: {
157 event_p->type = tok.tt.hdr32.e_type;
158 path_count = 0;
159 break;
160 }
161 case AUT_PATH: {
162 char *ptr;
163 int dir_wd, dir_iswatched;
164
165 ptr = memrchr(tok.tt.path.path, '/', tok.tt.path.len);
166
167 #ifdef PARANOID
168 if (ptr == NULL)
169 critical("relative path received from au_fetch_tok(): \"%s\" (len: %u)", tok.tt.path.path, tok.tt.path.len);
170 #endif
171
172 debug(6, "Event on \"%s\".", tok.tt.path.path);
173 *ptr = 0;
174 dir_wd = indexes_fpath2wd(indexes_p, tok.tt.path.path);
175 dir_iswatched = (dir_wd != -1);
176 debug(7, "Directory is \"%s\". dir_wd == %i; dir_iswatched == %u", tok.tt.path.path, dir_wd, dir_iswatched);
177 *ptr = '/';
178
179 if (dir_iswatched) {
180 debug(5, "Event on \"%s\" is watched. Pushing. path_count == %u", tok.tt.path.path, path_count);
181 switch (path_count) {
182 case 0:
183 memcpy(event_p->path, tok.tt.path.path, tok.tt.path.len+1);
184 break;
185 case 1:
186 memcpy(event_p->path_to, tok.tt.path.path, tok.tt.path.len+1);
187 break;
188 #ifdef PARANOID
189 default:
190 warning("To many paths on BSM event: \"%s\" (already count: %u)", tok.tt.path.path, path_count);
191 break;
192 #endif
193 }
194 }
195 path_count++;
196 break;
197 }
198 default:
199 continue;
200 }
201 }
202
203 // Cleanup
204 debug(4, "clean up");
205 free(au_buf);
206 au_buf = NULL;
207 au_len = 0;
208 au_parsed = 0;
209 }
210 return -1;
211 }
dtracepipe_handle(struct ctx * ctx_p,struct indexes * indexes_p)212 int dtracepipe_handle(struct ctx *ctx_p, struct indexes *indexes_p) {
213 return -1;
214 }
dtracepipe_add_watch_dir(struct ctx * ctx_p,struct indexes * indexes_p,const char * const accpath)215 int dtracepipe_add_watch_dir(struct ctx *ctx_p, struct indexes *indexes_p, const char *const accpath) {
216 return -1;
217 }
dtracepipe_deinit(ctx_t * ctx_p)218 int dtracepipe_deinit(ctx_t *ctx_p) {
219 mondata_t *mondata = ctx_p->fsmondata;
220
221 free(dtracepipe_wait_line);
222 free(mondata);
223
224 return -1;
225 }
226