• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (c) Crackerjack Project., 2007
4  * Copyright (c) 2016-2019 FUJITSU LIMITED. All rights reserved
5  * Author: Xiao Yang <yangx.jy@cn.fujitsu.com>
6  *
7  * This testcase checks the basic flag of quotactl(2) for non-XFS filesystems:
8  * 1) quotactl(2) succeeds to turn on quota with Q_QUOTAON flag for user.
9  * 2) quotactl(2) succeeds to set disk quota limits with Q_SETQUOTA flag
10  *    for user.
11  * 3) quotactl(2) succeeds to get disk quota limits with Q_GETQUOTA flag
12  *    for user.
13  * 4) quotactl(2) succeeds to set information about quotafile with Q_SETINFO
14  *    flag for user.
15  * 5) quotactl(2) succeeds to get information about quotafile with Q_GETINFO
16  *    flag for user.
17  * 6) quotactl(2) succeeds to get quota format with Q_GETFMT flag for user.
18  * 7) quotactl(2) succeeds to update quota usages with Q_SYNC flag for user.
19  * 8) quotactl(2) succeeds to get disk quota limit greater than or equal to
20  *    ID with Q_GETNEXTQUOTA flag for user.
21  * 9) quotactl(2) succeeds to turn off quota with Q_QUOTAOFF flag for user.
22  * 10) quotactl(2) succeeds to turn on quota with Q_QUOTAON flag for group.
23  * 11) quotactl(2) succeeds to set disk quota limits with Q_SETQUOTA flag
24  *     for group.
25  * 12) quotactl(2) succeeds to get disk quota limits with Q_GETQUOTA flag
26  *     for group.
27  * 13) quotactl(2) succeeds to set information about quotafile with Q_SETINFO
28  *     flag for group.
29  * 14) quotactl(2) succeeds to get information about quotafile with Q_GETINFO
30  *     flag for group.
31  * 15) quotactl(2) succeeds to get quota format with Q_GETFMT flag for group.
32  * 16) quotactl(2) succeeds to update quota usages with Q_SYNC flag for group.
33  * 17) quotactl(2) succeeds to get disk quota limit greater than or equal to
34  *     ID with Q_GETNEXTQUOTA flag for group.
35  * 18) quotactl(2) succeeds to turn off quota with Q_QUOTAOFF flag for group.
36  */
37 
38 #include "config.h"
39 #include <errno.h>
40 #include <string.h>
41 #include <unistd.h>
42 #include <stdio.h>
43 #include "lapi/quotactl.h"
44 #include "tst_test.h"
45 
46 #ifndef QFMT_VFS_V0
47 # define QFMT_VFS_V0	2
48 #endif
49 #define USRPATH MNTPOINT "/aquota.user"
50 #define GRPPATH MNTPOINT "/aquota.group"
51 #define FMTID	QFMT_VFS_V0
52 #define MNTPOINT	"mntpoint"
53 
54 static int32_t fmt_id = FMTID;
55 static int test_id;
56 static struct dqblk set_dq = {
57 	.dqb_bsoftlimit = 100,
58 	.dqb_valid = QIF_BLIMITS
59 };
60 static struct dqblk res_dq;
61 
62 static struct dqinfo set_qf = {
63 	.dqi_bgrace = 80,
64 	.dqi_valid = IIF_BGRACE
65 };
66 static struct dqinfo res_qf;
67 static int32_t fmt_buf;
68 static int getnextquota_nsup;
69 
70 static struct if_nextdqblk res_ndq;
71 
72 static struct tcase {
73 	int cmd;
74 	int *id;
75 	void *addr;
76 	void *set_data;
77 	void *res_data;
78 	int sz;
79 	char *des;
80 	char *tname;
81 } tcases[] = {
82 	{QCMD(Q_QUOTAON, USRQUOTA), &fmt_id, USRPATH,
83 	NULL, NULL, 0, "turn on quota for user",
84 	"QCMD(Q_QUOTAON, USRQUOTA)"},
85 
86 	{QCMD(Q_SETQUOTA, USRQUOTA), &test_id, &set_dq,
87 	NULL, NULL, 0, "set disk quota limit for user",
88 	"QCMD(Q_SETQUOTA, USRQUOTA)"},
89 
90 	{QCMD(Q_GETQUOTA, USRQUOTA), &test_id, &res_dq,
91 	&set_dq.dqb_bsoftlimit, &res_dq.dqb_bsoftlimit,
92 	sizeof(res_dq.dqb_bsoftlimit), "get disk quota limit for user",
93 	"QCMD(Q_GETQUOTA, USRQUOTA)"},
94 
95 	{QCMD(Q_SETINFO, USRQUOTA), &test_id, &set_qf,
96 	NULL, NULL, 0, "set information about quotafile for user",
97 	"QCMD(Q_SETINFO, USRQUOTA)"},
98 
99 	{QCMD(Q_GETINFO, USRQUOTA), &test_id, &res_qf,
100 	&set_qf.dqi_bgrace, &res_qf.dqi_bgrace, sizeof(res_qf.dqi_bgrace),
101 	"get information about quotafile for user",
102 	"QCMD(Q_GETINFO, USRQUOTA)"},
103 
104 	{QCMD(Q_GETFMT, USRQUOTA), &test_id, &fmt_buf,
105 	&fmt_id, &fmt_buf, sizeof(fmt_buf),
106 	"get quota format for user",
107 	"QCMD(Q_GETFMT, USRQUOTA)"},
108 
109 	{QCMD(Q_SYNC, USRQUOTA), &test_id, &res_dq,
110 	NULL, NULL, 0, "update quota usages for user",
111 	"QCMD(Q_SYNC, USRQUOTA)"},
112 
113 	{QCMD(Q_GETNEXTQUOTA, USRQUOTA), &test_id, &res_ndq,
114 	&test_id, &res_ndq.dqb_id, sizeof(res_ndq.dqb_id),
115 	"get next disk quota limit for user",
116 	"QCMD(Q_GETNEXTQUOTA, USRQUOTA)"},
117 
118 	{QCMD(Q_QUOTAOFF, USRQUOTA), &test_id, USRPATH,
119 	NULL, NULL, 0, "turn off quota for user",
120 	"QCMD(Q_QUOTAOFF, USRQUOTA)"},
121 
122 	{QCMD(Q_QUOTAON, GRPQUOTA), &fmt_id, GRPPATH,
123 	NULL, NULL, 0, "turn on quota for group",
124 	"QCMD(Q_QUOTAON, GRPQUOTA)"},
125 
126 	{QCMD(Q_SETQUOTA, GRPQUOTA), &test_id, &set_dq,
127 	NULL, NULL, 0, "set disk quota limit for group",
128 	"QCMD(Q_SETQUOTA, GRPQUOTA)"},
129 
130 	{QCMD(Q_GETQUOTA, GRPQUOTA), &test_id, &res_dq, &set_dq.dqb_bsoftlimit,
131 	&res_dq.dqb_bsoftlimit, sizeof(res_dq.dqb_bsoftlimit),
132 	"set disk quota limit for group",
133 	"QCMD(Q_GETQUOTA, GRPQUOTA)"},
134 
135 	{QCMD(Q_SETINFO, GRPQUOTA), &test_id, &set_qf,
136 	NULL, NULL, 0, "set information about quotafile for group",
137 	"QCMD(Q_SETINFO, GRPQUOTA)"},
138 
139 	{QCMD(Q_GETINFO, GRPQUOTA), &test_id, &res_qf, &set_qf.dqi_bgrace,
140 	&res_qf.dqi_bgrace, sizeof(res_qf.dqi_bgrace),
141 	"get information about quotafile for group",
142 	"QCMD(Q_GETINFO, GRPQUOTA)"},
143 
144 	{QCMD(Q_GETFMT, GRPQUOTA), &test_id, &fmt_buf,
145 	&fmt_id, &fmt_buf, sizeof(fmt_buf), "get quota format for group",
146 	"QCMD(Q_GETFMT, GRPQUOTA)"},
147 
148 	{QCMD(Q_SYNC, GRPQUOTA), &test_id, &res_dq,
149 	NULL, NULL, 0, "update quota usages for group",
150 	"QCMD(Q_SYNC, GRPQUOTA)"},
151 
152 	{QCMD(Q_GETNEXTQUOTA, GRPQUOTA), &test_id, &res_ndq,
153 	&test_id, &res_ndq.dqb_id, sizeof(res_ndq.dqb_id),
154 	"get next disk quota limit for group",
155 	"QCMD(Q_GETNEXTQUOTA, GRPQUOTA)"},
156 
157 	{QCMD(Q_QUOTAOFF, GRPQUOTA), &test_id, GRPPATH,
158 	NULL, NULL, 0, "turn off quota for group",
159 	"QCMD(Q_QUOTAOFF, GRPQUOTA)"},
160 };
161 
setup(void)162 static void setup(void)
163 {
164 	const char *const cmd[] = {"quotacheck", "-ugF", "vfsv0", MNTPOINT, NULL};
165 	int ret;
166 
167 	ret = tst_run_cmd(cmd, NULL, NULL, 1);
168 	switch (ret) {
169 	case 0:
170 		break;
171 	case 255:
172 		tst_brk(TCONF, "quotacheck binary not installed");
173 		break;
174 	default:
175 		tst_brk(TBROK, "quotacheck exited with %i", ret);
176 	}
177 
178 	test_id = geteuid();
179 	if (access(USRPATH, F_OK) == -1)
180 		tst_brk(TFAIL | TERRNO, "user quotafile didn't exist");
181 
182 	if (access(GRPPATH, F_OK) == -1)
183 		tst_brk(TFAIL | TERRNO, "group quotafile didn't exist");
184 
185 	TEST(quotactl(QCMD(Q_GETNEXTQUOTA, USRQUOTA), tst_device->dev,
186 		test_id, (void *) &res_ndq));
187 	if (TST_ERR == EINVAL || TST_ERR == ENOSYS)
188 		getnextquota_nsup = 1;
189 }
190 
verify_quota(unsigned int n)191 static void verify_quota(unsigned int n)
192 {
193 	struct tcase *tc = &tcases[n];
194 
195 	res_dq.dqb_bsoftlimit = 0;
196 	res_qf.dqi_igrace = 0;
197 	fmt_buf = 0;
198 	res_ndq.dqb_id = -1;
199 
200 	tst_res(TINFO, "Test #%d: %s", n, tc->tname);
201 	if ((tc->cmd == QCMD(Q_GETNEXTQUOTA, USRQUOTA) ||
202 		tc->cmd == QCMD(Q_GETNEXTQUOTA, GRPQUOTA)) &&
203 		getnextquota_nsup) {
204 		tst_res(TCONF, "current system doesn't support this cmd");
205 		return;
206 	}
207 	TEST(quotactl(tc->cmd, tst_device->dev, *tc->id, tc->addr));
208 	if (TST_RET == -1) {
209 		tst_res(TFAIL | TTERRNO, "quotactl failed to %s", tc->des);
210 		return;
211 	}
212 
213 	if (memcmp(tc->res_data, tc->set_data, tc->sz)) {
214 		tst_res(TFAIL, "quotactl failed to %s", tc->des);
215 		tst_res_hexd(TINFO, tc->res_data, tc->sz, "retval:   ");
216 		tst_res_hexd(TINFO, tc->set_data, tc->sz, "expected: ");
217 		return;
218 	}
219 
220 	tst_res(TPASS, "quotactl succeeded to %s", tc->des);
221 }
222 
223 static const char *kconfigs[] = {
224 	"CONFIG_QFMT_V2",
225 	NULL
226 };
227 
228 static struct tst_test test = {
229 	.needs_root = 1,
230 	.needs_kconfigs = kconfigs,
231 	.test = verify_quota,
232 	.tcnt = ARRAY_SIZE(tcases),
233 	.mount_device = 1,
234 	.dev_fs_type = "ext4",
235 	.mntpoint = MNTPOINT,
236 	.mnt_data = "usrquota,grpquota",
237 	.setup = setup,
238 };
239