1 /*
2 * Copyright (c) 1991, 1992 Paul Kranenburg <pk@cs.few.eur.nl>
3 * Copyright (c) 1993 Branko Lankester <branko@hacktic.nl>
4 * Copyright (c) 1993, 1994, 1995, 1996 Rick Sladkey <jrs@world.std.com>
5 * Copyright (c) 1996-1999 Wichert Akkerman <wichert@cistron.nl>
6 * Copyright (c) 2005-2016 Dmitry V. Levin <ldv@strace.io>
7 * Copyright (c) 2006-2021 The strace developers.
8 * All rights reserved.
9 *
10 * SPDX-License-Identifier: LGPL-2.1-or-later
11 */
12
13 #include "defs.h"
14 #include <linux/dqblk_xfs.h>
15
16 #define SUBCMDMASK 0x00ff
17 #define SUBCMDSHIFT 8
18 #define QCMD_CMD(cmd) ((uint32_t)(cmd) >> SUBCMDSHIFT)
19 #define QCMD_TYPE(cmd) ((uint32_t)(cmd) & SUBCMDMASK)
20
21 #define OLD_CMD(cmd) ((uint32_t)(cmd) << SUBCMDSHIFT)
22 #define NEW_CMD(cmd) ((uint32_t)(cmd) | 0x800000)
23
24 #include "xlat/quotacmds.h"
25 #include "xlat/quotatypes.h"
26 #include "xlat/quota_formats.h"
27 #include "xlat/xfs_quota_flags.h"
28 #include "xlat/xfs_dqblk_flags.h"
29 #include "xlat/if_dqblk_valid.h"
30 #include "xlat/if_dqinfo_flags.h"
31 #include "xlat/if_dqinfo_valid.h"
32
33 /*
34 * We add attribute packed due to the fact that the structure is 8-byte aligned
35 * on 64-bit systems and therefore has additional 4 bytes of padding, which
36 * leads to problems when it is used on 32-bit tracee which does not have such
37 * padding.
38 */
39 struct if_dqblk {
40 uint64_t dqb_bhardlimit;
41 uint64_t dqb_bsoftlimit;
42 uint64_t dqb_curspace;
43 uint64_t dqb_ihardlimit;
44 uint64_t dqb_isoftlimit;
45 uint64_t dqb_curinodes;
46 uint64_t dqb_btime;
47 uint64_t dqb_itime;
48 uint32_t dqb_valid;
49 } ATTRIBUTE_PACKED;
50
51 struct if_nextdqblk {
52 uint64_t dqb_bhardlimit;
53 uint64_t dqb_bsoftlimit;
54 uint64_t dqb_curspace;
55 uint64_t dqb_ihardlimit;
56 uint64_t dqb_isoftlimit;
57 uint64_t dqb_curinodes;
58 uint64_t dqb_btime;
59 uint64_t dqb_itime;
60 uint32_t dqb_valid;
61 uint32_t dqb_id;
62 };
63
64 struct if_dqinfo {
65 uint64_t dqi_bgrace;
66 uint64_t dqi_igrace;
67 uint32_t dqi_flags;
68 uint32_t dqi_valid;
69 };
70
71 static void
72 print_fs_qfilestat(const struct fs_qfilestat *const p)
73 {
74 tprint_struct_begin();
75 PRINT_FIELD_U(*p, qfs_ino);
76 tprint_struct_next();
77 PRINT_FIELD_U(*p, qfs_nblks);
78 tprint_struct_next();
79 PRINT_FIELD_U(*p, qfs_nextents);
80 tprint_struct_end();
81 }
82
83 static void
84 print_fs_qfilestatv(const struct fs_qfilestatv *const p)
85 {
86 tprint_struct_begin();
87 PRINT_FIELD_U(*p, qfs_ino);
88 tprint_struct_next();
89 PRINT_FIELD_U(*p, qfs_nblks);
90 tprint_struct_next();
91 PRINT_FIELD_U(*p, qfs_nextents);
92 tprint_struct_end();
93 }
94
95 static int
96 decode_cmd_data(struct tcb *tcp, uint32_t id, uint32_t cmd, kernel_ulong_t data)
97 {
98 switch (cmd) {
99 case Q_QUOTAOFF:
100 case Q_SYNC:
101 case Q_XQUOTASYNC:
102 break;
103 case Q_QUOTAON:
104 tprint_arg_next();
105 printxval(quota_formats, id, "QFMT_VFS_???");
106 tprint_arg_next();
107 printpath(tcp, data);
108 break;
109 case Q_GETQUOTA:
110 if (entering(tcp)) {
111 tprint_arg_next();
112 printuid(id);
113 tprint_arg_next();
114
115 return 0;
116 }
117
118 ATTRIBUTE_FALLTHROUGH;
119 case Q_SETQUOTA:
120 {
121 struct if_dqblk dq;
122
123 if (entering(tcp)) {
124 tprint_arg_next();
125 printuid(id);
126 tprint_arg_next();
127 }
128
129 if (umove_or_printaddr(tcp, data, &dq))
130 break;
131 tprint_struct_begin();
132 PRINT_FIELD_U(dq, dqb_bhardlimit);
133 tprint_struct_next();
134 PRINT_FIELD_U(dq, dqb_bsoftlimit);
135 tprint_struct_next();
136 PRINT_FIELD_U(dq, dqb_curspace);
137 tprint_struct_next();
138 PRINT_FIELD_U(dq, dqb_ihardlimit);
139 tprint_struct_next();
140 PRINT_FIELD_U(dq, dqb_isoftlimit);
141 tprint_struct_next();
142 PRINT_FIELD_U(dq, dqb_curinodes);
143 if (!abbrev(tcp)) {
144 tprint_struct_next();
145 PRINT_FIELD_U(dq, dqb_btime);
146 tprint_struct_next();
147 PRINT_FIELD_U(dq, dqb_itime);
148 tprint_struct_next();
149 PRINT_FIELD_FLAGS(dq, dqb_valid,
150 if_dqblk_valid, "QIF_???");
151 } else {
152 tprint_struct_next();
153 tprint_more_data_follows();
154 }
155 tprint_struct_end();
156 break;
157 }
158 case Q_GETNEXTQUOTA:
159 {
160 struct if_nextdqblk dq;
161
162 if (entering(tcp)) {
163 tprint_arg_next();
164 printuid(id);
165 tprint_arg_next();
166
167 return 0;
168 }
169
170 if (umove_or_printaddr(tcp, data, &dq))
171 break;
172 tprint_struct_begin();
173 PRINT_FIELD_U(dq, dqb_bhardlimit);
174 tprint_struct_next();
175 PRINT_FIELD_U(dq, dqb_bsoftlimit);
176 tprint_struct_next();
177 PRINT_FIELD_U(dq, dqb_curspace);
178 tprint_struct_next();
179 PRINT_FIELD_U(dq, dqb_ihardlimit);
180 tprint_struct_next();
181 PRINT_FIELD_U(dq, dqb_isoftlimit);
182 tprint_struct_next();
183 PRINT_FIELD_U(dq, dqb_curinodes);
184 if (!abbrev(tcp)) {
185 tprint_struct_next();
186 PRINT_FIELD_U(dq, dqb_btime);
187 tprint_struct_next();
188 PRINT_FIELD_U(dq, dqb_itime);
189 tprint_struct_next();
190 PRINT_FIELD_FLAGS(dq, dqb_valid,
191 if_dqblk_valid, "QIF_???");
192 tprint_struct_next();
193 PRINT_FIELD_U(dq, dqb_id);
194 } else {
195 tprint_struct_next();
196 PRINT_FIELD_U(dq, dqb_id);
197 tprint_struct_next();
198 tprint_more_data_follows();
199 }
200 tprint_struct_end();
201 break;
202 }
203 case Q_XGETQUOTA:
204 case Q_XGETNEXTQUOTA:
205 if (entering(tcp)) {
206 tprint_arg_next();
207 printuid(id);
208 tprint_arg_next();
209
210 return 0;
211 }
212
213 ATTRIBUTE_FALLTHROUGH;
214 case Q_XSETQLIM:
215 {
216 fs_disk_quota_t dq;
217
218 if (entering(tcp)) {
219 tprint_arg_next();
220 printuid(id);
221 tprint_arg_next();
222 }
223
224 if (umove_or_printaddr(tcp, data, &dq))
225 break;
226 tprint_struct_begin();
227 PRINT_FIELD_D(dq, d_version);
228 tprint_struct_next();
229 PRINT_FIELD_FLAGS(dq, d_flags,
230 xfs_dqblk_flags, "FS_???_QUOTA");
231 tprint_struct_next();
232 PRINT_FIELD_X(dq, d_fieldmask);
233 tprint_struct_next();
234 PRINT_FIELD_U(dq, d_id);
235 tprint_struct_next();
236 PRINT_FIELD_U(dq, d_blk_hardlimit);
237 tprint_struct_next();
238 PRINT_FIELD_U(dq, d_blk_softlimit);
239 tprint_struct_next();
240 PRINT_FIELD_U(dq, d_ino_hardlimit);
241 tprint_struct_next();
242 PRINT_FIELD_U(dq, d_ino_softlimit);
243 tprint_struct_next();
244 PRINT_FIELD_U(dq, d_bcount);
245 tprint_struct_next();
246 PRINT_FIELD_U(dq, d_icount);
247 if (!abbrev(tcp)) {
248 tprint_struct_next();
249 PRINT_FIELD_D(dq, d_itimer);
250 tprint_struct_next();
251 PRINT_FIELD_D(dq, d_btimer);
252 tprint_struct_next();
253 PRINT_FIELD_U(dq, d_iwarns);
254 tprint_struct_next();
255 PRINT_FIELD_U(dq, d_bwarns);
256 tprint_struct_next();
257 PRINT_FIELD_U(dq, d_rtb_hardlimit);
258 tprint_struct_next();
259 PRINT_FIELD_U(dq, d_rtb_softlimit);
260 tprint_struct_next();
261 PRINT_FIELD_U(dq, d_rtbcount);
262 tprint_struct_next();
263 PRINT_FIELD_D(dq, d_rtbtimer);
264 tprint_struct_next();
265 PRINT_FIELD_U(dq, d_rtbwarns);
266 } else {
267 tprint_struct_next();
268 tprint_more_data_follows();
269 }
270 tprint_struct_end();
271 break;
272 }
273 case Q_GETFMT:
274 {
275 uint32_t fmt;
276
277 if (entering(tcp)) {
278 tprint_arg_next();
279
280 return 0;
281 }
282
283 if (umove_or_printaddr(tcp, data, &fmt))
284 break;
285 tprint_indirect_begin();
286 printxval(quota_formats, fmt, "QFMT_VFS_???");
287 tprint_indirect_end();
288 break;
289 }
290 case Q_GETINFO:
291 if (entering(tcp)) {
292 tprint_arg_next();
293
294 return 0;
295 }
296
297 ATTRIBUTE_FALLTHROUGH;
298 case Q_SETINFO:
299 {
300 struct if_dqinfo dq;
301
302 if (entering(tcp))
303 tprint_arg_next();
304
305 if (umove_or_printaddr(tcp, data, &dq))
306 break;
307 tprint_struct_begin();
308 PRINT_FIELD_U(dq, dqi_bgrace);
309 tprint_struct_next();
310 PRINT_FIELD_U(dq, dqi_igrace);
311 tprint_struct_next();
312 PRINT_FIELD_FLAGS(dq, dqi_flags, if_dqinfo_flags, "DQF_???");
313 tprint_struct_next();
314 PRINT_FIELD_FLAGS(dq, dqi_valid, if_dqinfo_valid, "IIF_???");
315 tprint_struct_end();
316 break;
317 }
318 case Q_XGETQSTAT:
319 {
320 fs_quota_stat_t dq;
321
322 if (entering(tcp)) {
323 tprint_arg_next();
324
325 return 0;
326 }
327 if (fetch_struct_quotastat(tcp, data, &dq)) {
328 tprint_struct_begin();
329 PRINT_FIELD_D(dq, qs_version);
330 if (!abbrev(tcp)) {
331 tprint_struct_next();
332 PRINT_FIELD_FLAGS(dq, qs_flags,
333 xfs_quota_flags, "FS_QUOTA_???");
334 tprint_struct_next();
335 PRINT_FIELD_OBJ_PTR(dq, qs_uquota,
336 print_fs_qfilestat);
337 tprint_struct_next();
338 PRINT_FIELD_OBJ_PTR(dq, qs_gquota,
339 print_fs_qfilestat);
340 tprint_struct_next();
341 PRINT_FIELD_U(dq, qs_incoredqs);
342 tprint_struct_next();
343 PRINT_FIELD_D(dq, qs_btimelimit);
344 tprint_struct_next();
345 PRINT_FIELD_D(dq, qs_itimelimit);
346 tprint_struct_next();
347 PRINT_FIELD_D(dq, qs_rtbtimelimit);
348 tprint_struct_next();
349 PRINT_FIELD_U(dq, qs_bwarnlimit);
350 tprint_struct_next();
351 PRINT_FIELD_U(dq, qs_iwarnlimit);
352 } else {
353 tprint_struct_next();
354 tprint_more_data_follows();
355 }
356 tprint_struct_end();
357 }
358 break;
359 }
360 case Q_XGETQSTATV:
361 {
362 struct fs_quota_statv dq;
363
364 if (entering(tcp)) {
365 tprint_arg_next();
366
367 return 0;
368 }
369
370 if (umove_or_printaddr(tcp, data, &dq))
371 break;
372 tprint_struct_begin();
373 PRINT_FIELD_D(dq, qs_version);
374 if (!abbrev(tcp)) {
375 tprint_struct_next();
376 PRINT_FIELD_FLAGS(dq, qs_flags,
377 xfs_quota_flags, "FS_QUOTA_???");
378 tprint_struct_next();
379 PRINT_FIELD_U(dq, qs_incoredqs);
380 tprint_struct_next();
381 PRINT_FIELD_OBJ_PTR(dq, qs_uquota,
382 print_fs_qfilestatv);
383 tprint_struct_next();
384 PRINT_FIELD_OBJ_PTR(dq, qs_gquota,
385 print_fs_qfilestatv);
386 tprint_struct_next();
387 PRINT_FIELD_OBJ_PTR(dq, qs_pquota,
388 print_fs_qfilestatv);
389 tprint_struct_next();
390 PRINT_FIELD_D(dq, qs_btimelimit);
391 tprint_struct_next();
392 PRINT_FIELD_D(dq, qs_itimelimit);
393 tprint_struct_next();
394 PRINT_FIELD_D(dq, qs_rtbtimelimit);
395 tprint_struct_next();
396 PRINT_FIELD_U(dq, qs_bwarnlimit);
397 tprint_struct_next();
398 PRINT_FIELD_U(dq, qs_iwarnlimit);
399 } else {
400 tprint_struct_next();
401 tprint_more_data_follows();
402 }
403 tprint_struct_end();
404 break;
405 }
406 case Q_XQUOTAON:
407 case Q_XQUOTAOFF:
408 {
409 uint32_t flag;
410
411 tprint_arg_next();
412
413 if (umove_or_printaddr(tcp, data, &flag))
414 break;
415 tprint_indirect_begin();
416 printflags(xfs_quota_flags, flag, "FS_QUOTA_???");
417 tprint_indirect_end();
418 break;
419 }
420 case Q_XQUOTARM:
421 {
422 uint32_t flag;
423
424 tprint_arg_next();
425
426 if (umove_or_printaddr(tcp, data, &flag))
427 break;
428 tprint_indirect_begin();
429 printflags(xfs_dqblk_flags, flag, "FS_???_QUOTA");
430 tprint_indirect_end();
431 break;
432 }
433 default:
434 tprint_arg_next();
435 printuid(id);
436 tprint_arg_next();
437 printaddr(data);
438 break;
439 }
440 return RVAL_DECODED;
441 }
442
443 static void
444 print_qcmd(const uint32_t qcmd)
445 {
446 const uint32_t cmd = QCMD_CMD(qcmd);
447 const uint32_t type = QCMD_TYPE(qcmd);
448
449 if (xlat_verbose(xlat_verbosity) != XLAT_STYLE_ABBREV)
450 PRINT_VAL_U(qcmd);
451
452 if (xlat_verbose(xlat_verbosity) == XLAT_STYLE_RAW)
453 return;
454
455 if (xlat_verbose(xlat_verbosity) == XLAT_STYLE_VERBOSE)
456 tprint_comment_begin();
457
458 tprints_arg_begin("QCMD");
459 printxvals_ex(cmd, "Q_???", XLAT_STYLE_ABBREV, quotacmds, NULL);
460 tprint_arg_next();
461 printxvals_ex(type, "???QUOTA", XLAT_STYLE_ABBREV, quotatypes, NULL);
462 tprint_arg_end();
463
464 if (xlat_verbose(xlat_verbosity) == XLAT_STYLE_VERBOSE)
465 tprint_comment_end();
466 }
467
468 SYS_FUNC(quotactl)
469 {
470 /*
471 * The Linux kernel only looks at the low 32 bits of command and id
472 * arguments, but on some 64-bit architectures (s390x) this word
473 * will have been sign-extended when we see it. The high 1 bits
474 * don't mean anything, so don't confuse the output with them.
475 */
476 uint32_t qcmd = tcp->u_arg[0];
477 uint32_t cmd = QCMD_CMD(qcmd);
478 uint32_t id = tcp->u_arg[2];
479
480 if (entering(tcp)) {
481 /* cmd */
482 print_qcmd(qcmd);
483 tprint_arg_next();
484
485 /* special */
486 printpath(tcp, tcp->u_arg[1]);
487 }
488 return decode_cmd_data(tcp, id, cmd, tcp->u_arg[3]);
489 }
490
491 SYS_FUNC(quotactl_fd)
492 {
493 const unsigned int fd = tcp->u_arg[0];
494 const unsigned int qcmd = tcp->u_arg[1];
495 const uint32_t id = tcp->u_arg[2];
496 const kernel_ulong_t addr = tcp->u_arg[3];
497
498 if (entering(tcp)) {
499 /* fd */
500 printfd(tcp, fd);
501 tprint_arg_next();
502
503 /* cmd */
504 print_qcmd(qcmd);
505 }
506
507 return decode_cmd_data(tcp, id, QCMD_CMD(qcmd), addr);
508 }