]> git.ipfire.org Git - thirdparty/util-linux.git/blame - misc-utils/fincore.c
bash-completion: add a function for fincore command
[thirdparty/util-linux.git] / misc-utils / fincore.c
CommitLineData
a921a7de
MY
1/*
2 * fincore - count pages of file contents in core
3 *
4 * Copyright (C) 2017 Red Hat, Inc. All rights reserved.
5 * Written by Masatake YAMATO <yamato@redhat.com>
6 *
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.
11 *
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.
16 *
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.
20 */
21
22#include <sys/mman.h>
23#include <sys/stat.h>
24#include <unistd.h>
25#include <getopt.h>
26#include <stdio.h>
27#include <string.h>
28
29#include "c.h"
30#include "nls.h"
31#include "closestream.h"
32
33/* For large files, mmap is called in iterative way.
34 Window is the unit of vma prepared in each mmap
35 calling.
36
37 Window size depends on page size.
38 e.g. 128MB on x86_64. ( = N_PAGES_IN_WINDOW * 4096 ). */
39#define N_PAGES_IN_WINDOW (32 * 1024)
40
41static void __attribute__((__noreturn__)) usage(FILE *out)
42{
43 const char *p = program_invocation_short_name;
44
45 if (!*p)
46 p = "fincore";
47
48 fputs(USAGE_HEADER, out);
49 fprintf(out, _(" %s [options] file...\n"), program_invocation_short_name);
50 fputs(USAGE_OPTIONS, out);
51 fputs(USAGE_SEPARATOR, out);
52 fputs(USAGE_HELP, out);
53 fputs(USAGE_VERSION, out);
54 fprintf(out, USAGE_MAN_TAIL("fincore(1)"));
55 exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
56}
57
58static void report_count (const char *name, off_t file_size, off_t count_incore)
59{
60 printf ("%-10lu %-10lu %s\n", count_incore, file_size, name);
61}
62
63static void report_failure (const char *name)
64{
65 printf ("%-10s %-10ld %s\n", "failed", -1L, name);
66}
67
68static int do_mincore (void *window, const size_t len,
69 const char *name, const int pagesize,
70 off_t *count_incore)
71{
72 static unsigned char vec[N_PAGES_IN_WINDOW];
73 int n = (len / pagesize) + ((len % pagesize)? 1: 0);
74
75 if (mincore (window, len, vec) < 0) {
76 warn(_("failed to do mincore: %s"), name);
77 return EXIT_FAILURE;
78 }
79
80 while (n > 0)
81 {
82 if (vec[--n] & 0x1)
83 {
84 vec[n] = 0;
85 (*count_incore)++;
86 }
87 }
88
89 return EXIT_SUCCESS;
90}
91
92static int fincore_fd (int fd,
93 const char *name, const int pagesize,
94 off_t file_size,
95 off_t *count_incore)
96{
97 size_t window_size = N_PAGES_IN_WINDOW * pagesize;
98 off_t file_offset;
99 void *window = NULL;
100 int r = EXIT_SUCCESS;
101 int warned_once = 0;
102
103 for (file_offset = 0; file_offset < file_size; file_offset += window_size) {
104 size_t len;
105
106 len = file_size - file_offset;
107 if (len >= window_size)
108 len = window_size;
109
110 window = mmap(window, len, PROT_NONE, MAP_PRIVATE, fd, file_offset);
111 if (window == MAP_FAILED) {
112 if (!warned_once) {
113 r = EXIT_FAILURE;
114 warn(_("failed to do mmap: %s"), name);
115 warned_once = 1;
116 }
117 break;
118 }
119
120 if (do_mincore (window, len, name, pagesize, count_incore) != EXIT_SUCCESS)
121 r = EXIT_FAILURE;
122
123 munmap (window, len);
124 }
125
126 return r;
127}
128
129static int fincore_name (const char *name,
130 const int pagesize, struct stat *sb,
131 off_t *count_incore)
132{
133 int fd;
134 int r;
135
136 if ((fd = open (name, O_RDONLY)) < 0) {
137 warn(_("failed to open: %s"), name);
138 return EXIT_FAILURE;
139 }
140
141 if (fstat (fd, sb) < 0) {
142 warn(_("failed to do fstat: %s"), name);
143 return EXIT_FAILURE;
144 }
145
146 if (sb->st_size)
147 r = fincore_fd (fd, name, pagesize, sb->st_size, count_incore);
148 else
149 /* If the file is empty,
150 we just report this file as "successful". */
151 r = EXIT_SUCCESS;
152
153 close (fd);
154
155 return r;
156}
157
158int main(int argc, char ** argv)
159{
160 int c;
161 int pagesize;
162 int r;
163
164 static const struct option longopts[] = {
165 { "version", no_argument, NULL, 'V' },
166 { "help", no_argument, NULL, 'h' },
167 { NULL, 0, NULL, 0 },
168 };
169
170 setlocale(LC_ALL, "");
171 bindtextdomain(PACKAGE, LOCALEDIR);
172 textdomain(PACKAGE);
173 atexit(close_stdout);
174
175 while ((c = getopt_long (argc, argv, "Vh", longopts, NULL)) != -1) {
176 switch (c) {
177 case 'V':
178 printf(UTIL_LINUX_VERSION);
179 return EXIT_SUCCESS;
180 case 'h':
181 usage(stdout);
182 default:
183 errtryhelp(EXIT_FAILURE);
184 }
185 }
186
187 if (optind == argc) {
188 warnx(_("file argument is missing"));
189 usage(stderr);
190 }
191
192
193 pagesize = getpagesize();
194 r = EXIT_SUCCESS;
195 for(; optind < argc; optind++) {
196 char *name = argv[optind];
197 struct stat sb;
198 off_t count_incore = 0;
199
200 if (fincore_name (name, pagesize, &sb, &count_incore) == EXIT_SUCCESS)
201 report_count (name, sb.st_size, count_incore);
202 else {
203 report_failure (name);
204 r = EXIT_FAILURE;
205 }
206 }
207
208 return r;
209}