|  | // SPDX-License-Identifier: GPL-2.0 | 
|  | /* | 
|  | * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. | 
|  | * All Rights Reserved. | 
|  | */ | 
|  |  | 
|  | #include "libxfs.h" | 
|  | #include "bit.h" | 
|  | #include "bmap.h" | 
|  | #include "command.h" | 
|  | #include "type.h" | 
|  | #include "faddr.h" | 
|  | #include "fprint.h" | 
|  | #include "field.h" | 
|  | #include "inode.h" | 
|  | #include "io.h" | 
|  | #include "init.h" | 
|  | #include "output.h" | 
|  | #include "dquot.h" | 
|  |  | 
|  | static int	dquot_f(int argc, char **argv); | 
|  | static void	dquot_help(void); | 
|  |  | 
|  | static const cmdinfo_t	dquot_cmd = { | 
|  | "dquot", NULL, dquot_f, 1, 2, 1, N_("[-g|-p|-u] id"), | 
|  | N_("set current address to a group, project or user quota block for given ID"), | 
|  | dquot_help, | 
|  | }; | 
|  |  | 
|  | const field_t	dqblk_hfld[] = { | 
|  | { "", FLDT_DQBLK, OI(0), C1, 0, TYP_NONE }, | 
|  | { NULL } | 
|  | }; | 
|  |  | 
|  | #define	DDOFF(f)	bitize(offsetof(struct xfs_dqblk, dd_ ## f)) | 
|  | #define	DDSZC(f)	szcount(struct xfs_dqblk, dd_ ## f) | 
|  | const field_t	dqblk_flds[] = { | 
|  | { "diskdq", FLDT_DISK_DQUOT, OI(DDOFF(diskdq)), C1, 0, TYP_NONE }, | 
|  | { "fill", FLDT_CHARS, OI(DDOFF(fill)), CI(DDSZC(fill)), FLD_SKIPALL, | 
|  | TYP_NONE }, | 
|  | { "crc", FLDT_CRC, OI(DDOFF(crc)), C1, 0, TYP_NONE }, | 
|  | { "lsn", FLDT_UINT64X, OI(DDOFF(lsn)), C1, 0, TYP_NONE }, | 
|  | { "uuid", FLDT_UUID, OI(DDOFF(uuid)), C1, 0, TYP_NONE }, | 
|  | { NULL } | 
|  | }; | 
|  |  | 
|  | #define	DOFF(f)		bitize(offsetof(struct xfs_disk_dquot, d_ ## f)) | 
|  | const field_t	disk_dquot_flds[] = { | 
|  | { "magic", FLDT_UINT16X, OI(DOFF(magic)), C1, 0, TYP_NONE }, | 
|  | { "version", FLDT_UINT8X, OI(DOFF(version)), C1, 0, TYP_NONE }, | 
|  | { "type", FLDT_UINT8X, OI(DOFF(type)), C1, 0, TYP_NONE }, | 
|  | { "id", FLDT_DQID, OI(DOFF(id)), C1, 0, TYP_NONE }, | 
|  | { "blk_hardlimit", FLDT_QCNT, OI(DOFF(blk_hardlimit)), C1, 0, | 
|  | TYP_NONE }, | 
|  | { "blk_softlimit", FLDT_QCNT, OI(DOFF(blk_softlimit)), C1, 0, | 
|  | TYP_NONE }, | 
|  | { "ino_hardlimit", FLDT_QCNT, OI(DOFF(ino_hardlimit)), C1, 0, | 
|  | TYP_NONE }, | 
|  | { "ino_softlimit", FLDT_QCNT, OI(DOFF(ino_softlimit)), C1, 0, | 
|  | TYP_NONE }, | 
|  | { "bcount", FLDT_QCNT, OI(DOFF(bcount)), C1, 0, TYP_NONE }, | 
|  | { "icount", FLDT_QCNT, OI(DOFF(icount)), C1, 0, TYP_NONE }, | 
|  | { "itimer", FLDT_QTIMER, OI(DOFF(itimer)), C1, 0, TYP_NONE }, | 
|  | { "btimer", FLDT_QTIMER, OI(DOFF(btimer)), C1, 0, TYP_NONE }, | 
|  | { "iwarns", FLDT_QWARNCNT, OI(DOFF(iwarns)), C1, 0, TYP_NONE }, | 
|  | { "bwarns", FLDT_QWARNCNT, OI(DOFF(bwarns)), C1, 0, TYP_NONE }, | 
|  | { "pad0", FLDT_UINT32X, OI(DOFF(pad0)), C1, FLD_SKIPALL, TYP_NONE }, | 
|  | { "rtb_hardlimit", FLDT_QCNT, OI(DOFF(rtb_hardlimit)), C1, 0, | 
|  | TYP_NONE }, | 
|  | { "rtb_softlimit", FLDT_QCNT, OI(DOFF(rtb_softlimit)), C1, 0, | 
|  | TYP_NONE }, | 
|  | { "rtbcount", FLDT_QCNT, OI(DOFF(rtbcount)), C1, 0, TYP_NONE }, | 
|  | { "rtbtimer", FLDT_QTIMER, OI(DOFF(rtbtimer)), C1, 0, TYP_NONE }, | 
|  | { "rtbwarns", FLDT_QWARNCNT, OI(DOFF(rtbwarns)), C1, 0, TYP_NONE }, | 
|  | { "pad", FLDT_UINT16X, OI(DOFF(pad)), C1, FLD_SKIPALL, TYP_NONE }, | 
|  | { NULL } | 
|  | }; | 
|  |  | 
|  | static void | 
|  | dquot_help(void) | 
|  | { | 
|  | } | 
|  |  | 
|  | static int | 
|  | dquot_f( | 
|  | int		argc, | 
|  | char		**argv) | 
|  | { | 
|  | bmap_ext_t	bm; | 
|  | int		c; | 
|  | int		dogrp; | 
|  | int		doprj; | 
|  | xfs_dqid_t	id; | 
|  | xfs_ino_t	ino; | 
|  | xfs_extnum_t	nex; | 
|  | char		*p; | 
|  | int		perblock; | 
|  | xfs_fileoff_t	qbno; | 
|  | int		qoff; | 
|  | char		*s; | 
|  |  | 
|  | dogrp = doprj = optind = 0; | 
|  | while ((c = getopt(argc, argv, "gpu")) != EOF) { | 
|  | switch (c) { | 
|  | case 'g': | 
|  | dogrp = 1; | 
|  | doprj = 0; | 
|  | break; | 
|  | case 'p': | 
|  | doprj = 1; | 
|  | dogrp = 0; | 
|  | break; | 
|  | case 'u': | 
|  | dogrp = doprj = 0; | 
|  | break; | 
|  | default: | 
|  | dbprintf(_("bad option for dquot command\n")); | 
|  | return 0; | 
|  | } | 
|  | } | 
|  | s = doprj ? _("project") : dogrp ? _("group") : _("user"); | 
|  | if (optind != argc - 1) { | 
|  | dbprintf(_("dquot command requires one %s id argument\n"), s); | 
|  | return 0; | 
|  | } | 
|  | ino = mp->m_sb.sb_uquotino; | 
|  | if (doprj) | 
|  | ino = mp->m_sb.sb_pquotino; | 
|  | else if (dogrp) | 
|  | ino = mp->m_sb.sb_gquotino; | 
|  |  | 
|  | if (ino == 0 || ino == NULLFSINO) { | 
|  | dbprintf(_("no %s quota inode present\n"), s); | 
|  | return 0; | 
|  | } | 
|  | id = (xfs_dqid_t)strtol(argv[optind], &p, 0); | 
|  | if (*p != '\0') { | 
|  | dbprintf(_("bad %s id for dquot %s\n"), s, argv[optind]); | 
|  | return 0; | 
|  | } | 
|  | perblock = (int)(mp->m_sb.sb_blocksize / sizeof(struct xfs_dqblk)); | 
|  | qbno = (xfs_fileoff_t)id / perblock; | 
|  | qoff = (int)(id % perblock); | 
|  | push_cur(); | 
|  | set_cur_inode(ino); | 
|  | nex = 1; | 
|  | bmap(qbno, 1, XFS_DATA_FORK, &nex, &bm); | 
|  | pop_cur(); | 
|  | if (nex == 0) { | 
|  | dbprintf(_("no %s quota data for id %d\n"), s, id); | 
|  | return 0; | 
|  | } | 
|  | set_cur(&typtab[TYP_DQBLK], XFS_FSB_TO_DADDR(mp, bm.startblock), blkbb, | 
|  | DB_RING_IGN, NULL); | 
|  | iocur_top->dquot_buf = 1; | 
|  | off_cur(qoff * (int)sizeof(struct xfs_dqblk), sizeof(struct xfs_dqblk)); | 
|  | ring_add(); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | void | 
|  | xfs_dquot_set_crc( | 
|  | struct xfs_buf *bp) | 
|  | { | 
|  | ASSERT((iocur_top->dquot_buf)); | 
|  | ASSERT(iocur_top->bp == bp); | 
|  |  | 
|  | xfs_update_cksum(iocur_top->data, sizeof(struct xfs_dqblk), | 
|  | XFS_DQUOT_CRC_OFF); | 
|  | } | 
|  |  | 
|  | void | 
|  | dquot_init(void) | 
|  | { | 
|  | add_command(&dquot_cmd); | 
|  | } |