Branch data Line data Source code
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@altlinux.org>
7 : : * All rights reserved.
8 : : *
9 : : * Redistribution and use in source and binary forms, with or without
10 : : * modification, are permitted provided that the following conditions
11 : : * are met:
12 : : * 1. Redistributions of source code must retain the above copyright
13 : : * notice, this list of conditions and the following disclaimer.
14 : : * 2. Redistributions in binary form must reproduce the above copyright
15 : : * notice, this list of conditions and the following disclaimer in the
16 : : * documentation and/or other materials provided with the distribution.
17 : : * 3. The name of the author may not be used to endorse or promote products
18 : : * derived from this software without specific prior written permission.
19 : : *
20 : : * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21 : : * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22 : : * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23 : : * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24 : : * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 : : * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 : : * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 : : * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 : : * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29 : : * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 : : */
31 : :
32 : : #include "defs.h"
33 : :
34 : : #define SUBCMDMASK 0x00ff
35 : : #define SUBCMDSHIFT 8
36 : : #define QCMD_CMD(cmd) ((uint32_t)(cmd) >> SUBCMDSHIFT)
37 : : #define QCMD_TYPE(cmd) ((uint32_t)(cmd) & SUBCMDMASK)
38 : :
39 : : #define OLD_CMD(cmd) ((uint32_t)(cmd) << SUBCMDSHIFT)
40 : : #define NEW_CMD(cmd) ((uint32_t)(cmd) | 0x800000)
41 : : #define XQM_CMD(cmd) ((uint32_t)(cmd) | ('X' << SUBCMDSHIFT))
42 : :
43 : : #include "xlat/quotacmds.h"
44 : : #include "xlat/quotatypes.h"
45 : : #include "xlat/quota_formats.h"
46 : : #include "xlat/xfs_quota_flags.h"
47 : : #include "xlat/xfs_dqblk_flags.h"
48 : : #include "xlat/if_dqblk_valid.h"
49 : : #include "xlat/if_dqinfo_flags.h"
50 : : #include "xlat/if_dqinfo_valid.h"
51 : :
52 : : /*
53 : : * We add attribute packed due to the fact that the structure is 8-byte aligned
54 : : * on 64-bit systems and therefore has additional 4 bytes of padding, which
55 : : * leads to problems when it is used on 32-bit tracee which does not have such
56 : : * padding.
57 : : */
58 : : struct if_dqblk
59 : : {
60 : : uint64_t dqb_bhardlimit;
61 : : uint64_t dqb_bsoftlimit;
62 : : uint64_t dqb_curspace;
63 : : uint64_t dqb_ihardlimit;
64 : : uint64_t dqb_isoftlimit;
65 : : uint64_t dqb_curinodes;
66 : : uint64_t dqb_btime;
67 : : uint64_t dqb_itime;
68 : : uint32_t dqb_valid;
69 : : } ATTRIBUTE_PACKED;
70 : :
71 : : struct if_nextdqblk {
72 : : uint64_t dqb_bhardlimit;
73 : : uint64_t dqb_bsoftlimit;
74 : : uint64_t dqb_curspace;
75 : : uint64_t dqb_ihardlimit;
76 : : uint64_t dqb_isoftlimit;
77 : : uint64_t dqb_curinodes;
78 : : uint64_t dqb_btime;
79 : : uint64_t dqb_itime;
80 : : uint32_t dqb_valid;
81 : : uint32_t dqb_id;
82 : : };
83 : :
84 : : struct xfs_dqblk
85 : : {
86 : : int8_t d_version; /* version of this structure */
87 : : int8_t d_flags; /* XFS_{USER,PROJ,GROUP}_QUOTA */
88 : : uint16_t d_fieldmask; /* field specifier */
89 : : uint32_t d_id; /* user, project, or group ID */
90 : : uint64_t d_blk_hardlimit; /* absolute limit on disk blks */
91 : : uint64_t d_blk_softlimit; /* preferred limit on disk blks */
92 : : uint64_t d_ino_hardlimit; /* maximum # allocated inodes */
93 : : uint64_t d_ino_softlimit; /* preferred inode limit */
94 : : uint64_t d_bcount; /* # disk blocks owned by the user */
95 : : uint64_t d_icount; /* # inodes owned by the user */
96 : : int32_t d_itimer; /* zero if within inode limits */
97 : : int32_t d_btimer; /* similar to above; for disk blocks */
98 : : uint16_t d_iwarns; /* # warnings issued wrt num inodes */
99 : : uint16_t d_bwarns; /* # warnings issued wrt disk blocks */
100 : : int32_t d_padding2; /* padding2 - for future use */
101 : : uint64_t d_rtb_hardlimit; /* absolute limit on realtime blks */
102 : : uint64_t d_rtb_softlimit; /* preferred limit on RT disk blks */
103 : : uint64_t d_rtbcount; /* # realtime blocks owned */
104 : : int32_t d_rtbtimer; /* similar to above; for RT disk blks */
105 : : uint16_t d_rtbwarns; /* # warnings issued wrt RT disk blks */
106 : : int16_t d_padding3; /* padding3 - for future use */
107 : : char d_padding4[8]; /* yet more padding */
108 : : };
109 : :
110 : : struct if_dqinfo
111 : : {
112 : : uint64_t dqi_bgrace;
113 : : uint64_t dqi_igrace;
114 : : uint32_t dqi_flags;
115 : : uint32_t dqi_valid;
116 : : };
117 : :
118 : : typedef struct fs_qfilestat
119 : : {
120 : : uint64_t qfs_ino; /* inode number */
121 : : uint64_t qfs_nblks; /* number of BBs 512-byte-blks */
122 : : uint32_t qfs_nextents; /* number of extents */
123 : : } fs_qfilestat_t;
124 : :
125 : : struct xfs_dqstats
126 : : {
127 : : int8_t qs_version; /* version number for future changes */
128 : : uint16_t qs_flags; /* XFS_QUOTA_{U,P,G}DQ_{ACCT,ENFD} */
129 : : int8_t qs_pad; /* unused */
130 : : fs_qfilestat_t qs_uquota; /* user quota storage information */
131 : : fs_qfilestat_t qs_gquota; /* group quota storage information */
132 : : uint32_t qs_incoredqs; /* number of dquots incore */
133 : : int32_t qs_btimelimit; /* limit for blks timer */
134 : : int32_t qs_itimelimit; /* limit for inodes timer */
135 : : int32_t qs_rtbtimelimit; /* limit for rt blks timer */
136 : : uint16_t qs_bwarnlimit; /* limit for num warnings */
137 : : uint16_t qs_iwarnlimit; /* limit for num warnings */
138 : : };
139 : :
140 : : struct fs_qfilestatv {
141 : : uint64_t qfs_ino, qfs_nblks;
142 : : uint32_t qfs_nextents, qfs_pad;
143 : : };
144 : :
145 : : struct fs_quota_statv {
146 : : int8_t qs_version;
147 : : uint8_t qs_pad1;
148 : : uint16_t qs_flags;
149 : : uint32_t qs_incoredqs;
150 : : struct fs_qfilestatv qs_uquota;
151 : : struct fs_qfilestatv qs_gquota;
152 : : struct fs_qfilestatv qs_pquota;
153 : : int32_t qs_btimelimit;
154 : : int32_t qs_itimelimit;
155 : : int32_t qs_rtbtimelimit;
156 : : uint16_t qs_bwarnlimit;
157 : : uint16_t qs_iwarnlimit;
158 : : uint64_t qs_pad2[8];
159 : : };
160 : :
161 : : #define PRINT_FIELD_D(prefix, where, field) \
162 : : tprintf("%s%s=%lld", (prefix), #field, \
163 : : sign_extend_unsigned_to_ll((where).field))
164 : :
165 : : #define PRINT_FIELD_U(prefix, where, field) \
166 : : tprintf("%s%s=%llu", (prefix), #field, \
167 : : zero_extend_signed_to_ull((where).field))
168 : :
169 : : #define PRINT_FIELD_X(prefix, where, field) \
170 : : tprintf("%s%s=%#llx", (prefix), #field, \
171 : : zero_extend_signed_to_ull((where).field))
172 : :
173 : : static int
174 : 672 : decode_cmd_data(struct tcb *tcp, uint32_t id, uint32_t cmd, kernel_ulong_t data)
175 : : {
176 [ + + + + : 672 : switch (cmd) {
+ + + + +
+ + + + +
+ ]
177 : : case Q_QUOTAOFF:
178 : : case Q_SYNC:
179 : : case Q_XQUOTASYNC:
180 : 96 : break;
181 : : case Q_QUOTAON:
182 : 24 : tprints(", ");
183 : 24 : printxval(quota_formats, id, "QFMT_VFS_???");
184 : 24 : tprints(", ");
185 : 24 : printpath(tcp, data);
186 : 24 : break;
187 : : case Q_GETQUOTA:
188 [ + + ]: 96 : if (entering(tcp)) {
189 : 48 : printuid(", ", id);
190 : 48 : tprints(", ");
191 : :
192 : 48 : return 0;
193 : : }
194 : :
195 : : /* Fall-through */
196 : : case Q_SETQUOTA:
197 : : {
198 : : struct if_dqblk dq;
199 : :
200 [ + + ]: 72 : if (entering(tcp)) {
201 : 24 : printuid(", ", id);
202 : 24 : tprints(", ");
203 : : }
204 : :
205 [ + + ]: 72 : if (umove_or_printaddr(tcp, data, &dq))
206 : 60 : break;
207 : 12 : PRINT_FIELD_U("{", dq, dqb_bhardlimit);
208 : 12 : PRINT_FIELD_U(", ", dq, dqb_bsoftlimit);
209 : 12 : PRINT_FIELD_U(", ", dq, dqb_curspace);
210 : 12 : PRINT_FIELD_U(", ", dq, dqb_ihardlimit);
211 : 12 : PRINT_FIELD_U(", ", dq, dqb_isoftlimit);
212 : 12 : PRINT_FIELD_U(", ", dq, dqb_curinodes);
213 [ + + ]: 12 : if (!abbrev(tcp)) {
214 : 6 : PRINT_FIELD_U(", ", dq, dqb_btime);
215 : 6 : PRINT_FIELD_U(", ", dq, dqb_itime);
216 : 6 : tprints(", dqb_valid=");
217 : 6 : printflags(if_dqblk_valid,
218 : : dq.dqb_valid, "QIF_???");
219 : : } else {
220 : 6 : tprints(", ...");
221 : : }
222 : 12 : tprints("}");
223 : 72 : break;
224 : : }
225 : : case Q_GETNEXTQUOTA:
226 : : {
227 : : struct if_nextdqblk dq;
228 : :
229 [ + + ]: 24 : if (entering(tcp)) {
230 : 12 : printuid(", ", id);
231 : 12 : tprints(", ");
232 : :
233 : 12 : return 0;
234 : : }
235 : :
236 [ + - ]: 12 : if (umove_or_printaddr(tcp, data, &dq))
237 : 12 : break;
238 : 0 : PRINT_FIELD_U("{", dq, dqb_bhardlimit);
239 : 0 : PRINT_FIELD_U(", ", dq, dqb_bsoftlimit);
240 : 0 : PRINT_FIELD_U(", ", dq, dqb_curspace);
241 : 0 : PRINT_FIELD_U(", ", dq, dqb_ihardlimit);
242 : 0 : PRINT_FIELD_U(", ", dq, dqb_isoftlimit);
243 : 0 : PRINT_FIELD_U(", ", dq, dqb_curinodes);
244 [ # # ]: 0 : if (!abbrev(tcp)) {
245 : 0 : PRINT_FIELD_U(", ", dq, dqb_btime);
246 : 0 : PRINT_FIELD_U(", ", dq, dqb_itime);
247 : 0 : tprints(", dqb_valid=");
248 : 0 : printflags(if_dqblk_valid,
249 : : dq.dqb_valid, "QIF_???");
250 : 0 : PRINT_FIELD_U(", ", dq, dqb_id);
251 : : } else {
252 : 0 : PRINT_FIELD_U(", ", dq, dqb_id);
253 : 0 : tprints(", ...");
254 : : }
255 : 0 : tprints("}");
256 : 0 : break;
257 : : }
258 : : case Q_XGETQUOTA:
259 : : case Q_XGETNEXTQUOTA:
260 [ + + ]: 24 : if (entering(tcp)) {
261 : 12 : printuid(", ", id);
262 : 12 : tprints(", ");
263 : :
264 : 12 : return 0;
265 : : }
266 : :
267 : : /* Fall-through */
268 : : case Q_XSETQLIM:
269 : : {
270 : : struct xfs_dqblk dq;
271 : :
272 [ + + ]: 36 : if (entering(tcp)) {
273 : 24 : printuid(", ", id);
274 : 24 : tprints(", ");
275 : : }
276 : :
277 [ + + ]: 36 : if (umove_or_printaddr(tcp, data, &dq))
278 : 24 : break;
279 : 12 : PRINT_FIELD_D("{", dq, d_version);
280 : 12 : tprints(", d_flags=");
281 : 12 : printflags(xfs_dqblk_flags,
282 : 12 : (uint8_t) dq.d_flags, "XFS_???_QUOTA");
283 : 12 : PRINT_FIELD_X(", ", dq, d_fieldmask);
284 : 12 : PRINT_FIELD_U(", ", dq, d_id);
285 : 12 : PRINT_FIELD_U(", ", dq, d_blk_hardlimit);
286 : 12 : PRINT_FIELD_U(", ", dq, d_blk_softlimit);
287 : 12 : PRINT_FIELD_U(", ", dq, d_ino_hardlimit);
288 : 12 : PRINT_FIELD_U(", ", dq, d_ino_softlimit);
289 : 12 : PRINT_FIELD_U(", ", dq, d_bcount);
290 : 12 : PRINT_FIELD_U(", ", dq, d_icount);
291 [ + + ]: 12 : if (!abbrev(tcp)) {
292 : 6 : PRINT_FIELD_D(", ", dq, d_itimer);
293 : 6 : PRINT_FIELD_D(", ", dq, d_btimer);
294 : 6 : PRINT_FIELD_U(", ", dq, d_iwarns);
295 : 6 : PRINT_FIELD_U(", ", dq, d_bwarns);
296 : 6 : PRINT_FIELD_U(", ", dq, d_rtb_hardlimit);
297 : 6 : PRINT_FIELD_U(", ", dq, d_rtb_softlimit);
298 : 6 : PRINT_FIELD_U(", ", dq, d_rtbcount);
299 : 6 : PRINT_FIELD_D(", ", dq, d_rtbtimer);
300 : 6 : PRINT_FIELD_U(", ", dq, d_rtbwarns);
301 : : } else {
302 : 6 : tprints(", ...");
303 : : }
304 : 12 : tprints("}");
305 : 36 : break;
306 : : }
307 : : case Q_GETFMT:
308 : : {
309 : : uint32_t fmt;
310 : :
311 [ + + ]: 72 : if (entering(tcp)) {
312 : 36 : tprints(", ");
313 : :
314 : 36 : return 0;
315 : : }
316 : :
317 [ + - ]: 36 : if (umove_or_printaddr(tcp, data, &fmt))
318 : 36 : break;
319 : 0 : tprints("[");
320 : 0 : printxval(quota_formats, fmt, "QFMT_VFS_???");
321 : 0 : tprints("]");
322 : 0 : break;
323 : : }
324 : : case Q_GETINFO:
325 [ + + ]: 48 : if (entering(tcp)) {
326 : 24 : tprints(", ");
327 : :
328 : 24 : return 0;
329 : : }
330 : :
331 : : /* Fall-through */
332 : : case Q_SETINFO:
333 : : {
334 : : struct if_dqinfo dq;
335 : :
336 [ + + ]: 48 : if (entering(tcp))
337 : 24 : tprints(", ");
338 : :
339 [ + + ]: 48 : if (umove_or_printaddr(tcp, data, &dq))
340 : 36 : break;
341 : 12 : PRINT_FIELD_U("{", dq, dqi_bgrace);
342 : 12 : PRINT_FIELD_U(", ", dq, dqi_igrace);
343 : 12 : tprints(", dqi_flags=");
344 : 12 : printflags(if_dqinfo_flags, dq.dqi_flags, "DQF_???");
345 : 12 : tprints(", dqi_valid=");
346 : 12 : printflags(if_dqinfo_valid, dq.dqi_valid, "IIF_???");
347 : 12 : tprints("}");
348 : 48 : break;
349 : : }
350 : : case Q_XGETQSTAT:
351 : : {
352 : : struct xfs_dqstats dq;
353 : :
354 [ + + ]: 48 : if (entering(tcp)) {
355 : 24 : tprints(", ");
356 : :
357 : 24 : return 0;
358 : : }
359 : :
360 [ + - ]: 24 : if (umove_or_printaddr(tcp, data, &dq))
361 : 24 : break;
362 : 0 : PRINT_FIELD_D("{", dq, qs_version);
363 [ # # ]: 0 : if (!abbrev(tcp)) {
364 : 0 : tprints(", qs_flags=");
365 : 0 : printflags(xfs_quota_flags,
366 : 0 : dq.qs_flags, "XFS_QUOTA_???");
367 : 0 : PRINT_FIELD_U(", ", dq, qs_incoredqs);
368 : 0 : PRINT_FIELD_U(", qs_uquota={", dq.qs_uquota, qfs_ino);
369 : 0 : PRINT_FIELD_U(", ", dq.qs_uquota, qfs_nblks);
370 : 0 : PRINT_FIELD_U(", ", dq.qs_uquota, qfs_nextents);
371 : 0 : PRINT_FIELD_U("}, qs_gquota={", dq.qs_gquota, qfs_ino);
372 : 0 : PRINT_FIELD_U(", ", dq.qs_gquota, qfs_nblks);
373 : 0 : PRINT_FIELD_U(", ", dq.qs_gquota, qfs_nextents);
374 : 0 : PRINT_FIELD_D("}, ", dq, qs_btimelimit);
375 : 0 : PRINT_FIELD_D(", ", dq, qs_itimelimit);
376 : 0 : PRINT_FIELD_D(", ", dq, qs_rtbtimelimit);
377 : 0 : PRINT_FIELD_U(", ", dq, qs_bwarnlimit);
378 : 0 : PRINT_FIELD_U(", ", dq, qs_iwarnlimit);
379 : : } else {
380 : 0 : tprints(", ...");
381 : : }
382 : 0 : tprints("}");
383 : 0 : break;
384 : : }
385 : : case Q_XGETQSTATV:
386 : : {
387 : : struct fs_quota_statv dq;
388 : :
389 [ + + ]: 48 : if (entering(tcp)) {
390 : 24 : tprints(", ");
391 : :
392 : 24 : return 0;
393 : : }
394 : :
395 [ + - ]: 24 : if (umove_or_printaddr(tcp, data, &dq))
396 : 24 : break;
397 : 0 : PRINT_FIELD_D("{", dq, qs_version);
398 [ # # ]: 0 : if (!abbrev(tcp)) {
399 : 0 : tprints(", qs_flags=");
400 : 0 : printflags(xfs_quota_flags,
401 : 0 : dq.qs_flags, "XFS_QUOTA_???");
402 : 0 : PRINT_FIELD_U(", ", dq, qs_incoredqs);
403 : 0 : PRINT_FIELD_U(", qs_uquota={", dq.qs_uquota, qfs_ino);
404 : 0 : PRINT_FIELD_U(", ", dq.qs_uquota, qfs_nblks);
405 : 0 : PRINT_FIELD_U(", ", dq.qs_uquota, qfs_nextents);
406 : 0 : PRINT_FIELD_U("}, qs_gquota={", dq.qs_gquota, qfs_ino);
407 : 0 : PRINT_FIELD_U(", ", dq.qs_gquota, qfs_nblks);
408 : 0 : PRINT_FIELD_U(", ", dq.qs_gquota, qfs_nextents);
409 : 0 : PRINT_FIELD_U("}, qs_pquota={", dq.qs_pquota, qfs_ino);
410 : 0 : PRINT_FIELD_U(", ", dq.qs_pquota, qfs_nblks);
411 : 0 : PRINT_FIELD_U(", ", dq.qs_pquota, qfs_nextents);
412 : 0 : PRINT_FIELD_D("}, ", dq, qs_btimelimit);
413 : 0 : PRINT_FIELD_D(", ", dq, qs_itimelimit);
414 : 0 : PRINT_FIELD_D(", ", dq, qs_rtbtimelimit);
415 : 0 : PRINT_FIELD_U(", ", dq, qs_bwarnlimit);
416 : 0 : PRINT_FIELD_U(", ", dq, qs_iwarnlimit);
417 : : } else {
418 : 0 : tprints(", ...");
419 : : }
420 : 0 : tprints("}");
421 : 0 : break;
422 : : }
423 : : case Q_XQUOTAON:
424 : : case Q_XQUOTAOFF:
425 : : {
426 : : uint32_t flag;
427 : :
428 : 60 : tprints(", ");
429 : :
430 [ + + ]: 60 : if (umove_or_printaddr(tcp, data, &flag))
431 : 36 : break;
432 : 24 : tprints("[");
433 : 24 : printflags(xfs_quota_flags, flag, "XFS_QUOTA_???");
434 : 24 : tprints("]");
435 : 60 : break;
436 : : }
437 : : case Q_XQUOTARM:
438 : : {
439 : : uint32_t flag;
440 : :
441 : 36 : tprints(", ");
442 : :
443 [ + + ]: 36 : if (umove_or_printaddr(tcp, data, &flag))
444 : 24 : break;
445 : 12 : tprints("[");
446 : 12 : printflags(xfs_dqblk_flags, flag, "XFS_???_QUOTA");
447 : 12 : tprints("]");
448 : 36 : break;
449 : : }
450 : : default:
451 : 24 : printuid(", ", id);
452 : 24 : tprints(", ");
453 : 24 : printaddr(data);
454 : 24 : break;
455 : : }
456 : 492 : return RVAL_DECODED;
457 : : }
458 : :
459 : 672 : SYS_FUNC(quotactl)
460 : : {
461 : : /*
462 : : * The Linux kernel only looks at the low 32 bits of command and id
463 : : * arguments, but on some 64-bit architectures (s390x) this word
464 : : * will have been sign-extended when we see it. The high 1 bits
465 : : * don't mean anything, so don't confuse the output with them.
466 : : */
467 : 672 : uint32_t qcmd = tcp->u_arg[0];
468 : 672 : uint32_t cmd = QCMD_CMD(qcmd);
469 : 672 : uint32_t type = QCMD_TYPE(qcmd);
470 : 672 : uint32_t id = tcp->u_arg[2];
471 : :
472 [ + + ]: 672 : if (entering(tcp)) {
473 : 492 : tprints("QCMD(");
474 : 492 : printxval(quotacmds, cmd, "Q_???");
475 : 492 : tprints(", ");
476 : 492 : printxval(quotatypes, type, "???QUOTA");
477 : 492 : tprints("), ");
478 : 492 : printpath(tcp, tcp->u_arg[1]);
479 : : }
480 : 672 : return decode_cmd_data(tcp, id, cmd, tcp->u_arg[3]);
481 : : }
|