Blame view

mon_bsm.c 22.9 KB
redmine authored
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
/*
    clsync - file tree sync utility based on inotify/kqueue
    
    Copyright (C) 2013-2014 Dmitry Yu Okunev <dyokunev@ut.mephi.ru> 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 <http://www.gnu.org/licenses/>.
 */

redmine authored
20 21 22 23 24 25
#include "common.h"
#include "malloc.h"
#include "error.h"
#include "indexes.h"
#include "sync.h"
#include "mon_bsm.h"
redmine authored
26

redmine authored
27 28 29
#include <bsm/libbsm.h>
#include <bsm/audit_kevents.h>
#include <glib.h>
Artyom A Anikeev authored
30 31
#include <sys/ioctl.h>
#include <security/audit/audit_ioctl.h>
redmine authored
32

redmine authored
33 34 35 36 37 38
struct bsm_event {
	u_int16_t type;
	char path   [PATH_MAX];
	char path_to[PATH_MAX];
	int w_id;
};
redmine authored
39

redmine authored
40 41 42
struct mondata {
	FILE *pipe;
	int config_fd;
redmine authored
43
	size_t event_count;
redmine authored
44
	size_t event_count_wasinqueue;
redmine authored
45 46
	size_t event_alloc;
	struct bsm_event *event;
redmine authored
47 48
};
typedef struct mondata mondata_t;
redmine authored
49

redmine authored
50 51 52 53 54
enum event_bits {
	UEM_DIR		= 0x01,
	UEM_CREATED	= 0x02,
	UEM_DELETED	= 0x04,
};
redmine authored
55

redmine authored
56 57 58 59 60
enum bsm_handle_type {
	BSM_HANDLER_CALLWAIT,
	BSM_HANDLER_ITERATE,
};

redmine authored
61
struct recognize_event_return {
redmine authored
62 63 64 65 66 67 68 69
	struct {
		eventobjtype_t objtype_old;
		eventobjtype_t objtype_new;
	} f;
	struct {
		eventobjtype_t objtype_old;
		eventobjtype_t objtype_new;
	} t;
redmine authored
70
};
redmine authored
71

redmine authored
72 73 74
pthread_t       prefetcher_thread;
pthread_mutex_t bsm_mutex_prefetcher = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t  bsm_cond_gotevent    = PTHREAD_COND_INITIALIZER;
redmine authored
75
pthread_cond_t  bsm_cond_queueend    = PTHREAD_COND_INITIALIZER;
redmine authored
76 77 78 79 80 81 82 83 84 85 86 87

int bsm_queue_len;

int (*bsm_wait)(struct ctx *ctx_p, struct indexes *indexes_p, struct timeval *timeout_p);
int (*bsm_handle)(struct ctx *ctx_p, struct indexes *indexes_p);

extern int bsm_prefetcher(struct ctx *ctx_p);
extern int bsm_wait_prefetched  (struct ctx *ctx_p, struct indexes *indexes_p, struct timeval *timeout_p);
extern int bsm_wait_noprefetch  (struct ctx *ctx_p, struct indexes *indexes_p, struct timeval *timeout_p);
extern int bsm_handle_prefetched(struct ctx *ctx_p, struct indexes *indexes_p);
extern int bsm_handle_noprefetch(struct ctx *ctx_p, struct indexes *indexes_p);

redmine authored
88
static inline void recognize_event(struct recognize_event_return *r, uint32_t event) {
redmine authored
89 90
	int is_created, is_deleted, is_moved;
	eventobjtype_t type;
redmine authored
91

redmine authored
92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
	type       = EOT_FILE;
	is_moved   = 0;
	is_created = 0;
	is_deleted = 0;
	switch (event) {
		case AUE_MKDIR:
		case AUE_MKDIRAT:
			type       = EOT_DIR;
		case AUE_OPEN_RC:
		case AUE_OPEN_RTC:
		case AUE_OPEN_WC:
		case AUE_OPEN_WTC:
		case AUE_OPEN_RWC:
		case AUE_OPEN_RWTC:
		case AUE_LINK:
		case AUE_LINKAT:
		case AUE_MKFIFO:
		case AUE_MKFIFOAT:
		case AUE_MKNOD:
		case AUE_MKNODAT:
		case AUE_SYMLINK:
		case AUE_SYMLINKAT:
			is_created = 1;
			break;
		case AUE_RMDIR:
#if AUE_RMDIRAT
		case AUE_RMDIRAT:
#endif
			type       = EOT_DIR;
		case AUE_UNLINK:
		case AUE_UNLINKAT:
			is_deleted = 1;
			break;
		case AUE_RENAME:
		case AUE_RENAMEAT:
			type       = EOT_DIR;
			is_moved   = 1;
			break;
		case AUE_CLOSE:
		case AUE_CLOSEFROM:
			break;
		default:
			warning("Unknown event: 0x%x", event);
			break;
	}
redmine authored
137

redmine authored
138
	r->f.objtype_old = type;
redmine authored
139 140

	if (is_moved) {
redmine authored
141 142 143
		r->f.objtype_new = EOT_DOESNTEXIST;
		r->t.objtype_old = EOT_DOESNTEXIST;
		r->t.objtype_new = type;
redmine authored
144

redmine authored
145
		return;
redmine authored
146 147
	}

redmine authored
148
	r->f.objtype_new = type;
redmine authored
149 150

	if (is_created)
redmine authored
151
		r->f.objtype_old = EOT_DOESNTEXIST;
redmine authored
152 153

	if (is_deleted)
redmine authored
154
		r->f.objtype_new = EOT_DOESNTEXIST;
redmine authored
155

redmine authored
156
	return;
redmine authored
157
}
redmine authored
158

