Blame src/ledctl.c

Packit 7e09eb
/*
Packit 7e09eb
 * Intel(R) Enclosure LED Utilities
Packit Service cb68d2
 * Copyright (C) 2009-2021 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 Service cb68d2
#include <config_ac.h>
Packit 7e09eb
#include <ctype.h>
Packit 7e09eb
#include <errno.h>
Packit 7e09eb
#include <getopt.h>
Packit 7e09eb
#include <limits.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/stat.h>
Packit 7e09eb
#include <sys/types.h>
Packit 7e09eb
#include <syslog.h>
Packit 7e09eb
#include <time.h>
Packit 7e09eb
#include <unistd.h>
Packit 7e09eb
#include <sys/sysmacros.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 "scsi.h"
Packit 7e09eb
#include "status.h"
Packit 7e09eb
#include "sysfs.h"
Packit 7e09eb
#include "utils.h"
Packit 7e09eb
Packit 7e09eb
/**
Packit 7e09eb
 * @brief An IBPI state structure.
Packit 7e09eb
 *
Packit 7e09eb
 * This structure connects an IBPI pattern and block devices. It is used by
Packit 7e09eb
 * _determine() function to figure the correct pattern out.
Packit 7e09eb
 */
Packit 7e09eb
struct ibpi_state {
Packit 7e09eb
	enum ibpi_pattern ibpi;
Packit 7e09eb
	struct list block_list;
Packit 7e09eb
};
Packit 7e09eb
Packit 7e09eb
/**
Packit 7e09eb
 * @brief List of IBPI patterns.
Packit 7e09eb
 *
Packit 7e09eb
 * This is a list of IBPI patterns the user requested to be visualized.
Packit 7e09eb
 * Each element on the list is struct ibpi_state type. There's only one
Packit 7e09eb
 * instance of each IBPI pattern on the list (no duplicates).
Packit 7e09eb
 */
Packit 7e09eb
static struct list ibpi_list;
Packit 7e09eb
Packit 7e09eb
/**
Packit 7e09eb
 * @brief IBPI pattern names.
Packit 7e09eb
 *
Packit 7e09eb
 * This is internal array holding names of IBPI pattern. Logging routines use
Packit 7e09eb
 * this entries to translate enumeration type values into the string.
Packit 7e09eb
 */
Packit 7e09eb
const char *ibpi_str[] = {
Packit 7e09eb
	[IBPI_PATTERN_UNKNOWN]        = "",
Packit 7e09eb
	[IBPI_PATTERN_NORMAL]         = "NORMAL",
Packit 7e09eb
	[IBPI_PATTERN_ONESHOT_NORMAL] = "",
Packit 7e09eb
	[IBPI_PATTERN_DEGRADED]       = "ICA",
Packit 7e09eb
	[IBPI_PATTERN_REBUILD]        = "REBUILD",
Packit 7e09eb
	[IBPI_PATTERN_FAILED_ARRAY]   = "IFA",
Packit 7e09eb
	[IBPI_PATTERN_HOTSPARE]       = "HOTSPARE",
Packit 7e09eb
	[IBPI_PATTERN_PFA]            = "PFA",
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 ledctl utility. It is the pattern used to print out
Packit 7e09eb
 * information about the version of ledctl utility.
Packit 7e09eb
 */
Packit Service cb68d2
static char *ledctl_version = "Intel(R) Enclosure LED Control Application %s %s\n"
Packit Service cb68d2
			      "Copyright (C) 2009-2021 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_HELP,
Packit 7e09eb
	OPT_LOG,
Packit 7e09eb
	OPT_VERSION,
Packit 7e09eb
	OPT_LIST_CTRL,
Packit 7e09eb
	OPT_LISTED_ONLY,
Packit 7e09eb
	OPT_ALL,
Packit 7e09eb
	OPT_DEBUG,
Packit 7e09eb
	OPT_ERROR,
Packit 7e09eb
	OPT_INFO,
Packit 7e09eb
	OPT_QUIET,
Packit 7e09eb
	OPT_WARNING,
Packit 7e09eb
	OPT_LOG_LEVEL,
Packit 7e09eb
};
Packit 7e09eb
Packit 7e09eb
static const int possible_params_size = sizeof(possible_params)
Packit 7e09eb
		/ sizeof(possible_params[0]);
Packit 7e09eb
Packit 7e09eb
static int listed_only;
Packit 7e09eb
Packit 7e09eb
static void ibpi_state_fini(struct ibpi_state *p)
Packit 7e09eb
{
Packit 7e09eb
	list_clear(&p->block_list);
Packit 7e09eb
	free(p);
Packit 7e09eb
}
Packit 7e09eb
Packit 7e09eb
/**
Packit 7e09eb
 * @brief Finalizes LED control utility.
Packit 7e09eb
 *
Packit 7e09eb
 * This is internal function of ledctl utility. The function cleans up a memory
Packit 7e09eb
 * allocated for the application and closes all opened handles. This function is
Packit 7e09eb
 * design to be registered as on_exit() handler function.
Packit 7e09eb
 *
Packit 7e09eb
 * @param[in]      status         exit status of the ledctl application.
Packit 7e09eb
 * @param[in]      ignored        function ignores this argument.
Packit 7e09eb
 *
Packit 7e09eb
 * @return The function does not return a value.
Packit 7e09eb
 */
