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

File: [Development] / xfs-cmds / xfsprogs / io / open.c (download)

Revision 1.16, Fri Sep 17 06:32:01 2004 UTC (13 years, 1 month ago) by nathans.longdrop.melbourne.sgi.com
Branch: MAIN
Changes since 1.15: +1 -229 lines

Move lsattr/chattr commands into separate file, we need to add some more options here soon for IRIX so these are getting enough code to warrant separate sources.  No functional change.
Merge of xfs-cmds-melb:slinx:19483a by kenmcd.

/*
 * Copyright (c) 2003-2004 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/libxfs.h>
#include "command.h"
#include "input.h"
#include "init.h"
#include "io.h"

static cmdinfo_t open_cmd;
static cmdinfo_t stat_cmd;
static cmdinfo_t close_cmd;
static cmdinfo_t setfl_cmd;
static cmdinfo_t statfs_cmd;
static cmdinfo_t chproj_cmd;
static cmdinfo_t lsproj_cmd;
static cmdinfo_t extsize_cmd;

off64_t
filesize(void)
{
	struct stat64	st;

	if (fstat64(file->fd, &st) < 0) {
		perror("fstat64");
		return -1;
	}
	return st.st_size;
}

static char *
filetype(mode_t mode)
{
	switch (mode & S_IFMT) {
	case S_IFSOCK:
		return _("socket");
	case S_IFDIR:
		return _("directory");
	case S_IFCHR:
		return _("char device");
	case S_IFBLK:
		return _("block device");
	case S_IFREG:
		return _("regular file");
	case S_IFLNK:
		return _("symbolic link");
	case S_IFIFO:
		return _("fifo");
	}
	return NULL;
}

static int
stat_f(
	int		argc,
	char		**argv)
{
	struct fsxattr	fsx;
	struct stat64	st;
	int		verbose = (argc == 2 && !strcmp(argv[1], "-v"));

	printf(_("fd.path = \"%s\"\n"), file->name);
	printf(_("fd.flags = %s,%s,%s%s%s\n"),
		file->flags & IO_OSYNC ? _("sync") : _("non-sync"),
		file->flags & IO_DIRECT ? _("direct") : _("non-direct"),
		file->flags & IO_READONLY ? _("read-only") : _("read-write"),
		file->flags & IO_REALTIME ? _(",real-time") : "",
		file->flags & IO_APPEND ? _(",append-only") : "");
	if (fstat64(file->fd, &st) < 0) {
		perror("fstat64");
	} else {
		printf(_("stat.ino = %lld\n"), (long long)st.st_ino);
		printf(_("stat.type = %s\n"), filetype(st.st_mode));
		printf(_("stat.size = %lld\n"), (long long)st.st_size);
		printf(_("stat.blocks = %lld\n"), (long long)st.st_blocks);
		if (verbose) {
			printf(_("stat.atime = %s"), ctime(&st.st_atime));
			printf(_("stat.mtime = %s"), ctime(&st.st_mtime));
			printf(_("stat.ctime = %s"), ctime(&st.st_ctime));
		}
	}
	if (file->flags & IO_FOREIGN)
		return 0;
	if ((xfsctl(file->name, file->fd, XFS_IOC_FSGETXATTR, &fsx)) < 0) {
		perror("XFS_IOC_FSGETXATTR");
	} else {
		printf(_("xattr.xflags = 0x%x "), fsx.fsx_xflags);
		printxattr(fsx.fsx_xflags, verbose, 0, file->name, 1, 1);
		printf(_("xattr.extsize = %u\n"), fsx.fsx_extsize);
		printf(_("xattr.nextents = %u\n"), fsx.fsx_nextents);
	}
	return 0;
}

int
openfile(
	char		*path,
	xfs_fsop_geom_t	*geom,
	int		flags,
	mode_t		mode)
{
	int		fd;
	int		oflags;

	oflags = flags & IO_READONLY ? O_RDONLY : O_RDWR;
	if (flags & IO_APPEND)
		oflags |= O_APPEND;
	if (flags & IO_CREAT)
		oflags |= O_CREAT;
	if (flags & IO_DIRECT)
		oflags |= O_DIRECT;
	if (flags & IO_OSYNC)
		oflags |= O_SYNC;
	if (flags & IO_TRUNC)
		oflags |= O_TRUNC;

	fd = open(path, oflags, mode);
	if (fd < 0) {
		perror(path);
		return -1;
	}

	if (!geom)
		return fd;

	if (!platform_test_xfs_fd(fd)) {
		fprintf(stderr, _("%s: specified file "
			"[\"%s\"] is not on an XFS filesystem\n"),
			progname, path);
		close(fd);
		return -1;
	}

	if (xfsctl(path, fd, XFS_IOC_FSGEOMETRY, geom) < 0) {
		perror("XFS_IOC_FSGEOMETRY");
		close(fd);
		return -1;
	}

	if (!(flags & IO_READONLY) && (flags & IO_REALTIME)) {
		struct fsxattr	attr;

		if (xfsctl(path, fd, XFS_IOC_FSGETXATTR, &attr) < 0) {
			perror("XFS_IOC_FSGETXATTR");
			close(fd);
			return -1;
		}
		if (!(attr.fsx_xflags & XFS_XFLAG_REALTIME)) {
			attr.fsx_xflags |= XFS_XFLAG_REALTIME;
			if (xfsctl(path, fd, XFS_IOC_FSSETXATTR, &attr) < 0) {
				perror("XFS_IOC_FSSETXATTR");
				close(fd);
				return -1;
			}
		}
	}
	return fd;
}

int
addfile(
	char		*name,
	int		fd,
	xfs_fsop_geom_t	*geometry,
	int		flags)
{
	char		*filename;

	filename = strdup(name);
	if (!filename) {
		perror("strdup");
		close(fd);
		return -1;
	}

	/* Extend the table of currently open files */
	filetable = (fileio_t *)realloc(filetable,	/* growing */
					++filecount * sizeof(fileio_t));
	if (!filetable) {
		perror("realloc");
		filecount = 0;
		free(filename);
		close(fd);
		return -1;
	}

	/* Finally, make this the new active open file */
	file = &filetable[filecount - 1];
	file->fd = fd;
	file->flags = flags;
	file->name = filename;
	file->geom = *geometry;
	return 0;
}

