| // SPDX-License-Identifier: GPL-2.0 | |
| /* | |
| * Copyright (c) 2000-2003 Silicon Graphics, Inc. | |
| * All Rights Reserved. | |
| */ | |
| #include "global.h" | |
| #include <xfs/jdm.h> | |
| void | |
| dotime(void *ti, char *s) | |
| { | |
| char *c; | |
| xfs_bstime_t *t; | |
| t = (xfs_bstime_t *)ti; | |
| c = ctime(&t->tv_sec); | |
| printf("\t%s %19.19s.%09d %s", s, c, t->tv_nsec, c + 20); | |
| } | |
| void | |
| printbstat(struct xfs_bstat *sp) | |
| { | |
| printf("ino %lld mode %#o nlink %d uid %d gid %d rdev %#x\n", | |
| (long long)sp->bs_ino, sp->bs_mode, sp->bs_nlink, | |
| sp->bs_uid, sp->bs_gid, sp->bs_rdev); | |
| printf("\tblksize %d size %lld blocks %lld xflags %#x extsize %d\n", | |
| sp->bs_blksize, (long long)sp->bs_size, (long long)sp->bs_blocks, | |
| sp->bs_xflags, sp->bs_extsize); | |
| dotime(&sp->bs_atime, "atime"); | |
| dotime(&sp->bs_mtime, "mtime"); | |
| dotime(&sp->bs_ctime, "ctime"); | |
| printf( "\textents %d %d gen %d\n", | |
| sp->bs_extents, sp->bs_aextents, sp->bs_gen); | |
| printf( "\tDMI: event mask 0x%08x state 0x%04x\n", | |
| sp->bs_dmevmask, sp->bs_dmstate); | |
| } | |
| void | |
| printstat(struct stat64 *sp) | |
| { | |
| printf("ino %lld mode %#o nlink %d uid %d gid %d rdev %#x\n", | |
| (long long)sp->st_ino, (unsigned int)sp->st_mode, (int)sp->st_nlink, | |
| (int)sp->st_uid, (int)sp->st_gid, (int)sp->st_rdev); | |
| printf("\tblksize %llu size %lld blocks %lld\n", | |
| (unsigned long long)sp->st_blksize, (long long)sp->st_size, (long long)sp->st_blocks); | |
| dotime(&sp->st_atime, "atime"); | |
| dotime(&sp->st_mtime, "mtime"); | |
| dotime(&sp->st_ctime, "ctime"); | |
| } | |
| int | |
| main(int argc, char **argv) | |
| { | |
| __s32 count; | |
| int total = 0; | |
| int fsfd; | |
| int i; | |
| __u64 last = 0; | |
| char *name; | |
| int nent; | |
| int debug = 0; | |
| int quiet = 0; | |
| int statit = 0; | |
| int verbose = 0; | |
| struct xfs_bstat *t; | |
| int ret; | |
| jdm_fshandle_t *fshandlep = NULL; | |
| int fd; | |
| struct stat64 sb; | |
| int nread; | |
| char *cc_readlinkbufp; | |
| int cc_readlinkbufsz; | |
| int c; | |
| struct xfs_fsop_bulkreq bulkreq; | |
| while ((c = getopt(argc, argv, "cdl:qv")) != -1) { | |
| switch (c) { | |
| case 'q': | |
| quiet = 1; | |
| break; | |
| case 'v': | |
| verbose = 1; | |
| break; | |
| case 'c': | |
| statit = 1; | |
| break; | |
| case 'd': | |
| debug = 1; | |
| break; | |
| case 'l': | |
| last = atoi(optarg); | |
| break; | |
| case '?': | |
| printf("usage: xfs_bstat [-c] [-q] [-v] [ dir [ batch_size ]]\n"); | |
| printf(" -c Check the results against stat(3) output\n"); | |
| printf(" -q Quiet\n"); | |
| printf(" -l _num_ Inode to start with\n"); | |
| printf(" -v Verbose output\n"); | |
| exit(1); | |
| } | |
| } | |
| argc -= optind; | |
| argv += optind; | |
| if (argc < 1) | |
| name = "."; | |
| else | |
| name = *argv; | |
| fsfd = open(name, O_RDONLY); | |
| if (fsfd < 0) { | |
| perror(name); | |
| exit(1); | |
| } | |
| if (argc < 2) | |
| nent = 4096; | |
| else | |
| nent = atoi(*++argv); | |
| if (verbose) | |
| printf("Bulkstat test on %s, batch size=%d statcheck=%d\n", | |
| name, nent, statit); | |
| if (statit) { | |
| fshandlep = jdm_getfshandle( name ); | |
| if (! fshandlep) { | |
| printf("unable to construct sys handle for %s: %s\n", | |
| name, strerror(errno)); | |
| return -1; | |
| } | |
| } | |
| t = malloc(nent * sizeof(*t)); | |
| if (verbose) | |
| printf( | |
| "XFS_IOC_FSBULKSTAT test: last=%lld nent=%d\n", (long long)last, nent); | |
| bulkreq.lastip = &last; | |
| bulkreq.icount = nent; | |
| bulkreq.ubuffer = t; | |
| bulkreq.ocount = &count; | |
| while ((ret = xfsctl(name, fsfd, XFS_IOC_FSBULKSTAT, &bulkreq)) == 0) { | |
| total += count; | |
| if (verbose) | |
| printf( | |
| "XFS_IOC_FSBULKSTAT test: last=%lld ret=%d count=%d total=%d\n", | |
| (long long)last, ret, count, total); | |
| if (count == 0) | |
| exit(0); | |
| if ( quiet && ! statit ) | |
| continue; | |
| for (i = 0; i < count; i++) { | |
| if (! quiet) { | |
| printbstat(&t[i]); | |
| } | |
| if (statit) { | |
| switch(t[i].bs_mode & S_IFMT) { | |
| case S_IFLNK: | |
| cc_readlinkbufsz = MAXPATHLEN; | |
| cc_readlinkbufp = (char *)calloc( | |
| 1, | |
| cc_readlinkbufsz); | |
| nread = jdm_readlink( | |
| fshandlep, | |
| &t[i], | |
| cc_readlinkbufp, | |
| cc_readlinkbufsz); | |
| if (verbose && nread > 0) | |
| printf( | |
| "readlink: ino %lld: <%*s>\n", | |
| (long long)t[i].bs_ino, | |
| nread, | |
| cc_readlinkbufp); | |
| free(cc_readlinkbufp); | |
| if ( nread < 0 ) { | |
| printf( | |
| "could not read symlink ino %llu\n", | |
| (unsigned long long)t[i].bs_ino ); | |
| printbstat(&t[i]); | |
| } | |
| break; | |
| case S_IFCHR: | |
| case S_IFBLK: | |
| case S_IFIFO: | |
| case S_IFSOCK: | |
| break; | |
| case S_IFREG: | |
| case S_IFDIR: | |
| fd = jdm_open( fshandlep, &t[i], O_RDONLY); | |
| if (fd < 0) { | |
| printf( | |
| "unable to open handle ino %lld: %s\n", | |
| (long long)t[i].bs_ino, strerror(errno)); | |
| continue; | |
| } | |
| if (fstat64(fd, &sb) < 0) { | |
| printf( | |
| "unable to stat ino %lld: %s\n", | |
| (long long)t[i].bs_ino, strerror(errno)); | |
| } | |
| close(fd); | |
| /* | |
| * Don't compare blksize or blocks, | |
| * they are used differently by stat | |
| * and bstat. | |
| */ | |
| if ( (t[i].bs_ino != sb.st_ino) || | |
| (t[i].bs_mode != sb.st_mode) || | |
| (t[i].bs_nlink != sb.st_nlink) || | |
| (t[i].bs_uid != sb.st_uid) || | |
| (t[i].bs_gid != sb.st_gid) || | |
| (t[i].bs_rdev != sb.st_rdev) || | |
| (t[i].bs_size != sb.st_size) || | |
| /* (t[i].bs_blksize != sb.st_blksize) || */ | |
| (t[i].bs_mtime.tv_sec != sb.st_mtime) || | |
| (t[i].bs_ctime.tv_sec != sb.st_ctime) ) { | |
| printf("\nstat/bstat missmatch\n"); | |
| printbstat(&t[i]); | |
| printstat(&sb); | |
| } | |
| } | |
| } | |
| } | |
| if (debug) | |
| break; | |
| } | |
| if (fsfd) | |
| close(fsfd); | |
| if (ret < 0 ) | |
| perror("xfsctl(XFS_IOC_FSBULKSTAT)"); | |
| if (verbose) | |
| printf( | |
| "XFS_IOC_FSBULKSTAT test: last=%lld nent=%d ret=%d count=%d\n", | |
| (long long)last, nent, ret, count); | |
| return 1; | |
| } |