Packit 7e09eb
static void _ledctl_fini(int status __attribute__ ((unused)),
Packit 7e09eb
			 void *ignore __attribute__ ((unused)))
Packit 7e09eb
{
Packit 7e09eb
	sysfs_reset();
Packit 7e09eb
	list_erase(&ibpi_list);
Packit 7e09eb
	log_close();
Packit 7e09eb
}
Packit 7e09eb
Packit 7e09eb
/**
Packit 7e09eb
 * @brief Displays the credits.
Packit 7e09eb
 *
Packit 7e09eb
 * This is internal function of ledctl utility. 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 _ledctl_version(void)
Packit 7e09eb
{
Packit Service cb68d2
	printf(ledctl_version, PACKAGE_VERSION, 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 ledctl utility. 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 _ledctl_help(void)
Packit 7e09eb
{
Packit Service cb68d2
	printf(ledctl_version, PACKAGE_VERSION, BUILD_LABEL);
Packit 7e09eb
	printf("\nUsage: %s [OPTIONS] pattern=list_of_devices ...\n\n",
Packit 7e09eb
	       progname);
Packit 7e09eb
	printf("Mandatory arguments for long options are mandatory for short options, too.\n\n");
Packit 7e09eb
	print_opt("--listed-only", "-x",
Packit 7e09eb
			  "Ledctl will change state only for given devices.");
Packit 7e09eb
	print_opt("--list-controllers", "-L",
Packit 7e09eb
			  "Displays list of controllers detected by ledmon.");
Packit 7e09eb
	print_opt("--log=PATH", "-l PATH",
Packit 7e09eb
			  "Use local log file instead /var/log/ledctl.log.");
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
	print_opt("--log-level=VALUE", "-l VALUE",
Packit 7e09eb
			  "Allows user to set ledctl verbose level in logs.");
Packit 7e09eb
	printf("\nPatterns:\n"
Packit 7e09eb
	       "\tCommon patterns are:\n"
Packit 7e09eb
	       "\t\tlocate, locate_off, normal, off, degraded, rebuild,\n" ""
Packit 7e09eb
	       "\t\tfailed_array, hotspare, pfa, failure, disk_failed\n"
Packit 7e09eb
	       "\tSES-2 only patterns:\n"
Packit 7e09eb
	       "\t\tses_abort, ses_rebuild, ses_ifa, ses_ica, ses_cons_check,\n"
Packit 7e09eb
	       "\t\tses_hotspare, ses_rsvd_dev, ses_ok, ses_ident, ses_rm,\n"
Packit 7e09eb
	       "\t\tses_insert, ses_missing, ses_dnr, ses_active, ses_prdfail,\n"
Packit 7e09eb
	       "\t\tses_enable_bb, ses_enable_ba, ses_devoff, ses_fault\n"
Packit 7e09eb
	       "\tAutomatic translation form IBPI into SES-2:\n"
Packit 7e09eb
	       "\t\tlocate=ses_ident, locate_off=~ses_ident,\n"
Packit 7e09eb
	       "\t\tnormal=ses_ok, off=ses_ok, degraded=ses_ica,\n"
Packit 7e09eb
	       "\t\trebuild=ses_rebuild, failed_array=ses_ifa,\n"
Packit 7e09eb
	       "\t\thotspare=ses_hotspare, pfa=ses_prdfail, failure=ses_fault,\n"
Packit 7e09eb
	       "\t\tdisk_failed=ses_fault\n");
Packit 7e09eb
	printf("Refer to ledctl(8) man page for more detailed description.\n");
Packit 7e09eb
	printf("Bugs should be reported at: " \
Packit 7e09eb
		"https://github.com/intel/ledmon/issues\n");
Packit 7e09eb
}
Packit 7e09eb
Packit 7e09eb
/**
Packit 7e09eb
 * @brief Puts new IBPI state on the list.
Packit 7e09eb
 *
Packit 7e09eb
 * This is internal function of ledctl utility. The function creates a new entry
Packit 7e09eb
 * of the list with IBPI patterns. Each IBPI state has a list of block devices
Packit 7e09eb
 * attached. The function initializes this list and sets empty.
Packit 7e09eb
 *
Packit 7e09eb
 * @param[in]      ibpi           an IBPI pattern to add.
Packit 7e09eb
 *
Packit 7e09eb
 * @return Pointer to the created element if successful, otherwise function
Packit 7e09eb
 *         returns NULL. The NULL pointer means element allocation failed.
Packit 7e09eb
 */
