| // SPDX-License-Identifier: GPL-2.0 |
| /* |
| * Copyright (c) 2016 Red Hat, Inc. |
| * All Rights Reserved. |
| */ |
| #include <stdlib.h> |
| #include <stdio.h> |
| #include <string.h> |
| #include <sys/quota.h> |
| #include <sys/types.h> |
| #include <xfs/xqm.h> |
| |
| /* |
| * Exercise the Q_GETNEXTQUOTA and Q_XGETNEXTQUOTA quotactls. |
| * Really only returns a bare minimum of quota information, |
| * just enough to be sure we got a sane answer back. |
| * |
| * These quotactls take a quota ID as input, and return the |
| * next active quota >= that ID. |
| * |
| * usage: |
| * test-nextquota [-v] -[u|g|p] -i id -d device |
| */ |
| |
| #ifndef PRJQUOTA |
| #define PRJQUOTA 2 |
| #endif |
| |
| #ifndef Q_GETNEXTQUOTA |
| #define Q_GETNEXTQUOTA 0x800009 /* get disk limits and usage >= ID */ |
| #endif |
| |
| /* glibc 2.24 defines Q_GETNEXTQUOTA but not struct nextdqblk. */ |
| struct test_nextdqblk |
| { |
| u_int64_t dqb_bhardlimit; /* absolute limit on disk quota blocks alloc */ |
| u_int64_t dqb_bsoftlimit; /* preferred limit on disk quota blocks */ |
| u_int64_t dqb_curspace; /* current quota block count */ |
| u_int64_t dqb_ihardlimit; /* maximum # allocated inodes */ |
| u_int64_t dqb_isoftlimit; /* preferred inode limit */ |
| u_int64_t dqb_curinodes; /* current # allocated inodes */ |
| u_int64_t dqb_btime; /* time limit for excessive disk use */ |
| u_int64_t dqb_itime; /* time limit for excessive files */ |
| u_int32_t dqb_valid; /* bitmask of QIF_* constants */ |
| u_int32_t dqb_id; /* id for this quota info*/ |
| }; |
| |
| #ifndef Q_XGETNEXTQUOTA |
| #define Q_XGETNEXTQUOTA XQM_CMD(9) |
| #endif |
| |
| void usage(char *progname) |
| { |
| printf("usage: %s [-v] -[u|g|p] -i id -d device\n", progname); |
| exit(1); |
| } |
| |
| int main(int argc, char *argv[]) |
| { |
| int c; |
| int cmd; |
| int type = -1, typeflag = 0; |
| int verbose = 0; |
| int retval = 0; |
| uint id = 0, idflag = 0; |
| char *device = NULL; |
| char *tmp; |
| struct test_nextdqblk dqb; |
| struct fs_disk_quota xqb; |
| |
| while ((c = getopt(argc,argv,"ugpi:d:v")) != EOF) { |
| switch (c) { |
| case 'u': |
| type = USRQUOTA; |
| typeflag++; |
| break; |
| case 'g': |
| type = GRPQUOTA; |
| typeflag++; |
| break; |
| case 'p': |
| type = PRJQUOTA; |
| typeflag++; |
| break; |
| case 'i': |
| id = (uint) strtoul(optarg, &tmp, 0); |
| if (*tmp) { |
| fprintf(stderr, "Bad id: %s\n", optarg); |
| exit(1); |
| } |
| idflag++; |
| break; |
| case 'd': |
| device = optarg; |
| break; |
| case 'v': |
| verbose++; |
| break; |
| default: |
| usage(argv[0]); |
| } |
| } |
| |
| if (idflag == 0) { |
| printf("No id specified\n"); |
| usage(argv[0]); |
| } |
| if (typeflag == 0) { |
| printf("No type specified\n"); |
| usage(argv[0]); |
| } |
| if (typeflag > 1) { |
| printf("Multiple types specified\n"); |
| usage(argv[0]); |
| } |
| if (device == NULL) { |
| printf("No device specified\n"); |
| usage(argv[0]); |
| } |
| |
| if (verbose) |
| printf("asking for quota type %d for id %u on %s\n", type, id, device); |
| |
| memset(&dqb, 0, sizeof(struct test_nextdqblk)); |
| memset(&xqb, 0, sizeof(struct fs_disk_quota)); |
| |
| if (verbose) |
| printf("====Q_GETNEXTQUOTA====\n"); |
| cmd = QCMD(Q_GETNEXTQUOTA, type); |
| if (quotactl(cmd, device, id, (void *)&dqb) < 0) { |
| perror("Q_GETNEXTQUOTA"); |
| retval = 1; |
| } else { |
| /* |
| * We only print id and inode limits because |
| * block count varies depending on fs block size, etc; |
| * this is just a sanity test that we can retrieve the quota, |
| * and inode limits have the same units across both calls. |
| */ |
| printf("id %u\n", dqb.dqb_id); |
| printf("ihard %llu\n", |
| (unsigned long long)dqb.dqb_ihardlimit); |
| printf("isoft %llu\n", |
| (unsigned long long)dqb.dqb_isoftlimit); |
| } |
| |
| if (verbose) |
| printf("====Q_XGETNEXTQUOTA====\n"); |
| cmd = QCMD(Q_XGETNEXTQUOTA, USRQUOTA); |
| if (quotactl(cmd, device, id, (void *)&xqb) < 0) { |
| perror("Q_XGETNEXTQUOTA"); |
| retval = 1; |
| } else { |
| printf("id %u\n", xqb.d_id); |
| printf("ihard %llu\n", xqb.d_ino_hardlimit); |
| printf("isoft %llu\n", xqb.d_ino_softlimit); |
| } |
| |
| return retval; |
| } |