]> err.no Git - util-linux/commitdiff
findmnt: rewrite to use lib/tt.c
authorKarel Zak <kzak@redhat.com>
Tue, 6 Apr 2010 14:16:27 +0000 (16:16 +0200)
committerKarel Zak <kzak@redhat.com>
Thu, 3 Jun 2010 13:20:12 +0000 (15:20 +0200)
Signed-off-by: Karel Zak <kzak@redhat.com>
misc-utils/Makefile.am
misc-utils/findmnt.c

index 218a2103a514b0189d3b6ac19d21bce5a1e69f40..b5029166a4e475de334b8700aa0bfb6026041039 100644 (file)
@@ -47,6 +47,7 @@ wipefs_LDADD = $(ul_libblkid_la)
 wipefs_CFLAGS = $(AM_CFLAGS) -I$(ul_libblkid_incdir)
 findmnt_LDADD = $(ul_libmount_la)
 findmnt_CFLAGS = $(AM_CFLAGS) -I$(ul_libmount_incdir)
+findmnt_SOURCES = findmnt.c $(top_srcdir)/lib/tt.c
 if HAVE_STATIC_BLKID
 sbin_PROGRAMS += blkid.static
 blkid_static_SOURCES = $(blkid_SOURCES)
index 0fdb16c9526c7957016093d52704430d7e73a360..70678235f0fa3e96cc67394b5c1b41334ddd4ed2 100644 (file)
@@ -18,7 +18,6 @@
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
-
 #include <stdio.h>
 #include <stdlib.h>
 #include <errno.h>
 #ifdef HAVE_SYS_IOCTL_H
 #include <sys/ioctl.h>
 #endif
-#include <mount.h>
-
 #include <assert.h>
 
+#include <mount.h>
+
 #include "pathnames.h"
 #include "nls.h"
-#include "widechar.h"
 #include "c.h"