Packit 7e09eb
static struct ibpi_state *_ibpi_state_init(enum ibpi_pattern ibpi)
Packit 7e09eb
{
Packit 7e09eb
	struct ibpi_state *state = malloc(sizeof(struct ibpi_state));
Packit 7e09eb
Packit 7e09eb
	if (!state)
Packit 7e09eb
		return NULL;
Packit 7e09eb
Packit 7e09eb
	list_init(&state->block_list, NULL);
Packit 7e09eb
	state->ibpi = ibpi;
Packit 7e09eb
Packit 7e09eb
	list_append(&ibpi_list, state);
Packit 7e09eb
Packit 7e09eb
	return state;
Packit 7e09eb
}
Packit 7e09eb
Packit 7e09eb
/**
Packit 7e09eb
 * @brief Sets a state of block device.
Packit 7e09eb
 *
Packit 7e09eb
 * This is internal function of ledctl utility. The function sets
Packit 7e09eb
 * an IBPI pattern for block devices. The function is design to be used
Packit 7e09eb
 * as action parameter of list_for_each() function.
Packit 7e09eb
 *
Packit 7e09eb
 * @param[in]      state          pointer to structure holding the IBPI pattern
Packit 7e09eb
 *                                identifier and list of block devices.
Packit 7e09eb
 *
Packit 7e09eb
 * @return The function does not return a value.
Packit 7e09eb
 */
Packit 7e09eb
static void _determine(struct ibpi_state *state)
Packit 7e09eb
{
Packit 7e09eb
	if (list_is_empty(&state->block_list) == 0) {
Packit 7e09eb
		struct block_device *block;
Packit 7e09eb
Packit 7e09eb
		list_for_each(&state->block_list, block) {
Packit Service cb68d2
			if (block->ibpi != state->ibpi)
Packit 7e09eb
				block->ibpi = state->ibpi;
Packit 7e09eb
		}
Packit 7e09eb
	} else {
Packit 7e09eb
		log_warning
Packit 7e09eb
		    ("IBPI %s: missing block device(s)... pattern ignored.",
Packit 7e09eb
		     ibpi2str(state->ibpi));
Packit 7e09eb
	}
Packit 7e09eb
}
Packit 7e09eb
Packit 7e09eb
/**
Packit 7e09eb
 * @brief Determines a state of block devices.
Packit 7e09eb
 *
Packit 7e09eb
 * This is internal function of ledctl utility. The functions goes through list
Packit 7e09eb
 * of IBPI states and calls _determine() function for each element. If the list
Packit 7e09eb
 * is empty the function logs a warning message and does nothing.
Packit 7e09eb
 *
Packit 7e09eb
 * @param[in]      ibpi_local_list  pointer to list of IBPI states.
Packit 7e09eb
 *
Packit 7e09eb
 * @return STATUS_SUCCESS if successful, otherwise a valid status_t status code.
Packit 7e09eb
 *         The following status codes function returns:
Packit 7e09eb
 *
Packit 7e09eb
 *         STATUS_LIST_EMPTY      the specified list has no elements.
Packit 7e09eb
 */
Packit 7e09eb
static status_t _ibpi_state_determine(struct list *ibpi_local_list)
Packit 7e09eb
{
Packit 7e09eb
	if (list_is_empty(ibpi_local_list) == 0) {
Packit 7e09eb
		struct ibpi_state *state;
Packit 7e09eb
Packit 7e09eb
		list_for_each(ibpi_local_list, state)
Packit 7e09eb
			_determine(state);
Packit 7e09eb
		return STATUS_SUCCESS;
Packit 7e09eb
	}
Packit 7e09eb
	log_error("missing operand(s)... run %s --help for details.", progname);
Packit 7e09eb
	return STATUS_LIST_EMPTY;
Packit 7e09eb
}
Packit 7e09eb
Packit 7e09eb
static struct ibpi_state *_ibpi_find(const struct list *ibpi_local_list,
Packit 7e09eb
				     enum ibpi_pattern ibpi)
Packit 7e09eb
{
Packit 7e09eb
	struct ibpi_state *state;
Packit 7e09eb
Packit 7e09eb
	list_for_each(ibpi_local_list, state) {
Packit 7e09eb
		if (state->ibpi == ibpi)
Packit 7e09eb
			return state;
Packit 7e09eb
	}
Packit 7e09eb
	return NULL;
Packit 7e09eb
}
Packit 7e09eb
Packit 7e09eb
/**
Packit 7e09eb
 * @brief Gets a pointer to IBPI state structure.
Packit 7e09eb
 *
Packit 7e09eb
 * This is internal function of ledctl utility. The function retrieves an entry
Packit 7e09eb
 * to an IBPI state structure from ibpi_list list. If such an entry does not
Packit 7e09eb
 * exist the memory is allocated and entry is added to the list.
Packit 7e09eb
 *
Packit 7e09eb
 * @param[in]      name       a name of IBPI pattern i.e. taken from command
Packit 7e09eb
 *                            line interface. It might be 'locate', 'normal',
Packit 7e09eb
 *                            'locate_off', 'off', 'ica', 'degraded', 'rebuild',
Packit 7e09eb
 *                            'ifa', 'failed_array', 'hotspare',
Packit 7e09eb
 *                            'pfa', 'failure' or 'disk_failed' string.
Packit 7e09eb
 *
Packit 7e09eb
 * @return Pointer to IBPI state structure if successful, otherwise the function
Packit 7e09eb
 *         returns NULL. The NULL pointer means either the invalid status name
Packit 7e09eb
 *         has been given or there's not enough memory available in the system
Packit 7e09eb
 *         to allocate the structure.
Packit 7e09eb
 */
