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 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. The name of the author may not be used to endorse or promote products
17 *    derived from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31#include "tests.h"
32
33#include <asm/unistd.h>
34
35#if defined(__NR_quotactl) && \
36	(defined(HAVE_LINUX_QUOTA_H) || defined(HAVE_SYS_QUOTA_H))
37
38# include <inttypes.h>
39# include <stdint.h>
40# include <stdio.h>
41# include <string.h>
42# include <unistd.h>
43
44# include "quotactl.h"
45
46# ifndef HAVE_LINUX_QUOTA_H
47/* Some dirty hacks in order to make sys/quota.h usable as a backup */
48
49#  define if_dqblk dqblk
50#  define if_nextdqblk nextdqblk
51#  define if_dqinfo dqinfo
52
53# endif /* !HAVE_LINUX_QUOTA_H */
54
55# ifndef Q_GETNEXTQUOTA
56
57#  define Q_GETNEXTQUOTA 0x800009
58
59struct if_nextdqblk {
60	uint64_t dqb_bhardlimit;
61	uint64_t dqb_bsoftlimit;
62	uint64_t dqb_curspace;
63	uint64_t dqb_ihardlimit;
64	uint64_t dqb_isoftlimit;
65	uint64_t dqb_curinodes;
66	uint64_t dqb_btime;
67	uint64_t dqb_itime;
68	uint32_t dqb_valid;
69	uint32_t dqb_id;
70};
71# endif /* !Q_GETNEXTQUOTA */
72
73# include "xlat.h"
74# include "xlat/quota_formats.h"
75# include "xlat/if_dqblk_valid.h"
76# include "xlat/if_dqinfo_flags.h"
77# include "xlat/if_dqinfo_valid.h"
78
79void
80print_dqblk(long rc, void *ptr, void *arg)
81{
82	struct if_dqblk *db = ptr;
83	long out_arg = (long) arg;
84
85	if (((rc != 0) && out_arg) || (out_arg > 1)) {
86		printf("%p", db);
87		return;
88	}
89
90	PRINT_FIELD_U("{", db, dqb_bhardlimit);
91	PRINT_FIELD_U(", ", db, dqb_bsoftlimit);
92	PRINT_FIELD_U(", ", db, dqb_curspace);
93	PRINT_FIELD_U(", ", db, dqb_ihardlimit);
94	PRINT_FIELD_U(", ", db, dqb_isoftlimit);
95	PRINT_FIELD_U(", ", db, dqb_curinodes);
96
97# if VERBOSE
98	PRINT_FIELD_U(", ", db, dqb_btime);
99	PRINT_FIELD_U(", ", db, dqb_itime);
100
101	printf(", dqb_valid=");
102	printflags(if_dqblk_valid, db->dqb_valid, "QIF_???");
103# else
104	printf(", ...");
105# endif /* !VERBOSE */
106	printf("}");
107}
108
109void
110print_nextdqblk(long rc, void *ptr, void *arg)
111{
112	struct if_nextdqblk *db = ptr;
113	long out_arg = (long) arg;
114
115	if (((rc != 0) && out_arg) || (out_arg > 1)) {
116		printf("%p", db);
117		return;
118	}
119
120	PRINT_FIELD_U("{", db, dqb_bhardlimit);
121	PRINT_FIELD_U(", ", db, dqb_bsoftlimit);
122	PRINT_FIELD_U(", ", db, dqb_curspace);
123	PRINT_FIELD_U(", ", db, dqb_ihardlimit);
124	PRINT_FIELD_U(", ", db, dqb_isoftlimit);
125	PRINT_FIELD_U(", ", db, dqb_curinodes);
126
127# if VERBOSE
128	PRINT_FIELD_U(", ", db, dqb_btime);
129	PRINT_FIELD_U(", ", db, dqb_itime);
130
131	printf(", dqb_valid=");
132	printflags(if_dqblk_valid, db->dqb_valid, "QIF_???");
133
134	PRINT_FIELD_U(", ", db, dqb_id);
135# else
136	PRINT_FIELD_U(", ", db, dqb_id);
137	printf(", ...");
138# endif /* !VERBOSE */
139	printf("}");
140}
141
142void
143print_dqinfo(long rc, void *ptr, void *arg)
144{
145	struct if_dqinfo *di = ptr;
146	long out_arg = (long) arg;
147
148	if (((rc != 0) && out_arg) || (out_arg > 1)) {
149		printf("%p", di);
150		return;
151	}
152
153	PRINT_FIELD_U("{", di, dqi_bgrace);
154	PRINT_FIELD_U(", ", di, dqi_igrace);
155
156	printf(", dqi_flags=");
157	printflags(if_dqinfo_flags, di->dqi_flags, "DQF_???");
158	printf(", dqi_valid=");
159	printflags(if_dqinfo_valid, di->dqi_valid, "IIF_???");
160	printf("}");
161}
162
163
164int
165main(void)
166{
167	char *bogus_special = (char *) tail_alloc(1) + 1;
168	void *bogus_addr = (char *) tail_alloc(1) + 1;
169
170	char bogus_special_str[sizeof(void *) * 2 + sizeof("0x")];
171	char unterminated_str[sizeof(void *) * 2 + sizeof("0x")];
172
173	long rc;
174	char *unterminated = tail_memdup(unterminated_data,
175					 sizeof(unterminated_data));
176	struct if_dqblk *dqblk = tail_alloc(sizeof(*dqblk));
177	struct if_dqinfo *dqinfo = tail_alloc(sizeof(*dqinfo));
178	uint32_t *fmt = tail_alloc(sizeof(*fmt));
179	struct if_nextdqblk *nextdqblk = tail_alloc(sizeof(*nextdqblk));
180
181
182	snprintf(bogus_special_str, sizeof(bogus_special_str), "%p",
183		bogus_special);
184	snprintf(unterminated_str, sizeof(unterminated_str), "%p",
185		unterminated);
186
187
188	/* Invalid commands */
189
190	rc = syscall(__NR_quotactl, bogus_cmd, bogus_special, bogus_id,
191		     bogus_addr);
192	printf("quotactl(QCMD(%#x /* Q_??? */, %#x /* ???QUOTA */)"
193	       ", %p, %u, %p) = %s\n",
194	       QCMD_CMD(bogus_cmd), QCMD_TYPE(bogus_cmd),
195	       bogus_special, bogus_id, bogus_addr, sprintrc(rc));
196
197	rc = syscall(__NR_quotactl, 0, NULL, -1, NULL);
198	printf("quotactl(QCMD(0 /* Q_??? */, USRQUOTA), NULL, -1, NULL) = %s\n",
199	       sprintrc(rc));
200
201
202	/* Q_QUOTAON */
203
204	check_quota(CQF_ID_STR | CQF_ADDR_STR,
205		    ARG_STR(QCMD(Q_QUOTAON, USRQUOTA)),
206		    ARG_STR("/dev/bogus/"), ARG_STR(QFMT_VFS_OLD),
207		    ARG_STR("/tmp/bogus/"));
208
209	rc = syscall(__NR_quotactl, QCMD(Q_QUOTAON, 0xfacefeed), bogus_dev,
210		     bogus_id, bogus_addr);
211	printf("quotactl(QCMD(Q_QUOTAON, %#x /* ???QUOTA */)"
212	       ", %s, %#x /* QFMT_VFS_??? */, %p) = %s\n",
213	       QCMD_TYPE(QCMD(Q_QUOTAON, 0xfacefeed)),
214	       bogus_dev_str, bogus_id, bogus_addr, sprintrc(rc));
215
216
217	/* Q_QUOTAOFF */
218
219	check_quota(CQF_ID_SKIP | CQF_ADDR_SKIP,
220		    ARG_STR(QCMD(Q_QUOTAOFF, USRQUOTA)),
221		    bogus_special, bogus_special_str);
222	check_quota(CQF_ID_SKIP | CQF_ADDR_SKIP,
223		    ARG_STR(QCMD(Q_QUOTAOFF, GRPQUOTA)),
224		    ARG_STR("/dev/bogus/"));
225	check_quota(CQF_ID_SKIP | CQF_ADDR_SKIP,
226		    ARG_STR(QCMD(Q_QUOTAOFF, PRJQUOTA)), ARG_STR(NULL));
227	check_quota(CQF_ID_SKIP | CQF_ADDR_SKIP,
228		    QCMD(Q_QUOTAOFF, 3), "QCMD(Q_QUOTAOFF, 0x3 /* ???QUOTA */)",
229		    ARG_STR(NULL));
230
231
232	/* Q_GETQUOTA */
233
234	/* Trying our best to get successful result */
235	check_quota(CQF_ADDR_CB, ARG_STR(QCMD(Q_GETQUOTA, USRQUOTA)),
236		    ARG_STR("/dev/sda1"), getuid(), dqblk, print_dqblk,
237		    (intptr_t) 1);
238
239	check_quota(CQF_ADDR_CB, ARG_STR(QCMD(Q_GETQUOTA, GRPQUOTA)),
240		    ARG_STR(NULL), -1, dqblk, print_dqblk, (intptr_t) 2);
241
242
243	/* Q_GETNEXTQUOTA */
244
245	check_quota(CQF_ADDR_CB, ARG_STR(QCMD(Q_GETNEXTQUOTA, USRQUOTA)),
246		    ARG_STR("/dev/sda1"), 0, nextdqblk, print_nextdqblk,
247		    (intptr_t) 1);
248
249
250	/* Q_SETQUOTA */
251
252	fill_memory(dqblk, sizeof(*dqblk));
253
254	check_quota(CQF_NONE, ARG_STR(QCMD(Q_SETQUOTA, PRJQUOTA)),
255		    bogus_special, bogus_special_str, 0, bogus_addr);
256
257	check_quota(CQF_ADDR_CB, ARG_STR(QCMD(Q_SETQUOTA, PRJQUOTA)),
258		    ARG_STR("/dev/bogus/"), 3141592653U, dqblk, print_dqblk,
259		    (intptr_t) 0);
260
261
262	/* Q_GETINFO */
263
264	check_quota(CQF_ID_SKIP | CQF_ADDR_CB,
265		    ARG_STR(QCMD(Q_GETINFO, GRPQUOTA)),
266		    ARG_STR("/dev/sda1"), dqinfo, print_dqinfo, (intptr_t) 1);
267
268	check_quota(CQF_ID_SKIP | CQF_ADDR_CB,
269		    ARG_STR(QCMD(Q_GETINFO, GRPQUOTA)),
270		    bogus_special, bogus_special_str, dqinfo,
271		    print_dqinfo, (intptr_t) 2);
272
273	/* Q_SETINFO */
274
275	fill_memory(dqinfo, sizeof(*dqinfo));
276	/* In order to check flag printing correctness */
277	dqinfo->dqi_flags = 0xdeadabcd;
278
279	check_quota(CQF_ID_SKIP | CQF_ADDR_STR,
280		    ARG_STR(QCMD(Q_SETINFO, PRJQUOTA)),
281		    bogus_special, bogus_special_str, ARG_STR(NULL));
282
283	check_quota(CQF_ID_SKIP | CQF_ADDR_CB,
284		    ARG_STR(QCMD(Q_SETINFO, USRQUOTA)),
285		    ARG_STR("/dev/bogus/"), dqinfo, print_dqinfo, (intptr_t) 0);
286
287
288	/* Q_GETFMT */
289
290	check_quota(CQF_ID_SKIP | CQF_ADDR_STR,
291		    ARG_STR(QCMD(Q_GETFMT, PRJQUOTA)),
292		    bogus_special, bogus_special_str, ARG_STR(NULL));
293	check_quota(CQF_ID_SKIP,
294		    ARG_STR(QCMD(Q_GETFMT, USRQUOTA)),
295		    unterminated, unterminated_str, fmt + 1);
296	check_quota(CQF_ID_SKIP,
297		    ARG_STR(QCMD(Q_GETFMT, GRPQUOTA)),
298		    ARG_STR("/dev/sda1"), fmt);
299
300
301	/* Q_SYNC */
302
303	check_quota(CQF_ID_SKIP | CQF_ADDR_SKIP,
304		    ARG_STR(QCMD(Q_SYNC, USRQUOTA)),
305		    bogus_special, bogus_special_str);
306	check_quota(CQF_ID_SKIP | CQF_ADDR_SKIP,
307		    QCMD(Q_SYNC, 0xfff), "QCMD(Q_SYNC, 0xff /* ???QUOTA */)",
308		    ARG_STR(NULL));
309
310	puts("+++ exited with 0 +++");
311
312	return 0;
313}
314
315#else
316
317SKIP_MAIN_UNDEFINED("__NR_quotactl && "
318	"(HAVE_LINUX_QUOTA_H || HAVE_SYS_QUOTA_H)");
319
320#endif
321