574 lines
16 KiB
C
574 lines
16 KiB
C
/*
|
|
* CDE - Common Desktop Environment
|
|
*
|
|
* Copyright (c) 1993-2012, The Open Group. All rights reserved.
|
|
*
|
|
* These libraries and programs are free software; you can
|
|
* redistribute them and/or modify them under the terms of the GNU
|
|
* Lesser General Public License as published by the Free Software
|
|
* Foundation; either version 2 of the License, or (at your option)
|
|
* any later version.
|
|
*
|
|
* These libraries and programs are distributed in the hope that
|
|
* they will be useful, but WITHOUT ANY WARRANTY; without even the
|
|
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|
* PURPOSE. See the GNU Lesser General Public License for more
|
|
* details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with these libraries and programs; if not, write
|
|
* to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
|
|
* Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
//%% (c) Copyright 1993, 1994 Hewlett-Packard Company
|
|
//%% (c) Copyright 1993, 1994 International Business Machines Corp.
|
|
//%% (c) Copyright 1993, 1994 Sun Microsystems, Inc.
|
|
//%% (c) Copyright 1993, 1994 Novell, Inc.
|
|
//%% $TOG: tt_file_system.C /main/5 1998/03/19 18:59:48 mgreess $
|
|
//%% restrictions in a confidential disclosure agreement between
|
|
//%% HP, IBM, Sun, USL, SCO and Univel. Do not distribute this
|
|
//%% document outside HP, IBM, Sun, USL, SCO, or Univel without
|
|
//%% Sun's specific written approval. This document and all copies
|
|
//%% and derivative works thereof must be returned or destroyed at
|
|
//%% Sun's request.
|
|
//%%
|
|
//%% Copyright 1993, 1994 Sun Microsystems, Inc. All rights reserved.
|
|
//%%
|
|
/* @(#)tt_file_system.C 1.40 95/01/06
|
|
*
|
|
* Tool Talk Utility
|
|
*
|
|
* Copyright (c) 1990, 1994 by Sun Microsystems, Inc.
|
|
*
|
|
* Defines a class for browsing the file system mount table.
|
|
*
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
#if defined(__linux__)
|
|
# include <sys/poll.h>
|
|
#else
|
|
# include <poll.h>
|
|
#endif
|
|
#include <sys/stat.h>
|
|
#include <fcntl.h>
|
|
#include "tt_options.h"
|
|
#include "util/tt_port.h"
|
|
#include "util/tt_host_equiv.h"
|
|
|
|
#if defined(OPT_SVR4_GETMNTENT)
|
|
# include <sys/mnttab.h>
|
|
# include <sys/mntent.h>
|
|
# define TtMntTab MNTTAB
|
|
# define TtMntEntry struct mnttab
|
|
# define ttOpenMntTbl(path,mode) fopen(path,mode)
|
|
# define ttFsType(e) (e).mnt_fstype
|
|
# define ttFsName(e) (e).mnt_special
|
|
# define ttMountPt(e) (e).mnt_mountp
|
|
# define ttCloseMntTbl(f) fclose(f)
|
|
#elif defined(_AIX)
|
|
extern "C" int mntctl(int,int,char *);
|
|
# include <sys/vfs.h>
|
|
# define MNTTYPE_NFS "nfs"
|
|
# define ttOpenMntTbl(path,mode) ((FILE *) 1)
|
|
# define TtMntEntry struct vmount *
|
|
# define ttFsType(e) \
|
|
(((e)->vmt_gfstype == MNT_JFS) ? "jfs" \
|
|
: (((e)->vmt_gfstype == MNT_NFS) ? "nfs" \
|
|
: (((e)->vmt_gfstype == MNT_CDROM) ? "cdrom" \
|
|
: (((e)->vmt_gfstype == MNT_AIX) ? "oaix" \
|
|
: "unknown"))))
|
|
# define ttFsName(e) vmt2dataptr(e,VMT_OBJECT)
|
|
# define ttMountPt(e) vmt2dataptr(e,VMT_STUB)
|
|
# define ttCloseMntTbl(f) free(tmpbuf)
|
|
#elif defined(CSRG_BASED)
|
|
# include <sys/types.h>
|
|
# include <sys/mount.h>
|
|
|
|
|
|
#if defined(HAS_STATVFS)
|
|
extern "C" int getfsstat(struct statvfs *, long, int);
|
|
# endif
|
|
|
|
# define MNTTYPE_NFS "nfs"
|
|
# define ttOpenMntTbl(path,mode) ((FILE *) 1)
|
|
|
|
# if defined(HAS_STATVFS)
|
|
# include <sys/statvfs.h>
|
|
# define TtMntEntry struct statvfs *
|
|
# else
|
|
# define TtMntEntry struct statfs *
|
|
# endif
|
|
|
|
# if defined(CSRG_BASED)
|
|
# define ttFsType(e) (e->f_fstypename)
|
|
# endif
|
|
# define ttFsName(e) ((char *)((e)->f_mntfromname))
|
|
# define ttMountPt(e) ((char *)((e)->f_mntonname))
|
|
# define ttCloseMntTbl(f) free(buf)
|
|
#else
|
|
# include <mntent.h>
|
|
# define TtMntTab MOUNTED
|
|
# define MNTTYPE_RFS "rfs"
|
|
# define TtMntEntry struct mntent *
|
|
# define ttOpenMntTbl(path,mode) setmntent(path,mode)
|
|
# define ttFsType(e) (e)->mnt_type
|
|
# define ttFsName(e) (e)->mnt_fsname
|
|
# define ttMountPt(e) (e)->mnt_dir
|
|
# define ttCloseMntTbl(f) endmntent(f)
|
|
#endif
|
|
#include "util/tt_file_system_entry_utils.h"
|
|
#include "util/tt_file_system.h"
|
|
#include "util/tt_file_system_entry.h"
|
|
#include "util/tt_path.h"
|
|
#include "util/tt_port.h"
|
|
#include "util/tt_host.h"
|
|
#include "util/tt_global_env.h"
|
|
|
|
#if defined(OPT_BUG_SUNOS_5)
|
|
// Bug 1116904 filed on the absence of hasmntopt from the
|
|
// header file. Fixed in SunOS 5.3, but we leave this in so
|
|
// we can compile on 5.1 and 5.2.
|
|
extern "C" {
|
|
extern char *hasmntopt(struct mnttab *mnt, char *opt);
|
|
};
|
|
#endif
|
|
|
|
time_t _Tt_file_system::lastMountTime = 0;
|
|
|
|
_Tt_file_system::
|
|
_Tt_file_system ()
|
|
{
|
|
// It would be simpler just to have a static instance of
|
|
// _Tt_file_system_entry_list here, but static class instances
|
|
// are verboten if we want to be called by C programs.
|
|
if (_tt_global->fileSystemEntries.is_null()) {
|
|
_tt_global->fileSystemEntries = new _Tt_file_system_entry_list;
|
|
lastMountTime = 0;
|
|
}
|
|
}
|
|
|
|
_Tt_file_system::
|
|
~_Tt_file_system ()
|
|
{
|
|
lastMountTime = 0;
|
|
}
|
|
|
|
static _Tt_file_system_entry *
|
|
createFileSystemEntry(TtMntEntry entry)
|
|
{
|
|
_Tt_string hostname;
|
|
_Tt_string mount_point;
|
|
_Tt_string partition;
|
|
int local_flag = 1;
|
|
int loop_back_flag = 0;
|
|
//
|
|
// not all platforms have the IGNORE option, but if it
|
|
// is defined, be sure to ignore mount entries with it
|
|
// set, as they are things like automounter entries
|
|
// that will just confuse the mapping.
|
|
//
|
|
#if defined(MNTOPT_IGNORE)
|
|
if (0!=hasmntopt(&entry, MNTOPT_IGNORE)) {
|
|
return (_Tt_file_system_entry *)0;
|
|
}
|
|
#endif
|
|
if ( (strcmp( ttFsType(entry), MNTTYPE_NFS) == 0)
|
|
#if defined(MNTTYPE_RFS)
|
|
|| (strcmp( ttFsType(entry), MNTTYPE_RFS) == 0)
|
|
#endif
|
|
)
|
|
{
|
|
#if defined(_AIX)
|
|
// AIX is different; at least it\'s arguably better.
|
|
hostname = vmt2dataptr(entry,VMT_HOSTNAME);
|
|
partition = ttFsName(entry);
|
|
#else /* AIX */
|
|
|
|
// Search for a '.' to separate the hostname and
|
|
// the domain name
|
|
char *endOfHostNamePos =
|
|
strchr(ttFsName(entry), '.');
|
|
|
|
// Search for the ':' that separates the
|
|
// hostname and the rest of the mtab field.
|
|
|
|
char *justBeforePartitionPos =
|
|
strchr(ttFsName(entry), ':');
|
|
|
|
// If there was no domain name or the dot
|
|
// found above was after the ':' (the dot was
|
|
// just part of a directoty name), then the
|
|
// hostname ends at the ':' position.
|
|
|
|
if (!endOfHostNamePos ||
|
|
(justBeforePartitionPos < endOfHostNamePos)) {
|
|
endOfHostNamePos = justBeforePartitionPos;
|
|
}
|
|
|
|
// NULL terminate the hostname part of the field
|
|
if (endOfHostNamePos) {
|
|
*endOfHostNamePos = '\0';
|
|
}
|
|
|
|
if (justBeforePartitionPos) {
|
|
partition = justBeforePartitionPos+1;
|
|
}
|
|
|
|
hostname = ttFsName(entry);
|
|
#endif /* AIX */
|
|
local_flag = FALSE;
|
|
loop_back_flag = FALSE;
|
|
} else {
|
|
partition = ttFsName(entry);
|
|
_Tt_host_ptr localHost;
|
|
_tt_global->get_local_host( localHost );
|
|
hostname = localHost->name();
|
|
local_flag = TRUE;
|
|
loop_back_flag = FALSE;
|
|
|
|
#if defined(MNTTYPE_LOFS)
|
|
if (!strcmp( ttFsType(entry), MNTTYPE_LOFS)) {
|
|
loop_back_flag = TRUE;
|
|
}
|
|
#endif
|
|
}
|
|
mount_point = ttMountPt(entry);
|
|
|
|
return new _Tt_file_system_entry( hostname, mount_point, partition,
|
|
local_flag, loop_back_flag );
|
|
}
|
|
|
|
|
|
/*
|
|
* Finds the best match mount table entry to the specified local path
|
|
* resolving loop back mounts to the true mount point.
|
|
*/
|
|
_Tt_file_system_entry_ptr _Tt_file_system::
|
|
bestMatchToPath (const _Tt_string &path)
|
|
{
|
|
_Tt_string real_path = _tt_realpath(path);
|
|
|
|
updateFileSystemEntries();
|
|
|
|
_Tt_file_system_entry_ptr max_match_entry;
|
|
bool_t loop_back_flag = TRUE;
|
|
_Tt_string current_loop_back_mount_point;
|
|
_Tt_string first_loop_back_mount_point;
|
|
bool_t first_time = TRUE;
|
|
|
|
while (loop_back_flag) {
|
|
max_match_entry = findBestMountPoint(real_path,
|
|
loop_back_flag,
|
|
current_loop_back_mount_point);
|
|
|
|
if (loop_back_flag && first_time) {
|
|
first_loop_back_mount_point =
|
|
current_loop_back_mount_point;
|
|
}
|
|
|
|
first_time = FALSE;
|
|
}
|
|
|
|
max_match_entry->loopBackMountPoint = first_loop_back_mount_point;
|
|
return max_match_entry;
|
|
}
|
|
|
|
/*
|
|
* Finds the best matching mount pount to the specified local path.
|
|
* If the best match is a loop back then the matching portion of the
|
|
* specified path is updated to the loop back partition and the loop
|
|
* back flag parameter is set to TRUE.
|
|
*/
|
|
_Tt_file_system_entry_ptr _Tt_file_system::
|
|
findBestMountPoint (_Tt_string &path,
|
|
bool_t &loop_back_flag,
|
|
_Tt_string &loop_back_mount_point)
|
|
{
|
|
updateFileSystemEntries();
|
|
|
|
_Tt_string current_mount_point;
|
|
int current_mount_point_length;
|
|
_Tt_file_system_entry_ptr max_match_entry;
|
|
int max_match_length = 0;
|
|
int path_length = path.len();
|
|
|
|
_Tt_file_system_entry_list_cursor
|
|
entries_cursor(_tt_global->fileSystemEntries);
|
|
|
|
while (entries_cursor.next()) {
|
|
current_mount_point = entries_cursor->getMountPoint();
|
|
current_mount_point_length = current_mount_point.len();
|
|
if (path_length < current_mount_point_length) {
|
|
continue;
|
|
}
|
|
|
|
if (current_mount_point_length > max_match_length) {
|
|
if (!memcmp((char *)current_mount_point,
|
|
(char *)path,
|
|
current_mount_point_length)) {
|
|
max_match_length = current_mount_point_length;
|
|
max_match_entry = *entries_cursor;
|
|
}
|
|
}
|
|
|
|
if (max_match_length == path_length) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (max_match_entry->isLoopBack ()) {
|
|
loop_back_flag = TRUE;
|
|
|
|
_Tt_string mount_point = max_match_entry->getMountPoint();
|
|
_Tt_string partition = max_match_entry->getPartition();
|
|
|
|
// Get the path info after the mount point path
|
|
path = path.right(path.len()-mount_point.len());
|
|
|
|
// Prepend the loop back partition onto the rest of the path
|
|
path = partition.cat(path);
|
|
|
|
// Return the loop back mount point
|
|
loop_back_mount_point = mount_point;
|
|
} else {
|
|
loop_back_flag = FALSE;
|
|
}
|
|
|
|
return max_match_entry;
|
|
}
|
|
|
|
/*
|
|
* Finds the mount table entry corresponding to the specified network path.
|
|
* The specified path must be of the form:
|
|
*
|
|
* hostname:/path
|
|
*/
|
|
_Tt_file_system_entry_ptr _Tt_file_system::
|
|
findMountEntry (const _Tt_string &network_path)
|
|
{
|
|
updateFileSystemEntries();
|
|
|
|
_Tt_string current_hostname;
|
|
_Tt_string current_partition;
|
|
int current_partition_length;
|
|
_Tt_file_system_entry_ptr entry;
|
|
|
|
_Tt_string hostname;
|
|
_Tt_string path;
|
|
|
|
path = network_path;
|
|
path = path.split(':', hostname);
|
|
|
|
int path_length = path.len();
|
|
|
|
_Tt_file_system_entry_list_cursor
|
|
entries_cursor(_tt_global->fileSystemEntries);
|
|
|
|
_Tt_host_equiv_ptr eq_p = new _Tt_host_equiv();
|
|
while (entries_cursor.next()) {
|
|
current_hostname = entries_cursor->getHostname();
|
|
|
|
#ifdef notdef
|
|
printf("DEBUG findMountEntry: hostname = %s, current_hostname = %s\n",
|
|
(char *) hostname, (char *) current_hostname);
|
|
#endif
|
|
|
|
if (eq_p->hostname_equiv(hostname, current_hostname) == 1) {
|
|
current_partition = entries_cursor->getPartition();
|
|
current_partition_length = current_partition.len();
|
|
|
|
#ifdef notdef
|
|
printf("DEBUG findMountEntry: found hostname equivalence between %s and %s\n",
|
|
(char *) hostname, (char *) current_hostname);
|
|
#endif
|
|
|
|
if (path_length >= current_partition_length) {
|
|
if (!memcmp((char *)path, (char *)current_partition,
|
|
current_partition_length)) {
|
|
entry = *entries_cursor;
|
|
#ifdef notdef
|
|
printf("DEBUG findMountEntry: found PATH equivalence between %s and %s\n",
|
|
(char *) hostname, (char *) current_hostname);
|
|
#endif
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return entry;
|
|
}
|
|
|
|
void _Tt_file_system::
|
|
updateFileSystemEntries ()
|
|
{
|
|
static int firsttime = 1;
|
|
static int since_last = 0;
|
|
|
|
if (!firsttime) {
|
|
if (since_last < _tt_global->event_counter) {
|
|
since_last = _tt_global->event_counter;
|
|
} else {
|
|
return;
|
|
}
|
|
}
|
|
|
|
// AIX doesn\'t have a mount table file as such.
|
|
#ifdef TtMntTab
|
|
|
|
struct stat mount_table_stat;
|
|
if (stat(TtMntTab, &mount_table_stat)) {
|
|
return;
|
|
}
|
|
|
|
if (!firsttime && mount_table_stat.st_mtime <= lastMountTime) {
|
|
return;
|
|
}
|
|
|
|
firsttime = 0;
|
|
|
|
// XXX Due to bug #1126575 - MNTTAB temporarily goes to
|
|
// size 0 during automounter updates. The file stats
|
|
// OK, but has no data in it.
|
|
struct pollfd poll_fd;
|
|
while (mount_table_stat.st_size == 0) {
|
|
(void)poll (&poll_fd, 0, 100);
|
|
// Must use lstat here; mtab is often a symlink
|
|
if (lstat(TtMntTab, &mount_table_stat)) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
FILE *mount_table = ttOpenMntTbl(TtMntTab, "r");
|
|
|
|
if (! mount_table) {
|
|
return;
|
|
}
|
|
fcntl(fileno(mount_table), F_SETFD, 1); // Close on exec.
|
|
|
|
lastMountTime = mount_table_stat.st_mtime;
|
|
#endif
|
|
|
|
_tt_global->fileSystemEntries->flush();
|
|
_Tt_file_system_entry_ptr fse;
|
|
TtMntEntry entry;
|
|
#if defined(_AIX)
|
|
int rc, sz = BUFSIZ;
|
|
char *tmpbuf = (char *)malloc( sz );
|
|
|
|
while ((rc = mntctl(MCTL_QUERY, sz, tmpbuf)) == 0)
|
|
{
|
|
// increase buffer size
|
|
sz = *((int *) tmpbuf);
|
|
free( tmpbuf );
|
|
tmpbuf = (char *)malloc( sz );
|
|
}
|
|
|
|
for (entry = (TtMntEntry)tmpbuf; rc > 0; --rc,
|
|
entry = (TtMntEntry)((char *) entry + entry->vmt_length))
|
|
|
|
#elif defined(HAS_STATVFS)
|
|
int numfs,i;
|
|
struct statvfs *buf;
|
|
long bufsize;
|
|
int flags = MNT_NOWAIT;
|
|
char *s, *host, path[MNAMELEN] ;
|
|
|
|
numfs = getvfsstat ( (struct statvfs *)0, 0, 0 );
|
|
|
|
bufsize = numfs * sizeof ( struct statvfs );
|
|
buf = (struct statvfs *) malloc ( bufsize );
|
|
memset ((void *)buf,0,bufsize);
|
|
|
|
getvfsstat ( buf, bufsize, flags );
|
|
|
|
for ( i=0; i<numfs; i++ )
|
|
{
|
|
// convert path@host to host:/path
|
|
s = strchr(buf[i].f_mntfromname,'@');
|
|
if (s != NULL) {
|
|
host = s + 1 ;
|
|
memset((char*)path,0,MNAMELEN);
|
|
strncpy(path,buf[i].f_mntfromname, (strlen(buf[i].f_mntfromname)
|
|
- strlen(s))) ;
|
|
strcpy(buf[i].f_mntfromname,host) ;
|
|
strcat(buf[i].f_mntfromname,":") ;
|
|
strcat(buf[i].f_mntfromname,path) ;
|
|
}
|
|
entry = &buf[i];
|
|
|
|
#elif defined(CSRG_BASED)
|
|
int numfs,i;
|
|
struct statfs *buf;
|
|
long bufsize;
|
|
int flags = MNT_NOWAIT;
|
|
char *s, *host, path[MNAMELEN] ;
|
|
|
|
numfs = getfsstat ( (struct statfs *)0, 0, flags );
|
|
if(numfs == (-1)){
|
|
_tt_syslog(0,LOG_ERR,"getfsstat: %s",strerror(errno));
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
bufsize = numfs * sizeof ( struct statfs );
|
|
buf = (struct statfs *) malloc ( bufsize );
|
|
memset ((void *)buf,0,bufsize);
|
|
|
|
getfsstat ( buf, bufsize, flags );
|
|
|
|
for ( i=0; i<numfs; i++ )
|
|
{
|
|
// convert path@host to host:/path
|
|
s = strchr(buf[i].f_mntfromname,'@');
|
|
if (s != NULL) {
|
|
host = s + 1 ;
|
|
memset((char*)path,0,MNAMELEN);
|
|
strncpy(path,buf[i].f_mntfromname, (strlen(buf[i].f_mntfromname)
|
|
- strlen(s))) ;
|
|
strcpy(buf[i].f_mntfromname,host) ;
|
|
strcat(buf[i].f_mntfromname,":") ;
|
|
strcat(buf[i].f_mntfromname,path) ;
|
|
}
|
|
entry = &buf[i];
|
|
|
|
#elif defined(OPT_SVR4_GETMNTENT)
|
|
int rc;
|
|
while (! (rc = getmntent(mount_table, &entry)))
|
|
#else
|
|
while (entry = getmntent(mount_table))
|
|
#endif
|
|
#if !defined(CSRG_BASED)
|
|
{
|
|
#endif
|
|
fse = createFileSystemEntry( entry );
|
|
if (!fse.is_null()) {
|
|
#if defined(TT_DEBUG_FNM)
|
|
fprintf(stderr,"File name mapping: %s:%s on %s; %s %s\n",
|
|
(char *)fse->getHostname(),
|
|
(char *)fse->getPartition(),
|
|
(char *)fse->getMountPoint(),
|
|
fse->isLocal()?"local":"",
|
|
fse->isLoopBack()?"loopback":"");
|
|
#endif
|
|
_tt_global->fileSystemEntries->append(fse);
|
|
}
|
|
}
|
|
|
|
ttCloseMntTbl(mount_table);
|
|
}
|
|
|
|
void _Tt_file_system::
|
|
flush ()
|
|
{
|
|
if (!_tt_global->fileSystemEntries.is_null()) {
|
|
_tt_global->fileSystemEntries->flush();
|
|
}
|
|
|
|
lastMountTime = 0;
|
|
}
|
|
/* Local Variables : */
|
|
/* c++-indent-level: 2 */
|
|
/* End: */
|