|
Packit |
7e09eb |
/*
|
|
Packit |
7e09eb |
* Intel(R) Enclosure LED Utilities
|
|
Packit |
7e09eb |
* Copyright (C) 2009-2019 Intel Corporation.
|
|
Packit |
7e09eb |
*
|
|
Packit |
7e09eb |
* This program is free software; you can redistribute it and/or modify it
|
|
Packit |
7e09eb |
* under the terms and conditions of the GNU General Public License,
|
|
Packit |
7e09eb |
* version 2, as published by the Free Software Foundation.
|
|
Packit |
7e09eb |
*
|
|
Packit |
7e09eb |
* This program is distributed in the hope it will be useful, but WITHOUT
|
|
Packit |
7e09eb |
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
Packit |
7e09eb |
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
Packit |
7e09eb |
* more details.
|
|
Packit |
7e09eb |
*
|
|
Packit |
7e09eb |
* You should have received a copy of the GNU General Public License along with
|
|
Packit |
7e09eb |
* this program; if not, write to the Free Software Foundation, Inc.,
|
|
Packit |
7e09eb |
* 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
|
Packit |
7e09eb |
*
|
|
Packit |
7e09eb |
*/
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
#include <errno.h>
|
|
Packit |
7e09eb |
#include <fcntl.h>
|
|
Packit |
7e09eb |
#include <getopt.h>
|
|
Packit |
7e09eb |
#include <limits.h>
|
|
Packit |
7e09eb |
#include <signal.h>
|
|
Packit |
7e09eb |
#include <stdint.h>
|
|
Packit |
7e09eb |
#include <stdio.h>
|
|
Packit |
7e09eb |
#include <stdlib.h>
|
|
Packit |
7e09eb |
#include <string.h>
|
|
Packit |
7e09eb |
#include <sys/param.h>
|
|
Packit |
7e09eb |
#include <sys/select.h>
|
|
Packit |
7e09eb |
#include <sys/stat.h>
|
|
Packit |
7e09eb |
#include <sys/types.h>
|
|
Packit |
7e09eb |
#include <sys/wait.h>
|
|
Packit |
7e09eb |
#include <syslog.h>
|
|
Packit |
7e09eb |
#include <time.h>
|
|
Packit |
7e09eb |
#include <unistd.h>
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
#if _HAVE_DMALLOC_H
|
|
Packit |
7e09eb |
#include <dmalloc.h>
|
|
Packit |
7e09eb |
#endif
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
#include "ahci.h"
|
|
Packit |
7e09eb |
#include "block.h"
|
|
Packit |
7e09eb |
#include "cntrl.h"
|
|
Packit |
7e09eb |
#include "config.h"
|
|
Packit |
7e09eb |
#include "config_file.h"
|
|
Packit |
7e09eb |
#include "ibpi.h"
|
|
Packit |
7e09eb |
#include "list.h"
|
|
Packit |
7e09eb |
#include "pidfile.h"
|
|
Packit |
7e09eb |
#include "raid.h"
|
|
Packit |
7e09eb |
#include "scsi.h"
|
|
Packit |
7e09eb |
#include "slave.h"
|
|
Packit |
7e09eb |
#include "smp.h"
|
|
Packit |
7e09eb |
#include "status.h"
|
|
Packit |
7e09eb |
#include "sysfs.h"
|
|
Packit |
7e09eb |
#include "udev.h"
|
|
Packit |
7e09eb |
#include "utils.h"
|
|
Packit |
7e09eb |
#include "version.h"
|
|
Packit |
7e09eb |
#include "vmdssd.h"
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
/**
|
|
Packit |
7e09eb |
* @brief List of active block devices.
|
|
Packit |
7e09eb |
*
|
|
Packit |
7e09eb |
* This list holds all block devices attached to supported storage controllers.
|
|
Packit |
7e09eb |
* Only devices which have enclosure management feature enabled are on the
|
|
Packit |
7e09eb |
* list, other devices are ignored (except protocol is forced).
|
|
Packit |
7e09eb |
*/
|
|
Packit |
7e09eb |
static struct list ledmon_block_list;
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
/**
|
|
Packit |
7e09eb |
* @brief Daemon process termination flag.
|
|
Packit |
7e09eb |
*
|
|
Packit |
7e09eb |
* This flag indicates that daemon process should terminate. User must send
|
|
Packit |
7e09eb |
* SIGTERM to daemon in order to terminate the process gently.
|
|
Packit |
7e09eb |
*/
|
|
Packit |
7e09eb |
static sig_atomic_t terminate;
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
/**
|
|
Packit |
7e09eb |
* @brief Path to ledmon configuration file.
|
|
Packit |
7e09eb |
*
|
|
Packit |
7e09eb |
* This string contains path of the ledmon configuration file. The value is
|
|
Packit |
7e09eb |
* set to LEDMON_DEF_CONF_FILE by default and it can be changed by command line
|
|
Packit |
7e09eb |
* option.
|
|
Packit |
7e09eb |
*/
|
|
Packit |
7e09eb |
static char *ledmon_conf_path;
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
/**
|
|
Packit |
7e09eb |
* @brief Boolean flag whether to run foreground or not.
|
|
Packit |
7e09eb |
*
|
|
Packit |
7e09eb |
* This flag is turned on with --foreground option. Primary use of this option
|
|
Packit |
7e09eb |
* is to use it in systemd service file.
|
|
Packit |
7e09eb |
*/
|
|
Packit |
7e09eb |
static int foreground;
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
/**
|
|
Packit |
7e09eb |
* @brief Name of IBPI patterns.
|
|
Packit |
7e09eb |
*
|
|
Packit |
7e09eb |
* This is internal array with names of IBPI patterns. Logging routines use this
|
|
Packit |
7e09eb |
* entries to translate enumeration type into the string.
|
|
Packit |
7e09eb |
*/
|
|
Packit |
7e09eb |
const char *ibpi_str[] = {
|
|
Packit |
7e09eb |
[IBPI_PATTERN_UNKNOWN] = "None",
|
|
Packit |
7e09eb |
[IBPI_PATTERN_NORMAL] = "Off",
|
|
Packit |
7e09eb |
[IBPI_PATTERN_ONESHOT_NORMAL] = "Oneshot Off",
|
|
Packit |
7e09eb |
[IBPI_PATTERN_DEGRADED] = "In a Critical Array",
|
|
Packit |
7e09eb |
[IBPI_PATTERN_REBUILD] = "Rebuild",
|
|
Packit |
7e09eb |
[IBPI_PATTERN_FAILED_ARRAY] = "In a Failed Array",
|
|
Packit |
7e09eb |
[IBPI_PATTERN_HOTSPARE] = "Hotspare",
|
|
Packit |
7e09eb |
[IBPI_PATTERN_PFA] = "Predicted Failure Analysis",
|
|
Packit |
7e09eb |
[IBPI_PATTERN_FAILED_DRIVE] = "Failure",
|
|
Packit |
7e09eb |
[IBPI_PATTERN_LOCATE] = "Locate",
|
|
Packit |
7e09eb |
[IBPI_PATTERN_LOCATE_OFF] = "Locate Off",
|
|
Packit |
7e09eb |
[IBPI_PATTERN_ADDED] = "Added",
|
|
Packit |
7e09eb |
[IBPI_PATTERN_REMOVED] = "Removed"
|
|
Packit |
7e09eb |
};
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
/**
|
|
Packit |
7e09eb |
* Internal variable of monitor service. It is the pattern used to print out
|
|
Packit |
7e09eb |
* information about the version of monitor service.
|
|
Packit |
7e09eb |
*/
|
|
Packit |
7e09eb |
static char *ledmon_version = "Intel(R) Enclosure LED Monitor Service %d.%d %s\n"
|
|
Packit |
7e09eb |
"Copyright (C) 2009-2019 Intel Corporation.\n";
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
/**
|
|
Packit |
7e09eb |
* Internal variable of monitor service. It is used to help parse command line
|
|
Packit |
7e09eb |
* short options.
|
|
Packit |
7e09eb |
*/
|
|
Packit |
7e09eb |
static char *shortopt;
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
struct option *longopt;
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
static int possible_params[] = {
|
|
Packit |
7e09eb |
OPT_ALL,
|
|
Packit |
7e09eb |
OPT_CONFIG,
|
|
Packit |
7e09eb |
OPT_DEBUG,
|
|
Packit |
7e09eb |
OPT_ERROR,
|
|
Packit |
7e09eb |
OPT_HELP,
|
|
Packit |
7e09eb |
OPT_INFO,
|
|
Packit |
7e09eb |
OPT_INTERVAL,
|
|
Packit |
7e09eb |
OPT_LOG,
|
|
Packit |
7e09eb |
OPT_QUIET,
|
|
Packit |
7e09eb |
OPT_VERSION,
|
|
Packit |
7e09eb |
OPT_WARNING,
|
|
Packit |
7e09eb |
OPT_LOG_LEVEL,
|
|
Packit |
7e09eb |
OPT_FOREGROUND,
|
|
Packit |
7e09eb |
};
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
static int possible_params_size = sizeof(possible_params)
|
|
Packit |
7e09eb |
/ sizeof(possible_params[0]);
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
/**
|
|
Packit |
7e09eb |
* @brief Monitor service finalize function.
|
|
Packit |
7e09eb |
*
|
|
Packit |
7e09eb |
* This is internal function of monitor service. It is used to finalize daemon
|
|
Packit |
7e09eb |
* process i.e. free allocated memory, unlock and remove pidfile and close log
|
|
Packit |
7e09eb |
* file and syslog. The function is registered as on_exit() handler.
|
|
Packit |
7e09eb |
*
|
|
Packit |
7e09eb |
* @param[in] status The function ignores this parameter.
|
|
Packit |
7e09eb |
* @param[in] program_name The name of the binary file. This argument
|
|
Packit |
7e09eb |
* is passed via on_exit() function.
|
|
Packit |
7e09eb |
*
|
|
Packit |
7e09eb |
* @return The function does not return a value.
|
|
Packit |
7e09eb |
*/
|
|
Packit |
7e09eb |
static void _ledmon_fini(int __attribute__ ((unused)) status, void *program_name)
|
|
Packit |
7e09eb |
{
|
|
Packit |
7e09eb |
sysfs_reset();
|
|
Packit |
7e09eb |
list_erase(&ledmon_block_list);
|
|
Packit |
7e09eb |
log_close();
|
|
Packit |
7e09eb |
pidfile_remove(program_name);
|
|
Packit |
7e09eb |
}
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
/**
|
|
Packit |
7e09eb |
* @brief Puts exit status to a log file.
|
|
Packit |
7e09eb |
*
|
|
Packit |
7e09eb |
* This is internal function of monitor service. It is used to report an exit
|
|
Packit |
7e09eb |
* status of the monitor service. The message is logged in to syslog and to log
|
|
Packit |
7e09eb |
* file. The function is registered as on_exit() hander.
|
|
Packit |
7e09eb |
*
|
|
Packit |
7e09eb |
* @param[in] status Status given in the last call to exit()
|
|
Packit |
7e09eb |
* function.
|
|
Packit |
7e09eb |
* @param[in] arg Argument passed to on_exit().
|
|
Packit |
7e09eb |
*
|
|
Packit |
7e09eb |
* @return The function does not return a value.
|
|
Packit |
7e09eb |
*/
|
|
Packit |
7e09eb |
static void _ledmon_status(int status, void *arg)
|
|
Packit |
7e09eb |
{
|
|
Packit |
7e09eb |
int log_level;
|
|
Packit |
7e09eb |
char message[4096];
|
|
Packit |
7e09eb |
int ignore = *((int *)arg);
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
if (ignore)
|
|
Packit |
7e09eb |
return;
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
if (status == STATUS_SUCCESS)
|
|
Packit |
7e09eb |
log_level = LOG_LEVEL_INFO;
|
|
Packit |
7e09eb |
else
|
|
Packit |
7e09eb |
log_level = LOG_LEVEL_ERROR;
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
snprintf(message, sizeof(message), "exit status is %s.",
|
|
Packit |
7e09eb |
strstatus(status));
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
if (get_log_fd() >= 0)
|
|
Packit |
7e09eb |
_log(log_level, message);
|
|
Packit |
7e09eb |
else
|
|
Packit |
7e09eb |
syslog(log_level_infos[log_level].priority, "%s", message);
|
|
Packit |
7e09eb |
}
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
/**
|
|
Packit |
7e09eb |
* @brief Displays the credits.
|
|
Packit |
7e09eb |
*
|
|
Packit |
7e09eb |
* This is internal function of monitor service. It prints out the name and
|
|
Packit |
7e09eb |
* version of the program. It displays the copyright notice and information
|
|
Packit |
7e09eb |
* about the author and license, too.
|
|
Packit |
7e09eb |
*
|
|
Packit |
7e09eb |
* @return The function does not return a value.
|
|
Packit |
7e09eb |
*/
|
|
Packit |
7e09eb |
static void _ledmon_version(void)
|
|
Packit |
7e09eb |
{
|
|
Packit |
7e09eb |
printf(ledmon_version, VERSION_MAJOR, VERSION_MINOR, BUILD_LABEL);
|
|
Packit |
7e09eb |
printf("\nThis is free software; see the source for copying conditions."
|
|
Packit |
7e09eb |
" There is NO warranty;\nnot even for MERCHANTABILITY or FITNESS"
|
|
Packit |
7e09eb |
" FOR A PARTICULAR PURPOSE.\n\n");
|
|
Packit |
7e09eb |
}
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
/**
|
|
Packit |
7e09eb |
* @brief Displays the help.
|
|
Packit |
7e09eb |
*
|
|
Packit |
7e09eb |
* This is internal function of monitor service. The function prints the name
|
|
Packit |
7e09eb |
* and version of the program out. It displays the usage and available options
|
|
Packit |
7e09eb |
* and its arguments (if any). Each option is described. This is an extract
|
|
Packit |
7e09eb |
* from user manual page.
|
|
Packit |
7e09eb |
*
|
|
Packit |
7e09eb |
* @return The function does not return a value.
|
|
Packit |
7e09eb |
*/
|
|
Packit |
7e09eb |
static void _ledmon_help(void)
|
|
Packit |
7e09eb |
{
|
|
Packit |
7e09eb |
printf(ledmon_version, VERSION_MAJOR, VERSION_MINOR, BUILD_LABEL);
|
|
Packit |
7e09eb |
printf("\nUsage: %s [OPTIONS]\n\n", progname);
|
|
Packit |
7e09eb |
printf("Mandatory arguments for long options are mandatory for short "
|
|
Packit |
7e09eb |
"options, too.\n\n");
|
|
Packit |
7e09eb |
print_opt("--interval=VALUE", "-t VALUE",
|
|
Packit |
7e09eb |
"Set time interval to VALUE seconds.");
|
|
Packit |
7e09eb |
print_opt("", "", "The smallest interval is 5 seconds.");
|
|
Packit |
7e09eb |
print_opt("--config=PATH", "-c PATH",
|
|
Packit |
7e09eb |
"Use alternate configuration file.");
|
|
Packit |
7e09eb |
print_opt("--log=PATH", "-l PATH",
|
|
Packit |
7e09eb |
"Use local log file instead /var/log/ledmon.log");
|
|
Packit |
7e09eb |
print_opt("--log-level=VALUE", "-l VALUE",
|
|
Packit |
7e09eb |
"Allows user to set ledmon verbose level in logs.");
|
|
Packit |
7e09eb |
print_opt("--foreground", "",
|
|
Packit |
7e09eb |
"Do not run as daemon.");
|
|
Packit |
7e09eb |
print_opt("--help", "-h", "Displays this help text.");
|
|
Packit |
7e09eb |
print_opt("--version", "-v",
|
|
Packit |
7e09eb |
"Displays version and license information.");
|
|
Packit |
7e09eb |
printf("\nRefer to ledmon(8) man page for more detailed description.\n");
|
|
Packit |
7e09eb |
printf("Bugs should be reported at: https://github.com/intel/ledmon/issues\n");
|
|
Packit |
7e09eb |
}
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
/**
|
|
Packit |
7e09eb |
* @brief Sets the path to configuration file.
|
|
Packit |
7e09eb |
*
|
|
Packit |
7e09eb |
* This is internal function of monitor service. This function sets the path and
|
|
Packit |
7e09eb |
* name of configuration file. The function is checking whether the given path
|
|
Packit |
7e09eb |
* is valid or it is invalid and should be ignored.
|
|
Packit |
7e09eb |
*
|
|
Packit |
7e09eb |
* @param[in] path the new location and name of config file.
|
|
Packit |
7e09eb |
*
|
|
Packit |
7e09eb |
* @return STATUS_SUCCESS if successful, otherwise a valid status_t status code.
|
|
Packit |
7e09eb |
*/
|
|
Packit |
7e09eb |
static status_t _set_config_path(char **conf_path, const char *path)
|
|
Packit |
7e09eb |
{
|
|
Packit |
7e09eb |
if (!path)
|
|
Packit |
7e09eb |
path = LEDMON_DEF_CONF_FILE;
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
if (*conf_path)
|
|
Packit |
7e09eb |
free(*conf_path);
|
|
Packit |
7e09eb |
*conf_path = str_dup(path);
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
return STATUS_SUCCESS;
|
|
Packit |
7e09eb |
}
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
/**
|
|
Packit |
7e09eb |
* @brief Sets the value of sleep interval.
|
|
Packit |
7e09eb |
*
|
|
Packit |
7e09eb |
* This function is used by command line handler to set new value of time
|
|
Packit |
7e09eb |
* interval, @see time_interval for details.
|
|
Packit |
7e09eb |
*
|
|
Packit |
7e09eb |
* @param[in] optarg String containing the new value of time
|
|
Packit |
7e09eb |
* interval, given in command line option.
|
|
Packit |
7e09eb |
*
|
|
Packit |
7e09eb |
* @return STATUS_SUCCESS if successful, otherwise a valid status_t status code.
|
|
Packit |
7e09eb |
*/
|
|
Packit |
7e09eb |
static status_t _set_sleep_interval(const char *optarg)
|
|
Packit |
7e09eb |
{
|
|
Packit |
7e09eb |
conf.scan_interval = atoi(optarg);
|
|
Packit |
7e09eb |
if (conf.scan_interval < LEDMON_MIN_SLEEP_INTERVAL) {
|
|
Packit |
7e09eb |
log_warning("sleep interval too small... using default.");
|
|
Packit |
7e09eb |
conf.scan_interval = LEDMON_DEF_SLEEP_INTERVAL;
|
|
Packit |
7e09eb |
}
|
|
Packit |
7e09eb |
return STATUS_SUCCESS;
|
|
Packit |
7e09eb |
}
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
/**
|
|
Packit |
7e09eb |
* @brief Reads config file path and checks if command line input contains
|
|
Packit |
7e09eb |
* options which don't require to run ledmon as daemon.
|
|
Packit |
7e09eb |
*
|
|
Packit |
7e09eb |
* This is internal function of monitor service. This function looks for
|
|
Packit |
7e09eb |
* config file path in command line options given to the program from
|
|
Packit |
7e09eb |
* command line interface. It also handles options to print help and version.
|
|
Packit |
7e09eb |
*
|
|
Packit |
7e09eb |
* @param[in] argc - number of arguments.
|
|
Packit |
7e09eb |
* @param[in] argv - array of command line arguments.
|
|
Packit |
7e09eb |
*
|
|
Packit |
7e09eb |
* @return STATUS_SUCCESS if successful, otherwise a valid status_t status code.
|
|
Packit |
7e09eb |
*/
|
|
Packit |
7e09eb |
static status_t _cmdline_parse_non_daemonise(int argc, char *argv[])
|
|
Packit |
7e09eb |
{
|
|
Packit |
7e09eb |
int opt_index = -1;
|
|
Packit |
7e09eb |
int opt = -1;
|
|
Packit |
7e09eb |
status_t status = STATUS_SUCCESS;
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
do {
|
|
Packit |
7e09eb |
opt = getopt_long(argc, argv, shortopt, longopt, &opt_index);
|
|
Packit |
7e09eb |
switch (opt) {
|
|
Packit |
7e09eb |
case 'c':
|
|
Packit |
7e09eb |
status = _set_config_path(&ledmon_conf_path, optarg);
|
|
Packit |
7e09eb |
break;
|
|
Packit |
7e09eb |
case 'h':
|
|
Packit |
7e09eb |
_ledmon_help();
|
|
Packit |
7e09eb |
exit(EXIT_SUCCESS);
|
|
Packit |
7e09eb |
case 'v':
|
|
Packit |
7e09eb |
_ledmon_version();
|
|
Packit |
7e09eb |
exit(EXIT_SUCCESS);
|
|
Packit |
7e09eb |
case ':':
|
|
Packit |
7e09eb |
case '?':
|
|
Packit |
7e09eb |
return STATUS_CMDLINE_ERROR;
|
|
Packit |
7e09eb |
}
|
|
Packit |
7e09eb |
} while (opt >= 0);
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
return status;
|
|
Packit |
7e09eb |
}
|
|
Packit |
7e09eb |
/**
|
|
Packit |
7e09eb |
* @brief Command line interface handler function.
|
|
Packit |
7e09eb |
*
|
|
Packit |
7e09eb |
* This is internal function of monitor service. This function interprets the
|
|
Packit |
7e09eb |
* options and commands given to the program from command line interface.
|
|
Packit |
7e09eb |
*
|
|
Packit |
7e09eb |
* @param[in] argc - number of arguments.
|
|
Packit |
7e09eb |
* @param[in] argv - array of command line arguments.
|
|
Packit |
7e09eb |
*
|
|
Packit |
7e09eb |
* @return STATUS_SUCCESS if successful, otherwise a valid status_t status code.
|
|
Packit |
7e09eb |
*/
|
|
Packit |
7e09eb |
static status_t _cmdline_parse(int argc, char *argv[])
|
|
Packit |
7e09eb |
{
|
|
Packit |
7e09eb |
int opt, opt_index = -1;
|
|
Packit |
7e09eb |
status_t status = STATUS_SUCCESS;
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
optind = 1;
|
|
Packit |
7e09eb |
do {
|
|
Packit |
7e09eb |
opt = getopt_long(argc, argv, shortopt, longopt, &opt_index);
|
|
Packit |
7e09eb |
if (opt == -1)
|
|
Packit |
7e09eb |
break;
|
|
Packit |
7e09eb |
if (opt == 'c')
|
|
Packit |
7e09eb |
continue;
|
|
Packit |
7e09eb |
switch (opt) {
|
|
Packit |
7e09eb |
int log_level;
|
|
Packit |
7e09eb |
case 0:
|
|
Packit |
7e09eb |
switch (get_option_id(longopt[opt_index].name)) {
|
|
Packit |
7e09eb |
case OPT_LOG_LEVEL:
|
|
Packit |
7e09eb |
log_level = get_option_id(optarg);
|
|
Packit |
7e09eb |
if (log_level != -1)
|
|
Packit |
7e09eb |
status = set_verbose_level(log_level);
|
|
Packit |
7e09eb |
else
|
|
Packit |
7e09eb |
status = STATUS_CMDLINE_ERROR;
|
|
Packit |
7e09eb |
break;
|
|
Packit |
7e09eb |
case OPT_FOREGROUND:
|
|
Packit |
7e09eb |
foreground = 1;
|
|
Packit |
7e09eb |
break;
|
|
Packit |
7e09eb |
default:
|
|
Packit |
7e09eb |
status = set_verbose_level(
|
|
Packit |
7e09eb |
possible_params[opt_index]);
|
|
Packit |
7e09eb |
}
|
|
Packit |
7e09eb |
break;
|
|
Packit |
7e09eb |
case 'l':
|
|
Packit |
7e09eb |
status = set_log_path(optarg);
|
|
Packit |
7e09eb |
break;
|
|
Packit |
7e09eb |
case 't':
|
|
Packit |
7e09eb |
status = _set_sleep_interval(optarg);
|
|
Packit |
7e09eb |
break;
|
|
Packit |
7e09eb |
}
|
|
Packit |
7e09eb |
opt_index = -1;
|
|
Packit |
7e09eb |
if (status != STATUS_SUCCESS)
|
|
Packit |
7e09eb |
return status;
|
|
Packit |
7e09eb |
} while (1);
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
return STATUS_SUCCESS;
|
|
Packit |
7e09eb |
}
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
/**
|
|
Packit |
7e09eb |
* @brief SIGTERM handler function.
|
|
Packit |
7e09eb |
*
|
|
Packit |
7e09eb |
* This is internal function of monitor service.
|
|
Packit |
7e09eb |
*
|
|
Packit |
7e09eb |
* @param[in] signum - the number of signal received.
|
|
Packit |
7e09eb |
*
|
|
Packit |
7e09eb |
* @return The function does not return a value.
|
|
Packit |
7e09eb |
*/
|
|
Packit |
7e09eb |
static void _ledmon_sig_term(int signum)
|
|
Packit |
7e09eb |
{
|
|
Packit |
7e09eb |
if (signum == SIGTERM) {
|
|
Packit |
7e09eb |
log_info("SIGTERM caught - terminating daemon process.");
|
|
Packit |
7e09eb |
terminate = 1;
|
|
Packit |
7e09eb |
}
|
|
Packit |
7e09eb |
}
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
/**
|
|
Packit |
7e09eb |
* @brief Configures signal handlers.
|
|
Packit |
7e09eb |
*
|
|
Packit |
7e09eb |
* This is internal function of monitor services. It sets to ignore SIGALRM,
|
|
Packit |
7e09eb |
* SIGHUP and SIGPIPE signals. The function installs a handler for SIGTERM
|
|
Packit |
7e09eb |
* signal. User must send SIGTERM to daemon process in order to shutdown the
|
|
Packit |
7e09eb |
* daemon gently.
|
|
Packit |
7e09eb |
*
|
|
Packit |
7e09eb |
* @return The function does not return a value.
|
|
Packit |
7e09eb |
*/
|
|
Packit |
7e09eb |
static void _ledmon_setup_signals(void)
|
|
Packit |
7e09eb |
{
|
|
Packit |
7e09eb |
struct sigaction act;
|
|
Packit |
7e09eb |
sigset_t sigset;
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
sigemptyset(&sigset);
|
|
Packit |
7e09eb |
sigaddset(&sigset, SIGALRM);
|
|
Packit |
7e09eb |
sigaddset(&sigset, SIGHUP);
|
|
Packit |
7e09eb |
sigaddset(&sigset, SIGTERM);
|
|
Packit |
7e09eb |
sigaddset(&sigset, SIGPIPE);
|
|
Packit |
7e09eb |
sigaddset(&sigset, SIGUSR1);
|
|
Packit |
7e09eb |
sigprocmask(SIG_BLOCK, &sigset, NULL);
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
act.sa_handler = SIG_IGN;
|
|
Packit |
7e09eb |
act.sa_flags = 0;
|
|
Packit |
7e09eb |
sigemptyset(&act.sa_mask);
|
|
Packit |
7e09eb |
sigaction(SIGALRM, &act, NULL);
|
|
Packit |
7e09eb |
sigaction(SIGHUP, &act, NULL);
|
|
Packit |
7e09eb |
sigaction(SIGPIPE, &act, NULL);
|
|
Packit |
7e09eb |
act.sa_handler = _ledmon_sig_term;
|
|
Packit |
7e09eb |
sigaction(SIGTERM, &act, NULL);
|
|
Packit |
7e09eb |
sigaction(SIGUSR1, &act, NULL);
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
sigprocmask(SIG_UNBLOCK, &sigset, NULL);
|
|
Packit |
7e09eb |
}
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
/**
|
|
Packit |
7e09eb |
* @brief Puts the calling process into sleep.
|
|
Packit |
7e09eb |
*
|
|
Packit |
7e09eb |
* This is internal function of monitor service. The function puts the calling
|
|
Packit |
7e09eb |
* process into a sleep for the given amount of time (expressed in seconds). The
|
|
Packit |
7e09eb |
* function will give control back to the process as soon as time elapses or
|
|
Packit |
7e09eb |
* SIGTERM occurs.
|
|
Packit |
7e09eb |
*
|
|
Packit |
7e09eb |
* @param[in] seconds - the time interval given in seconds.
|
|
Packit |
7e09eb |
*
|
|
Packit |
7e09eb |
* @return The function does not return a value.
|
|
Packit |
7e09eb |
*/
|
|
Packit |
7e09eb |
static void _ledmon_wait(int seconds)
|
|
Packit |
7e09eb |
{
|
|
Packit |
7e09eb |
int fd, udev_fd, max_fd, res;
|
|
Packit |
7e09eb |
fd_set rdfds, exfds;
|
|
Packit |
7e09eb |
struct timespec timeout;
|
|
Packit |
7e09eb |
sigset_t sigset;
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
sigprocmask(SIG_UNBLOCK, NULL, &sigset);
|
|
Packit |
7e09eb |
sigdelset(&sigset, SIGTERM);
|
|
Packit |
7e09eb |
timeout.tv_nsec = 0;
|
|
Packit |
7e09eb |
timeout.tv_sec = seconds;
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
fd = open("/proc/mdstat", O_RDONLY);
|
|
Packit |
7e09eb |
udev_fd = get_udev_monitor();
|
|
Packit |
7e09eb |
max_fd = MAX(fd, udev_fd) + 1;
|
|
Packit |
7e09eb |
do {
|
|
Packit |
7e09eb |
FD_ZERO(&rdfds);
|
|
Packit |
7e09eb |
FD_ZERO(&exfds);
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
if (fd > 0)
|
|
Packit |
7e09eb |
FD_SET(fd, &exfds);
|
|
Packit |
7e09eb |
if (udev_fd > 0)
|
|
Packit |
7e09eb |
FD_SET(udev_fd, &rdfds);
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
res = pselect(max_fd, &rdfds, NULL, &exfds, &timeout, &sigset);
|
|
Packit |
7e09eb |
if (terminate || !FD_ISSET(udev_fd, &rdfds) ||
|
|
Packit |
7e09eb |
handle_udev_event(&ledmon_block_list) <= 0)
|
|
Packit |
7e09eb |
break;
|
|
Packit |
7e09eb |
} while (res > 0);
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
if (fd >= 0)
|
|
Packit |
7e09eb |
close(fd);
|
|
Packit |
7e09eb |
}
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
/**
|
|
Packit |
7e09eb |
* @brief Determine failed state by comparing saved block device with new
|
|
Packit |
7e09eb |
* scanned.
|
|
Packit |
7e09eb |
*
|
|
Packit |
7e09eb |
* This is internal function of monitor service. Due race conditions related
|
|
Packit |
7e09eb |
* with removing files from /sys/block/md* when raid is stopped or disk is
|
|
Packit |
7e09eb |
* failed, this function analyse state of every block device between scans.
|
|
Packit |
7e09eb |
*
|
|
Packit |
7e09eb |
* @param[in] block Pointer to new (scanned) block device
|
|
Packit |
7e09eb |
* structure.
|
|
Packit |
7e09eb |
* @param[in] temp Pointer to previously saved state of block
|
|
Packit |
7e09eb |
* device structure.
|
|
Packit |
7e09eb |
*
|
|
Packit |
7e09eb |
* @return The function does not return a value.
|
|
Packit |
7e09eb |
*/
|
|
Packit |
7e09eb |
static void _handle_fail_state(struct block_device *block,
|
|
Packit |
7e09eb |
struct block_device *temp)
|
|
Packit |
7e09eb |
{
|
|
Packit |
7e09eb |
struct raid_device *temp_raid_device = NULL;
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
if (!temp->raid_dev)
|
|
Packit |
7e09eb |
/*
|
|
Packit |
7e09eb |
* Device is a RAID member now, so keep information about
|
|
Packit |
7e09eb |
* related with device RAID.
|
|
Packit |
7e09eb |
*/
|
|
Packit |
7e09eb |
temp->raid_dev = raid_device_duplicate(block->raid_dev);
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
if (!temp->raid_dev)
|
|
Packit |
7e09eb |
return;
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
temp_raid_device = find_raid_device(sysfs_get_volumes(),
|
|
Packit |
7e09eb |
temp->raid_dev->sysfs_path);
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
if (!block->raid_dev) {
|
|
Packit |
7e09eb |
if (temp->raid_dev->type == DEVICE_TYPE_VOLUME &&
|
|
Packit |
7e09eb |
temp_raid_device) {
|
|
Packit |
7e09eb |
/*
|
|
Packit |
7e09eb |
* Device is outside of the volume, but related raid
|
|
Packit |
7e09eb |
* still exist, so disk has been removed from volume -
|
|
Packit |
7e09eb |
* blink fail LED. It is case when drive is removed
|
|
Packit |
7e09eb |
* by mdadm -If.
|
|
Packit |
7e09eb |
*/
|
|
Packit |
7e09eb |
temp->ibpi = IBPI_PATTERN_FAILED_DRIVE;
|
|
Packit |
7e09eb |
/*
|
|
Packit |
7e09eb |
* Changing failed state to hotspare will be prevent by
|
|
Packit |
7e09eb |
* code from _add_block function. If disk come back to
|
|
Packit |
7e09eb |
* container failed state should be removed. By setting
|
|
Packit |
7e09eb |
* type to CONTAINER ledmon can react in this case.
|
|
Packit |
7e09eb |
*/
|
|
Packit |
7e09eb |
temp->raid_dev->type = DEVICE_TYPE_CONTAINER;
|
|
Packit |
7e09eb |
} else {
|
|
Packit |
7e09eb |
/*
|
|
Packit |
7e09eb |
* Device was RAID member and was failed (was outside
|
|
Packit |
7e09eb |
* of array and container). Now again is in container.
|
|
Packit |
7e09eb |
* Release object to perform hotspare state.
|
|
Packit |
7e09eb |
* Or:
|
|
Packit |
7e09eb |
* Device is outside of the volume, but related raid is
|
|
Packit |
7e09eb |
* removed (or stopped) so device is no longer a RAID
|
|
Packit |
7e09eb |
* member.
|
|
Packit |
7e09eb |
*/
|
|
Packit |
7e09eb |
raid_device_fini(temp->raid_dev);
|
|
Packit |
7e09eb |
temp->raid_dev = NULL;
|
|
Packit |
7e09eb |
}
|
|
Packit |
7e09eb |
} else if (block->raid_dev) {
|
|
Packit |
7e09eb |
if (temp->raid_dev->type == DEVICE_TYPE_VOLUME &&
|
|
Packit |
7e09eb |
block->raid_dev->type == DEVICE_TYPE_CONTAINER) {
|
|
Packit |
7e09eb |
/*
|
|
Packit |
7e09eb |
* Drive is removed from volume, but still exist
|
|
Packit |
7e09eb |
* in container.
|
|
Packit |
7e09eb |
*/
|
|
Packit |
7e09eb |
enum raid_level new_level;
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
if (!temp_raid_device)
|
|
Packit |
7e09eb |
new_level = RAID_LEVEL_UNKNOWN;
|
|
Packit |
7e09eb |
else
|
|
Packit |
7e09eb |
new_level = temp_raid_device->level;
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
if ((temp->raid_dev->level == RAID_LEVEL_10 ||
|
|
Packit |
7e09eb |
temp->raid_dev->level == RAID_LEVEL_1) &&
|
|
Packit |
7e09eb |
new_level == RAID_LEVEL_0) {
|
|
Packit |
7e09eb |
/*
|
|
Packit |
7e09eb |
* Device is removed from volume due to
|
|
Packit |
7e09eb |
* migration to raid. State of this disk is
|
|
Packit |
7e09eb |
* hotspare now.
|
|
Packit |
7e09eb |
*/
|
|
Packit |
7e09eb |
temp->ibpi = IBPI_PATTERN_HOTSPARE;
|
|
Packit |
7e09eb |
} else {
|
|
Packit |
7e09eb |
/*
|
|
Packit |
7e09eb |
* Trasitions other than raid 0 migration.
|
|
Packit |
7e09eb |
* Like reshape, volume stopping etc.
|
|
Packit |
7e09eb |
*/
|
|
Packit |
7e09eb |
if (temp_raid_device) {
|
|
Packit |
7e09eb |
/*
|
|
Packit |
7e09eb |
* Drive is removed from volume,
|
|
Packit |
7e09eb |
* but still exist in container. This
|
|
Packit |
7e09eb |
* situation can be caused by bad
|
|
Packit |
7e09eb |
* blocks or calling mdadm
|
|
Packit |
7e09eb |
* --set-faulty.
|
|
Packit |
7e09eb |
*/
|
|
Packit |
7e09eb |
temp->ibpi = IBPI_PATTERN_FAILED_DRIVE;
|
|
Packit |
7e09eb |
}
|
|
Packit |
7e09eb |
}
|
|
Packit |
7e09eb |
} else if (temp->raid_dev->type == DEVICE_TYPE_CONTAINER &&
|
|
Packit |
7e09eb |
block->raid_dev->type == DEVICE_TYPE_VOLUME) {
|
|
Packit |
7e09eb |
/*
|
|
Packit |
7e09eb |
* Disk was in container and is added to volume.
|
|
Packit |
7e09eb |
* Release object for recreating.
|
|
Packit |
7e09eb |
*/
|
|
Packit |
7e09eb |
raid_device_fini(temp->raid_dev);
|
|
Packit |
7e09eb |
temp->raid_dev =
|
|
Packit |
7e09eb |
raid_device_duplicate(block->raid_dev);
|
|
Packit |
7e09eb |
}
|
|
Packit |
7e09eb |
}
|
|
Packit |
7e09eb |
}
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
/**
|
|
Packit |
7e09eb |
* @brief Adds the block device to list.
|
|
Packit |
7e09eb |
*
|
|
Packit |
7e09eb |
* This is internal function of monitor service. The function adds a block
|
|
Packit |
7e09eb |
* device to the ledmon_block_list list or if the device is already on the list
|
|
Packit |
7e09eb |
* it updates the IBPI state of the given device. The function updates timestamp
|
|
Packit |
7e09eb |
* value which indicates the time of last structure modification. The function
|
|
Packit |
7e09eb |
* is design to be used as 'action' parameter of list_for_each() function.
|
|
Packit |
7e09eb |
* Each change of state is logged to the file and to the syslog.
|
|
Packit |
7e09eb |
*
|
|
Packit |
7e09eb |
* @param[in] block Pointer to block device structure.
|
|
Packit |
7e09eb |
*
|
|
Packit |
7e09eb |
* @return The function does not return a value.
|
|
Packit |
7e09eb |
*/
|
|
Packit |
7e09eb |
static void _add_block(struct block_device *block)
|
|
Packit |
7e09eb |
{
|
|
Packit |
7e09eb |
struct block_device *temp = NULL;
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
list_for_each(&ledmon_block_list, temp) {
|
|
Packit |
7e09eb |
if (block_compare(temp, block))
|
|
Packit |
7e09eb |
break;
|
|
Packit |
7e09eb |
temp = NULL;
|
|
Packit |
7e09eb |
}
|
|
Packit |
7e09eb |
if (temp) {
|
|
Packit |
7e09eb |
enum ibpi_pattern ibpi = temp->ibpi;
|
|
Packit |
7e09eb |
temp->timestamp = block->timestamp;
|
|
Packit |
7e09eb |
if (temp->ibpi == IBPI_PATTERN_ADDED) {
|
|
Packit |
7e09eb |
temp->ibpi = IBPI_PATTERN_ONESHOT_NORMAL;
|
|
Packit |
7e09eb |
} else if (temp->ibpi == IBPI_PATTERN_ONESHOT_NORMAL) {
|
|
Packit |
7e09eb |
temp->ibpi = IBPI_PATTERN_UNKNOWN;
|
|
Packit |
7e09eb |
} else if (temp->ibpi != IBPI_PATTERN_FAILED_DRIVE) {
|
|
Packit |
7e09eb |
if (block->ibpi == IBPI_PATTERN_UNKNOWN) {
|
|
Packit |
7e09eb |
if ((temp->ibpi != IBPI_PATTERN_UNKNOWN) &&
|
|
Packit |
7e09eb |
(temp->ibpi != IBPI_PATTERN_NORMAL)) {
|
|
Packit |
7e09eb |
temp->ibpi =
|
|
Packit |
7e09eb |
IBPI_PATTERN_ONESHOT_NORMAL;
|
|
Packit |
7e09eb |
} else {
|
|
Packit |
7e09eb |
temp->ibpi = IBPI_PATTERN_UNKNOWN;
|
|
Packit |
7e09eb |
}
|
|
Packit |
7e09eb |
} else {
|
|
Packit |
7e09eb |
temp->ibpi = block->ibpi;
|
|
Packit |
7e09eb |
}
|
|
Packit |
7e09eb |
} else if (!(temp->ibpi == IBPI_PATTERN_FAILED_DRIVE &&
|
|
Packit |
7e09eb |
block->ibpi == IBPI_PATTERN_HOTSPARE) ||
|
|
Packit |
7e09eb |
(temp->ibpi == IBPI_PATTERN_FAILED_DRIVE &&
|
|
Packit |
7e09eb |
block->ibpi == IBPI_PATTERN_NONE)) {
|
|
Packit |
7e09eb |
temp->ibpi = block->ibpi;
|
|
Packit |
7e09eb |
}
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
_handle_fail_state(block, temp);
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
if (ibpi != temp->ibpi && ibpi <= IBPI_PATTERN_REMOVED) {
|
|
Packit |
7e09eb |
log_info("CHANGE %s: from '%s' to '%s'.",
|
|
Packit |
7e09eb |
temp->sysfs_path, ibpi2str(ibpi),
|
|
Packit |
7e09eb |
ibpi2str(temp->ibpi));
|
|
Packit |
7e09eb |
}
|
|
Packit |
7e09eb |
/* Check if name of the device changed.*/
|
|
Packit |
7e09eb |
if (strcmp(temp->sysfs_path, block->sysfs_path)) {
|
|
Packit |
7e09eb |
log_info("NAME CHANGED %s to %s",
|
|
Packit |
7e09eb |
temp->sysfs_path, block->sysfs_path);
|
|
Packit |
7e09eb |
free(temp->sysfs_path);
|
|
Packit |
7e09eb |
temp->sysfs_path = str_dup(block->sysfs_path);
|
|
Packit |
7e09eb |
}
|
|
Packit |
7e09eb |
} else {
|
|
Packit |
7e09eb |
/* Device not found, it's a new one! */
|
|
Packit |
7e09eb |
temp = block_device_duplicate(block);
|
|
Packit |
7e09eb |
if (temp != NULL) {
|
|
Packit |
7e09eb |
log_info("NEW %s: state '%s'.", temp->sysfs_path,
|
|
Packit |
7e09eb |
ibpi2str(temp->ibpi));
|
|
Packit |
7e09eb |
list_append(&ledmon_block_list, temp);
|
|
Packit |
7e09eb |
}
|
|
Packit |
7e09eb |
}
|
|
Packit |
7e09eb |
}
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
/**
|
|
Packit |
7e09eb |
* @brief Sends LED control message.
|
|
Packit |
7e09eb |
*
|
|
Packit |
7e09eb |
* This is internal function of monitor service. The function sends a LED
|
|
Packit |
7e09eb |
* command to storage controller or enclosure device. The function checks
|
|
Packit |
7e09eb |
* the time of last modification of block device structure. If the timestamp
|
|
Packit |
7e09eb |
* is different then the current global timestamp this means the device is
|
|
Packit |
7e09eb |
* missing due to hot-remove or hardware failure so it must be reported on
|
|
Packit |
7e09eb |
* LEDs appropriately. Note that controller device and host attached to this
|
|
Packit |
7e09eb |
* block device points to invalid pointer so it must be 'refreshed'.
|
|
Packit |
7e09eb |
*
|
|
Packit |
7e09eb |
* @param[in] block Pointer to block device structure.
|
|
Packit |
7e09eb |
*
|
|
Packit |
7e09eb |
* @return The function does not return a value.
|
|
Packit |
7e09eb |
*/
|
|
Packit |
7e09eb |
static void _send_msg(struct block_device *block)
|
|
Packit |
7e09eb |
{
|
|
Packit |
7e09eb |
if (!block->cntrl) {
|
|
Packit |
7e09eb |
log_debug("Missing cntrl for dev: %s. Not sending anything.",
|
|
Packit |
7e09eb |
strstr(block->sysfs_path, "host"));
|
|
Packit |
7e09eb |
return;
|
|
Packit |
7e09eb |
}
|
|
Packit |
7e09eb |
if (block->timestamp != timestamp ||
|
|
Packit |
7e09eb |
block->ibpi == IBPI_PATTERN_REMOVED) {
|
|
Packit |
7e09eb |
if (block->ibpi != IBPI_PATTERN_FAILED_DRIVE) {
|
|
Packit |
7e09eb |
log_info("CHANGE %s: from '%s' to '%s'.",
|
|
Packit |
7e09eb |
block->sysfs_path, ibpi2str(block->ibpi),
|
|
Packit |
7e09eb |
ibpi2str(IBPI_PATTERN_FAILED_DRIVE));
|
|
Packit |
7e09eb |
block->ibpi = IBPI_PATTERN_FAILED_DRIVE;
|
|
Packit |
7e09eb |
} else {
|
|
Packit |
7e09eb |
char *host = strstr(block->sysfs_path, "host");
|
|
Packit |
7e09eb |
log_debug("DETACHED DEV '%s' in failed state",
|
|
Packit |
7e09eb |
host ? host : block->sysfs_path);
|
|
Packit |
7e09eb |
}
|
|
Packit |
7e09eb |
}
|
|
Packit |
7e09eb |
block->send_fn(block, block->ibpi);
|
|
Packit |
7e09eb |
block->ibpi_prev = block->ibpi;
|
|
Packit |
7e09eb |
}
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
static void _flush_msg(struct block_device *block)
|
|
Packit |
7e09eb |
{
|
|
Packit |
7e09eb |
if (!block->cntrl)
|
|
Packit |
7e09eb |
return;
|
|
Packit |
7e09eb |
block->flush_fn(block);
|
|
Packit |
7e09eb |
}
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
static void _revalidate_dev(struct block_device *block)
|
|
Packit |
7e09eb |
{
|
|
Packit |
7e09eb |
/* Bring back controller and host to the device. */
|
|
Packit |
7e09eb |
block->cntrl = block_get_controller(sysfs_get_cntrl_devices(),
|
|
Packit |
7e09eb |
block->cntrl_path);
|
|
Packit |
7e09eb |
if (!block->cntrl) {
|
|
Packit |
7e09eb |
/* It could be removed VMD drive */
|
|
Packit |
7e09eb |
log_debug("Failed to get controller for dev: %s, ctrl path: %s",
|
|
Packit |
7e09eb |
block->sysfs_path, block->cntrl_path);
|
|
Packit |
7e09eb |
return;
|
|
Packit |
7e09eb |
}
|
|
Packit |
7e09eb |
if (block->cntrl->cntrl_type == CNTRL_TYPE_SCSI) {
|
|
Packit |
7e09eb |
block->host = block_get_host(block->cntrl, block->host_id);
|
|
Packit |
7e09eb |
if (block->host) {
|
|
Packit |
7e09eb |
if (dev_directly_attached(block->sysfs_path))
|
|
Packit |
7e09eb |
cntrl_init_smp(NULL, block->cntrl);
|
|
Packit |
7e09eb |
else
|
|
Packit |
7e09eb |
scsi_get_enclosure(block);
|
|
Packit |
7e09eb |
} else {
|
|
Packit |
7e09eb |
log_debug("Failed to get host for dev: %s, hostId: %d",
|
|
Packit |
7e09eb |
block->sysfs_path, block->host_id);
|
|
Packit |
7e09eb |
/* If failed, invalidate cntrl */
|
|
Packit |
7e09eb |
block->cntrl = NULL;
|
|
Packit |
7e09eb |
}
|
|
Packit |
7e09eb |
}
|
|
Packit |
7e09eb |
return;
|
|
Packit |
7e09eb |
}
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
static void _invalidate_dev(struct block_device *block)
|
|
Packit |
7e09eb |
{
|
|
Packit |
7e09eb |
/* Those fields are valid only per 'session' - through single scan. */
|
|
Packit |
7e09eb |
block->cntrl = NULL;
|
|
Packit |
7e09eb |
block->host = NULL;
|
|
Packit |
7e09eb |
block->enclosure = NULL;
|
|
Packit |
7e09eb |
block->encl_index = -1;
|
|
Packit |
7e09eb |
}
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
static void _check_block_dev(struct block_device *block, int *restart)
|
|
Packit |
7e09eb |
{
|
|
Packit |
7e09eb |
if (!block->cntrl) {
|
|
Packit |
7e09eb |
(*restart)++;
|
|
Packit |
7e09eb |
}
|
|
Packit |
7e09eb |
}
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
/**
|
|
Packit |
7e09eb |
* @brief Sets a list of block devices and sends LED control messages.
|
|
Packit |
7e09eb |
*
|
|
Packit |
7e09eb |
* This is internal function of monitor service. Based on current layout of
|
|
Packit |
7e09eb |
* sysfs tree the function extracts block devices and for each block device it
|
|
Packit |
7e09eb |
* send LED control message to storage controller or enclosure. The message is
|
|
Packit |
7e09eb |
* determine by appropriate field in block device's structure. See _add_block()
|
|
Packit |
7e09eb |
* and _send_msg() functions description for more details.
|
|
Packit |
7e09eb |
*
|
|
Packit |
7e09eb |
* @return The function does not return a value.
|
|
Packit |
7e09eb |
*/
|
|
Packit |
7e09eb |
static void _ledmon_execute(void)
|
|
Packit |
7e09eb |
{
|
|
Packit |
7e09eb |
int restart = 0; /* ledmon_block_list needs restart? */
|
|
Packit |
7e09eb |
struct block_device *device;
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
/* Revalidate each device in the list. Bring back controller and host */
|
|
Packit |
7e09eb |
list_for_each(&ledmon_block_list, device)
|
|
Packit |
7e09eb |
_revalidate_dev(device);
|
|
Packit |
7e09eb |
/* Scan all devices and compare them against saved list */
|
|
Packit |
7e09eb |
list_for_each(sysfs_get_block_devices(), device)
|
|
Packit |
7e09eb |
_add_block(device);
|
|
Packit |
7e09eb |
/* Send message to all devices in the list if needed. */
|
|
Packit |
7e09eb |
list_for_each(&ledmon_block_list, device)
|
|
Packit |
7e09eb |
_send_msg(device);
|
|
Packit |
7e09eb |
/* Flush unsent messages from internal buffers. */
|
|
Packit |
7e09eb |
list_for_each(&ledmon_block_list, device)
|
|
Packit |
7e09eb |
_flush_msg(device);
|
|
Packit |
7e09eb |
/* Check if there is any orphaned device. */
|
|
Packit |
7e09eb |
list_for_each(&ledmon_block_list, device)
|
|
Packit |
7e09eb |
_check_block_dev(device, &restart);
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
if (restart) {
|
|
Packit |
7e09eb |
/* there is at least one detached element in the list. */
|
|
Packit |
7e09eb |
list_erase(&ledmon_block_list);
|
|
Packit |
7e09eb |
}
|
|
Packit |
7e09eb |
}
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
static status_t _init_ledmon_conf(void)
|
|
Packit |
7e09eb |
{
|
|
Packit |
7e09eb |
memset(&conf, 0, sizeof(struct ledmon_conf));
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
/* initialize with default values */
|
|
Packit |
7e09eb |
conf.blink_on_init = 1;
|
|
Packit |
7e09eb |
conf.blink_on_migration = 1;
|
|
Packit |
7e09eb |
conf.rebuild_blink_on_all = 0;
|
|
Packit |
7e09eb |
conf.raid_members_only = 0;
|
|
Packit |
7e09eb |
conf.log_level = LOG_LEVEL_WARNING;
|
|
Packit |
7e09eb |
conf.scan_interval = LEDMON_DEF_SLEEP_INTERVAL;
|
|
Packit |
7e09eb |
list_init(&conf.cntrls_whitelist, NULL);
|
|
Packit |
7e09eb |
list_init(&conf.cntrls_blacklist, NULL);
|
|
Packit |
7e09eb |
return set_log_path(LEDMON_DEF_LOG_FILE);
|
|
Packit |
7e09eb |
}
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
static void _close_parent_fds(void)
|
|
Packit |
7e09eb |
{
|
|
Packit |
7e09eb |
struct list dir;
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
if (scan_dir("/proc/self/fd", &dir) == 0) {
|
|
Packit |
7e09eb |
char *elem;
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
list_for_each(&dir, elem) {
|
|
Packit |
7e09eb |
int fd = (int)strtol(basename(elem), NULL, 10);
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
if (fd != get_log_fd())
|
|
Packit |
7e09eb |
close(fd);
|
|
Packit |
7e09eb |
}
|
|
Packit |
7e09eb |
list_erase(&dir;;
|
|
Packit |
7e09eb |
}
|
|
Packit |
7e09eb |
}
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
/**
|
|
Packit |
7e09eb |
*/
|
|
Packit |
7e09eb |
int main(int argc, char *argv[])
|
|
Packit |
7e09eb |
{
|
|
Packit |
7e09eb |
status_t status = STATUS_SUCCESS;
|
|
Packit |
7e09eb |
int ignore = 0;
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
setup_options(&longopt, &shortopt, possible_params,
|
|
Packit |
7e09eb |
possible_params_size);
|
|
Packit |
7e09eb |
set_invocation_name(argv[0]);
|
|
Packit |
7e09eb |
openlog(progname, LOG_PID | LOG_PERROR, LOG_DAEMON);
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
if (on_exit(_ledmon_status, &ignore))
|
|
Packit |
7e09eb |
return STATUS_ONEXIT_ERROR;
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
if (_cmdline_parse_non_daemonise(argc, argv) != STATUS_SUCCESS)
|
|
Packit |
7e09eb |
return STATUS_CMDLINE_ERROR;
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
if (getuid() != 0) {
|
|
Packit |
7e09eb |
fprintf(stderr, "Only root can run this application.\n");
|
|
Packit |
7e09eb |
return STATUS_NOT_A_PRIVILEGED_USER;
|
|
Packit |
7e09eb |
}
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
status = _init_ledmon_conf();
|
|
Packit |
7e09eb |
if (status != STATUS_SUCCESS)
|
|
Packit |
7e09eb |
return status;
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
status = ledmon_read_config(ledmon_conf_path);
|
|
Packit |
7e09eb |
if (status != STATUS_SUCCESS)
|
|
Packit |
7e09eb |
return status;
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
if (_cmdline_parse(argc, argv) != STATUS_SUCCESS)
|
|
Packit |
7e09eb |
return STATUS_CMDLINE_ERROR;
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
ledmon_write_shared_conf();
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
if (log_open(conf.log_path) != STATUS_SUCCESS)
|
|
Packit |
7e09eb |
return STATUS_LOG_FILE_ERROR;
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
free(shortopt);
|
|
Packit |
7e09eb |
free(longopt);
|
|
Packit |
7e09eb |
if (pidfile_check(progname, NULL) == 0) {
|
|
Packit |
7e09eb |
log_warning("daemon is running...");
|
|
Packit |
7e09eb |
return STATUS_LEDMON_RUNNING;
|
|
Packit |
7e09eb |
}
|
|
Packit |
7e09eb |
if (!foreground) {
|
|
Packit |
7e09eb |
pid_t pid = fork();
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
if (pid < 0) {
|
|
Packit |
7e09eb |
log_debug("main(): fork() failed (errno=%d).", errno);
|
|
Packit |
7e09eb |
exit(EXIT_FAILURE);
|
|
Packit |
7e09eb |
}
|
|
Packit |
7e09eb |
if (pid > 0) {
|
|
Packit |
7e09eb |
ignore = 1; /* parent: don't print exit status */
|
|
Packit |
7e09eb |
exit(EXIT_SUCCESS);
|
|
Packit |
7e09eb |
}
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
pid_t sid = setsid();
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
if (sid < 0) {
|
|
Packit |
7e09eb |
log_debug("main(): setsid() failed (errno=%d).", errno);
|
|
Packit |
7e09eb |
exit(EXIT_FAILURE);
|
|
Packit |
7e09eb |
}
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
_close_parent_fds();
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
int t = open("/dev/null", O_RDWR);
|
|
Packit |
7e09eb |
UNUSED(dup(t));
|
|
Packit |
7e09eb |
UNUSED(dup(t));
|
|
Packit |
7e09eb |
}
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
umask(027);
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
if (chdir("/") < 0) {
|
|
Packit |
7e09eb |
log_debug("main(): chdir() failed (errno=%d).", errno);
|
|
Packit |
7e09eb |
exit(EXIT_FAILURE);
|
|
Packit |
7e09eb |
}
|
|
Packit |
7e09eb |
if (pidfile_create(progname)) {
|
|
Packit |
7e09eb |
log_debug("main(): pidfile_creat() failed.");
|
|
Packit |
7e09eb |
exit(EXIT_FAILURE);
|
|
Packit |
7e09eb |
}
|
|
Packit |
7e09eb |
_ledmon_setup_signals();
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
if (on_exit(_ledmon_fini, progname))
|
|
Packit |
7e09eb |
exit(STATUS_ONEXIT_ERROR);
|
|
Packit |
7e09eb |
list_init(&ledmon_block_list, (item_free_t)block_device_fini);
|
|
Packit |
7e09eb |
sysfs_init();
|
|
Packit |
7e09eb |
log_info("monitor service has been started...");
|
|
Packit |
7e09eb |
while (terminate == 0) {
|
|
Packit |
7e09eb |
struct block_device *device;
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
timestamp = time(NULL);
|
|
Packit |
7e09eb |
sysfs_scan();
|
|
Packit |
7e09eb |
_ledmon_execute();
|
|
Packit |
7e09eb |
_ledmon_wait(conf.scan_interval);
|
|
Packit |
7e09eb |
/* Invalidate each device in the list. Clear controller and host. */
|
|
Packit |
7e09eb |
list_for_each(&ledmon_block_list, device)
|
|
Packit |
7e09eb |
_invalidate_dev(device);
|
|
Packit |
7e09eb |
sysfs_reset();
|
|
Packit |
7e09eb |
}
|
|
Packit |
7e09eb |
ledmon_remove_shared_conf();
|
|
Packit |
7e09eb |
stop_udev_monitor();
|
|
Packit |
7e09eb |
exit(EXIT_SUCCESS);
|
|
Packit |
7e09eb |
}
|