static void
open_help(void)
{
	printf(_(
"\n"
" opens a new file in the requested mode\n"
"\n"
" Example:\n"
" 'open -cd /tmp/data' - creates/opens data file read-write for direct IO\n"
"\n"
" Opens a file for subsequent use by all of the other xfs_io commands.\n"
" With no arguments, open uses the stat command to show the current file.\n"
" -F -- foreign filesystem file, disallow XFS-specific commands\n"
" -a -- open with the O_APPEND flag (append-only mode)\n"
" -d -- open with O_DIRECT (non-buffered IO, note alignment constraints)\n"
" -f -- open with O_CREAT (create the file if it doesn't exist)\n"
" -m -- permissions to use in case a new file is created (default 0600)\n"
" -r -- open with O_RDONLY, the default is O_RDWR\n"
" -s -- open with O_SYNC\n"
" -t -- open with O_TRUNC (truncate the file to zero length if it exists)\n"
" -x -- mark the file as a realtime XFS file immediately after opening it\n"
" Note1: usually read/write direct IO requests must be blocksize aligned;\n"
"        some kernels, however, allow sectorsize alignment for direct IO.\n"
" Note2: the bmap for non-regular files can be obtained provided the file\n"
"        was opened correctly (in particular, must be opened read-only).\n"
"\n"));
}

static int
open_f(
	int		argc,
	char		**argv)
{
	int		c, fd, flags = 0;
	char		*sp;
	mode_t		mode = 0600;
	xfs_fsop_geom_t	geometry = { 0 };

	if (argc == 1) {
		if (file)
			return stat_f(argc, argv);
		fprintf(stderr, _("no files are open, try 'help open'\n"));
		return 0;
	}

	while ((c = getopt(argc, argv, "Facdfm:rstx")) != EOF) {
		switch (c) {
		case 'F':
			flags |= IO_FOREIGN;
			break;
		case 'a':
			flags |= IO_APPEND;
			break;
		case 'c':
		case 'f':
			flags |= IO_CREAT;
			break;
		case 'd':
			flags |= IO_DIRECT;
			break;
		case 'm':
			mode = strtoul(optarg, &sp, 0);
			if (!sp || sp == optarg) {
				printf(_("non-numeric mode -- %s\n"), optarg);
				return 0;
			}
			break;
		case 'r':
			flags |= IO_READONLY;
			break;
		case 's':
			flags |= IO_OSYNC;
			break;
		case 't':
			flags |= IO_TRUNC;
			break;
		case 'x':
			flags |= IO_REALTIME;
			break;
		default:
			return command_usage(&open_cmd);
		}
	}

	if (optind != argc - 1)
		return command_usage(&open_cmd);

	fd = openfile(argv[optind], flags & IO_FOREIGN ?
					NULL : &geometry, flags, mode);
	if (fd < 0)
		return 0;

	addfile(argv[optind], fd, &geometry, flags);
	return 0;
}

