[BACK]Return to state.c CVS log [TXT][DIR] Up to [Development] / xfs-cmds / xfsprogs / quota

File: [Development] / xfs-cmds / xfsprogs / quota / state.c (download)

Revision 1.2, Fri Jun 3 06:07:09 2005 UTC (12 years, 4 months ago) by nathans.longdrop.melbourne.sgi.com
Branch: MAIN
Changes since 1.1: +16 -8 lines

Portability changes to get xfs_quota to compile on IRIX as well.
Merge of master-melb:xfs-cmds:22792a by kenmcd.

/*
 * Copyright (c) 2005 Silicon Graphics, Inc.  All Rights Reserved.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of version 2 of the GNU General Public License as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it would be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 *
 * Further, this software is distributed without any warranty that it is
 * free of the rightful claim of any third person regarding infringement
 * or the like.  Any license provided herein, whether implied or
 * otherwise, applies only to this software file.  Patent licenses, if
 * any, provided herein do not apply to combinations of this program with
 * other software, or any other product whatsoever.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write the Free Software Foundation, Inc., 59
 * Temple Place - Suite 330, Boston MA 02111-1307, USA.
 *
 * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
 * Mountain View, CA  94043, or:
 *
 * http://www.sgi.com
 *
 * For further information regarding this notice, see:
 *
 * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
 */

#include <xfs/command.h>
#include "init.h"
#include "quota.h"

static cmdinfo_t off_cmd;
static cmdinfo_t state_cmd;
static cmdinfo_t enable_cmd;
static cmdinfo_t disable_cmd;
static cmdinfo_t remove_cmd;

static void
off_help(void)
{
	printf(_(
"\n"
" turn filesystem quota off, both accounting and enforcement\n"
"\n"
" Example:\n"
" 'off -uv'  (switch off user quota on the current filesystem)\n"
" This command is the equivalent of the traditional quotaoff command,\n"
" which disables quota completely on a mounted filesystem.\n"
" Note that there is no 'on' command - for XFS filesystems (with the\n"
" exception of the root filesystem on IRIX) quota can only be enabled\n"
" at mount time, through the use of one of the quota mount options.\n"
"\n"
" The state command is useful for displaying the current state.  Using\n"
" the -v (verbose) option with the 'off' command will display the quota\n"
" state for the affected filesystem once the operation is complete.\n"
" The affected quota type is -g (groups), -p (projects) or -u (users)\n"
" and defaults to user quota (multiple types can be specified).\n"
"\n"));
}

static void
state_help(void)
{
	printf(_(
"\n"
" query the state of quota on the current filesystem\n"
"\n"
" This is a verbose status command, reporting whether or not accounting\n"
" and/or enforcement are enabled for a filesystem, which inodes are in\n"
" use as the quota state inodes, and how many extents and blocks are\n"
" presently being used to hold that information.\n"
" The quota type is specified via -g (groups), -p (projects) or -u (users)\n"
" and defaults to user quota (multiple types can be specified).\n"
"\n"));
}

static void
enable_help(void)
{
	printf(_(
"\n"
" enable quota enforcement on a filesystem\n"
"\n"
" If a filesystem is mounted and has quota accounting enabled, but not\n"
" quota enforcement, enforcement can be enabled with this command.\n"
" With the -v (verbose) option, the status of the filesystem will be\n"
" reported after the operation is complete.\n"
" The affected quota type is -g (groups), -p (projects) or -u (users)\n"
" and defaults to user quota (multiple types can be specified).\n"
"\n"));
}

static void
disable_help(void)
{
	printf(_(
"\n"
" disable quota enforcement on a filesystem\n"
"\n"
" If a filesystem is mounted and is currently enforcing quota, this\n"
" provides a mechanism to switch off the enforcement, but continue to\n"
" perform used space (and used inodes) accounting.\n"
" The affected quota type is -g (groups), -p (projects) or -u (users).\n"
"\n"));
}

static void
remove_help(void)
{
	printf(_(
"\n"
" remove any space being used by the quota subsystem\n"
"\n"
" Once quota has been switched 'off' on a filesystem, the space that\n"
" was allocated to holding quota metadata can be freed via this command.\n"
" The affected quota type is -g (groups), -p (projects) or -u (users)\n"
" and defaults to user quota (multiple types can be specified).\n"
"\n"));
}

