|
Packit Service |
db8df9 |
/*
|
|
Packit Service |
db8df9 |
* Intel(R) Enclosure LED Utilities
|
|
Packit Service |
db8df9 |
* Copyright (C) 2017-2020 Intel Corporation.
|
|
Packit Service |
db8df9 |
*
|
|
Packit Service |
db8df9 |
* This program is free software; you can redistribute it and/or modify it
|
|
Packit Service |
db8df9 |
* under the terms and conditions of the GNU General Public License,
|
|
Packit Service |
db8df9 |
* version 2, as published by the Free Software Foundation.
|
|
Packit Service |
db8df9 |
*
|
|
Packit Service |
db8df9 |
* This program is distributed in the hope it will be useful, but WITHOUT
|
|
Packit Service |
db8df9 |
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
Packit Service |
db8df9 |
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
Packit Service |
db8df9 |
* more details.
|
|
Packit Service |
db8df9 |
*
|
|
Packit Service |
db8df9 |
* You should have received a copy of the GNU General Public License along with
|
|
Packit Service |
db8df9 |
* this program; if not, write to the Free Software Foundation, Inc.,
|
|
Packit Service |
db8df9 |
* 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
|
Packit Service |
db8df9 |
*
|
|
Packit Service |
db8df9 |
*/
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
#include <libudev.h>
|
|
Packit Service |
db8df9 |
#include <limits.h>
|
|
Packit Service |
db8df9 |
#include <stdint.h>
|
|
Packit Service |
db8df9 |
#include <string.h>
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
#include "block.h"
|
|
Packit Service |
db8df9 |
#include "ibpi.h"
|
|
Packit Service |
db8df9 |
#include "status.h"
|
|
Packit Service |
db8df9 |
#include "sysfs.h"
|
|
Packit Service |
db8df9 |
#include "udev.h"
|
|
Packit Service |
db8df9 |
#include "utils.h"
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
static struct udev_monitor *udev_monitor;
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
static int _compare(const struct block_device *bd, const char *syspath)
|
|
Packit Service |
db8df9 |
{
|
|
Packit Service |
db8df9 |
if (!bd || !syspath)
|
|
Packit Service |
db8df9 |
return 0;
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
if (strcmp(bd->sysfs_path, syspath) == 0) {
|
|
Packit Service |
db8df9 |
return 1;
|
|
Packit Service |
db8df9 |
} else {
|
|
Packit Service |
db8df9 |
struct block_device *bd_new;
|
|
Packit Service |
db8df9 |
int ret;
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
bd_new = block_device_init(sysfs_get_cntrl_devices(), syspath);
|
|
Packit Service |
db8df9 |
if (!bd_new)
|
|
Packit Service |
db8df9 |
return 0;
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
ret = block_compare(bd, bd_new);
|
|
Packit Service |
db8df9 |
block_device_fini(bd_new);
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
return ret;
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
static int create_udev_monitor(void)
|
|
Packit Service |
db8df9 |
{
|
|
Packit Service |
db8df9 |
int res;
|
|
Packit Service |
db8df9 |
struct udev *udev = udev_new();
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
if (!udev) {
|
|
Packit Service |
db8df9 |
log_error("Failed to create udev context instance.");
|
|
Packit Service |
db8df9 |
return -1;
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
udev_monitor = udev_monitor_new_from_netlink(udev, "udev");
|
|
Packit Service |
db8df9 |
if (!udev_monitor) {
|
|
Packit Service |
db8df9 |
log_error("Failed to create udev monitor object.");
|
|
Packit Service |
db8df9 |
udev_unref(udev);
|
|
Packit Service |
db8df9 |
return -1;
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
res = udev_monitor_filter_add_match_subsystem_devtype(udev_monitor,
|
|
Packit Service |
db8df9 |
"block", "disk");
|
|
Packit Service |
db8df9 |
if (res < 0) {
|
|
Packit Service |
db8df9 |
log_error("Failed to modify udev monitor filters.");
|
|
Packit Service |
db8df9 |
stop_udev_monitor();
|
|
Packit Service |
db8df9 |
return -1;
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
res = udev_monitor_enable_receiving(udev_monitor);
|
|
Packit Service |
db8df9 |
if (res < 0) {
|
|
Packit Service |
db8df9 |
log_error("Failed to switch udev monitor to listening mode.");
|
|
Packit Service |
db8df9 |
stop_udev_monitor();
|
|
Packit Service |
db8df9 |
return -1;
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
return udev_monitor_get_fd(udev_monitor);
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
void stop_udev_monitor(void)
|
|
Packit Service |
db8df9 |
{
|
|
Packit Service |
db8df9 |
if (udev_monitor) {
|
|
Packit Service |
db8df9 |
struct udev *udev = udev_monitor_get_udev(udev_monitor);
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
udev_monitor_unref(udev_monitor);
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
if (udev)
|
|
Packit Service |
db8df9 |
udev_unref(udev);
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
int get_udev_monitor(void)
|
|
Packit Service |
db8df9 |
{
|
|
Packit Service |
db8df9 |
if (udev_monitor)
|
|
Packit Service |
db8df9 |
return udev_monitor_get_fd(udev_monitor);
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
return create_udev_monitor();
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
static int _check_raid(const char *path)
|
|
Packit Service |
db8df9 |
{
|
|
Packit Service |
db8df9 |
char *t = strrchr(path, '/');
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
if (t == NULL)
|
|
Packit Service |
db8df9 |
return 0;
|
|
Packit Service |
db8df9 |
return strncmp(t + 1, "md", 2) == 0;
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
static enum udev_action _get_udev_action(const char *action)
|
|
Packit Service |
db8df9 |
{
|
|
Packit Service |
db8df9 |
enum udev_action ret = UDEV_ACTION_UNKNOWN;
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
if (strncmp(action, "add", 3) == 0)
|
|
Packit Service |
db8df9 |
ret = UDEV_ACTION_ADD;
|
|
Packit Service |
db8df9 |
else if (strncmp(action, "remove", 6) == 0)
|
|
Packit Service |
db8df9 |
ret = UDEV_ACTION_REMOVE;
|
|
Packit Service |
db8df9 |
return ret;
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
static void _clear_raid_dev_info(struct block_device *block, char *raid_dev)
|
|
Packit Service |
db8df9 |
{
|
|
Packit Service |
db8df9 |
if (block->raid_dev && block->raid_dev->sysfs_path) {
|
|
Packit Service |
db8df9 |
char *tmp = strrchr(block->raid_dev->sysfs_path, '/');
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
if (tmp == NULL) {
|
|
Packit Service |
db8df9 |
log_debug("Device: %s have wrong raid_dev path: %s",
|
|
Packit Service |
db8df9 |
block->sysfs_path,
|
|
Packit Service |
db8df9 |
block->raid_dev->sysfs_path);
|
|
Packit Service |
db8df9 |
return;
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
if (strcmp(raid_dev, tmp + 1) == 0) {
|
|
Packit Service |
db8df9 |
log_debug("CLEAR raid_dev %s in %s ",
|
|
Packit Service |
db8df9 |
raid_dev, block->sysfs_path);
|
|
Packit Service |
db8df9 |
raid_device_fini(block->raid_dev);
|
|
Packit Service |
db8df9 |
block->raid_dev = NULL;
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
int handle_udev_event(struct list *ledmon_block_list)
|
|
Packit Service |
db8df9 |
{
|
|
Packit Service |
db8df9 |
struct udev_device *dev;
|
|
Packit Service |
db8df9 |
int status = -1;
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
dev = udev_monitor_receive_device(udev_monitor);
|
|
Packit Service |
db8df9 |
if (dev) {
|
|
Packit Service |
db8df9 |
const char *action = udev_device_get_action(dev);
|
|
Packit Service |
db8df9 |
enum udev_action act = _get_udev_action(action);
|
|
Packit Service |
db8df9 |
const char *syspath = udev_device_get_syspath(dev);
|
|
Packit Service |
db8df9 |
struct block_device *block = NULL;
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
if (act == UDEV_ACTION_UNKNOWN) {
|
|
Packit Service |
db8df9 |
status = 1;
|
|
Packit Service |
db8df9 |
goto exit;
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
list_for_each(ledmon_block_list, block) {
|
|
Packit Service |
db8df9 |
if (_compare(block, syspath))
|
|
Packit Service |
db8df9 |
break;
|
|
Packit Service |
db8df9 |
block = NULL;
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
if (!block) {
|
|
Packit Service |
db8df9 |
if (act == UDEV_ACTION_REMOVE && _check_raid(syspath)) {
|
|
Packit Service |
db8df9 |
/*ledmon is interested about removed arrays*/
|
|
Packit Service |
db8df9 |
char *dev_name;
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
dev_name = strrchr(syspath, '/') + 1;
|
|
Packit Service |
db8df9 |
log_debug("REMOVED %s", dev_name);
|
|
Packit Service |
db8df9 |
list_for_each(ledmon_block_list, block)
|
|
Packit Service |
db8df9 |
_clear_raid_dev_info(block, dev_name);
|
|
Packit Service |
db8df9 |
status = 0;
|
|
Packit Service |
db8df9 |
goto exit;
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
status = 1;
|
|
Packit Service |
db8df9 |
goto exit;
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
if (act == UDEV_ACTION_ADD) {
|
|
Packit Service |
db8df9 |
log_debug("ADDED %s", block->sysfs_path);
|
|
Packit Service |
db8df9 |
if (block->ibpi == IBPI_PATTERN_FAILED_DRIVE ||
|
|
Packit Service |
db8df9 |
block->ibpi == IBPI_PATTERN_REMOVED ||
|
|
Packit Service |
db8df9 |
block->ibpi == IBPI_PATTERN_UNKNOWN)
|
|
Packit Service |
db8df9 |
block->ibpi = IBPI_PATTERN_ADDED;
|
|
Packit Service |
db8df9 |
} else if (act == UDEV_ACTION_REMOVE) {
|
|
Packit Service |
db8df9 |
log_debug("REMOVED %s", block->sysfs_path);
|
|
Packit Service |
db8df9 |
block->ibpi = IBPI_PATTERN_REMOVED;
|
|
Packit Service |
db8df9 |
} else {
|
|
Packit Service |
db8df9 |
/* not interesting event */
|
|
Packit Service |
db8df9 |
status = 1;
|
|
Packit Service |
db8df9 |
goto exit;
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
status = 0;
|
|
Packit Service |
db8df9 |
} else {
|
|
Packit Service |
db8df9 |
return -1;
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
exit:
|
|
Packit Service |
db8df9 |
udev_device_unref(dev);
|
|
Packit Service |
db8df9 |
return status;
|
|
Packit Service |
db8df9 |
}
|