]> git.ipfire.org Git - thirdparty/mdadm.git/blobdiff - Monitor.c
mdmon: refactor md device name check in main()
[thirdparty/mdadm.git] / Monitor.c
index 39598ba0c913ab88f7c0c743631dbf1584935e31..7cee95d4487ab89bb356c50e74712566079c95c6 100644 (file)
--- a/Monitor.c
+++ b/Monitor.c
  */
 
 #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;
@@ -47,15 +57,10 @@ struct state {
        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;
 };
 
@@ -120,13 +125,12 @@ static void link_containers_with_subarrays(struct state *list);
 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,
@@ -216,14 +220,13 @@ int Monitor(struct mddev_dev *devlist,
        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;
        }
 
@@ -234,7 +237,8 @@ int Monitor(struct mddev_dev *devlist,
        }
 
        if (share)
-               write_autorebuild_pid();
+               if (write_autorebuild_pid() != 0)
+                       return 1;
 
        if (devlist == NULL) {
                mdlist = conf_get_ident(NULL);
@@ -243,14 +247,14 @@ int Monitor(struct mddev_dev *devlist,
 
                        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;
@@ -271,7 +275,7 @@ int Monitor(struct mddev_dev *devlist,
 
                        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;
@@ -320,32 +324,12 @@ int Monitor(struct mddev_dev *devlist,
                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;
 
@@ -368,6 +352,49 @@ int Monitor(struct mddev_dev *devlist,
        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:
@@ -404,65 +431,111 @@ static int make_daemon(char *pidfile)
        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"
@@ -890,7 +963,7 @@ static int add_new_arrays(struct mdstat_ent *mdstat, struct state **statelist)
                                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 */
@@ -1199,64 +1272,6 @@ static void free_statelist(struct state *statelist)
        }
 }
 
-#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)
 {
@@ -1291,12 +1306,12 @@ 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) {
@@ -1375,7 +1390,7 @@ int WaitClean(char *dev, int verbose)
 
        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