Fix a bug in the installer.
authorMatthias Schmidt <matthias@dragonflybsd.org>
Tue, 13 Jan 2009 17:51:54 +0000 (18:51 +0100)
committerMatthias Schmidt <matthias@dragonflybsd.org>
Tue, 13 Jan 2009 17:58:30 +0000 (18:58 +0100)
The installer tried to unmount all mount points in order (e.g. /var/tmp
should be unmounted before /var).  The code had a bug which prevent it from
doing it correctly.  It seems that nobody noticed the bug, because the default
file system layout does not suggest subdir mounts.  With the introduction of
PFS and subdir mounts (e.g. a /var/crash PFS), the bug showed up.

Simplify the code a bit and sort the mounted file systems in reverse
lexicographical order.

In-collab-with: mneumann@

contrib/bsdinstaller-1.1.6/src/lib/libinstaller/mount.c

index 0008be2..ef31d0e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c)2004 The DragonFly Project.  All rights reserved.
+ * Copyright (c) 2004-09 The DragonFly Project.  All rights reserved.
  * 
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
 #include "commands.h"
 #include "functions.h"
 
-static void    unmount_all_under_r(struct i_fn_args *, struct commands *,
-                                   const char *, struct statfs *, int);
-
-static void
-unmount_all_under_r(struct i_fn_args *a, struct commands *cmds,
-                   const char *mtpt, struct statfs *mt_array, int count)
+static int
+compare(const void *a, const void *b)
 {
-       struct statfs *mt_ptr;
-       int k = count;
-       int unmount_me = 0;
-
-       for (mt_ptr = mt_array; k > 0; mt_ptr++, k--) {
-               if (strcmp(mt_ptr->f_mntonname, mtpt) == 0)
-                       unmount_me = 1;
-
-               if (strncmp(mt_ptr->f_mntonname, mtpt, strlen(mtpt)) == 0 &&
-                   strlen(mtpt) < strlen(mt_ptr->f_mntonname)) {
-                       unmount_all_under_r(a, cmds,
-                           mt_ptr->f_mntonname, mt_array, count);
-               }
-       }
+       const struct statfs *sa = a;
+       const struct statfs *sb = b;
 
-       if (unmount_me) {
-               command_add(cmds, "%s%s %s",
-                   a->os_root, cmd_name(a, "UMOUNT"), mtpt);
-       }
+       return -strcmp(sa->f_mntonname,
+           sb->f_mntonname);
 }
 
 /*
- * Unmount all mountpoints under a given mountpoint.  Recursively unmounts
- * dependent mountpoints, so that unmount_all'ing /mnt will first unmount
- * /mnt/usr/local, then /mnt/usr, then /mnt itself.
+ * Unmount all mountpoints under a given mountpoint in order (e.g. /var/tmp is
+ * unmounted before /var).
  */
 void
 unmount_all_under(struct i_fn_args *a, struct commands *cmds, const char *fmt, ...)
 {
        struct statfs *mt_array;
-       int count;
+       int count, i;
        char *mtpt;
        va_list args;
 
@@ -98,7 +79,19 @@ unmount_all_under(struct i_fn_args *a, struct commands *cmds, const char *fmt, .
        va_end(args);
 
        count = getmntinfo(&mt_array, MNT_WAIT);
-       unmount_all_under_r(a, cmds, mtpt, mt_array, count);
+
+       /* Order mount points in reverse lexicographically order. */
+       qsort((void*)mt_array, count, sizeof(struct statfs), compare);
+
+       for (i = 0; i < count; i++) {
+               if (strncmp(mtpt, mt_array[i].f_mntonname, strlen(mtpt)) != 0)
+                       continue;
+               if (strlen(mtpt) > strlen(mt_array[i].f_mntonname))
+                       continue;
+
+               command_add(cmds, "%s%s %s",
+                   a->os_root, cmd_name(a, "UMOUNT"), mt_array[i].f_mntonname);
+       }
 
        free(mtpt);
 }