1f08c3bdfSopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 2f08c3bdfSopenharmony_ci/* 3f08c3bdfSopenharmony_ci * Copyright (c) 2019-2021 FUJITSU LIMITED. All rights reserved. 4f08c3bdfSopenharmony_ci * Author: Yang Xu <xuyang2018.jy@fujitsu.com> 5f08c3bdfSopenharmony_ci */ 6f08c3bdfSopenharmony_ci 7f08c3bdfSopenharmony_ci/*\ 8f08c3bdfSopenharmony_ci * [Description] 9f08c3bdfSopenharmony_ci * 10f08c3bdfSopenharmony_ci * Tests basic error handling of the quotactl syscall with visible quota files 11f08c3bdfSopenharmony_ci * (cover two formats, vfsv0 and vfsv1): 12f08c3bdfSopenharmony_ci * 13f08c3bdfSopenharmony_ci * - EACCES when cmd is Q_QUOTAON and addr existed but not a regular file 14f08c3bdfSopenharmony_ci * - ENOENT when the file specified by special or addr does not exist 15f08c3bdfSopenharmony_ci * - EBUSY when cmd is Q_QUOTAON and another Q_QUOTAON had already been 16f08c3bdfSopenharmony_ci * performed 17f08c3bdfSopenharmony_ci * - EFAULT when addr or special is invalid 18f08c3bdfSopenharmony_ci * - EINVAL when cmd or type is invalid 19f08c3bdfSopenharmony_ci * - ENOTBLK when special is not a block device 20f08c3bdfSopenharmony_ci * - ESRCH when no disk quota is found for the indicated user and quotas have 21f08c3bdfSopenharmony_ci * not been turned on for this fs 22f08c3bdfSopenharmony_ci * - ESRCH when cmd is Q_QUOTAON, but the quota format was not found 23f08c3bdfSopenharmony_ci * - ESRCH when cmd is Q_GETNEXTQUOTA, but there is no ID greater than or 24f08c3bdfSopenharmony_ci * equal to id that has an active quota 25f08c3bdfSopenharmony_ci * - ERANGE when cmd is Q_SETQUOTA, but the specified limits are out of the 26f08c3bdfSopenharmony_ci * range allowed by the quota format 27f08c3bdfSopenharmony_ci * - EPERM when the caller lacked the required privilege (CAP_SYS_ADMIN) for 28f08c3bdfSopenharmony_ci * the specified operation 29f08c3bdfSopenharmony_ci * 30f08c3bdfSopenharmony_ci * For ERANGE error, the vfsv0 and vfsv1 format's maximum quota limit setting 31f08c3bdfSopenharmony_ci * have been fixed since the following kernel patch: 32f08c3bdfSopenharmony_ci * 33f08c3bdfSopenharmony_ci * commit 7e08da50cf706151f324349f9235ebd311226997 34f08c3bdfSopenharmony_ci * Author: Jan Kara <jack@suse.cz> 35f08c3bdfSopenharmony_ci * Date: Wed Mar 4 14:42:02 2015 +0100 36f08c3bdfSopenharmony_ci * 37f08c3bdfSopenharmony_ci * quota: Fix maximum quota limit settings 38f08c3bdfSopenharmony_ci */ 39f08c3bdfSopenharmony_ci 40f08c3bdfSopenharmony_ci#include <errno.h> 41f08c3bdfSopenharmony_ci#include <sys/quota.h> 42f08c3bdfSopenharmony_ci#include "tst_test.h" 43f08c3bdfSopenharmony_ci#include "quotactl_fmt_var.h" 44f08c3bdfSopenharmony_ci#include "tst_capability.h" 45f08c3bdfSopenharmony_ci 46f08c3bdfSopenharmony_ci#define OPTION_INVALID 999 47f08c3bdfSopenharmony_ci#define USRPATH MNTPOINT "/aquota.user" 48f08c3bdfSopenharmony_ci#define MNTPOINT "mntpoint" 49f08c3bdfSopenharmony_ci#define TESTDIR1 MNTPOINT "/testdir1" 50f08c3bdfSopenharmony_ci#define TESTDIR2 MNTPOINT "/testdir2" 51f08c3bdfSopenharmony_ci 52f08c3bdfSopenharmony_cistatic char usrpath[] = USRPATH; 53f08c3bdfSopenharmony_cistatic char testdir1[] = TESTDIR1; 54f08c3bdfSopenharmony_cistatic char testdir2[] = TESTDIR2; 55f08c3bdfSopenharmony_cistatic int32_t fmt_id; 56f08c3bdfSopenharmony_cistatic int32_t fmt_invalid = 999; 57f08c3bdfSopenharmony_cistatic int test_invalid = 1; 58f08c3bdfSopenharmony_cistatic int test_id; 59f08c3bdfSopenharmony_cistatic int getnextquota_nsup; 60f08c3bdfSopenharmony_ci 61f08c3bdfSopenharmony_cistatic struct if_nextdqblk res_ndq; 62f08c3bdfSopenharmony_cistatic struct dqblk set_dq = { 63f08c3bdfSopenharmony_ci .dqb_bsoftlimit = 100, 64f08c3bdfSopenharmony_ci .dqb_valid = QIF_BLIMITS 65f08c3bdfSopenharmony_ci}; 66f08c3bdfSopenharmony_ci 67f08c3bdfSopenharmony_cistatic struct dqblk set_dqmax = { 68f08c3bdfSopenharmony_ci .dqb_bsoftlimit = 0x7fffffffffffffffLL, /* 2^63-1 */ 69f08c3bdfSopenharmony_ci .dqb_valid = QIF_BLIMITS 70f08c3bdfSopenharmony_ci}; 71f08c3bdfSopenharmony_ci 72f08c3bdfSopenharmony_cistatic struct tst_cap dropadmin = { 73f08c3bdfSopenharmony_ci .action = TST_CAP_DROP, 74f08c3bdfSopenharmony_ci .id = CAP_SYS_ADMIN, 75f08c3bdfSopenharmony_ci .name = "CAP_SYS_ADMIN", 76f08c3bdfSopenharmony_ci}; 77f08c3bdfSopenharmony_ci 78f08c3bdfSopenharmony_cistatic struct tst_cap needadmin = { 79f08c3bdfSopenharmony_ci .action = TST_CAP_REQ, 80f08c3bdfSopenharmony_ci .id = CAP_SYS_ADMIN, 81f08c3bdfSopenharmony_ci .name = "CAP_SYS_ADMIN", 82f08c3bdfSopenharmony_ci}; 83f08c3bdfSopenharmony_ci 84f08c3bdfSopenharmony_cistatic struct tcase { 85f08c3bdfSopenharmony_ci int cmd; 86f08c3bdfSopenharmony_ci int *id; 87f08c3bdfSopenharmony_ci void *addr; 88f08c3bdfSopenharmony_ci int exp_err; 89f08c3bdfSopenharmony_ci int on_flag; 90f08c3bdfSopenharmony_ci char *des; 91f08c3bdfSopenharmony_ci} tcases[] = { 92f08c3bdfSopenharmony_ci {QCMD(Q_QUOTAON, USRQUOTA), &fmt_id, testdir1, EACCES, 0, 93f08c3bdfSopenharmony_ci "EACCES when cmd is Q_QUOTAON and addr existed but not a regular file"}, 94f08c3bdfSopenharmony_ci 95f08c3bdfSopenharmony_ci {QCMD(Q_QUOTAON, USRQUOTA), &fmt_id, testdir2, ENOENT, 0, 96f08c3bdfSopenharmony_ci "ENOENT when the file specified by special or addr does not exist"}, 97f08c3bdfSopenharmony_ci 98f08c3bdfSopenharmony_ci {QCMD(Q_QUOTAON, USRQUOTA), &fmt_id, usrpath, EBUSY, 1, 99f08c3bdfSopenharmony_ci "EBUSY when cmd is Q_QUOTAON and another Q_QUOTAON had already been performed"}, 100f08c3bdfSopenharmony_ci 101f08c3bdfSopenharmony_ci {QCMD(Q_SETQUOTA, USRQUOTA), &fmt_id, NULL, EFAULT, 1, 102f08c3bdfSopenharmony_ci "EFAULT when addr or special is invalid"}, 103f08c3bdfSopenharmony_ci 104f08c3bdfSopenharmony_ci {QCMD(OPTION_INVALID, USRQUOTA), &fmt_id, usrpath, EINVAL, 0, 105f08c3bdfSopenharmony_ci "EINVAL when cmd or type is invalid"}, 106f08c3bdfSopenharmony_ci 107f08c3bdfSopenharmony_ci {QCMD(Q_QUOTAON, USRQUOTA), &fmt_id, usrpath, ENOTBLK, 0, 108f08c3bdfSopenharmony_ci "ENOTBLK when special is not a block device"}, 109f08c3bdfSopenharmony_ci 110f08c3bdfSopenharmony_ci {QCMD(Q_SETQUOTA, USRQUOTA), &test_id, &set_dq, ESRCH, 0, 111f08c3bdfSopenharmony_ci "ESRCH is for Q_SETQUOTA but no quota found for the user or quotas are off"}, 112f08c3bdfSopenharmony_ci 113f08c3bdfSopenharmony_ci {QCMD(Q_QUOTAON, USRQUOTA), &fmt_invalid, usrpath, ESRCH, 0, 114f08c3bdfSopenharmony_ci "ESRCH when cmd is Q_QUOTAON, but the quota format was not found"}, 115f08c3bdfSopenharmony_ci 116f08c3bdfSopenharmony_ci {QCMD(Q_GETNEXTQUOTA, USRQUOTA), &test_invalid, usrpath, ESRCH, 0, 117f08c3bdfSopenharmony_ci "ESRCH for Q_GETNEXTQUOTA, but the id was last one"}, 118f08c3bdfSopenharmony_ci 119f08c3bdfSopenharmony_ci {QCMD(Q_SETQUOTA, USRQUOTA), &test_id, &set_dqmax, ERANGE, 1, 120f08c3bdfSopenharmony_ci "ERANGE for Q_SETQUOTA, but the specified limits are out of range"}, 121f08c3bdfSopenharmony_ci 122f08c3bdfSopenharmony_ci {QCMD(Q_QUOTAON, USRQUOTA), &fmt_id, usrpath, EPERM, 0, 123f08c3bdfSopenharmony_ci "EPERM when the caller lacks the required privilege (CAP_SYS_ADMIN)"}, 124f08c3bdfSopenharmony_ci}; 125f08c3bdfSopenharmony_ci 126f08c3bdfSopenharmony_cistatic void verify_quotactl(unsigned int n) 127f08c3bdfSopenharmony_ci{ 128f08c3bdfSopenharmony_ci struct tcase *tc = &tcases[n]; 129f08c3bdfSopenharmony_ci int quota_on = 0; 130f08c3bdfSopenharmony_ci int drop_flag = 0; 131f08c3bdfSopenharmony_ci 132f08c3bdfSopenharmony_ci tst_res(TINFO, "Testing %s", tc->des); 133f08c3bdfSopenharmony_ci if (tc->cmd == QCMD(Q_GETNEXTQUOTA, USRQUOTA) && getnextquota_nsup) { 134f08c3bdfSopenharmony_ci tst_res(TCONF, "current system doesn't support Q_GETNEXTQUOTA"); 135f08c3bdfSopenharmony_ci return; 136f08c3bdfSopenharmony_ci } 137f08c3bdfSopenharmony_ci 138f08c3bdfSopenharmony_ci if (tc->on_flag) { 139f08c3bdfSopenharmony_ci TST_EXP_PASS_SILENT(quotactl(QCMD(Q_QUOTAON, USRQUOTA), 140f08c3bdfSopenharmony_ci tst_device->dev, fmt_id, usrpath), 141f08c3bdfSopenharmony_ci "quotactl with Q_QUOTAON"); 142f08c3bdfSopenharmony_ci 143f08c3bdfSopenharmony_ci if (!TST_PASS) 144f08c3bdfSopenharmony_ci return; 145f08c3bdfSopenharmony_ci 146f08c3bdfSopenharmony_ci quota_on = 1; 147f08c3bdfSopenharmony_ci } 148f08c3bdfSopenharmony_ci 149f08c3bdfSopenharmony_ci if (tc->exp_err == EPERM) { 150f08c3bdfSopenharmony_ci tst_cap_action(&dropadmin); 151f08c3bdfSopenharmony_ci drop_flag = 1; 152f08c3bdfSopenharmony_ci } 153f08c3bdfSopenharmony_ci 154f08c3bdfSopenharmony_ci if (tc->exp_err == ENOTBLK) { 155f08c3bdfSopenharmony_ci TST_EXP_FAIL(quotactl(tc->cmd, "/dev/null", *tc->id, tc->addr), 156f08c3bdfSopenharmony_ci ENOTBLK, "quotactl()"); 157f08c3bdfSopenharmony_ci } else { 158f08c3bdfSopenharmony_ci TST_EXP_FAIL(quotactl(tc->cmd, tst_device->dev, *tc->id, 159f08c3bdfSopenharmony_ci tc->addr), tc->exp_err, "quotactl()"); 160f08c3bdfSopenharmony_ci } 161f08c3bdfSopenharmony_ci 162f08c3bdfSopenharmony_ci if (quota_on) { 163f08c3bdfSopenharmony_ci TST_EXP_PASS_SILENT(quotactl(QCMD(Q_QUOTAOFF, USRQUOTA), 164f08c3bdfSopenharmony_ci tst_device->dev, fmt_id, usrpath), 165f08c3bdfSopenharmony_ci "quotactl with Q_QUOTAOFF"); 166f08c3bdfSopenharmony_ci 167f08c3bdfSopenharmony_ci if (!TST_PASS) 168f08c3bdfSopenharmony_ci return; 169f08c3bdfSopenharmony_ci } 170f08c3bdfSopenharmony_ci 171f08c3bdfSopenharmony_ci if (drop_flag) 172f08c3bdfSopenharmony_ci tst_cap_action(&needadmin); 173f08c3bdfSopenharmony_ci} 174f08c3bdfSopenharmony_ci 175f08c3bdfSopenharmony_cistatic void setup(void) 176f08c3bdfSopenharmony_ci{ 177f08c3bdfSopenharmony_ci unsigned int i; 178f08c3bdfSopenharmony_ci const struct quotactl_fmt_variant *var = &fmt_variants[tst_variant]; 179f08c3bdfSopenharmony_ci const char *const cmd[] = { 180f08c3bdfSopenharmony_ci "quotacheck", "-ugF", var->fmt_name, MNTPOINT, NULL 181f08c3bdfSopenharmony_ci }; 182f08c3bdfSopenharmony_ci 183f08c3bdfSopenharmony_ci tst_res(TINFO, "quotactl() with %s format", var->fmt_name); 184f08c3bdfSopenharmony_ci SAFE_CMD(cmd, NULL, NULL); 185f08c3bdfSopenharmony_ci fmt_id = var->fmt_id; 186f08c3bdfSopenharmony_ci /* vfsv0 block limit 2^42, vfsv1 block limit 2^63 - 1 */ 187f08c3bdfSopenharmony_ci set_dqmax.dqb_bsoftlimit = tst_variant ? 0x20000000000000 : 0x100000000; 188f08c3bdfSopenharmony_ci 189f08c3bdfSopenharmony_ci SAFE_ACCESS(USRPATH, F_OK); 190f08c3bdfSopenharmony_ci 191f08c3bdfSopenharmony_ci SAFE_MKDIR(TESTDIR1, 0666); 192f08c3bdfSopenharmony_ci 193f08c3bdfSopenharmony_ci TEST(quotactl(QCMD(Q_GETNEXTQUOTA, USRQUOTA), tst_device->dev, 194f08c3bdfSopenharmony_ci test_id, (void *) &res_ndq)); 195f08c3bdfSopenharmony_ci if (TST_ERR == EINVAL || TST_ERR == ENOSYS) 196f08c3bdfSopenharmony_ci getnextquota_nsup = 1; 197f08c3bdfSopenharmony_ci 198f08c3bdfSopenharmony_ci for (i = 0; i < ARRAY_SIZE(tcases); i++) { 199f08c3bdfSopenharmony_ci if (!tcases[i].addr) 200f08c3bdfSopenharmony_ci tcases[i].addr = tst_get_bad_addr(NULL); 201f08c3bdfSopenharmony_ci } 202f08c3bdfSopenharmony_ci} 203f08c3bdfSopenharmony_ci 204f08c3bdfSopenharmony_cistatic void cleanup(void) 205f08c3bdfSopenharmony_ci{ 206f08c3bdfSopenharmony_ci if (!access(USRPATH, F_OK)) 207f08c3bdfSopenharmony_ci SAFE_UNLINK(USRPATH); 208f08c3bdfSopenharmony_ci 209f08c3bdfSopenharmony_ci if (!access(TESTDIR1, F_OK)) 210f08c3bdfSopenharmony_ci SAFE_RMDIR(TESTDIR1); 211f08c3bdfSopenharmony_ci} 212f08c3bdfSopenharmony_ci 213f08c3bdfSopenharmony_cistatic struct tst_test test = { 214f08c3bdfSopenharmony_ci .setup = setup, 215f08c3bdfSopenharmony_ci .cleanup = cleanup, 216f08c3bdfSopenharmony_ci .needs_drivers = (const char *const []) { 217f08c3bdfSopenharmony_ci "quota_v2", 218f08c3bdfSopenharmony_ci NULL 219f08c3bdfSopenharmony_ci }, 220f08c3bdfSopenharmony_ci .tcnt = ARRAY_SIZE(tcases), 221f08c3bdfSopenharmony_ci .test = verify_quotactl, 222f08c3bdfSopenharmony_ci .dev_fs_type = "ext4", 223f08c3bdfSopenharmony_ci .mntpoint = MNTPOINT, 224f08c3bdfSopenharmony_ci .mount_device = 1, 225f08c3bdfSopenharmony_ci .mnt_data = "usrquota", 226f08c3bdfSopenharmony_ci .needs_cmds = (const char *const []) { 227f08c3bdfSopenharmony_ci "quotacheck", 228f08c3bdfSopenharmony_ci NULL 229f08c3bdfSopenharmony_ci }, 230f08c3bdfSopenharmony_ci .needs_root = 1, 231f08c3bdfSopenharmony_ci .test_variants = QUOTACTL_FMT_VARIANTS, 232f08c3bdfSopenharmony_ci .tags = (const struct tst_tag[]) { 233f08c3bdfSopenharmony_ci {"linux-git", "7e08da50cf70"}, 234f08c3bdfSopenharmony_ci {} 235f08c3bdfSopenharmony_ci } 236f08c3bdfSopenharmony_ci}; 237