Blame keepalived/check/check_file.c

Packit Service dfccb1
/*
Packit Service dfccb1
 * Soft:        Keepalived is a failover program for the LVS project
Packit Service dfccb1
 *              <www.linuxvirtualserver.org>. It monitor & manipulate
Packit Service dfccb1
 *              a loadbalanced server pool using multi-layer checks.
Packit Service dfccb1
 *
Packit Service dfccb1
 * Part:        FILE CHECK. Monitor contents if a file
Packit Service dfccb1
 *
Packit Service dfccb1
 * Authors:     Quentin Armitage, <quentin@armitage.org.uk>
Packit Service dfccb1
 *
Packit Service dfccb1
 *              This program is distributed in the hope that it will be useful,
Packit Service dfccb1
 *              but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service dfccb1
 *              MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Packit Service dfccb1
 *              See the GNU General Public License for more details.
Packit Service dfccb1
 *
Packit Service dfccb1
 *              This program is free software; you can redistribute it and/or
Packit Service dfccb1
 *              modify it under the terms of the GNU General Public License
Packit Service dfccb1
 *              as published by the Free Software Foundation; either version
Packit Service dfccb1
 *              2 of the License, or (at your option) any later version.
Packit Service dfccb1
 *
Packit Service dfccb1
 * Copyright (C) 2020-2020 Alexandre Cassen, <acassen@gmail.com>
Packit Service dfccb1
 */