Packit 7e09eb
static struct ibpi_state *_ibpi_state_get(const char *name)
Packit 7e09eb
{
Packit 7e09eb
	struct ibpi_state *state = NULL;
Packit 7e09eb
	enum ibpi_pattern ibpi;
Packit 7e09eb
Packit 7e09eb
	if (strcmp(name, "locate") == 0) {
Packit 7e09eb
		ibpi = IBPI_PATTERN_LOCATE;
Packit 7e09eb
	} else if (strcmp(name, "locate_off") == 0) {
Packit 7e09eb
		ibpi = IBPI_PATTERN_LOCATE_OFF;
Packit 7e09eb
	} else if (strcmp(name, "normal") == 0) {
Packit 7e09eb
		ibpi = IBPI_PATTERN_NORMAL;
Packit 7e09eb
	} else if (strcmp(name, "off") == 0) {
Packit 7e09eb
		ibpi = IBPI_PATTERN_NORMAL;
Packit 7e09eb
	} else if ((strcmp(name, "ica") == 0) ||
Packit 7e09eb
		   (strcmp(name, "degraded") == 0)) {
Packit 7e09eb
		ibpi = IBPI_PATTERN_DEGRADED;
Packit 7e09eb
	} else if (strcmp(name, "rebuild") == 0) {
Packit 7e09eb
		ibpi = IBPI_PATTERN_REBUILD;
Packit 7e09eb
	} else if ((strcmp(name, "ifa") == 0) ||
Packit 7e09eb
		   (strcmp(name, "failed_array") == 0)) {
Packit 7e09eb
		ibpi = IBPI_PATTERN_FAILED_ARRAY;
Packit 7e09eb
	} else if (strcmp(name, "hotspare") == 0) {
Packit 7e09eb
		ibpi = IBPI_PATTERN_HOTSPARE;
Packit 7e09eb
	} else if (strcmp(name, "pfa") == 0) {
Packit 7e09eb
		ibpi = IBPI_PATTERN_PFA;
Packit 7e09eb
	} else if ((strcmp(name, "failure") == 0) ||
Packit 7e09eb
		   (strcmp(name, "disk_failed") == 0)) {
Packit 7e09eb
		ibpi = IBPI_PATTERN_FAILED_DRIVE;
Packit 7e09eb
	} else if (strcmp(name, "ses_abort") == 0) {
Packit 7e09eb
		ibpi = SES_REQ_ABORT;
Packit 7e09eb
	} else if (strcmp(name, "ses_rebuild") == 0) {
Packit 7e09eb
		ibpi = SES_REQ_REBUILD;
Packit 7e09eb
	} else if (strcmp(name, "ses_ifa") == 0) {
Packit 7e09eb
		ibpi = SES_REQ_IFA;
Packit 7e09eb
	} else if (strcmp(name, "ses_ica") == 0) {
Packit 7e09eb
		ibpi = SES_REQ_ICA;
Packit 7e09eb
	} else if (strcmp(name, "ses_cons_check") == 0) {
Packit 7e09eb
		ibpi = SES_REQ_CONS_CHECK;
Packit 7e09eb
	} else if (strcmp(name, "ses_hotspare") == 0) {
Packit 7e09eb
		ibpi = SES_REQ_HOSTSPARE;
Packit 7e09eb
	} else if (strcmp(name, "ses_rsvd_dev") == 0) {
Packit 7e09eb
		ibpi = SES_REQ_RSVD_DEV;
Packit 7e09eb
	} else if (strcmp(name, "ses_ok") == 0) {
Packit 7e09eb
		ibpi = SES_REQ_OK;
Packit 7e09eb
	} else if (strcmp(name, "ses_ident") == 0) {
Packit 7e09eb
		ibpi = SES_REQ_IDENT;
Packit 7e09eb
	} else if (strcmp(name, "ses_rm") == 0) {
Packit 7e09eb
		ibpi = SES_REQ_RM;
Packit 7e09eb
	} else if (strcmp(name, "ses_insert") == 0) {
Packit 7e09eb
		ibpi = SES_REQ_INS;
Packit 7e09eb
	} else if (strcmp(name, "ses_missing") == 0) {
Packit 7e09eb
		ibpi = SES_REQ_MISSING;
Packit 7e09eb
	} else if (strcmp(name, "ses_dnr") == 0) {
Packit 7e09eb
		ibpi = SES_REQ_DNR;
Packit 7e09eb
	} else if (strcmp(name, "ses_active") == 0) {
Packit 7e09eb
		ibpi = SES_REQ_ACTIVE;
Packit 7e09eb
	} else if (strcmp(name, "ses_enable_bb") == 0) {
Packit 7e09eb
		ibpi = SES_REQ_EN_BB;
Packit 7e09eb
	} else if (strcmp(name, "ses_enable_ba") == 0) {
Packit 7e09eb
		ibpi = SES_REQ_EN_BA;
Packit 7e09eb
	} else if (strcmp(name, "ses_devoff") == 0) {
Packit 7e09eb
		ibpi = SES_REQ_DEV_OFF;
Packit 7e09eb
	} else if (strcmp(name, "ses_fault") == 0) {
Packit 7e09eb
		ibpi = SES_REQ_FAULT;
Packit 7e09eb
	} else if (strcmp(name, "ses_prdfail") == 0) {
Packit 7e09eb
		ibpi = SES_REQ_PRDFAIL;
Packit 7e09eb
	} else {
Packit 7e09eb
		return NULL;
Packit 7e09eb
	}
Packit 7e09eb
	state = _ibpi_find(&ibpi_list, ibpi);
Packit 7e09eb
	if (state == NULL)
Packit 7e09eb
		state = _ibpi_state_init(ibpi);
Packit 7e09eb
	return state;
Packit 7e09eb
}
Packit 7e09eb
Packit 7e09eb
static struct block_device *_block_device_search(const struct list *block_list,
Packit 7e09eb
						 const char *path)
