| /* |
| * 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; |
| } |