+#include "tt.h"
 
 /* flags */
 enum {
@@ -48,10 +47,7 @@ enum {
        FL_CANONICALIZE = (1 << 2),
        FL_FIRSTONLY    = (1 << 3),
        FL_INVERT       = (1 << 4),
-       FL_NOHEADINGS   = (1 << 5),
        FL_NOSWAPMATCH  = (1 << 6),
-       FL_TREE         = (1 << 7),
-       FL_RAW          = (1 << 8)
 };
 
 /* column IDs */
@@ -66,101 +62,42 @@ enum {
        __NCOLUMNS
 };
 
-struct treenode {
-       mnt_fs          *fs;            /* filesystem */
-
-       struct treenode *parent;
-       struct treenode *first;         /* first child */
-       struct treenode *last;          /* last child */
-
-       struct treenode *next;          /* next node in the same level */
-};
-
 /* column names */
 struct colinfo {
        const char      *name;          /* header */
        double          whint;          /* width hint (N < 1 is in percent of termwidth) */
-       int             wrap;           /* boolean (FALSE = truncate the column) */
-
-       int             width;          /* real column width */
+       int             truncate;       /* boolean */
        const char      *match;         /* pattern for match_func() */
 };
 
 /* columns descriptions */
 struct colinfo infos[__NCOLUMNS] = {
-       [COL_SOURCE]  = { "SOURCE",     0.25, TRUE },
-       [COL_TARGET]  = { "TARGET",     0.30, TRUE },
-       [COL_FSTYPE]  = { "FSTYPE",     0.10, FALSE },
-       [COL_OPTIONS] = { "OPTIONS",    0.10, FALSE },
-       [COL_LABEL]   = { "LABEL",      0.10, TRUE },
-       [COL_UUID]    = { "UUID",         36, TRUE },
+       [COL_SOURCE]  = { "SOURCE",     0.25, FALSE },
+       [COL_TARGET]  = { "TARGET",     0.30, FALSE },
+       [COL_FSTYPE]  = { "FSTYPE",     0.10, TRUE },
+       [COL_OPTIONS] = { "OPTIONS",    0.10, TRUE },
+       [COL_LABEL]   = { "LABEL",      0.10, FALSE },
+       [COL_UUID]    = { "UUID",         36, FALSE },
 };
 
-struct treesym {
-       const char *branch;
-       const char *vert;
-       const char *right;
-};
-const struct treesym ascii_tree_symbols = {
-       .branch = "|-",
-       .vert   = "| ",
-       .right  = "`-",
-};
-
-#ifdef HAVE_WIDECHAR
-
-#define        mbs_width(_s)   mbstowcs(NULL, _s, 0)
-
-#define UTF_V  "\342\224\202"  /* U+2502, Vertical line drawing char */
-#define UTF_VR "\342\224\234"  /* U+251C, Vertical and right */
-#define UTF_H  "\342\224\200"  /* U+2500, Horizontal */
-#define UTF_UR "\342\224\224"  /* U+2514, Up and right */
-
-const struct treesym utf_tree_symbols = {
-       .branch = UTF_VR UTF_H,
-       .vert   = UTF_V " ",
-       .right  = UTF_UR UTF_H,
-};
-
-const struct treesym *tree_symbols = &utf_tree_symbols;
-
-#else /* !HAVE_WIDECHAR */
-
-# define mbs_width       strlen(_s)
-const struct treesym *tree_symbols = &ascii_tree_symbols;
-
-#endif /* !HAVE_WIDECHAR */
-
 /* global flags */
 int flags;
 
-/* array IDs of with enabled columns */
+/* array with IDs of enabled columns */
 int columns[__NCOLUMNS];
 int ncolumns;
 
-int termwidth; /* terminal width */
-char *treebuf; /* buffer for target column in tree mode */
-
 /* libmount cache */
 mnt_cache *cache;
 
-
-static inline int is_last_column(int num)
-{
-       return num + 1 == ncolumns;
-}
-
 static inline int get_column_id(int num)
 {
-       int id;
        assert(num < ncolumns);
-
-       id = columns[num];
-       assert(id < __NCOLUMNS);
-       return id;
+       assert(columns[num] < __NCOLUMNS);
+       return columns[num];
 }
 
-static inline struct colinfo *get_column_desc(int num)
+static inline struct colinfo *get_column_info(int num)
 {
        return &infos[ get_column_id(num) ];
 }
@@ -173,27 +110,17 @@ static inline const char *column_id_to_name(int id)
 
 static inline const char *get_column_name(int num)
 {
-       return get_column_desc(num)->name;
+       return get_column_info(num)->name;
 }
 
 static inline float get_column_whint(int num)
 {
-       return get_column_desc(num)->whint;
+       return get_column_info(num)->whint;
 }
 
-static inline int get_column_width(int num)
+static inline int get_column_truncate(int num)
 {
-       return get_column_desc(num)->width;
-}
-
-static inline void set_column_width(int num, int width)
-{
-       get_column_desc(num)->width = width;
-}
-
-static inline int get_column_wrap(int num)
-{
-       return get_column_desc(num)->wrap;
+       return get_column_info(num)->truncate;
 }
 
 static inline const char *get_match(int id)
@@ -236,12 +163,12 @@ static inline int is_mount_compatible_mode(void)
        return 1;                       /* ok */
 }
 
-static void set_all_columns_wrap(int set)
+static void set_all_columns_truncate(int set)
 {
        int i;
 
        for (i = 0; i < __NCOLUMNS; i++)
-               infos[i].wrap = set;
+               infos[i].truncate = set;
 }
 
 /*
@@ -257,8 +184,7 @@ static int column_name_to_id(const char *name, size_t namesz)
                if (!strncasecmp(name, cn, namesz) && !*(cn + namesz))
                        return i;
        }
-
-       errx(EXIT_FAILURE, _("unknown column: %s"), name);
+       warnx(_("unknown column: %s"), name);
        return -1;
 }
 
@@ -278,6 +204,7 @@ static int set_columns(const char *str)
 
        for (p = str; p && *p; p++) {
                const char *end = NULL;
+               int id;
 
                if (!begin)
                        begin = p;              /* begin of the column name */
