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