log-writes: Add support to output human readable flags
[xfstests-dev.git] / src / test-nextquota.c
1 /*
2  * Copyright (c) 2016 Red Hat, Inc.
3  * All Rights Reserved.
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License as
7  * published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope that it would be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write the Free Software Foundation,
16  * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17  */
18 #include <stdlib.h>
19 #include <stdio.h>
20 #include <string.h>
21 #include <sys/quota.h>
22 #include <sys/types.h>
23 #include <xfs/xqm.h>
24
25 /*
26  * Exercise the Q_GETNEXTQUOTA and Q_XGETNEXTQUOTA quotactls.
27  * Really only returns a bare minimum of quota information,
28  * just enough to be sure we got a sane answer back.
29  *
30  * These quotactls take a quota ID as input, and return the
31  * next active quota >= that ID.
32  *
33  * usage:
34  *      test-nextquota [-v] -[u|g|p] -i id -d device
35  */
36
37 #ifndef PRJQUOTA
38 #define PRJQUOTA 2
39 #endif
40
41 #ifndef Q_GETNEXTQUOTA
42 #define Q_GETNEXTQUOTA 0x800009        /* get disk limits and usage >= ID */
43 #endif
44
45 /* glibc 2.24 defines Q_GETNEXTQUOTA but not struct nextdqblk. */
46 struct test_nextdqblk
47   {
48     u_int64_t dqb_bhardlimit;   /* absolute limit on disk quota blocks alloc */
49     u_int64_t dqb_bsoftlimit;   /* preferred limit on disk quota blocks */
50     u_int64_t dqb_curspace;     /* current quota block count */
51     u_int64_t dqb_ihardlimit;   /* maximum # allocated inodes */
52     u_int64_t dqb_isoftlimit;   /* preferred inode limit */
53     u_int64_t dqb_curinodes;    /* current # allocated inodes */
54     u_int64_t dqb_btime;        /* time limit for excessive disk use */
55     u_int64_t dqb_itime;        /* time limit for excessive files */
56     u_int32_t dqb_valid;        /* bitmask of QIF_* constants */
57     u_int32_t dqb_id;           /* id for this quota info*/
58   };
59
60 #ifndef Q_XGETNEXTQUOTA
61 #define Q_XGETNEXTQUOTA XQM_CMD(9)
62 #endif
63
64 void usage(char *progname)
65 {
66         printf("usage: %s [-v] -[u|g|p] -i id -d device\n", progname);
67         exit(1);
68 }
69
70 int main(int argc, char *argv[])
71 {
72         int c;
73         int cmd;
74         int type = -1, typeflag = 0;
75         int verbose = 0;
76         int retval = 0;
77         uint id = 0, idflag = 0;
78         char *device = NULL;
79         char *tmp;
80         struct test_nextdqblk dqb;
81         struct fs_disk_quota xqb;
82
83         while ((c = getopt(argc,argv,"ugpi:d:v")) != EOF) {
84                 switch (c) {
85                 case 'u':
86                         type = USRQUOTA;
87                         typeflag++;
88                         break;
89                 case 'g':
90                         type = GRPQUOTA;
91                         typeflag++;
92                         break;
93                 case 'p':
94                         type = PRJQUOTA;
95                         typeflag++;
96                         break;
97                 case 'i':
98                         id = (uint) strtoul(optarg, &tmp, 0);
99                         if (*tmp) {
100                                 fprintf(stderr, "Bad id: %s\n", optarg);
101                                 exit(1);
102                         }
103                         idflag++;
104                         break;
105                 case 'd':
106                         device = optarg;
107                         break;
108                 case 'v':
109                         verbose++;
110                         break;
111                 default:
112                         usage(argv[0]);
113                 }
114         }
115
116         if (idflag == 0) {
117                 printf("No id specified\n");
118                 usage(argv[0]);
119         }
120         if (typeflag == 0) {
121                 printf("No type specified\n");
122                 usage(argv[0]);
123         }
124         if (typeflag > 1) {
125                 printf("Multiple types specified\n");
126                 usage(argv[0]);
127         }
128         if (device == NULL) {
129                 printf("No device specified\n");
130                 usage(argv[0]);
131         }
132
133         if (verbose)
134                 printf("asking for quota type %d for id %u on %s\n", type, id, device);
135
136         memset(&dqb, 0, sizeof(struct test_nextdqblk));
137         memset(&xqb, 0, sizeof(struct fs_disk_quota));
138
139         if (verbose)
140                 printf("====Q_GETNEXTQUOTA====\n");
141         cmd = QCMD(Q_GETNEXTQUOTA, type);
142         if (quotactl(cmd, device, id, (void *)&dqb) < 0) {
143                 perror("Q_GETNEXTQUOTA");
144                 retval = 1;
145         } else {
146                 /*
147                  * We only print id and inode limits because
148                  * block count varies depending on fs block size, etc;
149                  * this is just a sanity test that we can retrieve the quota,
150                  * and inode limits have the same units across both calls.
151                  */
152                 printf("id        %u\n", dqb.dqb_id);
153                 printf("ihard     %llu\n",
154                                   (unsigned long long)dqb.dqb_ihardlimit);
155                 printf("isoft     %llu\n",
156                                   (unsigned long long)dqb.dqb_isoftlimit);
157         }
158
159         if (verbose)
160                 printf("====Q_XGETNEXTQUOTA====\n");
161         cmd = QCMD(Q_XGETNEXTQUOTA, USRQUOTA);
162         if (quotactl(cmd, device, id, (void *)&xqb) < 0) {
163                 perror("Q_XGETNEXTQUOTA");
164                 retval = 1;
165         } else {
166                 printf("id        %u\n", xqb.d_id);
167                 printf("ihard     %llu\n", xqb.d_ino_hardlimit);
168                 printf("isoft     %llu\n", xqb.d_ino_softlimit);
169         }
170
171         return retval;
172 }