Packit 7e09eb
{
Packit 7e09eb
	struct block_device *block;
Packit 7e09eb
Packit 7e09eb
	list_for_each(block_list, block) {
Packit 7e09eb
		if (strcmp(block->sysfs_path, path) == 0)
Packit 7e09eb
			return block;
Packit 7e09eb
	}
Packit 7e09eb
	return NULL;
Packit 7e09eb
}
Packit 7e09eb
Packit 7e09eb
/**
Packit 7e09eb
 * @brief Adds a block device to a block list.
Packit 7e09eb
 *
Packit 7e09eb
 * This is internal function of ledctl utility. Each IBPI state has list of
Packit 7e09eb
 * block devices attached to. The function puts a pointer to a block device
Packit 7e09eb
 * on that list. First the function determines the canonical version of the
Packit 7e09eb
 * given path and checks if it is correct. If the path to /dev directory is
Packit 7e09eb
 * given the function finds out the correct entry in sysfs tree.
Packit 7e09eb
 *
Packit 7e09eb
 * @param[in]      state          pointer to IBPI state structure the block
Packit 7e09eb
 *                                device will be added to.
Packit Service cb68d2
 * @param[in]      name           path to block device.
Packit 7e09eb
 *
Packit 7e09eb
 * @return The function does not return a value.
Packit 7e09eb
 */