@@ -290,7 +217,10 @@ static int set_columns(const char *str)
                if (end <= begin)
                        return -1;
 
-               columns[ ncolumns++ ] = column_name_to_id(begin, end - begin);
+               id = column_name_to_id(begin, end - begin);
+               if (id == -1)
+                       return -1;
+               columns[ ncolumns++ ] = id;
                begin = NULL;
                if (end && !*end)
                        break;
@@ -298,136 +228,7 @@ static int set_columns(const char *str)
        return 0;
 }
 
-/* TODO: move to lib/terminal.c */
-static int terminal_get_width(void)
-{
-#ifdef TIOCGSIZE
-       struct ttysize  t_win;
-#endif
-#ifdef TIOCGWINSZ
-       struct winsize  w_win;
-#endif
-        const char     *cp;
-
-#ifdef TIOCGSIZE
-       if (ioctl (0, TIOCGSIZE, &t_win) == 0)
-               return t_win.ts_cols;
-#endif
-#ifdef TIOCGWINSZ
-       if (ioctl (0, TIOCGWINSZ, &w_win) == 0)
-               return w_win.ws_col;
-#endif
-        cp = getenv("COLUMNS");
-       if (cp)
-               return strtol(cp, NULL, 10);
-       return 80;
-}
-
-static void recount_widths(void)
-{
-       int i, width = 0, ignore_wraps;
-
-       /* set minimal width (= size of column header) */
-       for (i = 0; i < ncolumns; i++) {
-               const char *name = get_column_name(i);
-               size_t len = mbs_width(name);
-               float hint = get_column_whint(i);
-
-               if (get_column_width(i) < len)
-                       /* enlarge to small columns */
-                       set_column_width(i, len);
-
-               else if (hint >= 1)
-                       /* set absolute widths */
-                       set_column_width(i, (int) hint);
-       }
-
-       /* count used space */
-       for (i = 0; i < ncolumns; i++)
-               width += get_column_width(i) + (is_last_column(i) ? 0 : 1);
-
-       if (width == termwidth)
-               return;
-
-       if (width < termwidth) {
-               /* cool, use the extra space for the last column */
-               i = ncolumns - 1;
-               set_column_width(i, get_column_width(i) + (termwidth - width));
-
-               return;
-       }
-
-       /* bad, we have to reduce output width, this is done in two steps:
-        * 1/ reduce columns with a relative width (see colinfo.whint) and
-        *    without wrap flag (this columns could be truncated)
-        * 2) reduce columns with a relative width with wrap flag
-        */
-       ignore_wraps = 1;
-       while(width > termwidth) {
-               int org = width;
-               for (i = ncolumns - 1; i >= 0 && width > termwidth; i--) {
-                       float hint = get_column_whint(i);
-                       int w = get_column_width(i);
-
-                       if (hint > 1)
-                               /* never truncate columns with absolute sizes */
-                               continue;
-
-                       if (get_column_id(i) == COL_TARGET && (flags & FL_TREE))
-                               /* never truncate the tree */
-                               continue;
-
-                       if (ignore_wraps && get_column_wrap(i))
-                               continue;
-
-                       if (w > hint * termwidth) {
-                               set_column_width(i, w - 1);
-                               width--;
-                       }
-               }
-
-               if (org == width) {
-                       if (ignore_wraps)
-                               ignore_wraps = 0;
-                       else
-                               break;
-               }
-       }
-/*
-       fprintf(stderr, "terminal: %d, output: %d\n", termwidth, width);
-       for (i = 0; i < ncolumns; i++)
-               fprintf(stderr, "width: %s=%d [%d]\n",
-                       get_column_name(i),
-                       get_column_width(i),
-                       (int) (get_column_whint(i) * termwidth));
-*/
-}
-
-static char *get_treenode_ascii_art(struct treenode *node,
-                                       char *buf, size_t *bufsz)
-{
-       const char *sym;
-       size_t len;
-
-       if (!node->parent)
-               return buf;
-       else {
-               buf = get_treenode_ascii_art(node->parent, buf, bufsz);
-               if (!buf)
-                       return NULL;
-               sym = node->next ? tree_symbols->vert : " ";
-       }
-       len = strlen(sym);
-
-       if (*bufsz < len)
-               return NULL;    /* no space, internal error */
-
-       memcpy(buf, sym, len);
-       *bufsz -= len;
-       return buf + len;
-}
-
-/* Returns LABEl or UUID */
+/* Returns LABEL or UUID */
 static const char *get_tag(mnt_fs *fs, const char *tagname)
 {
        const char *t, *v, *res;
@@ -445,37 +246,8 @@ static const char *get_tag(mnt_fs *fs, const char *tagname)
        return res;
 }
 
