OSDN Git Service

Switch mtab_list to doubly linked so we can traverse in either order. Convert umount...
authorRob Landley <rob@landley.net>
Thu, 29 May 2014 10:22:02 +0000 (05:22 -0500)
committerRob Landley <rob@landley.net>
Thu, 29 May 2014 10:22:02 +0000 (05:22 -0500)
lib/getmountlist.c
lib/lib.h
lib/llist.c
toys/lsb/umount.c
toys/posix/df.c

index d5a392d..0b7ff06 100644 (file)
 
 struct mtab_list *xgetmountlist(char *path)
 {
-  struct mtab_list *mtlist, *mt;
+  struct mtab_list *mtlist = 0, *mt;
   struct mntent *me;
   FILE *fp;
+  char *p = path ? path : "/proc/mounts";
 
-  if (!path) path = "/proc/mounts";
-  if (!(fp = setmntent(path, "r"))) perror_exit("bad %s", path);
+  if (!(fp = setmntent(p, "r"))) perror_exit("bad %s", p);
 
   // The "test" part of the loop is done before the first time through and
   // again after each "increment", so putting the actual load there avoids
   // duplicating it. If the load was NULL, the loop stops.
 
-  for (mtlist = 0; (me = getmntent(fp)); mtlist = mt) {
+  while ((me = getmntent(fp))) {
     mt = xzalloc(sizeof(struct mtab_list) + strlen(me->mnt_fsname) +
       strlen(me->mnt_dir) + strlen(me->mnt_type) + strlen(me->mnt_opts) + 4);
-    mt->next = mtlist;
-
-    // Collect details about mounted filesystem (don't bother for /etc/fstab).
-    if (stat(me->mnt_dir, &(mt->stat)) || statvfs(me->mnt_dir, &(mt->statvfs)))
-      perror_msg("stat '%s'");
+    dlist_add_nomalloc((void *)&mtlist, (void *)mt);
+
+    // Collect details about mounted filesystem
+    // Don't report errors, just leave data zeroed
+    if (!path) {
+      stat(me->mnt_dir, &(mt->stat));
+      statvfs(me->mnt_dir, &(mt->statvfs));
+    }
 
     // Remember information from /proc/mounts
     mt->dir = stpcpy(mt->type, me->mnt_type)+1;
index bbb1488..09af283 100644 (file)
--- a/lib/lib.h
+++ b/lib/lib.h
@@ -31,6 +31,7 @@ void *llist_pop(void *list);  // actually void **list
 void *dlist_pop(void *list);  // actually struct double_list **list
 void dlist_add_nomalloc(struct double_list **list, struct double_list *new);
 struct double_list *dlist_add(struct double_list **list, char *data);
+void *dlist_terminate(void *list);
 
 // args.c
 void get_optflags(void);
@@ -162,7 +163,7 @@ int xsocket(int domain, int type, int protocol);
 
 // getmountlist.c
 struct mtab_list {
-  struct mtab_list *next;
+  struct mtab_list *next, *prev;
   struct stat stat;
   struct statvfs statvfs;
   char *dir;
index 2d5bc97..6b4b8f2 100644 (file)
@@ -85,3 +85,17 @@ struct double_list *dlist_add(struct double_list **list, char *data)
 
   return new;
 }
+
+// Terminate circular list for traversal in either direction. Returns end *.
+void *dlist_terminate(void *list)
+{
+  struct double_list *end = list;
+
+  if (!list) return 0;
+
+  end = end->prev;
+  end->next->prev = 0;
+  end->next = 0;
+
+  return end;
+}
index cc40f14..d1a2c69 100644 (file)
@@ -119,7 +119,10 @@ void umount_main(void)
     if (TT.t) arg_comma_collate(&typestr, TT.t);
 
     // Loop through mounted filesystems
-    for (mlsave = ml = xgetmountlist(0); ml; ml = ml->next) {
+    mlsave = xgetmountlist(0);
+    ml = ml->prev;
+
+    for (ml = dlist_terminate(mlsave); ml; ml = ml->prev) {
       if (TT.t) {
         char *type, *types = typestr;
         int len, skip = strncmp(types, "no", 2);
index 7fab428..afb296b 100644 (file)
@@ -95,7 +95,7 @@ static void show_mt(struct mtab_list *mt)
 
 void df_main(void)
 {
-  struct mtab_list *mt, *mt2, *mtlist;
+  struct mtab_list *mt, *mtstart, *mtend;
 
   // Handle -P and -k
   TT.units = 1024;
@@ -106,7 +106,8 @@ void df_main(void)
       TT.units);
   } else puts("Filesystem\t1K-blocks\tUsed Available Use% Mounted on");
 
-  mtlist = xgetmountlist(0);
+  if (!(mtstart = xgetmountlist(0))) return;
+  mtend = dlist_terminate(mtstart);
 
   // If we have a list of filesystems on the command line, loop through them.
   if (*toys.optargs) {
@@ -123,36 +124,36 @@ void df_main(void)
 
       // Find and display this filesystem.  Use _last_ hit in case of
       // overmounts (which is first hit in the reversed list).
-      mt2 = NULL;
-      for (mt = mtlist; mt; mt = mt->next) {
+      for (mt = mtend; mt; mt = mt->prev) {
         if (st.st_dev == mt->stat.st_dev) {
-          mt2 = mt;
+          show_mt(mt);
           break;
         }
       }
-      show_mt(mt2);
     }
   } else {
-    // Get and loop through mount list.
-
-    for (mt = mtlist; mt; mt = mt->next) {
+    // Loop through mount list to filter out overmounts.
+    for (mt = mtend; mt; mt = mt->prev) {
       struct mtab_list *mt2, *mt3;
 
+      // 0:0 is LANANA null device
       if (!mt->stat.st_dev) continue;
 
       // Filter out overmounts.
       mt3 = mt;
-      for (mt2 = mt->next; mt2; mt2 = mt2->next) {
+      for (mt2 = mt->prev; mt2; mt2 = mt2->prev) {
         if (mt->stat.st_dev == mt2->stat.st_dev) {
-          // For --bind mounts, take last match
-          if (!strcmp(mt->device, mt2->device)) mt3 = mt2;
-          // Filter out overmounts
-          mt2->stat.st_dev = 0;
+          // For --bind mounts, take show earliest mount
+          if (!strcmp(mt->device, mt2->device)) {
+            if (!toys.optflags & FLAG_a) mt3->stat.st_dev = 0;
+            mt3 = mt2;
+          } else mt2->stat.st_dev = 0;
         }
       }
-      show_mt(mt3);
     }
+    // Cosmetic: show filesystems in creation order
+    for (mt = mtstart; mt; mt = mt->next) if (mt->stat.st_dev) show_mt(mt);
   }
 
-  if (CFG_TOYBOX_FREE) llist_traverse(mtlist, free);
+  if (CFG_TOYBOX_FREE) llist_traverse(mtstart, free);
 }