예제 #1
0
int
test_text_split(test_case *test)
{
	int i, rc;
	char **token;
	Vector tokens;

	rc = 0;

	printf("s=\"%s\" d=\"%s\" f=0x%02X ", test->string, test->delims, test->flags);
	tokens = TextSplit(test->string, test->delims, test->flags);
	if (tokens == NULL) {
		return -1;
	}

	printf("e=%d l=%ld ", test->expect_length, VectorLength(tokens));
	if (test->expect_length != VectorLength(tokens)) {
		rc = -1;
	}

	for (i = 0, token = (char **)VectorBase(tokens); *token != NULL; token++, i++) {
		if (test->expect_items[i] == NULL || strcmp(*token, test->expect_items[i]) != 0)
			rc = -1;
		printf("[%s]", *token);
	}
	if (test->expect_items[i] != NULL)
		rc = -1;

	printf("... %s\n", rc == 0 ? "OK" : "FAIL");
	VectorDestroy(tokens);

	return rc;
}
예제 #2
0
int
main(int argc, char **argv)
{
	Vector v;
	char *delims;
	int i, ch, argi, flags;

	flags = 0;
	delims = NULL;
	
	while ((ch = getopt(argc, argv, "d:f:t")) != -1) {
		switch (ch) {
		case 'd':
			delims = optarg;
			break;
			
		case 'f':
			flags = (int) strtol(optarg, NULL, 0);
			break;
			
		case 't':
			return test_suite();
		
		default:
			optind = argc;
		}
	}
	
	if (argc <= optind) {
		(void) fputs(usage, stderr);
		return EXIT_FAILURE;
	}
	
	for (argi = optind; argi < argc; argi++) {		
		if ((v = TextSplit(argv[argi], delims, flags)) == NULL) {
			(void) fprintf(stderr, "out of memory\n");
			return EXIT_FAILURE;
		}
		
		for (i = 0; i < VectorLength(v); i++)
			(void) printf("%s\n", (char *)VectorGet(v, i));			

		VectorDestroy(v);
	}

	return EXIT_SUCCESS;
}
예제 #3
0
/*
 * Pattern Rule Grammar
 * --------------------
 *
 * line := blank | "#" comment | rule
 *
 * rule := pattern *[ whitespace ] actions
 *
 * whitespace := SPACE | TAB
 *
 * pattern := "/" extended_regex "/"
 *
 * actions := action [ ";" actions ]
 *
 * action := thread | limit | report | on_exceed | on_expire
 *
 * quote := "'" | '"'
 *
 * index := number | quote text quote
 *
 * indices := index [ "," index ]
 *
 * thread := "t=" indices
 *
 * limit := "l=" indices "," max "/" period [ unit ]
 *
 * report := "r=" mail *[ "," mail ]
 *
 * on_exceed := "c=" quoted_shell_command
 *
 * on_expire := "C=" quoted_shell_command
 *
 * quoted_shell_command := quote text quote
 */