static int
close_f(
	int		argc,
	char		**argv)
{
	size_t		length;
	unsigned int	offset;

	if (close(file->fd) < 0) {
		perror("close");
		return 0;
	}
	free(file->name);

	/* Shuffle the file table entries down over the removed entry */
	offset = file - &filetable[0];
	length = filecount * sizeof(fileio_t);
	length -= (offset + 1) * sizeof(fileio_t);
	if (length)
		memmove(file, file + 1, length);

	/* Resize the memory allocated for the table, possibly freeing */
	if (--filecount) {
		filetable = (fileio_t *)realloc(filetable,	/* shrinking */
					filecount * sizeof(fileio_t));
		if (offset == filecount)
			offset--;
		file = filetable + offset;
	} else {
		free(filetable);
		file = filetable = NULL;
	}
	filelist_f();
	return 0;
}

static int
lsproj_f(
	int		argc,
	char		**argv)
{
	__uint32_t	id;

#if defined(__sgi__)
	struct stat64	st;
	if (fstat64(file->fd, &st) < 0) {
		perror("fstat64");
		return 0;
	}
	id = st.st_projid;
#else
	id = 0;
#endif
	printf("projid = %u\n", (unsigned int)id);
	return 0;
}

static int
chproj_f(
	int		argc,
	char		**argv)
{
	__uint32_t	id;
	char		*sp;

	id = (__uint32_t) strtoul(argv[1], &sp, 0);
	if (!sp || sp == argv[1]) {
		printf(_("non-numeric project ID -- %s\n"), argv[1]);
		return 0;
	}
#if defined(__sgi__)
	if (fchproj(file->fd, id) < 0)
		perror("fchproj");
#else
	printf(_("Not yet implemented\n"));
#endif
	return 0;
}

static int
setfl_f(
	int			argc,
	char			**argv)
{
	int			c, flags;

	flags = fcntl(file->fd, F_GETFL, 0);
	if (flags < 0) {
		perror("fcntl(F_GETFL)");
		return 0;
	}

	while ((c = getopt(argc, argv, "ad")) != EOF) {
		switch (c) {
		case 'a':
			if (flags & O_APPEND)
				flags |= O_APPEND;
			else
				flags &= ~O_APPEND;
			break;
		case 'd':
			if (flags & O_DIRECT)
				flags |= O_DIRECT;
			else
				flags &= ~O_DIRECT;
			break;
		default:
			printf(_("invalid setfl argument -- '%c'\n"), c);
			return 0;
		}
	}

	if (fcntl(file->fd, F_SETFL, flags)  < 0)
		perror("fcntl(F_SETFL)");

	return 0;
}

static int
extsize_f(
	int			argc,
	char			**argv)
{
	struct fsxattr		fsx;
	long			extsize;
	int			blocksize, sectsize;

	init_cvtnum(&blocksize, &sectsize);
	extsize = (long)cvtnum(blocksize, sectsize, argv[1]);
	if (extsize < 0) {
		printf(_("non-numeric extsize argument -- %s\n"), argv[1]);
		return 0;
	}
	if ((xfsctl(file->name, file->fd, XFS_IOC_FSGETXATTR, &fsx)) < 0) {
		perror("XFS_IOC_FSGETXATTR");
		return 0;
	}
	fsx.fsx_extsize = extsize;
	if ((xfsctl(file->name, file->fd, XFS_IOC_FSSETXATTR, &fsx)) < 0) {
		perror("XFS_IOC_FSSETXATTR");
		return 0;
	}

	return 0;
}

