From: Nathan Scott Date: Tue, 19 Apr 2005 14:59:46 +0000 (+0000) Subject: Move common utility code into a libxcmd.a to ease sharing amongst multiple tools. X-Git-Tag: v2.7.0~35 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=3d93ccb7f1296ac928733aa84cddd3bdad1e8f92;p=thirdparty%2Fxfsprogs-dev.git Move common utility code into a libxcmd.a to ease sharing amongst multiple tools. Merge of master-melb:xfs-cmds:22271a by kenmcd. --- diff --git a/Makefile b/Makefile index 9cd405ec3..01e2a3c3a 100644 --- a/Makefile +++ b/Makefile @@ -43,7 +43,7 @@ LSRCFILES = configure configure.in Makepkgs aclocal.m4 install-sh README VERSION LDIRT = config.log .dep config.status config.cache confdefs.h conftest* \ Logs/* built .census install.* install-dev.* *.gz -SUBDIRS = include libxfs libxlog libhandle libdisk \ +SUBDIRS = include libxfs libxlog libxcmd libhandle libdisk \ copy db fsck growfs io logprint mkfile mkfs repair rtcp \ m4 man doc po debian build diff --git a/doc/Makefile b/doc/Makefile index 3e21eb17e..8d44b88fe 100644 --- a/doc/Makefile +++ b/doc/Makefile @@ -1,5 +1,5 @@ # -# Copyright (c) 2000-2001 Silicon Graphics, Inc. All Rights Reserved. +# Copyright (c) 2000-2001,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 @@ -33,8 +33,7 @@ TOPDIR = .. include $(TOPDIR)/include/builddefs -README = README.LVM README.quota -LSRCFILES = INSTALL PORTING CHANGES COPYING CREDITS $(README) +LSRCFILES = INSTALL PORTING CHANGES COPYING CREDITS LDIRT = *.gz default: CHANGES.gz @@ -46,7 +45,7 @@ CHANGES.gz: install: default $(INSTALL) -m 755 -d $(PKG_DOC_DIR) - $(INSTALL) -m 644 PORTING CHANGES.gz CREDITS $(README) $(PKG_DOC_DIR) + $(INSTALL) -m 644 PORTING CHANGES.gz CREDITS $(PKG_DOC_DIR) ifeq ($(PKG_DISTRIBUTION), debian) $(INSTALL) -S CHANGES.gz $(PKG_DOC_DIR)/changelog.gz else diff --git a/doc/README.LVM b/doc/README.LVM deleted file mode 100644 index 06eb6def8..000000000 --- a/doc/README.LVM +++ /dev/null @@ -1,77 +0,0 @@ -XFS on LVM -__________ - -PREFACE - -This is a quick reference to setting XFS up on LVM. For more information -please see the LVM HOWTO at: - - http://www.linuxdoc.org/HOWTO/LVM-HOWTO.html - -PREREQUISITES - -You need a kernel with LVM support either built in or as a module. -This document assumes lvm as a module. - -SETTING UP LVM - ->>> Load module - - [root@crash /sbin]# modprobe lvm-mod - ->>> Set partition type to 0x8e for partitions you wish to use with LVM - - [root@crash /sbin]# fdisk /dev/sda1 - Command (m for help): t - Partition number (1-4): 1 - Hex code (type L to list codes): 8e - Changed system type of partition 1 to 8e (Unknown) - - Command (m for help): w - The partition table has been altered! - ->>> Write PV superblock on physical volumes - - [root@crash /root]# pvcreate /dev/sda1 /dev/sdb1 /dev/sdc1 /dev/sdd1 - pvcreate -- physical volume "/dev/sda1" successfully created - pvcreate -- physical volume "/dev/sdb1" successfully created - pvcreate -- physical volume "/dev/sdc1" successfully created - pvcreate -- physical volume "/dev/sdd1" successfully created - ->>> Create a volume group consisting of the PVs we just set up - -[root@crash /root]# vgcreate vg00 /dev/sda1 /dev/sdb1 /dev/sdc1 /dev/sdd1 - vgcreate -- INFO: using default physical extent size 4 MB - vgcreate -- INFO: maximum logical volume size is 255.99 Gigabyte - vgcreate -- doing automatic backup of volume group "vg00" - vgcreate -- volume group "vg00" successfully created and activated - ->>> Create a logical volume - striped across 4 PVs, 64 KB chunk size, 20 GB - -[root@crash /root]# lvcreate -i 4 -I 64 -L 20G -n lv00 vg00 - lvcreate -- rounding 20971520 KB to stripe boundary size 20975616 KB / 5121 PE - lvcreate -- doing automatic backup of "vg00" - lvcreate -- logical volume "/dev/vg00/lv00" successfully created - ->>> Build a filesystem on the LV - -[root@crash /root]# mkfs -t xfs /dev/vg00/lv00 - meta-data=/dev/vg00/lv00 isize=256 agcount=20, agsize=262144 blks - data = bsize=4096 blocks=5242879, imaxpct=25 - = sunit=0 swidth=0 blks, unwritten=1 - naming =version 2 bsize=4096 - log =internal log bsize=4096 blocks=1200 - realtime =none extsz=65536 blocks=0, rtextents=0 - -[root@crash /root]# mount -t xfs /dev/vg00/lv00 /xfs - ->>> Go nuts - - -After a reboot you will need to reactivate the VGs/LVs: - - modprobe lvm-mod - vgchange -a y - -These commands could be added to a startup script. - diff --git a/doc/README.quota b/doc/README.quota deleted file mode 100644 index 4cabd2985..000000000 --- a/doc/README.quota +++ /dev/null @@ -1,309 +0,0 @@ -QUOTA on XFS -____________ - -PREFACE - -For an additional source of information on Linux quota, you can refer to -the (currently out-of-date) Linux Quota HOWTO at: - - http://www.linuxdoc.org/HOWTO/mini/Quota.html - -If you are looking to get started quickly, you can skip down to the -section GETTING STARTED below. It is recommended that you at least -read the "Administering the XFS Quota System" section below, however. - - -DESCRIPTION - -In most computing environments, disk space is not infinite. The quota -subsystem provides a mechanism to control usage of disk space. Quotas -can be set for each individual user on any/all of the local filesystems. -The quotas subsystem warns users when they exceed their allotted limit, -but allows some extra space for current work (hard limit/soft limit). -In addition, XFS filesystems with limit enforcement turned off can be -used as an effective disk usage accounting system. - - Users' Views of Disk Quotas - To most users, disk quotas are either of no concern or a fact of life - that cannot be avoided. There are two possible quotas that can be - imposed - a limit can be set on the amount of space a user can occupy, - and there may be a limit on the number of files (inodes) he can own. - - The quota(1) command provides information on the quotas that have been - set by the system administrators and current usage. - - There are four numbers for each limit: current usage, soft limit - (quota), hard limit, and time limit. The soft limit is the number of 1K - blocks (or files) that the user is expected to remain below. The hard - limit cannot be exceeded. If a user's usage reaches the hard limit, - further requests for space (or attempts to create a file) fail with an - EDQUOT/ENOSPC error. - - When a user exceeds the soft limit, the timer is enabled. Any time the - quota drops below the soft limits, the timer is disabled. If the timer - pops, the particular limit that has been exceeded is treated as if the - hard limit has been reached, and no more resources are allocated to the - user. The only way to reset this condition, short of turning off limit - enforcement or increasing the limit, is to reduce usage below quota. - Only the superuser can set the time limits and this is done on a per - filesystem basis. - - Surviving When the Quota Limit Is Reached - In most cases, the only way for a user to recover from over-quota - conditions is to abort whatever activity is in progress on the filesystem - that has reached its limit, remove sufficient files to bring the limit - back below quota, and retry the failed program. - - However, if a user is in the editor and a write fails because of an over - quota situation, that is not a suitable course of action. It is most - likely that initially attempting to write the file has truncated its - previous contents, so if the editor is aborted without correctly writing - the file, not only are the recent changes lost, but possibly much, or - even all, of the contents that previously existed. - - There are several possible safe exits for a user caught in this - situation. He can use the editor ! shell escape command to examine his - file space and remove surplus files. Alternatively, using csh(1), he can - suspend the editor, remove some files, then resume it. A third - possibility is to write the file to some other filesystem (perhaps to a - file on /tmp) where the user's quota has not been exceeded. Then after - rectifying the quota situation, the file can be moved back to the - filesystem it belongs on. - - -ADMINISTRATION - -Quotas is a configurable subsystem that is optionally built into the kernel. -A decision as to which filesystems need to have quotas enabled needs to be -made. Usually, only filesystems that house users' home directories or other -user files need to be subjected to the quota system. It is recommended that -the filesystem housing /tmp should be free of quotas. - -XFS and the Linux VFS quota systems (e.g. as used on ext2 filesystems) share -many characteristics. We begin with an overview of how the Linux VFS quota -system is administered. - - Administering the Linux VFS Quota System - On most filesystems, quota file(s) should be created in the root of - those filesystems that are to have quotas. These files should be of - size zero and should be readable and writable only by root. After - deciding on the filesystems that will have quotas, the administrator - then establishes quotas for individual users. - The edquota(8) and/or setquota(8) commands are used to actually set - the limits desired upon each user. Where a number of users are to be - given the same quotas (a common occurrence) the -p option to edquota - allows this to be easily accomplished. Unless explicitly given a quota, - users have no limits set on the amount of disk they can use or the number - of files they can create. - - Once the quotas are set and ready to operate, the system must be informed - to enforce quotas on the desired filesystems. This is accomplished with - the quotaon(8) command. For quotas to be accurate, it should be enabled - on a local filesystem immediately after the filesystem has been mounted. - quotaon either enables quotas for a particular filesystem or, with the -a - option, enables quotas for each filesystem indicated in /etc/fstab as - using quotas. See mount(8) for details. When the quota package is - installed, - - /usr/etc/quotaon -a - - can be automatically executed during system boot up time by the startup - scripts. - - When quotas need to be disabled, the quotaoff(8) command is used. - However, if the filesystem is about to be dismounted, the umount(8) - command disables quotas immediately before the filesystem is unmounted. - This is actually an effect of the umount(2) system call, and it - guarantees that the quota system is not disabled if the umount would fail - because the filesystem is not idle. - - Periodically (certainly after each reboot and when quotas are first - enabled for a filesystem), the records retained in the quota file should - be checked for consistency with the actual number of blocks and files - allocated to the user. The quotacheck(8) command is used to accomplish - this. It is not necessary to unmount the filesystem or disable the - quota system to run this command, though on active filesystems inaccurate - results may occur. This does no real harm in most cases; another run of - quotacheck when the filesystem is idle corrects any inaccuracy. The - startup scripts can be configured to run quotacheck automatically. - - The superuser can use the quota command to examine the usage and quotas - of any user, and the repquota(8) command can be used to check the usages - and limits for all users on a filesystem. - - Administering the XFS Quota System - The XFS quota system is different from that of the Linux VFS in many ways. - - o There is no need for quota file(s) in the root of the XFS filesystem. - - o XFS distinguishes between quota accounting and limit enforcement. - Quota accounting must be turned on at the time of mounting the XFS - filesystem. However, it is possible to turn on/off limit - enforcement any time quota accounting is turned on. The "quota" - option in mount(8) turns on both (user) quota accounting and - enforcement. The "uqnoenforce" option must be used to turn on - user accounting with limit enforcement disabled. quotaon(8) - contains some examples of frequently used procedures. - - o Turning on quotas on the root filesystem is slightly different - from the above. In more recent versions of XFS, the quota mount - flags must be passed in with the "rootflags=" boot parameter. - In older versions of XFS and (quota-tools) quotaon(8) must be - used on the root XFS filesystem first; and quotas will be turned - on the next time the system is rebooted. - - o It is useful to use repquota(8) with the -v option to monitor - the XFS quota state at various stages. - - o quotacheck(8) has no effect on XFS filesystems. The first time - quota accounting is turned on, XFS does an automatic quotacheck - internally; afterwards, the quota system will always be completely - consistent until quotas are manually turned off. - - o repquota(8) with the -v option can be used to monitor the status of - the quota system of an XFS filesystem. This can be used to see if - quotas are turned on, given an XFS filesystem. It can also be used - to monitor the space occupied by the quota system itself. - - o Refer to the xfsdump(8), xfsdq(8), and xfsrq(8) man pages, from the - xfsdump package, which describes a mechanism built into xfsdump that - allows quota limit information to be backed up and easily restored. - - o edquota(8) and setquota(8) cannot be used to set quota limits before - turning on quotas on the filesystem concerned. - - o XFS filesystems keep quota accounting on the superuser, and quota -v - will display the superuser's usage information. However, limits are - never enforced on the superuser. - - o XFS filesystems keep quota accounting whether the user has quota - limits or not. - - -IMPLEMENTATION NOTES - - On filesystems using Linux VFS quota, disk quota usage information is - stored in a file on the filesystem that the quotas are to be applied to. - Conventionally, this file is called quotas, and resides at the root of - the filesystem. - - The system is informed of the existence of the quota file by the quotactl - system call. It then reads the quota entries for any open files owned by - users. Each subsequent open of a file in the filesystem is accompanied - by a pairing with its quota information. - - Each time a block is accessed or released and each time an inode is - allocated or freed, the quota system gets told about it and, in the case - of allocations, gets the opportunity to deny the allocation. - - Note that the XFS quota system implementation is radically different - to the Linux VFS described above. XFS considers quota information as - filesystem metadata and uses journaling to provide a higher level - guarantee of consistency. - - -GETTING STARTED - - To use quota under XFS you will need the following: - o An XFS aware kernel; - o XFS quota must be enabled at the time XFS is built - (CONFIG_XFS_QUOTA, below XFS in the Filesystems menu) - - in older kernel versions this also required CONFIG_QUOTA - to be set, but this is no longer true; - o Userspace quota tools which are aware of XFS quota. - - User tools which support XFS can be downloaded from the Linux - quota project at: - http://sourceforge.net/projects/linuxquota/ - The quota tools from version 3.01-pre2 onward have full support - for XFS. They can be downloaded via cvs or as a source tarball. - - Building the user tools from source: - # autoconf - # ./configure --prefix=/usr --mandir=/usr/share/man - # make - # make install - - -EXAMPLES - ->>> Enabling quota enforcement on an XFS filesystem - -[root@troppo]# echo /dev/hdb10 /mnt/xqm xfs rw,usrquota 0 0 >>/etc/fstab -[root@troppo]# mount /mnt/xqm - ->>> Set limits for a user (can also use edquota, interactively) - -[root@troppo]# setquota nathans 600 800 15 20 /mnt/xqm - ->>> Report current user quota - -[root@troppo]# repquota /mnt/xqm -*** Report for user quotas on device /dev/hdb10 -Block grace time: 7days; Inode grace time: 7days - Block limits File limits -User used soft hard grace used soft hard grace ----------------------------------------------------------------------- -root -- 1552 0 0 11 0 0 -nathans -- 440 600 800 8 15 20 -pcpqa -- 880 0 0 1 0 0 - ->>> Push user over quota (see "File limits" above for user "nathans") - -[nathans@troppo]$ sh -sh-2.04$ for i in 0 1 2 3 4 5 6 7 8 9 10 11 12 13 -> do -> touch /mnt/xqm/blat/file${i} -> done -touch: creating `/mnt/xqm/blat/file12': Disk quota exceeded -touch: creating `/mnt/xqm/blat/file13': Disk quota exceeded -sh-2.04$ ^D - ->>> Report current user quota again - -[root@troppo]# repquota /mnt/xqm -*** Report for user quotas on device /dev/hdb10 -Block grace time: 7days; Inode grace time: 7days - Block limits File limits -User used soft hard grace used soft hard grace ----------------------------------------------------------------------- -root -- 1560 0 0 11 0 0 -nathans -+ 440 600 800 20 15 20 7 days -pcpqa -- 880 0 0 1 0 0 - ->>> From the users point of view: - -[nathans@troppo]$ quota -Disk quotas for user nathans (uid 16302): - Filesystem blocks quota limit grace files quota limit grace - /dev/hdb10 440 600 800 20* 15 20 7 days - ->>> Run warnquota(8) via cron(8) to periodically inform users of violations. - - -CAVEATS - -The XFS allocation mechanism will always reserve the maximum amount of -space required before proceeding with a space allocation. If insufficient -space for this reservation is available, due to the users block quota limit -being reached for example, this may result in the allocation failing even -though there is sufficient space. Quota enforcement can thus sometimes -happen in situations where the user is under quota and the end result of -some operation would still have left the user under quota had the operation -been allowed to run its course. This is an unavoidable side of affect of -the way XFS operates, so should be kept in mind when assigning users block -limits. This additional overhead is typically in the range of tens of -blocks - xfs_info(8) can be used to report the filesystem block size. - -On IRIX, XFS supports project quota. This is not (ever) likely to be -supported on Linux/XFS, as the concept of a project is specific to IRIX. -A filesystem that has used user quota on IRIX, however, can be migrated -to Linux, and vice-versa, as the ondisk format is shared between both -versions of XFS (and Linux/XFS is "endian clean"). Group quota support -has been implemented only in more recent versions of IRIX 6.5f, and the -same level of ondisk compatibility is now available as for user quota. - -Have fun, - - -- nathans@sgi.com - diff --git a/growfs/Makefile b/growfs/Makefile index a6c87e1af..b59a3dfe9 100644 --- a/growfs/Makefile +++ b/growfs/Makefile @@ -1,5 +1,5 @@ # -# Copyright (c) 2000-2001 Silicon Graphics, Inc. All Rights Reserved. +# Copyright (c) 2000-2001,2004-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 @@ -36,15 +36,9 @@ include $(TOPDIR)/include/builddefs LTCOMMAND = xfs_growfs CFILES = xfs_growfs.c -ifeq ($(PKG_PLATFORM),linux) -CFILES += explore.c -else -LSRCFILES = explore.c -endif -HFILES = explore.h -LLDLIBS = $(LIBXFS) $(LIBUUID) -LTDEPENDENCIES = $(LIBXFS) +LLDLIBS = $(LIBXFS) $(LIBXCMD) $(LIBUUID) +LTDEPENDENCIES = $(LIBXFS) $(LIBXCMD) LLDFLAGS = -static LSRCFILES = xfs_info.sh diff --git a/growfs/explore.c b/growfs/explore.c deleted file mode 100644 index 8c720b60f..000000000 --- a/growfs/explore.c +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright (c) 2000-2003 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 -#include - -extern char *fname; /* mount point name */ -extern char *datadev; /* data device name */ -extern char *logdev; /* log device name */ -extern char *rtdev; /* RT device name */ - -void -explore_mtab(char *mtab, char *mntpoint) -{ - struct mntent *mnt; - struct stat64 statuser; - struct stat64 statmtab_dir; - struct stat64 statmtab_dev; - FILE *mtp; - char *rtend; - char *logend; - int havedev; - - if (!mtab) - mtab = MOUNTED; - - if ((mtp = setmntent(mtab, "r")) == NULL) { - fprintf(stderr, _("%s: cannot access mount list %s: %s\n"), - progname, MOUNTED, strerror(errno)); - exit(1); - } - if (stat64(mntpoint, &statuser) < 0) { - fprintf(stderr, _("%s: cannot access mount point %s: %s\n"), - progname, mntpoint, strerror(errno)); - exit(1); - } - - while ((mnt = getmntent(mtp)) != NULL) { - if (stat64(mnt->mnt_dir, &statmtab_dir) < 0) { - fprintf(stderr, _("%s: ignoring entry %s in %s: %s\n"), - progname, mnt->mnt_dir, mtab, strerror(errno)); - continue; - } - havedev = (stat64(mnt->mnt_fsname, &statmtab_dev) != -1); - if ( !((statuser.st_ino == statmtab_dir.st_ino && - statuser.st_dev == statmtab_dir.st_dev) || - (statuser.st_ino == statmtab_dev.st_ino && - statuser.st_dev == statmtab_dev.st_dev && - havedev)) ) - continue; - else if (strcmp(mnt->mnt_type, "xfs") != 0) { - fprintf(stderr, _("%s: %s is not an XFS filesystem\n"), - progname, mntpoint); - exit(1); - } - break; /* we've found it */ - } - - if (mnt == NULL) { - fprintf(stderr, - _("%s: %s is not a mounted XFS filesystem, according to %s\n"), - progname, mntpoint, MOUNTED); - exit(1); - } - - /* find the data, log (logdev=), and realtime (rtdev=) devices */ - rtend = logend = NULL; - fname = mnt->mnt_dir; - datadev = mnt->mnt_fsname; - if ((logdev = hasmntopt(mnt, "logdev="))) { - logdev += 7; - logend = strtok(logdev, " ,"); - } - if ((rtdev = hasmntopt(mnt, "rtdev="))) { - rtdev += 6; - rtend = strtok(rtdev, " ,"); - } - - /* Do this only after we've finished processing mount options */ - if (logdev && logend != logdev) - *logend = '\0'; /* terminate end of log device name */ - if (rtdev && rtend != rtdev) - *rtend = '\0'; /* terminate end of rt device name */ - - endmntent(mtp); -} diff --git a/growfs/xfs_growfs.c b/growfs/xfs_growfs.c index ed96e8555..843fd5e80 100644 --- a/growfs/xfs_growfs.c +++ b/growfs/xfs_growfs.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2003 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (c) 2000-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 @@ -31,7 +31,7 @@ */ #include -#include "explore.h" +#include /* * When growing a filesystem, this is the most significant @@ -41,11 +41,6 @@ #define XFS_MAX_INODE_SIG_BITS 32 -char *fname; /* mount point name */ -char *datadev; /* data device name */ -char *logdev; /* log device name */ -char *rtdev; /* RT device name */ - static void usage(void) { @@ -125,13 +120,17 @@ main(int argc, char **argv) long long lsize; /* new log size in fs blocks */ int maxpct; /* -m flag value */ int mflag; /* -m flag */ - char *mtab; /* mount table file (/etc/mtab) */ int nflag; /* -n flag */ xfs_fsop_geom_t ngeo; /* new fs geometry */ int rflag; /* -r flag */ long long rsize; /* new rt size in fs blocks */ int unwritten; /* unwritten extent flag */ int xflag; /* -x flag */ + char *fname; /* mount point name */ + char *datadev; /* data device name */ + char *logdev; /* log device name */ + char *rtdev; /* RT device name */ + fs_path_t *fs; /* mount point information */ libxfs_init_t xi; /* libxfs structure */ progname = basename(argv[0]); @@ -139,7 +138,6 @@ main(int argc, char **argv) bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); - mtab = NULL; maxpct = esize = 0; dsize = lsize = rsize = 0LL; aflag = dflag = iflag = lflag = mflag = nflag = rflag = xflag = 0; @@ -182,7 +180,7 @@ main(int argc, char **argv) rflag = 1; break; case 't': - mtab = optarg; + mtab_file = optarg; break; case 'x': lflag = xflag = 1; @@ -202,7 +200,18 @@ main(int argc, char **argv) if (dflag + lflag + rflag == 0) aflag = 1; - explore_mtab(mtab, argv[optind]); + fs_table_initialise(); + fs = fs_table_lookup(argv[optind], FS_MOUNT_POINT); + if (!fs) { + fprintf(stderr, _("%s: %s is not a mounted XFS filesystem\n"), + progname, argv[optind]); + return 1; + } + + fname = fs->fs_dir; + datadev = fs->fs_name; + logdev = fs->fs_log; + rtdev = fs->fs_rt; ffd = open(fname, O_RDONLY); if (ffd < 0) { diff --git a/include/Makefile b/include/Makefile index be824d15f..bc3e3e9b2 100644 --- a/include/Makefile +++ b/include/Makefile @@ -49,6 +49,7 @@ PHFILES = darwin.h freebsd.h irix.h linux.h DKHFILES = volume.h fstyp.h dvh.h LSRCFILES = $(shell echo $(PHFILES) | sed -e "s/$(PKG_PLATFORM).h//g") LSRCFILES += platform_defs.h.in builddefs.in buildmacros buildrules $(DKHFILES) +LSRCFILES += path.h project.h command.h input.h LDIRT = xfs disk default install : diff --git a/include/builddefs.in b/include/builddefs.in index 7db6438e6..ac5780a01 100644 --- a/include/builddefs.in +++ b/include/builddefs.in @@ -45,6 +45,7 @@ LIBTERMCAP = @libtermcap@ LIBEDITLINE = @libeditline@ LIBREADLINE = @libreadline@ LIBXFS = $(TOPDIR)/libxfs/libxfs.la +LIBXCMD = $(TOPDIR)/libxcmd/libxcmd.la LIBXLOG = $(TOPDIR)/libxlog/libxlog.la LIBDISK = $(TOPDIR)/libdisk/libdisk.la LIBHANDLE = $(TOPDIR)/libhandle/libhandle.la diff --git a/io/command.h b/include/command.h similarity index 79% rename from io/command.h rename to include/command.h index fb3377a79..82cb682b2 100644 --- a/io/command.h +++ b/include/command.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (c) 2000-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 @@ -29,16 +29,12 @@ * * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ */ - -#define min(a,b) (((a)<(b))?(a):(b)) +#ifndef __COMMAND_H__ +#define __COMMAND_H__ typedef int (*cfunc_t)(int argc, char **argv); typedef void (*helpfunc_t)(void); -#define CMD_NOFILE_OK (1<<0) /* command doesn't need an open file */ -#define CMD_NOMAP_OK (1<<1) /* command doesn't need a mapped region */ -#define CMD_FOREIGN_OK (1<<2) /* command not restricted to XFS files */ - typedef struct cmdinfo { const char *name; const char *altname; @@ -55,8 +51,21 @@ typedef struct cmdinfo { extern cmdinfo_t *cmdtab; extern int ncmds; +extern void help_init(void); +extern void quit_init(void); + +typedef int (*argsfunc_t)(int index); +typedef int (*checkfunc_t)(const cmdinfo_t *ci); + extern void add_command(const cmdinfo_t *ci); +extern void add_user_command(char *optarg); +extern void add_args_command(argsfunc_t af); +extern void add_check_command(checkfunc_t cf); + +extern const cmdinfo_t *find_command(const char *cmd); + +extern void command_loop(void); extern int command_usage(const cmdinfo_t *ci); extern int command(int argc, char **argv); -extern const cmdinfo_t *find_command(const char *cmd); +#endif /* __COMMAND_H__ */ diff --git a/io/input.h b/include/input.h similarity index 72% rename from io/input.h rename to include/input.h index 36a19ee47..d7f836295 100644 --- a/io/input.h +++ b/include/input.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (c) 2000-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 @@ -29,13 +29,23 @@ * * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ */ +#ifndef __INPUT_H__ +#define __INPUT_H__ + +#include +#include +#include +#include extern char **breakline(char *input, int *count); extern void doneline(char *input, char **vec); extern char *fetchline(void); -extern void init_cvtnum(int *blocksize, int *sectorsize); + extern long long cvtnum(int blocksize, int sectorsize, char *s); extern void cvtstr(double value, char *str, size_t sz); +extern unsigned long cvttime(char *s); + +extern struct timeval tadd(struct timeval t1, struct timeval t2); extern struct timeval tsub(struct timeval t1, struct timeval t2); extern double tdiv(double value, struct timeval tv); @@ -47,3 +57,22 @@ enum { extern void timestr(struct timeval *tv, char *str, size_t sz, int flags); +extern uid_t uid_from_string(char *user); +extern gid_t gid_from_string(char *group); +extern prid_t prid_from_string(char *project); + +#define HAVE_FTW_H 1 /* TODO: configure me */ + +#ifdef HAVE_FTW_H +#include +#else +struct FTW; +struct stat; +extern int nftw( + char *dir, + int (*fn)(const char *, const struct stat *, int, struct FTW *), + int depth, + int flags); +#endif + +#endif /* __INPUT_H__ */ diff --git a/include/path.h b/include/path.h new file mode 100644 index 000000000..e2f8e41b2 --- /dev/null +++ b/include/path.h @@ -0,0 +1,83 @@ +/* + * 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/ + */ +#ifndef __PATHS_H__ +#define __PATHS_H__ + +#include + +/* + * XFS Filesystem Paths + * + * Utility routines for iterating and searching through the list + * of known mounted filesystems and project paths. + */ + +#define FS_MOUNT_POINT (1<<0) +#define FS_PROJECT_PATH (1<<1) + +typedef struct fs_path { + char *fs_name; /* Data device for filesystem */ + dev_t fs_datadev; + char *fs_log; /* External log device, if any */ + dev_t fs_logdev; + char *fs_rt; /* Realtime device, if any */ + dev_t fs_rtdev; + char *fs_dir; /* Directory / mount point */ + uint fs_flags; /* FS_MOUNT_POINT/FS_MOUNT_TREE */ + uint fs_prid; /* Project ID for tree root */ +} fs_path_t; + +extern int fs_count; /* number of entries in fs table */ +extern fs_path_t *fs_table; /* array of entries in fs table */ +extern fs_path_t *fs_path; /* current entry in the fs table */ +extern char *mtab_file; + +extern void fs_table_initialise(void); +extern void fs_table_destroy(void); + +extern void fs_table_insert_mount(char *__mount); +extern void fs_table_insert_project(char *__project); + +extern fs_path_t *fs_table_lookup(const char *__dir, uint __flags); + +typedef struct fs_cursor { + uint count; /* total count of mount entries */ + uint index; /* current position in table */ + uint flags; /* iterator flags: mounts/trees */ + fs_path_t *table; /* local/global table pointer */ + fs_path_t local; /* space for single-entry table */ +} fs_cursor_t; + +extern void fs_cursor_initialise(char *__dir, uint __flags, fs_cursor_t *__cp); +extern fs_path_t *fs_cursor_next_entry(fs_cursor_t *__cp); + +#endif /* __PATHS_H__ */ diff --git a/growfs/explore.h b/include/project.h similarity index 56% rename from growfs/explore.h rename to include/project.h index 8f2b480ba..b605211bf 100644 --- a/growfs/explore.h +++ b/include/project.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. + * 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 @@ -29,20 +29,37 @@ * * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ */ -#ifndef XFS_GROWFS_EXPLORE_H -#define XFS_GROWFS_EXPLORE_H +#ifndef __PROJECT_H__ +#define __PROJECT_H__ -/* - * This was written as part of the Linux port. On IRIX, - * the volume managers have knowledge of log and realtime - * subvolumes, and the equivalent functionality is built - * into the kernel - XFS/XLV/XVM talk amongst themselves - * and there are no rtdev/logdev mount parameters at all. - */ -#ifdef __linux__ -extern void explore_mtab(char *mtab, char *mntpoint); -#else -# define explore_mtab(mtab, mpoint) do { } while (0) -#endif +#include + +typedef __uint32_t prid_t; +extern int setprojid(const char *__name, int __fd, prid_t __id); +extern int getprojid(const char *__name, int __fd, prid_t *__id); + +typedef struct fs_project { + prid_t pr_prid; /* project identifier */ + char *pr_name; /* project name */ +} fs_project_t; + +extern void setprent(void); +extern void endprent(void); +extern fs_project_t *getprent(void); +extern fs_project_t *getprnam(char *__name); +extern fs_project_t *getprprid(prid_t __id); + +typedef struct fs_project_path { + prid_t pp_prid; /* project identifier */ + char *pp_pathname; /* pathname to root of project tree */ +} fs_project_path_t; + +extern void setprpathent(void); +extern void endprpathent(void); +extern fs_project_path_t *getprpathent(void); + +extern void setprfiles(void); +extern char *projid_file; +extern char *projects_file; -#endif /* XFS_GROWFS_EXPLORE_H */ +#endif /* __PROJECT_H__ */ diff --git a/io/Makefile b/io/Makefile index f132273bd..0bc9c5be8 100644 --- a/io/Makefile +++ b/io/Makefile @@ -35,11 +35,15 @@ include $(TOPDIR)/include/builddefs LTCOMMAND = xfs_io LSRCFILES = xfs_bmap.sh xfs_freeze.sh -HFILES = command.h input.h init.h io.h -CFILES = command.c input.c init.c help.c quit.c \ +HFILES = init.h io.h +CFILES = init.c \ attr.c bmap.c file.c freeze.c fsync.c getrusage.c imap.c \ mmap.c open.c pread.c prealloc.c pwrite.c truncate.c +LLDLIBS = $(LIBXCMD) +LTDEPENDENCIES = $(LIBXCMD) +LLDFLAGS = -static + ifeq ($(HAVE_FADVISE),yes) CFILES += fadvise.c LCFLAGS += -DHAVE_FADVISE diff --git a/io/attr.c b/io/attr.c index 0e82b39cd..fae6d73d8 100644 --- a/io/attr.c +++ b/io/attr.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2004 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (c) 2003-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 @@ -36,30 +36,12 @@ #include "init.h" #include "io.h" -#define HAVE_FTW_H 1 /* TODO: configure me */ - -#ifdef HAVE_FTW_H -#include -#else -static int -nftw( - char *dir, - int (*fn)(const char *, const struct stat *, int, struct FTW *), - int depth, - int flags) -{ - fprintf(stderr, "%s: not implemented, no recursion available\n", - __FUNCTION__); - return 0; -} -#endif - static cmdinfo_t chattr_cmd; static cmdinfo_t lsattr_cmd; static unsigned int orflags; static unsigned int andflags; -static unsigned int recurse_all; -static unsigned int recurse_dir; +unsigned int recurse_all; +unsigned int recurse_dir; #define CHATTR_XFLAG_LIST "riasAdtPn" diff --git a/io/init.c b/io/init.c index dc6018d78..c1f81ff9e 100644 --- a/io/init.c +++ b/io/init.c @@ -33,6 +33,7 @@ #include #include "command.h" #include "input.h" +#include "init.h" #include "io.h" char *progname; @@ -41,9 +42,6 @@ int expert; size_t pagesize; struct timeval stopwatch; -static int ncmdline; -static char **cmdline; - void usage(void) { @@ -54,6 +52,20 @@ usage(void) } void +init_cvtnum( + int *blocksize, + int *sectsize) +{ + if (!file || (file->flags & IO_FOREIGN)) { + *blocksize = 4096; + *sectsize = 512; + } else { + *blocksize = file->geom.blocksize; + *sectsize = file->geom.sectsize; + } +} + +static void init_commands(void) { attr_init(); @@ -78,6 +90,38 @@ init_commands(void) truncate_init(); } +static int +init_args_command( + int index) +{ + if (index >= filecount) + return 0; + file = &filetable[index++]; + return index; +} + +static int +init_check_command( + const cmdinfo_t *ct) +{ + if (!file && !(ct->flags & CMD_NOFILE_OK)) { + fprintf(stderr, _("no files are open, try 'help open'\n")); + return 0; + } + if (!mapping && !(ct->flags & CMD_NOMAP_OK)) { + fprintf(stderr, _("no mapped regions, try 'help mmap'\n")); + return 0; + } + if (file && !(ct->flags & CMD_FOREIGN_OK) && + (file->flags & IO_FOREIGN)) { + fprintf(stderr, + _("foreign file active, %s command is for XFS filesystems only\n"), + ct->name); + return 0; + } + return 1; +} + void init( int argc, @@ -102,13 +146,7 @@ init( flags |= IO_APPEND; break; case 'c': /* commands */ - ncmdline++; - cmdline = realloc(cmdline, sizeof(char*) * (ncmdline)); - if (!cmdline) { - perror("realloc"); - exit(1); - } - cmdline[ncmdline-1] = optarg; + add_user_command(optarg); break; case 'd': flags |= IO_DIRECT; @@ -163,6 +201,8 @@ init( } init_commands(); + add_args_command(init_args_command); + add_check_command(init_check_command); } int @@ -170,32 +210,7 @@ main( int argc, char **argv) { - int c, i, j, done = 0; - char *input; - char **v; - init(argc, argv); - - for (i = 0; !done && i < ncmdline; i++) { - for (j = 0; !done && j < filecount; j++) { - file = &filetable[j]; - v = breakline(cmdline[i], &c); - if (c) - done = command(c, v); - free(v); - } - } - if (cmdline) { - free(cmdline); - return exitcode; - } - while (!done) { - if ((input = fetchline()) == NULL) - break; - v = breakline(input, &c); - if (c) - done = command(c, v); - doneline(input, v); - } + command_loop(); return exitcode; } diff --git a/io/init.h b/io/init.h index 913718514..57b17a765 100644 --- a/io/init.h +++ b/io/init.h @@ -30,8 +30,16 @@ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ */ +#define CMD_NOFILE_OK (1<<0) /* command doesn't need an open file */ +#define CMD_NOMAP_OK (1<<1) /* command doesn't need a mapped region */ +#define CMD_FOREIGN_OK (1<<2) /* command not restricted to XFS files */ + extern char *progname; extern int exitcode; extern int expert; extern size_t pagesize; extern struct timeval stopwatch; + +#define min(a,b) (((a)<(b))?(a):(b)) + +extern void init_cvtnum(int *blocksize, int *sectsize); diff --git a/io/io.h b/io/io.h index d68f013a8..c5cdd4635 100644 --- a/io/io.h +++ b/io/io.h @@ -80,6 +80,9 @@ extern int openfile(char *, xfs_fsop_geom_t *, int, mode_t); extern int addfile(char *, int , xfs_fsop_geom_t *, int); extern void printxattr(uint, int, int, const char *, int, int); +extern unsigned int recurse_all; +extern unsigned int recurse_dir; + extern void *buffer; extern ssize_t buffersize; extern int alloc_buffer(ssize_t, int, unsigned int); diff --git a/io/open.c b/io/open.c index 90495132e..398e291fb 100644 --- a/io/open.c +++ b/io/open.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2004 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (c) 2003-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 @@ -44,6 +44,7 @@ static cmdinfo_t statfs_cmd; static cmdinfo_t chproj_cmd; static cmdinfo_t lsproj_cmd; static cmdinfo_t extsize_cmd; +static prid_t prid; off64_t filesize(void) @@ -354,24 +355,111 @@ close_f( return 0; } +static void +lsproj_help(void) +{ + printf(_( +"\n" +" displays the project identifier associated with the current path\n" +"\n" +" Options:\n" +" -R -- recursively descend (useful when current path is a directory)\n" +" -D -- recursively descend, but only list projects on directories\n" +"\n")); +} + +static int +lsproj_callback( + const char *path, + const struct stat *stat, + int status, + struct FTW *data) +{ + prid_t projid; + int fd; + + if (recurse_dir && !S_ISDIR(stat->st_mode)) + return 0; + + if ((fd = open(path, O_RDONLY)) == -1) { + fprintf(stderr, _("%s: cannot open %s: %s\n"), + progname, path, strerror(errno)); + } else { + if (getprojid(path, fd, &projid) == 0) + printf("[%u] %s\n", projid, path); + close(fd); + } + return 0; +} + static int lsproj_f( int argc, char **argv) { - __uint32_t id; + prid_t projid; + int c; -#if defined(__sgi__) - struct stat64 st; - if (fstat64(file->fd, &st) < 0) { - perror("fstat64"); + while ((c = getopt(argc, argv, "DR")) != EOF) { + switch (c) { + case 'D': + recurse_all = 0; + recurse_dir = 1; + break; + case 'R': + recurse_all = 1; + recurse_dir = 0; + break; + default: + return command_usage(&lsproj_cmd); + } + } + + if (argc != optind) + return command_usage(&lsproj_cmd); + + if (recurse_all || recurse_dir) + nftw(file->name, lsproj_callback, + 100, FTW_PHYS | FTW_MOUNT | FTW_DEPTH); + else if (getprojid(file->name, file->fd, &projid) < 0) + perror("getprojid"); + else + printf(_("projid = %u\n"), projid); + return 0; +} + +static void +chproj_help(void) +{ + printf(_( +"\n" +" modifies the project identifier associated with the current path\n" +"\n" +" -R -- recursively descend (useful when current path is a directory)\n" +" -D -- recursively descend, only modifying projects on directories\n" +"\n")); +} + +static int +chproj_callback( + const char *path, + const struct stat *stat, + int status, + struct FTW *data) +{ + int fd; + + if (recurse_dir && !S_ISDIR(stat->st_mode)) return 0; + + if ((fd = open(path, O_RDONLY)) == -1) { + fprintf(stderr, _("%s: cannot open %s: %s\n"), + progname, path, strerror(errno)); + } else { + if (setprojid(path, fd, prid) < 0) + perror("setprojid"); + close(fd); } - id = st.st_projid; -#else - id = 0; -#endif - printf("projid = %u\n", (unsigned int)id); return 0; } @@ -380,20 +468,37 @@ chproj_f( int argc, char **argv) { - __uint32_t id; - char *sp; + int c; - id = (__uint32_t) strtoul(argv[1], &sp, 0); - if (!sp || sp == argv[1]) { - printf(_("non-numeric project ID -- %s\n"), argv[1]); + while ((c = getopt(argc, argv, "DR")) != EOF) { + switch (c) { + case 'D': + recurse_all = 0; + recurse_dir = 1; + break; + case 'R': + recurse_all = 1; + recurse_dir = 0; + break; + default: + return command_usage(&chproj_cmd); + } + } + + if (argc != optind + 1) + return command_usage(&chproj_cmd); + + prid = prid_from_string(argv[optind]); + if (prid == -1) { + printf(_("invalid project ID -- %s\n"), argv[optind]); return 0; } -#if defined(__sgi__) - if (fchproj(file->fd, id) < 0) - perror("fchproj"); -#else - printf(_("Not yet implemented\n")); -#endif + + if (recurse_all || recurse_dir) + nftw(file->name, chproj_callback, + 100, FTW_PHYS | FTW_MOUNT | FTW_DEPTH); + else if (setprojid(file->name, file->fd, prid) < 0) + perror("setprojid"); return 0; } @@ -564,20 +669,23 @@ open_init(void) chproj_cmd.name = _("chproj"); chproj_cmd.cfunc = chproj_f; - chproj_cmd.args = _("projid"); + chproj_cmd.args = _("[-D | -R] projid"); chproj_cmd.argmin = 1; - chproj_cmd.argmax = 1; + chproj_cmd.argmax = -1; chproj_cmd.flags = CMD_NOMAP_OK; chproj_cmd.oneline = _("change project identifier on the currently open file"); + chproj_cmd.help = chproj_help; lsproj_cmd.name = _("lsproj"); lsproj_cmd.cfunc = lsproj_f; + lsproj_cmd.args = _("[-D | -R]"); lsproj_cmd.argmin = 0; - lsproj_cmd.argmax = 0; + lsproj_cmd.argmax = -1; lsproj_cmd.flags = CMD_NOMAP_OK; lsproj_cmd.oneline = _("list project identifier set on the currently open file"); + lsproj_cmd.help = lsproj_help; extsize_cmd.name = _("extsize"); extsize_cmd.cfunc = extsize_f; diff --git a/libxcmd/Makefile b/libxcmd/Makefile new file mode 100644 index 000000000..d989a23e2 --- /dev/null +++ b/libxcmd/Makefile @@ -0,0 +1,50 @@ +# +# 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/ +# + +TOPDIR = .. +include $(TOPDIR)/include/builddefs + +LTLIBRARY = libxcmd.la +LT_CURRENT = 0 +LT_REVISION = 0 +LT_AGE = 0 + +CFILES = command.c input.c paths.c projects.c help.c quit.c + +default: $(LTLIBRARY) + +include $(BUILDRULES) + +install: default + +install-dev: default + $(INSTALL_LTLIB_STATIC) diff --git a/io/command.c b/libxcmd/command.c similarity index 63% rename from io/command.c rename to libxcmd/command.c index 041ad76f6..ce1c10609 100644 --- a/io/command.c +++ b/libxcmd/command.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2004 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (c) 2003-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 @@ -31,15 +31,19 @@ */ #include -#include "command.h" -#include "init.h" -#include "io.h" +#include +#include cmdinfo_t *cmdtab; int ncmds; +static argsfunc_t args_func; +static checkfunc_t check_func; +static int ncmdline; +static char **cmdline; + static int -cmd_compare(const void *a, const void *b) +compare(const void *a, const void *b) { return strcmp(((const cmdinfo_t *)a)->name, ((const cmdinfo_t *)b)->name); @@ -51,14 +55,30 @@ add_command( { cmdtab = realloc((void *)cmdtab, ++ncmds * sizeof(*cmdtab)); cmdtab[ncmds - 1] = *ci; - qsort(cmdtab, ncmds, sizeof(*cmdtab), cmd_compare); + qsort(cmdtab, ncmds, sizeof(*cmdtab), compare); +} + +static int +check_command( + const cmdinfo_t *ci) +{ + if (check_func) + return check_func(ci); + return 1; +} + +void +add_check_command( + checkfunc_t cf) +{ + check_func = cf; } int command_usage( const cmdinfo_t *ci) { - printf("%s %s\n", ci->name, ci->oneline); + printf("%s %s -- %s\n", ci->name, ci->args, ci->oneline); return 0; } @@ -76,21 +96,8 @@ command( fprintf(stderr, _("command \"%s\" not found\n"), cmd); return 0; } - if (!file && !(ct->flags & CMD_NOFILE_OK)) { - fprintf(stderr, _("no files are open, try 'help open'\n")); + if (!check_command(ct)) return 0; - } - if (!mapping && !(ct->flags & CMD_NOMAP_OK)) { - fprintf(stderr, _("no mapped regions, try 'help mmap'\n")); - return 0; - } - if (file && !(ct->flags & CMD_FOREIGN_OK) && - (file->flags & IO_FOREIGN)) { - fprintf(stderr, - _("foreign file active, %s command is for XFS filesystems only\n"), - cmd); - return 0; - } if (argc-1 < ct->argmin || (ct->argmax != -1 && argc-1 > ct->argmax)) { if (ct->argmax == -1) fprintf(stderr, @@ -123,3 +130,68 @@ find_command( } return NULL; } + +void +add_user_command(char *optarg) +{ + ncmdline++; + cmdline = realloc(cmdline, sizeof(char*) * (ncmdline)); + if (!cmdline) { + perror("realloc"); + exit(1); + } + cmdline[ncmdline-1] = optarg; +} + +static int +args_command( + int index) +{ + if (args_func) + return args_func(index); + return 0; +} + +void +add_args_command( + argsfunc_t af) +{ + args_func = af; +} + +void +command_loop(void) +{ + int c, i, j = 0, done = 0; + char *input; + char **v; + + for (i = 0; !done && i < ncmdline; i++) { + while (!done && (j = args_command(j))) { + input = strdup(cmdline[i]); + if (!input) { + fprintf(stderr, + _("cannot strdup command '%s': %s\n"), + cmdline[i], strerror(errno)); + exit(1); + } + v = breakline(input, &c); + if (c) + done = command(c, v); + free(v); + free(input); + } + } + if (cmdline) { + free(cmdline); + return; + } + while (!done) { + if ((input = fetchline()) == NULL) + break; + v = breakline(input, &c); + if (c) + done = command(c, v); + doneline(input, v); + } +} diff --git a/io/help.c b/libxcmd/help.c similarity index 93% rename from io/help.c rename to libxcmd/help.c index 68ac15c03..e4dae1ffb 100644 --- a/io/help.c +++ b/libxcmd/help.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2004 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (c) 2003-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 @@ -31,8 +31,7 @@ */ #include -#include "command.h" -#include "io.h" +#include static cmdinfo_t help_cmd; static void help_onecmd(const char *cmd, const cmdinfo_t *ct); @@ -103,7 +102,7 @@ help_init(void) help_cmd.cfunc = help_f; help_cmd.argmin = 0; help_cmd.argmax = 1; - help_cmd.flags = CMD_NOMAP_OK | CMD_NOFILE_OK | CMD_FOREIGN_OK; + help_cmd.flags = -1; help_cmd.args = _("[command]"); help_cmd.oneline = _("help for one or all commands"); diff --git a/io/input.c b/libxcmd/input.c similarity index 72% rename from io/input.c rename to libxcmd/input.c index 11bf850af..5758d8c2c 100644 --- a/io/input.c +++ b/libxcmd/input.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2004 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (c) 2003-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 @@ -31,9 +31,7 @@ */ #include -#include "input.h" -#include "init.h" -#include "io.h" +#include #if defined(ENABLE_READLINE) # include @@ -45,7 +43,7 @@ static char * get_prompt(void) { - static char prompt[FILENAME_MAX + 1]; + static char prompt[FILENAME_MAX + 2 /*"> "*/ + 1 /*"\0"*/ ]; if (!prompt[0]) snprintf(prompt, sizeof(prompt), "%s> ", progname); @@ -123,11 +121,15 @@ breakline( char *p; char **rval = calloc(sizeof(char *), 1); - while ((p = strsep(&input, " ")) != NULL) { + while (rval && (p = strsep(&input, " ")) != NULL) { if (!*p) continue; c++; rval = realloc(rval, sizeof(*rval) * (c + 1)); + if (!rval) { + c = 0; + break; + } rval[c - 1] = p; rval[c] = NULL; } @@ -144,20 +146,6 @@ doneline( free(vec); } -void -init_cvtnum( - int *blocksize, - int *sectsize) -{ - if (!file || (file->flags & IO_FOREIGN)) { - *blocksize = 4096; - *sectsize = 512; - } else { - *blocksize = file->geom.blocksize; - *sectsize = file->geom.sectsize; - } -} - #define EXABYTES(x) ((long long)(x) << 60) #define PETABYTES(x) ((long long)(x) << 50) #define TERABYTES(x) ((long long)(x) << 40) @@ -240,6 +228,54 @@ cvtstr( } } +#define MINUTES_TO_SECONDS(m) ((m) * 60) +#define HOURS_TO_SECONDS(h) ((h) * MINUTES_TO_SECONDS(60)) +#define DAYS_TO_SECONDS(d) ((d) * HOURS_TO_SECONDS(24)) +#define WEEKS_TO_SECONDS(w) ((w) * DAYS_TO_SECONDS(7)) + +unsigned long +cvttime( + char *s) +{ + unsigned long i; + char *sp; + + i = strtoul(s, &sp, 0); + if (i == 0 && sp == s) + return 0; + if (*sp == '\0') + return i; + if ((*sp == 'm' && sp[1] == '\0') || + (strcmp(sp, "minutes") == 0) || + (strcmp(sp, "minute") == 0)) + return MINUTES_TO_SECONDS(i); + if ((*sp == 'h' && sp[1] == '\0') || + (strcmp(sp, "hours") == 0) || + (strcmp(sp, "hour") == 0)) + return HOURS_TO_SECONDS(i); + if ((*sp == 'd' && sp[1] == '\0') || + (strcmp(sp, "days") == 0) || + (strcmp(sp, "day") == 0)) + return DAYS_TO_SECONDS(i); + if ((*sp == 'w' && sp[1] == '\0') || + (strcmp(sp, "weeks") == 0) || + (strcmp(sp, "week") == 0)) + return WEEKS_TO_SECONDS(i); + return 0; +} + +struct timeval +tadd(struct timeval t1, struct timeval t2) +{ + t1.tv_usec += t2.tv_usec; + if (t1.tv_usec > 1000000) { + t1.tv_usec -= 1000000; + t1.tv_sec++; + } + t1.tv_sec += t2.tv_sec; + return t1; +} + struct timeval tsub(struct timeval t1, struct timeval t2) { @@ -292,3 +328,76 @@ timestr( snprintf(ts, size, "0.%04u sec", (unsigned int) usec * 10000); } } + +/* + * Convert from arbitrary user strings into a numeric ID. + * If its all numeric, we convert that inplace, else we do + * the name lookup, and return the found identifier. + */ + +prid_t +prid_from_string( + char *project) +{ + fs_project_t *prj; + prid_t prid; + char *sp; + + prid = strtoul(project, &sp, 10); + if (sp != project) + return prid; + prj = getprnam(project); + if (prj) + return prj->pr_prid; + return -1; +} + +uid_t +uid_from_string( + char *user) +{ + struct passwd *pwd; + uid_t uid; + char *sp; + + uid = strtoul(user, &sp, 10); + if (sp != user) + return uid; + pwd = getpwnam(user); + if (pwd) + return pwd->pw_uid; + return -1; +} + +gid_t +gid_from_string( + char *group) +{ + struct group *grp; + gid_t gid; + char *sp; + + gid = strtoul(group, &sp, 10); + if (sp != group) + return gid; + grp = getgrnam(group); + if (grp) + return grp->gr_gid; + return -1; +} + +#define HAVE_FTW_H 1 /* TODO: configure me */ + +#ifndef HAVE_FTW_H +int +nftw( + char *dir, + int (*fn)(const char *, const struct stat *, int, struct FTW *), + int depth, + int flags) +{ + fprintf(stderr, "%s: not implemented, no recursion available\n", + __FUNCTION__); + return 0; +} +#endif diff --git a/libxcmd/paths.c b/libxcmd/paths.c new file mode 100644 index 000000000..8ff96d5cb --- /dev/null +++ b/libxcmd/paths.c @@ -0,0 +1,430 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define HAVE_MNTENT_H 1 /* TODO - configure me (+HAVE_GETMNTINFO) */ + +int fs_count; +struct fs_path *fs_table; +struct fs_path *fs_path; +char *mtab_file; + +struct fs_path * +fs_table_lookup( + const char *dir, + uint flags) +{ + struct stat64 sbuf; + uint i; + + if (stat64(dir, &sbuf) < 0) + return NULL; + for (i = 0; i < fs_count; i++) { + if ((flags & fs_table[i].fs_flags) == 0) + continue; + if (sbuf.st_dev == fs_table[i].fs_datadev) + return &fs_table[i]; + } + return NULL; +} + +static int +fs_table_insert( + char *dir, + uint prid, + uint flags, + char *fsname, + char *fslog, + char *fsrt) +{ + struct stat64 sbuf; + dev_t datadev, logdev, rtdev; + + if (!dir || !fsname) + return EINVAL; + + datadev = logdev = rtdev = 0; + if (stat64(dir, &sbuf) < 0) + return errno; + datadev = sbuf.st_dev; + if (fslog) { + if (stat64(fslog, &sbuf) < 0) + return errno; + logdev = sbuf.st_dev; + } + if (fsrt) { + if (stat64(fsrt, &sbuf) < 0) + return errno; + rtdev = sbuf.st_dev; + } + + fs_table = realloc(fs_table, sizeof(fs_path_t) * (fs_count + 1)); + if (!fs_table) + goto error; + + fs_path = &fs_table[fs_count]; + fs_path->fs_dir = dir; + fs_path->fs_prid = prid; + fs_path->fs_flags = flags; + fs_path->fs_name = fsname; + fs_path->fs_log = fslog; + fs_path->fs_rt = fsrt; + fs_path->fs_datadev = datadev; + fs_path->fs_logdev = logdev; + fs_path->fs_rtdev = rtdev; + fs_count++; + return 0; + + error: + if (dir) free(dir); + if (fsrt) free(fsrt); + if (fslog) free(fslog); + if (fsname) free(fsname); + return errno; +} + +void +fs_table_destroy(void) +{ + while (--fs_count >= 0) { + free(fs_table[fs_count].fs_name); + if (fs_table[fs_count].fs_log) + free(fs_table[fs_count].fs_log); + if (fs_table[fs_count].fs_rt) + free(fs_table[fs_count].fs_rt); + free(fs_table[fs_count].fs_dir); + } + if (fs_table) + free(fs_table); + fs_table = NULL; + fs_count = 0; +} + + +#if defined(HAVE_MNTENT_H) +#include + +static void +fs_extract_mount_options( + struct mntent *mnt, + char **logp, + char **rtp) +{ + char *fslog, *fsrt, *fslogend, *fsrtend; + + fslog = fsrt = fslogend = fsrtend = NULL; + + /* Extract log device and realtime device from mount options */ + if ((fslog = hasmntopt(mnt, "logdev="))) { + fslog += 7; + fslogend = strtok(fslog, " ,"); + } + if ((fsrt = hasmntopt(mnt, "rtdev="))) { + fsrt += 6; + fsrtend = strtok(fsrt, " ,"); + } + + /* Do this only after we've finished processing mount options */ + if (fslog) { + if (fslogend != fslog) + *fslogend = '\0'; /* terminate end of logdev name */ + fslog = strdup(fslog); + } + if (fsrt) { + if (fsrtend != fsrt) + *fsrtend = '\0'; /* terminate end of rtdev name */ + fsrt = strdup(fsrt); + } + + *logp = fslog; + *rtp = fsrt; +} + +static int +fs_table_initialise_mounts( + char *path) +{ + struct mntent *mnt; + FILE *mtp; + char *dir = NULL, *fsname = NULL, *fslog, *fsrt; + int error = 0, found = 0; + + if (!mtab_file) + mtab_file = MOUNTED; + + if ((mtp = setmntent(mtab_file, "r")) == NULL) + return ENOENT; + + while ((mnt = getmntent(mtp)) != NULL) { + if (strcmp(mnt->mnt_type, "xfs") != 0) + continue; + if (path && + ((strcmp(path, mnt->mnt_dir) != 0) && + (strcmp(path, mnt->mnt_fsname) != 0))) + continue; + found = 1; + dir = strdup(mnt->mnt_dir); + fsname = strdup(mnt->mnt_fsname); + if (!dir || !fsname) { + error = ENOMEM; + break; + } + fs_extract_mount_options(mnt, &fslog, &fsrt); + if ((error = fs_table_insert(dir, 0, FS_MOUNT_POINT, + fsname, fslog, fsrt))) + break; + } + endmntent(mtp); + if (!error && path && !found) + error = ENXIO; + if (error) { + free(dir); + free(fsname); + } + return error; +} + +#elif defined(HAVE_GETMNTINFO) +#include + +static int +fs_table_initialise_mounts( + char *path) +{ + struct statfs *stats; + char *dir = NULL, *fsname = NULL, *fslog = NULL, *fsrt = NULL; + int i, count, found = 0, error = 0; + + if ((count = getmntinfo(&stats, 0)) < 0) { + perror("getmntinfo"); + return 0; + } + + for (i = 0; i < count; i++) { + if (strcmp(stats[i].f_fstypename, "xfs") != 0) + continue; + if (path && + ((strcmp(path, stats[i].f_mntonname) != 0) && + (strcmp(path, stats[i].f_mntfromname) != 0))) + continue; + found = 1; + dir = strdup(stats[i].f_mntonname); + fsname = strdup(stats[i].f_mntfromname); + if (!dir || !fsname) { + error = ENOMEM; + break; + } + /* TODO: external log and realtime device? */ + if ((error = fs_table_insert(dir, 0, FS_MOUNT_POINT, + fsname, fslog, fsrt); + break; + } + if (!error && path && !found) + error = ENXIO; + if (error) { + free(dir); + free(fsname); + } + return error; +} + +#else +# error "How do I extract info about mounted filesystems on this platform?" +#endif + +/* + * Given a directory, match it up to a filesystem mount point. + */ +static struct fs_path * +fs_mount_point_from_path( + const char *dir) +{ + fs_cursor_t cursor; + fs_path_t *fs; + struct stat64 s; + + if (stat64(dir, &s) < 0) { + perror(dir); + return NULL; + } + + fs_cursor_initialise(NULL, FS_MOUNT_POINT, &cursor); + while ((fs = fs_cursor_next_entry(&cursor))) { + if (fs->fs_datadev == s.st_dev) + break; + } + return fs; +} + +static int +fs_table_initialise_projects( + char *project) +{ + fs_project_path_t *path; + fs_path_t *fs; + prid_t prid = 0; + char *dir = NULL, *fsname = NULL; + int error = 0, found = 0; + + if (project) + prid = prid_from_string(project); + + setprpathent(); + while ((path = getprpathent()) != NULL) { + if (project && prid != path->pp_prid) + continue; + if ((fs = fs_mount_point_from_path(path->pp_pathname)) == NULL) + continue; + found = 1; + dir = strdup(path->pp_pathname); + fsname = strdup(fs->fs_name); + if (!dir || !fsname) { + error = ENOMEM; + break; + } + if ((error = fs_table_insert(dir, path->pp_prid, + FS_PROJECT_PATH, fsname, NULL, NULL))) + break; + } + endprpathent(); + + if (!error && project && !found) + error = ENOENT; + if (error) { + free(dir); + free(fsname); + } + return error; +} + +void +fs_table_initialise(void) +{ + int error; + + error = fs_table_initialise_mounts(NULL); + if (!error) + error = fs_table_initialise_projects(NULL); + if (error) { + fs_table_destroy(); + fprintf(stderr, _("%s: cannot initialise path table: %s\n"), + progname, strerror(error)); + exit(1); + } +} + +void +fs_table_insert_mount( + char *mount) +{ + int error; + + error = fs_table_initialise_mounts(mount); + if (error) { + fs_table_destroy(); + fprintf(stderr, _("%s: cannot setup path for mount %s: %s\n"), + progname, mount, strerror(error)); + exit(1); + } +} + +void +fs_table_insert_project( + char *project) +{ + int error; + + if (!fs_count) { + fprintf(stderr, _("%s: no mount table yet, so no projects\n"), + progname); + exit(1); + } + error = fs_table_initialise_projects(project); + if (error) { + fs_table_destroy(); + fprintf(stderr, _("%s: cannot setup path for project %s: %s\n"), + progname, project, strerror(error)); + exit(1); + } +} + +/* + * Table iteration (cursor-based) interfaces + */ + +void +fs_cursor_initialise( + char *dir, + uint flags, + fs_cursor_t *cur) +{ + fs_path_t *path; + + memset(cur, 0, sizeof(*cur)); + if (dir) { + if ((path = fs_table_lookup(dir, flags)) == NULL) + return; + cur->local = *path; + cur->count = 1; + cur->table = &cur->local; + } else { + cur->count = fs_count; + cur->table = fs_table; + } + cur->flags = flags; +} + +struct fs_path * +fs_cursor_next_entry( + fs_cursor_t *cur) +{ + fs_path_t *next = NULL; + + while (cur->index < cur->count) { + next = &cur->table[cur->index++]; + if (cur->flags & next->fs_flags) + break; + next = NULL; + } + return next; +} diff --git a/libxcmd/projects.c b/libxcmd/projects.c new file mode 100644 index 000000000..18e723155 --- /dev/null +++ b/libxcmd/projects.c @@ -0,0 +1,218 @@ +/* + * 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 +#include +#include +#include + +#define PROJID "/etc/projid" +#define PROJECT_PATHS "/etc/projects" +char *projid_file; +char *projects_file; + +static FILE *projects; +static fs_project_t p; +static char projects_buffer[512]; + +static FILE *project_paths; +static fs_project_path_t pp; +static char project_paths_buffer[1024]; + +void +setprfiles(void) +{ + if (!projid_file) + projid_file = PROJID; + if (!projects_file) + projects_file = PROJECT_PATHS; +} + +void +setprent() +{ + setprfiles(); + projects = fopen(projid_file, "r"); +} + +void +setprpathent() +{ + setprfiles(); + project_paths = fopen(projects_file, "r"); +} + +void +endprent(void) +{ + if (projects) + fclose(projects); + projects = NULL; +} + +void +endprpathent(void) +{ + if (project_paths) + fclose(project_paths); + project_paths = NULL; +} + +fs_project_t * +getprent(void) +{ + char *idstart, *idend; + size_t size = sizeof(projects_buffer) - 1; + + if (!projects) + return NULL; + do { + if (!fgets(projects_buffer, size, projects)) + break; + /* + * /etc/projid file format -- "name:id\n", ignore "^#..." + */ + if (projects_buffer[0] == '#') + continue; + idstart = strchr(projects_buffer, ':'); + if (!idstart) + continue; + if ((idstart + 1) - projects_buffer >= size) + continue; + idend = strchr(idstart+1, ':'); + if (idend) + *idend = '\0'; + *idstart = '\0'; + p.pr_prid = atoi(idstart+1); + p.pr_name = &projects_buffer[0]; + return &p; + } while (1); + + return NULL; +} + +fs_project_t * +getprnam( + char *name) +{ + fs_project_t *p = NULL; + + setprent(); + while ((p = getprent()) != NULL) + if (strcmp(p->pr_name, name) == 0) + break; + endprent(); + return p; +} + +fs_project_t * +getprprid( + prid_t prid) +{ + fs_project_t *p = NULL; + + setprent(); + while ((p = getprent()) != NULL) + if (p->pr_prid == prid) + break; + endprent(); + return p; +} + +fs_project_path_t * +getprpathent(void) +{ + char *nmstart, *nmend; + size_t size = sizeof(project_paths_buffer) - 1; + + if (!project_paths) + return NULL; + do { + if (!fgets(project_paths_buffer, size, project_paths)) + break; + /* + * /etc/projects format -- "id:pathname\n", ignore "^#..." + */ + if (project_paths_buffer[0] == '#') + continue; + nmstart = strchr(project_paths_buffer, ':'); + if (!nmstart) + continue; + if ((nmstart + 1) - project_paths_buffer >= size) + continue; + nmend = strchr(nmstart + 1, '\n'); + if (nmend) + *nmend = '\0'; + *nmstart = '\0'; + pp.pp_pathname = nmstart + 1; + pp.pp_prid = atoi(&project_paths_buffer[0]); + return &pp; + } while (1); + + return NULL; +} + + +int +getprojid( + const char *name, + int fd, + prid_t *projid) +{ +#if defined(__sgi__) + struct stat64 st; + if (fstat64(fd, &st) < 0) { + perror("fstat64"); + return -1; + } + *projid = st.st_projid; +#else + if (xfsctl(name, fd, XFS_IOC_GETPROJID, projid)) { + perror("XFS_IOC_GETPROJID"); + return -1; + } +#endif + return 0; +} + +int +setprojid( + const char *name, + int fd, + prid_t projid) +{ +#if defined(__sgi__) + return fchproj(fd, projid); +#else + return xfsctl(name, fd, XFS_IOC_SETPROJID, &projid); +#endif +} diff --git a/io/quit.c b/libxcmd/quit.c similarity index 90% rename from io/quit.c rename to libxcmd/quit.c index a6d5a9f17..59917174e 100644 --- a/io/quit.c +++ b/libxcmd/quit.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2004 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (c) 2003-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 @@ -31,7 +31,7 @@ */ #include -#include "command.h" +#include static cmdinfo_t quit_cmd; @@ -49,7 +49,9 @@ quit_init(void) quit_cmd.name = _("quit"); quit_cmd.altname = _("q"); quit_cmd.cfunc = quit_f; - quit_cmd.flags = CMD_NOMAP_OK | CMD_NOFILE_OK | CMD_FOREIGN_OK; + quit_cmd.argmin = -1; + quit_cmd.argmax = -1; + quit_cmd.flags = -1; quit_cmd.oneline = _("exit the program"); add_command(&quit_cmd);