Have I done something incorrectly? How or does this feature request proceed from here?
Thank you for considering it. Dan. On Wednesday, February 28, 2018, Daniel Gall <daniel.r.g...@gmail.com> wrote: > uggh and i'm not current with master. one more time. > > From bbbbd12345c4585de20f2fef304c6b5c7185d2a2 Mon Sep 17 00:00:00 2001 > From: Daniel Gall <daniel.r.g...@gmail.com> > Date: Tue, 27 Feb 2018 20:05:01 -0500 > Subject: [PATCH] du: Added group reporting feature > > --- > NEWS | 2 + > doc/coreutils.texi | 5 ++ > src/du.c | 176 ++++++++++++++++++++++++++++++ > ++++++++++++++++++++--- > 3 files changed, 174 insertions(+), 9 deletions(-) > > diff --git a/NEWS b/NEWS > index 5fa6928..a136cc9 100644 > --- a/NEWS > +++ b/NEWS > @@ -61,6 +61,8 @@ GNU coreutils NEWS > -*- outline -*- > > timeout now supports the --verbose option to diagnose forced > termination. > > + du now supports the -g option for group reporting > + > ** Improvements > > dd now supports iflag=direct with arbitrary sized files on all file > systems. > diff --git a/doc/coreutils.texi b/doc/coreutils.texi > index cdde136..d220012 100644 > --- a/doc/coreutils.texi > +++ b/doc/coreutils.texi > @@ -11910,6 +11910,11 @@ is at level 0, so @code{du --max-depth=0} is > equivalent to @code{du -s}. > @c --files0-from=FILE > @filesZeroFromOption{du,, with the @option{--total} (@option{-c}) option} > > +@item -g > +@opindex -g > +@cindex group reporting > +Show group subtotals for each item reported on. > + > @item -H > @opindex -H > Equivalent to @option{--dereference-args} (@option{-D}). > diff --git a/src/du.c b/src/du.c > index ac4489f..97edb5d 100644 > --- a/src/du.c > +++ b/src/du.c > @@ -35,6 +35,7 @@ > #include "error.h" > #include "exclude.h" > #include "fprintftime.h" > +#include "grp.h" > #include "human.h" > #include "mountlist.h" > #include "quote.h" > @@ -61,6 +62,9 @@ extern bool fts_debug; > # define FTS_CROSS_CHECK(Fts) > #endif > > +/* If true, display group size info. */ > +bool opt_group_sizes = false; > + > /* A set of dev/ino pairs to help identify files and directories > whose sizes have already been counted. */ > static struct di_set *di_files; > @@ -80,7 +84,7 @@ struct duinfo > > /* Number of inodes in directory. */ > uintmax_t inodes; > - > + uintmax_t *group_size; > /* Latest timestamp found. If tmax.tv_sec == TYPE_MINIMUM (time_t) > && tmax.tv_nsec < 0, no timestamp has been found. */ > struct timespec tmax; > @@ -90,28 +94,62 @@ struct duinfo > static inline void > duinfo_init (struct duinfo *a) > { > + uintmax_t i = 0; > a->size = 0; > a->inodes = 0; > a->tmax.tv_sec = TYPE_MINIMUM (time_t); > a->tmax.tv_nsec = -1; > + if (opt_group_sizes) > + { > + for (i=0; i<65535; i++) > + { > + a->group_size[i] = 0; > + } > + } > } > > /* Set directory data. */ > static inline void > -duinfo_set (struct duinfo *a, uintmax_t size, struct timespec tmax) > +duinfo_set (struct duinfo *a, uintmax_t size, struct timespec tmax, > uintmax_t gid) > { > + uintmax_t gid_u = (uintmax_t)gid; > + uintmax_t gid_s; > a->size = size; > a->inodes = 1; > a->tmax = tmax; > + if (opt_group_sizes) > + { > + if (gid_u > 65534) > + { > + gid_s = 65534; > + } > + else > + { > + gid_s = gid_u; > + } > + if (gid_s >=0 && gid_s <=65534) > + { > + a->group_size[gid_s] = size; > + } > + } > } > > /* Accumulate directory data. */ > static inline void > duinfo_add (struct duinfo *a, struct duinfo const *b) > { > + uintmax_t i = 0; > uintmax_t sum = a->size + b->size; > a->size = a->size <= sum ? sum : UINTMAX_MAX; > a->inodes = a->inodes + b->inodes; > + if (opt_group_sizes) > + { > + for (i=0; i<65535; i++) > + { > + sum = a->group_size[i] + b->group_size[i]; > + a->group_size[i] = a->group_size[i] <= sum ? sum : UINTMAX_MAX; > + } > + } > if (timespec_cmp (a->tmax, b->tmax) < 0) > a->tmax = b->tmax; > } > @@ -226,6 +264,7 @@ static struct option const long_options[] = > {"exclude", required_argument, NULL, EXCLUDE_OPTION}, > {"exclude-from", required_argument, NULL, 'X'}, > {"files0-from", required_argument, NULL, FILES0_FROM_OPTION}, > + {"group-reporting", no_argument, NULL, 'g'}, > {"human-readable", no_argument, NULL, 'h'}, > {"inodes", no_argument, NULL, INODES_OPTION}, > {"si", no_argument, NULL, HUMAN_SI_OPTION}, > @@ -317,6 +356,7 @@ Summarize disk usage of the set of FILEs, > recursively for directories.\n\ > --files0-from=F summarize disk usage of the\n\ > NUL-terminated file names specified in file > F;\n\ > if F is -, then read names from standard > input\n\ > + -g, --group-reporting also print group subtotals\n\ > -H equivalent to --dereference-args (-D)\n\ > -h, --human-readable print sizes in human readable format (e.g., > 1K 234M 2G)\ > \n\ > @@ -411,7 +451,25 @@ print_size (const struct duinfo *pdui, const char > *string) > print_only_size (opt_inodes > ? pdui->inodes > : pdui->size); > - > + if (opt_group_sizes) > + { > + uintmax_t i=0; > + struct group *g; > + printf(" Groups"); > + for (i=0; i<65535; i++){ > + if (pdui->group_size[i] > 0) > + { > + g = getgrgid(i); > + printf (","); > + if (g == NULL){ > + printf (" %Ld:", (long long unsigned int)i); > + }else{ > + printf(" %s:", g->gr_name); > + } > + print_only_size(pdui->group_size[i]); > + } > + } > + } > if (opt_time) > { > putchar ('\t'); > @@ -506,6 +564,12 @@ process_file (FTS *fts, FTSENT *ent) > const struct stat *sb = ent->fts_statp; > int info = ent->fts_info; > > + if(opt_group_sizes) > + { > + dui.group_size = xcalloc (65536, sizeof (uintmax_t)); > + dui_to_print.group_size = xcalloc (65536, sizeof (uintmax_t)); > + } > + > if (info == FTS_DNR) > { > /* An error occurred, but the size is known, so count it. */ > @@ -530,7 +594,18 @@ process_file (FTS *fts, FTSENT *ent) > if (info == FTS_NS || info == FTS_SLNONE) > { > error (0, ent->fts_errno, _("cannot access %s"), quoteaf > (file)); > - return false; > + if(opt_group_sizes) > + { > + if (dui.group_size != NULL) > + { > + free(dui.group_size); > + } > + if (dui_to_print.group_size != NULL) > + { > + free(dui_to_print.group_size); > + } > + } > + return false; > } > > /* The --one-file-system (-x) option cannot exclude anything > @@ -558,13 +633,34 @@ process_file (FTS *fts, FTSENT *ent) > FTSENT const *e = fts_read (fts); > assert (e == ent); > } > - > + if(opt_group_sizes) > + { > + if (dui.group_size != NULL) > + { > + free(dui.group_size); > + } > + if (dui_to_print.group_size != NULL) > + { > + free(dui_to_print.group_size); > + } > + } > return true; > } > > switch (info) > { > case FTS_D: > + if(opt_group_sizes) > + { > + if (dui.group_size != NULL) > + { > + free(dui.group_size); > + } > + if (dui_to_print.group_size != NULL) > + { > + free(dui_to_print.group_size); > + } > + } > return true; > > case FTS_ERR: > @@ -574,6 +670,17 @@ process_file (FTS *fts, FTSENT *ent) > break; > > case FTS_DC: > + if(opt_group_sizes) > + { > + if (dui.group_size != NULL) > + { > + free(dui.group_size); > + } > + if (dui_to_print.group_size != NULL) > + { > + free(dui_to_print.group_size); > + } > + } > /* If not following symlinks and not a (bind) mount point. */ > if (cycle_warning_required (fts, ent) > && ! mount_point_in_fts_cycle (ent)) > @@ -591,15 +698,40 @@ process_file (FTS *fts, FTSENT *ent) > : (uintmax_t) ST_NBLOCKS (*sb) * ST_NBLOCKSIZE), > (time_type == time_mtime ? get_stat_mtime (sb) > : time_type == time_atime ? get_stat_atime (sb) > - : get_stat_ctime (sb))); > + : get_stat_ctime (sb)), > + sb->st_gid); > > level = ent->fts_level; > - dui_to_print = dui; > + > + if (opt_group_sizes) > + { > + duinfo_set (&dui_to_print, > + (apparent_size > + ? MAX (0, sb->st_size) > + : (uintmax_t) ST_NBLOCKS (*sb) * ST_NBLOCKSIZE), > + (time_type == time_mtime ? get_stat_mtime (sb) > + : time_type == time_atime ? get_stat_atime (sb) > + : get_stat_ctime (sb)), > + sb->st_gid); > + } > + else > + { > + dui_to_print = dui; > + } > > if (n_alloc == 0) > { > + size_t i; > n_alloc = level + 10; > dulvl = xcalloc (n_alloc, sizeof *dulvl); > + if(opt_group_sizes) > + { > + for (i=0; i<n_alloc; i++) > + { > + dulvl[i].ent.group_size = xcalloc (65536, sizeof > (uintmax_t)); > + dulvl[i].subdir.group_size = xcalloc (65536, sizeof > (uintmax_t)); > + } > + } > } > else > { > @@ -613,14 +745,23 @@ process_file (FTS *fts, FTSENT *ent) > Clear the accumulators for *all* levels between prev_level > and the current one. The depth may change dramatically, > e.g., from 1 to 10. */ > + size_t i; > > if (n_alloc <= level) > { > dulvl = xnrealloc (dulvl, level, 2 * sizeof *dulvl); > + if(opt_group_sizes) > + { > + for (i=n_alloc; i<level*2; i++) > + { > + dulvl[i].ent.group_size = xcalloc (65536, > sizeof (uintmax_t)); > + dulvl[i].subdir.group_size = xcalloc (65536, > sizeof (uintmax_t)); > + } > + } > n_alloc = level * 2; > } > > - for (size_t i = prev_level + 1; i <= level; i++) > + for (i = prev_level + 1; i <= level; i++) > { > duinfo_init (&dulvl[i].ent); > duinfo_init (&dulvl[i].subdir); > @@ -666,6 +807,18 @@ process_file (FTS *fts, FTSENT *ent) > print_size (&dui_to_print, file); > } > > + if(opt_group_sizes) > + { > + if (dui.group_size != NULL) > + { > + free(dui.group_size); > + } > + if (dui_to_print.group_size != NULL) > + { > + free(dui_to_print.group_size); > + } > + } > + > return ok; > } > > @@ -755,7 +908,7 @@ main (int argc, char **argv) > while (true) > { > int oi = -1; > - int c = getopt_long (argc, argv, "0abd:chHklmst:xB:DLPSX:", > + int c = getopt_long (argc, argv, "0abgd:chHklmst:xB:DLPSX:", > long_options, &oi); > if (c == -1) > break; > @@ -800,6 +953,11 @@ main (int argc, char **argv) > output_block_size = 1; > break; > > + case 'g': > + tot_dui.group_size = xcalloc (65536, sizeof (uintmax_t)); > + opt_group_sizes = true; > + break; > + > case 'k': > human_output_opts = 0; > output_block_size = 1024; > -- > 2.10.2 > > > On Wed, Feb 28, 2018 at 12:59 AM, Daniel Gall <daniel.r.g...@gmail.com> > wrote: > > Ok, here it all is in one commit. > > > > From f170b214684f870e81ab79c83a0dd87206fee4af Mon Sep 17 00:00:00 2001 > > From: Daniel Gall <daniel.r.g...@gmail.com> > > Date: Tue, 27 Feb 2018 19:51:34 -0500 > > Subject: [PATCH] du: Added group reporting feature > > > > --- > > NEWS | 7 +-- > > doc/coreutils.texi | 5 ++ > > src/du.c | 176 ++++++++++++++++++++++++++++++ > ++++++++++++++++++++--- > > 3 files changed, 174 insertions(+), 14 deletions(-) > > > > diff --git a/NEWS b/NEWS > > index 5fa6928..97ccc2c 100644 > > --- a/NEWS > > +++ b/NEWS > > @@ -16,11 +16,6 @@ GNU coreutils NEWS > > -*- outline -*- > > that caused -u to sometimes override -n. > > [bug introduced with coreutils-7.1] > > > > - 'cp -a --no-preserve=mode' now sets appropriate default permissions > > - for non regular files like fifos and character device nodes etc. > > - Previously it would have set executable bits on created special files. > > - [bug introduced with coreutils-8.20] > > - > > > > * Noteworthy changes in release 8.29 (2017-12-27) [stable] > > > > @@ -61,6 +56,8 @@ GNU coreutils NEWS > > -*- outline -*- > > > > timeout now supports the --verbose option to diagnose forced > termination. > > > > + du now supports the -g option for group reporting > > + > > ** Improvements > > > > dd now supports iflag=direct with arbitrary sized files on all file > systems. > > diff --git a/doc/coreutils.texi b/doc/coreutils.texi > > index cdde136..d220012 100644 > > --- a/doc/coreutils.texi > > +++ b/doc/coreutils.texi > > @@ -11910,6 +11910,11 @@ is at level 0, so @code{du --max-depth=0} is > > equivalent to @code{du -s}. > > @c --files0-from=FILE > > @filesZeroFromOption{du,, with the @option{--total} (@option{-c}) > option} > > > > +@item -g > > +@opindex -g > > +@cindex group reporting > > +Show group subtotals for each item reported on. > > + > > @item -H > > @opindex -H > > Equivalent to @option{--dereference-args} (@option{-D}). > > diff --git a/src/du.c b/src/du.c > > index ac4489f..97edb5d 100644 > > --- a/src/du.c > > +++ b/src/du.c > > @@ -35,6 +35,7 @@ > > #include "error.h" > > #include "exclude.h" > > #include "fprintftime.h" > > +#include "grp.h" > > #include "human.h" > > #include "mountlist.h" > > #include "quote.h" > > @@ -61,6 +62,9 @@ extern bool fts_debug; > > # define FTS_CROSS_CHECK(Fts) > > #endif > > > > +/* If true, display group size info. */ > > +bool opt_group_sizes = false; > > + > > /* A set of dev/ino pairs to help identify files and directories > > whose sizes have already been counted. */ > > static struct di_set *di_files; > > @@ -80,7 +84,7 @@ struct duinfo > > > > /* Number of inodes in directory. */ > > uintmax_t inodes; > > - > > + uintmax_t *group_size; > > /* Latest timestamp found. If tmax.tv_sec == TYPE_MINIMUM (time_t) > > && tmax.tv_nsec < 0, no timestamp has been found. */ > > struct timespec tmax; > > @@ -90,28 +94,62 @@ struct duinfo > > static inline void > > duinfo_init (struct duinfo *a) > > { > > + uintmax_t i = 0; > > a->size = 0; > > a->inodes = 0; > > a->tmax.tv_sec = TYPE_MINIMUM (time_t); > > a->tmax.tv_nsec = -1; > > + if (opt_group_sizes) > > + { > > + for (i=0; i<65535; i++) > > + { > > + a->group_size[i] = 0; > > + } > > + } > > } > > > > /* Set directory data. */ > > static inline void > > -duinfo_set (struct duinfo *a, uintmax_t size, struct timespec tmax) > > +duinfo_set (struct duinfo *a, uintmax_t size, struct timespec tmax, > > uintmax_t gid) > > { > > + uintmax_t gid_u = (uintmax_t)gid; > > + uintmax_t gid_s; > > a->size = size; > > a->inodes = 1; > > a->tmax = tmax; > > + if (opt_group_sizes) > > + { > > + if (gid_u > 65534) > > + { > > + gid_s = 65534; > > + } > > + else > > + { > > + gid_s = gid_u; > > + } > > + if (gid_s >=0 && gid_s <=65534) > > + { > > + a->group_size[gid_s] = size; > > + } > > + } > > } > > > > /* Accumulate directory data. */ > > static inline void > > duinfo_add (struct duinfo *a, struct duinfo const *b) > > { > > + uintmax_t i = 0; > > uintmax_t sum = a->size + b->size; > > a->size = a->size <= sum ? sum : UINTMAX_MAX; > > a->inodes = a->inodes + b->inodes; > > + if (opt_group_sizes) > > + { > > + for (i=0; i<65535; i++) > > + { > > + sum = a->group_size[i] + b->group_size[i]; > > + a->group_size[i] = a->group_size[i] <= sum ? sum : > UINTMAX_MAX; > > + } > > + } > > if (timespec_cmp (a->tmax, b->tmax) < 0) > > a->tmax = b->tmax; > > } > > @@ -226,6 +264,7 @@ static struct option const long_options[] = > > {"exclude", required_argument, NULL, EXCLUDE_OPTION}, > > {"exclude-from", required_argument, NULL, 'X'}, > > {"files0-from", required_argument, NULL, FILES0_FROM_OPTION}, > > + {"group-reporting", no_argument, NULL, 'g'}, > > {"human-readable", no_argument, NULL, 'h'}, > > {"inodes", no_argument, NULL, INODES_OPTION}, > > {"si", no_argument, NULL, HUMAN_SI_OPTION}, > > @@ -317,6 +356,7 @@ Summarize disk usage of the set of FILEs, > > recursively for directories.\n\ > > --files0-from=F summarize disk usage of the\n\ > > NUL-terminated file names specified in file > F;\n\ > > if F is -, then read names from standard > input\n\ > > + -g, --group-reporting also print group subtotals\n\ > > -H equivalent to --dereference-args (-D)\n\ > > -h, --human-readable print sizes in human readable format (e.g., > > 1K 234M 2G)\ > > \n\ > > @@ -411,7 +451,25 @@ print_size (const struct duinfo *pdui, const char > *string) > > print_only_size (opt_inodes > > ? pdui->inodes > > : pdui->size); > > - > > + if (opt_group_sizes) > > + { > > + uintmax_t i=0; > > + struct group *g; > > + printf(" Groups"); > > + for (i=0; i<65535; i++){ > > + if (pdui->group_size[i] > 0) > > + { > > + g = getgrgid(i); > > + printf (","); > > + if (g == NULL){ > > + printf (" %Ld:", (long long unsigned int)i); > > + }else{ > > + printf(" %s:", g->gr_name); > > + } > > + print_only_size(pdui->group_size[i]); > > + } > > + } > > + } > > if (opt_time) > > { > > putchar ('\t'); > > @@ -506,6 +564,12 @@ process_file (FTS *fts, FTSENT *ent) > > const struct stat *sb = ent->fts_statp; > > int info = ent->fts_info; > > > > + if(opt_group_sizes) > > + { > > + dui.group_size = xcalloc (65536, sizeof (uintmax_t)); > > + dui_to_print.group_size = xcalloc (65536, sizeof (uintmax_t)); > > + } > > + > > if (info == FTS_DNR) > > { > > /* An error occurred, but the size is known, so count it. */ > > @@ -530,7 +594,18 @@ process_file (FTS *fts, FTSENT *ent) > > if (info == FTS_NS || info == FTS_SLNONE) > > { > > error (0, ent->fts_errno, _("cannot access %s"), quoteaf > (file)); > > - return false; > > + if(opt_group_sizes) > > + { > > + if (dui.group_size != NULL) > > + { > > + free(dui.group_size); > > + } > > + if (dui_to_print.group_size != NULL) > > + { > > + free(dui_to_print.group_size); > > + } > > + } > > + return false; > > } > > > > /* The --one-file-system (-x) option cannot exclude anything > > @@ -558,13 +633,34 @@ process_file (FTS *fts, FTSENT *ent) > > FTSENT const *e = fts_read (fts); > > assert (e == ent); > > } > > - > > + if(opt_group_sizes) > > + { > > + if (dui.group_size != NULL) > > + { > > + free(dui.group_size); > > + } > > + if (dui_to_print.group_size != NULL) > > + { > > + free(dui_to_print.group_size); > > + } > > + } > > return true; > > } > > > > switch (info) > > { > > case FTS_D: > > + if(opt_group_sizes) > > + { > > + if (dui.group_size != NULL) > > + { > > + free(dui.group_size); > > + } > > + if (dui_to_print.group_size != NULL) > > + { > > + free(dui_to_print.group_size); > > + } > > + } > > return true; > > > > case FTS_ERR: > > @@ -574,6 +670,17 @@ process_file (FTS *fts, FTSENT *ent) > > break; > > > > case FTS_DC: > > + if(opt_group_sizes) > > + { > > + if (dui.group_size != NULL) > > + { > > + free(dui.group_size); > > + } > > + if (dui_to_print.group_size != NULL) > > + { > > + free(dui_to_print.group_size); > > + } > > + } > > /* If not following symlinks and not a (bind) mount point. */ > > if (cycle_warning_required (fts, ent) > > && ! mount_point_in_fts_cycle (ent)) > > @@ -591,15 +698,40 @@ process_file (FTS *fts, FTSENT *ent) > > : (uintmax_t) ST_NBLOCKS (*sb) * ST_NBLOCKSIZE), > > (time_type == time_mtime ? get_stat_mtime (sb) > > : time_type == time_atime ? get_stat_atime (sb) > > - : get_stat_ctime (sb))); > > + : get_stat_ctime (sb)), > > + sb->st_gid); > > > > level = ent->fts_level; > > - dui_to_print = dui; > > + > > + if (opt_group_sizes) > > + { > > + duinfo_set (&dui_to_print, > > + (apparent_size > > + ? MAX (0, sb->st_size) > > + : (uintmax_t) ST_NBLOCKS (*sb) * ST_NBLOCKSIZE), > > + (time_type == time_mtime ? get_stat_mtime (sb) > > + : time_type == time_atime ? get_stat_atime (sb) > > + : get_stat_ctime (sb)), > > + sb->st_gid); > > + } > > + else > > + { > > + dui_to_print = dui; > > + } > > > > if (n_alloc == 0) > > { > > + size_t i; > > n_alloc = level + 10; > > dulvl = xcalloc (n_alloc, sizeof *dulvl); > > + if(opt_group_sizes) > > + { > > + for (i=0; i<n_alloc; i++) > > + { > > + dulvl[i].ent.group_size = xcalloc (65536, sizeof > (uintmax_t)); > > + dulvl[i].subdir.group_size = xcalloc (65536, sizeof > (uintmax_t)); > > + } > > + } > > } > > else > > { > > @@ -613,14 +745,23 @@ process_file (FTS *fts, FTSENT *ent) > > Clear the accumulators for *all* levels between prev_level > > and the current one. The depth may change dramatically, > > e.g., from 1 to 10. */ > > + size_t i; > > > > if (n_alloc <= level) > > { > > dulvl = xnrealloc (dulvl, level, 2 * sizeof *dulvl); > > + if(opt_group_sizes) > > + { > > + for (i=n_alloc; i<level*2; i++) > > + { > > + dulvl[i].ent.group_size = xcalloc (65536, > > sizeof (uintmax_t)); > > + dulvl[i].subdir.group_size = xcalloc (65536, > > sizeof (uintmax_t)); > > + } > > + } > > n_alloc = level * 2; > > } > > > > - for (size_t i = prev_level + 1; i <= level; i++) > > + for (i = prev_level + 1; i <= level; i++) > > { > > duinfo_init (&dulvl[i].ent); > > duinfo_init (&dulvl[i].subdir); > > @@ -666,6 +807,18 @@ process_file (FTS *fts, FTSENT *ent) > > print_size (&dui_to_print, file); > > } > > > > + if(opt_group_sizes) > > + { > > + if (dui.group_size != NULL) > > + { > > + free(dui.group_size); > > + } > > + if (dui_to_print.group_size != NULL) > > + { > > + free(dui_to_print.group_size); > > + } > > + } > > + > > return ok; > > } > > > > @@ -755,7 +908,7 @@ main (int argc, char **argv) > > while (true) > > { > > int oi = -1; > > - int c = getopt_long (argc, argv, "0abd:chHklmst:xB:DLPSX:", > > + int c = getopt_long (argc, argv, "0abgd:chHklmst:xB:DLPSX:", > > long_options, &oi); > > if (c == -1) > > break; > > @@ -800,6 +953,11 @@ main (int argc, char **argv) > > output_block_size = 1; > > break; > > > > + case 'g': > > + tot_dui.group_size = xcalloc (65536, sizeof (uintmax_t)); > > + opt_group_sizes = true; > > + break; > > + > > case 'k': > > human_output_opts = 0; > > output_block_size = 1024; > > -- > > 2.10.2 > > > > > > On Wed, Feb 7, 2018 at 8:01 AM, Daniel Gall <daniel.r.g...@gmail.com> > wrote: > >> From 9fa842c9153dc0f68cfcf4ba25fa7f6798b4e2e4 Mon Sep 17 00:00:00 2001 > >> From: Daniel Gall <daniel.r.g...@gmail.com> > >> Date: Wed, 7 Feb 2018 02:58:52 -0500 > >> Subject: [PATCH 2/2] du: added "Groups" intro to group reporting > >> > >> In the event that both the group subtotal reporting feature > >> and the users subtotal reporting feature are accepted, > >> invokers may wish to use both features at the same time. > >> This necessitates some delineation of user vs group reporting. > >> --- > >> src/du.c | 1 + > >> 1 file changed, 1 insertion(+) > >> > >> diff --git a/src/du.c b/src/du.c > >> index a8318ca..97edb5d 100644 > >> --- a/src/du.c > >> +++ b/src/du.c > >> @@ -455,6 +455,7 @@ print_size (const struct duinfo *pdui, const char > *string) > >> { > >> uintmax_t i=0; > >> struct group *g; > >> + printf(" Groups"); > >> for (i=0; i<65535; i++){ > >> if (pdui->group_size[i] > 0) > >> { > >> -- > >> 2.10.2 > >> > >> On Tue, Feb 6, 2018 at 10:45 PM, Daniel Gall <daniel.r.g...@gmail.com> > wrote: > >>> I realized as I was implementing the user subtotal reporting feature > >>> that if both the user and group reporting features are accepted then > >>> users will be able to invoke both options and thus the reporting would > >>> be confusing without some delineation of user vs group reporting > >>> output. I intend to add a line to the group feature request to try to > >>> address that. > >>> > >>> Dan. > >>> > >>> On Mon, Feb 5, 2018 at 7:32 PM, Daniel Gall <daniel.r.g...@gmail.com> > wrote: > >>>> From c5b3dc83a762fd96c60d7560249a1815386a5efb Mon Sep 17 00:00:00 > 2001 > >>>> From: Daniel Gall <daniel.r.g...@gmail.com> > >>>> Date: Mon, 5 Feb 2018 14:30:39 -0500 > >>>> Subject: [PATCH] :Added group reporting to du > >>>> > >>>> --- > >>>> NEWS | 2 + > >>>> doc/coreutils.texi | 5 ++ > >>>> src/du.c | 175 ++++++++++++++++++++++++++++++ > ++++++++++++++++++++--- > >>>> 3 files changed, 173 insertions(+), 9 deletions(-) > >>>> > >>>> diff --git a/NEWS b/NEWS > >>>> index 8a9e09e..97ccc2c 100644 > >>>> --- a/NEWS > >>>> +++ b/NEWS > >>>> @@ -56,6 +56,8 @@ GNU coreutils NEWS > >>>> -*- outline -*- > >>>> > >>>> timeout now supports the --verbose option to diagnose forced > termination. > >>>> > >>>> + du now supports the -g option for group reporting > >>>> + > >>>> ** Improvements > >>>> > >>>> dd now supports iflag=direct with arbitrary sized files on all > file systems. > >>>> diff --git a/doc/coreutils.texi b/doc/coreutils.texi > >>>> index cdde136..d220012 100644 > >>>> --- a/doc/coreutils.texi > >>>> +++ b/doc/coreutils.texi > >>>> @@ -11910,6 +11910,11 @@ is at level 0, so @code{du --max-depth=0} is > >>>> equivalent to @code{du -s}. > >>>> @c --files0-from=FILE > >>>> @filesZeroFromOption{du,, with the @option{--total} (@option{-c}) > option} > >>>> > >>>> +@item -g > >>>> +@opindex -g > >>>> +@cindex group reporting > >>>> +Show group subtotals for each item reported on. > >>>> + > >>>> @item -H > >>>> @opindex -H > >>>> Equivalent to @option{--dereference-args} (@option{-D}). > >>>> diff --git a/src/du.c b/src/du.c > >>>> index ac4489f..a8318ca 100644 > >>>> --- a/src/du.c > >>>> +++ b/src/du.c > >>>> @@ -35,6 +35,7 @@ > >>>> #include "error.h" > >>>> #include "exclude.h" > >>>> #include "fprintftime.h" > >>>> +#include "grp.h" > >>>> #include "human.h" > >>>> #include "mountlist.h" > >>>> #include "quote.h" > >>>> @@ -61,6 +62,9 @@ extern bool fts_debug; > >>>> # define FTS_CROSS_CHECK(Fts) > >>>> #endif > >>>> > >>>> +/* If true, display group size info. */ > >>>> +bool opt_group_sizes = false; > >>>> + > >>>> /* A set of dev/ino pairs to help identify files and directories > >>>> whose sizes have already been counted. */ > >>>> static struct di_set *di_files; > >>>> @@ -80,7 +84,7 @@ struct duinfo > >>>> > >>>> /* Number of inodes in directory. */ > >>>> uintmax_t inodes; > >>>> - > >>>> + uintmax_t *group_size; > >>>> /* Latest timestamp found. If tmax.tv_sec == TYPE_MINIMUM (time_t) > >>>> && tmax.tv_nsec < 0, no timestamp has been found. */ > >>>> struct timespec tmax; > >>>> @@ -90,28 +94,62 @@ struct duinfo > >>>> static inline void > >>>> duinfo_init (struct duinfo *a) > >>>> { > >>>> + uintmax_t i = 0; > >>>> a->size = 0; > >>>> a->inodes = 0; > >>>> a->tmax.tv_sec = TYPE_MINIMUM (time_t); > >>>> a->tmax.tv_nsec = -1; > >>>> + if (opt_group_sizes) > >>>> + { > >>>> + for (i=0; i<65535; i++) > >>>> + { > >>>> + a->group_size[i] = 0; > >>>> + } > >>>> + } > >>>> } > >>>> > >>>> /* Set directory data. */ > >>>> static inline void > >>>> -duinfo_set (struct duinfo *a, uintmax_t size, struct timespec tmax) > >>>> +duinfo_set (struct duinfo *a, uintmax_t size, struct timespec tmax, > >>>> uintmax_t gid) > >>>> { > >>>> + uintmax_t gid_u = (uintmax_t)gid; > >>>> + uintmax_t gid_s; > >>>> a->size = size; > >>>> a->inodes = 1; > >>>> a->tmax = tmax; > >>>> + if (opt_group_sizes) > >>>> + { > >>>> + if (gid_u > 65534) > >>>> + { > >>>> + gid_s = 65534; > >>>> + } > >>>> + else > >>>> + { > >>>> + gid_s = gid_u; > >>>> + } > >>>> + if (gid_s >=0 && gid_s <=65534) > >>>> + { > >>>> + a->group_size[gid_s] = size; > >>>> + } > >>>> + } > >>>> } > >>>> > >>>> /* Accumulate directory data. */ > >>>> static inline void > >>>> duinfo_add (struct duinfo *a, struct duinfo const *b) > >>>> { > >>>> + uintmax_t i = 0; > >>>> uintmax_t sum = a->size + b->size; > >>>> a->size = a->size <= sum ? sum : UINTMAX_MAX; > >>>> a->inodes = a->inodes + b->inodes; > >>>> + if (opt_group_sizes) > >>>> + { > >>>> + for (i=0; i<65535; i++) > >>>> + { > >>>> + sum = a->group_size[i] + b->group_size[i]; > >>>> + a->group_size[i] = a->group_size[i] <= sum ? sum : > UINTMAX_MAX; > >>>> + } > >>>> + } > >>>> if (timespec_cmp (a->tmax, b->tmax) < 0) > >>>> a->tmax = b->tmax; > >>>> } > >>>> @@ -226,6 +264,7 @@ static struct option const long_options[] = > >>>> {"exclude", required_argument, NULL, EXCLUDE_OPTION}, > >>>> {"exclude-from", required_argument, NULL, 'X'}, > >>>> {"files0-from", required_argument, NULL, FILES0_FROM_OPTION}, > >>>> + {"group-reporting", no_argument, NULL, 'g'}, > >>>> {"human-readable", no_argument, NULL, 'h'}, > >>>> {"inodes", no_argument, NULL, INODES_OPTION}, > >>>> {"si", no_argument, NULL, HUMAN_SI_OPTION}, > >>>> @@ -317,6 +356,7 @@ Summarize disk usage of the set of FILEs, > >>>> recursively for directories.\n\ > >>>> --files0-from=F summarize disk usage of the\n\ > >>>> NUL-terminated file names specified in > file F;\n\ > >>>> if F is -, then read names from standard > input\n\ > >>>> + -g, --group-reporting also print group subtotals\n\ > >>>> -H equivalent to --dereference-args (-D)\n\ > >>>> -h, --human-readable print sizes in human readable format (e.g., > >>>> 1K 234M 2G)\ > >>>> \n\ > >>>> @@ -411,7 +451,24 @@ print_size (const struct duinfo *pdui, const > char *string) > >>>> print_only_size (opt_inodes > >>>> ? pdui->inodes > >>>> : pdui->size); > >>>> - > >>>> + if (opt_group_sizes) > >>>> + { > >>>> + uintmax_t i=0; > >>>> + struct group *g; > >>>> + for (i=0; i<65535; i++){ > >>>> + if (pdui->group_size[i] > 0) > >>>> + { > >>>> + g = getgrgid(i); > >>>> + printf (","); > >>>> + if (g == NULL){ > >>>> + printf (" %Ld:", (long long unsigned int)i); > >>>> + }else{ > >>>> + printf(" %s:", g->gr_name); > >>>> + } > >>>> + print_only_size(pdui->group_size[i]); > >>>> + } > >>>> + } > >>>> + } > >>>> if (opt_time) > >>>> { > >>>> putchar ('\t'); > >>>> @@ -506,6 +563,12 @@ process_file (FTS *fts, FTSENT *ent) > >>>> const struct stat *sb = ent->fts_statp; > >>>> int info = ent->fts_info; > >>>> > >>>> + if(opt_group_sizes) > >>>> + { > >>>> + dui.group_size = xcalloc (65536, sizeof (uintmax_t)); > >>>> + dui_to_print.group_size = xcalloc (65536, sizeof (uintmax_t)); > >>>> + } > >>>> + > >>>> if (info == FTS_DNR) > >>>> { > >>>> /* An error occurred, but the size is known, so count it. */ > >>>> @@ -530,7 +593,18 @@ process_file (FTS *fts, FTSENT *ent) > >>>> if (info == FTS_NS || info == FTS_SLNONE) > >>>> { > >>>> error (0, ent->fts_errno, _("cannot access %s"), > quoteaf (file)); > >>>> - return false; > >>>> + if(opt_group_sizes) > >>>> + { > >>>> + if (dui.group_size != NULL) > >>>> + { > >>>> + free(dui.group_size); > >>>> + } > >>>> + if (dui_to_print.group_size != NULL) > >>>> + { > >>>> + free(dui_to_print.group_size); > >>>> + } > >>>> + } > >>>> + return false; > >>>> } > >>>> > >>>> /* The --one-file-system (-x) option cannot exclude > anything > >>>> @@ -558,13 +632,34 @@ process_file (FTS *fts, FTSENT *ent) > >>>> FTSENT const *e = fts_read (fts); > >>>> assert (e == ent); > >>>> } > >>>> - > >>>> + if(opt_group_sizes) > >>>> + { > >>>> + if (dui.group_size != NULL) > >>>> + { > >>>> + free(dui.group_size); > >>>> + } > >>>> + if (dui_to_print.group_size != NULL) > >>>> + { > >>>> + free(dui_to_print.group_size); > >>>> + } > >>>> + } > >>>> return true; > >>>> } > >>>> > >>>> switch (info) > >>>> { > >>>> case FTS_D: > >>>> + if(opt_group_sizes) > >>>> + { > >>>> + if (dui.group_size != NULL) > >>>> + { > >>>> + free(dui.group_size); > >>>> + } > >>>> + if (dui_to_print.group_size != NULL) > >>>> + { > >>>> + free(dui_to_print.group_size); > >>>> + } > >>>> + } > >>>> return true; > >>>> > >>>> case FTS_ERR: > >>>> @@ -574,6 +669,17 @@ process_file (FTS *fts, FTSENT *ent) > >>>> break; > >>>> > >>>> case FTS_DC: > >>>> + if(opt_group_sizes) > >>>> + { > >>>> + if (dui.group_size != NULL) > >>>> + { > >>>> + free(dui.group_size); > >>>> + } > >>>> + if (dui_to_print.group_size != NULL) > >>>> + { > >>>> + free(dui_to_print.group_size); > >>>> + } > >>>> + } > >>>> /* If not following symlinks and not a (bind) mount > point. */ > >>>> if (cycle_warning_required (fts, ent) > >>>> && ! mount_point_in_fts_cycle (ent)) > >>>> @@ -591,15 +697,40 @@ process_file (FTS *fts, FTSENT *ent) > >>>> : (uintmax_t) ST_NBLOCKS (*sb) * ST_NBLOCKSIZE), > >>>> (time_type == time_mtime ? get_stat_mtime (sb) > >>>> : time_type == time_atime ? get_stat_atime (sb) > >>>> - : get_stat_ctime (sb))); > >>>> + : get_stat_ctime (sb)), > >>>> + sb->st_gid); > >>>> > >>>> level = ent->fts_level; > >>>> - dui_to_print = dui; > >>>> + > >>>> + if (opt_group_sizes) > >>>> + { > >>>> + duinfo_set (&dui_to_print, > >>>> + (apparent_size > >>>> + ? MAX (0, sb->st_size) > >>>> + : (uintmax_t) ST_NBLOCKS (*sb) * ST_NBLOCKSIZE), > >>>> + (time_type == time_mtime ? get_stat_mtime (sb) > >>>> + : time_type == time_atime ? get_stat_atime (sb) > >>>> + : get_stat_ctime (sb)), > >>>> + sb->st_gid); > >>>> + } > >>>> + else > >>>> + { > >>>> + dui_to_print = dui; > >>>> + } > >>>> > >>>> if (n_alloc == 0) > >>>> { > >>>> + size_t i; > >>>> n_alloc = level + 10; > >>>> dulvl = xcalloc (n_alloc, sizeof *dulvl); > >>>> + if(opt_group_sizes) > >>>> + { > >>>> + for (i=0; i<n_alloc; i++) > >>>> + { > >>>> + dulvl[i].ent.group_size = xcalloc (65536, sizeof > (uintmax_t)); > >>>> + dulvl[i].subdir.group_size = xcalloc (65536, sizeof > (uintmax_t)); > >>>> + } > >>>> + } > >>>> } > >>>> else > >>>> { > >>>> @@ -613,14 +744,23 @@ process_file (FTS *fts, FTSENT *ent) > >>>> Clear the accumulators for *all* levels between > prev_level > >>>> and the current one. The depth may change dramatically, > >>>> e.g., from 1 to 10. */ > >>>> + size_t i; > >>>> > >>>> if (n_alloc <= level) > >>>> { > >>>> dulvl = xnrealloc (dulvl, level, 2 * sizeof *dulvl); > >>>> + if(opt_group_sizes) > >>>> + { > >>>> + for (i=n_alloc; i<level*2; i++) > >>>> + { > >>>> + dulvl[i].ent.group_size = xcalloc (65536, > >>>> sizeof (uintmax_t)); > >>>> + dulvl[i].subdir.group_size = xcalloc (65536, > >>>> sizeof (uintmax_t)); > >>>> + } > >>>> + } > >>>> n_alloc = level * 2; > >>>> } > >>>> > >>>> - for (size_t i = prev_level + 1; i <= level; i++) > >>>> + for (i = prev_level + 1; i <= level; i++) > >>>> { > >>>> duinfo_init (&dulvl[i].ent); > >>>> duinfo_init (&dulvl[i].subdir); > >>>> @@ -666,6 +806,18 @@ process_file (FTS *fts, FTSENT *ent) > >>>> print_size (&dui_to_print, file); > >>>> } > >>>> > >>>> + if(opt_group_sizes) > >>>> + { > >>>> + if (dui.group_size != NULL) > >>>> + { > >>>> + free(dui.group_size); > >>>> + } > >>>> + if (dui_to_print.group_size != NULL) > >>>> + { > >>>> + free(dui_to_print.group_size); > >>>> + } > >>>> + } > >>>> + > >>>> return ok; > >>>> } > >>>> > >>>> @@ -755,7 +907,7 @@ main (int argc, char **argv) > >>>> while (true) > >>>> { > >>>> int oi = -1; > >>>> - int c = getopt_long (argc, argv, "0abd:chHklmst:xB:DLPSX:", > >>>> + int c = getopt_long (argc, argv, "0abgd:chHklmst:xB:DLPSX:", > >>>> long_options, &oi); > >>>> if (c == -1) > >>>> break; > >>>> @@ -800,6 +952,11 @@ main (int argc, char **argv) > >>>> output_block_size = 1; > >>>> break; > >>>> > >>>> + case 'g': > >>>> + tot_dui.group_size = xcalloc (65536, sizeof (uintmax_t)); > >>>> + opt_group_sizes = true; > >>>> + break; > >>>> + > >>>> case 'k': > >>>> human_output_opts = 0; > >>>> output_block_size = 1024; > >>>> -- > >>>> 2.10.2 > >>>> > >>>> On Mon, Feb 5, 2018 at 10:14 AM, Daniel Gall <daniel.r.g...@gmail.com> > wrote: > >>>>> Thanks. Will resubmit without it. > >>>>> > >>>>> Sent from my iPhone > >>>>> > >>>>>> On Feb 5, 2018, at 9:20 AM, Eric Blake <ebl...@redhat.com> wrote: > >>>>>> > >>>>>>> On 02/02/2018 09:27 PM, Daniel Gall wrote: > >>>>>>> Sorry for the delay; life intervened. In addition to the feature > add, > >>>>>>> I found a place where du was calling xcalloc and did not check that > >>>>>>> the returned pointer was not NULL. I added a check. > >>>>>> > >>>>>> Wrong; the contract of xcalloc() is that it CAN'T return NULL (it > will > >>>>>> have abort()ed instead, if you are low on memory). > >>>>>> > >>>>>>>> From 544c581654cd0dcfb363215801245a7c2dd3fcd3 Mon Sep 17 > 00:00:00 2001 > >>>>>>> From: Daniel Gall <daniel.r.g...@gmail.com> > >>>>>>> Date: Fri, 2 Feb 2018 17:18:44 -0500 > >>>>>>> Subject: [PATCH] added du group reporting feature and fixed a bug > where du > >>>>>>> allocated memory and did not check that the target pointer was not > NULL after > >>>>>>> the allocation call. > >>>>>> > >>>>>> Too long of a subject line; the best commits include a one-line > summary > >>>>>> (~60 characters or less), then a blank line, then more details. > >>>>>> > >>>>>>> +++ b/NEWS > >>>>>>> @@ -32,6 +32,8 @@ GNU coreutils NEWS > >>>>>>> -*- outline -*- > >>>>>>> df no longer hangs when given a fifo argument. > >>>>>>> [bug introduced in coreutils-7.3] > >>>>>>> > >>>>>>> + du no longer allocates memory without checking whether the > >>>>>>> allocation call succeeded. > >>>>>> > >>>>>> This change is not needed, as it was not a bug in the first place. > >>>>>> > >>>>>> -- > >>>>>> Eric Blake, Principal Software Engineer > >>>>>> Red Hat, Inc. +1-919-301-3266 > >>>>>> Virtualization: qemu.org | libvirt.org > >>>>>> >