Packit Service dfccb1
Packit Service dfccb1
#include "config.h"
Packit Service dfccb1
Packit Service dfccb1
#include <stdio.h>
Packit Service dfccb1
Packit Service dfccb1
#include "check_file.h"
Packit Service dfccb1
#include "check_data.h"
Packit Service dfccb1
#include "track_file.h"
Packit Service dfccb1
#include "parser.h"
Packit Service dfccb1
#include "logger.h"
Packit Service dfccb1
#include "check_data.h"
Packit Service dfccb1
#include "logger.h"
Packit Service dfccb1
#include "main.h"
Packit Service dfccb1
Packit Service dfccb1
Packit Service dfccb1
static void
Packit Service dfccb1
free_file_check(checker_t *checker)
Packit Service dfccb1
{
Packit Service dfccb1
	FREE(checker);
Packit Service dfccb1
}
Packit Service dfccb1
Packit Service dfccb1
static void
Packit Service dfccb1
dump_file_check(FILE *fp, const checker_t *checker)
Packit Service dfccb1
{
Packit Service dfccb1
	tracked_file_t *tfp = checker->data;
Packit Service dfccb1
Packit Service dfccb1
	conf_write(fp, "   Keepalive method = FILE_CHECK");
Packit Service dfccb1
	conf_write(fp, "     Tracked file = %s", tfp->fname);
Packit Service dfccb1
	conf_write(fp, "     Reloaded = %s", tfp->reloaded ? "Yes" : "No");
Packit Service dfccb1
}
Packit Service dfccb1
Packit Service dfccb1
static bool
Packit Service dfccb1
file_check_compare(const checker_t *old_c, checker_t *new_c)
Packit Service dfccb1
{
Packit Service dfccb1
	const tracked_file_t *old = old_c->data;
Packit Service dfccb1
	tracked_file_t *new = new_c->data;
Packit Service dfccb1
Packit Service dfccb1
	if (strcmp(old->file_path, new->file_path))
Packit Service dfccb1
		return false;
Packit Service dfccb1
	if (old->weight != new->weight)
Packit Service dfccb1
		return false;
Packit Service dfccb1
	if (old->weight_reverse != new->weight_reverse)
Packit Service dfccb1
		return false;
Packit Service dfccb1
Packit Service dfccb1
	new->reloaded = true;
Packit Service dfccb1
Packit Service dfccb1
	return true;
Packit Service dfccb1
}
Packit Service dfccb1
Packit Service dfccb1
static void
Packit Service dfccb1
track_file_handler(const vector_t *strvec)
Packit Service dfccb1
{
Packit Service dfccb1
	virtual_server_t *vs = list_last_entry(&check_data->vs, virtual_server_t, e_list);
Packit Service dfccb1
	real_server_t *rs = list_last_entry(&vs->rs, real_server_t, e_list);
Packit Service dfccb1
	tracked_file_monitor_t *tfile;
Packit Service dfccb1
	tracked_file_t *vsf;
Packit Service dfccb1
Packit Service dfccb1
	tfile = list_last_entry(&rs->track_files, tracked_file_monitor_t, e_list);
Packit Service dfccb1
Packit Service dfccb1
	vsf = find_tracked_file_by_name(strvec_slot(strvec, 1), &check_data->track_files);
Packit Service dfccb1
	if (!vsf) {
Packit Service dfccb1
		report_config_error(CONFIG_GENERAL_ERROR, "track_file %s not found", strvec_slot(strvec, 1));
Packit Service dfccb1
		return;
Packit Service dfccb1
	}
Packit Service dfccb1
Packit Service dfccb1
	tfile->file = vsf;
Packit Service dfccb1
}
Packit Service dfccb1
Packit Service dfccb1
static void
Packit Service dfccb1
file_check_handler(__attribute__((unused)) const vector_t *strvec)
Packit Service dfccb1
{
Packit Service dfccb1
	virtual_server_t *vs = list_last_entry(&check_data->vs, virtual_server_t, e_list);
Packit Service dfccb1
	real_server_t *rs = list_last_entry(&vs->rs, real_server_t, e_list);
Packit Service dfccb1
	tracked_file_monitor_t *tfile;
Packit Service dfccb1
Packit Service dfccb1
	PMALLOC(tfile);
Packit Service dfccb1
	INIT_LIST_HEAD(&tfile->e_list);
Packit Service dfccb1
	list_add_tail(&tfile->e_list, &rs->track_files);
Packit Service dfccb1
}
Packit Service dfccb1
Packit Service dfccb1
static void
Packit Service dfccb1
track_file_weight_handler(const vector_t *strvec)
Packit Service dfccb1
{
Packit Service dfccb1
	virtual_server_t *vs = list_last_entry(&check_data->vs, virtual_server_t, e_list);
Packit Service dfccb1
	real_server_t *rs = list_last_entry(&vs->rs, real_server_t, e_list);
Packit Service dfccb1
	tracked_file_monitor_t *tfile;
Packit Service dfccb1
	int weight;
Packit Service dfccb1
	bool reverse = false;
Packit Service dfccb1
Packit Service dfccb1
	tfile = list_last_entry(&rs->track_files, tracked_file_monitor_t, e_list);
Packit Service dfccb1
Packit Service dfccb1
	if (vector_size(strvec) < 2) {
Packit Service dfccb1
		report_config_error(CONFIG_GENERAL_ERROR, "track file weight missing");
Packit Service dfccb1
		return;
Packit Service dfccb1
	}
Packit Service dfccb1
Packit Service dfccb1
	if (!read_int_strvec(strvec, 1, &weight, -IPVS_WEIGHT_MAX, IPVS_WEIGHT_MAX, true)) {
Packit Service dfccb1
		report_config_error(CONFIG_GENERAL_ERROR, "weight for track file must be in "
Packit Service dfccb1
				 "[-IPVS_WEIGHT_MAX..IPVS_WEIGHT_MAX] inclusive. Ignoring...");
Packit Service dfccb1
		return;
Packit Service dfccb1
	}
Packit Service dfccb1
Packit Service dfccb1
	if (vector_size(strvec) >= 3) {
Packit Service dfccb1
		if (!strcmp(strvec_slot(strvec, 2), "reverse"))
Packit Service dfccb1
			reverse = true;
Packit Service dfccb1
		else if (!strcmp(strvec_slot(strvec, 2), "noreverse"))
Packit Service dfccb1
			reverse = false;
Packit Service dfccb1
		else {
Packit Service dfccb1
			report_config_error(CONFIG_GENERAL_ERROR, "unknown track file weight option %s - ignoring",
Packit Service dfccb1
					 strvec_slot(strvec, 2));
Packit Service dfccb1
			return;
Packit Service dfccb1
		}
Packit Service dfccb1
	}
Packit Service dfccb1
Packit Service dfccb1
	tfile->weight = weight;
Packit Service dfccb1
	tfile->weight_reverse = reverse;
Packit Service dfccb1
}
Packit Service dfccb1
Packit Service dfccb1
static void
Packit Service dfccb1
file_end_handler(void)
Packit Service dfccb1
{
Packit Service dfccb1
	virtual_server_t *vs = list_last_entry(&check_data->vs, virtual_server_t, e_list);
Packit Service dfccb1
	real_server_t *rs = list_last_entry(&vs->rs, real_server_t, e_list);
Packit Service dfccb1
	tracked_file_monitor_t *tfile;
Packit Service dfccb1
Packit Service dfccb1
	tfile = list_last_entry(&rs->track_files, tracked_file_monitor_t, e_list);
Packit Service dfccb1
Packit Service dfccb1
	if (!tfile->file) {
Packit Service dfccb1
		report_config_error(CONFIG_GENERAL_ERROR, "FILE_CHECK has no track_file specified - ignoring");
Packit Service dfccb1
		free_track_file_monitor(tfile);
Packit Service dfccb1
		return;
Packit Service dfccb1
	}
Packit Service dfccb1
Packit Service dfccb1
	if (!tfile->weight) {
Packit Service dfccb1
		tfile->weight = tfile->file->weight;
Packit Service dfccb1
		tfile->weight_reverse = tfile->file->weight_reverse;
Packit Service dfccb1
	}
Packit Service dfccb1
}
Packit Service dfccb1
Packit Service dfccb1
void
Packit Service dfccb1
install_file_check_keyword(void)
Packit Service dfccb1
{
Packit Service dfccb1
	install_keyword("FILE_CHECK", &file_check_handler);
Packit Service dfccb1
	install_sublevel();
Packit Service dfccb1
	install_keyword("track_file", &track_file_handler);
Packit Service dfccb1
	install_keyword("weight", &track_file_weight_handler);
Packit Service dfccb1
	install_sublevel_end_handler(&file_end_handler);
Packit Service dfccb1
	install_sublevel_end();
Packit Service dfccb1
}
Packit Service dfccb1
Packit Service dfccb1
void
Packit Service dfccb1
add_rs_to_track_files(void)
Packit Service dfccb1
{
Packit Service dfccb1
	virtual_server_t *vs;
Packit Service dfccb1
	real_server_t *rs;
Packit Service dfccb1
	tracked_file_monitor_t *tfl;
Packit Service dfccb1
	checker_t *new_checker;
Packit Service dfccb1
Packit Service dfccb1
	list_for_each_entry(vs, &check_data->vs, e_list) {
Packit Service dfccb1
		list_for_each_entry(rs, &vs->rs, e_list) {
Packit Service dfccb1
			list_for_each_entry(tfl, &rs->track_files, e_list) {
Packit Service dfccb1
				/* queue new checker */
Packit Service dfccb1
				new_checker = queue_checker(free_file_check, dump_file_check, NULL, file_check_compare, tfl->file, NULL, false);
Packit Service dfccb1
				new_checker->vs = vs;
Packit Service dfccb1
				new_checker->rs = rs;
Packit Service dfccb1
Packit Service dfccb1
				/* There is no concept of the checker running, but we will have
Packit Service dfccb1
				 * checked the file, so mark it as run. */
Packit Service dfccb1
				new_checker->has_run = true;
Packit Service dfccb1
Packit Service dfccb1
				add_obj_to_track_file(new_checker, tfl, FMT_RS(rs, vs), dump_tracking_rs);
Packit Service dfccb1
			}
Packit Service dfccb1
		}
Packit Service dfccb1
	}
Packit Service dfccb1
}
Packit Service dfccb1
Packit Service dfccb1
void
Packit Service dfccb1
set_track_file_checkers_down(void)
Packit Service dfccb1
{
Packit Service dfccb1
	tracked_file_t *tfl;
Packit Service dfccb1
	tracking_obj_t *top;
Packit Service dfccb1
	int status;
Packit Service dfccb1
Packit Service dfccb1
	list_for_each_entry(tfl, &check_data->track_files, e_list) {
Packit Service dfccb1
		if (tfl->last_status) {
Packit Service dfccb1
			list_for_each_entry(top, &tfl->tracking_obj, e_list) {
Packit Service dfccb1
				checker_t *checker = top->obj.checker;
Packit Service dfccb1
Packit Service dfccb1
				if (!top->weight) {
Packit Service dfccb1
					if (reload && !tfl->reloaded) {
Packit Service dfccb1
						/* This is pretty horrible. At some stage this should
Packit Service dfccb1
						 * be tidied up so that it works without having to
Packit Service dfccb1
						 * fudge the values to make update_track_file_status()
Packit Service dfccb1
						 * work for us. */
Packit Service dfccb1
						status = tfl->last_status;
Packit Service dfccb1
						tfl->last_status = 0;
Packit Service dfccb1
						process_update_checker_track_file_status(tfl, !!status == (top->weight_multiplier == 1) ? INT_MIN : 0, top);
Packit Service dfccb1
						tfl->last_status = status;
Packit Service dfccb1
					} else
Packit Service dfccb1
						checker->is_up = false;
Packit Service dfccb1
				}
Packit Service dfccb1
			}
Packit Service dfccb1
		}
Packit Service dfccb1
	}
Packit Service dfccb1
}
Packit Service dfccb1
Packit Service dfccb1
#ifdef THREAD_DUMP
Packit Service dfccb1
void
Packit Service dfccb1
register_check_file_addresses(void)
Packit Service dfccb1
{
Packit Service dfccb1
	register_track_file_inotify_addresses();
Packit Service dfccb1
}
Packit Service dfccb1
#endif