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, §size);
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);
}