static void
state_qfilestat(
	FILE		*fp,
	fs_path_t	*mount,
	uint		type,
	fs_qfilestat_t	*qfs,
	int		accounting,
	int		enforcing)
{
	fprintf(fp, _("%s quota state on %s (%s)\n"), type_to_string(type),
		mount->fs_dir, mount->fs_name);
	fprintf(fp, _("  Accounting: %s\n"), accounting ? _("ON") : _("OFF"));
	fprintf(fp, _("  Enforcement: %s\n"), enforcing ? _("ON") : _("OFF"));
	fprintf(fp, _("  Inode: #%llu (%llu blocks, %lu extents)\n"),
		(unsigned long long)qfs->qfs_ino,
		(unsigned long long)qfs->qfs_nblks,
		(unsigned long)qfs->qfs_nextents);
}

static void
state_timelimit(
	FILE		*fp,
	uint		form,
	__uint32_t	timelimit)
{
	fprintf(fp, _("%s grace time: %s\n"),
		form_to_string(form),
		time_to_string(timelimit, VERBOSE_FLAG | ABSOLUTE_FLAG));
}

static void
state_quotafile_mount(
	FILE		*fp,
	uint		type,
	fs_path_t	*mount,
	uint		flags)
{
	fs_quota_stat_t	s;
	char		*dev = mount->fs_name;

	if (xfsquotactl(XFS_GETQSTAT, dev, type, 0, (void *)&s) < 0) {
		if (flags & VERBOSE_FLAG)
			fprintf(fp, _("%s quota are not enabled on %s\n"),
				type_to_string(type), dev);
		return;
	}

	if (type & XFS_USER_QUOTA)
		state_qfilestat(fp, mount, XFS_USER_QUOTA, &s.qs_uquota,
				s.qs_flags & XFS_QUOTA_UDQ_ACCT,
				s.qs_flags & XFS_QUOTA_UDQ_ENFD);
	if (type & XFS_GROUP_QUOTA)
		state_qfilestat(fp, mount, XFS_GROUP_QUOTA, &s.qs_gquota,
				s.qs_flags & XFS_QUOTA_GDQ_ACCT,
				s.qs_flags & XFS_QUOTA_GDQ_ENFD);
	if (type & XFS_PROJ_QUOTA)
		state_qfilestat(fp, mount, XFS_PROJ_QUOTA, &s.qs_gquota,
				s.qs_flags & XFS_QUOTA_PDQ_ACCT,
				s.qs_flags & XFS_QUOTA_PDQ_ENFD);

	state_timelimit(fp, XFS_BLOCK_QUOTA, s.qs_btimelimit);
	state_timelimit(fp, XFS_INODE_QUOTA, s.qs_itimelimit);
	state_timelimit(fp, XFS_RTBLOCK_QUOTA, s.qs_rtbtimelimit);
}

static void
state_quotafile(
	FILE		*fp,
	uint		type,
	char		*dir,
	uint		flags)
{
	fs_cursor_t	cursor;
	fs_path_t	*mount;

	fs_cursor_initialise(dir, FS_MOUNT_POINT, &cursor);
	while ((mount = fs_cursor_next_entry(&cursor)))
		state_quotafile_mount(fp, type, mount, flags);
}

static int
state_f(
	int		argc,
	char		**argv)
{
	FILE		*fp = NULL;
	char		*fname = NULL;
	int		c, flags = 0, type = 0;

	while ((c = getopt(argc, argv, "af:gpuv")) != EOF) {
		switch (c) {
		case 'a':
			flags |= ALL_MOUNTS_FLAG;
			break;
		case 'f':
			fname = optarg;
			break;
		case 'g':
			type |= XFS_GROUP_QUOTA;
			break;
		case 'p':
			type |= XFS_PROJ_QUOTA;
			break;
		case 'u':
			type |= XFS_USER_QUOTA;
			break;
		case 'v':
			flags |= VERBOSE_FLAG;
			break;
		default:
			return command_usage(&state_cmd);
		}
	}

	if (argc != optind)
		return command_usage(&state_cmd);

	if ((fp = fopen_write_secure(fname)) == NULL)
		return 0;

	if (!type)
		type = XFS_USER_QUOTA | XFS_GROUP_QUOTA | XFS_PROJ_QUOTA;

	state_quotafile(fp, type, (flags & ALL_MOUNTS_FLAG) ?
			NULL : fs_path->fs_dir, flags);

	if (fname)
		fclose(fp);
	return 0;
}

static void
enable_enforcement(
	char		*dir,
	uint		type,
	uint		qflags,
	uint		flags)
{
	fs_path_t	*mount;
	fs_quota_stat_t	qstat = { 0 };

	qstat.qs_version = FS_QSTAT_VERSION;
	qstat.qs_flags = qflags;

	mount = fs_table_lookup(dir, FS_MOUNT_POINT);
	if (!mount) {
		fprintf(stderr, "%s: unknown mount point %s\n", progname, dir);
		return;
	}
	dir = mount->fs_name;
	if (xfsquotactl(XFS_QUOTAON, dir, type, 0, (void *)&qstat) < 0)
		perror("XFS_QUOTAON");
	else if (flags & VERBOSE_FLAG)
		state_quotafile_mount(stdout, type, mount, flags);
}