Packit 7e09eb
static status_t _ibpi_state_add_block(struct ibpi_state *state, char *name)
Packit 7e09eb
{
Packit 7e09eb
	struct stat st;
Packit 7e09eb
	char temp[PATH_MAX], path[PATH_MAX];
Packit 7e09eb
	struct block_device *blk1, *blk2;
Packit 7e09eb
Packit 7e09eb
	if ((realpath(name, temp) == NULL) && (errno != ENOTDIR))
Packit 7e09eb
		return STATUS_INVALID_PATH;
Packit 7e09eb
	if (strstr(temp, "/dev/") != NULL) {
Packit 7e09eb
		if (stat(temp, &st) < 0)
Packit 7e09eb
			return STATUS_STAT_ERROR;
Packit 7e09eb
		sprintf(temp, "/sys/dev/block/%u:%u", major(st.st_rdev),
Packit 7e09eb
			minor(st.st_rdev));
Packit 7e09eb
		if ((realpath(temp, path) == NULL) && (errno != ENOTDIR))
Packit 7e09eb
			return STATUS_INVALID_PATH;
Packit 7e09eb
	} else {
Packit 7e09eb
		str_cpy(path, temp, PATH_MAX);
Packit 7e09eb
	}
Packit 7e09eb
	blk1 = _block_device_search(sysfs_get_block_devices(), path);
Packit 7e09eb
	if (blk1 == NULL) {
Packit 7e09eb
		log_error("%s: device not supported", name);
Packit 7e09eb
		return STATUS_NOT_SUPPORTED;
Packit 7e09eb
	}
Packit 7e09eb
	blk2 = _block_device_search(&state->block_list, path);
Packit 7e09eb
	if (blk2 == NULL)
Packit 7e09eb
		list_append(&state->block_list, blk1);
Packit 7e09eb
	else
Packit 7e09eb
		log_info("%s: %s: device already on the list.",
Packit 7e09eb
			 ibpi2str(state->ibpi), path);
Packit 7e09eb
	return STATUS_SUCCESS;
Packit 7e09eb
}
Packit 7e09eb
Packit 7e09eb
/**
Packit 7e09eb
 * @brief Command line parser - operands.
Packit 7e09eb
 *
Packit 7e09eb
 * This is internal function of ledctl utility. The function parses operands of
Packit 7e09eb
 * ledctl application. The operands section contains the pattern name and a list
Packit 7e09eb
 * of block devices associated with each pattern. There are two different
Packit 7e09eb
 * formats for the operand. First format is pattern={ dev_list }, where elements
Packit 7e09eb
 * are space separated on the dev_list. Second format is pattern=dev1,dev2,...
Packit 7e09eb
 * where elements are comma separated on the list of devices.
Packit 7e09eb
 *
Packit 7e09eb
 * @param[in]      argc           number of elements in argv array.
Packit 7e09eb
 * @param[in]      argv           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_ibpi_parse(int argc, char *argv[])
Packit 7e09eb
{
Packit 7e09eb
	status_t t_status, ret_status = STATUS_SUCCESS;
Packit 7e09eb
Packit 7e09eb
	while (optind < argc) {
Packit 7e09eb
		struct ibpi_state *state = NULL;
Packit 7e09eb
		char *p = argv[optind++];
Packit 7e09eb
		char *t;
Packit 7e09eb
		t = strchrnul(p, '=');
Packit 7e09eb
		if (*t != '\0') {
Packit 7e09eb
			*(t++) = '\0';
Packit 7e09eb
			state = _ibpi_state_get(p);
Packit 7e09eb
			if (state == NULL) {
Packit 7e09eb
				log_error("%s - unknown pattern name.", p);
Packit 7e09eb
				return STATUS_INVALID_STATE;
Packit 7e09eb
			}
Packit 7e09eb
			if (*t == '{') {
Packit 7e09eb
				while ((t = argv[optind++]) != NULL) {
Packit 7e09eb
					if (*t == '}')
Packit 7e09eb
						break;
Packit 7e09eb
					t_status =
Packit 7e09eb
					_ibpi_state_add_block(state, t);
Packit 7e09eb
					if (t_status != STATUS_SUCCESS)
Packit 7e09eb
						ret_status = t_status;
Packit 7e09eb
				}
Packit 7e09eb
			} else {
Packit 7e09eb
				while (*(p = t) != '\0') {
Packit 7e09eb
					t = strchrnul(p, ',');
Packit 7e09eb
					if (*t != '\0')
Packit 7e09eb
						*(t++) = '\0';
Packit 7e09eb
					t_status =
Packit 7e09eb
					_ibpi_state_add_block(state, p);
Packit 7e09eb
					if (t_status != STATUS_SUCCESS)
Packit 7e09eb
						ret_status = t_status;
Packit 7e09eb
				}
Packit 7e09eb
			}
Packit 7e09eb
		}
Packit 7e09eb
	}
Packit 7e09eb
	if (_ibpi_state_determine(&ibpi_list) != STATUS_SUCCESS)
Packit 7e09eb
		ret_status = STATUS_IBPI_DETERMINE_ERROR;
Packit 7e09eb
	return ret_status;
Packit 7e09eb
}
Packit 7e09eb
Packit 7e09eb
/**
Packit Service cb68d2
 * @brief Command line parser - checks if command line input contains
Packit Service cb68d2
 * options which don't require to run ledctl as root.
Packit Service cb68d2
 *
Packit Service cb68d2
 * The function parses options of ledctl application.
Packit Service cb68d2
 * It handles option to print version and help.
Packit Service cb68d2
 *
Packit Service cb68d2
 * @param[in]      argc           number of elements in argv array.
Packit Service cb68d2
 * @param[in]      argv           command line arguments.
Packit Service cb68d2
 *
Packit Service cb68d2
 * @return STATUS_SUCCESS if successful, otherwise a valid status_t status code.
Packit Service cb68d2
 */
