Teach ToolTalk config about NetBSD and adds HAS_STATVFS identifier which is consequen...
[oweals/cde.git] / cde / lib / tt / lib / util / tt_file_system.C
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
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)
10  * any later version.
11  *
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
16  * details.
17  *
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
22  */
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   
33 //%%    Sun's request.                                                  
34 //%%                                                                    
35 //%%    Copyright 1993, 1994 Sun Microsystems, Inc.  All rights reserved.       
36 //%%                                                                    
37 /* @(#)tt_file_system.C 1.40 95/01/06
38  *
39  * Tool Talk Utility
40  *
41  * Copyright (c) 1990, 1994 by Sun Microsystems, Inc.
42  *
43  * Defines a class for browsing the file system mount table.
44  *
45  */
46
47 #include <stdio.h>
48 #include <string.h>
49 #if defined(linux)
50 # include <sys/poll.h>
51 #else
52 # include <poll.h>
53 #endif
54 #include <sys/stat.h>
55 #include <fcntl.h>
56 #include "tt_options.h"
57 #include "util/tt_port.h"
58 #include "util/tt_host_equiv.h"
59
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)
70 #elif defined(_AIX)
71         extern "C" int mntctl(int,int,char *);
72 #       include <sys/vfs.h>
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" \
81                                    : "unknown"))))
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>
88
89
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);
94 # endif
95
96 #       define MNTTYPE_NFS              "nfs"
97 #       define ttOpenMntTbl(path,mode)  ((FILE *) 1)
98
99 # if defined(HAS_STATVFS)
100 #     include <sys/statvfs.h>
101 #     define TtMntEntry struct statvfs *
102 # else
103 #     define TtMntEntry struct statfs *
104 # endif
105
106 # ifdef __osf__
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" \
113                                    : "unknown")))))
114 # elif defined(CSRG_BASED)
115 #       define ttFsType(e)              (e->f_fstypename)
116 # endif
117 #       define ttFsName(e)              ((char *)((e)->f_mntfromname))
118 #       define ttMountPt(e)             ((char *)((e)->f_mntonname))
119 #       define ttCloseMntTbl(f)         free(buf)
120 #else
121 #       include <mntent.h>
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)
130 #endif
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"
138
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.
143 extern "C" {
144         extern char *hasmntopt(struct mnttab *mnt, char *opt);
145 };
146 #endif
147
148 time_t                          _Tt_file_system::lastMountTime          = 0;
149
150 _Tt_file_system::
151 _Tt_file_system ()
152 {
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;
158                 lastMountTime = 0;
159         }
160 }
161
162 _Tt_file_system::
163 ~_Tt_file_system ()
164 {
165         lastMountTime = 0;
166 }
167
168 static _Tt_file_system_entry *
169 createFileSystemEntry(TtMntEntry entry)
170 {
171         _Tt_string hostname;
172         _Tt_string mount_point;
173         _Tt_string partition;
174         int        local_flag = 1;
175         int        loop_back_flag = 0;
176         //
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.
181         //
182 #if defined(MNTOPT_IGNORE)
183         if (0!=hasmntopt(&entry, MNTOPT_IGNORE)) {
184                 return (_Tt_file_system_entry *)0;
185         }
186 #endif
187         if (   (strcmp( ttFsType(entry), MNTTYPE_NFS) == 0)
188 #if defined(MNTTYPE_RFS)
189             || (strcmp( ttFsType(entry), MNTTYPE_RFS) == 0)
190 #endif
191            )
192         {
193 #if defined(_AIX)
194                 // AIX is different; at least it\'s arguably better.
195                 hostname = vmt2dataptr(entry,VMT_HOSTNAME);
196                 partition = ttFsName(entry);
197 #else /* AIX */
198         
199                 // Search for a '.' to separate the hostname and
200                 // the domain name
201                 char *endOfHostNamePos =
202                         strchr(ttFsName(entry), '.');
203
204                 // Search for the ':' that separates the
205                 // hostname and the rest of the mtab field.
206
207                 char *justBeforePartitionPos =
208                         strchr(ttFsName(entry), ':');
209
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.
214
215                 if (!endOfHostNamePos ||
216                     (justBeforePartitionPos < endOfHostNamePos)) {
217                         endOfHostNamePos = justBeforePartitionPos;
218                 }
219
220                 // NULL terminate the hostname part of the field
221                 if (endOfHostNamePos) {
222                         *endOfHostNamePos = '\0';
223                 }
224
225                 if (justBeforePartitionPos) {
226                         partition = justBeforePartitionPos+1;
227                 }
228
229                 hostname = ttFsName(entry);
230 #endif  /* AIX */       
231                 local_flag = FALSE;
232                 loop_back_flag = FALSE;
233         } else {
234                 partition = ttFsName(entry);
235                 _Tt_host_ptr localHost;
236                 _tt_global->get_local_host( localHost );
237                 hostname = localHost->name();
238                 local_flag = TRUE;
239                 loop_back_flag = FALSE;
240
241 #if defined(MNTTYPE_LOFS)
242                 if (!strcmp( ttFsType(entry), MNTTYPE_LOFS)) {
243                         loop_back_flag = TRUE;
244                 }
245 #endif
246         }
247         mount_point = ttMountPt(entry);
248
249         return new _Tt_file_system_entry( hostname, mount_point, partition,
250                                           local_flag, loop_back_flag );
251 }
252
253
254 /*
255  * Finds the best match mount table entry to the specified local path
256  * resolving loop back mounts to the true mount point.
257  */
258 _Tt_file_system_entry_ptr _Tt_file_system::
259 bestMatchToPath (const _Tt_string &path)
260 {
261         _Tt_string real_path = _tt_realpath(path);
262
263         updateFileSystemEntries();
264
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;
270
271         while (loop_back_flag) {
272                 max_match_entry = findBestMountPoint(real_path,
273                                                   loop_back_flag,
274                                                   current_loop_back_mount_point);
275
276                 if (loop_back_flag && first_time) {
277                         first_loop_back_mount_point =
278                                 current_loop_back_mount_point;
279                 }
280
281                 first_time = FALSE;
282         }
283
284         max_match_entry->loopBackMountPoint = first_loop_back_mount_point;
285         return max_match_entry;
286 }
287
288 /*
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.
293  */
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)
298 {
299         updateFileSystemEntries();
300
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();
306
307         _Tt_file_system_entry_list_cursor
308                 entries_cursor(_tt_global->fileSystemEntries);
309
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) {
314                         continue;
315                 }
316
317                 if (current_mount_point_length > max_match_length) {
318                         if (!memcmp((char *)current_mount_point,
319                                     (char *)path,
320                                     current_mount_point_length)) {
321                                 max_match_length = current_mount_point_length;
322                                 max_match_entry = *entries_cursor;
323                         }  
324                 }
325
326                 if (max_match_length == path_length) {
327                         break;
328                 }
329         }
330
331         if (max_match_entry->isLoopBack ()) {
332                 loop_back_flag = TRUE;
333
334                 _Tt_string mount_point = max_match_entry->getMountPoint();
335                 _Tt_string partition = max_match_entry->getPartition();
336
337                 // Get the path info after the mount point path
338                 path = path.right(path.len()-mount_point.len());
339
340                 // Prepend the loop back partition onto the rest of the path
341                 path = partition.cat(path);
342
343                 // Return the loop back mount point
344                 loop_back_mount_point = mount_point;
345         } else {
346                 loop_back_flag = FALSE;
347         }
348
349         return max_match_entry;
350 }
351
352 /*
353  * Finds the mount table entry corresponding to the specified network path.
354  * The specified path must be of the form:
355  *
356  *              hostname:/path
357  */
358 _Tt_file_system_entry_ptr _Tt_file_system::
359 findMountEntry (const _Tt_string &network_path)
360 {
361         updateFileSystemEntries();
362
363         _Tt_string                      current_hostname;
364         _Tt_string                      current_partition;
365         int                             current_partition_length;
366         _Tt_file_system_entry_ptr       entry;
367
368         _Tt_string hostname;
369         _Tt_string path;
370
371         path = network_path;
372         path = path.split(':', hostname);
373
374         int path_length = path.len();
375
376         _Tt_file_system_entry_list_cursor
377                 entries_cursor(_tt_global->fileSystemEntries);
378
379         _Tt_host_equiv_ptr eq_p = new _Tt_host_equiv();
380         while (entries_cursor.next()) {
381                 current_hostname = entries_cursor->getHostname();
382
383 #ifdef notdef
384 printf("DEBUG findMountEntry: hostname = %s, current_hostname = %s\n",
385         (char *) hostname, (char *) current_hostname);
386 #endif
387
388                 if (eq_p->hostname_equiv(hostname, current_hostname) == 1) {
389                         current_partition = entries_cursor->getPartition();
390                         current_partition_length = current_partition.len();
391
392 #ifdef notdef
393 printf("DEBUG findMountEntry: found hostname equivalence between %s and %s\n",
394         (char *) hostname, (char *) current_hostname);
395 #endif
396
397                         if (path_length >= current_partition_length) {
398                                 if (!memcmp((char *)path, (char *)current_partition,
399                                             current_partition_length)) {
400                                         entry = *entries_cursor;
401 #ifdef notdef
402 printf("DEBUG findMountEntry: found PATH equivalence between %s and %s\n",
403         (char *) hostname, (char *) current_hostname);
404 #endif
405
406                                         break;
407                                 }
408                         }
409                 }
410         }
411         return entry;
412 }
413
414 void _Tt_file_system::
415 updateFileSystemEntries ()
416 {
417         static int firsttime = 1;
418         static int since_last = 0;
419
420         if (!firsttime) {
421                 if (since_last < _tt_global->event_counter) {
422                         since_last = _tt_global->event_counter;
423                 } else {
424                         return;
425                 }
426         }
427
428 // AIX  doesn\'t have a mount table file as such.
429 #ifdef TtMntTab
430
431         struct stat mount_table_stat;
432         if (stat(TtMntTab, &mount_table_stat)) {
433                 return;
434         }
435
436         if (!firsttime && mount_table_stat.st_mtime <= lastMountTime) {
437                 return;
438         }
439
440         firsttime = 0;
441         
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.
445         pollfd poll_fd;
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)) {
450                         return;
451                 }
452         }
453
454         FILE *mount_table = ttOpenMntTbl(TtMntTab, "r");
455
456         if (! mount_table) {
457                 return;
458         }
459         fcntl(fileno(mount_table), F_SETFD, 1);         // Close on exec.
460
461         lastMountTime = mount_table_stat.st_mtime;
462 #endif
463
464         _tt_global->fileSystemEntries->flush();
465         _Tt_file_system_entry_ptr fse;  
466         TtMntEntry entry;
467 #if defined(_AIX)
468         int     rc, sz = BUFSIZ;
469         char    *tmpbuf = (char *)malloc( sz );
470
471         while ((rc = mntctl(MCTL_QUERY, sz, tmpbuf)) == 0)
472         {
473                 // increase buffer size
474                 sz = *((int *) tmpbuf);
475                 free( tmpbuf );
476                 tmpbuf = (char *)malloc( sz );
477         }
478
479         for (entry = (TtMntEntry)tmpbuf; rc > 0; --rc,
480              entry = (TtMntEntry)((char *) entry + entry->vmt_length))
481
482 #elif defined(HAS_STATVFS)
483         int             numfs,i;
484         struct statvfs  *buf;
485         long            bufsize;
486         int             flags = MNT_NOWAIT;
487         char            *s, *host, path[MNAMELEN] ;
488
489         numfs = getvfsstat ( (struct statvfs *)0, 0, 0 );
490
491         bufsize = numfs * sizeof ( struct statvfs );
492         buf = (struct statvfs *) malloc ( bufsize );
493         memset ((void *)buf,0,bufsize);
494
495         getvfsstat ( buf, bufsize, flags );
496
497         for ( i=0; i<numfs; i++ )
498         {
499             // convert path@host to host:/path
500             s = strchr(buf[i].f_mntfromname,'@');
501             if (s != NULL) {
502                 host = s + 1 ;
503                 memset((char*)path,0,MNAMELEN);
504                 strncpy(path,buf[i].f_mntfromname, (strlen(buf[i].f_mntfromname)
505  - strlen(s))) ;
506                 strcpy(buf[i].f_mntfromname,host) ;
507                 strcat(buf[i].f_mntfromname,":") ;
508                 strcat(buf[i].f_mntfromname,path) ;
509             }
510             entry = &buf[i];
511
512 #elif defined(__osf__) || defined(CSRG_BASED)
513         int             numfs,i;
514         struct statfs   *buf;
515         long            bufsize;
516         int             flags = MNT_NOWAIT;
517         char            *s, *host, path[MNAMELEN] ;
518  
519         numfs = getfsstat ( (struct statfs *)0, 0, 0 );
520
521         bufsize = numfs * sizeof ( struct statfs );
522         buf = (struct statfs *) malloc ( bufsize );
523         memset ((void *)buf,0,bufsize);
524
525         getfsstat ( buf, bufsize, flags );
526
527         for ( i=0; i<numfs; i++ )
528         {
529             // convert path@host to host:/path
530             s = strchr(buf[i].f_mntfromname,'@');
531             if (s != NULL) {
532                 host = s + 1 ;
533                  memset((char*)path,0,MNAMELEN);
534                 strncpy(path,buf[i].f_mntfromname, (strlen(buf[i].f_mntfromname)
535  - strlen(s))) ;
536                 strcpy(buf[i].f_mntfromname,host) ;
537                 strcat(buf[i].f_mntfromname,":") ;
538                 strcat(buf[i].f_mntfromname,path) ;
539             }
540             entry = &buf[i];
541
542 #elif defined(OPT_SVR4_GETMNTENT)
543         int rc;     
544         while (! (rc = getmntent(mount_table, &entry)))
545 #else               
546         while (entry = getmntent(mount_table))
547 #endif
548 #if !defined(__osf__) && !defined(CSRG_BASED)
549         {
550 #endif
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":"");
560 #endif                  
561                         _tt_global->fileSystemEntries->append(fse);
562                 }
563         }
564
565         ttCloseMntTbl(mount_table);
566 }
567
568 void _Tt_file_system::
569 flush ()
570 {
571         if (!_tt_global->fileSystemEntries.is_null()) {
572                 _tt_global->fileSystemEntries->flush();
573         }
574
575         lastMountTime = 0;
576 }
577 /* Local Variables : */
578 /* c++-indent-level: 2 */
579 /* End: */