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