2 * Check decoding of quotactl xfs subcommands.
4 * Copyright (c) 2016 Eugene Syromyatnikov <evgsyr@gmail.com>
5 * Copyright (c) 2016 Dmitry V. Levin <ldv@altlinux.org>
6 * Copyright (c) 2016-2019 The strace developers.
9 * SPDX-License-Identifier: GPL-2.0-or-later
16 #if defined(__NR_quotactl) && \
17 (defined(HAVE_LINUX_QUOTA_H) || defined(HAVE_SYS_QUOTA_H)) && \
18 defined(HAVE_LINUX_DQBLK_XFS_H)
24 # include <linux/dqblk_xfs.h>
26 # include "quotactl.h"
28 # ifndef Q_GETNEXTQUOTA
29 # define Q_XGETNEXTQUOTA XQM_CMD(0x9)
30 # endif /* !Q_GETNEXTQUOTA */
34 # define Q_XGETQSTATV XQM_CMD(8)
35 # define FS_QSTATV_VERSION1 1
37 struct fs_qfilestatv {
38 uint64_t qfs_ino; /* inode number */
39 uint64_t qfs_nblks; /* number of BBs 512-byte-blks */
40 uint32_t qfs_nextents; /* number of extents */
41 uint32_t qfs_pad; /* pad for 8-byte alignment */
44 struct fs_quota_statv {
45 int8_t qs_version; /* version for future changes */
46 uint8_t qs_pad1; /* pad for 16bit alignment */
47 uint16_t qs_flags; /* XFS_QUOTA_.* flags */
48 uint32_t qs_incoredqs; /* number of dquots incore */
49 struct fs_qfilestatv qs_uquota; /* user quota information */
50 struct fs_qfilestatv qs_gquota; /* group quota information */
51 struct fs_qfilestatv qs_pquota; /* project quota information */
52 int32_t qs_btimelimit; /* limit for blks timer */
53 int32_t qs_itimelimit; /* limit for inodes timer */
54 int32_t qs_rtbtimelimit; /* limit for rt blks timer */
55 uint16_t qs_bwarnlimit; /* limit for num warnings */
56 uint16_t qs_iwarnlimit; /* limit for num warnings */
57 uint64_t qs_pad2[8]; /* for future proofing */
60 # endif /* !Q_XGETQSTATV */
63 # include "xlat/xfs_dqblk_flags.h"
65 # include "xlat/xfs_quota_flags.h"
70 print_xdisk_quota(int rc, void *ptr, void *arg)
72 struct fs_disk_quota *dq = ptr;
73 long out_arg = (long) arg;
75 if (((rc < 0) && out_arg) || (out_arg > 1)) {
80 PRINT_FIELD_D("{", *dq, d_version);
82 printflags(xfs_dqblk_flags, (uint8_t) dq->d_flags, "XFS_???_QUOTA");
84 PRINT_FIELD_X(", ", *dq, d_fieldmask);
85 PRINT_FIELD_U(", ", *dq, d_id);
86 PRINT_FIELD_U(", ", *dq, d_blk_hardlimit);
87 PRINT_FIELD_U(", ", *dq, d_blk_softlimit);
88 PRINT_FIELD_U(", ", *dq, d_ino_hardlimit);
89 PRINT_FIELD_U(", ", *dq, d_ino_softlimit);
90 PRINT_FIELD_U(", ", *dq, d_bcount);
91 PRINT_FIELD_U(", ", *dq, d_icount);
94 PRINT_FIELD_D(", ", *dq, d_itimer);
95 PRINT_FIELD_D(", ", *dq, d_btimer);
96 PRINT_FIELD_U(", ", *dq, d_iwarns);
97 PRINT_FIELD_U(", ", *dq, d_bwarns);
98 PRINT_FIELD_U(", ", *dq, d_rtb_hardlimit);
99 PRINT_FIELD_U(", ", *dq, d_rtb_softlimit);
100 PRINT_FIELD_U(", ", *dq, d_rtbcount);
101 PRINT_FIELD_D(", ", *dq, d_rtbtimer);
102 PRINT_FIELD_U(", ", *dq, d_rtbwarns);
105 # endif /* !VERBOSE */
110 print_xquota_stat(int rc, void *ptr, void *arg)
112 struct fs_quota_stat *qs = ptr;
113 long out_arg = (long) arg;
115 if (((rc < 0) && out_arg) || (out_arg > 1)) {
120 PRINT_FIELD_D("{", *qs, qs_version);
123 printf(", qs_flags=");
124 printflags(xfs_quota_flags, qs->qs_flags, "XFS_QUOTA_???");
125 PRINT_FIELD_U(", qs_uquota={", qs->qs_uquota, qfs_ino);
126 PRINT_FIELD_U(", ", qs->qs_uquota, qfs_nblks);
127 PRINT_FIELD_U(", ", qs->qs_uquota, qfs_nextents);
128 PRINT_FIELD_U("}, qs_gquota={", qs->qs_gquota, qfs_ino);
129 PRINT_FIELD_U(", ", qs->qs_gquota, qfs_nblks);
130 PRINT_FIELD_U(", ", qs->qs_gquota, qfs_nextents);
131 PRINT_FIELD_U("}, ", *qs, qs_incoredqs);
132 PRINT_FIELD_D(", ", *qs, qs_btimelimit);
133 PRINT_FIELD_D(", ", *qs, qs_itimelimit);
134 PRINT_FIELD_D(", ", *qs, qs_rtbtimelimit);
135 PRINT_FIELD_U(", ", *qs, qs_bwarnlimit);
136 PRINT_FIELD_U(", ", *qs, qs_iwarnlimit);
139 # endif /* !VERBOSE */
144 print_xquota_statv(int rc, void *ptr, void *arg)
146 struct fs_quota_statv *qs = ptr;
147 long out_arg = (long) arg;
149 if (((rc < 0) && out_arg) || (out_arg > 1)) {
154 PRINT_FIELD_D("{", *qs, qs_version);
157 printf(", qs_flags=");
158 printflags(xfs_quota_flags, qs->qs_flags, "XFS_QUOTA_???");
159 PRINT_FIELD_U(", ", *qs, qs_incoredqs);
160 PRINT_FIELD_U(", qs_uquota={", qs->qs_uquota, qfs_ino);
161 PRINT_FIELD_U(", ", qs->qs_uquota, qfs_nblks);
162 PRINT_FIELD_U(", ", qs->qs_uquota, qfs_nextents);
163 PRINT_FIELD_U("}, qs_gquota={", qs->qs_gquota, qfs_ino);
164 PRINT_FIELD_U(", ", qs->qs_gquota, qfs_nblks);
165 PRINT_FIELD_U(", ", qs->qs_gquota, qfs_nextents);
166 PRINT_FIELD_U("}, qs_pquota={", qs->qs_pquota, qfs_ino);
167 PRINT_FIELD_U(", ", qs->qs_pquota, qfs_nblks);
168 PRINT_FIELD_U(", ", qs->qs_pquota, qfs_nextents);
169 PRINT_FIELD_D("}, ", *qs, qs_btimelimit);
170 PRINT_FIELD_D(", ", *qs, qs_itimelimit);
171 PRINT_FIELD_D(", ", *qs, qs_rtbtimelimit);
172 PRINT_FIELD_U(", ", *qs, qs_bwarnlimit);
173 PRINT_FIELD_U(", ", *qs, qs_iwarnlimit);
176 # endif /* !VERBOSE */
183 char *bogus_special = (char *) tail_alloc(1) + 1;
184 void *bogus_addr = (char *) tail_alloc(1) + 1;
186 char bogus_special_str[sizeof(void *) * 2 + sizeof("0x")];
187 char bogus_addr_str[sizeof(void *) * 2 + sizeof("0x")];
188 char unterminated_str[sizeof(void *) * 2 + sizeof("0x")];
190 static char invalid_cmd_str[1024];
191 TAIL_ALLOC_OBJECT_CONST_PTR(struct fs_disk_quota, xdq);
192 TAIL_ALLOC_OBJECT_CONST_PTR(struct fs_quota_stat, xqstat);
193 TAIL_ALLOC_OBJECT_CONST_PTR(struct fs_quota_statv, xqstatv);
194 TAIL_ALLOC_OBJECT_CONST_PTR(uint32_t, flags);
195 char *unterminated = tail_memdup(unterminated_data,
196 sizeof(unterminated_data));
198 snprintf(bogus_special_str, sizeof(bogus_special_str), "%p",
200 snprintf(bogus_addr_str, sizeof(bogus_addr_str), "%p",
202 snprintf(unterminated_str, sizeof(unterminated_str), "%p",
210 check_quota(CQF_ID_SKIP | CQF_ADDR_STR,
211 ARG_STR(QCMD(Q_XQUOTAON, USRQUOTA)),
212 ARG_STR("/dev/bogus/"), flags,
213 "[XFS_QUOTA_UDQ_ACCT|XFS_QUOTA_UDQ_ENFD"
214 "|XFS_QUOTA_GDQ_ACCT|XFS_QUOTA_GDQ_ENFD"
215 "|XFS_QUOTA_PDQ_ENFD|0xdeadbec0]");
217 snprintf(invalid_cmd_str, sizeof(invalid_cmd_str),
218 "QCMD(Q_XQUOTAON, %#x /* ???QUOTA */)",
219 QCMD_TYPE(QCMD(Q_XQUOTAON, 0xfacefeed)));
220 check_quota(CQF_ID_SKIP,
221 QCMD(Q_XQUOTAON, 0xfacefeed), invalid_cmd_str,
222 bogus_dev, bogus_dev_str, bogus_addr);
227 check_quota(CQF_ID_SKIP | CQF_ADDR_STR,
228 ARG_STR(QCMD(Q_XQUOTAOFF, USRQUOTA)),
229 bogus_special, bogus_special_str,
230 bogus_addr, bogus_addr_str);
231 check_quota(CQF_ID_SKIP | CQF_ADDR_STR,
232 ARG_STR(QCMD(Q_XQUOTAOFF, GRPQUOTA)),
233 ARG_STR("/dev/bogus/"),
235 check_quota(CQF_ID_SKIP | CQF_ADDR_STR,
236 QCMD(Q_XQUOTAOFF, 3),
237 "QCMD(Q_XQUOTAOFF, 0x3 /* ???QUOTA */)",
238 ARG_STR("/dev/bogus/"), flags,
239 "[XFS_QUOTA_UDQ_ACCT|XFS_QUOTA_UDQ_ENFD"
240 "|XFS_QUOTA_GDQ_ACCT|XFS_QUOTA_GDQ_ENFD"
241 "|XFS_QUOTA_PDQ_ENFD|0xdeadbec0]");
246 /* Trying our best to get successful result */
247 check_quota(CQF_ADDR_CB, ARG_STR(QCMD(Q_XGETQUOTA, USRQUOTA)),
248 ARG_STR("/dev/sda1"), getuid(), xdq, print_xdisk_quota,
251 check_quota(CQF_ADDR_CB, ARG_STR(QCMD(Q_XGETQUOTA, GRPQUOTA)),
252 ARG_STR(NULL), -1, xdq, print_xdisk_quota, (intptr_t) 1);
255 /* Q_XGETNEXTQUOTA */
257 check_quota(CQF_ADDR_CB, ARG_STR(QCMD(Q_XGETNEXTQUOTA, USRQUOTA)),
258 ARG_STR("/dev/sda1"), 0, xdq, print_xdisk_quota,
264 check_quota(CQF_NONE, ARG_STR(QCMD(Q_XSETQLIM, PRJQUOTA)),
265 bogus_special, bogus_special_str, 0, bogus_addr);
267 fill_memory_ex(xdq, sizeof(*xdq), 0x8e, 0x80);
269 check_quota(CQF_ADDR_CB, ARG_STR(QCMD(Q_XSETQLIM, PRJQUOTA)),
270 bogus_dev, bogus_dev_str, 3141592653U,
271 xdq, print_xdisk_quota, (intptr_t) 0);
276 check_quota(CQF_ID_SKIP | CQF_ADDR_CB,
277 ARG_STR(QCMD(Q_XGETQSTAT, USRQUOTA)),
278 ARG_STR("/dev/sda1"), xqstat, print_xquota_stat, (intptr_t) 1);
280 check_quota(CQF_ID_SKIP | CQF_ADDR_CB,
281 ARG_STR(QCMD(Q_XGETQSTAT, USRQUOTA)),
282 ARG_STR("NULL"), xqstat, print_xquota_stat, (intptr_t) 1);
284 check_quota(CQF_ID_SKIP,
285 ARG_STR(QCMD(Q_XGETQSTAT, PRJQUOTA)),
286 unterminated, unterminated_str,
292 check_quota(CQF_ID_SKIP | CQF_ADDR_CB,
293 ARG_STR(QCMD(Q_XGETQSTATV, USRQUOTA)),
294 ARG_STR("/dev/sda1"), xqstatv, print_xquota_statv, (intptr_t) 1);
296 check_quota(CQF_ID_SKIP | CQF_ADDR_CB,
297 ARG_STR(QCMD(Q_XGETQSTATV, GRPQUOTA)),
298 ARG_STR(NULL), xqstatv, print_xquota_statv, (intptr_t) 1);
300 check_quota(CQF_ID_SKIP,
301 ARG_STR(QCMD(Q_XGETQSTATV, PRJQUOTA)),
302 unterminated, unterminated_str,
308 check_quota(CQF_ID_SKIP | CQF_ADDR_STR,
309 ARG_STR(QCMD(Q_XQUOTARM, PRJQUOTA)),
310 bogus_special, bogus_special_str, ARG_STR(NULL));
311 check_quota(CQF_ID_SKIP,
312 ARG_STR(QCMD(Q_XQUOTARM, USRQUOTA)),
313 unterminated, unterminated_str, flags + 1);
316 check_quota(CQF_ID_SKIP | CQF_ADDR_STR,
317 ARG_STR(QCMD(Q_XQUOTARM, GRPQUOTA)),
318 ARG_STR(NULL), flags,
319 "[XFS_USER_QUOTA|XFS_PROJ_QUOTA"
320 "|XFS_GROUP_QUOTA|0xdeadbee8]");
325 check_quota(CQF_ID_SKIP | CQF_ADDR_SKIP,
326 ARG_STR(QCMD(Q_XQUOTASYNC, USRQUOTA)),
327 bogus_special, bogus_special_str);
328 check_quota(CQF_ID_SKIP | CQF_ADDR_SKIP,
329 QCMD(Q_XQUOTASYNC, 0xfff),
330 "QCMD(Q_XQUOTASYNC, 0xff /* ???QUOTA */)",
333 puts("+++ exited with 0 +++");
340 SKIP_MAIN_UNDEFINED("__NR_quotactl && "
341 "(HAVE_LINUX_QUOTA_H || HAVE_SYS_QUOTA_H) && "
342 "HAVE_LINUX_DQBLK_XFS_H");