aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRob Landley <rob@landley.net>2014-05-29 05:22:02 -0500
committerRob Landley <rob@landley.net>2014-05-29 05:22:02 -0500
commitdc640259adff6007d195fd4cc78dcf9829e5e6ee (patch)
tree97ab6eb6abb286a3d612b8aa86646cf655b1a1cf
parent55e9f35223e40f455b80671f25b412072d9af678 (diff)
downloadtoybox-dc640259adff6007d195fd4cc78dcf9829e5e6ee.tar.gz
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.
-rw-r--r--lib/getmountlist.c21
-rw-r--r--lib/lib.h3
-rw-r--r--lib/llist.c14
-rw-r--r--toys/lsb/umount.c5
-rw-r--r--toys/posix/df.c33
5 files changed, 49 insertions, 27 deletions
diff --git a/lib/getmountlist.c b/lib/getmountlist.c
index d5a392d6..0b7ff06b 100644
--- a/lib/getmountlist.c
+++ b/lib/getmountlist.c
@@ -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;
-
- // 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;
diff --git a/lib/lib.h b/lib/lib.h
index bbb1488d..09af2837 100644
--- 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;
diff --git a/lib/llist.c b/lib/llist.c
index 2d5bc97a..6b4b8f2c 100644
--- a/lib/llist.c
+++ b/lib/llist.c
@@ -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;
+}
diff --git a/toys/lsb/umount.c b/toys/lsb/umount.c
index cc40f144..d1a2c69d 100644
--- a/toys/lsb/umount.c
+++ b/toys/lsb/umount.c
@@ -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);
diff --git a/toys/posix/df.c b/toys/posix/df.c
index 7fab4281..afb296b2 100644
--- a/toys/posix/df.c
+++ b/toys/posix/df.c
@@ -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);
}