1/*
2 * Copyright (c) 2017 Fujitsu Ltd.
3 * Author: Xiao Yang <yangx.jy@cn.fujitsu.com>
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program, if not, see <http://www.gnu.org/licenses/>.
17 */
18
19/*
20 * Test Name: quotactl03
21 *
22 * Description:
23 * quotactl(2) with XGETNEXTQUOTA looks for the next active quota for an user
24 * equal or higher to a given ID, in this test the ID is specified to a value
25 * close to UINT_MAX(max value of unsigned int). When reaching the upper limit
26 * and finding no active quota, it should return -1 and set errno to ENOENT.
27 * Actually, quotactl(2) overflows and and return 0 as the "next" active id.
28 *
29 * This kernel bug of xfs has been fixed in:
30 *
31 * commit 657bdfb7f5e68ca5e2ed009ab473c429b0d6af85
32 * Author: Eric Sandeen <sandeen@redhat.com>
33 * Date:   Tue Jan 17 11:43:38 2017 -0800
34 *
35 *     xfs: don't wrap ID in xfs_dq_get_next_id
36 */
37
38#define _GNU_SOURCE
39#include <errno.h>
40#include <unistd.h>
41#include <stdio.h>
42#include <sys/quota.h>
43#include "config.h"
44
45#if defined(HAVE_QUOTAV2) || defined(HAVE_QUOTAV1)
46# include <sys/quota.h>
47#endif
48
49#if defined(HAVE_XFS_QUOTA)
50# include <xfs/xqm.h>
51#endif
52
53#include "tst_test.h"
54#include "lapi/quotactl.h"
55
56#if defined(HAVE_XFS_QUOTA) && (defined(HAVE_QUOTAV2) || defined(HAVE_QUOTAV1))
57
58static const char mntpoint[] = "mnt_point";
59static uint32_t test_id = 0xfffffffc;
60
61static void verify_quota(void)
62{
63	struct fs_disk_quota res_dquota;
64
65	res_dquota.d_id = 1;
66
67	TEST(quotactl(QCMD(Q_XGETNEXTQUOTA, USRQUOTA), tst_device->dev,
68		test_id, (void *)&res_dquota));
69	if (TEST_RETURN != -1) {
70		tst_res(TFAIL, "quotactl() found the next active ID:"
71			" %u unexpectedly", res_dquota.d_id);
72		return;
73	}
74
75	if (TEST_ERRNO == EINVAL) {
76		tst_brk(TCONF | TTERRNO,
77			"Q_XGETNEXTQUOTA wasn't supported in quotactl()");
78	}
79
80	if (TEST_ERRNO != ENOENT) {
81		tst_res(TFAIL | TTERRNO, "quotaclt() failed unexpectedly with"
82			" %s expected ENOENT", tst_strerrno(TEST_ERRNO));
83	} else {
84		tst_res(TPASS, "quotaclt() failed with ENOENT as expected");
85	}
86}
87
88static struct tst_test test = {
89	.needs_tmpdir = 1,
90	.needs_root = 1,
91	.test_all = verify_quota,
92	.mount_device = 1,
93	.dev_fs_type = "xfs",
94	.mntpoint = mntpoint,
95	.mnt_data = "usrquota",
96};
97
98#else
99	TST_TEST_TCONF("This system didn't support quota or xfs quota");
100#endif
101