static int
init_rule(char *line)
{
	Vector fields;
	const char *next;
	struct pattern_rule *rule;
	int i, rc = -1, err;
	char *field, error[128];

	if (*line != '/')
		goto error0;
	if ((rule = calloc(1, sizeof (*rule))) == NULL)
		goto error0;
	if ((rule->pattern = TokenNext(line, &next, "/", TOKEN_KEEP_ASIS)) == NULL)
		goto error1;
	if ((fields = TextSplit(next, ";", TOKEN_KEEP_ASIS)) == NULL)
		goto error1;

	if ((err = regcomp(&rule->re, rule->pattern, REG_EXTENDED|REG_NEWLINE)) != 0) {
		(void) regerror(err, &rule->re, error, sizeof (error));
		(void) fprintf(stderr, "pattern /%s/: %s (%d)\n", rule->pattern, error, err);
		goto error2;
	}

	/* Assume new previously unknown pattern. */
	if ((err = sqlite3_bind_text(ctx.insert_pattern, 1, rule->pattern, -1, SQLITE_STATIC)) != SQLITE_OK) {
		sql_error(__FILE__, __LINE__, ctx.insert_pattern);
		goto error2;
	}
	if ((err = sql_step(ctx.db, ctx.insert_pattern)) != SQLITE_DONE) {
		sql_error(__FILE__, __LINE__, ctx.insert_pattern);
		goto error2;
	}

	rule->id_pattern = sqlite3_last_insert_rowid(ctx.db);
	(void) sqlite3_clear_bindings(ctx.insert_pattern);
	sqlite3_reset(ctx.insert_pattern);

	/* Last insert rowid is zero if no row was inserted, thus it
	 * already exists and we need to find the pattern number (OID).
	 */
	if (rule->id_pattern == 0) {
		if ((err = sqlite3_bind_text(ctx.find_pattern, 1, rule->pattern, -1, SQLITE_STATIC)) != SQLITE_OK) {
			sql_error(__FILE__, __LINE__, ctx.find_pattern);
			goto error2;
		}
		if ((err = sql_step(ctx.db, ctx.find_pattern)) != SQLITE_ROW) {
			sql_error(__FILE__, __LINE__, ctx.find_pattern);
			goto error2;
		}
		if ((rule->id_pattern = sqlite3_column_int64(ctx.find_pattern, 0)) == 0) {
			sql_error(__FILE__, __LINE__, ctx.find_pattern);
			goto error2;
		}
		(void) sqlite3_clear_bindings(ctx.find_pattern);
                sqlite3_reset(ctx.find_pattern);
	}

	for (i = 0; i < VectorLength(fields); i++) {
		field = VectorGet(fields, i);
		field += strspn(field, " \t");

		switch (*field) {
		case 'c':
			if (field[1] == '=') {
				free(rule->on_exceed);
				rule->on_exceed = VectorReplace(fields, i, NULL);
			}
			break;
		case 'C':
			if (field[1] == '=') {
				free(rule->on_expire);
				rule->on_expire = VectorReplace(fields, i, NULL);
			}
			break;
		case 'r':
			if (field[1] == '=') {
				free(rule->report);
				rule->report = VectorReplace(fields, i, NULL);
			}
			break;
		case 't':
			if (field[1] == '=')
				rule->thread = strtol(field+2, NULL, 10);
			break;
		case 'l':
			if (field[1] == '=')
				continue;
		}

		(void) VectorRemove(fields, i--);
	}

	field[strcspn(field, "\r\n")] = '\0';

	/* What remains of fields should be an empty vector or an array of l= actions. */
	rule->limits = (char **) VectorBase(fields);
	fields = NULL;

	rule->node.data = rule;
	rule->node.free = free_rule;
	listInsertAfter(&pattern_rules, NULL, &rule->node);

	rc = 0;
error2:
	VectorDestroy(fields);
error1:
	if (rc != 0)
		free_rule(rule);
error0:
	return rc;
}
예제 #4
0
static void
limit_report(struct pattern_rule *rule, const char *action, struct limit *limit, const char *line, regmatch_t *parens)
{
        SMTP2 *smtp;
        Vector rcpts;
        int smtp_flags;
	const unsigned char *text;
        char **table, buffer[SMTP_PATH_LENGTH];

	if (0 < debug)
		(void) fprintf(
			stdout, "/%s/ %s: limit exceeded (%d)\n",
			rule->pattern, action, limit->reported + limit->counter
		);

	smtp = NULL;
	rcpts = NULL;
        if (report_to != NULL) {
		rcpts = TextSplit(rule->report != NULL ? strchr(rule->report, '=')+1 : report_to, ",; ", 0);
		 if (VectorLength(rcpts) <= 0) {
			(void) fprintf(stderr, "no report-to mail addresses\n");
			goto error0;
		}

		/* Try to connect to local smart host. */
		smtp_flags = SMTP_FLAG_LOG | (1 < debug ? SMTP_FLAG_DEBUG : 0);
		smtp = smtp2Open(smtp_host, SMTP_CONNECT_TO * UNIT_MILLI, SMTP_COMMAND_TO * UNIT_MILLI, smtp_flags);
		if (smtp == NULL) {
			(void) fprintf(stderr, "%s: %s (%d)\n", smtp_host, strerror(errno), errno);
			goto error1;
		}
		if (smtp2Mail(smtp, report_from) != SMTP_OK) {
			(void) fprintf(stderr, "%s: null sender not accepted\n", smtp_host);
			goto error2;
		}

		for (table = (char **) VectorBase(rcpts); *table != NULL; table++) {
			if (smtp2Rcpt(smtp, *table) != SMTP_OK)
				goto error2;
		}

		TimeStamp(&smtp->start, buffer, sizeof (buffer));
		(void) smtp2Printf(smtp, "Date: %s" CRLF, buffer);
		(void) smtp2Printf(smtp, "From: \"%s\" <%s>" CRLF, _NAME, smtp->sender);
		(void) smtp2Printf(smtp, "Message-ID: <%s@%s>" CRLF, smtp->id_string, smtp->local_ip);
		(void) smtp2Printf(smtp, "Subject: %s log limit exceeded %s" CRLF, _NAME, limit->token);
		(void) smtp2Print(smtp, CRLF, sizeof (CRLF)-1);
		(void) smtp2Printf(
			smtp, "/%s/ %s: limit exceeded (%d)" CRLF CRLF,
			rule->pattern, action, limit->reported + limit->counter
		);
	}

	if (sqlite3_bind_int64(ctx.select_limit_to_log, 1, limit->id_limit) != SQLITE_OK) {
		sql_error(__FILE__, __LINE__, ctx.increment_limit);
                goto error2;
	}
	if (sqlite3_bind_int64(ctx.select_limit_to_log, 2, limit->updated) != SQLITE_OK) {
		sql_error(__FILE__, __LINE__, ctx.increment_limit);
		goto error2;
	}

	while (sql_step(ctx.db, ctx.select_limit_to_log) == SQLITE_ROW) {
		if ((text = sqlite3_column_text(ctx.select_limit_to_log, 0)) == NULL)
			continue;
		if (0 < debug)
			(void) fprintf(stdout, "\t%s" CRLF, text);
		if (smtp != NULL)
			(void) smtp2Printf(smtp, "%s" CRLF, text);
	}

	if (rule->on_exceed != NULL)
		do_command(rule, rule->on_exceed, line, parens);

	(void) sqlite3_clear_bindings(ctx.select_limit_to_log);
	sqlite3_reset(ctx.select_limit_to_log);
	if (smtp != NULL)
		(void) smtp2Dot(smtp);
error2:
	smtp2Close(smtp);
error1:
	VectorDestroy(rcpts);
error0:
	;
}
예제 #5
0
int
main(int argc, char **argv)
{
	int ch, argi;

	while ((ch = getopt(argc, argv, options)) != -1) {
		switch (ch) {
		case '1':
			first_match_only = 1;
			break;

		case 'f':
			follow_flag = 1;
			break;

		case 'F':
			report_from = optarg;
			if (*report_from == '\0')
				report_from = NULL;
			break;

		case 'v':
			debug++;
			break;

		case 'd':
			db_path = optarg;
			break;

		case 'D':
			db_delete = 1;
			break;

		case 'r':
			report_to = optarg;
			break;

		case 'R':
			db_reset = 1;
			break;

		case 's':
			smtp_host = optarg;
			break;

		case 'y':
			assumed_year = strtol(optarg, NULL, 10);
			break;

		case 'z':
			assumed_tz = strtol(optarg, NULL, 10);
			break;

		default:
			(void) printf(usage);
			return EX_USAGE;
		}
	}

	if (argc <= optind || (follow_flag && optind+2 < argc)) {
		(void) printf(usage);
		return EX_USAGE;
	}

	if (1 < debug)
		LogOpen(NULL);

	if (db_path == NULL) {
		(void) snprintf(db_user, sizeof (db_user), DB_PATH_FMT, getuid());
		db_path = db_user;
	}

	if (db_delete)
		(void) unlink(db_path);

	init_today();

	if (atexit(at_exit_cleanup) || init_db(db_path) || init_rules(argv[optind]))
		return EX_SOFTWARE;

	if ((report = TextSplit(report_to, ", ", 0)) == NULL)
		return EX_SOFTWARE;

	if (optind+1 == argc) {
		follow_flag = 0;
		process_file("-");
	} else {
		for (argi = optind+1; argi < argc; argi++)
			process_file(argv[argi]);
	}

	return EXIT_SUCCESS;
}