static int
statfs_f(
	int			argc,
	char			**argv)
{
	struct xfs_fsop_counts	fscounts;
	struct xfs_fsop_geom	fsgeo;
	struct statfs		st;

	printf(_("fd.path = \"%s\"\n"), file->name);
	if (platform_fstatfs(file->fd, &st) < 0) {
		perror("fstatfs");
	} else {
		printf(_("statfs.f_bsize = %lld\n"), (long long) st.f_bsize);
		printf(_("statfs.f_blocks = %lld\n"), (long long) st.f_blocks);
#if defined(__sgi__)
		printf(_("statfs.f_frsize = %lld\n"), (long long) st.f_frsize);
#else
		printf(_("statfs.f_bavail = %lld\n"), (long long) st.f_bavail);
#endif
		printf(_("statfs.f_files = %lld\n"), (long long) st.f_files);
		printf(_("statfs.f_ffree = %lld\n"), (long long) st.f_ffree);
	}
	if (file->flags & IO_FOREIGN)
		return 0;
	if ((xfsctl(file->name, file->fd, XFS_IOC_FSGEOMETRY_V1, &fsgeo)) < 0) {
		perror("XFS_IOC_FSGEOMETRY_V1");
	} else {
		printf(_("geom.bsize = %u\n"), fsgeo.blocksize);
		printf(_("geom.agcount = %u\n"), fsgeo.agcount);
		printf(_("geom.agblocks = %u\n"), fsgeo.agblocks);
		printf(_("geom.datablocks = %llu\n"),
			(unsigned long long) fsgeo.datablocks);
		printf(_("geom.rtblocks = %llu\n"),
			(unsigned long long) fsgeo.rtblocks);
		printf(_("geom.rtextents = %llu\n"),
			(unsigned long long) fsgeo.rtextents);
		printf(_("geom.rtextsize = %u\n"), fsgeo.rtextsize);
		printf(_("geom.sunit = %u\n"), fsgeo.sunit);
		printf(_("geom.swidth = %u\n"), fsgeo.swidth);
	}
	if ((xfsctl(file->name, file->fd, XFS_IOC_FSCOUNTS, &fscounts)) < 0) {
		perror("XFS_IOC_FSCOUNTS");
	} else {
		printf(_("counts.freedata = %llu\n"),
			(unsigned long long) fscounts.freedata);
		printf(_("counts.freertx = %llu\n"),
			(unsigned long long) fscounts.freertx);
		printf(_("counts.freeino = %llu\n"),
			(unsigned long long) fscounts.freeino);
		printf(_("counts.allocino = %llu\n"),
			(unsigned long long) fscounts.allocino);
	}
	return 0;
}

void
open_init(void)
{
	open_cmd.name = _("open");
	open_cmd.altname = _("o");
	open_cmd.cfunc = open_f;
	open_cmd.argmin = 0;
	open_cmd.argmax = -1;
	open_cmd.flags = CMD_NOMAP_OK | CMD_NOFILE_OK | CMD_FOREIGN_OK;
	open_cmd.args = _("[-acdrstx] [path]");
	open_cmd.oneline = _("open the file specified by path");
	open_cmd.help = open_help;

	stat_cmd.name = _("stat");
	stat_cmd.cfunc = stat_f;
	stat_cmd.argmin = 0;
	stat_cmd.argmax = 1;
	stat_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK;
	stat_cmd.args = _("[-v]");
	stat_cmd.oneline = _("statistics on the currently open file");

	close_cmd.name = _("close");
	close_cmd.altname = _("c");
	close_cmd.cfunc = close_f;
	close_cmd.argmin = 0;
	close_cmd.argmax = 0;
	close_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK;
	close_cmd.oneline = _("close the current open file");

	setfl_cmd.name = _("setfl");
	setfl_cmd.cfunc = setfl_f;
	setfl_cmd.args = _("[-adx]");
	setfl_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK;
	setfl_cmd.oneline =
		_("set/clear append/direct flags on the open file");

	statfs_cmd.name = _("statfs");
	statfs_cmd.cfunc = statfs_f;
	statfs_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK;
	statfs_cmd.oneline =
		_("statistics on the filesystem of the currently open file");

	chproj_cmd.name = _("chproj");
	chproj_cmd.cfunc = chproj_f;
	chproj_cmd.args = _("projid");
	chproj_cmd.argmin = 1;
	chproj_cmd.argmax = 1;
	chproj_cmd.flags = CMD_NOMAP_OK;
	chproj_cmd.oneline =
		_("change project identifier on the currently open file");

	lsproj_cmd.name = _("lsproj");
	lsproj_cmd.cfunc = lsproj_f;
	lsproj_cmd.argmin = 0;
	lsproj_cmd.argmax = 0;
	lsproj_cmd.flags = CMD_NOMAP_OK;
	lsproj_cmd.oneline =
		_("list project identifier set on the currently open file");

	extsize_cmd.name = _("extsize");
	extsize_cmd.cfunc = extsize_f;
	extsize_cmd.argmin = 1;
	extsize_cmd.argmax = 1;
	extsize_cmd.flags = CMD_NOMAP_OK;
	extsize_cmd.oneline =
		_("set prefered extent size (in bytes) for the open file");

	add_command(&open_cmd);
	add_command(&stat_cmd);
	add_command(&close_cmd);
	add_command(&setfl_cmd);
	add_command(&statfs_cmd);
	add_command(&chproj_cmd);
	add_command(&lsproj_cmd);

	if (expert)
		add_command(&extsize_cmd);
}