static void
disable_enforcement(
	char		*dir,
	uint		type,
	uint		qflags,
	uint		flags)
{
	fs_path_t	*mount;
	fs_quota_stat_t	qstat = { 0 };

	qstat.qs_version = FS_QSTAT_VERSION;
	qstat.qs_flags = qflags;

	mount = fs_table_lookup(dir, FS_MOUNT_POINT);
	if (!mount) {
		fprintf(stderr, "%s: unknown mount point %s\n", progname, dir);
		return;
	}
	dir = mount->fs_name;
	if (xfsquotactl(XFS_QUOTAOFF, dir, type, 0, (void *)&qstat) < 0)
		perror("XFS_QUOTAOFF");
	else if (flags & VERBOSE_FLAG)
		state_quotafile_mount(stdout, type, mount, flags);
}

static void
quotaoff(
	char		*dir,
	uint		type,
	uint		qflags,
	uint		flags)
{
	fs_path_t	*mount;
	fs_quota_stat_t	qstat = { 0 };

	qstat.qs_version = FS_QSTAT_VERSION;
	qstat.qs_flags = qflags;

	mount = fs_table_lookup(dir, FS_MOUNT_POINT);
	if (!mount) {
		fprintf(stderr, "%s: unknown mount point %s\n", progname, dir);
		return;
	}
	dir = mount->fs_name;
	if (xfsquotactl(XFS_QUOTAOFF, dir, type, 0, (void *)&qstat) < 0)
		perror("XFS_QUOTAOFF");
	else if (flags & VERBOSE_FLAG)
		state_quotafile_mount(stdout, type, mount, flags);
}

static void
remove_extents(
	char		*dir,
	uint		type,
	uint		qflags,
	uint		flags)
{
	fs_path_t	*mount;
	fs_quota_stat_t	qstat = { 0 };

	qstat.qs_version = FS_QSTAT_VERSION;
	qstat.qs_flags = qflags;

	mount = fs_table_lookup(dir, FS_MOUNT_POINT);
	if (!mount) {
		fprintf(stderr, "%s: unknown mount point %s\n", progname, dir);
		return;
	}
	dir = mount->fs_name;
	if (xfsquotactl(XFS_QUOTARM, dir, type, 0, (void *)&qstat) < 0)
		perror("XFS_QUOTARM");
	else if (flags & VERBOSE_FLAG)
		state_quotafile_mount(stdout, type, mount, flags);
}

static int
enable_f(
	int		argc,
	char		**argv)
{
	int		c, flags = 0, qflags = 0, type = 0;

	while ((c = getopt(argc, argv, "gpuv")) != EOF) {
		switch (c) {
		case 'g':
			type |= XFS_GROUP_QUOTA;
			qflags |= XFS_QUOTA_GDQ_ACCT | XFS_QUOTA_GDQ_ENFD;
			break;
		case 'p':
			type |= XFS_PROJ_QUOTA;
			qflags |= XFS_QUOTA_PDQ_ACCT | XFS_QUOTA_PDQ_ENFD;
			break;
		case 'u':
			type |= XFS_USER_QUOTA;
			qflags |= XFS_QUOTA_UDQ_ACCT | XFS_QUOTA_UDQ_ENFD;
			break;
		case 'v':
			flags |= VERBOSE_FLAG;
			break;
		default:
			return command_usage(&enable_cmd);
		}
	}

	if (argc != optind)
		return command_usage(&enable_cmd);

	if (!flags) {
		type |= XFS_USER_QUOTA;
		qflags |= XFS_QUOTA_UDQ_ACCT | XFS_QUOTA_UDQ_ENFD;
	}

	enable_enforcement(fs_path->fs_dir, type, qflags, flags);
	return 0;
}

static int
disable_f(
	int		argc,
	char		**argv)
{
	int		c, flags = 0, qflags = 0, type = 0;

	while ((c = getopt(argc, argv, "gpuv")) != EOF) {
		switch (c) {
		case 'g':
			type |= XFS_GROUP_QUOTA;
			qflags |= XFS_QUOTA_GDQ_ACCT;
			break;
		case 'p':
			type |= XFS_PROJ_QUOTA;
			qflags |= XFS_QUOTA_PDQ_ACCT;
			break;
		case 'u':
			type |= XFS_USER_QUOTA;
			qflags |= XFS_QUOTA_UDQ_ACCT;
			break;
		case 'v':
			flags |= VERBOSE_FLAG;
			break;
		default:
			return command_usage(&disable_cmd);
		}
	}

	if (argc != optind)
		return command_usage(&disable_cmd);

	if (!flags) {
		type |= XFS_USER_QUOTA;
		qflags |= XFS_QUOTA_UDQ_ACCT;
	}

	disable_enforcement(fs_path->fs_dir, type, qflags, flags);
	return 0;
}