redmine authored
159
int auditd_restart() {
redmine authored
160
	debug(1, "Running \""AUDIT_CONTROL_INITSCRIPT" onerestart\"");
redmine authored
161 162 163 164 165 166 167

	pid_t pid = fork();
	switch (pid) {
		case -1: 
			error("Cannot fork().");
			return -1;
		case  0:
redmine authored
168 169 170
			debug(5, "fork: execl(\""AUDIT_CONTROL_INITSCRIPT"\", \""AUDIT_CONTROL_INITSCRIPT"\", \"onerestart\", NULL);", pid);
			execl(AUDIT_CONTROL_INITSCRIPT, AUDIT_CONTROL_INITSCRIPT, "onerestart", NULL);
			error("fork: Cannot execute \""AUDIT_CONTROL_INITSCRIPT" onerestart\"");
redmine authored
171 172 173
			return -1;
	}

redmine authored
174
	debug(6, "Waiting for %u", pid);
redmine authored
175 176 177 178 179 180 181 182
	int status;
	if (waitpid(pid, &status, 0) != pid) {
		error("Cannot waitid().");
		return -1;
	}
	int exitcode = WEXITSTATUS(status);

	if (exitcode)
redmine authored
183
		error("Got error while running \""AUDIT_CONTROL_INITSCRIPT" onerestart\"");
redmine authored
184

redmine authored
185
	debug(4, "exitcode == %u", exitcode);
redmine authored
186 187
	return exitcode;
}
redmine authored
188 189 190 191 192

int bsm_config_backup(mondata_t *mondata) {
	char buf[sizeof(AUDIT_CONTROL_HEADER)];
	int fd = open(AUDIT_CONTROL_PATH, O_RDONLY);

redmine authored
193 194 195 196
	if (fd == -1) {
		debug(4, "Cannot open "AUDIT_CONTROL_PATH". No need for backup.");
		return 1;
	}
redmine authored
197 198 199 200 201

	int r = read(fd, buf, sizeof(AUDIT_CONTROL_HEADER)-1);
	close(fd);

	if (r == sizeof(AUDIT_CONTROL_HEADER)-1)
redmine authored
202 203
		if (!memcmp(buf, AUDIT_CONTROL_HEADER, sizeof(AUDIT_CONTROL_HEADER)-1)) {
			debug(4, "File "AUDIT_CONTROL_PATH" is already clsync-compatible.");
redmine authored
204
			return 0;
redmine authored
205
		}
redmine authored
206 207 208 209 210 211 212


	if (!access(AUDIT_CONTROL_PATH"-clsync_backup", R_OK)) {
		error("File \""AUDIT_CONTROL_PATH"-clsync_backup\" already exists. Cannot backup \""AUDIT_CONTROL_PATH"\".");
		return -1;
	}

redmine authored
213
	debug(3, "mv: "AUDIT_CONTROL_PATH" -> "AUDIT_CONTROL_PATH"-clsync_backup");
redmine authored
214 215 216 217
	rename(AUDIT_CONTROL_PATH, AUDIT_CONTROL_PATH"-clsync_backup");

	close(fd);

redmine authored
218
	return 1;
redmine authored
219 220 221
}

