1 /*
2  * Copyright (c) 2013 Fujitsu Ltd.
3  * Author: DAN LI <li.dan@cn.fujitsu.com>
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of version 2 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, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12  *
13  * You should have received a copy of the GNU General Public License along
14  * with this program; if not, write the Free Software Foundation, Inc.,
15  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
16  */
17 
18 /*
19  * Description:
20  *	This tests basic flags of quotactl() syscall:
21  *	1) Q_XQUOTAOFF - Turn off quotas for an XFS file system.
22  *	2) Q_XQUOTAON - Turn on quotas for an XFS file system.
23  *	3) Q_XGETQUOTA - Get disk quota limits and current usage for user id.
24  *	4) Q_XSETQLIM - Set disk quota limits for user id.
25  *	5) Q_XGETQSTAT - Get XFS file system specific quota information.
26  */
27 
28 #define _GNU_SOURCE
29 #include <fcntl.h>
30 #include <unistd.h>
31 #include <sys/syscall.h>
32 #include <stdio.h>
33 #include <errno.h>
34 #include <sys/mount.h>
35 #include <linux/fs.h>
36 #include <sys/types.h>
37 
38 #include "config.h"
39 #if defined(HAVE_XFS_QUOTA)
40 # include <xfs/xqm.h>
41 #endif
42 #include "test.h"
43 #include "linux_syscall_numbers.h"
44 #include "safe_macros.h"
45 
46 #define USRQCMD(cmd)	((cmd) << 8)
47 #define RTBLIMIT	2000
48 
49 char *TCID = "quotactl02";
50 int TST_TOTAL = 5;
51 
52 #if defined(HAVE_XFS_QUOTA)
53 static void check_qoff(void);
54 static void check_qon(void);
55 static void check_getq(void);
56 static void setup_setqlim(void), check_setqlim(void);
57 static void check_getqstat(void);
58 
59 static void setup(void);
60 static void cleanup(void);
61 
62 static int i;
63 static int uid;
64 static const char *block_dev;
65 static int mount_flag;
66 static struct fs_disk_quota dquota;
67 static struct fs_quota_stat qstat;
68 static unsigned int qflag = XFS_QUOTA_UDQ_ENFD;
69 static const char mntpoint[] = "mnt_point";
70 
71 static struct test_case_t {
72 	int cmd;
73 	void *addr;
74 	void (*func_test) ();
75 	void (*func_setup) ();
76 } TC[] = {
77 	{Q_XQUOTAOFF, &qflag, check_qoff, NULL},
78 	{Q_XQUOTAON, &qflag, check_qon, NULL},
79 	{Q_XGETQUOTA, &dquota, check_getq, NULL},
80 	{Q_XSETQLIM, &dquota, check_setqlim, setup_setqlim},
81 	{Q_XGETQSTAT, &qstat, check_getqstat, NULL},
82 };
83 
main(int argc,char * argv[])84 int main(int argc, char *argv[])
85 {
86 	int lc;
87 
88 	tst_parse_opts(argc, argv, NULL, NULL);
89 
90 	setup();
91 
92 	for (lc = 0; TEST_LOOPING(lc); ++lc) {
93 
94 		tst_count = 0;
95 
96 		for (i = 0; i < TST_TOTAL; i++) {
97 
98 			if (TC[i].func_setup != NULL)
99 				(*TC[i].func_setup) ();
100 
101 			TEST(ltp_syscall(__NR_quotactl,
102 					 USRQCMD(TC[i].cmd), block_dev,
103 					 uid, TC[i].addr));
104 
105 			if (TEST_RETURN != 0)
106 				tst_resm(TFAIL | TERRNO,
107 					 "cmd=0x%x failed", TC[i].cmd);
108 
109 			(*TC[i].func_test) ();
110 		}
111 	}
112 	cleanup();
113 	tst_exit();
114 }
115 
check_qoff(void)116 static void check_qoff(void)
117 {
118 	int ret;
119 
120 	ret = ltp_syscall(__NR_quotactl, USRQCMD(Q_XGETQSTAT),
121 			  block_dev, uid, &qstat);
122 	if (ret != 0)
123 		tst_brkm(TBROK | TERRNO, cleanup, "fail to get quota stat");
124 
125 	if (qstat.qs_flags & XFS_QUOTA_UDQ_ENFD) {
126 		tst_resm(TFAIL, "enforcement is not off");
127 		return;
128 	}
129 
130 	tst_resm(TPASS, "enforcement is off");
131 }
132 
check_qon(void)133 static void check_qon(void)
134 {
135 	int ret;
136 	ret = ltp_syscall(__NR_quotactl, USRQCMD(Q_XGETQSTAT),
137 			  block_dev, uid, &qstat);
138 	if (ret != 0)
139 		tst_brkm(TBROK | TERRNO, cleanup, "fail to get quota stat");
140 
141 	if (!(qstat.qs_flags & XFS_QUOTA_UDQ_ENFD)) {
142 		tst_resm(TFAIL, "enforcement is off");
143 		return;
144 	}
145 
146 	tst_resm(TPASS, "enforcement is on");
147 }
148 
check_getq(void)149 static void check_getq(void)
150 {
151 	if (!(dquota.d_flags & XFS_USER_QUOTA)) {
152 		tst_resm(TFAIL, "get incorrect quota type");
153 		return;
154 	}
155 
156 	tst_resm(TPASS, "get the right quota type");
157 }
158 
setup_setqlim(void)159 static void setup_setqlim(void)
160 {
161 	dquota.d_rtb_hardlimit = RTBLIMIT;
162 	dquota.d_fieldmask = FS_DQ_LIMIT_MASK;
163 }
164 
check_setqlim(void)165 static void check_setqlim(void)
166 {
167 	int ret;
168 	ret = ltp_syscall(__NR_quotactl, USRQCMD(Q_XGETQUOTA),
169 			  block_dev, uid, &dquota);
170 	if (ret != 0)
171 		tst_brkm(TFAIL | TERRNO, NULL,
172 			 "fail to get quota information");
173 
174 	if (dquota.d_rtb_hardlimit != RTBLIMIT) {
175 		tst_resm(TFAIL, "limit on RTB, except %lu get %lu",
176 			 (uint64_t)RTBLIMIT,
177 			 (uint64_t)dquota.d_rtb_hardlimit);
178 		return;
179 	}
180 
181 	tst_resm(TPASS, "quotactl works fine with Q_XSETQLIM");
182 }
183 
check_getqstat(void)184 static void check_getqstat(void)
185 {
186 	if (qstat.qs_version != FS_QSTAT_VERSION) {
187 		tst_resm(TFAIL, "get incorrect qstat version");
188 		return;
189 	}
190 
191 	tst_resm(TPASS, "get correct qstat version");
192 }
193 
setup(void)194 static void setup(void)
195 {
196 
197 	tst_require_root();
198 
199 	TEST_PAUSE;
200 
201 	tst_tmpdir();
202 
203 	SAFE_MKDIR(cleanup, mntpoint, 0755);
204 
205 	block_dev = tst_acquire_device(cleanup);
206 
207 	if (!block_dev)
208 		tst_brkm(TCONF, cleanup, "Failed to obtain block device");
209 
210 	tst_mkfs(cleanup, block_dev, "xfs", NULL, NULL);
211 
212 	if (mount(block_dev, mntpoint, "xfs", 0, "uquota") < 0)
213 		tst_brkm(TFAIL | TERRNO, NULL, "mount(2) fail");
214 	mount_flag = 1;
215 }
216 
cleanup(void)217 static void cleanup(void)
218 {
219 	if (mount_flag && tst_umount(mntpoint) < 0)
220 		tst_resm(TWARN | TERRNO, "umount(2) failed");
221 
222 	if (block_dev)
223 		tst_release_device(block_dev);
224 
225 	tst_rmdir();
226 }
227 #else
main(void)228 int main(void)
229 {
230 	tst_brkm(TCONF, NULL, "This system doesn't support xfs quota");
231 }
232 #endif
233