2 * fincore - count pages of file contents in core
4 * Copyright (C) 2017 Red Hat, Inc. All rights reserved.
5 * Written by Masatake YAMATO <yamato@redhat.com>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it would be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
31 #include "closestream.h"
35 #include "libsmartcols.h"
37 /* For large files, mmap is called in iterative way.
38 Window is the unit of vma prepared in each mmap
41 Window size depends on page size.
42 e.g. 128MB on x86_64. ( = N_PAGES_IN_WINDOW * 4096 ). */
43 #define N_PAGES_IN_WINDOW (32 * 1024)
59 static struct colinfo infos
[] = {
60 [COL_PAGES
] = { "PAGES", 1, SCOLS_FL_RIGHT
, N_("number of memory page")},
61 [COL_SIZE
] = { "SIZE", 5, SCOLS_FL_RIGHT
, N_("size of the file")},
62 [COL_FILE
] = { "FILE", 4, 0, N_("file name")},
65 static int columns
[ARRAY_SIZE(infos
) * 2] = {-1};
66 static size_t ncolumns
;
68 struct fincore_control
{
71 struct libscols_table
*tb
; /* output */
73 unsigned int bytes
: 1,
80 static int column_name_to_id(const char *name
, size_t namesz
)
84 for (i
= 0; i
< ARRAY_SIZE(infos
); i
++) {
85 const char *cn
= infos
[i
].name
;
87 if (!strncasecmp(name
, cn
, namesz
) && !*(cn
+ namesz
))
90 warnx(_("unknown column: %s"), name
);
94 static int get_column_id(int num
)
97 assert((size_t) num
< ncolumns
);
98 assert(columns
[num
] < (int) ARRAY_SIZE(infos
));
102 static const struct colinfo
*get_column_info(int num
)
104 return &infos
[ get_column_id(num
) ];
107 static int add_output_data(struct fincore_control
*ctl
,
114 struct libscols_line
*ln
;
119 ln
= scols_table_new_line(ctl
->tb
, NULL
);
121 err(EXIT_FAILURE
, _("failed to initialize output line"));
123 for (i
= 0; i
< ncolumns
; i
++) {
124 switch(get_column_id(i
)) {
126 scols_line_set_data(ln
, i
, name
);
129 xasprintf(&tmp
, "%jd", (intmax_t) count_incore
);
130 scols_line_refer_data(ln
, i
, tmp
);
134 xasprintf(&tmp
, "%jd", (intmax_t) file_size
);
136 tmp
= size_to_human_string(SIZE_SUFFIX_1LETTER
, file_size
);
137 scols_line_refer_data(ln
, i
, tmp
);
147 static int do_mincore(struct fincore_control
*ctl
,
148 void *window
, const size_t len
,
152 static unsigned char vec
[N_PAGES_IN_WINDOW
];
153 int n
= (len
/ ctl
->pagesize
) + ((len
% ctl
->pagesize
)? 1: 0);
155 if (mincore (window
, len
, vec
) < 0) {
156 warn(_("failed to do mincore: %s"), name
);
172 static int fincore_fd (struct fincore_control
*ctl
,
178 size_t window_size
= N_PAGES_IN_WINDOW
* ctl
->pagesize
;
184 for (file_offset
= 0; file_offset
< file_size
; file_offset
+= window_size
) {
187 len
= file_size
- file_offset
;
188 if (len
>= window_size
)
191 window
= mmap(window
, len
, PROT_NONE
, MAP_PRIVATE
, fd
, file_offset
);
192 if (window
== MAP_FAILED
) {
195 warn(_("failed to do mmap: %s"), name
);
201 rc
= do_mincore(ctl
, window
, len
, name
, count_incore
);
205 munmap (window
, len
);
212 * Returns: <0 on error, 0 success, 1 ignore.
214 static int fincore_name(struct fincore_control
*ctl
,
222 if ((fd
= open (name
, O_RDONLY
)) < 0) {
223 warn(_("failed to open: %s"), name
);
227 if (fstat (fd
, sb
) < 0) {
228 warn(_("failed to do fstat: %s"), name
);
232 if (S_ISDIR(sb
->st_mode
))
235 else if (sb
->st_size
)
236 rc
= fincore_fd(ctl
, fd
, name
, sb
->st_size
, count_incore
);
242 static void __attribute__((__noreturn__
)) usage(FILE *out
)
246 fputs(USAGE_HEADER
, out
);
247 fprintf(out
, _(" %s [options] file...\n"), program_invocation_short_name
);
249 fputs(USAGE_OPTIONS
, out
);
250 fputs(_(" -J, --json use JSON output format\n"), out
);
251 fputs(_(" -b, --bytes print sizes in bytes rather than in human readable format\n"), out
);
252 fputs(_(" -n, --noheadings don't print headings\n"), out
);
253 fputs(_(" -o, --output <list> output columns\n"), out
);
254 fputs(_(" -r, --raw use raw output format\n"), out
);
256 fputs(USAGE_SEPARATOR
, out
);
257 fputs(USAGE_HELP
, out
);
258 fputs(USAGE_VERSION
, out
);
260 fprintf(out
, _("\nAvailable columns (for --output):\n"));
262 for (i
= 0; i
< ARRAY_SIZE(infos
); i
++)
263 fprintf(out
, " %11s %s\n", infos
[i
].name
, _(infos
[i
].help
));
265 fprintf(out
, USAGE_MAN_TAIL("fincore(1)"));
267 exit(out
== stderr
? EXIT_FAILURE
: EXIT_SUCCESS
);
270 int main(int argc
, char ** argv
)
274 int rc
= EXIT_SUCCESS
;
277 struct fincore_control ctl
= {
278 .pagesize
= getpagesize()
281 static const struct option longopts
[] = {
282 { "bytes", no_argument
, NULL
, 'b' },
283 { "noheadings", no_argument
, NULL
, 'n' },
284 { "output", required_argument
, NULL
, 'o' },
285 { "version", no_argument
, NULL
, 'V' },
286 { "help", no_argument
, NULL
, 'h' },
287 { "json", no_argument
, NULL
, 'J' },
288 { "raw", no_argument
, NULL
, 'r' },
289 { NULL
, 0, NULL
, 0 },
292 setlocale(LC_ALL
, "");
293 bindtextdomain(PACKAGE
, LOCALEDIR
);
295 atexit(close_stdout
);
297 while ((c
= getopt_long (argc
, argv
, "bno:JrVh", longopts
, NULL
)) != -1) {
315 printf(UTIL_LINUX_VERSION
);
320 errtryhelp(EXIT_FAILURE
);
324 if (optind
== argc
) {
325 warnx(_("no file specified"));
326 errtryhelp(EXIT_FAILURE
);
330 columns
[ncolumns
++] = COL_PAGES
;
331 columns
[ncolumns
++] = COL_SIZE
;
332 columns
[ncolumns
++] = COL_FILE
;
335 if (outarg
&& string_add_to_idarray(outarg
, columns
, ARRAY_SIZE(columns
),
336 &ncolumns
, column_name_to_id
) < 0)
340 ctl
.tb
= scols_new_table();
342 err(EXIT_FAILURE
, _("failed to create output table"));
344 scols_table_enable_noheadings(ctl
.tb
, ctl
.noheadings
);
345 scols_table_enable_raw(ctl
.tb
, ctl
.raw
);
346 scols_table_enable_json(ctl
.tb
, ctl
.json
);
348 scols_table_set_name(ctl
.tb
, "fincore");
350 for (i
= 0; i
< ncolumns
; i
++) {
351 const struct colinfo
*col
= get_column_info(i
);
353 if (!scols_table_new_column(ctl
.tb
, col
->name
, col
->whint
, col
->flags
))
354 err(EXIT_FAILURE
, _("failed to initialize output column"));
357 for(; optind
< argc
; optind
++) {
358 char *name
= argv
[optind
];
360 off_t count_incore
= 0;
362 switch (fincore_name(&ctl
, name
, &sb
, &count_incore
)) {
364 add_output_data(&ctl
, name
, sb
.st_size
, count_incore
);
374 scols_print_table(ctl
.tb
);
375 scols_unref_table(ctl
.tb
);