int bsm_config_setup(mondata_t *mondata) {
redmine authored
222 223 224 225 226 227 228 229 230 231
	debug(3, "");
	switch (bsm_config_backup(mondata)) {
		case 0:
			debug(4, "bsm_config_backup(): no reconfig required");
			return 0;
		case -1:
			debug(4, "bsm_config_backup(): error");
			return -1;
	}
	debug(3, "Writting a new audit_control file to \""AUDIT_CONTROL_PATH"\"");
redmine authored
232 233 234 235 236

	mondata->config_fd = open(AUDIT_CONTROL_PATH, O_RDONLY);
	flock(mondata->config_fd, LOCK_SH);

	int fd_w = open(AUDIT_CONTROL_PATH, O_WRONLY|O_CREAT);
redmine authored
237 238
	if (fd_w == -1) {
		error("Cannot open file \""AUDIT_CONTROL_PATH"\" for writing");
redmine authored
239
		return -1;
redmine authored
240
	}
redmine authored
241 242 243 244 245 246 247 248 249

	int w;
	if ((w=write(fd_w, AUDIT_CONTROL_HEADER AUDIT_CONTROL_CONTENT, sizeof(AUDIT_CONTROL_HEADER AUDIT_CONTROL_CONTENT)-1)) != sizeof(AUDIT_CONTROL_HEADER AUDIT_CONTROL_CONTENT)-1) {
		error("Cannot write to \""AUDIT_CONTROL_HEADER AUDIT_CONTROL_CONTENT"\" (%u != %u)", w, sizeof(AUDIT_CONTROL_HEADER AUDIT_CONTROL_CONTENT)-1);
		return -1;
	}

	close(fd_w);

redmine authored
250 251
	if (auditd_restart()) {
		error("Cannot restart auditd to apply a new "AUDIT_CONTROL_PATH);
redmine authored
252
		return -1;
redmine authored
253
	}
redmine authored
254 255 256 257 258

	return 0;
}

int bsm_config_revert(mondata_t *mondata) {
redmine authored
259
	int rc = 0;
redmine authored
260 261 262 263 264 265 266
	int fd = mondata->config_fd;

	flock(fd, LOCK_UN);

	if (flock(fd, LOCK_NB|LOCK_EX))
		return 0;

redmine authored
267
	debug(1, "I'm the last BSM clsync instance.");
redmine authored
268

redmine authored
269 270 271 272
	if (!access(AUDIT_CONTROL_PATH"-clsync_backup", R_OK)) {
		debug(1,"Reverting the audit config file (\""AUDIT_CONTROL_PATH"-clsync_backup\" -> \""AUDIT_CONTROL_PATH"\").");
		rc = rename(AUDIT_CONTROL_PATH"-clsync_backup", AUDIT_CONTROL_PATH);
	}
redmine authored
273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289
	flock(fd, LOCK_UN);

	if (rc) {
		error("Got error while rename(\""AUDIT_CONTROL_PATH"-clsync_backup\", \""AUDIT_CONTROL_PATH"\")");
		return -1;
	}
	return 0;
}


#define BSM_INIT_ERROR {\
	free(ctx_p->fsmondata);\
	ctx_p->fsmondata = NULL;\
	return -1;\
}

int bsm_init(ctx_t *ctx_p) {
Artyom A Anikeev authored
290
	debug(9, "");
redmine authored
291 292 293 294 295 296 297

	ctx_p->fsmondata = xcalloc(sizeof(mondata_t), 1);
	mondata_t *mondata = ctx_p->fsmondata;

	if (bsm_config_setup(mondata) == -1)
		BSM_INIT_ERROR;

Artyom A Anikeev authored
298
	debug(5, "Openning \""AUDITPIPE_PATH"\"");
redmine authored
299 300 301 302 303
	FILE *pipe = fopen(AUDITPIPE_PATH, "r");
	if (pipe == NULL) {
		error("Cannot open \""AUDITPIPE_PATH"\" for reading.");
		BSM_INIT_ERROR;
	}
Artyom A Anikeev authored
304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327

	{
		// Setting auditpipe queue length to be maximal

		int fd;
		u_int len;

		fd = fileno(pipe);

		if (ioctl(fd, AUDITPIPE_GET_QLIMIT_MAX, &len) < 0) {
			error("Cannot read QLIMIT_MAX from auditpipe");
			BSM_INIT_ERROR;
		}

		if (ioctl(fd, AUDITPIPE_SET_QLIMIT, &len) < 0) {
			error("Cannot set QLIMIT through auditpipe");
			BSM_INIT_ERROR;
		}

		if (ioctl(fd, AUDITPIPE_GET_QLIMIT, &len) < 0) {
			error("Cannot read QLIMIT from auditpipe");
			BSM_INIT_ERROR;
		}

redmine authored
328 329
		bsm_queue_len = len;

Artyom A Anikeev authored
330 331
		debug(5, "auditpipe QLIMIT -> %i", (int)len);
	}
redmine authored
332 333 334 335 336
	
	if (setvbuf(pipe, NULL, _IONBF, 0)) {
		error("Cannot set unbuffered mode for auditpipe");
		BSM_INIT_ERROR;
	}
redmine authored
337 338 339

	mondata->pipe = pipe;

redmine authored
340 341 342 343 344 345 346 347 348
	switch (ctx_p->flags[MONITOR]) {
		case NE_BSM:
			bsm_wait   = bsm_wait_noprefetch;
			bsm_handle = bsm_handle_noprefetch;
			mondata->event = xcalloc(sizeof(*mondata->event), 1);
			break;
		case NE_BSM_PREFETCH:
			pthread_mutex_init(&bsm_mutex_prefetcher, NULL);
			pthread_cond_init (&bsm_cond_gotevent,    NULL);
redmine authored
349
			pthread_cond_init (&bsm_cond_queueend,    NULL);
redmine authored
350 351 352 353 354 355 356 357 358
			bsm_wait   = bsm_wait_prefetched;
			bsm_handle = bsm_handle_prefetched;

			critical_on (pthread_create(&prefetcher_thread, NULL, (void *(*)(void *))bsm_prefetcher, ctx_p));
			break;
		default:
			critical("Invalid ctx_p->flags[MONITOR]: %u", ctx_p->flags[MONITOR]);
	}

redmine authored
359 360
	return 0;
}
redmine authored
361 362

