changeset 1321:4d898affda0c draft

Switch mtab_list to doubly linked so we can traverse in either order. Convert umount and df. Add dlist_terminate() to break lists for traversal in either direction.
author Rob Landley <rob@landley.net>
date Thu, 29 May 2014 05:22:02 -0500
parents b2cc738d3cfc
children b91284c2e569
files lib/getmountlist.c lib/lib.h lib/llist.c toys/lsb/umount.c toys/posix/df.c
diffstat 5 files changed, 48 insertions(+), 26 deletions(-) [+]
line wrap: on
line diff
--- a/lib/getmountlist.c	Tue May 27 07:56:51 2014 -0500
+++ b/lib/getmountlist.c	Thu May 29 05:22:02 2014 -0500
@@ -11,25 +11,28 @@
 
 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;
+    dlist_add_nomalloc((void *)&mtlist, (void *)mt);
 
-    // 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'");
+    // 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;
--- a/lib/lib.h	Tue May 27 07:56:51 2014 -0500
+++ b/lib/lib.h	Thu May 29 05:22:02 2014 -0500
@@ -31,6 +31,7 @@
 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 @@
 
 // getmountlist.c
 struct mtab_list {
-  struct mtab_list *next;
+  struct mtab_list *next, *prev;
   struct stat stat;
   struct statvfs statvfs;
   char *dir;
--- a/lib/llist.c	Tue May 27 07:56:51 2014 -0500
+++ b/lib/llist.c	Thu May 29 05:22:02 2014 -0500
@@ -85,3 +85,17 @@
 
   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;
+}
--- a/toys/lsb/umount.c	Tue May 27 07:56:51 2014 -0500
+++ b/toys/lsb/umount.c	Thu May 29 05:22:02 2014 -0500
@@ -119,7 +119,10 @@
     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);
--- a/toys/posix/df.c	Tue May 27 07:56:51 2014 -0500
+++ b/toys/posix/df.c	Thu May 29 05:22:02 2014 -0500
@@ -95,7 +95,7 @@
 
 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 @@
       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 @@
 
       // 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);
 }