summaryrefslogtreecommitdiffstats
path: root/misc-utils/findmnt.c
diff options
context:
space:
mode:
Diffstat (limited to 'misc-utils/findmnt.c')
-rw-r--r--misc-utils/findmnt.c230
1 files changed, 170 insertions, 60 deletions
diff --git a/misc-utils/findmnt.c b/misc-utils/findmnt.c
index 733bbc1..cc397da 100644
--- a/misc-utils/findmnt.c
+++ b/misc-utils/findmnt.c
@@ -20,6 +20,7 @@
*/
#include <stdio.h>
#include <stdlib.h>
+#include <stdbool.h>
#include <errno.h>
#include <unistd.h>
#include <getopt.h>
@@ -48,6 +49,7 @@
#include "optutils.h"
#include "mangle.h"
#include "buffer.h"
+#include "column-list-table.h"
#include "findmnt.h"
@@ -60,6 +62,10 @@ enum {
COL_FSTYPE,
COL_FS_OPTIONS,
COL_ID,
+ COL_INO_AVAIL,
+ COL_INO_TOTAL,
+ COL_INO_USED,
+ COL_INO_USEPERC,
COL_LABEL,
COL_MAJMIN,
COL_OLD_OPTIONS,
@@ -90,7 +96,7 @@ enum {
/* column names */
struct colinfo {
- const char *name; /* header */
+ const char * const name; /* header */
double whint; /* width hint (N < 1 is in percent of termwidth) */
int flags; /* libsmartcols flags */
const char *help; /* column description */
@@ -101,12 +107,16 @@ struct colinfo {
/* columns descriptions (don't use const, this is writable) */
static struct colinfo infos[] = {
[COL_ACTION] = { "ACTION", 10, SCOLS_FL_STRICTWIDTH, N_("action detected by --poll") },
- [COL_AVAIL] = { "AVAIL", 5, SCOLS_FL_RIGHT, N_("filesystem size available") },
+ [COL_AVAIL] = { "AVAIL", 5, SCOLS_FL_RIGHT, N_("filesystem size available, use <number> if --bytes is given") },
[COL_FREQ] = { "FREQ", 1, SCOLS_FL_RIGHT, N_("dump(8) period in days [fstab only]") },
[COL_FSROOT] = { "FSROOT", 0.25, SCOLS_FL_NOEXTREMES, N_("filesystem root") },
[COL_FSTYPE] = { "FSTYPE", 0.10, SCOLS_FL_TRUNC, N_("filesystem type") },
[COL_FS_OPTIONS] = { "FS-OPTIONS", 0.10, SCOLS_FL_TRUNC, N_("FS specific mount options") },
[COL_ID] = { "ID", 2, SCOLS_FL_RIGHT, N_("mount ID") },
+ [COL_INO_AVAIL] = { "INO.AVAIL", 5, SCOLS_FL_RIGHT, N_("number of available inodes") },
+ [COL_INO_TOTAL] = { "INO.TOTAL", 5, SCOLS_FL_RIGHT, N_("total number of inodes") },
+ [COL_INO_USED] = { "INO.USED", 5, SCOLS_FL_RIGHT, N_("number of used inodes") },
+ [COL_INO_USEPERC] = { "INO.USE%", 3, SCOLS_FL_RIGHT, N_("percentage of INO.USED divided by INO.TOTAL") },
[COL_LABEL] = { "LABEL", 0.10, 0, N_("filesystem label") },
[COL_MAJMIN] = { "MAJ:MIN", 6, 0, N_("major:minor device number") },
[COL_OLD_OPTIONS] = { "OLD-OPTIONS", 0.10, SCOLS_FL_TRUNC, N_("old mount options saved by --poll") },
@@ -118,12 +128,12 @@ static struct colinfo infos[] = {
[COL_PARTUUID] = { "PARTUUID", 36, 0, N_("partition UUID") },
[COL_PASSNO] = { "PASSNO", 1, SCOLS_FL_RIGHT, N_("pass number on parallel fsck(8) [fstab only]") },
[COL_PROPAGATION] = { "PROPAGATION", 0.10, 0, N_("VFS propagation flags") },
- [COL_SIZE] = { "SIZE", 5, SCOLS_FL_RIGHT, N_("filesystem size") },
+ [COL_SIZE] = { "SIZE", 5, SCOLS_FL_RIGHT, N_("filesystem size, use <number> if --bytes is given") },
[COL_SOURCES] = { "SOURCES", 0.25, SCOLS_FL_WRAP, N_("all possible source devices") },
[COL_SOURCE] = { "SOURCE", 0.25, SCOLS_FL_NOEXTREMES, N_("source device") },
[COL_TARGET] = { "TARGET", 0.30, SCOLS_FL_TREE| SCOLS_FL_NOEXTREMES, N_("mountpoint") },
[COL_TID] = { "TID", 4, SCOLS_FL_RIGHT, N_("task ID") },
- [COL_USED] = { "USED", 5, SCOLS_FL_RIGHT, N_("filesystem size used") },
+ [COL_USED] = { "USED", 5, SCOLS_FL_RIGHT, N_("filesystem size used, use <number> if --bytes is given") },
[COL_USEPERC] = { "USE%", 3, SCOLS_FL_RIGHT, N_("filesystem use percentage") },
[COL_UUID] = { "UUID", 36, 0, N_("filesystem UUID") },
[COL_VFS_OPTIONS] = { "VFS-OPTIONS", 0.20, SCOLS_FL_TRUNC, N_("VFS specific mount options") }
@@ -475,6 +485,7 @@ static char *get_vfs_attr(struct libmnt_fs *fs, int sizetype)
struct statvfs buf;
uint64_t vfs_attr = 0;
char *sizestr;
+ bool no_bytes = false;
if (statvfs(mnt_fs_get_target(fs), &buf) != 0)
return NULL;
@@ -497,11 +508,38 @@ static char *get_vfs_attr(struct libmnt_fs *fs, int sizetype)
(double)(buf.f_blocks - buf.f_bfree) /
buf.f_blocks * 100);
return sizestr;
+ case COL_INO_AVAIL:
+ /* Quoted from startvfs(3):
+ *
+ * Under Linux, f_favail is always the same as
+ * f_ffree, and there's no way for a filesystem to
+ * report otherwise. This is not an issue, since no
+ * filesystems with an inode root reservation exist.
+ */
+ no_bytes = true;
+ vfs_attr = buf.f_ffree;
+ break;
+ case COL_INO_TOTAL:
+ no_bytes = true;
+ vfs_attr = buf.f_files;
+ break;
+ case COL_INO_USED:
+ no_bytes = true;
+ vfs_attr = buf.f_files - buf.f_ffree;
+ break;
+ case COL_INO_USEPERC:
+ if (buf.f_files == 0)
+ return xstrdup("-");
+
+ xasprintf(&sizestr, "%.0f%%",
+ (double)(buf.f_files - buf.f_ffree) /
+ buf.f_files * 100);
+ return sizestr;
}
if (!vfs_attr)
sizestr = xstrdup("0");
- else if (flags & FL_BYTES)
+ else if ((flags & FL_BYTES) || no_bytes)
xasprintf(&sizestr, "%ju", vfs_attr);
else
sizestr = size_to_human_string(SIZE_SUFFIX_1LETTER, vfs_attr);
@@ -511,7 +549,7 @@ static char *get_vfs_attr(struct libmnt_fs *fs, int sizetype)
/* reads sources from libmount/libblkid
*/
-static char *get_data_col_sources(struct libmnt_fs *fs, int evaluate)
+static char *get_data_col_sources(struct libmnt_fs *fs, int evaluate, size_t *datasiz)
{
const char *tag = NULL, *p = NULL;
int i = 0;
@@ -565,14 +603,14 @@ static char *get_data_col_sources(struct libmnt_fs *fs, int evaluate)
if (!dev)
continue;
if (i != 0)
- ul_buffer_append_data(&buf, "\n", 1);
+ ul_buffer_append_data(&buf, "\0", 1);
ul_buffer_append_string(&buf, blkid_dev_devname(dev));
i++;
}
blkid_dev_iterate_end(iter);
free(val);
- return ul_buffer_get_data(&buf, NULL, NULL);
+ return ul_buffer_get_data(&buf, datasiz, NULL);
nothing:
free(val);
@@ -581,7 +619,7 @@ nothing:
/* reads FS data from libmount
*/
-static char *get_data(struct libmnt_fs *fs, int num)
+static char *get_data(struct libmnt_fs *fs, int num, size_t *datasiz)
{
char *str = NULL;
int col_id = get_column_id(num);
@@ -589,7 +627,7 @@ static char *get_data(struct libmnt_fs *fs, int num)
switch (col_id) {
case COL_SOURCES:
/* print all devices with the same tag (LABEL, UUID) */
- str = get_data_col_sources(fs, flags & FL_EVALUATE);
+ str = get_data_col_sources(fs, flags & FL_EVALUATE, datasiz);
if (str)
break;
@@ -672,6 +710,10 @@ static char *get_data(struct libmnt_fs *fs, int num)
case COL_AVAIL:
case COL_USED:
case COL_USEPERC:
+ case COL_INO_TOTAL:
+ case COL_INO_AVAIL:
+ case COL_INO_USED:
+ case COL_INO_USEPERC:
str = get_vfs_attr(fs, col_id);
break;
case COL_FSROOT:
@@ -730,7 +772,8 @@ static char *get_data(struct libmnt_fs *fs, int num)
static char *get_tabdiff_data(struct libmnt_fs *old_fs,
struct libmnt_fs *new_fs,
int change,
- int num)
+ int num,
+ size_t *datasiz)
{
char *str = NULL;
@@ -769,14 +812,30 @@ static char *get_tabdiff_data(struct libmnt_fs *old_fs,
break;
default:
if (new_fs)
- str = get_data(new_fs, num);
+ str = get_data(new_fs, num, datasiz);
else
- str = get_data(old_fs, num);
+ str = get_data(old_fs, num, datasiz);
break;
}
return str;
}
+static void set_line_data(struct libscols_line *ln, size_t i, char *data, size_t datasiz)
+{
+ int rc;
+ struct libscols_cell *ce;
+
+ ce = scols_line_get_cell(ln, i);
+ if (!ce)
+ return;
+ if (datasiz)
+ rc = scols_cell_refer_memory(ce, data, datasiz);
+ else
+ rc = scols_cell_refer_data(ce, data);
+ if (rc)
+ err(EXIT_FAILURE, _("failed to add output data"));
+}
+
/* adds one line to the output @tab */
static struct libscols_line *add_line(struct libscols_table *table, struct libmnt_fs *fs,
struct libscols_line *parent)
@@ -788,8 +847,11 @@ static struct libscols_line *add_line(struct libscols_table *table, struct libmn
err(EXIT_FAILURE, _("failed to allocate output line"));
for (i = 0; i < ncolumns; i++) {
- if (scols_line_refer_data(line, i, get_data(fs, i)))
- err(EXIT_FAILURE, _("failed to add output data"));
+ size_t datasiz = 0;
+ char *data = get_data(fs, i, &datasiz);
+
+ if (data)
+ set_line_data(line, i, data, datasiz);
}
scols_line_set_userdata(line, fs);
@@ -806,9 +868,11 @@ static struct libscols_line *add_tabdiff_line(struct libscols_table *table, stru
err(EXIT_FAILURE, _("failed to allocate output line"));
for (i = 0; i < ncolumns; i++) {
- if (scols_line_refer_data(line, i,
- get_tabdiff_data(old_fs, new_fs, change, i)))
- err(EXIT_FAILURE, _("failed to add output data"));
+ size_t datasiz = 0;
+ char *data = get_tabdiff_data(old_fs, new_fs, change, i, &datasiz);
+
+ if (data)
+ set_line_data(line, i, data, datasiz);
}
return line;
@@ -901,7 +965,7 @@ static int parser_errcb(struct libmnt_table *tb __attribute__ ((__unused__)),
static char **append_tabfile(char **files, int *nfiles, char *filename)
{
- files = xrealloc(files, sizeof(char *) * (*nfiles + 1));
+ files = xreallocarray(files, *nfiles + 1, sizeof(char *));
files[(*nfiles)++] = filename;
return files;
}
@@ -1272,9 +1336,7 @@ static int poll_table(struct libmnt_table *tb, const char *tabfile,
if (count) {
rc = scols_table_print_range(table, NULL, NULL);
- if (rc == 0)
- fputc('\n', scols_table_get_stream(table));
- fflush(stdout);
+ fflush(scols_table_get_stream(table));
if (rc)
goto done;
}
@@ -1310,10 +1372,36 @@ static int uniq_fs_target_cmp(
return !mnt_fs_match_target(a, mnt_fs_get_target(b), cache);
}
+static int get_column_json_type(int id, int scols_flags, int *multi)
+{
+ switch (id) {
+ case COL_SIZE:
+ case COL_AVAIL:
+ case COL_USED:
+ if (multi)
+ *multi = 1;
+ if (!(flags & FL_BYTES))
+ break;
+ /* fallthrough */
+ case COL_ID:
+ case COL_PARENT:
+ case COL_FREQ:
+ case COL_PASSNO:
+ case COL_TID:
+ return SCOLS_JSON_NUMBER;
+
+ default:
+ if (scols_flags & SCOLS_FL_WRAP)
+ return SCOLS_JSON_ARRAY_STRING;
+ break;
+ }
+
+ return SCOLS_JSON_STRING; /* default */
+}
+
static void __attribute__((__noreturn__)) usage(void)
{
FILE *out = stdout;
- size_t i;
fputs(USAGE_HEADER, out);
fprintf(out, _(
@@ -1348,13 +1436,14 @@ static void __attribute__((__noreturn__)) usage(void)
" to device names\n"), out);
fputs(_(" -F, --tab-file <path> alternative file for -s, -m or -k options\n"), out);
fputs(_(" -f, --first-only print the first found filesystem only\n"), out);
+ fputs(_(" -I, --dfi imitate the output of df(1) with -i option\n"), out);
fputs(_(" -i, --invert invert the sense of matching\n"), out);
fputs(_(" -J, --json use JSON output format\n"), out);
fputs(_(" -l, --list use list format output\n"), out);
fputs(_(" -N, --task <tid> use alternative namespace (/proc/<tid>/mountinfo file)\n"), out);
fputs(_(" -n, --noheadings don't print column headings\n"), out);
fputs(_(" -O, --options <list> limit the set of filesystems by mount options\n"), out);
- fputs(_(" -o, --output <list> the output columns to be shown\n"), out);
+ fputs(_(" -o, --output <list> output columns (see --list-columns)\n"), out);
fputs(_(" --output-all output all available columns\n"), out);
fputs(_(" -P, --pairs use key=\"value\" output format\n"), out);
fputs(_(" --pseudo print only pseudo-filesystems\n"), out);
@@ -1379,23 +1468,45 @@ static void __attribute__((__noreturn__)) usage(void)
fputs(_(" --vfs-all print all VFS options\n"), out);
fputs(USAGE_SEPARATOR, out);
- printf(USAGE_HELP_OPTIONS(24));
+ fputs(_(" -H, --list-columns list the available columns\n"), out);
+ fprintf(out, USAGE_HELP_OPTIONS(24));
- fputs(USAGE_COLUMNS, out);
- for (i = 0; i < ARRAY_SIZE(infos); i++)
- fprintf(out, " %11s %s\n", infos[i].name, _(infos[i].help));
+ fprintf(out, USAGE_MAN_TAIL("findmnt(8)"));
+
+ exit(EXIT_SUCCESS);
+}
+
+static void __attribute__((__noreturn__)) list_colunms(void)
+{
+ size_t i;
+ struct libscols_table *tb = xcolumn_list_table_new("findmnt-columns", stdout,
+ flags & FL_RAW,
+ flags & FL_JSON);
+
+ for (i = 0; i < ARRAY_SIZE(infos); i++) {
+ const struct colinfo *ci = &infos[i];
+ int multi = 0;
+ int json = get_column_json_type(i, ci->flags, &multi);
+
+ xcolumn_list_table_append_line(tb, ci->name,
+ multi ? -1 : json,
+ multi ? "<string|number>" : NULL,
+ _(ci->help));
+ }
- printf(USAGE_MAN_TAIL("findmnt(8)"));
+ scols_print_table(tb);
+ scols_unref_table(tb);
exit(EXIT_SUCCESS);
}
+
int main(int argc, char *argv[])
{
struct libmnt_table *tb = NULL;
char **tabfiles = NULL;
int direction = MNT_ITER_FORWARD;
- int verify = 0;
+ int verify = 0, collist = 0;
int c, rc = -1, timeout = -1;
int ntabfiles = 0, tabtype = 0;
char *outarg = NULL;
@@ -1421,6 +1532,7 @@ int main(int argc, char *argv[])
{ "canonicalize", no_argument, NULL, 'c' },
{ "direction", required_argument, NULL, 'd' },
{ "df", no_argument, NULL, 'D' },
+ { "dfi", no_argument, NULL, 'I' },
{ "evaluate", no_argument, NULL, 'e' },
{ "first-only", no_argument, NULL, 'f' },
{ "fstab", no_argument, NULL, 's' },
@@ -1458,6 +1570,7 @@ int main(int argc, char *argv[])
{ "pseudo", no_argument, NULL, FINDMNT_OPT_PSEUDO },
{ "vfs-all", no_argument, NULL, FINDMNT_OPT_VFS_ALL },
{ "shadowed", no_argument, NULL, FINDMNT_OPT_SHADOWED },
+ { "list-columns", no_argument, NULL, 'H' },
{ NULL, 0, NULL, 0 }
};
@@ -1484,7 +1597,7 @@ int main(int argc, char *argv[])
flags |= FL_TREE;
while ((c = getopt_long(argc, argv,
- "AabCcDd:ehiJfF:o:O:p::PklmM:nN:rst:uvRS:T:Uw:Vxy",
+ "AabCcDd:ehIiJfF:o:O:p::PklmM:nN:rst:uvRS:T:Uw:VxyH",
longopts, NULL)) != -1) {
err_exclusive_options(c, longopts, excl, excl_st);
@@ -1521,6 +1634,10 @@ int main(int argc, char *argv[])
case 'e':
flags |= FL_EVALUATE;
break;
+ case 'I':
+ flags &= ~FL_TREE;
+ flags |= FL_DF_INODES;
+ break;
case 'i':
flags |= FL_INVERT;
break;
@@ -1642,6 +1759,10 @@ int main(int argc, char *argv[])
case FINDMNT_OPT_SHADOWED:
flags |= FL_SHADOWED;
break;
+
+ case 'H':
+ collist = 1;
+ break;
case 'h':
usage();
case 'V':
@@ -1651,7 +1772,19 @@ int main(int argc, char *argv[])
}
}
- if (!ncolumns && (flags & FL_DF)) {
+ if (collist)
+ list_colunms(); /* print end exit */
+
+ if (!ncolumns && (flags & FL_DF_INODES)) {
+ add_column(columns, ncolumns++, COL_SOURCE);
+ add_column(columns, ncolumns++, COL_FSTYPE);
+ add_column(columns, ncolumns++, COL_INO_TOTAL);
+ add_column(columns, ncolumns++, COL_INO_USED);
+ add_column(columns, ncolumns++, COL_INO_AVAIL);
+ add_column(columns, ncolumns++, COL_INO_USEPERC);
+ add_column(columns, ncolumns++, COL_TARGET);
+ }
+ else if (!ncolumns && (flags & FL_DF)) {
add_column(columns, ncolumns++, COL_SOURCE);
add_column(columns, ncolumns++, COL_FSTYPE);
add_column(columns, ncolumns++, COL_SIZE);
@@ -1793,36 +1926,13 @@ int main(int argc, char *argv[])
goto leave;
}
/* multi-line cells (now used for SOURCES) */
- if (fl & SCOLS_FL_WRAP) {
+ if (fl & SCOLS_FL_WRAP)
scols_column_set_wrapfunc(cl,
- scols_wrapnl_chunksize,
- scols_wrapnl_nextchunk,
+ NULL,
+ scols_wrapzero_nextchunk,
NULL);
- scols_column_set_safechars(cl, "\n");
- }
- if (flags & FL_JSON) {
- switch (id) {
- case COL_SIZE:
- case COL_AVAIL:
- case COL_USED:
- if (!(flags & FL_BYTES))
- break;
- /* fallthrough */
- case COL_ID:
- case COL_PARENT:
- case COL_FREQ:
- case COL_PASSNO:
- case COL_TID:
- scols_column_set_json_type(cl, SCOLS_JSON_NUMBER);
- break;
- default:
- if (fl & SCOLS_FL_WRAP)
- scols_column_set_json_type(cl, SCOLS_JSON_ARRAY_STRING);
- else
- scols_column_set_json_type(cl, SCOLS_JSON_STRING);
- break;
- }
- }
+ if (flags & FL_JSON)
+ scols_column_set_json_type(cl, get_column_json_type(id, fl, NULL));
}
/*