int select_rfd(int fd, struct timeval *timeout_p) {
redmine authored
363 364
	int rc;
	debug(9, "%i, {%li, %li}", fd, timeout_p == NULL ? -1 : timeout_p->tv_sec, timeout_p == NULL ? 0 : timeout_p->tv_usec);
redmine authored
365 366 367
	fd_set rfds;
	FD_ZERO(&rfds);
	FD_SET(fd, &rfds);
redmine authored
368 369 370
	rc = select(fd+1, &rfds, NULL, NULL, timeout_p);
	debug(9, "rc -> %i", rc);
	return rc;
redmine authored
371 372 373
}

int bsm_fetch(ctx_t *ctx_p, indexes_t *indexes_p, struct bsm_event *event_p, int pipe_fd, struct timeval *timeout_p, struct timeval *timeout_abs_p) {
redmine authored
374 375
	size_t  au_len;
	size_t  au_parsed;
redmine authored
376
	u_char *au_buf;
redmine authored
377
	tokenstr_t tok;
redmine authored
378 379 380 381 382
	int recalc_timeout;
	static int dont_wait = 0;
	struct timeval tv_abs;
	struct timeval timeout_zero = {0};
	mondata_t *mondata = ctx_p->fsmondata;
redmine authored
383

redmine authored
384 385 386 387
	recalc_timeout = 0;
	if (timeout_p != NULL)
		if (timeout_p->tv_sec != 0 || timeout_p->tv_usec != 0)
			recalc_timeout = 1;
redmine authored
388 389 390

	while (42) {
		int path_count;
redmine authored
391

redmine authored
392
		// Checking if there already a recond in mondata
redmine authored
393 394
		if (*event_p->path) {
			debug(2, "we have an event. return 1.");
redmine authored
395 396 397 398 399
			return 1;
		}

		// Getting a record
		{
redmine authored
400 401 402 403 404 405 406 407
			int rc;

			rc = 0;
			if (dont_wait) {
				debug(4, "select() without waiting");
				rc = select_rfd(pipe_fd, &timeout_zero);
				if (rc == 0) {
					dont_wait = 0;
redmine authored
408 409 410 411 412 413 414 415
					mondata->event_count_wasinqueue = 0;
					switch (ctx_p->flags[MONITOR]) {
						case NE_BSM_PREFETCH:
							pthread_cond_broadcast(&bsm_cond_queueend);
							break;
						default:
							break;
					}
redmine authored
416 417
				} else
				if (rc > 0) {
redmine authored
418 419
					mondata->event_count_wasinqueue++;
					if (mondata->event_count_wasinqueue+1 >= bsm_queue_len)
redmine authored
420 421 422
						critical_or_warning(ctx_p->flags[EXITONSYNCSKIP], "The was too many events in BSM queue (reached kernel BSM queue limit: %u).", bsm_queue_len);
				}
			}
redmine authored
423

redmine authored
424 425 426 427 428 429 430 431 432 433
			if (rc == 0) {
				if (recalc_timeout == 2) {
					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_p, &tv_abs, <))
						timersub(timeout_abs_p, &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);
				}
redmine authored
434

redmine authored
435 436 437 438 439 440
				debug(3, "select() with timeout %li.%06li secs (recalc_timeout == %u).", 
					timeout_p == NULL ? -1 : timeout_p->tv_sec,
					timeout_p == NULL ?  0 : timeout_p->tv_usec,
					recalc_timeout);

				rc = select_rfd(pipe_fd, timeout_p);
redmine authored
441 442
				if (rc > 0)
					mondata->event_count_wasinqueue++;
redmine authored
443

redmine authored
444 445
				if (recalc_timeout == 1)
					recalc_timeout++;
redmine authored
446
			}
redmine authored
447

redmine authored
448 449 450
			critical_on ((rc == -1) && (errno != EINTR));
			if (rc == 0 || rc == -1) {
				debug(3, "rc == %i; errno == %i; return 0", rc, errno);
redmine authored
451
				return 0;
redmine authored
452
			}
redmine authored
453 454 455 456 457

			dont_wait = 1;

			au_len = au_read_rec(mondata->pipe, &au_buf);
			critical_on (au_len == -1);
redmine authored
458 459 460
		}

		// Parsing the record
