1 /* 2 * Copyright (c) 1991, 1992 Paul Kranenburg <pk (at) cs.few.eur.nl> 3 * Copyright (c) 1993 Branko Lankester <branko (at) hacktic.nl> 4 * Copyright (c) 1993, 1994, 1995, 1996 Rick Sladkey <jrs (at) world.std.com> 5 * Copyright (c) 1996-1999 Wichert Akkerman <wichert (at) cistron.nl> 6 * Copyright (c) 2005, 2006 Dmitry V. Levin <ldv (at) altlinux.org> 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 "defs.h" 33 34 #define SUBCMDMASK 0x00ff 35 #define SUBCMDSHIFT 8 36 #define QCMD_CMD(cmd) ((u_int32_t)(cmd) >> SUBCMDSHIFT) 37 #define QCMD_TYPE(cmd) ((u_int32_t)(cmd) & SUBCMDMASK) 38 39 #define OLD_CMD(cmd) ((u_int32_t)(cmd) << 8) 40 #define NEW_CMD(cmd) ((u_int32_t)(cmd) | 0x800000) 41 #define XQM_CMD(cmd) ((u_int32_t)(cmd) | ('X'<<8)) 42 43 #define Q_V1_QUOTAON OLD_CMD(0x1) 44 #define Q_V1_QUOTAOFF OLD_CMD(0x2) 45 #define Q_V1_GETQUOTA OLD_CMD(0x3) 46 #define Q_V1_SETQUOTA OLD_CMD(0x4) 47 #define Q_V1_SETUSE OLD_CMD(0x5) 48 #define Q_V1_SYNC OLD_CMD(0x6) 49 #define Q_SETQLIM OLD_CMD(0x7) 50 #define Q_V1_GETSTATS OLD_CMD(0x8) 51 #define Q_V1_RSQUASH OLD_CMD(0x10) 52 53 #define Q_V2_GETQUOTA OLD_CMD(0xD) 54 #define Q_V2_SETQUOTA OLD_CMD(0xE) 55 #define Q_V2_SETUSE OLD_CMD(0xF) 56 #define Q_V2_GETINFO OLD_CMD(0x9) 57 #define Q_V2_SETINFO OLD_CMD(0xA) 58 #define Q_V2_SETGRACE OLD_CMD(0xB) 59 #define Q_V2_SETFLAGS OLD_CMD(0xC) 60 #define Q_V2_GETSTATS OLD_CMD(0x11) 61 62 #define Q_SYNC NEW_CMD(0x1) 63 #define Q_QUOTAON NEW_CMD(0x2) 64 #define Q_QUOTAOFF NEW_CMD(0x3) 65 #define Q_GETFMT NEW_CMD(0x4) 66 #define Q_GETINFO NEW_CMD(0x5) 67 #define Q_SETINFO NEW_CMD(0x6) 68 #define Q_GETQUOTA NEW_CMD(0x7) 69 #define Q_SETQUOTA NEW_CMD(0x8) 70 71 #define Q_XQUOTAON XQM_CMD(0x1) 72 #define Q_XQUOTAOFF XQM_CMD(0x2) 73 #define Q_XGETQUOTA XQM_CMD(0x3) 74 #define Q_XSETQLIM XQM_CMD(0x4) 75 #define Q_XGETQSTAT XQM_CMD(0x5) 76 #define Q_XQUOTARM XQM_CMD(0x6) 77 #define Q_XQUOTASYNC XQM_CMD(0x7) 78 79 #include "xlat/quotacmds.h" 80 81 #define USRQUOTA 0 82 #define GRPQUOTA 1 83 84 #include "xlat/quotatypes.h" 85 86 /* Quota format identifiers */ 87 #define QFMT_VFS_OLD 1 88 #define QFMT_VFS_V0 2 89 90 #include "xlat/quota_formats.h" 91 92 #define XFS_QUOTA_UDQ_ACCT (1<<0) /* user quota accounting */ 93 #define XFS_QUOTA_UDQ_ENFD (1<<1) /* user quota limits enforcement */ 94 #define XFS_QUOTA_GDQ_ACCT (1<<2) /* group quota accounting */ 95 #define XFS_QUOTA_GDQ_ENFD (1<<3) /* group quota limits enforcement */ 96 97 #define XFS_USER_QUOTA (1<<0) /* user quota type */ 98 #define XFS_PROJ_QUOTA (1<<1) /* (IRIX) project quota type */ 99 #define XFS_GROUP_QUOTA (1<<2) /* group quota type */ 100 101 #include "xlat/xfs_quota_flags.h" 102 #include "xlat/xfs_dqblk_flags.h" 103 104 /* 105 * Following flags are used to specify which fields are valid 106 */ 107 #define QIF_BLIMITS 1 108 #define QIF_SPACE 2 109 #define QIF_ILIMITS 4 110 #define QIF_INODES 8 111 #define QIF_BTIME 16 112 #define QIF_ITIME 32 113 114 #include "xlat/if_dqblk_valid.h" 115 116 struct if_dqblk 117 { 118 u_int64_t dqb_bhardlimit; 119 u_int64_t dqb_bsoftlimit; 120 u_int64_t dqb_curspace; 121 u_int64_t dqb_ihardlimit; 122 u_int64_t dqb_isoftlimit; 123 u_int64_t dqb_curinodes; 124 u_int64_t dqb_btime; 125 u_int64_t dqb_itime; 126 u_int32_t dqb_valid; 127 }; 128 129 struct v1_dqblk 130 { 131 u_int32_t dqb_bhardlimit; /* absolute limit on disk blks alloc */ 132 u_int32_t dqb_bsoftlimit; /* preferred limit on disk blks */ 133 u_int32_t dqb_curblocks; /* current block count */ 134 u_int32_t dqb_ihardlimit; /* maximum # allocated inodes */ 135 u_int32_t dqb_isoftlimit; /* preferred inode limit */ 136 u_int32_t dqb_curinodes; /* current # allocated inodes */ 137 time_t dqb_btime; /* time limit for excessive disk use */ 138 time_t dqb_itime; /* time limit for excessive files */ 139 }; 140 141 struct v2_dqblk 142 { 143 unsigned int dqb_ihardlimit; 144 unsigned int dqb_isoftlimit; 145 unsigned int dqb_curinodes; 146 unsigned int dqb_bhardlimit; 147 unsigned int dqb_bsoftlimit; 148 u_int64_t dqb_curspace; 149 time_t dqb_btime; 150 time_t dqb_itime; 151 }; 152 153 struct xfs_dqblk 154 { 155 int8_t d_version; /* version of this structure */ 156 int8_t d_flags; /* XFS_{USER,PROJ,GROUP}_QUOTA */ 157 u_int16_t d_fieldmask; /* field specifier */ 158 u_int32_t d_id; /* user, project, or group ID */ 159 u_int64_t d_blk_hardlimit; /* absolute limit on disk blks */ 160 u_int64_t d_blk_softlimit; /* preferred limit on disk blks */ 161 u_int64_t d_ino_hardlimit; /* maximum # allocated inodes */ 162 u_int64_t d_ino_softlimit; /* preferred inode limit */ 163 u_int64_t d_bcount; /* # disk blocks owned by the user */ 164 u_int64_t d_icount; /* # inodes owned by the user */ 165 int32_t d_itimer; /* zero if within inode limits */ 166 int32_t d_btimer; /* similar to above; for disk blocks */ 167 u_int16_t d_iwarns; /* # warnings issued wrt num inodes */ 168 u_int16_t d_bwarns; /* # warnings issued wrt disk blocks */ 169 int32_t d_padding2; /* padding2 - for future use */ 170 u_int64_t d_rtb_hardlimit; /* absolute limit on realtime blks */ 171 u_int64_t d_rtb_softlimit; /* preferred limit on RT disk blks */ 172 u_int64_t d_rtbcount; /* # realtime blocks owned */ 173 int32_t d_rtbtimer; /* similar to above; for RT disk blks */ 174 u_int16_t d_rtbwarns; /* # warnings issued wrt RT disk blks */ 175 int16_t d_padding3; /* padding3 - for future use */ 176 char d_padding4[8]; /* yet more padding */ 177 }; 178 179 /* 180 * Following flags are used to specify which fields are valid 181 */ 182 #define IIF_BGRACE 1 183 #define IIF_IGRACE 2 184 #define IIF_FLAGS 4 185 186 #include "xlat/if_dqinfo_valid.h" 187 188 struct if_dqinfo 189 { 190 u_int64_t dqi_bgrace; 191 u_int64_t dqi_igrace; 192 u_int32_t dqi_flags; 193 u_int32_t dqi_valid; 194 }; 195 196 struct v2_dqinfo 197 { 198 unsigned int dqi_bgrace; 199 unsigned int dqi_igrace; 200 unsigned int dqi_flags; 201 unsigned int dqi_blocks; 202 unsigned int dqi_free_blk; 203 unsigned int dqi_free_entry; 204 }; 205 206 struct v1_dqstats 207 { 208 u_int32_t lookups; 209 u_int32_t drops; 210 u_int32_t reads; 211 u_int32_t writes; 212 u_int32_t cache_hits; 213 u_int32_t allocated_dquots; 214 u_int32_t free_dquots; 215 u_int32_t syncs; 216 }; 217 218 struct v2_dqstats 219 { 220 u_int32_t lookups; 221 u_int32_t drops; 222 u_int32_t reads; 223 u_int32_t writes; 224 u_int32_t cache_hits; 225 u_int32_t allocated_dquots; 226 u_int32_t free_dquots; 227 u_int32_t syncs; 228 u_int32_t version; 229 }; 230 231 typedef struct fs_qfilestat 232 { 233 u_int64_t qfs_ino; /* inode number */ 234 u_int64_t qfs_nblks; /* number of BBs 512-byte-blks */ 235 u_int32_t qfs_nextents; /* number of extents */ 236 } fs_qfilestat_t; 237 238 struct xfs_dqstats 239 { 240 int8_t qs_version; /* version number for future changes */ 241 u_int16_t qs_flags; /* XFS_QUOTA_{U,P,G}DQ_{ACCT,ENFD} */ 242 int8_t qs_pad; /* unused */ 243 fs_qfilestat_t qs_uquota; /* user quota storage information */ 244 fs_qfilestat_t qs_gquota; /* group quota storage information */ 245 u_int32_t qs_incoredqs; /* number of dquots incore */ 246 int32_t qs_btimelimit; /* limit for blks timer */ 247 int32_t qs_itimelimit; /* limit for inodes timer */ 248 int32_t qs_rtbtimelimit; /* limit for rt blks timer */ 249 u_int16_t qs_bwarnlimit; /* limit for num warnings */ 250 u_int16_t qs_iwarnlimit; /* limit for num warnings */ 251 }; 252 253 static void 254 decode_cmd_data(struct tcb *tcp, u_int32_t cmd, unsigned long data) 255 { 256 switch (cmd) { 257 case Q_GETQUOTA: 258 case Q_SETQUOTA: 259 { 260 struct if_dqblk dq; 261 262 if (umove_or_printaddr(tcp, data, &dq)) 263 break; 264 tprintf("{bhardlimit=%" PRIu64 ", ", dq.dqb_bhardlimit); 265 tprintf("bsoftlimit=%" PRIu64 ", ", dq.dqb_bsoftlimit); 266 tprintf("curspace=%" PRIu64 ", ", dq.dqb_curspace); 267 tprintf("ihardlimit=%" PRIu64 ", ", dq.dqb_ihardlimit); 268 tprintf("isoftlimit=%" PRIu64 ", ", dq.dqb_isoftlimit); 269 tprintf("curinodes=%" PRIu64 ", ", dq.dqb_curinodes); 270 if (!abbrev(tcp)) { 271 tprintf("btime=%" PRIu64 ", ", dq.dqb_btime); 272 tprintf("itime=%" PRIu64 ", ", dq.dqb_itime); 273 tprints("valid="); 274 printflags(if_dqblk_valid, 275 dq.dqb_valid, "QIF_???"); 276 tprints("}"); 277 } else 278 tprints("...}"); 279 break; 280 } 281 case Q_V1_GETQUOTA: 282 case Q_V1_SETQUOTA: 283 { 284 struct v1_dqblk dq; 285 286 if (umove_or_printaddr(tcp, data, &dq)) 287 break; 288 tprintf("{bhardlimit=%u, ", dq.dqb_bhardlimit); 289 tprintf("bsoftlimit=%u, ", dq.dqb_bsoftlimit); 290 tprintf("curblocks=%u, ", dq.dqb_curblocks); 291 tprintf("ihardlimit=%u, ", dq.dqb_ihardlimit); 292 tprintf("isoftlimit=%u, ", dq.dqb_isoftlimit); 293 tprintf("curinodes=%u, ", dq.dqb_curinodes); 294 tprintf("btime=%lu, ", (long) dq.dqb_btime); 295 tprintf("itime=%lu}", (long) dq.dqb_itime); 296 break; 297 } 298 case Q_V2_GETQUOTA: 299 case Q_V2_SETQUOTA: 300 { 301 struct v2_dqblk dq; 302 303 if (umove_or_printaddr(tcp, data, &dq)) 304 break; 305 tprintf("{ihardlimit=%u, ", dq.dqb_ihardlimit); 306 tprintf("isoftlimit=%u, ", dq.dqb_isoftlimit); 307 tprintf("curinodes=%u, ", dq.dqb_curinodes); 308 tprintf("bhardlimit=%u, ", dq.dqb_bhardlimit); 309 tprintf("bsoftlimit=%u, ", dq.dqb_bsoftlimit); 310 tprintf("curspace=%" PRIu64 ", ", dq.dqb_curspace); 311 tprintf("btime=%lu, ", (long) dq.dqb_btime); 312 tprintf("itime=%lu}", (long) dq.dqb_itime); 313 break; 314 } 315 case Q_XGETQUOTA: 316 case Q_XSETQLIM: 317 { 318 struct xfs_dqblk dq; 319 320 if (umove_or_printaddr(tcp, data, &dq)) 321 break; 322 tprintf("{version=%d, ", dq.d_version); 323 tprints("flags="); 324 printflags(xfs_dqblk_flags, 325 dq.d_flags, "XFS_???_QUOTA"); 326 tprintf(", fieldmask=%#x, ", dq.d_fieldmask); 327 tprintf("id=%u, ", dq.d_id); 328 tprintf("blk_hardlimit=%" PRIu64 ", ", dq.d_blk_hardlimit); 329 tprintf("blk_softlimit=%" PRIu64 ", ", dq.d_blk_softlimit); 330 tprintf("ino_hardlimit=%" PRIu64 ", ", dq.d_ino_hardlimit); 331 tprintf("ino_softlimit=%" PRIu64 ", ", dq.d_ino_softlimit); 332 tprintf("bcount=%" PRIu64 ", ", dq.d_bcount); 333 tprintf("icount=%" PRIu64 ", ", dq.d_icount); 334 if (!abbrev(tcp)) { 335 tprintf("itimer=%d, ", dq.d_itimer); 336 tprintf("btimer=%d, ", dq.d_btimer); 337 tprintf("iwarns=%u, ", dq.d_iwarns); 338 tprintf("bwarns=%u, ", dq.d_bwarns); 339 tprintf("rtbcount=%" PRIu64 ", ", dq.d_rtbcount); 340 tprintf("rtbtimer=%d, ", dq.d_rtbtimer); 341 tprintf("rtbwarns=%u}", dq.d_rtbwarns); 342 } else 343 tprints("...}"); 344 break; 345 } 346 case Q_GETFMT: 347 { 348 u_int32_t fmt; 349 350 if (umove_or_printaddr(tcp, data, &fmt)) 351 break; 352 tprints("{"); 353 printxval(quota_formats, fmt, "QFMT_VFS_???"); 354 tprints("}"); 355 break; 356 } 357 case Q_GETINFO: 358 case Q_SETINFO: 359 { 360 struct if_dqinfo dq; 361 362 if (umove_or_printaddr(tcp, data, &dq)) 363 break; 364 tprintf("{bgrace=%" PRIu64 ", ", dq.dqi_bgrace); 365 tprintf("igrace=%" PRIu64 ", ", dq.dqi_igrace); 366 tprintf("flags=%#x, ", dq.dqi_flags); 367 tprints("valid="); 368 printflags(if_dqinfo_valid, dq.dqi_valid, "IIF_???"); 369 tprints("}"); 370 break; 371 } 372 case Q_V2_GETINFO: 373 case Q_V2_SETINFO: 374 { 375 struct v2_dqinfo dq; 376 377 if (umove_or_printaddr(tcp, data, &dq)) 378 break; 379 tprintf("{bgrace=%u, ", dq.dqi_bgrace); 380 tprintf("igrace=%u, ", dq.dqi_igrace); 381 tprintf("flags=%#x, ", dq.dqi_flags); 382 tprintf("blocks=%u, ", dq.dqi_blocks); 383 tprintf("free_blk=%u, ", dq.dqi_free_blk); 384 tprintf("free_entry=%u}", dq.dqi_free_entry); 385 break; 386 } 387 case Q_V1_GETSTATS: 388 { 389 struct v1_dqstats dq; 390 391 if (umove_or_printaddr(tcp, data, &dq)) 392 break; 393 tprintf("{lookups=%u, ", dq.lookups); 394 tprintf("drops=%u, ", dq.drops); 395 tprintf("reads=%u, ", dq.reads); 396 tprintf("writes=%u, ", dq.writes); 397 tprintf("cache_hits=%u, ", dq.cache_hits); 398 tprintf("allocated_dquots=%u, ", dq.allocated_dquots); 399 tprintf("free_dquots=%u, ", dq.free_dquots); 400 tprintf("syncs=%u}", dq.syncs); 401 break; 402 } 403 case Q_V2_GETSTATS: 404 { 405 struct v2_dqstats dq; 406 407 if (umove_or_printaddr(tcp, data, &dq)) 408 break; 409 tprintf("{lookups=%u, ", dq.lookups); 410 tprintf("drops=%u, ", dq.drops); 411 tprintf("reads=%u, ", dq.reads); 412 tprintf("writes=%u, ", dq.writes); 413 tprintf("cache_hits=%u, ", dq.cache_hits); 414 tprintf("allocated_dquots=%u, ", dq.allocated_dquots); 415 tprintf("free_dquots=%u, ", dq.free_dquots); 416 tprintf("syncs=%u, ", dq.syncs); 417 tprintf("version=%u}", dq.version); 418 break; 419 } 420 case Q_XGETQSTAT: 421 { 422 struct xfs_dqstats dq; 423 424 if (umove_or_printaddr(tcp, data, &dq)) 425 break; 426 tprintf("{version=%d, ", dq.qs_version); 427 if (abbrev(tcp)) { 428 tprints("...}"); 429 break; 430 } 431 tprints("flags="); 432 printflags(xfs_quota_flags, 433 dq.qs_flags, "XFS_QUOTA_???"); 434 tprintf(", incoredqs=%u, ", dq.qs_incoredqs); 435 tprintf("u_ino=%" PRIu64 ", ", dq.qs_uquota.qfs_ino); 436 tprintf("u_nblks=%" PRIu64 ", ", dq.qs_uquota.qfs_nblks); 437 tprintf("u_nextents=%u, ", dq.qs_uquota.qfs_nextents); 438 tprintf("g_ino=%" PRIu64 ", ", dq.qs_gquota.qfs_ino); 439 tprintf("g_nblks=%" PRIu64 ", ", dq.qs_gquota.qfs_nblks); 440 tprintf("g_nextents=%u, ", dq.qs_gquota.qfs_nextents); 441 tprintf("btimelimit=%d, ", dq.qs_btimelimit); 442 tprintf("itimelimit=%d, ", dq.qs_itimelimit); 443 tprintf("rtbtimelimit=%d, ", dq.qs_rtbtimelimit); 444 tprintf("bwarnlimit=%u, ", dq.qs_bwarnlimit); 445 tprintf("iwarnlimit=%u}", dq.qs_iwarnlimit); 446 break; 447 } 448 case Q_XQUOTAON: 449 { 450 u_int32_t flag; 451 452 if (umove_or_printaddr(tcp, data, &flag)) 453 break; 454 tprints("{"); 455 printflags(xfs_quota_flags, flag, "XFS_QUOTA_???"); 456 tprints("}"); 457 break; 458 } 459 default: 460 printaddr(data); 461 break; 462 } 463 } 464 465 SYS_FUNC(quotactl) 466 { 467 /* 468 * The Linux kernel only looks at the low 32 bits of command and id 469 * arguments, but on some 64-bit architectures (s390x) this word 470 * will have been sign-extended when we see it. The high 1 bits 471 * don't mean anything, so don't confuse the output with them. 472 */ 473 u_int32_t qcmd = tcp->u_arg[0]; 474 u_int32_t cmd = QCMD_CMD(qcmd); 475 u_int32_t type = QCMD_TYPE(qcmd); 476 u_int32_t id = tcp->u_arg[2]; 477 478 if (entering(tcp)) { 479 printxval(quotacmds, cmd, "Q_???"); 480 tprints("|"); 481 printxval(quotatypes, type, "???QUOTA"); 482 tprints(", "); 483 printpath(tcp, tcp->u_arg[1]); 484 tprints(", "); 485 switch (cmd) { 486 case Q_V1_QUOTAON: 487 case Q_QUOTAON: 488 printxval(quota_formats, id, "QFMT_VFS_???"); 489 break; 490 case Q_V1_GETQUOTA: 491 case Q_V2_GETQUOTA: 492 case Q_GETQUOTA: 493 case Q_XGETQUOTA: 494 tprintf("%u", id); 495 break; 496 case Q_SETQLIM: 497 case Q_SETQUOTA: 498 case Q_V1_SETQUOTA: 499 case Q_V1_SETUSE: 500 case Q_V2_SETQUOTA: 501 case Q_V2_SETUSE: 502 case Q_XSETQLIM: 503 tprintf("%u, ", id); 504 case Q_SETINFO: 505 case Q_V2_SETFLAGS: 506 case Q_V2_SETGRACE: 507 case Q_V2_SETINFO: 508 decode_cmd_data(tcp, cmd, tcp->u_arg[3]); 509 return RVAL_DECODED; 510 break; 511 default: 512 printaddr(tcp->u_arg[2]); 513 break; 514 } 515 tprints(", "); 516 } else { 517 decode_cmd_data(tcp, cmd, tcp->u_arg[3]); 518 } 519 return 0; 520 } 521