>From dcb21719a7ffc54c81113add61e5b95d4adad133 Mon Sep 17 00:00:00 2001 From: Bernhard Voelker
Date: Fri, 26 Jul 2013 16:03:18 +0200 Subject: [PATCH] du: add --inodes option This new option can be used to find directories with a huge amount of files. The GNU find utility has the printf format "%h" which prints the number of entries in a directory, but this is non-cumulative and doesn't handle hard links. * src/du.c (struct duinfo): Add new member for counting inodes. (duinfo_init): Initialize inodes member with Zero. (duinfo_set): Set inodes counter to 1. (duinfo_add): Sum up the 2 given inodes counters. (opt_inodes): Add new boolean flag to remember if the --inodes option has been specified. (INODES_OPTION): Add new enum value to be used ... (long_options): ... here. (usage): Add description of the new option. (print_size): Pass inodes counter or size to print_only_size, depending on the inodes mode. (process_file): Adapt threshold handling: with --inodes, print or elide the entries according to the struct member inodes. (main): Add a case for accepting the new INODES_OPTION. Print a warning diagnostic when --inodes is used together with the option --apparent-size or -b. Reset the output_block_size to 1 ... and thus ignoring the options -m and -k. * tests/du/inodes.sh: Add a new test. * tests/local.mk (all_tests): Mention it. * doc/coreutils.texi (du invocation): Document the new option. * NEWS: Mention the new option. --- NEWS | 3 ++ doc/coreutils.texi | 29 +++++++++++- src/du.c | 38 +++++++++++++-- tests/du/inodes.sh | 133 +++++++++++++++++++++++++++++++++++++++++++++++++++++ tests/local.mk | 1 + 5 files changed, 199 insertions(+), 5 deletions(-) create mode 100755 tests/du/inodes.sh diff --git a/NEWS b/NEWS index 3d0fb18..4a78617 100644 --- a/NEWS +++ b/NEWS @@ -37,6 +37,9 @@ GNU coreutils NEWS -*- outline -*- ** New features + du accepts a new option: --inodes to show the number of inodes instead + of the blocks used. + id and ls with -Z report the SMACK security context where available. mkdir, mkfifo and mknod with -Z set the SMACK context where available. diff --git a/doc/coreutils.texi b/doc/coreutils.texi index b8d40b4..64d23b9 100644 --- a/doc/coreutils.texi +++ b/doc/coreutils.texi @@ -11424,6 +11424,20 @@ Equivalent to @option{--dereference-args} (@option{-D}). @optHumanReadable +@itemx --inodes +@opindex --inodes +@cindex inode usage, dereferencing in @command{du} +List inode usage information instead of block usage. An inode (short +for index node) contains information about a file such as its owner, +permissions, timestamps, and location on the disk. +This option is useful for finding directories which contain many files, and +therefore eat up most of the inodes space of a file system (see @command{df}, +option @option{--inodes}). +It can well be combined with the options @option{-a}, @option{-c}, +@option{-h}, @option{-l}, @option{-s}, @option{-S}, @option{-t} and +@option{-x}; however, passing other options regarding the block size, for +example @option{-b}, @option{-m} and @option{--apparent-size}, is ignored. + @item -k @opindex -k @cindex kibibytes for file sizes @@ -11485,7 +11499,9 @@ Display only a total for each argument. @itemx --threshold=@var{size} @opindex -t @opindex --threshold -Exclude entries based on a given @var{size} (@pxref{Block size}). +Exclude entries based on a given @var{size}. The @var{size} refers to used +blocks in normal mode (@pxref{Block size}), or inodes count in conjunction +with the @option{--inodes} option. If @var{size} is positive, then @command{du} will only print entries with a size greater than or equal to that. @@ -11501,6 +11517,10 @@ Please note that the @option{--threshold} option can be combined with the @option{--apparent-size} option, and in this case would elide entries based on its apparent size. +Please note that the @option{--threshold} option can be combined with the +@option{--inodes} option, and in this case would elide entries based on +its inodes count. + Here's how you would use @option{--threshold} to find directories with a size greater than or equal to 200 megabytes: @@ -11515,6 +11535,13 @@ note the @option{-a} - with an apparent size smaller than or equal to 500 bytes: du -a -t -500 --apparent-size @end example +Here's how you would use @option{--threshold} to find directories on the root +file system with more than 20000 inodes used in the directory tree below: + +@example +du --inodes -x --threshold=20000 / +@end example + @item --time @opindex --time diff --git a/src/du.c b/src/du.c index a6fa16b..d22ca73 100644 --- a/src/du.c +++ b/src/du.c @@ -78,6 +78,9 @@ struct duinfo /* Size of files in directory. */ uintmax_t size; + /* Number of inodes in directory. */ + size_t inodes; + /* Latest time stamp found. If tmax.tv_sec == TYPE_MINIMUM (time_t) && tmax.tv_nsec < 0, no time stamp has been found. */ struct timespec tmax; @@ -88,6 +91,7 @@ static inline void duinfo_init (struct duinfo *a) { a->size = 0; + a->inodes = 0; a->tmax.tv_sec = TYPE_MINIMUM (time_t); a->tmax.tv_nsec = -1; } @@ -97,6 +101,7 @@ static inline void duinfo_set (struct duinfo *a, uintmax_t size, struct timespec tmax) { a->size = size; + a->inodes = 1; a->tmax = tmax; } @@ -106,6 +111,7 @@ duinfo_add (struct duinfo *a, struct duinfo const *b) { uintmax_t sum = a->size + b->size; a->size = a->size <= sum ? sum : UINTMAX_MAX; + a->inodes = a->inodes + b->inodes; if (timespec_cmp (a->tmax, b->tmax) < 0) a->tmax = b->tmax; } @@ -154,6 +160,9 @@ static intmax_t opt_threshold = 0; /* Human-readable options for output. */ static int human_output_opts; +/* Output inodes count instead of blocks used. */ +static bool opt_inodes = false; + /* If true, print most recently modified date, using the specified format. */ static bool opt_time = false; @@ -197,7 +206,8 @@ enum HUMAN_SI_OPTION, FTS_DEBUG, TIME_OPTION, - TIME_STYLE_OPTION + TIME_STYLE_OPTION, + INODES_OPTION }; static struct option const long_options[] = @@ -214,6 +224,7 @@ static struct option const long_options[] = {"exclude-from", required_argument, NULL, 'X'}, {"files0-from", required_argument, NULL, FILES0_FROM_OPTION}, {"human-readable", no_argument, NULL, 'h'}, + {"inodes", no_argument, NULL, INODES_OPTION}, {"si", no_argument, NULL, HUMAN_SI_OPTION}, {"max-depth", required_argument, NULL, 'd'}, {"null", no_argument, NULL, '0'}, @@ -306,6 +317,7 @@ Summarize disk usage of each FILE, recursively for directories.\n\ -H equivalent to --dereference-args (-D)\n\ -h, --human-readable print sizes in human readable format (e.g., 1K 234M 2G)\ \n\ + --inodes list inode usage information instead of block usage\n\ "), stdout); fputs (_("\ -k like --block-size=1K\n\ @@ -394,7 +406,10 @@ print_only_size (uintmax_t n_bytes) static void print_size (const struct duinfo *pdui, const char *string) { - print_only_size (pdui->size); + print_only_size (opt_inodes + ? pdui->inodes + : pdui->size); + if (opt_time) { putchar ('\t'); @@ -589,9 +604,10 @@ process_file (FTS *fts, FTSENT *ent) || level == 0) { /* Print or elide this entry according to the --threshold option. */ + intmax_t v = opt_inodes ? dui_to_print.inodes : dui_to_print.size; if (opt_threshold < 0 - ? dui_to_print.size <= -opt_threshold - : dui_to_print.size >= opt_threshold) + ? v <= -opt_threshold + : v >= opt_threshold) print_size (&dui_to_print, file); } @@ -853,6 +869,10 @@ main (int argc, char **argv) add_exclude (exclude, optarg, EXCLUDE_WILDCARDS); break; + case INODES_OPTION: + opt_inodes = true; + break; + case TIME_OPTION: opt_time = true; time_type = @@ -899,6 +919,16 @@ main (int argc, char **argv) if (opt_summarize_only) max_depth = 0; + if (opt_inodes) + { + if (apparent_size) + { + error (0, 0, _("warning: options --apparent-size and -b are " + "ineffective with --inodes")); + } + output_block_size = 1; + } + /* Process time style if printing last times. */ if (opt_time) { diff --git a/tests/du/inodes.sh b/tests/du/inodes.sh new file mode 100755 index 0000000..d9b3980 --- /dev/null +++ b/tests/du/inodes.sh @@ -0,0 +1,133 @@ +#!/bin/sh +# exercise du's --inodes option + +# Copyright (C) 2010-2013 Free Software Foundation, Inc. + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see