redmine authored
461
		au_parsed  = 0;
redmine authored
462
		path_count = 0;
Artyom A Anikeev authored
463
		debug(3, "parsing the event (au_parsed == %u; au_len == %u)", au_parsed, au_len);
redmine authored
464
		while (au_parsed < au_len) {
redmine authored
465 466
			critical_on (au_fetch_tok(&tok, &au_buf[au_parsed], au_len - au_parsed) == -1);

redmine authored
467
			au_parsed += tok.len;
Artyom A Anikeev authored
468
			debug(4, "au_fetch_tok(): au_parsed -> %u", tok.len);
redmine authored
469 470 471 472 473 474 475 476 477 478 479 480

			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;
redmine authored
481
					int dir_wd, dir_iswatched;
redmine authored
482 483 484 485 486 487 488 489 490 491

					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;
redmine authored
492 493 494
					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);
redmine authored
495 496 497
					*ptr = '/';

					if (dir_iswatched) {
redmine authored
498
						debug(5, "Event on \"%s\" is watched. Pushing. path_count == %u", tok.tt.path.path, path_count);
redmine authored
499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521
						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
redmine authored
522
		debug(4, "clean up");
redmine authored
523 524 525
		free(au_buf);
	}

redmine authored
526
	critical ("This code shouldn't be reached");
