*/
#include "mdadm.h"
+#include "udev.h"
#include "md_p.h"
#include "md_u.h"
#include <sys/wait.h>
#include <limits.h>
#include <syslog.h>
-#ifndef NO_LIBUDEV
-#include <libudev.h>
-#endif
+#define TASK_COMM_LEN 16
#define EVENT_NAME_MAX 32
+#define AUTOREBUILD_PID_PATH MDMON_DIR "/autorebuild.pid"
+#define FALLBACK_DELAY 5
+/**
+ * struct state - external array or container properties.
+ * @devname: has length of %DEV_MD_DIR + device name + terminating byte
+ * @devnm: to sync with mdstat info
+ * @parent_devnm: or subarray, devnm of parent, for others, ""
+ * @subarray: for a container it is a link to first subarray, for a subarray it is a link to next
+ * subarray in the same container
+ * @parent: for a subarray it is a link to its container
+ */
struct state {
- char devname[MD_NAME_MAX + sizeof("/dev/md/")]; /* length of "/dev/md/" + device name + terminating byte*/
- char devnm[MD_NAME_MAX]; /* to sync with mdstat info */
+ char devname[MD_NAME_MAX + sizeof(DEV_MD_DIR)];
+ char devnm[MD_NAME_MAX];
unsigned int utime;
int err;
char *spare_group;
int devstate[MAX_DISKS];
dev_t devid[MAX_DISKS];
int percent;
- char parent_devnm[MD_NAME_MAX]; /* For subarray, devnm of parent.
- * For others, ""
- */
+ char parent_devnm[MD_NAME_MAX];
struct supertype *metadata;
- struct state *subarray;/* for a container it is a link to first subarray
- * for a subarray it is a link to next subarray
- * in the same container */
- struct state *parent; /* for a subarray it is a link to its container
- */
+ struct state *subarray;
+ struct state *parent;
struct state *next;
};
static void free_statelist(struct state *statelist);
static int check_array(struct state *st, struct mdstat_ent *mdstat, int increments, char *prefer);
static int check_one_sharer(int scan);
-#ifndef NO_LIBUDEV
-static int check_udev_activity(void);
-#endif
static void link_containers_with_subarrays(struct state *list);
static int make_daemon(char *pidfile);
static void try_spare_migration(struct state *statelist);
-static void write_autorebuild_pid(void);
+static void wait_for_events(int *delay_for_event, int c_delay);
+static void wait_for_events_mdstat(int *delay_for_event, int c_delay);
+static int write_autorebuild_pid(void);
int Monitor(struct mddev_dev *devlist,
char *mailaddr, char *alert_cmd,
info.dosyslog = dosyslog;
info.test = c->test;
- if (gethostname(info.hostname, sizeof(info.hostname)) != 0) {
+ if (s_gethostname(info.hostname, sizeof(info.hostname)) != 0) {
pr_err("Cannot get hostname.\n");
return 1;
}
- info.hostname[sizeof(info.hostname) - 1] = '\0';
if (share){
- if (check_one_sharer(c->scan))
+ if (check_one_sharer(c->scan) == 2)
return 1;
}
}
if (share)
- write_autorebuild_pid();
+ if (write_autorebuild_pid() != 0)
+ return 1;
if (devlist == NULL) {
mdlist = conf_get_ident(NULL);
if (mdlist->devname == NULL)
continue;
- if (strcasecmp(mdlist->devname, "<ignore>") == 0)
+ if (is_devname_ignore(mdlist->devname) == true)
continue;
if (!is_mddev(mdlist->devname))
continue;
st = xcalloc(1, sizeof *st);
- snprintf(st->devname, MD_NAME_MAX + sizeof("/dev/md/"),
- "/dev/md/%s", basename(mdlist->devname));
+ snprintf(st->devname, MD_NAME_MAX + sizeof(DEV_MD_DIR), DEV_MD_DIR "%s",
+ basename(mdlist->devname));
st->next = statelist;
st->devnm[0] = 0;
st->percent = RESYNC_UNKNOWN;
st = xcalloc(1, sizeof *st);
mdlist = conf_get_ident(dv->devname);
- snprintf(st->devname, MD_NAME_MAX + sizeof("/dev/md/"), "%s", dv->devname);
+ snprintf(st->devname, MD_NAME_MAX + sizeof(DEV_MD_DIR), "%s", dv->devname);
st->next = statelist;
st->devnm[0] = 0;
st->percent = RESYNC_UNKNOWN;
if (!new_found) {
if (oneshot)
break;
- else if (!anyredundant) {
+ if (!anyredundant) {
pr_err("No array with redundancy detected, stopping\n");
break;
}
- else {
-#ifndef NO_LIBUDEV
- /*
- * Wait for udevd to finish new devices
- * processing.
- */
- if (mdstat_wait(delay_for_event) &&
- check_udev_activity())
- pr_err("Error while waiting for UDEV to complete new devices processing\n");
-#else
- int wait_result = mdstat_wait(delay_for_event);
- /*
- * Give chance to process new device
- */
- if (wait_result != 0) {
- if (c->delay > 5)
- delay_for_event = 5;
- } else
- delay_for_event = c->delay;
-#endif
- mdstat_close();
- }
+
+ wait_for_events(&delay_for_event, c->delay);
}
info.test = 0;
return 0;
}
+/*
+ * wait_for_events() - Waits for events on md devices.
+ * @delay_for_event: pointer to current event delay
+ * @c_delay: delay from config
+ */
+static void wait_for_events(int *delay_for_event, int c_delay)
+{
+#ifndef NO_LIBUDEV
+ if (udev_is_available()) {
+ if (udev_wait_for_events(*delay_for_event) == UDEV_STATUS_ERROR)
+ pr_err("Error while waiting for udev events.\n");
+ return;
+ }
+#endif
+ wait_for_events_mdstat(delay_for_event, c_delay);
+}
+
+/*
+ * wait_for_events_mdstat() - Waits for events on mdstat.
+ * @delay_for_event: pointer to current event delay
+ * @c_delay: delay from config
+ */
+static void wait_for_events_mdstat(int *delay_for_event, int c_delay)
+{
+ int wait_result = mdstat_wait(*delay_for_event);
+
+ if (wait_result < 0) {
+ pr_err("Error while waiting for events on mdstat.\n");
+ return;
+ }
+
+ /*
+ * Give chance to process new device
+ */
+ if (wait_result != 0) {
+ if (c_delay > FALLBACK_DELAY)
+ *delay_for_event = FALLBACK_DELAY;
+ } else {
+ *delay_for_event = c_delay;
+ }
+ mdstat_close();
+}
+
static int make_daemon(char *pidfile)
{
/* Return:
return -1;
}
+/*
+ * check_one_sharer() - Checks for other mdmon processes running.
+ *
+ * Return:
+ * 0 - no other processes running,
+ * 1 - warning,
+ * 2 - error, or when scan mode is enabled, and one mdmon process already exists
+ */
static int check_one_sharer(int scan)
{
int pid;
- FILE *comm_fp;
- FILE *fp;
+ FILE *fp, *comm_fp;
char comm_path[PATH_MAX];
- char path[PATH_MAX];
- char comm[20];
-
- sprintf(path, "%s/autorebuild.pid", MDMON_DIR);
- fp = fopen(path, "r");
- if (fp) {
- if (fscanf(fp, "%d", &pid) != 1)
- pid = -1;
- snprintf(comm_path, sizeof(comm_path),
- "/proc/%d/comm", pid);
- comm_fp = fopen(comm_path, "r");
- if (comm_fp) {
- if (fscanf(comm_fp, "%19s", comm) &&
- strncmp(basename(comm), Name, strlen(Name)) == 0) {
- if (scan) {
- pr_err("Only one autorebuild process allowed in scan mode, aborting\n");
- fclose(comm_fp);
- fclose(fp);
- return 1;
- } else {
- pr_err("Warning: One autorebuild process already running.\n");
- }
- }
+ char comm[TASK_COMM_LEN];
+
+ if (!is_directory(MDMON_DIR)) {
+ pr_err("%s is not a regular directory.\n", MDMON_DIR);
+ return 2;
+ }
+
+ fp = fopen(AUTOREBUILD_PID_PATH, "r");
+ if (!fp) {
+ pr_err("Cannot open %s file.\n", AUTOREBUILD_PID_PATH);
+ return 2;
+ }
+
+ if (!is_file(AUTOREBUILD_PID_PATH)) {
+ pr_err("%s is not a regular file.\n", AUTOREBUILD_PID_PATH);
+ return 2;
+ }
+
+ if (fscanf(fp, "%d", &pid) != 1) {
+ pr_err("Cannot read pid from %s file.\n", AUTOREBUILD_PID_PATH);
+ fclose(fp);
+ return 2;
+ }
+
+ snprintf(comm_path, sizeof(comm_path), "/proc/%d/comm", pid);
+
+ comm_fp = fopen(comm_path, "r");
+ if (!comm_fp) {
+ dprintf("Warning: Cannot open %s, continuing\n", comm_path);
+ fclose(fp);
+ return 1;
+ }
+
+ if (fscanf(comm_fp, "%15s", comm) == 0) {
+ dprintf("Warning: Cannot read comm from %s, continuing\n", comm_path);
+ fclose(comm_fp);
+ fclose(fp);
+ return 1;
+ }
+
+ if (strncmp(basename(comm), Name, strlen(Name)) == 0) {
+ if (scan) {
+ pr_err("Only one autorebuild process allowed in scan mode, aborting\n");
fclose(comm_fp);
+ fclose(fp);
+ return 2;
}
- fclose(fp);
+ pr_err("Warning: One autorebuild process already running.\n");
}
+ fclose(comm_fp);
+ fclose(fp);
return 0;
}
-static void write_autorebuild_pid()
+/*
+ * write_autorebuild_pid() - Writes pid to autorebuild.pid file.
+ *
+ * Return: 0 on success, 1 on error
+ */
+static int write_autorebuild_pid(void)
{
- char path[PATH_MAX];
- int pid;
- FILE *fp = NULL;
- sprintf(path, "%s/autorebuild.pid", MDMON_DIR);
+ FILE *fp;
+ int fd;
if (mkdir(MDMON_DIR, 0700) < 0 && errno != EEXIST) {
- pr_err("Can't create autorebuild.pid file\n");
- } else {
- int fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0700);
+ pr_err("%s: %s\n", strerror(errno), MDMON_DIR);
+ return 1;
+ }
- if (fd >= 0)
- fp = fdopen(fd, "w");
+ if (!is_directory(MDMON_DIR)) {
+ pr_err("%s is not a regular directory.\n", MDMON_DIR);
+ return 1;
+ }
- if (!fp)
- pr_err("Can't create autorebuild.pid file\n");
- else {
- pid = getpid();
- fprintf(fp, "%d\n", pid);
- fclose(fp);
- }
+ fd = open(AUTOREBUILD_PID_PATH, O_WRONLY | O_CREAT | O_TRUNC, 0700);
+
+ if (fd < 0) {
+ pr_err("Error opening %s file.\n", AUTOREBUILD_PID_PATH);
+ return 1;
}
+
+ fp = fdopen(fd, "w");
+
+ if (!fp) {
+ pr_err("Error opening fd for %s file.\n", AUTOREBUILD_PID_PATH);
+ return 1;
+ }
+
+ fprintf(fp, "%d\n", getpid());
+
+ fclose(fp);
+ return 0;
}
#define BASE_MESSAGE "%s event detected on md device %s"
continue;
}
- snprintf(st->devname, MD_NAME_MAX + sizeof("/dev/md/"), "%s", name);
+ snprintf(st->devname, MD_NAME_MAX + sizeof(DEV_MD_DIR), "%s", name);
if ((fd = open(st->devname, O_RDONLY)) < 0 ||
md_get_array_info(fd, &array) < 0) {
/* no such array */
}
}
-#ifndef NO_LIBUDEV
-/* function: check_udev_activity
- * Description: Function waits for udev to finish
- * events processing.
- * Returns:
- * 1 - detected error while opening udev
- * 2 - timeout
- * 0 - successfull completion
- */
-static int check_udev_activity(void)
-{
- struct udev *udev = NULL;
- struct udev_queue *udev_queue = NULL;
- int timeout_cnt = 30;
- int rc = 0;
-
- /*
- * In rare cases systemd may not have udevm,
- * in such cases just exit with rc 0
- */
- if (!use_udev())
- goto out;
-
- udev = udev_new();
- if (!udev) {
- rc = 1;
- goto out;
- }
-
- udev_queue = udev_queue_new(udev);
- if (!udev_queue) {
- rc = 1;
- goto out;
- }
-
- if (udev_queue_get_queue_is_empty(udev_queue))
- goto out;
-
- while (!udev_queue_get_queue_is_empty(udev_queue)) {
- sleep(1);
-
- if (timeout_cnt)
- timeout_cnt--;
- else {
- rc = 2;
- goto out;
- }
- }
-
-out:
- if (udev_queue)
- udev_queue_unref(udev_queue);
- if (udev)
- udev_unref(udev);
- return rc;
-}
-#endif
-
/* Not really Monitor but ... */
int Wait(char *dev)
{
* sync_action does.
*/
struct mdinfo mdi;
- char buf[21];
+ char buf[SYSFS_MAX_BUF_SIZE];
if (sysfs_init(&mdi, -1, devnm))
return 2;
if (sysfs_get_str(&mdi, NULL, "sync_action",
- buf, 20) > 0 &&
+ buf, sizeof(buf)) > 0 &&
strcmp(buf,"idle\n") != 0) {
e->percent = RESYNC_UNKNOWN;
if (strcmp(buf, "frozen\n") == 0) {
if (rv) {
int state_fd = sysfs_open(fd2devnm(fd), NULL, "array_state");
- char buf[20];
+ char buf[SYSFS_MAX_BUF_SIZE];
int delay = 5000;
/* minimize the safe_mode_delay and prepare to wait up to 5s