static int
off_f(
	int		argc,
	char		**argv)
{
	int		c, flags = 0, qflags = 0, type = 0;

	while ((c = getopt(argc, argv, "gpuv")) != EOF) {
		switch (c) {
		case 'g':
			type |= XFS_GROUP_QUOTA;
			qflags |= XFS_QUOTA_GDQ_ACCT | XFS_QUOTA_GDQ_ENFD;
			break;
		case 'p':
			type |= XFS_PROJ_QUOTA;
			qflags |= XFS_QUOTA_PDQ_ACCT | XFS_QUOTA_PDQ_ENFD;
			break;
		case 'u':
			type |= XFS_USER_QUOTA;
			qflags |= XFS_QUOTA_UDQ_ACCT | XFS_QUOTA_UDQ_ENFD;
			break;
		case 'v':
			flags |= VERBOSE_FLAG;
			break;
		default:
			return command_usage(&off_cmd);
		}
	}

	if (argc != optind)
		return command_usage(&off_cmd);

	if (!flags) {
		type |= XFS_USER_QUOTA;
		qflags |= XFS_QUOTA_UDQ_ACCT | XFS_QUOTA_UDQ_ENFD;
	}

	quotaoff(fs_path->fs_dir, type, qflags, flags);
	return 0;
}

static int
remove_f(
	int		argc,
	char		**argv)
{
	int		c, flags = 0, qflags = 0, type = 0;

	while ((c = getopt(argc, argv, "gpuv")) != EOF) {
		switch (c) {
		case 'g':
			type |= XFS_GROUP_QUOTA;
			qflags |= XFS_QUOTA_GDQ_ACCT | XFS_QUOTA_GDQ_ENFD;
			break;
		case 'p':
			type |= XFS_PROJ_QUOTA;
			qflags |= XFS_QUOTA_PDQ_ACCT | XFS_QUOTA_PDQ_ENFD;
			break;
		case 'u':
			type |= XFS_USER_QUOTA;
			qflags |= XFS_QUOTA_UDQ_ACCT | XFS_QUOTA_UDQ_ENFD;
			break;
		case 'v':
			flags |= VERBOSE_FLAG;
			break;
		default:
			return command_usage(&remove_cmd);
		}
	}

	if (argc != optind)
		return command_usage(&remove_cmd);

	if (!flags) {
		type |= XFS_USER_QUOTA;
		qflags |= XFS_QUOTA_UDQ_ACCT | XFS_QUOTA_UDQ_ENFD;
	}

	remove_extents(fs_path->fs_dir, type, qflags, flags);
	return 0;
}

void
state_init(void)
{
	off_cmd.name = _("off");
	off_cmd.cfunc = off_f;
	off_cmd.argmin = 0;
	off_cmd.argmax = -1;
	off_cmd.args = _("[-gpu] [-v]");
	off_cmd.oneline = _("permanently switch quota off for a path");
	off_cmd.help = off_help;

	state_cmd.name = _("state");
	state_cmd.cfunc = state_f;
	state_cmd.argmin = 0;
	state_cmd.argmax = -1;
	state_cmd.args = _("[-gpu] [-f file]");
	state_cmd.oneline = _("get overall quota state information");
	state_cmd.help = state_help;

	enable_cmd.name = _("enable");
	enable_cmd.cfunc = enable_f;
	enable_cmd.argmin = 0;
	enable_cmd.argmax = -1;
	enable_cmd.args = _("[-gpu] [-v]");
	enable_cmd.oneline = _("enable quota enforcement");
	enable_cmd.help = enable_help;

	disable_cmd.name = _("disable");
	disable_cmd.cfunc = disable_f;
	disable_cmd.argmin = 0;
	disable_cmd.argmax = -1;
	disable_cmd.args = _("[-gpu] [-v]");
	disable_cmd.oneline = _("disable quota enforcement");
	disable_cmd.help = disable_help;

	remove_cmd.name = _("remove");
	remove_cmd.cfunc = remove_f;
	remove_cmd.argmin = 0;
	remove_cmd.argmax = -1;
	remove_cmd.args = _("[-gpu] [-v]");
	remove_cmd.oneline = _("remove quota extents from a filesystem");
	remove_cmd.help = remove_help;

	if (expert) {
		add_command(&off_cmd);
		add_command(&state_cmd);
		add_command(&enable_cmd);
		add_command(&disable_cmd);
		add_command(&remove_cmd);
	}
}