Packit Service cb68d2
static status_t _cmdline_parse_non_root(int argc, char *argv[])
Packit Service cb68d2
{
Packit Service cb68d2
	int opt_index, opt = -1;
Packit Service cb68d2
	status_t status = STATUS_SUCCESS;
Packit Service cb68d2
Packit Service cb68d2
	do {
Packit Service cb68d2
		opt = getopt_long(argc, argv, shortopt, longopt, &opt_index);
Packit Service cb68d2
		switch (opt) {
Packit Service cb68d2
		case 'v':
Packit Service cb68d2
			_ledctl_version();
Packit Service cb68d2
			exit(EXIT_SUCCESS);
Packit Service cb68d2
		case 'h':
Packit Service cb68d2
			_ledctl_help();
Packit Service cb68d2
			exit(EXIT_SUCCESS);
Packit Service cb68d2
		case ':':
Packit Service cb68d2
		case '?':
Packit Service cb68d2
			return STATUS_CMDLINE_ERROR;
Packit Service cb68d2
		}
Packit Service cb68d2
	} while (opt >= 0);
Packit Service cb68d2
Packit Service cb68d2
	return status;
Packit Service cb68d2
}
Packit Service cb68d2
Packit Service cb68d2
/**
Packit 7e09eb
 * @brief Command line parser - options.
Packit 7e09eb
 *
Packit 7e09eb
 * This is internal function of ledctl utility. The function parses options of
Packit 7e09eb
 * ledctl application. Refer to ledctl help in order to get more information
Packit 7e09eb
 * about ledctl command line options.
Packit 7e09eb
 *
Packit 7e09eb
 * @param[in]      argc           number of elements in argv array.
Packit 7e09eb
 * @param[in]      argv           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 Service cb68d2
	optind = 1;
Packit Service cb68d2
Packit 7e09eb
	do {
Packit 7e09eb
		opt = getopt_long(argc, argv, shortopt, longopt, &opt_index);
Packit 7e09eb
		if (opt == -1)
Packit 7e09eb
			break;
Packit 7e09eb
		switch (opt) {
Packit 7e09eb
		int log_level;
Packit 7e09eb
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
			default:
Packit 7e09eb
				status = set_verbose_level(
Packit 7e09eb
						possible_params[opt_index]);
Packit 7e09eb
Packit 7e09eb
			}
Packit 7e09eb
			break;
Packit 7e09eb
		case 'l':
Packit 7e09eb
			status = set_log_path(optarg);
Packit 7e09eb
			break;
Packit 7e09eb
		case 'x':
Packit 7e09eb
			status = STATUS_SUCCESS;
Packit 7e09eb
			listed_only = 1;
Packit 7e09eb
			break;
Packit 7e09eb
		case 'L':
Packit 7e09eb
		{
Packit 7e09eb
			struct cntrl_device *ctrl_dev;
Packit 7e09eb
Packit 7e09eb
			sysfs_init();
Packit 7e09eb
			sysfs_scan();
Packit 7e09eb
			list_for_each(sysfs_get_cntrl_devices(), ctrl_dev)
Packit 7e09eb
				print_cntrl(ctrl_dev);
Packit 7e09eb
			sysfs_reset();
Packit 7e09eb
			exit(EXIT_SUCCESS);
Packit 7e09eb
		}
Packit 7e09eb
		case ':':
Packit 7e09eb
		case '?':
Packit 7e09eb
		default:
Packit 7e09eb
			log_debug("[opt='%c', opt_index=%d]", opt, opt_index);
Packit 7e09eb
			return STATUS_CMDLINE_ERROR;
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 Service cb68d2
 * @brief Send IBPI pattern.
Packit 7e09eb
 *
Packit Service cb68d2
 * This is internal function of ledctl utility. The function set a requested
Packit Service cb68d2
 * ibpi_state for devices linked with this ibpi_state on ibpi_local_list.
Packit Service cb68d2
 * For other devices IBPI_PATTERN_LOCATE_OFF might be set - depending on
Packit Service cb68d2
 * listed_only parameter. Then it sends a LED control message to controller
Packit Service cb68d2
 * to visualize the pattern.
Packit 7e09eb
 *
Packit Service cb68d2
 * @param[in]      ibpi_local_list	    pointer to list of ipbi_state.
Packit 7e09eb
 *
Packit Service cb68d2
 * @return STATUS_SUCCESS if successful, otherwise STATUS_IBPI_DETERMINE_ERROR
Packit 7e09eb
 */