redmine authored
527 528
	return -1;
}
redmine authored
529 530 531 532 533 534
enum bsm_handletype {
	BSM_HANDLE_CALLWAIT,
	BSM_HANDLE_ITERATE,
};
typedef enum bsm_handletype bsm_handletype_t;
int bsm_handle_allevents(struct ctx *ctx_p, struct indexes *indexes_p, bsm_handletype_t how) {
Artyom A Anikeev authored
535
	debug(4, "");
redmine authored
536 537
	static struct timeval tv={0};
	mondata_t *mondata = ctx_p->fsmondata;
redmine authored
538 539 540 541
	int count, event_num;
	char   *path_rel	 = NULL;
	size_t  path_rel_len	 = 0;
	int left_count;
redmine authored
542

redmine authored
543 544
	event_num = 0;
	count     = 0;
redmine authored
545

redmine authored
546 547 548 549
#ifdef PARANOID
	g_hash_table_remove_all(indexes_p->fpath2ei_ht);
#endif

redmine authored
550
	do {
redmine authored
551
		struct  recognize_event_return r = {{0}};
redmine authored
552
		char *path_stat;
redmine authored
553
		struct stat st, *st_p;
redmine authored
554 555
		mode_t st_mode;
		size_t st_size;
redmine authored
556
		struct bsm_event *event_p = &mondata->event[event_num];
redmine authored
557 558 559

#ifdef PARANOID
		if (!*event_p->path && !*event_p->path_to) {
redmine authored
560
			warning("no events are parsed (event_p == %p; mondata->event_count == %i).", event_p, mondata->event_count);
redmine authored
561 562 563 564
			continue;
		}
#endif

redmine authored
565
		recognize_event(&r, event_p->type);
redmine authored
566

redmine authored
567
		if (r.t.objtype_new != EOT_UNKNOWN) 
redmine authored
568 569 570 571
			path_stat = event_p->path_to;
		else 
			path_stat = event_p->path;

redmine authored
572 573 574
		if ((r.t.objtype_new == EOT_DOESNTEXIST) || (ctx_p->flags[CANCEL_SYSCALLS]&CSC_MON_STAT) || lstat(path_stat, &st)) {
			debug(2, "Cannot lstat64(\"%s\", st). Seems, that the object had been deleted (%i) or option \"--cancel-syscalls=mon_stat\" (%i) is set.", path_stat, r.t.objtype_new == EOT_DOESNTEXIST, ctx_p->flags[CANCEL_SYSCALLS]&CSC_MON_STAT);
			if (r.f.objtype_old == EOT_DIR || r.f.objtype_new == EOT_DIR)
redmine authored
575 576 577 578
				st_mode = S_IFDIR;
			else
				st_mode = S_IFREG;
			st_size = 0;
redmine authored
579 580

			st_p    = NULL;
redmine authored
581 582 583
		} else {
			st_mode = st.st_mode;
			st_size = st.st_size;
redmine authored
584 585

			st_p    = &st;
redmine authored
586 587 588
		}

		if (*event_p->path) {
redmine authored
589
			if (sync_prequeue_loadmark(1, ctx_p, indexes_p, event_p->path, NULL, st_p, r.f.objtype_old, r.f.objtype_new, event_p->type, event_p->w_id, st_mode, st_size, &path_rel, &path_rel_len, NULL)) {
redmine authored
590
				error("Got error while load_mark-ing into pre-queue \"%s\"", event_p->path);
redmine authored
591 592 593 594 595
				count = -1;
				*event_p->path = 0;
				break;
			}
			*event_p->path = 0;
redmine authored
596
			count++;
redmine authored
597 598
		}

redmine authored
599
		if ((r.t.objtype_new != EOT_UNKNOWN) && *event_p->path_to) {
redmine authored
600
			if (sync_prequeue_loadmark(1, ctx_p, indexes_p, event_p->path_to, NULL, st_p, r.t.objtype_old, r.t.objtype_new, event_p->type, event_p->w_id, st_mode, st_size, &path_rel, &path_rel_len, NULL)) {
redmine authored
601
				error("Got error while load_mark-ing into pre-queue \"%s\"", event_p->path_to);
redmine authored
602 603 604 605 606
				count = -1;
				*event_p->path_to = 0;
				break;
			}
			*event_p->path_to = 0;
redmine authored
607
			count++;
redmine authored
608
		}
redmine authored
609 610
		switch (how) {
			case BSM_HANDLE_CALLWAIT:
redmine authored
611
				debug(15, "BSM_HANDLE_CALLWAIT");
redmine authored
612 613 614
				left_count = bsm_wait(ctx_p, indexes_p, &tv);
				break;
			case BSM_HANDLE_ITERATE:
redmine authored
615
				debug(15, "BSM_HANDLE_ITERATE");
redmine authored
616 617 618 619
				event_num++;
				left_count = mondata->event_count - event_num;
				break;
		}
redmine authored
620
		debug(10, "left_count: %i; event_num: %i; mondata->event_count: %i", left_count, event_num, mondata->event_count);
redmine authored
621 622 623 624 625 626 627 628 629 630
	} while (left_count > 0);
	switch (how) {
		case BSM_HANDLE_ITERATE:
			if (event_num < mondata->event_count) {
				memmove(
					 mondata->event,
					&mondata->event[event_num],
					sizeof(*mondata->event)*(mondata->event_count - event_num)
				);
			}
redmine authored
631
			mondata->event_count -= event_num;
redmine authored
632 633 634 635
			break;
		default:
			break;
	}
redmine authored
636 637 638 639 640 641 642 643 644 645 646

	free(path_rel);
#ifdef VERYPARANOID
	path_rel     = NULL;
	path_rel_len = 0;
#endif

	// Globally queueing captured events:
	// Moving events from local queue to global ones
	sync_prequeue_unload(ctx_p, indexes_p);

redmine authored
647
	debug(4, "Result processed count: %i (left, mondata->event_count == %i)", count, mondata->event_count);
redmine authored
648 649 650 651
	if (count == -1)
		return -1;

	return count;
redmine authored
652
}
redmine authored
653

redmine authored
654 655 656 657 658 659 660 661
void bsm_prefetcher_sig_int(int signal) {
	debug(2, "signal -> %i. Sending pthread_cond_broadcast() to bsm_cond_gotevent and bsm_cond_queueend.", signal);
	pthread_cond_broadcast(&bsm_cond_gotevent);
	pthread_cond_broadcast(&bsm_cond_queueend);
	return;
}

