Mirror of strace – the linux syscall tracer
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

quota.c 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440
  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. * SPDX-License-Identifier: LGPL-2.1-or-later
  11. */
  12. #include "defs.h"
  13. #include "print_fields.h"
  14. #include "xfs_quota_stat.h"
  15. #define SUBCMDMASK 0x00ff
  16. #define SUBCMDSHIFT 8
  17. #define QCMD_CMD(cmd) ((uint32_t)(cmd) >> SUBCMDSHIFT)
  18. #define QCMD_TYPE(cmd) ((uint32_t)(cmd) & SUBCMDMASK)
  19. #define OLD_CMD(cmd) ((uint32_t)(cmd) << SUBCMDSHIFT)
  20. #define NEW_CMD(cmd) ((uint32_t)(cmd) | 0x800000)
  21. #define XQM_CMD(cmd) ((uint32_t)(cmd) | ('X' << SUBCMDSHIFT))
  22. #include "xlat/quotacmds.h"
  23. #include "xlat/quotatypes.h"
  24. #include "xlat/quota_formats.h"
  25. #include "xlat/xfs_quota_flags.h"
  26. #include "xlat/xfs_dqblk_flags.h"
  27. #include "xlat/if_dqblk_valid.h"
  28. #include "xlat/if_dqinfo_flags.h"
  29. #include "xlat/if_dqinfo_valid.h"
  30. /*
  31. * We add attribute packed due to the fact that the structure is 8-byte aligned
  32. * on 64-bit systems and therefore has additional 4 bytes of padding, which
  33. * leads to problems when it is used on 32-bit tracee which does not have such
  34. * padding.
  35. */
  36. struct if_dqblk {
  37. uint64_t dqb_bhardlimit;
  38. uint64_t dqb_bsoftlimit;
  39. uint64_t dqb_curspace;
  40. uint64_t dqb_ihardlimit;
  41. uint64_t dqb_isoftlimit;
  42. uint64_t dqb_curinodes;
  43. uint64_t dqb_btime;
  44. uint64_t dqb_itime;
  45. uint32_t dqb_valid;
  46. } ATTRIBUTE_PACKED;
  47. struct if_nextdqblk {
  48. uint64_t dqb_bhardlimit;
  49. uint64_t dqb_bsoftlimit;
  50. uint64_t dqb_curspace;
  51. uint64_t dqb_ihardlimit;
  52. uint64_t dqb_isoftlimit;
  53. uint64_t dqb_curinodes;
  54. uint64_t dqb_btime;
  55. uint64_t dqb_itime;
  56. uint32_t dqb_valid;
  57. uint32_t dqb_id;
  58. };
  59. struct xfs_dqblk {
  60. int8_t d_version; /* version of this structure */
  61. uint8_t d_flags; /* XFS_{USER,PROJ,GROUP}_QUOTA */
  62. uint16_t d_fieldmask; /* field specifier */
  63. uint32_t d_id; /* user, project, or group ID */
  64. uint64_t d_blk_hardlimit; /* absolute limit on disk blks */
  65. uint64_t d_blk_softlimit; /* preferred limit on disk blks */
  66. uint64_t d_ino_hardlimit; /* maximum # allocated inodes */
  67. uint64_t d_ino_softlimit; /* preferred inode limit */
  68. uint64_t d_bcount; /* # disk blocks owned by the user */
  69. uint64_t d_icount; /* # inodes owned by the user */
  70. int32_t d_itimer; /* zero if within inode limits */
  71. int32_t d_btimer; /* similar to above; for disk blocks */
  72. uint16_t d_iwarns; /* # warnings issued wrt num inodes */
  73. uint16_t d_bwarns; /* # warnings issued wrt disk blocks */
  74. int32_t d_padding2; /* padding2 - for future use */
  75. uint64_t d_rtb_hardlimit; /* absolute limit on realtime blks */
  76. uint64_t d_rtb_softlimit; /* preferred limit on RT disk blks */
  77. uint64_t d_rtbcount; /* # realtime blocks owned */
  78. int32_t d_rtbtimer; /* similar to above; for RT disk blks */
  79. uint16_t d_rtbwarns; /* # warnings issued wrt RT disk blks */
  80. int16_t d_padding3; /* padding3 - for future use */
  81. char d_padding4[8]; /* yet more padding */
  82. };
  83. struct if_dqinfo {
  84. uint64_t dqi_bgrace;
  85. uint64_t dqi_igrace;
  86. uint32_t dqi_flags;
  87. uint32_t dqi_valid;
  88. };
  89. struct fs_qfilestatv {
  90. uint64_t qfs_ino, qfs_nblks;
  91. uint32_t qfs_nextents, qfs_pad;
  92. };
  93. struct fs_quota_statv {
  94. int8_t qs_version;
  95. uint8_t qs_pad1;
  96. uint16_t qs_flags;
  97. uint32_t qs_incoredqs;
  98. struct fs_qfilestatv qs_uquota;
  99. struct fs_qfilestatv qs_gquota;
  100. struct fs_qfilestatv qs_pquota;
  101. int32_t qs_btimelimit;
  102. int32_t qs_itimelimit;
  103. int32_t qs_rtbtimelimit;
  104. uint16_t qs_bwarnlimit;
  105. uint16_t qs_iwarnlimit;
  106. uint64_t qs_pad2[8];
  107. };
  108. static int
  109. decode_cmd_data(struct tcb *tcp, uint32_t id, uint32_t cmd, kernel_ulong_t data)
  110. {
  111. switch (cmd) {
  112. case Q_QUOTAOFF:
  113. case Q_SYNC:
  114. case Q_XQUOTASYNC:
  115. break;
  116. case Q_QUOTAON:
  117. tprints(", ");
  118. printxval(quota_formats, id, "QFMT_VFS_???");
  119. tprints(", ");
  120. printpath(tcp, data);
  121. break;
  122. case Q_GETQUOTA:
  123. if (entering(tcp)) {
  124. printuid(", ", id);
  125. tprints(", ");
  126. return 0;
  127. }
  128. ATTRIBUTE_FALLTHROUGH;
  129. case Q_SETQUOTA:
  130. {
  131. struct if_dqblk dq;
  132. if (entering(tcp)) {
  133. printuid(", ", id);
  134. tprints(", ");
  135. }
  136. if (umove_or_printaddr(tcp, data, &dq))
  137. break;
  138. PRINT_FIELD_U("{", dq, dqb_bhardlimit);
  139. PRINT_FIELD_U(", ", dq, dqb_bsoftlimit);
  140. PRINT_FIELD_U(", ", dq, dqb_curspace);
  141. PRINT_FIELD_U(", ", dq, dqb_ihardlimit);
  142. PRINT_FIELD_U(", ", dq, dqb_isoftlimit);
  143. PRINT_FIELD_U(", ", dq, dqb_curinodes);
  144. if (!abbrev(tcp)) {
  145. PRINT_FIELD_U(", ", dq, dqb_btime);
  146. PRINT_FIELD_U(", ", dq, dqb_itime);
  147. PRINT_FIELD_FLAGS(", ", dq, dqb_valid,
  148. if_dqblk_valid, "QIF_???");
  149. } else {
  150. tprints(", ...");
  151. }
  152. tprints("}");
  153. break;
  154. }
  155. case Q_GETNEXTQUOTA:
  156. {
  157. struct if_nextdqblk dq;
  158. if (entering(tcp)) {
  159. printuid(", ", id);
  160. tprints(", ");
  161. return 0;
  162. }
  163. if (umove_or_printaddr(tcp, data, &dq))
  164. break;
  165. PRINT_FIELD_U("{", dq, dqb_bhardlimit);
  166. PRINT_FIELD_U(", ", dq, dqb_bsoftlimit);
  167. PRINT_FIELD_U(", ", dq, dqb_curspace);
  168. PRINT_FIELD_U(", ", dq, dqb_ihardlimit);
  169. PRINT_FIELD_U(", ", dq, dqb_isoftlimit);
  170. PRINT_FIELD_U(", ", dq, dqb_curinodes);
  171. if (!abbrev(tcp)) {
  172. PRINT_FIELD_U(", ", dq, dqb_btime);
  173. PRINT_FIELD_U(", ", dq, dqb_itime);
  174. PRINT_FIELD_FLAGS(", ", dq, dqb_valid,
  175. if_dqblk_valid, "QIF_???");
  176. PRINT_FIELD_U(", ", dq, dqb_id);
  177. } else {
  178. PRINT_FIELD_U(", ", dq, dqb_id);
  179. tprints(", ...");
  180. }
  181. tprints("}");
  182. break;
  183. }
  184. case Q_XGETQUOTA:
  185. case Q_XGETNEXTQUOTA:
  186. if (entering(tcp)) {
  187. printuid(", ", id);
  188. tprints(", ");
  189. return 0;
  190. }
  191. ATTRIBUTE_FALLTHROUGH;
  192. case Q_XSETQLIM:
  193. {
  194. struct xfs_dqblk dq;
  195. if (entering(tcp)) {
  196. printuid(", ", id);
  197. tprints(", ");
  198. }
  199. if (umove_or_printaddr(tcp, data, &dq))
  200. break;
  201. PRINT_FIELD_D("{", dq, d_version);
  202. PRINT_FIELD_FLAGS(", ", dq, d_flags,
  203. xfs_dqblk_flags, "XFS_???_QUOTA");
  204. PRINT_FIELD_X(", ", dq, d_fieldmask);
  205. PRINT_FIELD_U(", ", dq, d_id);
  206. PRINT_FIELD_U(", ", dq, d_blk_hardlimit);
  207. PRINT_FIELD_U(", ", dq, d_blk_softlimit);
  208. PRINT_FIELD_U(", ", dq, d_ino_hardlimit);
  209. PRINT_FIELD_U(", ", dq, d_ino_softlimit);
  210. PRINT_FIELD_U(", ", dq, d_bcount);
  211. PRINT_FIELD_U(", ", dq, d_icount);
  212. if (!abbrev(tcp)) {
  213. PRINT_FIELD_D(", ", dq, d_itimer);
  214. PRINT_FIELD_D(", ", dq, d_btimer);
  215. PRINT_FIELD_U(", ", dq, d_iwarns);
  216. PRINT_FIELD_U(", ", dq, d_bwarns);
  217. PRINT_FIELD_U(", ", dq, d_rtb_hardlimit);
  218. PRINT_FIELD_U(", ", dq, d_rtb_softlimit);
  219. PRINT_FIELD_U(", ", dq, d_rtbcount);
  220. PRINT_FIELD_D(", ", dq, d_rtbtimer);
  221. PRINT_FIELD_U(", ", dq, d_rtbwarns);
  222. } else {
  223. tprints(", ...");
  224. }
  225. tprints("}");
  226. break;
  227. }
  228. case Q_GETFMT:
  229. {
  230. uint32_t fmt;
  231. if (entering(tcp)) {
  232. tprints(", ");
  233. return 0;
  234. }
  235. if (umove_or_printaddr(tcp, data, &fmt))
  236. break;
  237. tprints("[");
  238. printxval(quota_formats, fmt, "QFMT_VFS_???");
  239. tprints("]");
  240. break;
  241. }
  242. case Q_GETINFO:
  243. if (entering(tcp)) {
  244. tprints(", ");
  245. return 0;
  246. }
  247. ATTRIBUTE_FALLTHROUGH;
  248. case Q_SETINFO:
  249. {
  250. struct if_dqinfo dq;
  251. if (entering(tcp))
  252. tprints(", ");
  253. if (umove_or_printaddr(tcp, data, &dq))
  254. break;
  255. PRINT_FIELD_U("{", dq, dqi_bgrace);
  256. PRINT_FIELD_U(", ", dq, dqi_igrace);
  257. PRINT_FIELD_FLAGS(", ", dq, dqi_flags, if_dqinfo_flags, "DQF_???");
  258. PRINT_FIELD_FLAGS(", ", dq, dqi_valid, if_dqinfo_valid, "IIF_???");
  259. tprints("}");
  260. break;
  261. }
  262. case Q_XGETQSTAT:
  263. {
  264. struct xfs_dqstats dq;
  265. if (entering(tcp)) {
  266. tprints(", ");
  267. return 0;
  268. }
  269. if (fetch_struct_quotastat(tcp, data, &dq)) {
  270. PRINT_FIELD_D("{", dq, qs_version);
  271. if (!abbrev(tcp)) {
  272. PRINT_FIELD_FLAGS(", ", dq, qs_flags,
  273. xfs_quota_flags, "XFS_QUOTA_???");
  274. PRINT_FIELD_U(", qs_uquota={", dq.qs_uquota, qfs_ino);
  275. PRINT_FIELD_U(", ", dq.qs_uquota, qfs_nblks);
  276. PRINT_FIELD_U(", ", dq.qs_uquota, qfs_nextents);
  277. PRINT_FIELD_U("}, qs_gquota={", dq.qs_gquota, qfs_ino);
  278. PRINT_FIELD_U(", ", dq.qs_gquota, qfs_nblks);
  279. PRINT_FIELD_U(", ", dq.qs_gquota, qfs_nextents);
  280. PRINT_FIELD_U("}, ", dq, qs_incoredqs);
  281. PRINT_FIELD_D(", ", dq, qs_btimelimit);
  282. PRINT_FIELD_D(", ", dq, qs_itimelimit);
  283. PRINT_FIELD_D(", ", dq, qs_rtbtimelimit);
  284. PRINT_FIELD_U(", ", dq, qs_bwarnlimit);
  285. PRINT_FIELD_U(", ", dq, qs_iwarnlimit);
  286. } else {
  287. tprints(", ...");
  288. }
  289. tprints("}");
  290. }
  291. break;
  292. }
  293. case Q_XGETQSTATV:
  294. {
  295. struct fs_quota_statv dq;
  296. if (entering(tcp)) {
  297. tprints(", ");
  298. return 0;
  299. }
  300. if (umove_or_printaddr(tcp, data, &dq))
  301. break;
  302. PRINT_FIELD_D("{", dq, qs_version);
  303. if (!abbrev(tcp)) {
  304. PRINT_FIELD_FLAGS(", ", dq, qs_flags,
  305. xfs_quota_flags, "XFS_QUOTA_???");
  306. PRINT_FIELD_U(", ", dq, qs_incoredqs);
  307. PRINT_FIELD_U(", qs_uquota={", dq.qs_uquota, qfs_ino);
  308. PRINT_FIELD_U(", ", dq.qs_uquota, qfs_nblks);
  309. PRINT_FIELD_U(", ", dq.qs_uquota, qfs_nextents);
  310. PRINT_FIELD_U("}, qs_gquota={", dq.qs_gquota, qfs_ino);
  311. PRINT_FIELD_U(", ", dq.qs_gquota, qfs_nblks);
  312. PRINT_FIELD_U(", ", dq.qs_gquota, qfs_nextents);
  313. PRINT_FIELD_U("}, qs_pquota={", dq.qs_pquota, qfs_ino);
  314. PRINT_FIELD_U(", ", dq.qs_pquota, qfs_nblks);
  315. PRINT_FIELD_U(", ", dq.qs_pquota, qfs_nextents);
  316. PRINT_FIELD_D("}, ", dq, qs_btimelimit);
  317. PRINT_FIELD_D(", ", dq, qs_itimelimit);
  318. PRINT_FIELD_D(", ", dq, qs_rtbtimelimit);
  319. PRINT_FIELD_U(", ", dq, qs_bwarnlimit);
  320. PRINT_FIELD_U(", ", dq, qs_iwarnlimit);
  321. } else {
  322. tprints(", ...");
  323. }
  324. tprints("}");
  325. break;
  326. }
  327. case Q_XQUOTAON:
  328. case Q_XQUOTAOFF:
  329. {
  330. uint32_t flag;
  331. tprints(", ");
  332. if (umove_or_printaddr(tcp, data, &flag))
  333. break;
  334. tprints("[");
  335. printflags(xfs_quota_flags, flag, "XFS_QUOTA_???");
  336. tprints("]");
  337. break;
  338. }
  339. case Q_XQUOTARM:
  340. {
  341. uint32_t flag;
  342. tprints(", ");
  343. if (umove_or_printaddr(tcp, data, &flag))
  344. break;
  345. tprints("[");
  346. printflags(xfs_dqblk_flags, flag, "XFS_???_QUOTA");
  347. tprints("]");
  348. break;
  349. }
  350. default:
  351. printuid(", ", id);
  352. tprints(", ");
  353. printaddr(data);
  354. break;
  355. }
  356. return RVAL_DECODED;
  357. }
  358. static void
  359. print_qcmd(const uint32_t qcmd)
  360. {
  361. const uint32_t cmd = QCMD_CMD(qcmd);
  362. const uint32_t type = QCMD_TYPE(qcmd);
  363. if (xlat_verbose(xlat_verbosity) != XLAT_STYLE_ABBREV)
  364. tprintf("%u", qcmd);
  365. if (xlat_verbose(xlat_verbosity) == XLAT_STYLE_RAW)
  366. return;
  367. if (xlat_verbose(xlat_verbosity) == XLAT_STYLE_VERBOSE)
  368. tprints(" /* ");
  369. tprints("QCMD(");
  370. printxvals_ex(cmd, "Q_???", XLAT_STYLE_ABBREV, quotacmds, NULL);
  371. tprints(", ");
  372. printxvals_ex(type, "???QUOTA", XLAT_STYLE_ABBREV, quotatypes, NULL);
  373. tprints(")");
  374. if (xlat_verbose(xlat_verbosity) == XLAT_STYLE_VERBOSE)
  375. tprints(" */");
  376. }
  377. SYS_FUNC(quotactl)
  378. {
  379. /*
  380. * The Linux kernel only looks at the low 32 bits of command and id
  381. * arguments, but on some 64-bit architectures (s390x) this word
  382. * will have been sign-extended when we see it. The high 1 bits
  383. * don't mean anything, so don't confuse the output with them.
  384. */
  385. uint32_t qcmd = tcp->u_arg[0];
  386. uint32_t cmd = QCMD_CMD(qcmd);
  387. uint32_t id = tcp->u_arg[2];
  388. if (entering(tcp)) {
  389. print_qcmd(qcmd);
  390. tprints(", ");
  391. printpath(tcp, tcp->u_arg[1]);
  392. }
  393. return decode_cmd_data(tcp, id, cmd, tcp->u_arg[3]);
  394. }