]> git.ipfire.org Git - thirdparty/mdadm.git/blobdiff - lib.c
Report replacement devices correctly with --detail and --examine
[thirdparty/mdadm.git] / lib.c
diff --git a/lib.c b/lib.c
index 2739b3d388b2833d6a7f271242d8ab065f2fe11d..1c856541c9cc538ea2f142af75ef8f7fa81e9c2a 100644 (file)
--- a/lib.c
+++ b/lib.c
@@ -70,7 +70,7 @@ char *devnum2devname(int num)
 {
        char name[100];
        fmt_devname(name,num);
-       return strdup(name);
+       return xstrdup(name);
 }
 
 int devname2devnum(char *name)
@@ -133,9 +133,9 @@ int fd2devnum(int fd)
  * Put them in a simple linked listfor now.
  */
 struct devmap {
-    int major, minor;
-    char *name;
-    struct devmap *next;
+       int major, minor;
+       char *name;
+       struct devmap *next;
 } *devlist = NULL;
 int devlist_ready = 0;
 
@@ -150,8 +150,8 @@ int add_dev(const char *name, const struct stat *stb, int flag, struct FTW *s)
        }
 
        if ((stb->st_mode&S_IFMT)== S_IFBLK) {
-               char *n = strdup(name);
-               struct devmap *dm = malloc(sizeof(*dm));
+               char *n = xstrdup(name);
+               struct devmap *dm = xmalloc(sizeof(*dm));
                if (strncmp(n, "/dev/./", 7)==0)
                        strcpy(n+4, name+6);
                if (dm) {
@@ -188,8 +188,11 @@ int nftw(const char *path, int (*han)(const char *name, const struct stat *stb,
  * If we find multiple names, choose the shortest.
  * If we find a name in /dev/md/, we prefer that.
  * This applies only to names for MD devices.
+ * If 'prefer' is set (normally to e.g. /by-path/)
+ * then we prefer a name which contains that string.
  */
-char *map_dev(int major, int minor, int create)
+char *map_dev_preferred(int major, int minor, int create,
+                       char *prefer)
 {
        struct devmap *p;
        char *regular = NULL, *preferred=NULL;
@@ -219,7 +222,8 @@ char *map_dev(int major, int minor, int create)
        for (p=devlist; p; p=p->next)
                if (p->major == major &&
                    p->minor == minor) {
-                       if (strncmp(p->name, "/dev/md/",8) == 0) {
+                       if (strncmp(p->name, "/dev/md/",8) == 0
+                           || (prefer && strstr(p->name, prefer))) {
                                if (preferred == NULL ||
                                    strlen(p->name) < strlen(preferred))
                                        preferred = p->name;
@@ -243,6 +247,7 @@ char *map_dev(int major, int minor, int create)
 }
 
 
+
 /* conf_word gets one word from the conf file.
  * if "allow_key", then accept words at the start of a line,
  * otherwise stop when such a word is found.
@@ -257,9 +262,7 @@ char *conf_word(FILE *file, int allow_key)
        int c;
        int quote;
        int wordfound = 0;
-       char *word = malloc(wsize);
-
-       if (!word) abort();
+       char *word = xmalloc(wsize);
 
        while (wordfound==0) {
                /* at the end of a word.. */
@@ -289,8 +292,7 @@ char *conf_word(FILE *file, int allow_key)
                                else {
                                        if (len == wsize-1) {
                                                wsize += 100;
-                                               word = realloc(word, wsize);
-                                               if (!word) abort();
+                                               word = xrealloc(word, wsize);
                                        }
                                        word[len++] = c;
                                }
@@ -320,3 +322,71 @@ char *conf_word(FILE *file, int allow_key)
        }
        return word;
 }
+
+void print_quoted(char *str)
+{
+       /* Printf the string with surrounding quotes
+        * iff needed.
+        * If no space, tab, or quote - leave unchanged.
+        * Else print surrounded by " or ', swapping quotes
+        * when we find one that will cause confusion.
+        */
+
+       char first_quote = 0, q;
+       char *c;
+
+       for (c = str; *c; c++) {
+               switch(*c) {
+               case '\'':
+               case '"':
+                       first_quote = *c;
+                       break;
+               case ' ':
+               case '\t':
+                       first_quote = *c;
+                       continue;
+               default:
+                       continue;
+               }
+               break;
+       }
+       if (!first_quote) {
+               printf("%s", str);
+               return;
+       }
+
+       if (first_quote == '"')
+               q = '\'';
+       else
+               q = '"';
+       putchar(q);
+       for (c = str; *c; c++) {
+               if (*c == q) {
+                       putchar(q);
+                       q ^= '"' ^ '\'';
+                       putchar(q);
+               }
+               putchar(*c);
+       }
+       putchar(q);
+}
+
+void print_escape(char *str)
+{
+       /* print str, but change space and tab to '_'
+        * as is suitable for device names
+        */
+       for (; *str ; str++) {
+               switch (*str) {
+               case ' ':
+               case '\t':
+                       putchar('_');
+                       break;
+               case '/':
+                       putchar('-');
+                       break;
+               default:
+                       putchar(*str);
+               }
+       }
+}