static int bsm_prefetcher_running=2;
redmine authored
662 663 664 665 666
int bsm_prefetcher(struct ctx *ctx_p) {
	mondata_t *mondata   = ctx_p->fsmondata;
	indexes_t *indexes_p = ctx_p->indexes_p;
	struct bsm_event event, *event_p;

redmine authored
667 668 669
	register_blockthread();
	signal(SIGUSR_BLOPINT,  bsm_prefetcher_sig_int);

redmine authored
670 671 672
	int pipe_fd = fileno(mondata->pipe);
	mondata->event = xcalloc(sizeof(*mondata->event), ALLOC_PORTION);

redmine authored
673 674
	bsm_prefetcher_running = 1;
	while (bsm_prefetcher_running) {
redmine authored
675 676 677
		if (bsm_fetch(ctx_p, indexes_p, &event, pipe_fd, NULL, NULL) > 0) {
			// Pushing the event
			debug(5, "We have an event. Pushing.");
redmine authored
678
#ifdef PARANOID
redmine authored
679
			critical_on (mondata->event_count >= BSM_QUEUE_LENGTH_MAX);
redmine authored
680
#endif
redmine authored
681
			if (mondata->event_count >= mondata->event_alloc) {
redmine authored
682
				debug(2, "Increasing queue length: %u -> %u (limit is "XTOSTR(BSM_QUEUE_LENGTH_MAX)")", mondata->event_alloc, mondata->event_alloc+ALLOC_PORTION);
redmine authored
683 684 685 686
				mondata->event_alloc += ALLOC_PORTION;
				mondata->event = xrealloc(mondata->event, mondata->event_alloc*sizeof(*mondata->event));
				memset(&mondata->event[mondata->event_count], 0, sizeof(*mondata->event)*(mondata->event_alloc - mondata->event_count));
			}
redmine authored
687

redmine authored
688 689 690 691 692 693 694 695 696
			pthread_mutex_lock(&bsm_mutex_prefetcher);
			event_p = &mondata->event[mondata->event_count++];
			memcpy(event_p, &event, sizeof(*event_p));
			debug(2, "event_count -> %u (event_p == %p; event_p->path == \"%s\")", mondata->event_count, event_p, event_p->path);
			pthread_cond_broadcast(&bsm_cond_gotevent);
			pthread_mutex_unlock(&bsm_mutex_prefetcher);

			memset(&event, 0, sizeof(event));
		}
redmine authored
697 698
	}

redmine authored
699
	return 0;
redmine authored
700 701
}
int bsm_wait_prefetched(struct ctx *ctx_p, struct indexes *indexes_p, struct timeval *timeout_p) {
redmine authored
702
	debug(3, "(ctx_p, indexes_p, %p {%u, %u})", timeout_p, timeout_p == NULL?-1:timeout_p->tv_sec, timeout_p == NULL?0:timeout_p->tv_usec);
redmine authored
703 704 705 706 707 708 709
#ifdef PARANOID
	critical_on (timeout_p == NULL);
#endif
	mondata_t *mondata = ctx_p->fsmondata;
	struct timespec ts_abs;
	struct timeval tv_abs, timeout_abs;

redmine authored
710 711 712 713 714
#define INFINITETIME (3600 * 24 * 365 * 10) /* ~10 years */
	if (timeout_p->tv_sec > INFINITETIME)
		timeout_p->tv_sec = INFINITETIME;
#undef INFINITETIME

redmine authored
715 716 717 718 719 720 721 722 723 724 725 726
	gettimeofday(&tv_abs, NULL);
	timeradd(&tv_abs, timeout_p, &timeout_abs);

	ts_abs.tv_sec  = timeout_abs.tv_sec;
	ts_abs.tv_nsec = timeout_abs.tv_usec*1000;

	pthread_mutex_lock(&bsm_mutex_prefetcher);
	if (mondata->event_count) {
		debug(2, "Already have an event. mondata->event_count == %i", mondata->event_count);
		pthread_mutex_unlock(&bsm_mutex_prefetcher);
		return mondata->event_count;
	}
redmine authored
727

redmine authored
728
	if (timeout_p->tv_sec == 0 && timeout_p->tv_sec == 0) {
redmine authored
729 730
		debug(2, "Zero timeout. Waiting for the current queue to be processed.")
		pthread_cond_wait(&bsm_cond_queueend, &bsm_mutex_prefetcher);
redmine authored
731
		pthread_mutex_unlock(&bsm_mutex_prefetcher);
redmine authored
732 733
		debug(3, "return mondata->event_count == %i", mondata->event_count);
		return mondata->event_count;
redmine authored
734
	}
redmine authored
735 736 737 738

//l_pthread_cond_timedwait_restart:
	debug(10, "pthread_cond_timedwait(&bsm_cond_gotevent, &bsm_mutex_prefetcher, {%i, %i})", ts_abs.tv_sec, ts_abs.tv_nsec);
	if ((errno = pthread_cond_timedwait(&bsm_cond_gotevent, &bsm_mutex_prefetcher, &ts_abs))) {
redmine authored
739 740 741 742 743 744 745 746
		pthread_mutex_unlock(&bsm_mutex_prefetcher);
		switch (errno) {
			case ETIMEDOUT:
#ifdef PARANOID
				critical_on (mondata->event_count);
#endif
				debug(2, "Timed out -> no events (mondata->event_count == %i)", mondata->event_count);
				return 0;
redmine authored
747 748 749
/*			case EINTR:
				debug(3, "pthread_cond_timedwait() -> EINTR. Restarting.");
				goto l_pthread_cond_timedwait_restart;*/
redmine authored
750 751 752 753 754 755
			default:
				critical("Got unhandled error on pthread_cond_timedwait()");
		}
	}

	pthread_mutex_unlock(&bsm_mutex_prefetcher);
redmine authored
756
/*#ifdef PARANOID
redmine authored
757
	critical_on (!mondata->event_count);
redmine authored
758 759 760
#endif*/

	debug(2, "%s. mondata->event_count == %i", mondata->event_count?"Got an event":"Got signal SIGUSR_BLOPINT", mondata->event_count);
redmine authored
761 762 763 764
	return mondata->event_count;
}
int bsm_handle_prefetched(struct ctx *ctx_p, struct indexes *indexes_p) {
	int count;
redmine authored
765
	debug(8, "");
redmine authored
766 767 768 769 770 771 772 773

	pthread_mutex_lock(&bsm_mutex_prefetcher);
	count = bsm_handle_allevents(ctx_p, indexes_p, BSM_HANDLE_ITERATE);
	pthread_mutex_unlock(&bsm_mutex_prefetcher);

	return count;
}
int bsm_wait_noprefetch(struct ctx *ctx_p, struct indexes *indexes_p, struct timeval *timeout_p) {
Artyom A Anikeev authored
774
	debug(3, "(ctx_p, indexes_p, %p {%u, %u})", timeout_p, timeout_p == NULL?-1:timeout_p->tv_sec, timeout_p == NULL?0:timeout_p->tv_usec);
redmine authored
775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804
	mondata_t *mondata = ctx_p->fsmondata;
	struct timeval timeout_abs, tv_abs;
	struct bsm_event *event_p = mondata->event;

	if (timeout_p->tv_sec != 0 || timeout_p->tv_usec != 0) {
		gettimeofday(&tv_abs, NULL);
		timeradd(&tv_abs, timeout_p, &timeout_abs);
	}

	int pipe_fd = fileno(mondata->pipe);

	if (*event_p->path) {
		debug(2, "We already have an event. Return 1.");
		return 1;
	}

	if (bsm_fetch(ctx_p, indexes_p, mondata->event, pipe_fd, timeout_p, &timeout_abs) == 0) {
		debug(2, "No events. Return 0");
		return 0;
	}

	if (*event_p->path) {
		debug(2, "We have an event. Return 1.");
		return 1;
	}

	critical ("This code shouldn't be reached");
	return -1;
}
int bsm_handle_noprefetch(struct ctx *ctx_p, struct indexes *indexes_p) {
Artyom A Anikeev authored
805
	debug(3, "");
redmine authored
806 807
	return bsm_handle_allevents(ctx_p, indexes_p, BSM_HANDLE_CALLWAIT);
}
redmine authored
808
int bsm_add_watch_dir(struct ctx *ctx_p, struct indexes *indexes_p, const char *const accpath) {
redmine authored
809 810 811 812 813 814 815 816 817
	static int id = 1;
	if (id == -1)
		id = (int)((unsigned int)~0 >> 2);

	// TODO: optimize this line out:
	while (indexes_wd2fpath(indexes_p, id) != NULL)
		id++;

	return id++;
redmine authored
818 819
}
int bsm_deinit(ctx_t *ctx_p) {
redmine authored
820
	void *ret;
redmine authored
821 822
	int rc = 0;
	mondata_t *mondata = ctx_p->fsmondata;
redmine authored
823

redmine authored
824 825 826 827 828 829
	bsm_prefetcher_running = 0;
	pthread_kill(prefetcher_thread, SIGUSR_BLOPINT);
	pthread_cond_destroy (&bsm_cond_gotevent);
	pthread_mutex_destroy(&bsm_mutex_prefetcher);
	pthread_join(prefetcher_thread, &ret);

redmine authored
830
	rc |= fclose(mondata->pipe);
redmine authored
831

redmine authored
832
	rc |= bsm_config_revert(mondata);
redmine authored
833

redmine authored
834 835 836 837 838 839
	free(ctx_p->fsmondata);
	ctx_p->fsmondata = NULL;

	rc |= auditd_restart();

	return rc;
redmine authored
840 841
}