blob: a4c175c3d30c74b0a2202bfe565aa002d9c79246 [file] [log] [blame]
/*
* Copyright (c) 2000-2002 Silicon Graphics, Inc.
* All Rights Reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms 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. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "config.h"
#include <unistd.h>
#include <sys/stat.h>
#include <sys/statvfs.h>
#include <time.h>
#include <errno.h>
#include <fcntl.h>
#include <mntent.h>
#include <sys/ioctl.h>
#include <assert.h>
#include <string.h>
#include <uuid/uuid.h>
#include <xfs/xfs.h>
#include "config.h"
#include "types.h"
#include "mlog.h"
#include "fs.h"
/* fs_info - a magic, highly heuristic function to convert a user-supplied
* string into a file system type, character special device pathname,
* a mount point, and file system ID (uuid). The primary source of information
* is the getmntent(3) routines. Correspondence between "standard" disk
* block and character device pathnames is used. The fstyp(1) utility
* may be invoked as well.
*
* returns BOOL_TRUE on success, BOOL_FALSE on failure.
*
* coding rules: to make this very complex and lengthy decision tree
* more graspable, some very strict coding rules were followed:
*
* 1) function arguments are ordered reference returns first, input
* parameters second.
*
* 2) all buffer-like refence return arguments are followed by a
* caller-supplied buffer size.
*
* 3) wherever possible functions return the result buffer pointer.
*
* 4) boolean functions return TRUE on success, FALSE on failure.
*
* all variables, parameters, and structure members are named as follows:
* object types:
* usr - user-specified mystery
* typ - file system type
* mnt - mount point pathname
* blk - block device pathname
* chr - character device pathname
* id - file system ID
* stat - stat buffer
* te - file system table entry
* object modifiers: appended to object type:
* b - buffer
* s - string
* d - default string
* p - pointer
* object size indication modifiers: appended to a modified object type:
* z - buffer size
* l - string length
*/
/* declarations of externally defined global variables
*/
/* definitions used locally
*/
struct fs_tab_ent {
char *fte_blks;
char *fte_mnts;
char *fte_typs;
struct fs_tab_ent *fte_nextp;
};
typedef struct fs_tab_ent fs_tab_ent_t;
static fs_tab_ent_t *fs_tabp;
/* forward declarations
*/
static void fs_tab_build(void);
static void fs_tab_free(void);
static fs_tab_ent_t *fs_tab_ent_build(struct mntent *);
static void fs_tab_ent_free(fs_tab_ent_t *);
static fs_tab_ent_t *fs_tab_lookup_blk(char *);
static fs_tab_ent_t *fs_tab_lookup_mnt(char *);
/* ARGSUSED */
bool_t
fs_info(char *typb, /* out */
int typbz,
char *typd,
char *blkb, /* out */
int blkbz,
char *mntb, /* out */
int mntbz,
uuid_t *idb, /* out */
char *usrs) /* in */
{
struct stat64 statb;
fs_tab_ent_t *tep;
char *blks;
char *mnts;
char *typs;
bool_t canstat;
bool_t ok = BOOL_UNKNOWN;
fs_tab_build();
canstat = (stat64(usrs, &statb) == 0);
if (canstat && (statb.st_mode & S_IFMT) == S_IFBLK) {
if ((tep = fs_tab_lookup_blk(usrs)) != 0) {
blks = tep->fte_blks;
assert(strlen(blks) < (size_t)blkbz);
strcpy(blkb, blks);
mnts = tep->fte_mnts;
if (mnts) {
assert(strlen(mnts) < (size_t)mntbz);
strcpy(mntb, mnts);
} else {
mntb[0] = 0;
}
if ((typs = tep->fte_typs) == 0) {
typs = typd;
}
assert(strlen(typs) < (size_t)typbz);
strcpy(typb, typs);
ok = BOOL_TRUE;
} else {
ok = BOOL_FALSE;
}
} else if ((tep = fs_tab_lookup_mnt(usrs)) != 0) {
blks = tep->fte_blks;
assert(strlen(blks) < (size_t)blkbz);
strcpy(blkb, blks);
mnts = tep->fte_mnts;
assert(strlen(mnts) < (size_t)mntbz);
strcpy(mntb, mnts);
typs = tep->fte_typs;
assert(strlen(typs) < (size_t)typbz);
strcpy(typb, typs);
ok = BOOL_TRUE;
} else {
ok = BOOL_FALSE;
}
fs_tab_free();
assert(ok != BOOL_UNKNOWN);
if (ok == BOOL_TRUE) {
int rval = fs_getid(mntb, idb);
if (rval) {
mlog(MLOG_NORMAL,
_("unable to determine uuid of fs mounted at %s: "
"%s\n"),
mntb,
strerror(errno));
}
{
char string_uuid[37];
uuid_unparse(*idb, string_uuid);
mlog(MLOG_DEBUG,
"fs %s uuid [%s]\n",
mntb,
string_uuid);
}
}
return ok;
}
/* fs_mounted - a predicate determining if the specified file system
* is actually currently mounted at its mount point.
* will not take time to code this now - just check if mntpt is non-NULL.
*/
/* ARGSUSED */
bool_t
fs_mounted(char *typs, char *chrs, char *mnts, uuid_t *idp)
{
return strlen(mnts) > 0 ? BOOL_TRUE : BOOL_FALSE;
}
int
fs_getid(char *mnts, uuid_t *idb)
{
xfs_fsop_geom_v1_t geo;
int fd;
fd = open(mnts, O_RDONLY);
if (fd < 0) {
uuid_clear(*idb);
return -1;
}
if (ioctl(fd, XFS_IOC_FSGEOMETRY_V1, &geo)) {
uuid_clear(*idb);
close(fd);
return -1;
}
close(fd);
uuid_copy(*idb, geo.uuid);
return 0;
}
size_t
fs_getinocnt(char *mnts)
{
struct statvfs vfsstat;
int rval;
rval = statvfs(mnts, &vfsstat);
if (rval) {
return 0;
}
if (vfsstat.f_files < vfsstat.f_ffree) {
return 0;
}
return (size_t)(vfsstat.f_files - vfsstat.f_ffree);
}
static void
fs_tab_build(void)
{
register struct mntent *mntentp;
fs_tab_ent_t *tep;
FILE *fp;
fs_tabp = 0;
fp = setmntent(MOUNTED, "r");
if (fp == NULL) {
mlog(MLOG_NORMAL,
_("Can't open %s for mount information\n"),
MOUNTED);
return;
}
while ((mntentp = getmntent(fp)) != 0) {
tep = fs_tab_ent_build(mntentp);
tep->fte_nextp = fs_tabp;
fs_tabp = tep;
}
endmntent(fp);
}
static void
fs_tab_free(void)
{
fs_tab_ent_t *tep;
fs_tab_ent_t *otep;
for (tep = fs_tabp
;
tep
;
otep = tep, tep = tep->fte_nextp, fs_tab_ent_free(otep))
;
}
static fs_tab_ent_t *
fs_tab_ent_build(struct mntent *mntentp)
{
fs_tab_ent_t *tep;
char *cp;
tep = (fs_tab_ent_t *)calloc(1, sizeof(fs_tab_ent_t));
assert(tep);
if (mntentp->mnt_dir) {
cp = calloc(1, strlen(mntentp->mnt_dir) + 1);
assert(cp);
(void)strcpy(cp, mntentp->mnt_dir);
tep->fte_mnts = cp;
} else {
tep->fte_mnts = 0;
}
if (mntentp->mnt_type) {
cp = calloc(1, strlen(mntentp->mnt_type) + 1);
assert(cp);
(void)strcpy(cp, mntentp->mnt_type);
tep->fte_typs = cp;
} else {
tep->fte_typs = 0;
}
if (mntentp->mnt_fsname) {
cp = calloc(1, strlen(mntentp->mnt_fsname) + 1);
assert(cp);
(void)strcpy(cp, mntentp->mnt_fsname);
tep->fte_blks = cp;
} else {
tep->fte_blks = 0;
}
return tep;
}
static void
fs_tab_ent_free(fs_tab_ent_t *tep)
{
if (tep->fte_blks) free(tep->fte_blks);
if (tep->fte_mnts) free(tep->fte_mnts);
if (tep->fte_typs) free(tep->fte_typs);
memset((void *)tep, 0, sizeof(*tep)); /* bug catcher */
free(tep);
}
static fs_tab_ent_t *
fs_tab_lookup_blk(char *blks)
{
fs_tab_ent_t *tep;
for (tep = fs_tabp; tep; tep = tep->fte_nextp) {
struct stat64 stata;
bool_t aok;
struct stat64 statb;
bool_t bok;
if (!tep->fte_blks) {
continue;
}
if (!strcmp(tep->fte_blks, blks)) {
return tep;
}
aok = !stat64(blks, &stata);
bok = !stat64(tep->fte_blks, &statb);
if (aok && bok && stata.st_rdev == statb.st_rdev) {
return tep;
}
}
return 0;
}
static fs_tab_ent_t *
fs_tab_lookup_mnt(char *mnts)
{
fs_tab_ent_t *tep;
for (tep = fs_tabp; tep; tep = tep->fte_nextp) {
if (tep->fte_mnts && !strcmp(tep->fte_mnts, mnts)) {
return tep;
}
}
return 0;
}