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