(root)/
strace-6.5/
tests/
quotactl.c
       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@strace.io>
       6   * Copyright (c) 2016-2021 The strace developers.
       7   * All rights reserved.
       8   *
       9   * SPDX-License-Identifier: GPL-2.0-or-later
      10   */
      11  
      12  #include "tests.h"
      13  #include "scno.h"
      14  
      15  #include <inttypes.h>
      16  #include <stdint.h>
      17  #include <stdio.h>
      18  #include <string.h>
      19  #include <unistd.h>
      20  
      21  #include "quotactl.h"
      22  
      23  #include "xlat.h"
      24  #include "xlat/quota_formats.h"
      25  #include "xlat/if_dqblk_valid.h"
      26  #include "xlat/if_dqinfo_flags.h"
      27  #include "xlat/if_dqinfo_valid.h"
      28  
      29  #define QUOTA_STR(_arg) (_arg), gen_quotacmd(#_arg, _arg)
      30  #define QUOTA_ID_STR(_arg) (_arg), gen_quotaid(#_arg, _arg)
      31  #define QUOTA_STR_INVALID(_arg, str) (_arg), gen_quotacmd(str, _arg)
      32  
      33  static void
      34  print_dqblk(long rc, void *ptr, void *arg)
      35  {
      36  	struct if_dqblk *db = ptr;
      37  	long out_arg = (long) arg;
      38  
      39  	if (((rc < 0) && out_arg) || (out_arg > 1)) {
      40  		printf("%p", db);
      41  		return;
      42  	}
      43  
      44  	printf("{");
      45  	PRINT_FIELD_U(*db, dqb_bhardlimit);
      46  	printf(", ");
      47  	PRINT_FIELD_U(*db, dqb_bsoftlimit);
      48  	printf(", ");
      49  	PRINT_FIELD_U(*db, dqb_curspace);
      50  	printf(", ");
      51  	PRINT_FIELD_U(*db, dqb_ihardlimit);
      52  	printf(", ");
      53  	PRINT_FIELD_U(*db, dqb_isoftlimit);
      54  	printf(", ");
      55  	PRINT_FIELD_U(*db, dqb_curinodes);
      56  
      57  #if VERBOSE
      58  	printf(", ");
      59  	PRINT_FIELD_U(*db, dqb_btime);
      60  	printf(", ");
      61  	PRINT_FIELD_U(*db, dqb_itime);
      62  
      63  	printf(", dqb_valid=");
      64  	printflags(if_dqblk_valid, db->dqb_valid, "QIF_???");
      65  #else
      66  	printf(", ...");
      67  #endif /* !VERBOSE */
      68  	printf("}");
      69  }
      70  
      71  static void
      72  print_nextdqblk(long rc, void *ptr, void *arg)
      73  {
      74  	struct if_nextdqblk *db = ptr;
      75  	long out_arg = (long) arg;
      76  
      77  	if (((rc < 0) && out_arg) || (out_arg > 1)) {
      78  		printf("%p", db);
      79  		return;
      80  	}
      81  
      82  	printf("{");
      83  	PRINT_FIELD_U(*db, dqb_bhardlimit);
      84  	printf(", ");
      85  	PRINT_FIELD_U(*db, dqb_bsoftlimit);
      86  	printf(", ");
      87  	PRINT_FIELD_U(*db, dqb_curspace);
      88  	printf(", ");
      89  	PRINT_FIELD_U(*db, dqb_ihardlimit);
      90  	printf(", ");
      91  	PRINT_FIELD_U(*db, dqb_isoftlimit);
      92  	printf(", ");
      93  	PRINT_FIELD_U(*db, dqb_curinodes);
      94  
      95  #if VERBOSE
      96  	printf(", ");
      97  	PRINT_FIELD_U(*db, dqb_btime);
      98  	printf(", ");
      99  	PRINT_FIELD_U(*db, dqb_itime);
     100  
     101  	printf(", dqb_valid=");
     102  	printflags(if_dqblk_valid, db->dqb_valid, "QIF_???");
     103  
     104  	printf(", ");
     105  	PRINT_FIELD_U(*db, dqb_id);
     106  #else
     107  	printf(", ");
     108  	PRINT_FIELD_U(*db, dqb_id);
     109  	printf(", ...");
     110  #endif /* !VERBOSE */
     111  	printf("}");
     112  }
     113  
     114  static void
     115  print_dqinfo(long rc, void *ptr, void *arg)
     116  {
     117  	struct if_dqinfo *di = ptr;
     118  	long out_arg = (long) arg;
     119  
     120  	if (((rc < 0) && out_arg) || (out_arg > 1)) {
     121  		printf("%p", di);
     122  		return;
     123  	}
     124  
     125  	printf("{");
     126  	PRINT_FIELD_U(*di, dqi_bgrace);
     127  	printf(", ");
     128  	PRINT_FIELD_U(*di, dqi_igrace);
     129  
     130  	printf(", dqi_flags=");
     131  #if XLAT_RAW
     132  	printf("%#x", di->dqi_flags);
     133  #elif XLAT_VERBOSE
     134  	printf("%#x /* ", di->dqi_flags);
     135  	printflags(if_dqinfo_flags, di->dqi_flags, "DQF_???");
     136  	printf(" */");
     137  #else /* XLAT_ABBREV */
     138  	printflags(if_dqinfo_flags, di->dqi_flags, "DQF_???");
     139  #endif
     140  	printf(", dqi_valid=");
     141  #if XLAT_RAW
     142  	printf("%#x", di->dqi_valid);
     143  #elif XLAT_VERBOSE
     144  	printf("%#x /* ", di->dqi_valid);
     145  	printflags(if_dqinfo_valid, di->dqi_valid, "IIF_???");
     146  	printf(" */");
     147  #else /* XLAT_ABBREV */
     148  	printflags(if_dqinfo_valid, di->dqi_valid, "IIF_???");
     149  #endif
     150  	printf("}");
     151  }
     152  
     153  static void
     154  print_dqfmt(long rc, void *ptr, void *arg)
     155  {
     156  	uint32_t *fmtval = ptr;
     157  	long out_arg = (long) arg;
     158  	const char *fmtstr;
     159  
     160  	if (((rc < 0) && out_arg) || (out_arg > 1)) {
     161  		printf("%p", fmtval);
     162  		return;
     163  	}
     164  	printf("[");
     165  #if XLAT_RAW
     166  	printf("%#x]", *fmtval);
     167  	return;
     168  #else
     169  	switch (*fmtval) {
     170  	case 1:
     171  		fmtstr = "QFMT_VFS_OLD";
     172  		break;
     173  	case 2:
     174  		fmtstr = "QFMT_VFS_V0";
     175  		break;
     176  	case 3:
     177  		fmtstr = "QFMT_OCFS2";
     178  		break;
     179  	case 4:
     180  		fmtstr = "QFMT_VFS_V1";
     181  		break;
     182  	default:
     183  		printf("%#x /* QFMT_VFS_??? */]", *fmtval);
     184  		return;
     185  	}
     186  #endif
     187  #if XLAT_VERBOSE
     188  	printf("%#x /* %s */]", *fmtval, fmtstr);
     189  #else
     190  	printf("%s]", fmtstr);
     191  #endif
     192  }
     193  
     194  static const char *
     195  gen_quotacmd(const char *abbrev_str, const uint32_t cmd)
     196  {
     197  	static char quotacmd_str[2048];
     198  
     199  #if XLAT_RAW
     200  	snprintf(quotacmd_str, sizeof(quotacmd_str), "%u", cmd);
     201  #elif XLAT_VERBOSE
     202  	snprintf(quotacmd_str, sizeof(quotacmd_str), "%u /* %s */", cmd, abbrev_str);
     203  #else
     204  	return abbrev_str;
     205  #endif
     206  	return quotacmd_str;
     207  }
     208  
     209  static const char *
     210  gen_quotaid(const char *abbrev_str, const uint32_t id)
     211  {
     212  	static char quotaid_str[1024];
     213  
     214  #if XLAT_RAW
     215  	snprintf(quotaid_str, sizeof(quotaid_str), "%#x", id);
     216  #elif XLAT_VERBOSE
     217  	snprintf(quotaid_str, sizeof(quotaid_str), "%#x /* %s */", id, abbrev_str);
     218  #else
     219  	return abbrev_str;
     220  #endif
     221  	return quotaid_str;
     222  }
     223  
     224  int
     225  main(void)
     226  {
     227  	char *bogus_special = (char *) tail_alloc(1) + 1;
     228  	void *bogus_addr = (char *) tail_alloc(1) + 1;
     229  
     230  	char bogus_special_str[sizeof(void *) * 2 + sizeof("0x")];
     231  	char unterminated_str[sizeof(void *) * 2 + sizeof("0x")];
     232  
     233  	static char invalid_cmd_str[1024];
     234  	static char invalid_id_str[1024];
     235  	char *unterminated = tail_memdup(unterminated_data,
     236  					 sizeof(unterminated_data));
     237  	TAIL_ALLOC_OBJECT_CONST_PTR(struct if_dqblk, dqblk);
     238  	TAIL_ALLOC_OBJECT_CONST_PTR(struct if_dqinfo, dqinfo);
     239  	TAIL_ALLOC_OBJECT_CONST_PTR(uint32_t, fmt);
     240  	TAIL_ALLOC_OBJECT_CONST_PTR(struct if_nextdqblk, nextdqblk);
     241  
     242  	snprintf(bogus_special_str, sizeof(bogus_special_str), "%p",
     243  		bogus_special);
     244  	snprintf(unterminated_str, sizeof(unterminated_str), "%p",
     245  		unterminated);
     246  
     247  
     248  	/* Invalid commands */
     249  	snprintf(invalid_cmd_str, sizeof(invalid_cmd_str),
     250  		 "QCMD(%#x /* Q_??? */, %#x /* ???QUOTA */)",
     251  		 QCMD_CMD(bogus_cmd), QCMD_TYPE(bogus_cmd));
     252  	check_quota(CQF_NONE, bogus_cmd, gen_quotacmd(invalid_cmd_str, bogus_cmd),
     253  		    bogus_special, bogus_special_str, bogus_id, bogus_addr);
     254  
     255  	snprintf(invalid_cmd_str, sizeof(invalid_cmd_str),
     256  		 "QCMD(0 /* Q_??? */, USRQUOTA)");
     257  	check_quota(CQF_ADDR_STR, 0, gen_quotacmd(invalid_cmd_str, 0),
     258  		    ARG_STR(NULL), -1, ARG_STR(NULL));
     259  
     260  
     261  	/* Q_QUOTAON */
     262  
     263  	check_quota(CQF_ID_STR | CQF_ADDR_STR,
     264  		    QUOTA_STR(QCMD(Q_QUOTAON, USRQUOTA)),
     265  		    ARG_STR("/dev/bogus/"), QUOTA_ID_STR(QFMT_VFS_OLD),
     266  		    ARG_STR("/tmp/bogus/"));
     267  
     268  	snprintf(invalid_cmd_str, sizeof(invalid_cmd_str),
     269  		 "QCMD(Q_QUOTAON, %#x /* ???QUOTA */)",
     270  		 QCMD_TYPE(QCMD(Q_QUOTAON, 0xfacefeed)));
     271  #if XLAT_RAW
     272  	snprintf(invalid_id_str, sizeof(invalid_id_str),
     273  		 "%#x", bogus_id);
     274  #else
     275  	snprintf(invalid_id_str, sizeof(invalid_id_str),
     276  		 "%#x /* QFMT_VFS_??? */", bogus_id);
     277  #endif
     278  	check_quota(CQF_ID_STR, QCMD(Q_QUOTAON, 0xfacefeed),
     279  		    gen_quotacmd(invalid_cmd_str, QCMD(Q_QUOTAON, 0xfacefeed)),
     280  		    bogus_dev, bogus_dev_str,
     281  		    bogus_id, invalid_id_str, bogus_addr);
     282  
     283  
     284  	/* Q_QUOTAOFF */
     285  
     286  	check_quota(CQF_ID_SKIP | CQF_ADDR_SKIP,
     287  		    QUOTA_STR(QCMD(Q_QUOTAOFF, USRQUOTA)),
     288  		    bogus_special, bogus_special_str);
     289  	check_quota(CQF_ID_SKIP | CQF_ADDR_SKIP,
     290  		    QUOTA_STR(QCMD(Q_QUOTAOFF, GRPQUOTA)),
     291  		    ARG_STR("/dev/bogus/"));
     292  	check_quota(CQF_ID_SKIP | CQF_ADDR_SKIP,
     293  		    QUOTA_STR(QCMD(Q_QUOTAOFF, PRJQUOTA)), ARG_STR(NULL));
     294  	const char *cmd_str = "QCMD(Q_QUOTAOFF, 0x3 /* ???QUOTA */)";
     295  	check_quota(CQF_ID_SKIP | CQF_ADDR_SKIP,
     296  		    QUOTA_STR_INVALID(QCMD(Q_QUOTAOFF, 3), cmd_str),
     297  		    ARG_STR(NULL));
     298  
     299  
     300  	/* Q_GETQUOTA */
     301  
     302  	/* Trying our best to get successful result */
     303  	check_quota(CQF_ADDR_CB, QUOTA_STR(QCMD(Q_GETQUOTA, USRQUOTA)),
     304  		    ARG_STR("/dev/sda1"), getuid(), dqblk, print_dqblk,
     305  		    (intptr_t) 1);
     306  
     307  	check_quota(CQF_ADDR_CB, QUOTA_STR(QCMD(Q_GETQUOTA, GRPQUOTA)),
     308  		    ARG_STR(NULL), -1, dqblk, print_dqblk, (intptr_t) 1);
     309  
     310  
     311  	/* Q_GETNEXTQUOTA */
     312  
     313  	check_quota(CQF_ADDR_CB, QUOTA_STR(QCMD(Q_GETNEXTQUOTA, USRQUOTA)),
     314  		    ARG_STR("/dev/sda1"), 0, nextdqblk, print_nextdqblk,
     315  		    (intptr_t) 1);
     316  
     317  
     318  	/* Q_SETQUOTA */
     319  
     320  	fill_memory(dqblk, sizeof(*dqblk));
     321  
     322  	check_quota(CQF_NONE, QUOTA_STR(QCMD(Q_SETQUOTA, PRJQUOTA)),
     323  		    bogus_special, bogus_special_str, 0, bogus_addr);
     324  
     325  	check_quota(CQF_ADDR_CB, QUOTA_STR(QCMD(Q_SETQUOTA, PRJQUOTA)),
     326  		    ARG_STR("/dev/bogus/"), 3141592653U, dqblk, print_dqblk,
     327  		    (intptr_t) 0);
     328  
     329  
     330  	/* Q_GETINFO */
     331  
     332  	check_quota(CQF_ID_SKIP | CQF_ADDR_CB,
     333  		    QUOTA_STR(QCMD(Q_GETINFO, GRPQUOTA)),
     334  		    ARG_STR("/dev/sda1"), dqinfo, print_dqinfo, (intptr_t) 1);
     335  
     336  	check_quota(CQF_ID_SKIP | CQF_ADDR_CB,
     337  		    QUOTA_STR(QCMD(Q_GETINFO, GRPQUOTA)),
     338  		    bogus_special, bogus_special_str, dqinfo,
     339  		    print_dqinfo, (intptr_t) 1);
     340  
     341  	/* Q_SETINFO */
     342  
     343  	fill_memory(dqinfo, sizeof(*dqinfo));
     344  	/* In order to check flag printing correctness */
     345  	dqinfo->dqi_flags = 0xdeadabcd;
     346  
     347  	check_quota(CQF_ID_SKIP | CQF_ADDR_STR,
     348  		    QUOTA_STR(QCMD(Q_SETINFO, PRJQUOTA)),
     349  		    bogus_special, bogus_special_str, ARG_STR(NULL));
     350  
     351  	check_quota(CQF_ID_SKIP | CQF_ADDR_CB,
     352  		    QUOTA_STR(QCMD(Q_SETINFO, USRQUOTA)),
     353  		    ARG_STR("/dev/bogus/"), dqinfo, print_dqinfo, (intptr_t) 0);
     354  
     355  
     356  	/* Q_GETFMT */
     357  
     358  	check_quota(CQF_ID_SKIP | CQF_ADDR_STR,
     359  		    QUOTA_STR(QCMD(Q_GETFMT, PRJQUOTA)),
     360  		    bogus_special, bogus_special_str, ARG_STR(NULL));
     361  	check_quota(CQF_ID_SKIP,
     362  		    QUOTA_STR(QCMD(Q_GETFMT, USRQUOTA)),
     363  		    unterminated, unterminated_str, fmt + 1);
     364  	check_quota(CQF_ID_SKIP | CQF_ADDR_CB,
     365  		    QUOTA_STR(QCMD(Q_GETFMT, GRPQUOTA)),
     366  		    ARG_STR("/dev/sda1"), fmt, print_dqfmt, (uintptr_t) 1);
     367  	/* Try to check valid quota format */
     368  	*fmt = QFMT_VFS_OLD;
     369  	check_quota(CQF_ID_SKIP | CQF_ADDR_CB,
     370  		    QUOTA_STR(QCMD(Q_GETFMT, GRPQUOTA)),
     371  		    ARG_STR("/dev/sda1"), fmt, print_dqfmt, (uintptr_t) 1);
     372  
     373  
     374  	/* Q_SYNC */
     375  
     376  	check_quota(CQF_ID_SKIP | CQF_ADDR_SKIP,
     377  		    QUOTA_STR(QCMD(Q_SYNC, USRQUOTA)),
     378  		    bogus_special, bogus_special_str);
     379  	cmd_str = "QCMD(Q_SYNC, 0xff /* ???QUOTA */)";
     380  	check_quota(CQF_ID_SKIP | CQF_ADDR_SKIP,
     381  		    QUOTA_STR_INVALID(QCMD(Q_SYNC, 0xfff), cmd_str),
     382  		    ARG_STR(NULL));
     383  
     384  	puts("+++ exited with 0 +++");
     385  
     386  	return 0;
     387  }