(root)/
util-linux-2.39/
libsmartcols/
samples/
tree.c
       1  /*
       2   * Copyright (C) 2010-2014 Karel Zak <kzak@redhat.com>
       3   *
       4   * This file may be redistributed under the terms of the
       5   * GNU Lesser General Public License.
       6   */
       7  #include <stdlib.h>
       8  #include <unistd.h>
       9  #include <string.h>
      10  #include <errno.h>
      11  #include <sys/types.h>
      12  #include <sys/stat.h>
      13  #include <dirent.h>
      14  #include <getopt.h>
      15  
      16  #include "c.h"
      17  #include "nls.h"
      18  #include "strutils.h"
      19  
      20  #include "libsmartcols.h"
      21  
      22  static int add_children(struct libscols_table *tb,
      23  			struct libscols_line *ln, int fd);
      24  
      25  
      26  enum { COL_MODE, COL_SIZE, COL_NAME };
      27  
      28  struct libscols_column *sort_column;
      29  
      30  /* add columns to the @tb */
      31  static void setup_columns(struct libscols_table *tb, int notree)
      32  {
      33  	if (!scols_table_new_column(tb, "MODE", 0.3, 0))
      34  		goto fail;
      35  	if (!scols_table_new_column(tb, "SIZE", 5, SCOLS_FL_RIGHT))
      36  		goto fail;
      37  
      38  	sort_column = scols_table_new_column(tb, "NAME", 0.5,
      39  			(notree ? 0 : SCOLS_FL_TREE) | SCOLS_FL_NOEXTREMES);
      40  	if (!sort_column)
      41  		goto fail;
      42  	scols_column_set_cmpfunc(sort_column, scols_cmpstr_cells, NULL);
      43  
      44  	return;
      45  fail:
      46  	scols_unref_table(tb);
      47  	err(EXIT_FAILURE, "failed to create output columns");
      48  }
      49  
      50  /* add a new line to @tb, the content is based on @st */
      51  static int add_line_from_stat(struct libscols_table *tb,
      52  			      struct libscols_line *parent,
      53  			      int parent_fd,
      54  			      struct stat *st,
      55  			      const char *name)
      56  {
      57  	struct libscols_line *ln;
      58  	char modbuf[11], *p;
      59  	mode_t mode = st->st_mode;
      60  	int rc = 0;
      61  
      62  	ln = scols_table_new_line(tb, parent);
      63  	if (!ln)
      64  		err(EXIT_FAILURE, "failed to create output line");
      65  
      66  	/* MODE; local buffer, use scols_line_set_data() that calls strdup() */
      67  	xstrmode(mode, modbuf);
      68  	if (scols_line_set_data(ln, COL_MODE, modbuf))
      69  		goto fail;
      70  
      71  	/* SIZE; already allocated string, use scols_line_refer_data() */
      72  	p = size_to_human_string(0, st->st_size);
      73  	if (!p || scols_line_refer_data(ln, COL_SIZE, p))
      74  		goto fail;
      75  
      76  	/* NAME */
      77  	if (scols_line_set_data(ln, COL_NAME, name))
      78  		goto fail;
      79  
      80  	/* colors */
      81  	if (scols_table_colors_wanted(tb)) {
      82  		struct libscols_cell *ce = scols_line_get_cell(ln, COL_NAME);
      83  
      84  		if (S_ISDIR(mode))
      85  			scols_cell_set_color(ce, "blue");
      86  		else if (S_ISLNK(mode))
      87  			scols_cell_set_color(ce, "cyan");
      88  		else if (S_ISBLK(mode))
      89  			scols_cell_set_color(ce, "magenta");
      90  		else if ((mode & S_IXOTH) || (mode & S_IXGRP) || (mode & S_IXUSR))
      91  			scols_cell_set_color(ce, "green");
      92  	}
      93  
      94  	if (S_ISDIR(st->st_mode)) {
      95  		int fd;
      96  
      97  		if (parent_fd >= 0)
      98  			fd = openat(parent_fd, name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC);
      99  		else
     100  			fd = open(name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC);
     101  		if (fd >= 0) {
     102  			rc = add_children(tb, ln, fd);
     103  			close(fd);
     104  		}
     105  	}
     106  	return rc;
     107  fail:
     108  	err(EXIT_FAILURE, "failed to create cell data");
     109  	return -1;
     110  }
     111  
     112  /* read all entries from directory addressed by @fd */
     113  static int add_children(struct libscols_table *tb,
     114  			struct libscols_line *ln,
     115  			int fd)
     116  {
     117  	DIR *dir;
     118  	struct dirent *d;
     119  
     120  	dir = fdopendir(fd);
     121  	if (!dir)
     122  		return -errno;
     123  
     124  	while ((d = readdir(dir))) {
     125  		struct stat st;
     126  
     127  		if (strcmp(d->d_name, ".") == 0 || strcmp(d->d_name, "..") == 0)
     128  			continue;
     129  		if (fstatat(fd, d->d_name, &st, AT_SYMLINK_NOFOLLOW) != 0)
     130  			continue;
     131  		add_line_from_stat(tb, ln, fd, &st, d->d_name);
     132  	}
     133  	closedir(dir);
     134  	return 0;
     135  }
     136  
     137  static void add_lines(struct libscols_table *tb, const char *dirname)
     138  {
     139  	struct stat st;
     140  
     141  	if (lstat(dirname, &st))
     142  		err(EXIT_FAILURE, "%s", dirname);
     143  
     144  	add_line_from_stat(tb, NULL, -1, &st, dirname);
     145  }
     146  
     147  static void __attribute__((__noreturn__)) usage(FILE *out)
     148  {
     149  	fprintf(out, " %s [options] [<dir> ...]\n\n", program_invocation_short_name);
     150  	fputs(" -c, --csv               display a csv-like output\n", out);
     151  	fputs(" -i, --ascii             use ascii characters only\n", out);
     152  	fputs(" -l, --list              use list format output\n", out);
     153  	fputs(" -n, --noheadings        don't print headings\n", out);
     154  	fputs(" -p, --pairs             use key=\"value\" output format\n", out);
     155  	fputs(" -J, --json              use JSON output format\n", out);
     156  	fputs(" -r, --raw               use raw output format\n", out);
     157  	fputs(" -s, --sort              sort by NAME\n", out);
     158  	fputs(" -x, --tree-sort         keep tree-like order (also for --list)\n", out);
     159  	fputs(" -S, --range-start <n>   first line to print\n", out);
     160  	fputs(" -E, --range-end <n>     last line to print\n", out);
     161  
     162  	exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
     163  }
     164  
     165  int main(int argc, char *argv[])
     166  {
     167  	struct libscols_table *tb;
     168  	int c, notree = 0, nstart = -1, nend = -1, sort = 0, force_tree_sort = 0;
     169  
     170  
     171  	static const struct option longopts[] = {
     172  		{ "ascii",	0, NULL, 'i' },
     173  		{ "csv",        0, NULL, 'c' },
     174  		{ "list",       0, NULL, 'l' },
     175  		{ "noheadings",	0, NULL, 'n' },
     176  		{ "pairs",      0, NULL, 'p' },
     177  		{ "json",       0, NULL, 'J' },
     178  		{ "raw",        0, NULL, 'r' },
     179  		{ "range-start",1, NULL, 'S' },
     180  		{ "range-end",  1, NULL, 'E' },
     181  		{ "sort",       0, NULL, 's' },
     182  		{ "tree-sort",  0, NULL, 'x' },
     183  		{ NULL, 0, NULL, 0 },
     184  	};
     185  
     186  	setlocale(LC_ALL, "");	/* just to have enable UTF8 chars */
     187  
     188  	scols_init_debug(0);
     189  
     190  	tb = scols_new_table();
     191  	if (!tb)
     192  		err(EXIT_FAILURE, "failed to create output table");
     193  
     194  	while((c = getopt_long(argc, argv, "ciJlnprS:sE:x", longopts, NULL)) != -1) {
     195  		switch(c) {
     196  		case 'c':
     197  			scols_table_set_column_separator(tb, ",");
     198  			scols_table_enable_raw(tb, 1);
     199  			notree = 1;
     200  			break;
     201  		case 'i':
     202  			scols_table_enable_ascii(tb, 1);
     203  			break;
     204  		case 'J':
     205  			scols_table_set_name(tb, "scolstest");
     206  			scols_table_enable_json(tb, 1);
     207  			break;
     208  		case 'l':
     209  			notree = 1;
     210  			break;
     211  		case 'n':
     212  			scols_table_enable_noheadings(tb, 1);
     213  			break;
     214  		case 'p':
     215  			scols_table_enable_export(tb, 1);
     216  			notree = 1;
     217  			break;
     218  		case 'r':
     219  			scols_table_enable_raw(tb, 1);
     220  			notree = 1;
     221  			break;
     222  		case 'S':
     223  			nstart = strtos32_or_err(optarg, "failed to parse range start") - 1;
     224  			break;
     225  		case 's':
     226  			sort = 1;
     227  			break;
     228  		case 'E':
     229  			nend = strtos32_or_err(optarg, "failed to parse range end") - 1;
     230  			break;
     231  		case 'x':
     232  			force_tree_sort = 1;
     233  			break;
     234  		default:
     235  			usage(stderr);
     236  		}
     237  	}
     238  
     239  	scols_table_enable_colors(tb, isatty(STDOUT_FILENO));
     240  	setup_columns(tb, notree);
     241  
     242  	if (optind == argc)
     243  		add_lines(tb, ".");
     244  	else while (optind < argc)
     245  		add_lines(tb, argv[optind++]);
     246  
     247  	if (sort)
     248  		scols_sort_table(tb, sort_column);
     249  	if (force_tree_sort)
     250  		scols_sort_table_by_tree(tb);
     251  
     252  	if (nstart >= 0 || nend >= 0) {
     253  		/* print subset */
     254  		struct libscols_line *start = NULL, *end = NULL;
     255  
     256  		if (nstart >= 0)
     257  			start = scols_table_get_line(tb, nstart);
     258  		if (nend >= 0)
     259  			end = scols_table_get_line(tb, nend);
     260  
     261  		if (start || end)
     262  			scols_table_print_range(tb, start, end);
     263  	} else
     264  		/* print all table */
     265  		scols_print_table(tb);
     266  
     267  	scols_unref_table(tb);
     268  	return EXIT_SUCCESS;
     269  }