-static const char *get_tree_target(mnt_fs *fs, char *buf, size_t bufsz)
-{
-       struct treenode *node;
-       const char *target;
-       char *p = buf;
-
-       node = (struct treenode *) mnt_fs_get_userdata(fs);
-       if (!node)
-               return NULL;
-
-       target = mnt_fs_get_target(fs);
-       if (!target)
-               return NULL;
-
-       if (node->parent) {
-               p = get_treenode_ascii_art(node->parent, buf, &bufsz);
-               if (!p)
-                       return NULL;
-       }
-
-       if (node->next)
-               snprintf(p, bufsz, "%s%s", tree_symbols->branch, target);
-       else if (node->parent)
-               snprintf(p, bufsz, "%s%s", tree_symbols->right, target);
-       else
-               snprintf(p, bufsz, "%s", target);       /* root node */
-
-       return buf;
-}
-
-static const char *get_column_data(mnt_fs *fs, int num)
+/* reads FS data from libmount */
+static const char *get_data(mnt_fs *fs, int num)
 {
        const char *str = NULL;
 
@@ -494,8 +266,7 @@ static const char *get_column_data(mnt_fs *fs, int num)
                }
                break;
        case COL_TARGET:
-               str = flags & FL_TREE ? get_tree_target(fs, treebuf, termwidth) :
-                                       mnt_fs_get_target(fs);
+               str = mnt_fs_get_target(fs);
                break;
        case COL_FSTYPE:
                str = mnt_fs_get_fstype(fs);
@@ -512,180 +283,85 @@ static const char *get_column_data(mnt_fs *fs, int num)
        default:
                break;
        }
-
-       return str ? str : "-";
-}
-
-/* TODO: move to lib/mbalign.c */
-#ifdef HAVE_WIDECHAR
-static size_t wc_truncate (wchar_t *wc, size_t width)
-{
-  size_t cells = 0;
-  int next_cells = 0;
-
-  while (*wc)
-    {
-      next_cells = wcwidth (*wc);
-      if (next_cells == -1) /* non printable */
-        {
-          *wc = 0xFFFD; /* L'\uFFFD' (replacement char) */
-          next_cells = 1;
-        }
-      if (cells + next_cells > width)
-        break;
-      cells += next_cells;
-      wc++;
-    }
-  *wc = L'\0';
-  return cells;
-}
-#endif
-
-/* TODO: move to lib/mbalign.c */
-static size_t mbs_truncate(char *str, size_t width)
-{
-       size_t bytes = strlen(str) + 1;
-#ifdef HAVE_WIDECHAR
-       size_t sz = mbs_width(str);
-       wchar_t *wcs = NULL;
-       int rc = -1;
-
-       if (sz <= width)
-               return sz;              /* truncate is unnecessary */
-
-       if (sz == (size_t) -1)
-               goto done;
-
-       wcs = malloc(sz * sizeof(wchar_t));
-       if (!wcs)
-               goto done;
-
-       if (!mbstowcs(wcs, str, sz))
-               goto done;
-       rc = wc_truncate(wcs, width);
-       wcstombs(str, wcs, bytes);
-done:
-       free(wcs);
-       return rc;
-#else
-       if (width < bytes) {
-               str[width] = '\0';
-               return width;
-       }
-       return bytes;                   /* truncate is unnecessary */
-#endif
+       return str;
 }
 
