2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
6 * These libraries and programs are free software; you can
7 * redistribute them and/or modify them under the terms of the GNU
8 * Lesser General Public License as published by the Free Software
9 * Foundation; either version 2 of the License, or (at your option)
12 * These libraries and programs are distributed in the hope that
13 * they will be useful, but WITHOUT ANY WARRANTY; without even the
14 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU Lesser General Public License for more
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with these librararies and programs; if not, write
20 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 * Floor, Boston, MA 02110-1301 USA
23 //%% (c) Copyright 1993, 1994 Hewlett-Packard Company
24 //%% (c) Copyright 1993, 1994 International Business Machines Corp.
25 //%% (c) Copyright 1993, 1994 Sun Microsystems, Inc.
26 //%% (c) Copyright 1993, 1994 Novell, Inc.
27 //%% $TOG: tt_file_system.C /main/5 1998/03/19 18:59:48 mgreess $
28 //%% restrictions in a confidential disclosure agreement between
29 //%% HP, IBM, Sun, USL, SCO and Univel. Do not distribute this
30 //%% document outside HP, IBM, Sun, USL, SCO, or Univel without
31 //%% Sun's specific written approval. This document and all copies
32 //%% and derivative works thereof must be returned or destroyed at
35 //%% Copyright 1993, 1994 Sun Microsystems, Inc. All rights reserved.
37 /* @(#)tt_file_system.C 1.40 95/01/06
41 * Copyright (c) 1990, 1994 by Sun Microsystems, Inc.
43 * Defines a class for browsing the file system mount table.
50 # include <sys/poll.h>
56 #include "tt_options.h"
57 #include "util/tt_port.h"
58 #include "util/tt_host_equiv.h"
60 #if defined(OPT_SVR4_GETMNTENT)
61 # include <sys/mnttab.h>
62 # include <sys/mntent.h>
63 # define TtMntTab MNTTAB
64 # define TtMntEntry struct mnttab
65 # define ttOpenMntTbl(path,mode) fopen(path,mode)
66 # define ttFsType(e) (e).mnt_fstype
67 # define ttFsName(e) (e).mnt_special
68 # define ttMountPt(e) (e).mnt_mountp
69 # define ttCloseMntTbl(f) fclose(f)
71 extern "C" int mntctl(int,int,char *);
73 # define MNTTYPE_NFS "nfs"
74 # define ttOpenMntTbl(path,mode) ((FILE *) 1)
75 # define TtMntEntry struct vmount *
76 # define ttFsType(e) \
77 (((e)->vmt_gfstype == MNT_JFS) ? "jfs" \
78 : (((e)->vmt_gfstype == MNT_NFS) ? "nfs" \
79 : (((e)->vmt_gfstype == MNT_CDROM) ? "cdrom" \
80 : (((e)->vmt_gfstype == MNT_AIX) ? "oaix" \
82 # define ttFsName(e) vmt2dataptr(e,VMT_OBJECT)
83 # define ttMountPt(e) vmt2dataptr(e,VMT_STUB)
84 # define ttCloseMntTbl(f) free(tmpbuf)
85 #elif defined(__osf__) || defined(CSRG_BASED)
86 # include <sys/types.h>
87 # include <sys/mount.h>
90 #if defined(HAS_STATVFS)
91 extern "C" int getfsstat(struct statvfs *, long, int);
92 #elif defined(__osf__)
93 extern "C" int getfsstat(struct statfs *, long, int);
96 # define MNTTYPE_NFS "nfs"
97 # define ttOpenMntTbl(path,mode) ((FILE *) 1)
99 # if defined(HAS_STATVFS)
100 # include <sys/statvfs.h>
101 # define TtMntEntry struct statvfs *
103 # define TtMntEntry struct statfs *
107 # define ttFsType(e) \
108 (((e)->f_type == MOUNT_UFS) ? "ufs" \
109 : (((e)->f_type == MOUNT_NFS3) ? "nfs" \
110 : (((e)->f_type == MOUNT_NFS) ? "nfs" \
111 : (((e)->f_type == MOUNT_CDFS) ? "cdfs" \
112 : (((e)->f_type == MOUNT_PROCFS) ? "procfs" \
114 # elif defined(CSRG_BASED)
115 # define ttFsType(e) (e->f_fstypename)
117 # define ttFsName(e) ((char *)((e)->f_mntfromname))
118 # define ttMountPt(e) ((char *)((e)->f_mntonname))
119 # define ttCloseMntTbl(f) free(buf)
122 # define TtMntTab MOUNTED
123 # define MNTTYPE_RFS "rfs"
124 # define TtMntEntry struct mntent *
125 # define ttOpenMntTbl(path,mode) setmntent(path,mode)
126 # define ttFsType(e) (e)->mnt_type
127 # define ttFsName(e) (e)->mnt_fsname
128 # define ttMountPt(e) (e)->mnt_dir
129 # define ttCloseMntTbl(f) endmntent(f)
131 #include "util/tt_file_system_entry_utils.h"
132 #include "util/tt_file_system.h"
133 #include "util/tt_file_system_entry.h"
134 #include "util/tt_path.h"
135 #include "util/tt_port.h"
136 #include "util/tt_host.h"
137 #include "util/tt_global_env.h"
139 #if defined(OPT_BUG_SUNOS_5)
140 // Bug 1116904 filed on the absence of hasmntopt from the
141 // header file. Fixed in SunOS 5.3, but we leave this in so
142 // we can compile on 5.1 and 5.2.
144 extern char *hasmntopt(struct mnttab *mnt, char *opt);
148 time_t _Tt_file_system::lastMountTime = 0;
153 // It would be simpler just to have a static instance of
154 // _Tt_file_system_entry_list here, but static class instances
155 // are verboten if we want to be called by C programs.
156 if (_tt_global->fileSystemEntries.is_null()) {
157 _tt_global->fileSystemEntries = new _Tt_file_system_entry_list;
168 static _Tt_file_system_entry *
169 createFileSystemEntry(TtMntEntry entry)
172 _Tt_string mount_point;
173 _Tt_string partition;
175 int loop_back_flag = 0;
177 // not all platforms have the IGNORE option, but if it
178 // is defined, be sure to ignore mount entries with it
179 // set, as they are things like automounter entries
180 // that will just confuse the mapping.
182 #if defined(MNTOPT_IGNORE)
183 if (0!=hasmntopt(&entry, MNTOPT_IGNORE)) {
184 return (_Tt_file_system_entry *)0;
187 if ( (strcmp( ttFsType(entry), MNTTYPE_NFS) == 0)
188 #if defined(MNTTYPE_RFS)
189 || (strcmp( ttFsType(entry), MNTTYPE_RFS) == 0)
194 // AIX is different; at least it\'s arguably better.
195 hostname = vmt2dataptr(entry,VMT_HOSTNAME);
196 partition = ttFsName(entry);
199 // Search for a '.' to separate the hostname and
201 char *endOfHostNamePos =
202 strchr(ttFsName(entry), '.');
204 // Search for the ':' that separates the
205 // hostname and the rest of the mtab field.
207 char *justBeforePartitionPos =
208 strchr(ttFsName(entry), ':');
210 // If there was no domain name or the dot
211 // found above was after the ':' (the dot was
212 // just part of a directoty name), then the
213 // hostname ends at the ':' position.
215 if (!endOfHostNamePos ||
216 (justBeforePartitionPos < endOfHostNamePos)) {
217 endOfHostNamePos = justBeforePartitionPos;
220 // NULL terminate the hostname part of the field
221 if (endOfHostNamePos) {
222 *endOfHostNamePos = '\0';
225 if (justBeforePartitionPos) {
226 partition = justBeforePartitionPos+1;
229 hostname = ttFsName(entry);
232 loop_back_flag = FALSE;
234 partition = ttFsName(entry);
235 _Tt_host_ptr localHost;
236 _tt_global->get_local_host( localHost );
237 hostname = localHost->name();
239 loop_back_flag = FALSE;
241 #if defined(MNTTYPE_LOFS)
242 if (!strcmp( ttFsType(entry), MNTTYPE_LOFS)) {
243 loop_back_flag = TRUE;
247 mount_point = ttMountPt(entry);
249 return new _Tt_file_system_entry( hostname, mount_point, partition,
250 local_flag, loop_back_flag );
255 * Finds the best match mount table entry to the specified local path
256 * resolving loop back mounts to the true mount point.
258 _Tt_file_system_entry_ptr _Tt_file_system::
259 bestMatchToPath (const _Tt_string &path)
261 _Tt_string real_path = _tt_realpath(path);
263 updateFileSystemEntries();
265 _Tt_file_system_entry_ptr max_match_entry;
266 bool_t loop_back_flag = TRUE;
267 _Tt_string current_loop_back_mount_point;
268 _Tt_string first_loop_back_mount_point;
269 bool_t first_time = TRUE;
271 while (loop_back_flag) {
272 max_match_entry = findBestMountPoint(real_path,
274 current_loop_back_mount_point);
276 if (loop_back_flag && first_time) {
277 first_loop_back_mount_point =
278 current_loop_back_mount_point;
284 max_match_entry->loopBackMountPoint = first_loop_back_mount_point;
285 return max_match_entry;
289 * Finds the best matching mount pount to the specified local path.
290 * If the best match is a loop back then the matching portion of the
291 * specified path is updated to the loop back partition and the loop
292 * back flag parameter is set to TRUE.
294 _Tt_file_system_entry_ptr _Tt_file_system::
295 findBestMountPoint (_Tt_string &path,
296 bool_t &loop_back_flag,
297 _Tt_string &loop_back_mount_point)
299 updateFileSystemEntries();
301 _Tt_string current_mount_point;
302 int current_mount_point_length;
303 _Tt_file_system_entry_ptr max_match_entry;
304 int max_match_length = 0;
305 int path_length = path.len();
307 _Tt_file_system_entry_list_cursor
308 entries_cursor(_tt_global->fileSystemEntries);
310 while (entries_cursor.next()) {
311 current_mount_point = entries_cursor->getMountPoint();
312 current_mount_point_length = current_mount_point.len();
313 if (path_length < current_mount_point_length) {
317 if (current_mount_point_length > max_match_length) {
318 if (!memcmp((char *)current_mount_point,
320 current_mount_point_length)) {
321 max_match_length = current_mount_point_length;
322 max_match_entry = *entries_cursor;
326 if (max_match_length == path_length) {
331 if (max_match_entry->isLoopBack ()) {
332 loop_back_flag = TRUE;
334 _Tt_string mount_point = max_match_entry->getMountPoint();
335 _Tt_string partition = max_match_entry->getPartition();
337 // Get the path info after the mount point path
338 path = path.right(path.len()-mount_point.len());
340 // Prepend the loop back partition onto the rest of the path
341 path = partition.cat(path);
343 // Return the loop back mount point
344 loop_back_mount_point = mount_point;
346 loop_back_flag = FALSE;
349 return max_match_entry;
353 * Finds the mount table entry corresponding to the specified network path.
354 * The specified path must be of the form:
358 _Tt_file_system_entry_ptr _Tt_file_system::
359 findMountEntry (const _Tt_string &network_path)
361 updateFileSystemEntries();
363 _Tt_string current_hostname;
364 _Tt_string current_partition;
365 int current_partition_length;
366 _Tt_file_system_entry_ptr entry;
372 path = path.split(':', hostname);
374 int path_length = path.len();
376 _Tt_file_system_entry_list_cursor
377 entries_cursor(_tt_global->fileSystemEntries);
379 _Tt_host_equiv_ptr eq_p = new _Tt_host_equiv();
380 while (entries_cursor.next()) {
381 current_hostname = entries_cursor->getHostname();
384 printf("DEBUG findMountEntry: hostname = %s, current_hostname = %s\n",
385 (char *) hostname, (char *) current_hostname);
388 if (eq_p->hostname_equiv(hostname, current_hostname) == 1) {
389 current_partition = entries_cursor->getPartition();
390 current_partition_length = current_partition.len();
393 printf("DEBUG findMountEntry: found hostname equivalence between %s and %s\n",
394 (char *) hostname, (char *) current_hostname);
397 if (path_length >= current_partition_length) {
398 if (!memcmp((char *)path, (char *)current_partition,
399 current_partition_length)) {
400 entry = *entries_cursor;
402 printf("DEBUG findMountEntry: found PATH equivalence between %s and %s\n",
403 (char *) hostname, (char *) current_hostname);
414 void _Tt_file_system::
415 updateFileSystemEntries ()
417 static int firsttime = 1;
418 static int since_last = 0;
421 if (since_last < _tt_global->event_counter) {
422 since_last = _tt_global->event_counter;
428 // AIX doesn\'t have a mount table file as such.
431 struct stat mount_table_stat;
432 if (stat(TtMntTab, &mount_table_stat)) {
436 if (!firsttime && mount_table_stat.st_mtime <= lastMountTime) {
442 // XXX Due to bug #1126575 - MNTTAB temporarily goes to
443 // size 0 during automounter updates. The file stats
444 // OK, but has no data in it.
446 while (mount_table_stat.st_size == 0) {
447 (void)poll (&poll_fd, 0, 100);
448 // Must use lstat here; mtab is often a symlink
449 if (lstat(TtMntTab, &mount_table_stat)) {
454 FILE *mount_table = ttOpenMntTbl(TtMntTab, "r");
459 fcntl(fileno(mount_table), F_SETFD, 1); // Close on exec.
461 lastMountTime = mount_table_stat.st_mtime;
464 _tt_global->fileSystemEntries->flush();
465 _Tt_file_system_entry_ptr fse;
469 char *tmpbuf = (char *)malloc( sz );
471 while ((rc = mntctl(MCTL_QUERY, sz, tmpbuf)) == 0)
473 // increase buffer size
474 sz = *((int *) tmpbuf);
476 tmpbuf = (char *)malloc( sz );
479 for (entry = (TtMntEntry)tmpbuf; rc > 0; --rc,
480 entry = (TtMntEntry)((char *) entry + entry->vmt_length))
482 #elif defined(HAS_STATVFS)
486 int flags = MNT_NOWAIT;
487 char *s, *host, path[MNAMELEN] ;
489 numfs = getvfsstat ( (struct statvfs *)0, 0, 0 );
491 bufsize = numfs * sizeof ( struct statvfs );
492 buf = (struct statvfs *) malloc ( bufsize );
493 memset ((void *)buf,0,bufsize);
495 getvfsstat ( buf, bufsize, flags );
497 for ( i=0; i<numfs; i++ )
499 // convert path@host to host:/path
500 s = strchr(buf[i].f_mntfromname,'@');
503 memset((char*)path,0,MNAMELEN);
504 strncpy(path,buf[i].f_mntfromname, (strlen(buf[i].f_mntfromname)
506 strcpy(buf[i].f_mntfromname,host) ;
507 strcat(buf[i].f_mntfromname,":") ;
508 strcat(buf[i].f_mntfromname,path) ;
512 #elif defined(__osf__) || defined(CSRG_BASED)
516 int flags = MNT_NOWAIT;
517 char *s, *host, path[MNAMELEN] ;
519 numfs = getfsstat ( (struct statfs *)0, 0, 0 );
521 bufsize = numfs * sizeof ( struct statfs );
522 buf = (struct statfs *) malloc ( bufsize );
523 memset ((void *)buf,0,bufsize);
525 getfsstat ( buf, bufsize, flags );
527 for ( i=0; i<numfs; i++ )
529 // convert path@host to host:/path
530 s = strchr(buf[i].f_mntfromname,'@');
533 memset((char*)path,0,MNAMELEN);
534 strncpy(path,buf[i].f_mntfromname, (strlen(buf[i].f_mntfromname)
536 strcpy(buf[i].f_mntfromname,host) ;
537 strcat(buf[i].f_mntfromname,":") ;
538 strcat(buf[i].f_mntfromname,path) ;
542 #elif defined(OPT_SVR4_GETMNTENT)
544 while (! (rc = getmntent(mount_table, &entry)))
546 while (entry = getmntent(mount_table))
548 #if !defined(__osf__) && !defined(CSRG_BASED)
551 fse = createFileSystemEntry( entry );
552 if (!fse.is_null()) {
553 #if defined(TT_DEBUG_FNM)
554 fprintf(stderr,"File name mapping: %s:%s on %s; %s %s\n",
555 (char *)fse->getHostname(),
556 (char *)fse->getPartition(),
557 (char *)fse->getMountPoint(),
558 fse->isLocal()?"local":"",
559 fse->isLoopBack()?"loopback":"");
561 _tt_global->fileSystemEntries->append(fse);
565 ttCloseMntTbl(mount_table);
568 void _Tt_file_system::
571 if (!_tt_global->fileSystemEntries.is_null()) {
572 _tt_global->fileSystemEntries->flush();
577 /* Local Variables : */
578 /* c++-indent-level: 2 */