Home | History | Annotate | Download | only in tests-mx32
      1 /*
      2  * Check decoding of quotactl syscall.
      3  *
      4  * Copyright (c) 2016 Eugene Syromyatnikov <evgsyr (at) gmail.com>
      5  * Copyright (c) 2016 Dmitry V. Levin <ldv (at) 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 
     59 struct 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 
     79 void
     80 print_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 
    109 void
    110 print_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 
    142 void
    143 print_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 
    164 int
    165 main(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 
    317 SKIP_MAIN_UNDEFINED("__NR_quotactl && "
    318 	"(HAVE_LINUX_QUOTA_H || HAVE_SYS_QUOTA_H)");
    319 
    320 #endif
    321