]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - io/bulkstat.c
libfrog: convert fsgeom.c functions to negative error codes
[thirdparty/xfsprogs-dev.git] / io / bulkstat.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3 * Copyright (C) 2019 Oracle. All Rights Reserved.
4 * Author: Darrick J. Wong <darrick.wong@oracle.com>
5 */
6 #include "xfs.h"
7 #include "platform_defs.h"
8 #include "command.h"
9 #include "init.h"
10 #include "libfrog/logging.h"
11 #include "libfrog/fsgeom.h"
12 #include "libfrog/bulkstat.h"
13 #include "libfrog/paths.h"
14 #include "io.h"
15 #include "input.h"
16
17 static void
18 dump_bulkstat_time(
19 const char *tag,
20 uint64_t sec,
21 uint32_t nsec)
22 {
23 printf("\t%s = %"PRIu64".%"PRIu32"\n", tag, sec, nsec);
24 }
25
26 static void
27 dump_bulkstat(
28 struct xfs_bulkstat *bstat)
29 {
30 printf("bs_ino = %"PRIu64"\n", bstat->bs_ino);
31 printf("\tbs_size = %"PRIu64"\n", bstat->bs_size);
32
33 printf("\tbs_blocks = %"PRIu64"\n", bstat->bs_blocks);
34 printf("\tbs_xflags = 0x%"PRIx64"\n", bstat->bs_xflags);
35
36 dump_bulkstat_time("bs_atime", bstat->bs_atime, bstat->bs_atime_nsec);
37 dump_bulkstat_time("bs_ctime", bstat->bs_ctime, bstat->bs_ctime_nsec);
38 dump_bulkstat_time("bs_mtime", bstat->bs_mtime, bstat->bs_mtime_nsec);
39 dump_bulkstat_time("bs_btime", bstat->bs_btime, bstat->bs_btime_nsec);
40
41 printf("\tbs_gen = 0x%"PRIx32"\n", bstat->bs_gen);
42 printf("\tbs_uid = %"PRIu32"\n", bstat->bs_uid);
43 printf("\tbs_gid = %"PRIu32"\n", bstat->bs_gid);
44 printf("\tbs_projectid = %"PRIu32"\n", bstat->bs_projectid);
45
46 printf("\tbs_blksize = %"PRIu32"\n", bstat->bs_blksize);
47 printf("\tbs_rdev = %"PRIu32"\n", bstat->bs_rdev);
48 printf("\tbs_cowextsize_blks = %"PRIu32"\n", bstat->bs_cowextsize_blks);
49 printf("\tbs_extsize_blks = %"PRIu32"\n", bstat->bs_extsize_blks);
50
51 printf("\tbs_nlink = %"PRIu32"\n", bstat->bs_nlink);
52 printf("\tbs_extents = %"PRIu32"\n", bstat->bs_extents);
53 printf("\tbs_aextents = %"PRIu32"\n", bstat->bs_aextents);
54 printf("\tbs_version = %"PRIu16"\n", bstat->bs_version);
55 printf("\tbs_forkoff = %"PRIu16"\n", bstat->bs_forkoff);
56
57 printf("\tbs_sick = 0x%"PRIx16"\n", bstat->bs_sick);
58 printf("\tbs_checked = 0x%"PRIx16"\n", bstat->bs_checked);
59 printf("\tbs_mode = 0%"PRIo16"\n", bstat->bs_mode);
60 };
61
62 static void
63 bulkstat_help(void)
64 {
65 printf(_(
66 "Bulk-queries the filesystem for inode stat information and prints it.\n"
67 "\n"
68 " -a <agno> Only iterate this AG.\n"
69 " -d Print debugging output.\n"
70 " -e <ino> Stop after this inode.\n"
71 " -n <nr> Ask for this many results at once.\n"
72 " -s <ino> Inode to start with.\n"
73 " -v <ver> Use this version of the ioctl (1 or 5).\n"));
74 }
75
76 static void
77 set_xfd_flags(
78 struct xfs_fd *xfd,
79 uint32_t ver)
80 {
81 switch (ver) {
82 case 1:
83 xfd->flags |= XFROG_FLAG_BULKSTAT_FORCE_V1;
84 break;
85 case 5:
86 xfd->flags |= XFROG_FLAG_BULKSTAT_FORCE_V5;
87 break;
88 default:
89 break;
90 }
91 }
92
93 static int
94 bulkstat_f(
95 int argc,
96 char **argv)
97 {
98 struct xfs_fd xfd = XFS_FD_INIT(file->fd);
99 struct xfs_bulkstat_req *breq;
100 uint64_t startino = 0;
101 uint64_t endino = -1ULL;
102 uint32_t batch_size = 4096;
103 uint32_t agno = 0;
104 uint32_t ver = 0;
105 bool has_agno = false;
106 bool debug = false;
107 unsigned int i;
108 int c;
109 int ret;
110
111 while ((c = getopt(argc, argv, "a:de:n:s:v:")) != -1) {
112 switch (c) {
113 case 'a':
114 agno = cvt_u32(optarg, 10);
115 if (errno) {
116 perror(optarg);
117 return 1;
118 }
119 has_agno = true;
120 break;
121 case 'd':
122 debug = true;
123 break;
124 case 'e':
125 endino = cvt_u64(optarg, 10);
126 if (errno) {
127 perror(optarg);
128 return 1;
129 }
130 break;
131 case 'n':
132 batch_size = cvt_u32(optarg, 10);
133 if (errno) {
134 perror(optarg);
135 return 1;
136 }
137 break;
138 case 's':
139 startino = cvt_u64(optarg, 10);
140 if (errno) {
141 perror(optarg);
142 return 1;
143 }
144 break;
145 case 'v':
146 ver = cvt_u32(optarg, 10);
147 if (errno) {
148 perror(optarg);
149 return 1;
150 }
151 if (ver != 1 && ver != 5) {
152 fprintf(stderr, "version must be 1 or 5.\n");
153 return 1;
154 }
155 break;
156 default:
157 bulkstat_help();
158 return 0;
159 }
160 }
161 if (optind != argc) {
162 bulkstat_help();
163 return 0;
164 }
165
166 ret = -xfd_prepare_geometry(&xfd);
167 if (ret) {
168 xfrog_perror(ret, "xfd_prepare_geometry");
169 exitcode = 1;
170 return 0;
171 }
172
173 breq = xfrog_bulkstat_alloc_req(batch_size, startino);
174 if (!breq) {
175 perror("alloc bulkreq");
176 exitcode = 1;
177 return 0;
178 }
179
180 if (has_agno)
181 xfrog_bulkstat_set_ag(breq, agno);
182
183 set_xfd_flags(&xfd, ver);
184
185 while ((ret = xfrog_bulkstat(&xfd, breq)) == 0) {
186 if (debug)
187 printf(
188 _("bulkstat: startino=%lld flags=0x%x agno=%u ret=%d icount=%u ocount=%u\n"),
189 (long long)breq->hdr.ino,
190 (unsigned int)breq->hdr.flags,
191 (unsigned int)breq->hdr.agno,
192 ret,
193 (unsigned int)breq->hdr.icount,
194 (unsigned int)breq->hdr.ocount);
195 if (breq->hdr.ocount == 0)
196 break;
197
198 for (i = 0; i < breq->hdr.ocount; i++) {
199 if (breq->bulkstat[i].bs_ino > endino)
200 break;
201 dump_bulkstat(&breq->bulkstat[i]);
202 }
203 }
204 if (ret) {
205 xfrog_perror(ret, "xfrog_bulkstat");
206 exitcode = 1;
207 }
208
209 free(breq);
210 return 0;
211 }
212
213 static void
214 bulkstat_single_help(void)
215 {
216 printf(_(
217 "Queries the filesystem for a single inode's stat information and prints it.\n"
218 "If a given inode is not allocated, information about the next allocated \n"
219 "inode will be printed instead.\n"
220 "\n"
221 " -v (ver) Use this version of the ioctl (1 or 5).\n"
222 " -d Print debugging information.\n"
223 "\n"
224 "Pass in inode numbers or a special inode name:\n"
225 " root Root directory.\n"));
226 }
227
228 struct single_map {
229 const char *tag;
230 uint64_t code;
231 };
232
233 struct single_map tags[] = {
234 {"root", XFS_BULK_IREQ_SPECIAL_ROOT},
235 {NULL, 0},
236 };
237
238 static int
239 bulkstat_single_f(
240 int argc,
241 char **argv)
242 {
243 struct xfs_fd xfd = XFS_FD_INIT(file->fd);
244 struct xfs_bulkstat bulkstat;
245 unsigned long ver = 0;
246 unsigned int i;
247 bool debug = false;
248 int c;
249 int ret;
250
251 while ((c = getopt(argc, argv, "dv:")) != -1) {
252 switch (c) {
253 case 'd':
254 debug = true;
255 break;
256 case 'v':
257 errno = 0;
258 ver = strtoull(optarg, NULL, 10);
259 if (errno) {
260 perror(optarg);
261 return 1;
262 }
263 if (ver != 1 && ver != 5) {
264 fprintf(stderr, "version must be 1 or 5.\n");
265 return 1;
266 }
267 break;
268 default:
269 bulkstat_single_help();
270 return 0;
271 }
272 }
273
274 ret = -xfd_prepare_geometry(&xfd);
275 if (ret) {
276 xfrog_perror(ret, "xfd_prepare_geometry");
277 exitcode = 1;
278 return 0;
279 }
280
281 set_xfd_flags(&xfd, ver);
282
283 for (i = optind; i < argc; i++) {
284 struct single_map *sm = tags;
285 uint64_t ino;
286 unsigned int flags = 0;
287
288 /* Try to look up our tag... */
289 for (sm = tags; sm->tag; sm++) {
290 if (!strcmp(argv[i], sm->tag)) {
291 ino = sm->code;
292 flags |= XFS_BULK_IREQ_SPECIAL;
293 break;
294 }
295 }
296
297 /* ...or else it's an inode number. */
298 if (sm->tag == NULL) {
299 errno = 0;
300 ino = strtoull(argv[i], NULL, 10);
301 if (errno) {
302 perror(argv[i]);
303 exitcode = 1;
304 return 0;
305 }
306 }
307
308 ret = xfrog_bulkstat_single(&xfd, ino, flags, &bulkstat);
309 if (ret) {
310 xfrog_perror(ret, "xfrog_bulkstat_single");
311 continue;
312 }
313
314 if (debug)
315 printf(
316 _("bulkstat_single: startino=%"PRIu64" flags=0x%"PRIx32" ret=%d\n"),
317 ino, flags, ret);
318
319 dump_bulkstat(&bulkstat);
320 }
321
322 return 0;
323 }
324
325 static void
326 dump_inumbers(
327 struct xfs_inumbers *inumbers)
328 {
329 printf("xi_startino = %"PRIu64"\n", inumbers->xi_startino);
330 printf("\txi_allocmask = 0x%"PRIx64"\n", inumbers->xi_allocmask);
331 printf("\txi_alloccount = %"PRIu8"\n", inumbers->xi_alloccount);
332 printf("\txi_version = %"PRIu8"\n", inumbers->xi_version);
333 }
334
335 static void
336 inumbers_help(void)
337 {
338 printf(_(
339 "Queries the filesystem for inode group information and prints it.\n"
340 "\n"
341 " -a <agno> Only iterate this AG.\n"
342 " -d Print debugging output.\n"
343 " -e <ino> Stop after this inode.\n"
344 " -n <nr> Ask for this many results at once.\n"
345 " -s <ino> Inode to start with.\n"
346 " -v <ver> Use this version of the ioctl (1 or 5).\n"));
347 }
348
349 static int
350 inumbers_f(
351 int argc,
352 char **argv)
353 {
354 struct xfs_fd xfd = XFS_FD_INIT(file->fd);
355 struct xfs_inumbers_req *ireq;
356 uint64_t startino = 0;
357 uint64_t endino = -1ULL;
358 uint32_t batch_size = 4096;
359 uint32_t agno = 0;
360 uint32_t ver = 0;
361 bool has_agno = false;
362 bool debug = false;
363 unsigned int i;
364 int c;
365 int ret;
366
367 while ((c = getopt(argc, argv, "a:de:n:s:v:")) != -1) {
368 switch (c) {
369 case 'a':
370 agno = cvt_u32(optarg, 10);
371 if (errno) {
372 perror(optarg);
373 return 1;
374 }
375 has_agno = true;
376 break;
377 case 'd':
378 debug = true;
379 break;
380 case 'e':
381 endino = cvt_u64(optarg, 10);
382 if (errno) {
383 perror(optarg);
384 return 1;
385 }
386 break;
387 case 'n':
388 batch_size = cvt_u32(optarg, 10);
389 if (errno) {
390 perror(optarg);
391 return 1;
392 }
393 break;
394 case 's':
395 startino = cvt_u64(optarg, 10);
396 if (errno) {
397 perror(optarg);
398 return 1;
399 }
400 break;
401 case 'v':
402 ver = cvt_u32(optarg, 10);
403 if (errno) {
404 perror(optarg);
405 return 1;
406 }
407 if (ver != 1 && ver != 5) {
408 fprintf(stderr, "version must be 1 or 5.\n");
409 return 1;
410 }
411 break;
412 default:
413 bulkstat_help();
414 return 0;
415 }
416 }
417 if (optind != argc) {
418 bulkstat_help();
419 return 0;
420 }
421
422 ret = -xfd_prepare_geometry(&xfd);
423 if (ret) {
424 xfrog_perror(ret, "xfd_prepare_geometry");
425 exitcode = 1;
426 return 0;
427 }
428
429 ireq = xfrog_inumbers_alloc_req(batch_size, startino);
430 if (!ireq) {
431 perror("alloc inumbersreq");
432 exitcode = 1;
433 return 0;
434 }
435
436 if (has_agno)
437 xfrog_inumbers_set_ag(ireq, agno);
438
439 set_xfd_flags(&xfd, ver);
440
441 while ((ret = xfrog_inumbers(&xfd, ireq)) == 0) {
442 if (debug)
443 printf(
444 _("bulkstat: startino=%"PRIu64" flags=0x%"PRIx32" agno=%"PRIu32" ret=%d icount=%"PRIu32" ocount=%"PRIu32"\n"),
445 ireq->hdr.ino,
446 ireq->hdr.flags,
447 ireq->hdr.agno,
448 ret,
449 ireq->hdr.icount,
450 ireq->hdr.ocount);
451 if (ireq->hdr.ocount == 0)
452 break;
453
454 for (i = 0; i < ireq->hdr.ocount; i++) {
455 if (ireq->inumbers[i].xi_startino > endino)
456 break;
457 dump_inumbers(&ireq->inumbers[i]);
458 }
459 }
460 if (ret) {
461 xfrog_perror(ret, "xfrog_inumbers");
462 exitcode = 1;
463 }
464
465 free(ireq);
466 return 0;
467 }
468
469 static cmdinfo_t bulkstat_cmd = {
470 .name = "bulkstat",
471 .cfunc = bulkstat_f,
472 .argmin = 0,
473 .argmax = -1,
474 .flags = CMD_NOMAP_OK | CMD_FLAG_ONESHOT,
475 .help = bulkstat_help,
476 };
477
478 static cmdinfo_t bulkstat_single_cmd = {
479 .name = "bulkstat_single",
480 .cfunc = bulkstat_single_f,
481 .argmin = 1,
482 .argmax = -1,
483 .flags = CMD_NOMAP_OK | CMD_FLAG_ONESHOT,
484 .help = bulkstat_single_help,
485 };
486
487 static cmdinfo_t inumbers_cmd = {
488 .name = "inumbers",
489 .cfunc = inumbers_f,
490 .argmin = 0,
491 .argmax = -1,
492 .flags = CMD_NOMAP_OK | CMD_FLAG_ONESHOT,
493 .help = inumbers_help,
494 };
495
496 void
497 bulkstat_init(void)
498 {
499 bulkstat_cmd.args =
500 _("[-a agno] [-d] [-e endino] [-n batchsize] [-s startino] [-v version]");
501 bulkstat_cmd.oneline = _("Bulk stat of inodes in a filesystem");
502
503 bulkstat_single_cmd.args = _("[-d] [-v version] inum...");
504 bulkstat_single_cmd.oneline = _("Stat one inode in a filesystem");
505
506 inumbers_cmd.args =
507 _("[-a agno] [-d] [-e endino] [-n batchsize] [-s startino] [-v version]");
508 inumbers_cmd.oneline = _("Query inode groups in a filesystem");
509
510 add_command(&bulkstat_cmd);
511 add_command(&bulkstat_single_cmd);
512 add_command(&inumbers_cmd);
513 }