summaryrefslogtreecommitdiff
path: root/src/test-nextquota.c
blob: 9c97c99ea0764fc4154d61a53bd25c5594e4d7f3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
// 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;
}