-static void print_column_data(const char *data0, int num)
+/* adds one line to the output @tab */
+static struct tt_line *add_line(struct tt *tt, mnt_fs *fs,
+                                       struct tt_line *parent)
 {
-       size_t len, wrap, i;
-       int width;
-       char *data = (char *) data0;
-
-       if (flags & FL_RAW) {
-               fputs(data, stdout);
-               if (!is_last_column(num))
-                       fputc(' ', stdout);
-               return;
-       }
-
-       /* note that 'len' and 'width' is number of cells, not bytes */
-       len = mbs_width(data);
+       int i;
+       struct tt_line *line = tt_add_line(tt, parent);
 
-       if (!len || len == (size_t) -1) {
-               len = 0;
-               data = NULL;
+       if (!line) {
+               warn(_("failed to add line to output"));
+               return NULL;
        }
+       for (i = 0; i < ncolumns; i++)
+               tt_line_set_data(line, i, get_data(fs, i));
 
-       width = get_column_width(num);
-       wrap = get_column_wrap(num);
-
-       if (is_last_column(num) && len < width)
-               width = len;
-
-       if (len > width && !wrap) {
-               data = strdup(data);
-               if (data)
-                       len = mbs_truncate(data, width);
-               if (!data || len == (size_t) -1) {
-                       len = 0;
-                       data = NULL;
-               }
-       }
-       if (data)
-               fputs(data, stdout);
-       for (i = len; i < width; i++)           /* padding */
-               fputc(' ', stdout);
-
-       if (!is_last_column(num)) {
-               if (len > width && wrap) {
-                       fputc('\n', stdout);
-
-                       for (i = 0; i <= num; i++)
-                               printf("%*s ",
-                                       -get_column_width(i), " ");
-               } else
-                       fputc(' ', stdout);     /* columns separator */
-       }
-       if (data != data0)
-               free(data);
+       return line;
 }
 
-static void print_fs(mnt_fs *fs, int line)
+/* reads filesystems from @tb (libmount) and fillin @tab (output table) */
+static int create_treenode(struct tt *tt, mnt_tab *tb,
+                               mnt_fs *fs, struct tt_line *parent_line)
 {
-       int i;
-
-       /* print header */
-       if (!(flags & FL_NOHEADINGS) && !line) {
-               for (i = 0; i < ncolumns; i++)
-                       print_column_data(get_column_name(i), i);
-               printf("\n");
-       }
+       mnt_fs *chld = NULL;
+       mnt_iter *itr = NULL;
+       struct tt_line *line;
+       int rc = -1;
 
-       /* print data */
-       for (i = 0; i < ncolumns; i++) {
-               const char *data = get_column_data(fs, i);
-               print_column_data(data, i);
+       if (!fs) {
+               /* first call, get root FS */
+               if (mnt_tab_get_root_fs(tb, &fs))
+                       goto leave;
+               parent_line = NULL;
        }
-       printf("\n");
-}
 
-static void set_widths(mnt_fs *fs)
-{
-       int i;
+       itr = mnt_new_iter(MNT_ITER_FORWARD);
+       if (!itr)
+               goto leave;
 
-       for (i = 0; i < ncolumns; i++) {
-               const char *data = get_column_data(fs, i);
-               size_t len = data ? mbs_width(data) : 0;
-               int old = get_column_width(i);
+       line = add_line(tt, fs, parent_line);
+       if (!line)
+               goto leave;
 
-               if (old < len)
-                       set_column_width(i, len);
+       /*
+        * add all children to the output table
+        */
+       while(mnt_tab_next_child_fs(tb, itr, fs, &chld) == 0) {
+               if (create_treenode(tt, tb, chld, line))
+                       goto leave;
        }
+       rc = 0;
+leave:
+       mnt_free_iter(itr);
+       return rc;
 }
 
+/* calls libmount fstab/mtab/mountinfo parser */
 static mnt_tab *parse_tabfile(const char *path)
 {
        mnt_tab *tb = mnt_new_tab(path);
-       if (!tb)
+       if (!tb) {
+               warn(_("failed to initialize libmount tab"));
                return NULL;
-
-       if (mnt_tab_parse_file(tb) != 0)
-               goto err;
-
+       }
+       if (mnt_tab_parse_file(tb) != 0) {
+               mnt_free_tab(tb);
+               warn(_("can't read: %s"), path);
+               return NULL;
+       }
        if (mnt_tab_get_nerrs(tb)) {
                char buf[BUFSIZ];
                mnt_tab_strerror(tb, buf, sizeof(buf));
                warnx(_("%s: parse error: %s"), path, buf);
        }
        return tb;
-err:
-       mnt_free_tab(tb);
-       err(EXIT_FAILURE, _("can't read: %s"), path);
-
-       return NULL;
 }
 
+/* filter function for libmount (mnt_tab_find_next_fs()) */
 static int match_func(mnt_fs *fs, void *data)
 {
        int rc = flags & FL_INVERT ? 1 : 0;
@@ -710,6 +386,7 @@ static int match_func(mnt_fs *fs, void *data)
        return !rc;
 }
 
+/* iterate over filesystems in @tb */
 static mnt_fs *get_next_fs(mnt_tab *tb, mnt_iter *itr)
 {
        mnt_fs *fs = NULL;
@@ -753,89 +430,8 @@ again:
                        goto again;
                }
        }
-       return fs;
-}
-
-static struct treenode *create_treenode(mnt_tab *tb, mnt_fs *fs)
-{
-       mnt_fs *chld = NULL;
-       mnt_iter *itr = NULL;
-       struct treenode *node = NULL;
-
-       if (!fs) {
-               /* first call - start with root FS and initialize tree buffer */
-               if (mnt_tab_get_root_fs(tb, &fs))
-                       goto err;
-
-               treebuf = malloc(termwidth);
-               if (!treebuf)
-                       goto err;
-       }
-
-       itr = mnt_new_iter(MNT_ITER_FORWARD);
-       if (!itr)
-               goto err;
-
-       node = calloc(1, sizeof(*node));
-       if (!node)
-               goto err;
-
-       node->fs = fs;
-       mnt_fs_set_userdata(fs, (void *) node);
-
-       while(mnt_tab_next_child_fs(tb, itr, fs, &chld) == 0) {
-               struct treenode *chnode;
-
-               chnode = create_treenode(tb, chld);
-               if (!chnode)
-                       break;
-
-               chnode->parent = node;
-
-               if (node->last)
-                       node->last->next = chnode;
-               else
-                       node->first = chnode;
-
-               node->last = chnode;
-       }
-
-       return node;
-
-err:
-       if (!fs)
-               free(treebuf);
-       free(node);
-       mnt_free_iter(itr);
-       return NULL;
-}
-
-static void print_treenode(struct treenode *node, int line)
-{
-       print_fs(node->fs, line++);
-
-       /* print children */
-       node = node->first;
-       while(node) {
-               print_treenode(node, line++);
-               node = node->next;
-       }
-}
-
-static void free_treenode(struct treenode *node)
-{
-       struct treenode *chld = node->first;
-
-       if (!node->parent)              /* root node */
-               free(treebuf);
 
-       while(chld) {
-               struct treenode *next = chld->next;
-               free_treenode(chld);
-               chld = next;
-       }
-
-       free(node);
+       return fs;
 }
 
 static int __attribute__((__noreturn__)) usage(FILE *out)
@@ -884,12 +480,18 @@ errx_mutually_exclusive(const char *opts)
 
 int main(int argc, char *argv[])
 {
+       /* libmount */
+       mnt_tab *tb = NULL;
+       mnt_iter *itr = NULL;
+       mnt_fs *fs = NULL;
        char *tabfile = NULL;
        int direction = MNT_ITER_FORWARD;
-       mnt_tab *tb;
-       mnt_iter *itr;
-       mnt_fs *fs = NULL;
-       int c, ct = 0;
+
+       /* table.h */
+       struct tt *tt = NULL;
+       int tt_flags = 0;
+
+       int i, c, rc = EXIT_FAILURE;
 
        struct option longopts[] = {
            { "ascii",        0, 0, 'a' },
@@ -928,13 +530,13 @@ int main(int argc, char *argv[])
        columns[ncolumns++] = COL_OPTIONS;
 
        /* default output format */
-       flags |= FL_TREE;
+       tt_flags |= TT_FL_TREE;
 
        while ((c = getopt_long(argc, argv,
                                "cd:ehifo:O:klmnrst:uS:T:", longopts, NULL)) != -1) {
                switch(c) {
                case 'a':
-                       tree_symbols = &ascii_tree_symbols;
+                       tt_flags |= TT_FL_ASCII;
                        break;
                case 'c':
                        flags |= FL_CANONICALIZE;
@@ -961,27 +563,28 @@ int main(int argc, char *argv[])
                        flags |= FL_FIRSTONLY;
                        break;
                case 'u':
-                       set_all_columns_wrap(TRUE);
+                       set_all_columns_truncate(FALSE);
                        break;
                case 'o':
-                       set_columns(optarg);
+                       if (set_columns(optarg))
+                               exit(EXIT_FAILURE);
                        break;
                case 'O':
                        set_match(COL_OPTIONS, optarg);
                        break;
-               case 'm':
+               case 'm':               /* mtab */
                        if (tabfile)
                                errx_mutually_exclusive("--{fstab,mtab,kernel}");
                        tabfile = _PATH_MOUNTED;
-                       flags &= ~FL_TREE;      /* disable the default */
+                       tt_flags &= ~TT_FL_TREE;
                        break;
-               case 's':
+               case 's':               /* fstab */
                        if (tabfile)
                                errx_mutually_exclusive("--{fstab,mtab,kernel}");
                        tabfile = _PATH_MNTTAB;
-                       flags &= ~FL_TREE;      /* disable the default */
+                       flags &= ~TT_FL_TREE;
                        break;
-               case 'k':
+               case 'k':               /* kernel (mountinfo) */
                        if (tabfile)
                                 errx_mutually_exclusive("--{fstab,mtab,kernel}");
                        tabfile = _PATH_PROC_MOUNTINFO;
@@ -990,20 +593,21 @@ int main(int argc, char *argv[])
                        set_match(COL_FSTYPE, optarg);
                        break;
                case 'r':
-                       if (!(flags & FL_TREE) && !(flags & FL_RAW))
+                       if (!(tt_flags & TT_FL_TREE) &&
+                           !(tt_flags & TT_FL_RAW))
                                errx_mutually_exclusive("--{raw,list}");
 
-                       flags &= ~FL_TREE;      /* disable the default */
-                       flags |= FL_RAW;        /* enable raw */
+                       tt_flags &= ~TT_FL_TREE;        /* disable the default */
+                       tt_flags |= TT_FL_RAW;          /* enable raw */
                        break;
                case 'l':
-                       if (flags & FL_RAW)
+                       if (tt_flags & TT_FL_RAW)
                                errx_mutually_exclusive("--{raw,list}");
 
-                       flags &= ~FL_TREE;      /* disable the default */
+                       tt_flags &= ~TT_FL_TREE; /* disable the default */
                        break;
                case 'n':
-                       flags |= FL_NOHEADINGS;
+                       tt_flags |= TT_FL_NOHEADINGS;
                        break;
                case 'S':
                        set_match(COL_SOURCE, optarg);
@@ -1019,16 +623,14 @@ int main(int argc, char *argv[])
                }
        }
 
-       if (!tabfile)
+       if (!tabfile) {
                tabfile = _PATH_PROC_MOUNTINFO;
 
-#ifdef HAVE_WIDECHAR
-       /* non-UTF terminal */
-       if ((flags & FL_TREE) && tree_symbols != &ascii_tree_symbols &&
-                                       strcmp(nl_langinfo(CODESET), "UTF-8"))
-               tree_symbols = &ascii_tree_symbols;
-#endif
-
+               if (access(tabfile, R_OK)) {            /* old kernel? */
+                       tabfile = _PATH_PROC_MOUNTS;
+                       tt_flags &= ~TT_FL_TREE;
+               }
+       }
        if (optind < argc && (get_match(COL_SOURCE) || get_match(COL_TARGET)))
                errx(EXIT_FAILURE, _(
                        "options --target and --source can't be used together "
@@ -1039,58 +641,75 @@ int main(int argc, char *argv[])
        if (optind < argc)
                set_match(COL_TARGET, argv[optind++]);  /* mountpoint */
 
+       if (!is_listall_mode() || (flags & FL_FIRSTONLY))
+               tt_flags &= ~TT_FL_TREE;
+
+       /*
+        * initialize libmount
+        */
        tb = parse_tabfile(tabfile);
        if (!tb)
-               return EXIT_FAILURE;
+               goto leave;
 
        itr = mnt_new_iter(direction);
-       if (!itr)
-               err(EXIT_FAILURE, _("failed to initialize libmount iterator"));
-
+       if (!itr) {
+               warn(_("failed to initialize libmount iterator"));
+               goto leave;
+       }
        cache = mnt_new_cache();
-       if (!cache)
-               err(EXIT_FAILURE, _("failed to initialize libmount cache"));
-
+       if (!cache) {
+               warn(_("failed to initialize libmount cache"));
+               goto leave;
+       }
        mnt_tab_set_cache(tb, cache);
 
-       termwidth = terminal_get_width();
+       /*
+        * initialize output formatting (table.h)
+        */
+       tt = tt_new_table(tt_flags);
+       if (!tt) {
+               warn(_("failed to initialize output table"));
+               goto leave;
+       }
+       for (i = 0; i < ncolumns; i++) {
+               int fl = get_column_truncate(i) ? TT_FL_TRUNCATE : 0;
 
-       if (flags & FL_TREE) {
-               struct treenode *tree = create_treenode(tb, NULL);
-               if (!tree)
-                       err(EXIT_FAILURE, _("failed to create tree"));
+               if (get_column_id(i) == COL_TARGET && (tt_flags & TT_FL_TREE))
+                       fl |= TT_FL_TREE;
 
-               while (mnt_tab_next_fs(tb, itr, &fs) == 0) {
-                       set_widths(fs);
-                       ct++;
-               }
-               recount_widths();
-               print_treenode(tree, 0);
-               free_treenode(tree);
-       } else {
-               /* set width */
-
-               if (!(flags & FL_RAW)) {
-                       while((fs = get_next_fs(tb, itr))) {
-                               set_widths(fs);
-                               if (flags & FL_FIRSTONLY)
-                                       break;
-                       }
-                       ct = 0;
-                       mnt_reset_iter(itr, -1);
-                       recount_widths();
+               if (!tt_define_column(tt, get_column_name(i),
+                                       get_column_whint(i), fl)) {
+                       warn(_("failed to initialize output column"));
+                       goto leave;
                }
+       }
 
-               /* Print */
+       /*
+        * Fill in data to the output table
+        */
+       if (tt_flags & TT_FL_TREE) {
+               if (create_treenode(tt, tb, NULL, NULL))
+                       goto leave;
+       } else {
                while((fs = get_next_fs(tb, itr))) {
-                       print_fs(fs, ct++);
+                       if (!add_line(tt, fs, NULL))
+                               goto leave;
                        if (flags & FL_FIRSTONLY)
                                break;
                }
        }
+
+       /*
+        * Print the output table
+        */
+       tt_print_table(tt);
+       rc = EXIT_SUCCESS;
+leave:
+       tt_free_table(tt);
+
        mnt_free_tab(tb);
        mnt_free_cache(cache);
        mnt_free_iter(itr);
 
-       return ct ? EXIT_SUCCESS : 2;
+       return rc;
 }