[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.1, Tue Apr 19 15:00:30 2005 UTC (12 years, 5 months ago) by nathans.longdrop.melbourne.sgi.com
Branch: MAIN

Initial version of xfs quota utility.  Knows how to do user/group/project quota, provides missing freespace reporting for realtime on Linux, and for project quotas.  Allows all current and future XFS quota functionality to be exposed without complicating the standard quota tools.
Merge of master-melb:xfs-cmds:22274a 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 =
		{ .qs_version = FS_QSTAT_VERSION, .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 =
		{ .qs_version = FS_QSTAT_VERSION, .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 =
		{ .qs_version = FS_QSTAT_VERSION, .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 =
		{ .qs_version = FS_QSTAT_VERSION, .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);
	}
}