[BACK]Return to FileSystemTable.c++ CVS log [TXT][DIR] Up to [Development] / fam / fam

Annotation of fam/fam/FileSystemTable.c++, Revision 1.1

1.1     ! trev        1: //  Copyright (C) 1999 Silicon Graphics, Inc.  All Rights Reserved.
        !             2: //
        !             3: //  This program is free software; you can redistribute it and/or modify it
        !             4: //  under the terms of version 2 of the GNU General Public License as
        !             5: //  published by the Free Software Foundation.
        !             6: //
        !             7: //  This program is distributed in the hope that it would be useful, but
        !             8: //  WITHOUT ANY WARRANTY; without even the implied warranty of
        !             9: //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  Further, any
        !            10: //  license provided herein, whether implied or otherwise, is limited to
        !            11: //  this program in accordance with the express provisions of the GNU
        !            12: //  General Public License.  Patent licenses, if any, provided herein do not
        !            13: //  apply to combinations of this program with other product or programs, or
        !            14: //  any other product whatsoever.  This program is distributed without any
        !            15: //  warranty that the program is delivered free of the rightful claim of any
        !            16: //  third person by way of infringement or the like.  See the GNU General
        !            17: //  Public License for more details.
        !            18: //
        !            19: //  You should have received a copy of the GNU General Public License along
        !            20: //  with this program; if not, write the Free Software Foundation, Inc., 59
        !            21: //  Temple Place - Suite 330, Boston MA 02111-1307, USA.
        !            22:
        !            23: #include <stddef.h>
        !            24: #include "FileSystemTable.h"
        !            25:
        !            26: #include <mntent.h>
        !            27: #include <stdlib.h>
        !            28: #include <string.h>
        !            29:
        !            30: #if HAVE_STATVFS
        !            31: #include <sys/statvfs.h>
        !            32: #endif
        !            33:
        !            34: #include "Cred.h"
        !            35: #include "Event.h"
        !            36: #include "FileSystem.h"
        !            37: #include "InternalClient.h"
        !            38: #include "LocalFileSystem.h"
        !            39: #include "Log.h"
        !            40: #include "NFSFileSystem.h"
        !            41:
        !            42: //  Fam has two tables of mounted filesystems -- fs_by_name and
        !            43: //  fs_by_id.  They are keyed by mountpoint and by filesystem ID,
        !            44: //  respectively.  fs_by_id is lazily filled in as needed (so we only
        !            45: //  do as many statvfs calls as needed -- fam may hang if the NFS
        !            46: //  server is down).  fs_by_name is completely rebuilt when /etc/mtab
        !            47: //  is changed, and fs_by_id is destroyed, to be lazily re-filled
        !            48: //  later.
        !            49:
        !            50: //  Class Variables
        !            51:
        !            52: unsigned int		    FileSystemTable::count;
        !            53: FileSystemTable::IDTable    FileSystemTable::fs_by_id;
        !            54: FileSystemTable::NameTable *FileSystemTable::fs_by_name;
        !            55: const char		    FileSystemTable::mtab_name[] = MOUNTED;
        !            56: InternalClient		   *FileSystemTable::mtab_watcher;
        !            57: FileSystem		   *FileSystemTable::root;
        !            58:
        !            59: #ifdef HAPPY_PURIFY
        !            60:
        !            61: //////////////////////////////////////////////////////////////////////////////
        !            62: //  The constructor and destructor simply maintain a refcount of the
        !            63: //  files that include FileSystemTable.h.  When the last reference
        !            64: //  is destroyed, the mtab watcher is turned off, and the fs_by_name
        !            65: //  table is destroyed.
        !            66:
        !            67: FileSystemTable::FileSystemTable()
        !            68: {
        !            69:     count++;
        !            70: }
        !            71:
        !            72: FileSystemTable::~FileSystemTable()
        !            73: {
        !            74:     if (!--count)
        !            75:     {   delete mtab_watcher;
        !            76: 	mtab_watcher = NULL;
        !            77: 	if (fs_by_name)
        !            78: 	{   destroy_fses(fs_by_name);
        !            79: 	    delete fs_by_name;
        !            80: 	    fs_by_name = NULL;
        !            81: 	}
        !            82:     }
        !            83: }
        !            84:
        !            85: #endif /* HAPPY_PURIFY */
        !            86:
        !            87: //////////////////////////////////////////////////////////////////////////////
        !            88: //  fs_by_name is a table that maps mount directories to FileSystem pointers.
        !            89: //
        !            90: //  It is built the first time FileSystemTable::find() is called, and
        !            91: //  it's rebuilt whenever /etc/mtab changes.  When it is rebuilt,
        !            92: //  existing FileSystems are moved to the new table.  This is done
        !            93: //  because each ClientInterest has a pointer to its FileSystem,
        !            94: //  and we don't want to change all ClientInterests, nor do we want
        !            95: //  two FileSystem structures representing the same file system.
        !            96:
        !            97:
        !            98: void
        !            99: FileSystemTable::create_fs_by_name()
        !           100: {
        !           101:     NameTable *new_fs_by_name = new NameTable;
        !           102:     NameTable mount_parents, dismounted_fses;
        !           103:
        !           104:     if (fs_by_name)
        !           105: 	dismounted_fses = *fs_by_name;
        !           106:
        !           107:     //  Read /etc/mtab.
        !           108:     Cred::SuperUser.become_user();
        !           109:     FILE *mtab = setmntent(mtab_name, "r");
        !           110:     if(mtab == NULL)
        !           111:     {
        !           112:         Log::error("couldn't open %s for reading", mtab_name);
        !           113:         delete new_fs_by_name;
        !           114:         return;
        !           115:     }
        !           116:     root = NULL;
        !           117:     for (mntent *mp; ((mp = getmntent(mtab)) != NULL); )
        !           118:     {
        !           119: 	FileSystem *fs = fs_by_name ? fs_by_name->find(mp->mnt_dir) : NULL;
        !           120: 	if (fs && fs->matches(*mp))
        !           121: 	{
        !           122: 	    Log::debug("mtab: MATCH     \"%s\" on \"%s\" using type <%s>",
        !           123: 		       mp->mnt_fsname, mp->mnt_dir, mp->mnt_type);
        !           124:
        !           125: 	    new_fs_by_name->insert(mp->mnt_dir, fs);
        !           126: 	    if (dismounted_fses.find(mp->mnt_dir))
        !           127: 		dismounted_fses.remove(mp->mnt_dir);
        !           128: 	}
        !           129: 	else
        !           130: 	{
        !           131:
        !           132:             if ((!strcmp(mp->mnt_type, MNTTYPE_NFS)
        !           133: #if HAVE_MNTTYPE_NFS2
        !           134:                 || !strcmp(mp->mnt_type, MNTTYPE_NFS2)
        !           135: #endif
        !           136: #if HAVE_MNTTYPE_NFS3
        !           137:                 || !strcmp(mp->mnt_type, MNTTYPE_NFS3)
        !           138: #endif
        !           139: #if HAVE_MNTTYPE_CACHEFS
        !           140:                 || !strcmp(mp->mnt_type, MNTTYPE_CACHEFS)
        !           141: #endif
        !           142:                 ) && strchr(mp->mnt_fsname, ':'))
        !           143:             {
        !           144:                 if(Log::get_level() == Log::DEBUG)
        !           145:                 {
        !           146:                     const char *mntopt = hasmntopt(mp, "dev");
        !           147:                     if(mntopt == NULL) mntopt = "";
        !           148: 		    Log::debug("mtab: new NFS   \"%s\" on \"%s\" %s using <%s>",
        !           149: 			       mp->mnt_fsname, mp->mnt_dir, mntopt,
        !           150:                                mp->mnt_type);
        !           151:                 }
        !           152:
        !           153: 		fs = new NFSFileSystem(*mp);
        !           154: 	    }
        !           155: 	    else
        !           156: 	    {
        !           157: 		Log::debug("mtab: new local \"%s\" on \"%s\"",
        !           158: 			   mp->mnt_fsname, mp->mnt_dir);
        !           159:
        !           160: 		fs = new LocalFileSystem(*mp);
        !           161: 	    }
        !           162: 	    new_fs_by_name->insert(mp->mnt_dir, fs);
        !           163: 	    if (fs_by_name)
        !           164: 	    {
        !           165: 		// Find parent filesystem.
        !           166:
        !           167: 		FileSystem *parent = longest_prefix(mp->mnt_dir);
        !           168: 		assert(parent);
        !           169: 		mount_parents.insert(parent->dir(), parent);
        !           170: 	    }
        !           171: 	}
        !           172: 	if (!strcmp(mp->mnt_dir, "/"))
        !           173: 	    root = fs;
        !           174:     }
        !           175:     endmntent(mtab);
        !           176:
        !           177:     if(root == NULL)
        !           178:     {
        !           179:         assert(root);
        !           180:         Log::error("couldn't find / in %s", mtab_name);
        !           181:         delete new_fs_by_name;
        !           182:         return;  //  horrible... we're not in a good state, the
        !           183:                  //  now-brain-damaged fs_by_name is hanging around, etc.
        !           184:                  //  It might be better to exit.
        !           185:     }
        !           186:
        !           187:     //  Install the new table.
        !           188:
        !           189:     delete fs_by_name;
        !           190:     fs_by_name = new_fs_by_name;
        !           191:
        !           192:     //  Relocate all interests in parents of new filesystems.
        !           193:     //  We relocate interests out of parents before relocating
        !           194:     //  out of dismounted filesystems in the hope that we can
        !           195:     //	avoid relocating some interests twice.  Consider the case
        !           196:     //  where /mnt/foo is an interest, and we simultaneously
        !           197:     //  learn that /mnt was dismounted and /fred was mounted.
        !           198:     //  We don't want to relocate /mnt/foo to /, then test
        !           199:     //  it for relocation to /fred.
        !           200:
        !           201:     unsigned i;
        !           202:     FileSystem *fs;
        !           203:     for (i = 0; ((fs = mount_parents.value(i)) != NULL); i++)
        !           204:     {
        !           205: 	Log::debug("mtab: relocating in parent \"%s\"", fs->dir());
        !           206: 	fs->relocate_interests();
        !           207:     }
        !           208:
        !           209:     //  Relocate all interests in dismounted filesystems and destroy
        !           210:     //  the filesystems.
        !           211:
        !           212:     for (i = 0; ((fs = dismounted_fses.value(i)) != NULL); i++)
        !           213:     {
        !           214: 	Log::debug("mtab: dismount  \"%s\" on \"%s\"",
        !           215: 		   fs->fsname(), fs->dir());
        !           216:
        !           217: 	fs->relocate_interests();
        !           218: 	delete fs;
        !           219:     }
        !           220:     Log::debug("mtab done.");
        !           221: }
        !           222:
        !           223: void
        !           224: FileSystemTable::destroy_fses(NameTable *fstab)
        !           225: {
        !           226:     //  Destroy any unreclaimed filesystems.
        !           227:
        !           228:     for (unsigned i = 0; fstab->key(i); i++)
        !           229: 	delete fstab->value(i);
        !           230: }
        !           231:
        !           232: void
        !           233: FileSystemTable::mtab_event_handler(const Event& event, void *)
        !           234: {
        !           235:     if (event == Event::Changed)
        !           236:     {
        !           237: 	Log::debug("%s changed, rebuilding filesystem table", mtab_name);
        !           238: 	fs_by_id.removeAll();
        !           239: 	create_fs_by_name();
        !           240:     }
        !           241: }
        !           242:
        !           243: //////////////////////////////////////////////////////////////////////////////
        !           244: //
        !           245:
        !           246: FileSystem *
        !           247: FileSystemTable::find(const char *path, const Cred& cr)
        !           248: {
        !           249:     char temp_path[PATH_MAX];
        !           250:     FileSystem *fs = NULL;
        !           251:
        !           252:     assert(path[0] == '/');
        !           253:
        !           254:     //  (Initialize fs_by_name if necessary.) As a side effect,
        !           255:     //  create_fs_by_name initializes our "root" member variable.
        !           256:     if (!fs_by_name)
        !           257:     {   create_fs_by_name();
        !           258: 	mtab_watcher = new InternalClient(mtab_name, mtab_event_handler, NULL);
        !           259:     }
        !           260:
        !           261:     cr.become_user();
        !           262:
        !           263:     //  If !HAVE_STATVFS, we could use statfs instead, but the statfs.f_fsid
        !           264:     //  is not set reliably on Linux, so it's useless.  We'll do every lookup
        !           265:     //  by name; hopefully that doesn't suck.
        !           266: #if HAVE_STATVFS
        !           267:
        !           268:     //  Perform a statvfs(2) on the first existing ancestor.
        !           269:
        !           270:     struct statvfs fs_status;
        !           271:     int rc = statvfs(path, &fs_status);
        !           272:     if (rc < 0)
        !           273:     {   (void) strcpy(temp_path, path);
        !           274: 	while (rc < 0)
        !           275: 	{   char *slash = strrchr(temp_path, '/');
        !           276: 	    if (!slash)
        !           277: 		return root;
        !           278: 	    *slash = '\0';
        !           279: 	    rc = statvfs(temp_path, &fs_status);
        !           280: 	}
        !           281:     }
        !           282:
        !           283:     //  Look up filesystem by ID.
        !           284:
        !           285:     fs = fs_by_id.find(fs_status.f_fsid);
        !           286:     if (fs)
        !           287: 	return fs;
        !           288: #endif
        !           289:
        !           290:     //  Convert to real path.  Look up real path in fs_by_name().
        !           291:
        !           292:     cr.become_user();
        !           293:     (void) realpath(path, temp_path);
        !           294:     fs = longest_prefix(temp_path);
        !           295:
        !           296:     //  Insert into fs_by_id.
        !           297:
        !           298: #if HAVE_STATVFS
        !           299:     fs_by_id.insert(fs_status.f_fsid, fs);
        !           300: #endif
        !           301:
        !           302:     return fs;
        !           303: }
        !           304:
        !           305: FileSystem *
        !           306: FileSystemTable::longest_prefix(const char *path)
        !           307: {
        !           308:     FileSystem * bestmatch = root;
        !           309:     int maxmatch = -1;
        !           310:     const char *key;
        !           311:     for (unsigned i = 0; ((key = fs_by_name->key(i)) != NULL); i++)
        !           312:     {   for (int j = 0; ; j++)
        !           313: 	{   if (!key[j])
        !           314: 	    {   if ((!path[j] || path[j] == '/') && j > maxmatch)
        !           315: 		{   maxmatch = j;
        !           316: 		    bestmatch = fs_by_name->value(i);
        !           317: 		}
        !           318: 		break;
        !           319: 	    }
        !           320: 	    if (key[j] != path[j])
        !           321: 		break;
        !           322: 	}
        !           323:     }
        !           324:     assert(bestmatch);
        !           325:     return bestmatch;
        !           326: }
        !           327:

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>