1/*
2 * Check decoding of quotactl syscall.
3 *
4 * Copyright (c) 2016 Eugene Syromyatnikov <evgsyr@gmail.com>
5 * Copyright (c) 2016 Dmitry V. Levin <ldv@altlinux.org>
6 * Copyright (c) 2016-2017 The strace developers.
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 "tests.h"
33
34#include <asm/unistd.h>
35
36#if defined(__NR_quotactl) && \
37	(defined(HAVE_LINUX_QUOTA_H) || defined(HAVE_SYS_QUOTA_H))
38
39# include <inttypes.h>
40# include <stdint.h>
41# include <stdio.h>
42# include <string.h>
43# include <unistd.h>
44
45# include "quotactl.h"
46
47# ifndef HAVE_LINUX_QUOTA_H
48/* Some dirty hacks in order to make sys/quota.h usable as a backup */
49
50#  define if_dqblk dqblk
51#  define if_nextdqblk nextdqblk
52#  define if_dqinfo dqinfo
53
54# endif /* !HAVE_LINUX_QUOTA_H */
55
56# ifndef Q_GETNEXTQUOTA
57
58#  define Q_GETNEXTQUOTA 0x800009
59
60struct if_nextdqblk {
61	uint64_t dqb_bhardlimit;
62	uint64_t dqb_bsoftlimit;
63	uint64_t dqb_curspace;
64	uint64_t dqb_ihardlimit;
65	uint64_t dqb_isoftlimit;
66	uint64_t dqb_curinodes;
67	uint64_t dqb_btime;
68	uint64_t dqb_itime;
69	uint32_t dqb_valid;
70	uint32_t dqb_id;
71};
72# endif /* !Q_GETNEXTQUOTA */
73
74# include "xlat.h"
75# include "xlat/quota_formats.h"
76# include "xlat/if_dqblk_valid.h"
77# include "xlat/if_dqinfo_flags.h"
78# include "xlat/if_dqinfo_valid.h"
79
80void
81print_dqblk(long rc, void *ptr, void *arg)
82{
83	struct if_dqblk *db = ptr;
84	long out_arg = (long) arg;
85
86	if (((rc != 0) && out_arg) || (out_arg > 1)) {
87		printf("%p", db);
88		return;
89	}
90
91	PRINT_FIELD_U("{", *db, dqb_bhardlimit);
92	PRINT_FIELD_U(", ", *db, dqb_bsoftlimit);
93	PRINT_FIELD_U(", ", *db, dqb_curspace);
94	PRINT_FIELD_U(", ", *db, dqb_ihardlimit);
95	PRINT_FIELD_U(", ", *db, dqb_isoftlimit);
96	PRINT_FIELD_U(", ", *db, dqb_curinodes);
97
98# if VERBOSE
99	PRINT_FIELD_U(", ", *db, dqb_btime);
100	PRINT_FIELD_U(", ", *db, dqb_itime);
101
102	printf(", dqb_valid=");
103	printflags(if_dqblk_valid, db->dqb_valid, "QIF_???");
104# else
105	printf(", ...");
106# endif /* !VERBOSE */
107	printf("}");
108}
109
110void
111print_nextdqblk(long rc, void *ptr, void *arg)
112{
113	struct if_nextdqblk *db = ptr;
114	long out_arg = (long) arg;
115
116	if (((rc != 0) && out_arg) || (out_arg > 1)) {
117		printf("%p", db);
118		return;
119	}
120
121	PRINT_FIELD_U("{", *db, dqb_bhardlimit);
122	PRINT_FIELD_U(", ", *db, dqb_bsoftlimit);
123	PRINT_FIELD_U(", ", *db, dqb_curspace);
124	PRINT_FIELD_U(", ", *db, dqb_ihardlimit);
125	PRINT_FIELD_U(", ", *db, dqb_isoftlimit);
126	PRINT_FIELD_U(", ", *db, dqb_curinodes);
127
128# if VERBOSE
129	PRINT_FIELD_U(", ", *db, dqb_btime);
130	PRINT_FIELD_U(", ", *db, dqb_itime);
131
132	printf(", dqb_valid=");
133	printflags(if_dqblk_valid, db->dqb_valid, "QIF_???");
134
135	PRINT_FIELD_U(", ", *db, dqb_id);
136# else
137	PRINT_FIELD_U(", ", *db, dqb_id);
138	printf(", ...");
139# endif /* !VERBOSE */
140	printf("}");
141}
142
143void
144print_dqinfo(long rc, void *ptr, void *arg)
145{
146	struct if_dqinfo *di = ptr;
147	long out_arg = (long) arg;
148
149	if (((rc != 0) && out_arg) || (out_arg > 1)) {
150		printf("%p", di);
151		return;
152	}
153
154	PRINT_FIELD_U("{", *di, dqi_bgrace);
155	PRINT_FIELD_U(", ", *di, dqi_igrace);
156
157	printf(", dqi_flags=");
158	printflags(if_dqinfo_flags, di->dqi_flags, "DQF_???");
159	printf(", dqi_valid=");
160	printflags(if_dqinfo_valid, di->dqi_valid, "IIF_???");
161	printf("}");
162}
163
164
165int
166main(void)
167{
168	char *bogus_special = (char *) tail_alloc(1) + 1;
169	void *bogus_addr = (char *) tail_alloc(1) + 1;
170
171	char bogus_special_str[sizeof(void *) * 2 + sizeof("0x")];
172	char unterminated_str[sizeof(void *) * 2 + sizeof("0x")];
173
174	long rc;
175	char *unterminated = tail_memdup(unterminated_data,
176					 sizeof(unterminated_data));
177	TAIL_ALLOC_OBJECT_CONST_PTR(struct if_dqblk, dqblk);
178	TAIL_ALLOC_OBJECT_CONST_PTR(struct if_dqinfo, dqinfo);
179	TAIL_ALLOC_OBJECT_CONST_PTR(uint32_t, fmt);
180	TAIL_ALLOC_OBJECT_CONST_PTR(struct if_nextdqblk, nextdqblk);
181
182
183	snprintf(bogus_special_str, sizeof(bogus_special_str), "%p",
184		bogus_special);
185	snprintf(unterminated_str, sizeof(unterminated_str), "%p",
186		unterminated);
187
188
189	/* Invalid commands */
190
191	rc = syscall(__NR_quotactl, bogus_cmd, bogus_special, bogus_id,
192		     bogus_addr);
193	printf("quotactl(QCMD(%#x /* Q_??? */, %#x /* ???QUOTA */)"
194	       ", %p, %u, %p) = %s\n",
195	       QCMD_CMD(bogus_cmd), QCMD_TYPE(bogus_cmd),
196	       bogus_special, bogus_id, bogus_addr, sprintrc(rc));
197
198	rc = syscall(__NR_quotactl, 0, NULL, -1, NULL);
199	printf("quotactl(QCMD(0 /* Q_??? */, USRQUOTA), NULL, -1, NULL) = %s\n",
200	       sprintrc(rc));
201
202
203	/* Q_QUOTAON */
204
205	check_quota(CQF_ID_STR | CQF_ADDR_STR,
206		    ARG_STR(QCMD(Q_QUOTAON, USRQUOTA)),
207		    ARG_STR("/dev/bogus/"), ARG_STR(QFMT_VFS_OLD),
208		    ARG_STR("/tmp/bogus/"));
209
210	rc = syscall(__NR_quotactl, QCMD(Q_QUOTAON, 0xfacefeed), bogus_dev,
211		     bogus_id, bogus_addr);
212	printf("quotactl(QCMD(Q_QUOTAON, %#x /* ???QUOTA */)"
213	       ", %s, %#x /* QFMT_VFS_??? */, %p) = %s\n",
214	       QCMD_TYPE(QCMD(Q_QUOTAON, 0xfacefeed)),
215	       bogus_dev_str, bogus_id, bogus_addr, sprintrc(rc));
216
217
218	/* Q_QUOTAOFF */
219
220	check_quota(CQF_ID_SKIP | CQF_ADDR_SKIP,
221		    ARG_STR(QCMD(Q_QUOTAOFF, USRQUOTA)),
222		    bogus_special, bogus_special_str);
223	check_quota(CQF_ID_SKIP | CQF_ADDR_SKIP,
224		    ARG_STR(QCMD(Q_QUOTAOFF, GRPQUOTA)),
225		    ARG_STR("/dev/bogus/"));
226	check_quota(CQF_ID_SKIP | CQF_ADDR_SKIP,
227		    ARG_STR(QCMD(Q_QUOTAOFF, PRJQUOTA)), ARG_STR(NULL));
228	check_quota(CQF_ID_SKIP | CQF_ADDR_SKIP,
229		    QCMD(Q_QUOTAOFF, 3), "QCMD(Q_QUOTAOFF, 0x3 /* ???QUOTA */)",
230		    ARG_STR(NULL));
231
232
233	/* Q_GETQUOTA */
234
235	/* Trying our best to get successful result */
236	check_quota(CQF_ADDR_CB, ARG_STR(QCMD(Q_GETQUOTA, USRQUOTA)),
237		    ARG_STR("/dev/sda1"), getuid(), dqblk, print_dqblk,
238		    (intptr_t) 1);
239
240	check_quota(CQF_ADDR_CB, ARG_STR(QCMD(Q_GETQUOTA, GRPQUOTA)),
241		    ARG_STR(NULL), -1, dqblk, print_dqblk, (intptr_t) 2);
242
243
244	/* Q_GETNEXTQUOTA */
245
246	check_quota(CQF_ADDR_CB, ARG_STR(QCMD(Q_GETNEXTQUOTA, USRQUOTA)),
247		    ARG_STR("/dev/sda1"), 0, nextdqblk, print_nextdqblk,
248		    (intptr_t) 1);
249
250
251	/* Q_SETQUOTA */
252
253	fill_memory(dqblk, sizeof(*dqblk));
254
255	check_quota(CQF_NONE, ARG_STR(QCMD(Q_SETQUOTA, PRJQUOTA)),
256		    bogus_special, bogus_special_str, 0, bogus_addr);
257
258	check_quota(CQF_ADDR_CB, ARG_STR(QCMD(Q_SETQUOTA, PRJQUOTA)),
259		    ARG_STR("/dev/bogus/"), 3141592653U, dqblk, print_dqblk,
260		    (intptr_t) 0);
261
262
263	/* Q_GETINFO */
264
265	check_quota(CQF_ID_SKIP | CQF_ADDR_CB,
266		    ARG_STR(QCMD(Q_GETINFO, GRPQUOTA)),
267		    ARG_STR("/dev/sda1"), dqinfo, print_dqinfo, (intptr_t) 1);
268
269	check_quota(CQF_ID_SKIP | CQF_ADDR_CB,
270		    ARG_STR(QCMD(Q_GETINFO, GRPQUOTA)),
271		    bogus_special, bogus_special_str, dqinfo,
272		    print_dqinfo, (intptr_t) 2);
273
274	/* Q_SETINFO */
275
276	fill_memory(dqinfo, sizeof(*dqinfo));
277	/* In order to check flag printing correctness */
278	dqinfo->dqi_flags = 0xdeadabcd;
279
280	check_quota(CQF_ID_SKIP | CQF_ADDR_STR,
281		    ARG_STR(QCMD(Q_SETINFO, PRJQUOTA)),
282		    bogus_special, bogus_special_str, ARG_STR(NULL));
283
284	check_quota(CQF_ID_SKIP | CQF_ADDR_CB,
285		    ARG_STR(QCMD(Q_SETINFO, USRQUOTA)),
286		    ARG_STR("/dev/bogus/"), dqinfo, print_dqinfo, (intptr_t) 0);
287
288
289	/* Q_GETFMT */
290
291	check_quota(CQF_ID_SKIP | CQF_ADDR_STR,
292		    ARG_STR(QCMD(Q_GETFMT, PRJQUOTA)),
293		    bogus_special, bogus_special_str, ARG_STR(NULL));
294	check_quota(CQF_ID_SKIP,
295		    ARG_STR(QCMD(Q_GETFMT, USRQUOTA)),
296		    unterminated, unterminated_str, fmt + 1);
297	check_quota(CQF_ID_SKIP,
298		    ARG_STR(QCMD(Q_GETFMT, GRPQUOTA)),
299		    ARG_STR("/dev/sda1"), fmt);
300
301
302	/* Q_SYNC */
303
304	check_quota(CQF_ID_SKIP | CQF_ADDR_SKIP,
305		    ARG_STR(QCMD(Q_SYNC, USRQUOTA)),
306		    bogus_special, bogus_special_str);
307	check_quota(CQF_ID_SKIP | CQF_ADDR_SKIP,
308		    QCMD(Q_SYNC, 0xfff), "QCMD(Q_SYNC, 0xff /* ???QUOTA */)",
309		    ARG_STR(NULL));
310
311	puts("+++ exited with 0 +++");
312
313	return 0;
314}
315
316#else
317
318SKIP_MAIN_UNDEFINED("__NR_quotactl && "
319	"(HAVE_LINUX_QUOTA_H || HAVE_SYS_QUOTA_H)");
320
321#endif
322