074d2a5bb87fe5d68d525344a4fecb1bbc9f47cb
[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 # ifdef __osf__
89         extern "C" int getfsstat(struct statfs *, long, int);
90 # endif
91 #       define MNTTYPE_NFS              "nfs"
92 #       define ttOpenMntTbl(path,mode)  ((FILE *) 1)
93 #       define TtMntEntry               struct statfs *
94 # ifdef __osf__
95 #       define ttFsType(e)              \
96                                 (((e)->f_type == MOUNT_UFS) ? "ufs" \
97                                 : (((e)->f_type == MOUNT_NFS3) ? "nfs" \
98                                 : (((e)->f_type == MOUNT_NFS) ? "nfs" \
99                                  : (((e)->f_type == MOUNT_CDFS) ? "cdfs" \
100                                   : (((e)->f_type == MOUNT_PROCFS) ? "procfs" \
101                                    : "unknown")))))
102 # elif defined(CSRG_BASED)
103 #       define ttFsType(e)              (e->f_fstypename)
104 # endif
105 #       define ttFsName(e)              ((char *)((e)->f_mntfromname))
106 #       define ttMountPt(e)             ((char *)((e)->f_mntonname))
107 #       define ttCloseMntTbl(f)         free(buf)
108 #else
109 #       include <mntent.h>
110 #       define TtMntTab                 MOUNTED
111 #       define MNTTYPE_RFS              "rfs"
112 #       define TtMntEntry               struct mntent *
113 #       define ttOpenMntTbl(path,mode)  setmntent(path,mode)
114 #       define ttFsType(e)              (e)->mnt_type
115 #       define ttFsName(e)              (e)->mnt_fsname
116 #       define ttMountPt(e)             (e)->mnt_dir
117 #       define ttCloseMntTbl(f)         endmntent(f)
118 #endif
119 #include "util/tt_file_system_entry_utils.h"
120 #include "util/tt_file_system.h"
121 #include "util/tt_file_system_entry.h"
122 #include "util/tt_path.h"
123 #include "util/tt_port.h"
124 #include "util/tt_host.h"
125 #include "util/tt_global_env.h"
126
127 #if defined(OPT_BUG_SUNOS_5)
128 // Bug 1116904 filed on the absence of hasmntopt from the
129 // header file.  Fixed in SunOS 5.3, but we leave this in so 
130 // we can compile on 5.1 and 5.2.
131 extern "C" {
132         extern char *hasmntopt(struct mnttab *mnt, char *opt);
133 };
134 #endif
135
136 time_t                          _Tt_file_system::lastMountTime          = 0;
137
138 _Tt_file_system::
139 _Tt_file_system ()
140 {
141         // It would be simpler just to have a static instance of 
142         // _Tt_file_system_entry_list here, but static class instances
143         // are verboten if we want to be called by C programs.
144         if (_tt_global->fileSystemEntries.is_null()) {
145                 _tt_global->fileSystemEntries = new _Tt_file_system_entry_list;
146                 lastMountTime = 0;
147         }
148 }
149
150 _Tt_file_system::
151 ~_Tt_file_system ()
152 {
153         lastMountTime = 0;
154 }
155
156 static _Tt_file_system_entry *
157 createFileSystemEntry(TtMntEntry entry)
158 {
159         _Tt_string hostname;
160         _Tt_string mount_point;
161         _Tt_string partition;
162         int        local_flag = 1;
163         int        loop_back_flag = 0;
164         //
165         // not all platforms have the IGNORE option, but if it
166         // is defined, be sure to ignore mount entries with it
167         // set, as they are things like automounter entries
168         // that will just confuse the mapping.
169         //
170 #if defined(MNTOPT_IGNORE)
171         if (0!=hasmntopt(&entry, MNTOPT_IGNORE)) {
172                 return (_Tt_file_system_entry *)0;
173         }
174 #endif
175         if (   (strcmp( ttFsType(entry), MNTTYPE_NFS) == 0)
176 #if defined(MNTTYPE_RFS)
177             || (strcmp( ttFsType(entry), MNTTYPE_RFS) == 0)
178 #endif
179            )
180         {
181 #if defined(_AIX)
182                 // AIX is different; at least it\'s arguably better.
183                 hostname = vmt2dataptr(entry,VMT_HOSTNAME);
184                 partition = ttFsName(entry);
185 #else /* AIX */
186         
187                 // Search for a '.' to separate the hostname and
188                 // the domain name
189                 char *endOfHostNamePos =
190                         strchr(ttFsName(entry), '.');
191
192                 // Search for the ':' that separates the
193                 // hostname and the rest of the mtab field.
194
195                 char *justBeforePartitionPos =
196                         strchr(ttFsName(entry), ':');
197
198                 // If there was no domain name or the dot
199                 // found above was after the ':' (the dot was
200                 // just part of a directoty name), then the
201                 // hostname ends at the ':' position.
202
203                 if (!endOfHostNamePos ||
204                     (justBeforePartitionPos < endOfHostNamePos)) {
205                         endOfHostNamePos = justBeforePartitionPos;
206                 }
207
208                 // NULL terminate the hostname part of the field
209                 if (endOfHostNamePos) {
210                         *endOfHostNamePos = '\0';
211                 }
212
213                 if (justBeforePartitionPos) {
214                         partition = justBeforePartitionPos+1;
215                 }
216
217                 hostname = ttFsName(entry);
218 #endif  /* AIX */       
219                 local_flag = FALSE;
220                 loop_back_flag = FALSE;
221         } else {
222                 partition = ttFsName(entry);
223                 _Tt_host_ptr localHost;
224                 _tt_global->get_local_host( localHost );
225                 hostname = localHost->name();
226                 local_flag = TRUE;
227                 loop_back_flag = FALSE;
228
229 #if defined(MNTTYPE_LOFS)
230                 if (!strcmp( ttFsType(entry), MNTTYPE_LOFS)) {
231                         loop_back_flag = TRUE;
232                 }
233 #endif
234         }
235         mount_point = ttMountPt(entry);
236
237         return new _Tt_file_system_entry( hostname, mount_point, partition,
238                                           local_flag, loop_back_flag );
239 }
240
241
242 /*
243  * Finds the best match mount table entry to the specified local path
244  * resolving loop back mounts to the true mount point.
245  */
246 _Tt_file_system_entry_ptr _Tt_file_system::
247 bestMatchToPath (const _Tt_string &path)
248 {
249         _Tt_string real_path = _tt_realpath(path);
250
251         updateFileSystemEntries();
252
253         _Tt_file_system_entry_ptr max_match_entry;
254         bool_t              loop_back_flag = TRUE;
255         _Tt_string          current_loop_back_mount_point;
256         _Tt_string          first_loop_back_mount_point;
257         bool_t              first_time = TRUE;
258
259         while (loop_back_flag) {
260                 max_match_entry = findBestMountPoint(real_path,
261                                                   loop_back_flag,
262                                                   current_loop_back_mount_point);
263
264                 if (loop_back_flag && first_time) {
265                         first_loop_back_mount_point =
266                                 current_loop_back_mount_point;
267                 }
268
269                 first_time = FALSE;
270         }
271
272         max_match_entry->loopBackMountPoint = first_loop_back_mount_point;
273         return max_match_entry;
274 }
275
276 /*
277  * Finds the best matching mount pount to the specified local path.
278  * If the best match is a loop back then the matching portion of the
279  * specified path is updated to the loop back partition and the loop
280  * back flag parameter is set to TRUE.
281  */
282 _Tt_file_system_entry_ptr _Tt_file_system::
283 findBestMountPoint (_Tt_string &path,
284                     bool_t     &loop_back_flag,
285                     _Tt_string &loop_back_mount_point)
286 {
287         updateFileSystemEntries();
288
289         _Tt_string                current_mount_point;
290         int                       current_mount_point_length;
291         _Tt_file_system_entry_ptr max_match_entry;
292         int                       max_match_length = 0;
293         int                       path_length = path.len();
294
295         _Tt_file_system_entry_list_cursor
296                 entries_cursor(_tt_global->fileSystemEntries);
297
298         while (entries_cursor.next()) {
299                 current_mount_point = entries_cursor->getMountPoint();
300                 current_mount_point_length = current_mount_point.len();
301                 if (path_length < current_mount_point_length) {
302                         continue;
303                 }
304
305                 if (current_mount_point_length > max_match_length) {
306                         if (!memcmp((char *)current_mount_point,
307                                     (char *)path,
308                                     current_mount_point_length)) {
309                                 max_match_length = current_mount_point_length;
310                                 max_match_entry = *entries_cursor;
311                         }  
312                 }
313
314                 if (max_match_length == path_length) {
315                         break;
316                 }
317         }
318
319         if (max_match_entry->isLoopBack ()) {
320                 loop_back_flag = TRUE;
321
322                 _Tt_string mount_point = max_match_entry->getMountPoint();
323                 _Tt_string partition = max_match_entry->getPartition();
324
325                 // Get the path info after the mount point path
326                 path = path.right(path.len()-mount_point.len());
327
328                 // Prepend the loop back partition onto the rest of the path
329                 path = partition.cat(path);
330
331                 // Return the loop back mount point
332                 loop_back_mount_point = mount_point;
333         } else {
334                 loop_back_flag = FALSE;
335         }
336
337         return max_match_entry;
338 }
339
340 /*
341  * Finds the mount table entry corresponding to the specified network path.
342  * The specified path must be of the form:
343  *
344  *              hostname:/path
345  */
346 _Tt_file_system_entry_ptr _Tt_file_system::
347 findMountEntry (const _Tt_string &network_path)
348 {
349         updateFileSystemEntries();
350
351         _Tt_string                      current_hostname;
352         _Tt_string                      current_partition;
353         int                             current_partition_length;
354         _Tt_file_system_entry_ptr       entry;
355
356         _Tt_string hostname;
357         _Tt_string path;
358
359         path = network_path;
360         path = path.split(':', hostname);
361
362         int path_length = path.len();
363
364         _Tt_file_system_entry_list_cursor
365                 entries_cursor(_tt_global->fileSystemEntries);
366
367         _Tt_host_equiv_ptr eq_p = new _Tt_host_equiv();
368         while (entries_cursor.next()) {
369                 current_hostname = entries_cursor->getHostname();
370
371 #ifdef notdef
372 printf("DEBUG findMountEntry: hostname = %s, current_hostname = %s\n",
373         (char *) hostname, (char *) current_hostname);
374 #endif
375
376                 if (eq_p->hostname_equiv(hostname, current_hostname) == 1) {
377                         current_partition = entries_cursor->getPartition();
378                         current_partition_length = current_partition.len();
379
380 #ifdef notdef
381 printf("DEBUG findMountEntry: found hostname equivalence between %s and %s\n",
382         (char *) hostname, (char *) current_hostname);
383 #endif
384
385                         if (path_length >= current_partition_length) {
386                                 if (!memcmp((char *)path, (char *)current_partition,
387                                             current_partition_length)) {
388                                         entry = *entries_cursor;
389 #ifdef notdef
390 printf("DEBUG findMountEntry: found PATH equivalence between %s and %s\n",
391         (char *) hostname, (char *) current_hostname);
392 #endif
393
394                                         break;
395                                 }
396                         }
397                 }
398         }
399         return entry;
400 }
401
402 void _Tt_file_system::
403 updateFileSystemEntries ()
404 {
405         static int firsttime = 1;
406         static int since_last = 0;
407
408         if (!firsttime) {
409                 if (since_last < _tt_global->event_counter) {
410                         since_last = _tt_global->event_counter;
411                 } else {
412                         return;
413                 }
414         }
415
416 // AIX  doesn\'t have a mount table file as such.
417 #ifdef TtMntTab
418
419         struct stat mount_table_stat;
420         if (stat(TtMntTab, &mount_table_stat)) {
421                 return;
422         }
423
424         if (!firsttime && mount_table_stat.st_mtime <= lastMountTime) {
425                 return;
426         }
427
428         firsttime = 0;
429         
430         // XXX Due to bug #1126575 - MNTTAB temporarily goes to
431         //     size 0 during automounter updates.  The file stats
432         //     OK, but has no data in it.
433         pollfd poll_fd;
434         while (mount_table_stat.st_size == 0) {
435                 (void)poll (&poll_fd, 0, 100);
436                 // Must use lstat here; mtab is often a symlink
437                 if (lstat(TtMntTab, &mount_table_stat)) {
438                         return;
439                 }
440         }
441
442         FILE *mount_table = ttOpenMntTbl(TtMntTab, "r");
443
444         if (! mount_table) {
445                 return;
446         }
447         fcntl(fileno(mount_table), F_SETFD, 1);         // Close on exec.
448
449         lastMountTime = mount_table_stat.st_mtime;
450 #endif
451
452         _tt_global->fileSystemEntries->flush();
453         _Tt_file_system_entry_ptr fse;  
454         TtMntEntry entry;
455 #if defined(_AIX)
456         int     rc, sz = BUFSIZ;
457         char    *tmpbuf = (char *)malloc( sz );
458
459         while ((rc = mntctl(MCTL_QUERY, sz, tmpbuf)) == 0)
460         {
461                 // increase buffer size
462                 sz = *((int *) tmpbuf);
463                 free( tmpbuf );
464                 tmpbuf = (char *)malloc( sz );
465         }
466
467         for (entry = (TtMntEntry)tmpbuf; rc > 0; --rc,
468              entry = (TtMntEntry)((char *) entry + entry->vmt_length))
469 #elif defined(__osf__) || defined(CSRG_BASED)
470         int             numfs,i;
471         struct statfs   *buf;
472         long            bufsize;
473         int             flags = MNT_NOWAIT;
474         char            *s, *host, path[MNAMELEN] ;
475  
476         numfs = getfsstat ( (struct statfs *)0, 0, 0 );
477
478         bufsize = numfs * sizeof ( struct statfs );
479         buf = (struct statfs *) malloc ( bufsize );
480         memset ((void *)buf,0,bufsize);
481
482         getfsstat ( buf, bufsize, flags );
483
484         for ( i=0; i<numfs; i++ )
485         {
486             // convert path@host to host:/path
487             s = strchr(buf[i].f_mntfromname,'@');
488             if (s != NULL) {
489                 host = s + 1 ;
490                  memset((char*)path,0,MNAMELEN);
491                 strncpy(path,buf[i].f_mntfromname, (strlen(buf[i].f_mntfromname)
492  - strlen(s))) ;
493                 strcpy(buf[i].f_mntfromname,host) ;
494                 strcat(buf[i].f_mntfromname,":") ;
495                 strcat(buf[i].f_mntfromname,path) ;
496             }
497             entry = &buf[i];
498
499 #elif defined(OPT_SVR4_GETMNTENT)
500         int rc;     
501         while (! (rc = getmntent(mount_table, &entry)))
502 #else               
503         while (entry = getmntent(mount_table))
504 #endif
505 #if !defined(__osf__) && !defined(CSRG_BASED)
506         {
507 #endif
508                 fse =  createFileSystemEntry( entry );
509                 if (!fse.is_null()) {
510 #if defined(TT_DEBUG_FNM)
511 fprintf(stderr,"File name mapping: %s:%s on %s; %s %s\n",
512         (char *)fse->getHostname(),
513         (char *)fse->getPartition(),
514         (char *)fse->getMountPoint(),
515         fse->isLocal()?"local":"",
516         fse->isLoopBack()?"loopback":"");
517 #endif                  
518                         _tt_global->fileSystemEntries->append(fse);
519                 }
520         }
521
522         ttCloseMntTbl(mount_table);
523 }
524
525 void _Tt_file_system::
526 flush ()
527 {
528         if (!_tt_global->fileSystemEntries.is_null()) {
529                 _tt_global->fileSystemEntries->flush();
530         }
531
532         lastMountTime = 0;
533 }
534 /* Local Variables : */
535 /* c++-indent-level: 2 */
536 /* End: */