]> granicus.if.org Git - strace/blob - quota.c
Enhance capget and capset syscalls decoding
[strace] / quota.c
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, 2006 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  *      $Id$
32  */
33
34 #include "defs.h"
35
36 #include <inttypes.h>
37
38 #define SUBCMDMASK  0x00ff
39 #define SUBCMDSHIFT 8
40 #define QCMD_CMD(cmd)   ((u_int32_t)(cmd) >> SUBCMDSHIFT)
41 #define QCMD_TYPE(cmd)  ((u_int32_t)(cmd) & SUBCMDMASK)
42
43 #define OLD_CMD(cmd)    ((u_int32_t)(cmd) << 8)
44 #define NEW_CMD(cmd)    ((u_int32_t)(cmd) | 0x800000)
45 #define XQM_CMD(cmd)    ((u_int32_t)(cmd) | ('X'<<8))
46
47 #define Q_V1_QUOTAON    OLD_CMD(0x1)
48 #define Q_V1_QUOTAOFF   OLD_CMD(0x2)
49 #define Q_V1_GETQUOTA   OLD_CMD(0x3)
50 #define Q_V1_SETQUOTA   OLD_CMD(0x4)
51 #define Q_V1_SETUSE     OLD_CMD(0x5)
52 #define Q_V1_SYNC       OLD_CMD(0x6)
53 #define Q_SETQLIM       OLD_CMD(0x7)
54 #define Q_V1_GETSTATS   OLD_CMD(0x8)
55 #define Q_V1_RSQUASH    OLD_CMD(0x10)
56
57 #define Q_V2_GETQUOTA   OLD_CMD(0xD)
58 #define Q_V2_SETQUOTA   OLD_CMD(0xE)
59 #define Q_V2_SETUSE     OLD_CMD(0xF)
60 #define Q_V2_GETINFO    OLD_CMD(0x9)
61 #define Q_V2_SETINFO    OLD_CMD(0xA)
62 #define Q_V2_SETGRACE   OLD_CMD(0xB)
63 #define Q_V2_SETFLAGS   OLD_CMD(0xC)
64 #define Q_V2_GETSTATS   OLD_CMD(0x11)
65
66 #define Q_SYNC          NEW_CMD(0x1)
67 #define Q_QUOTAON       NEW_CMD(0x2)
68 #define Q_QUOTAOFF      NEW_CMD(0x3)
69 #define Q_GETFMT        NEW_CMD(0x4)
70 #define Q_GETINFO       NEW_CMD(0x5)
71 #define Q_SETINFO       NEW_CMD(0x6)
72 #define Q_GETQUOTA      NEW_CMD(0x7)
73 #define Q_SETQUOTA      NEW_CMD(0x8)
74
75 #define Q_XQUOTAON      XQM_CMD(0x1)
76 #define Q_XQUOTAOFF     XQM_CMD(0x2)
77 #define Q_XGETQUOTA     XQM_CMD(0x3)
78 #define Q_XSETQLIM      XQM_CMD(0x4)
79 #define Q_XGETQSTAT     XQM_CMD(0x5)
80 #define Q_XQUOTARM      XQM_CMD(0x6)
81 #define Q_XQUOTASYNC    XQM_CMD(0x7)
82
83 static const struct xlat quotacmds[] = {
84         {Q_V1_QUOTAON, "Q_V1_QUOTAON"},
85         {Q_V1_QUOTAOFF, "Q_V1_QUOTAOFF"},
86         {Q_V1_GETQUOTA, "Q_V1_GETQUOTA"},
87         {Q_V1_SETQUOTA, "Q_V1_SETQUOTA"},
88         {Q_V1_SETUSE, "Q_V1_SETUSE"},
89         {Q_V1_SYNC, "Q_V1_SYNC"},
90         {Q_SETQLIM, "Q_SETQLIM"},
91         {Q_V1_GETSTATS, "Q_V1_GETSTATS"},
92         {Q_V1_RSQUASH, "Q_V1_RSQUASH"},
93
94         {Q_V2_GETQUOTA, "Q_V2_GETQUOTA"},
95         {Q_V2_SETQUOTA, "Q_V2_SETQUOTA"},
96         {Q_V2_SETUSE, "Q_V2_SETUSE"},
97         {Q_V2_GETINFO, "Q_V2_GETINFO"},
98         {Q_V2_SETINFO, "Q_V2_SETINFO"},
99         {Q_V2_SETGRACE, "Q_V2_SETGRACE"},
100         {Q_V2_SETFLAGS, "Q_V2_SETFLAGS"},
101         {Q_V2_GETSTATS, "Q_V2_GETSTATS"},
102
103         {Q_SYNC, "Q_SYNC"},
104         {Q_QUOTAON, "Q_QUOTAON"},
105         {Q_QUOTAOFF, "Q_QUOTAOFF"},
106         {Q_GETFMT, "Q_GETFMT"},
107         {Q_GETINFO, "Q_GETINFO"},
108         {Q_SETINFO, "Q_SETINFO"},
109         {Q_GETQUOTA, "Q_GETQUOTA"},
110         {Q_SETQUOTA, "Q_SETQUOTA"},
111
112         {Q_XQUOTAON, "Q_XQUOTAON"},
113         {Q_XQUOTAOFF, "Q_XQUOTAOFF"},
114         {Q_XGETQUOTA, "Q_XGETQUOTA"},
115         {Q_XSETQLIM, "Q_XSETQLIM"},
116         {Q_XGETQSTAT, "Q_XGETQSTAT"},
117         {Q_XQUOTARM, "Q_XQUOTARM"},
118         {Q_XQUOTASYNC, "Q_XQUOTASYNC"},
119
120         {0, NULL},
121 };
122
123 #define USRQUOTA 0
124 #define GRPQUOTA 1
125
126 static const struct xlat quotatypes[] = {
127         {USRQUOTA, "USRQUOTA"},
128         {GRPQUOTA, "GRPQUOTA"},
129         {0, NULL},
130 };
131
132 /* Quota format identifiers */
133 #define QFMT_VFS_OLD 1
134 #define QFMT_VFS_V0  2
135
136 static const struct xlat quota_formats[] = {
137         {QFMT_VFS_OLD, "QFMT_VFS_OLD"},
138         {QFMT_VFS_V0, "QFMT_VFS_V0"},
139         {0, NULL},
140 };
141
142 #define XFS_QUOTA_UDQ_ACCT      (1<<0)  /* user quota accounting */
143 #define XFS_QUOTA_UDQ_ENFD      (1<<1)  /* user quota limits enforcement */
144 #define XFS_QUOTA_GDQ_ACCT      (1<<2)  /* group quota accounting */
145 #define XFS_QUOTA_GDQ_ENFD      (1<<3)  /* group quota limits enforcement */
146
147 #define XFS_USER_QUOTA          (1<<0)  /* user quota type */
148 #define XFS_PROJ_QUOTA          (1<<1)  /* (IRIX) project quota type */
149 #define XFS_GROUP_QUOTA         (1<<2)  /* group quota type */
150
151 static const struct xlat xfs_quota_flags[] = {
152         {XFS_QUOTA_UDQ_ACCT, "XFS_QUOTA_UDQ_ACCT"},
153         {XFS_QUOTA_UDQ_ENFD, "XFS_QUOTA_UDQ_ENFD"},
154         {XFS_QUOTA_GDQ_ACCT, "XFS_QUOTA_GDQ_ACCT"},
155         {XFS_QUOTA_GDQ_ENFD, "XFS_QUOTA_GDQ_ENFD"},
156         {0, NULL}
157 };
158
159 static const struct xlat xfs_dqblk_flags[] = {
160         {XFS_USER_QUOTA, "XFS_USER_QUOTA"},
161         {XFS_PROJ_QUOTA, "XFS_PROJ_QUOTA"},
162         {XFS_GROUP_QUOTA, "XFS_GROUP_QUOTA"},
163         {0, NULL}
164 };
165
166 /*
167  * Following flags are used to specify which fields are valid
168  */
169 #define QIF_BLIMITS     1
170 #define QIF_SPACE       2
171 #define QIF_ILIMITS     4
172 #define QIF_INODES      8
173 #define QIF_BTIME       16
174 #define QIF_ITIME       32
175
176 static const struct xlat if_dqblk_valid[] = {
177         {QIF_BLIMITS, "QIF_BLIMITS"},
178         {QIF_SPACE, "QIF_SPACE"},
179         {QIF_ILIMITS, "QIF_ILIMITS"},
180         {QIF_INODES, "QIF_INODES"},
181         {QIF_BTIME, "QIF_BTIME"},
182         {QIF_ITIME, "QIF_ITIME"},
183         {0, NULL}
184 };
185
186 struct if_dqblk
187 {
188         u_int64_t dqb_bhardlimit;
189         u_int64_t dqb_bsoftlimit;
190         u_int64_t dqb_curspace;
191         u_int64_t dqb_ihardlimit;
192         u_int64_t dqb_isoftlimit;
193         u_int64_t dqb_curinodes;
194         u_int64_t dqb_btime;
195         u_int64_t dqb_itime;
196         u_int32_t dqb_valid;
197 };
198
199 struct v1_dqblk
200 {
201         u_int32_t dqb_bhardlimit;       /* absolute limit on disk blks alloc */
202         u_int32_t dqb_bsoftlimit;       /* preferred limit on disk blks */
203         u_int32_t dqb_curblocks;        /* current block count */
204         u_int32_t dqb_ihardlimit;       /* maximum # allocated inodes */
205         u_int32_t dqb_isoftlimit;       /* preferred inode limit */
206         u_int32_t dqb_curinodes;        /* current # allocated inodes */
207         time_t  dqb_btime;      /* time limit for excessive disk use */
208         time_t  dqb_itime;      /* time limit for excessive files */
209 };
210
211 struct v2_dqblk
212 {
213         unsigned int dqb_ihardlimit;
214         unsigned int dqb_isoftlimit;
215         unsigned int dqb_curinodes;
216         unsigned int dqb_bhardlimit;
217         unsigned int dqb_bsoftlimit;
218         u_int64_t dqb_curspace;
219         time_t  dqb_btime;
220         time_t  dqb_itime;
221 };
222
223 struct xfs_dqblk
224 {
225         int8_t  d_version;      /* version of this structure */
226         int8_t  d_flags;        /* XFS_{USER,PROJ,GROUP}_QUOTA */
227         u_int16_t d_fieldmask;  /* field specifier */
228         u_int32_t d_id;         /* user, project, or group ID */
229         u_int64_t d_blk_hardlimit;      /* absolute limit on disk blks */
230         u_int64_t d_blk_softlimit;      /* preferred limit on disk blks */
231         u_int64_t d_ino_hardlimit;      /* maximum # allocated inodes */
232         u_int64_t d_ino_softlimit;      /* preferred inode limit */
233         u_int64_t d_bcount;     /* # disk blocks owned by the user */
234         u_int64_t d_icount;     /* # inodes owned by the user */
235         int32_t d_itimer;       /* zero if within inode limits */
236         int32_t d_btimer;       /* similar to above; for disk blocks */
237         u_int16_t d_iwarns;     /* # warnings issued wrt num inodes */
238         u_int16_t d_bwarns;     /* # warnings issued wrt disk blocks */
239         int32_t d_padding2;     /* padding2 - for future use */
240         u_int64_t d_rtb_hardlimit;      /* absolute limit on realtime blks */
241         u_int64_t d_rtb_softlimit;      /* preferred limit on RT disk blks */
242         u_int64_t d_rtbcount;   /* # realtime blocks owned */
243         int32_t d_rtbtimer;     /* similar to above; for RT disk blks */
244         u_int16_t d_rtbwarns;   /* # warnings issued wrt RT disk blks */
245         int16_t d_padding3;     /* padding3 - for future use */
246         char    d_padding4[8];  /* yet more padding */
247 };
248
249 /*
250  * Following flags are used to specify which fields are valid
251  */
252 #define IIF_BGRACE      1
253 #define IIF_IGRACE      2
254 #define IIF_FLAGS       4
255
256 static const struct xlat if_dqinfo_valid[] = {
257         {IIF_BGRACE, "IIF_BGRACE"},
258         {IIF_IGRACE, "IIF_IGRACE"},
259         {IIF_FLAGS, "IIF_FLAGS"},
260         {0, NULL}
261 };
262
263 struct if_dqinfo
264 {
265         u_int64_t dqi_bgrace;
266         u_int64_t dqi_igrace;
267         u_int32_t dqi_flags;
268         u_int32_t dqi_valid;
269 };
270
271 struct v2_dqinfo
272 {
273         unsigned int dqi_bgrace;
274         unsigned int dqi_igrace;
275         unsigned int dqi_flags;
276         unsigned int dqi_blocks;
277         unsigned int dqi_free_blk;
278         unsigned int dqi_free_entry;
279 };
280
281 struct v1_dqstats
282 {
283         u_int32_t lookups;
284         u_int32_t drops;
285         u_int32_t reads;
286         u_int32_t writes;
287         u_int32_t cache_hits;
288         u_int32_t allocated_dquots;
289         u_int32_t free_dquots;
290         u_int32_t syncs;
291 };
292
293 struct v2_dqstats
294 {
295         u_int32_t lookups;
296         u_int32_t drops;
297         u_int32_t reads;
298         u_int32_t writes;
299         u_int32_t cache_hits;
300         u_int32_t allocated_dquots;
301         u_int32_t free_dquots;
302         u_int32_t syncs;
303         u_int32_t version;
304 };
305
306 typedef struct fs_qfilestat
307 {
308         u_int64_t qfs_ino;      /* inode number */
309         u_int64_t qfs_nblks;    /* number of BBs 512-byte-blks */
310         u_int32_t qfs_nextents; /* number of extents */
311 } fs_qfilestat_t;
312
313 struct xfs_dqstats
314 {
315         int8_t  qs_version;     /* version number for future changes */
316         u_int16_t qs_flags;     /* XFS_QUOTA_{U,P,G}DQ_{ACCT,ENFD} */
317         int8_t  qs_pad;         /* unused */
318         fs_qfilestat_t qs_uquota;       /* user quota storage information */
319         fs_qfilestat_t qs_gquota;       /* group quota storage information */
320         u_int32_t qs_incoredqs; /* number of dquots incore */
321         int32_t qs_btimelimit;  /* limit for blks timer */
322         int32_t qs_itimelimit;  /* limit for inodes timer */
323         int32_t qs_rtbtimelimit;        /* limit for rt blks timer */
324         u_int16_t qs_bwarnlimit;        /* limit for num warnings */
325         u_int16_t qs_iwarnlimit;        /* limit for num warnings */
326 };
327
328 static void
329 decode_cmd_data(struct tcb *tcp, u_int32_t cmd, unsigned long data)
330 {
331         switch (cmd) {
332                 case Q_GETQUOTA:
333                 case Q_SETQUOTA:
334                 {
335                         struct if_dqblk dq;
336
337                         if (cmd == Q_GETQUOTA && syserror(tcp)) {
338                                 tprintf("%#lx", data);
339                                 break;
340                         }
341                         if (umove(tcp, data, &dq) < 0) {
342                                 tprintf("{???} %#lx", data);
343                                 break;
344                         }
345                         tprintf("{bhardlimit=%" PRIu64 ", ", dq.dqb_bhardlimit);
346                         tprintf("bsoftlimit=%" PRIu64 ", ", dq.dqb_bsoftlimit);
347                         tprintf("curspace=%" PRIu64 ", ", dq.dqb_curspace);
348                         tprintf("ihardlimit=%" PRIu64 ", ", dq.dqb_ihardlimit);
349                         tprintf("isoftlimit=%" PRIu64 ", ", dq.dqb_isoftlimit);
350                         tprintf("curinodes=%" PRIu64 ", ", dq.dqb_curinodes);
351                         if (!abbrev(tcp)) {
352                                 tprintf("btime=%" PRIu64 ", ", dq.dqb_btime);
353                                 tprintf("itime=%" PRIu64 ", ", dq.dqb_itime);
354                                 tprints("valid=");
355                                 printflags(if_dqblk_valid,
356                                            dq.dqb_valid, "QIF_???");
357                                 tprints("}");
358                         } else
359                                 tprints("...}");
360                         break;
361                 }
362                 case Q_V1_GETQUOTA:
363                 case Q_V1_SETQUOTA:
364                 {
365                         struct v1_dqblk dq;
366
367                         if (cmd == Q_V1_GETQUOTA && syserror(tcp)) {
368                                 tprintf("%#lx", data);
369                                 break;
370                         }
371                         if (umove(tcp, data, &dq) < 0) {
372                                 tprintf("{???} %#lx", data);
373                                 break;
374                         }
375                         tprintf("{bhardlimit=%u, ", dq.dqb_bhardlimit);
376                         tprintf("bsoftlimit=%u, ", dq.dqb_bsoftlimit);
377                         tprintf("curblocks=%u, ", dq.dqb_curblocks);
378                         tprintf("ihardlimit=%u, ", dq.dqb_ihardlimit);
379                         tprintf("isoftlimit=%u, ", dq.dqb_isoftlimit);
380                         tprintf("curinodes=%u, ", dq.dqb_curinodes);
381                         tprintf("btime=%lu, ", (long) dq.dqb_btime);
382                         tprintf("itime=%lu}", (long) dq.dqb_itime);
383                         break;
384                 }
385                 case Q_V2_GETQUOTA:
386                 case Q_V2_SETQUOTA:
387                 {
388                         struct v2_dqblk dq;
389
390                         if (cmd == Q_V2_GETQUOTA && syserror(tcp)) {
391                                 tprintf("%#lx", data);
392                                 break;
393                         }
394                         if (umove(tcp, data, &dq) < 0) {
395                                 tprintf("{???} %#lx", data);
396                                 break;
397                         }
398                         tprintf("{ihardlimit=%u, ", dq.dqb_ihardlimit);
399                         tprintf("isoftlimit=%u, ", dq.dqb_isoftlimit);
400                         tprintf("curinodes=%u, ", dq.dqb_curinodes);
401                         tprintf("bhardlimit=%u, ", dq.dqb_bhardlimit);
402                         tprintf("bsoftlimit=%u, ", dq.dqb_bsoftlimit);
403                         tprintf("curspace=%" PRIu64 ", ", dq.dqb_curspace);
404                         tprintf("btime=%lu, ", (long) dq.dqb_btime);
405                         tprintf("itime=%lu}", (long) dq.dqb_itime);
406                         break;
407                 }
408                 case Q_XGETQUOTA:
409                 case Q_XSETQLIM:
410                 {
411                         struct xfs_dqblk dq;
412
413                         if (cmd == Q_XGETQUOTA && syserror(tcp)) {
414                                 tprintf("%#lx", data);
415                                 break;
416                         }
417                         if (umove(tcp, data, &dq) < 0) {
418                                 tprintf("{???} %#lx", data);
419                                 break;
420                         }
421                         tprintf("{version=%d, ", dq.d_version);
422                         tprints("flags=");
423                         printflags(xfs_dqblk_flags,
424                                    dq.d_flags, "XFS_???_QUOTA");
425                         tprintf(", fieldmask=%#x, ", dq.d_fieldmask);
426                         tprintf("id=%u, ", dq.d_id);
427                         tprintf("blk_hardlimit=%" PRIu64 ", ", dq.d_blk_hardlimit);
428                         tprintf("blk_softlimit=%" PRIu64 ", ", dq.d_blk_softlimit);
429                         tprintf("ino_hardlimit=%" PRIu64 ", ", dq.d_ino_hardlimit);
430                         tprintf("ino_softlimit=%" PRIu64 ", ", dq.d_ino_softlimit);
431                         tprintf("bcount=%" PRIu64 ", ", dq.d_bcount);
432                         tprintf("icount=%" PRIu64 ", ", dq.d_icount);
433                         if (!abbrev(tcp)) {
434                                 tprintf("itimer=%d, ", dq.d_itimer);
435                                 tprintf("btimer=%d, ", dq.d_btimer);
436                                 tprintf("iwarns=%u, ", dq.d_iwarns);
437                                 tprintf("bwarns=%u, ", dq.d_bwarns);
438                                 tprintf("rtbcount=%" PRIu64 ", ", dq.d_rtbcount);
439                                 tprintf("rtbtimer=%d, ", dq.d_rtbtimer);
440                                 tprintf("rtbwarns=%u}", dq.d_rtbwarns);
441                         } else
442                                 tprints("...}");
443                         break;
444                 }
445                 case Q_GETFMT:
446                 {
447                         u_int32_t fmt;
448
449                         if (syserror(tcp)) {
450                                 tprintf("%#lx", data);
451                                 break;
452                         }
453                         if (umove(tcp, data, &fmt) < 0) {
454                                 tprintf("{???} %#lx", data);
455                                 break;
456                         }
457                         tprints("{");
458                         printxval(quota_formats, fmt, "QFMT_VFS_???");
459                         tprints("}");
460                         break;
461                 }
462                 case Q_GETINFO:
463                 case Q_SETINFO:
464                 {
465                         struct if_dqinfo dq;
466
467                         if (cmd == Q_GETINFO && syserror(tcp)) {
468                                 tprintf("%#lx", data);
469                                 break;
470                         }
471                         if (umove(tcp, data, &dq) < 0) {
472                                 tprintf("{???} %#lx", data);
473                                 break;
474                         }
475                         tprintf("{bgrace=%" PRIu64 ", ", dq.dqi_bgrace);
476                         tprintf("igrace=%" PRIu64 ", ", dq.dqi_igrace);
477                         tprintf("flags=%#x, ", dq.dqi_flags);
478                         tprints("valid=");
479                         printflags(if_dqinfo_valid, dq.dqi_valid, "IIF_???");
480                         tprints("}");
481                         break;
482                 }
483                 case Q_V2_GETINFO:
484                 case Q_V2_SETINFO:
485                 {
486                         struct v2_dqinfo dq;
487
488                         if (cmd == Q_V2_GETINFO && syserror(tcp)) {
489                                 tprintf("%#lx", data);
490                                 break;
491                         }
492                         if (umove(tcp, data, &dq) < 0) {
493                                 tprintf("{???} %#lx", data);
494                                 break;
495                         }
496                         tprintf("{bgrace=%u, ", dq.dqi_bgrace);
497                         tprintf("igrace=%u, ", dq.dqi_igrace);
498                         tprintf("flags=%#x, ", dq.dqi_flags);
499                         tprintf("blocks=%u, ", dq.dqi_blocks);
500                         tprintf("free_blk=%u, ", dq.dqi_free_blk);
501                         tprintf("free_entry=%u}", dq.dqi_free_entry);
502                         break;
503                 }
504                 case Q_V1_GETSTATS:
505                 {
506                         struct v1_dqstats dq;
507
508                         if (syserror(tcp)) {
509                                 tprintf("%#lx", data);
510                                 break;
511                         }
512                         if (umove(tcp, data, &dq) < 0) {
513                                 tprintf("{???} %#lx", data);
514                                 break;
515                         }
516                         tprintf("{lookups=%u, ", dq.lookups);
517                         tprintf("drops=%u, ", dq.drops);
518                         tprintf("reads=%u, ", dq.reads);
519                         tprintf("writes=%u, ", dq.writes);
520                         tprintf("cache_hits=%u, ", dq.cache_hits);
521                         tprintf("allocated_dquots=%u, ", dq.allocated_dquots);
522                         tprintf("free_dquots=%u, ", dq.free_dquots);
523                         tprintf("syncs=%u}", dq.syncs);
524                         break;
525                 }
526                 case Q_V2_GETSTATS:
527                 {
528                         struct v2_dqstats dq;
529
530                         if (syserror(tcp)) {
531                                 tprintf("%#lx", data);
532                                 break;
533                         }
534                         if (umove(tcp, data, &dq) < 0) {
535                                 tprintf("{???} %#lx", data);
536                                 break;
537                         }
538                         tprintf("{lookups=%u, ", dq.lookups);
539                         tprintf("drops=%u, ", dq.drops);
540                         tprintf("reads=%u, ", dq.reads);
541                         tprintf("writes=%u, ", dq.writes);
542                         tprintf("cache_hits=%u, ", dq.cache_hits);
543                         tprintf("allocated_dquots=%u, ", dq.allocated_dquots);
544                         tprintf("free_dquots=%u, ", dq.free_dquots);
545                         tprintf("syncs=%u, ", dq.syncs);
546                         tprintf("version=%u}", dq.version);
547                         break;
548                 }
549                 case Q_XGETQSTAT:
550                 {
551                         struct xfs_dqstats dq;
552
553                         if (syserror(tcp)) {
554                                 tprintf("%#lx", data);
555                                 break;
556                         }
557                         if (umove(tcp, data, &dq) < 0) {
558                                 tprintf("{???} %#lx", data);
559                                 break;
560                         }
561                         tprintf("{version=%d, ", dq.qs_version);
562                         if (abbrev(tcp)) {
563                                 tprints("...}");
564                                 break;
565                         }
566                         tprints("flags=");
567                         printflags(xfs_quota_flags,
568                                    dq.qs_flags, "XFS_QUOTA_???");
569                         tprintf(", incoredqs=%u, ", dq.qs_incoredqs);
570                         tprintf("u_ino=%" PRIu64 ", ", dq.qs_uquota.qfs_ino);
571                         tprintf("u_nblks=%" PRIu64 ", ", dq.qs_uquota.qfs_nblks);
572                         tprintf("u_nextents=%u, ", dq.qs_uquota.qfs_nextents);
573                         tprintf("g_ino=%" PRIu64 ", ", dq.qs_gquota.qfs_ino);
574                         tprintf("g_nblks=%" PRIu64 ", ", dq.qs_gquota.qfs_nblks);
575                         tprintf("g_nextents=%u, ", dq.qs_gquota.qfs_nextents);
576                         tprintf("btimelimit=%d, ", dq.qs_btimelimit);
577                         tprintf("itimelimit=%d, ", dq.qs_itimelimit);
578                         tprintf("rtbtimelimit=%d, ", dq.qs_rtbtimelimit);
579                         tprintf("bwarnlimit=%u, ", dq.qs_bwarnlimit);
580                         tprintf("iwarnlimit=%u}", dq.qs_iwarnlimit);
581                         break;
582                 }
583                 case Q_XQUOTAON:
584                 {
585                         u_int32_t flag;
586
587                         if (umove(tcp, data, &flag) < 0) {
588                                 tprintf("{???} %#lx", data);
589                                 break;
590                         }
591                         tprints("{");
592                         printflags(xfs_quota_flags, flag, "XFS_QUOTA_???");
593                         tprints("}");
594                         break;
595                 }
596                 default:
597                         tprintf("%#lx", data);
598                         break;
599         }
600 }
601
602 int
603 sys_quotactl(struct tcb *tcp)
604 {
605         /*
606          * The Linux kernel only looks at the low 32 bits of command and id
607          * arguments, but on some 64-bit architectures (s390x) this word
608          * will have been sign-extended when we see it.  The high 1 bits
609          * don't mean anything, so don't confuse the output with them.
610          */
611         u_int32_t qcmd = tcp->u_arg[0];
612         u_int32_t cmd = QCMD_CMD(qcmd);
613         u_int32_t type = QCMD_TYPE(qcmd);
614         u_int32_t id = tcp->u_arg[2];
615
616         if (!verbose(tcp))
617                 return printargs(tcp);
618
619         if (entering(tcp)) {
620                 printxval(quotacmds, cmd, "Q_???");
621                 tprints("|");
622                 printxval(quotatypes, type, "???QUOTA");
623                 tprints(", ");
624                 printstr(tcp, tcp->u_arg[1], -1);
625                 tprints(", ");
626                 switch (cmd) {
627                         case Q_V1_QUOTAON:
628                         case Q_QUOTAON:
629                                 printxval(quota_formats, id, "QFMT_VFS_???");
630                                 break;
631                         case Q_V1_GETQUOTA:
632                         case Q_V2_GETQUOTA:
633                         case Q_GETQUOTA:
634                         case Q_V1_SETQUOTA:
635                         case Q_V2_SETQUOTA:
636                         case Q_V1_SETUSE:
637                         case Q_V2_SETUSE:
638                         case Q_SETQLIM:
639                         case Q_SETQUOTA:
640                         case Q_XGETQUOTA:
641                         case Q_XSETQLIM:
642                                 tprintf("%u", id);
643                                 break;
644                         default:
645                                 tprintf("%#lx", tcp->u_arg[2]);
646                                 break;
647                 }
648                 tprints(", ");
649         } else {
650                 if (!tcp->u_arg[3])
651                         tprints("NULL");
652                 else
653                         decode_cmd_data(tcp, cmd, tcp->u_arg[3]);
654         }
655         return 0;
656 }