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