Packit 7e09eb
static status_t _ledctl_execute(struct list *ibpi_local_list)
Packit 7e09eb
{
Packit 7e09eb
	struct ibpi_state *state;
Packit 7e09eb
	struct block_device *device;
Packit 7e09eb
Packit 7e09eb
	if (!listed_only) {
Packit 7e09eb
		list_for_each(sysfs_get_block_devices(), device)
Packit 7e09eb
			device->send_fn(device, IBPI_PATTERN_LOCATE_OFF);
Packit 7e09eb
	}
Packit 7e09eb
Packit 7e09eb
	list_for_each(ibpi_local_list, state)
Packit Service cb68d2
		list_for_each(&state->block_list, device) {
Packit Service cb68d2
			if (state->ibpi != device->ibpi) {
Packit Service cb68d2
				log_debug("Mismatch detected for %s, ibpi state: %s, device state %s\n",
Packit Service cb68d2
					  device->sysfs_path, state->ibpi,
Packit Service cb68d2
					  device->ibpi);
Packit Service cb68d2
				return STATUS_IBPI_DETERMINE_ERROR;
Packit Service cb68d2
			}
Packit 7e09eb
			device->send_fn(device, device->ibpi);
Packit Service cb68d2
		}
Packit 7e09eb
Packit 7e09eb
	list_for_each(sysfs_get_block_devices(), device)
Packit 7e09eb
		device->flush_fn(device);
Packit 7e09eb
Packit 7e09eb
	return STATUS_SUCCESS;
Packit 7e09eb
}
Packit 7e09eb
Packit 7e09eb
static status_t _read_shared_conf(void)
Packit 7e09eb
{
Packit 7e09eb
	status_t status;
Packit 7e09eb
	char share_conf_path[PATH_MAX];
Packit 7e09eb
Packit 7e09eb
	memset(share_conf_path, 0, sizeof(share_conf_path));
Packit 7e09eb
	snprintf(share_conf_path, sizeof(share_conf_path), "/dev/shm%s",
Packit 7e09eb
		 LEDMON_SHARE_MEM_FILE);
Packit 7e09eb
Packit 7e09eb
	status = ledmon_read_config(share_conf_path);
Packit 7e09eb
	return status;
Packit 7e09eb
}
Packit 7e09eb
Packit 7e09eb
static status_t _init_ledctl_conf(void)
Packit 7e09eb
{
Packit 7e09eb
	memset(&conf, 0, sizeof(struct ledmon_conf));
Packit 7e09eb
	/* initialize with default values */
Packit 7e09eb
	conf.log_level = LOG_LEVEL_WARNING;
Packit 7e09eb
	list_init(&conf.cntrls_whitelist, NULL);
Packit 7e09eb
	list_init(&conf.cntrls_blacklist, NULL);
Packit 7e09eb
Packit 7e09eb
	return set_log_path(LEDCTL_DEF_LOG_FILE);
Packit 7e09eb
}
Packit 7e09eb
Packit 7e09eb
/**
Packit 7e09eb
 * @brief Application's entry point.
Packit 7e09eb
 *
Packit 7e09eb
 * This is the entry point of ledctl utility. This function does all the work.
Packit 7e09eb
 * It allocates and initializes all used structures. Registers on_exit()
Packit 7e09eb
 * handlers.
Packit 7e09eb
 * Then the function parses command line options and commands given and scans
Packit 7e09eb
 * sysfs tree for controllers, block devices and RAID devices. If no error is
Packit 7e09eb
 * the function send LED control messages according to IBPI pattern set.
Packit 7e09eb
 *
Packit 7e09eb
 * @param[in]      argc           number of elements in argv array, number of
Packit 7e09eb
 *                                command line arguments.
Packit 7e09eb
 * @param[in]      argv           array of command line arguments. The last
Packit 7e09eb
 *                                element on the list is NULL pointer.
Packit 7e09eb
 *
Packit 7e09eb
 * @return STATUS_SUCCESS if successful, otherwise a valid status_t status code.
Packit 7e09eb
 */
Packit 7e09eb
int main(int argc, char *argv[])
Packit 7e09eb
{
Packit 7e09eb
	status_t status;
Packit 7e09eb
Packit 7e09eb
	setup_options(&longopt, &shortopt, possible_params,
Packit 7e09eb
			possible_params_size);
Packit 7e09eb
	set_invocation_name(argv[0]);
Packit Service cb68d2
Packit Service cb68d2
	if (_cmdline_parse_non_root(argc, argv) != STATUS_SUCCESS)
Packit Service cb68d2
		return STATUS_CMDLINE_ERROR;
Packit Service cb68d2
Packit 7e09eb
	openlog(progname, LOG_PERROR, LOG_USER);
Packit 7e09eb
Packit Service cb68d2
	if (geteuid() != 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_ledctl_conf();
Packit 7e09eb
	if (status != STATUS_SUCCESS)
Packit 7e09eb
		return status;
Packit 7e09eb
	if (on_exit(_ledctl_fini, progname))
Packit 7e09eb
		exit(STATUS_ONEXIT_ERROR);
Packit 7e09eb
	if (_cmdline_parse(argc, argv))
Packit 7e09eb
		exit(STATUS_CMDLINE_ERROR);
Packit 7e09eb
	free(shortopt);
Packit 7e09eb
	free(longopt);
Packit 7e09eb
	status = _read_shared_conf();
Packit 7e09eb
	if (status != STATUS_SUCCESS)
Packit 7e09eb
		return status;
Packit 7e09eb
	status = log_open(conf.log_path);
Packit 7e09eb
	if (status != STATUS_SUCCESS)
Packit 7e09eb
		return STATUS_LOG_FILE_ERROR;
Packit 7e09eb
Packit 7e09eb
	list_init(&ibpi_list, (item_free_t)ibpi_state_fini);
Packit 7e09eb
	sysfs_init();
Packit 7e09eb
	sysfs_scan();
Packit 7e09eb
	status = _cmdline_ibpi_parse(argc, argv);
Packit 7e09eb
	if (status != STATUS_SUCCESS) {
Packit 7e09eb
		log_debug("main(): _ibpi_parse() failed (status=%s).",
Packit 7e09eb
			  strstatus(status));
Packit 7e09eb
		exit(status);
Packit 7e09eb
	}
Packit 7e09eb
	return _ledctl_execute(&ibpi_list);
Packit 7e09eb
}