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 libraries 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_path.C /main/9 1999/10/14 18:42:31 mgreess $
28 /* @(#)tt_path.C 1.26 93/07/30
29 * Tool Talk Utility - tt_path.cc
31 * Copyright (c) 1990, 1993 by Sun Microsystems, Inc.
33 * Implementation for filepath utility functions
36 #include <sys/types.h>
41 #include "util/tt_assert.h"
42 #include "util/tt_string.h"
43 #include "util/tt_file_system_entry.h"
44 #include "util/tt_file_system.h"
45 #include "util/tt_host.h"
46 #include "util/tt_global_env.h"
47 #include "util/tt_host_equiv.h"
49 /* Included after "util/tt_string.h" to avoid index/strchr conflicts. */
50 #define X_INCLUDE_DIRENT_H
51 #define XOS_USE_NO_LOCKING
52 #if defined(linux) || defined(CSRG_BASED)
56 #include <X11/Xos_r.h>
57 #if defined(linux) || defined(CSRG_BASED)
62 #if defined(OPT_BUG_USL)
63 #define S_ISLNK(mode) ((mode & 0xF000) == S_IFLNK)
66 // Not everybody has realpath() in libc, sometimes we have to define
67 // it ourselves, see realpath*.c in tt/lib
69 #if !defined(OPT_HAS_REALPATH)
70 extern "C" { char *_tt_internal_realpath(char*, char*); }
73 // Use the system realpath on OS's that have it, otherwise
74 // use the ToolTalk implementation of it.
76 _tt_get_realpath(char *pathname, char *finalpath)
78 #ifdef OPT_HAS_REALPATH
79 return realpath(pathname, finalpath);
81 return _tt_internal_realpath(pathname, finalpath);
86 * _Tt_dirname - given a path name, returns the char index to the end of
87 * the path's longest prefix (directory), i.e., excluding the basename and the
88 * last '/'. e.g., given "/home3/dynamo/tan/text", returns 16
89 * (/home3/dynamo/tan^).
92 int _Tt_dirname(const char *path, int len)
94 int path_len = len ? len : strlen(path);
95 while (path[path_len] != '/') { /* discard base name */
96 ASSERT(path_len >= 0, "Invalid path");
99 return (path_len - 1); /* discard the suffix '/' */
103 * _Tt_basename - given a path name, returns the char index to the beginning of
104 * the path's suffix, e.g., given "/home3/dynamo/tan/text", returns 18
105 * (/home3/dynamo/tan/^).
108 int _Tt_basename(const char *path, int len)
110 return (_Tt_dirname(path, len) + 2);
114 * _tt_dir_entries() - Return a new list of paths, with one entry for each
115 * entry in the directory <path>, each entry consisting of
116 * <path> appended by a slash and the name of the entry.
117 * Returns an empty list if <path> is not a directory.
118 * If !follow_symlinks, returns an empty list if <path> is a symlink.
121 _tt_dir_entries(const _Tt_string &path, bool_t follow_symlinks )
124 _Tt_string_list_ptr entries(new _Tt_string_list);
126 if (! follow_symlinks) {
127 struct stat lstat_buf;
130 lstat_status = lstat( (char *)path, &lstat_buf );
131 if (( lstat_status == 0) && S_ISLNK(lstat_buf.st_mode)) {
135 dirp = opendir( (char *)path );
142 _Xreaddirparams dir_buf;
144 memset((char*) &dir_buf, 0, sizeof(_Xreaddirparams));
146 struct dirent *entry;
148 entry = _XReaddir( dirp, dir_buf );
152 ename = entry->d_name;
153 if ((ename == ".") || (ename == "..")) {
156 epath = (char *)path;
157 epath = epath.cat("/").cat( ename );
158 entries->push( epath );
160 int closedir_err = closedir( dirp );
161 ASSERT(closedir_err == 0, "Could not close directory");
164 } /* dir_entries() */
167 * Returns the real path (resolves symbolic links, etc) of the specified path,
168 * even if the file in the specified path does not exist.
171 _tt_realpath(const _Tt_string &path)
173 _Tt_string temp_path = path;
179 if (temp_path[0] != '/') {
180 // A relative path, make it absolute.
181 char wd[MAXPATHLEN+1];
182 if (getcwd(wd, sizeof(wd))) {
183 temp_path = _Tt_string(wd).cat("/").cat(path);
187 _Tt_string right, left, dir, base;
190 _Tt_string temp_real_path(MAXPATHLEN);
191 char *p = _tt_get_realpath((char *)temp_path, (char *)temp_real_path);
193 while ((p == 0) && (left.len() > 0)) {
194 // Realpath failed; drop right components until it works.
195 base = left.rsplit('/', dir);
197 // Takes care of special case of "/file" where
198 // file does not exist.
199 if ((dir.len() <= 0) && (left[0]=='/')) {
204 if (right.len() > 0) {
205 right = base.cat("/").cat(right);
209 p = _tt_get_realpath((char *)left, (char *)temp_real_path);
212 _Tt_string real_path;
214 // Only "/" matches a real path...
216 // Use the original path
217 real_path = temp_path;
219 // Else parts of the path don't really exist...
220 else if (right.len() > 0) {
221 // Append the fake stuff on
222 real_path = (char *)temp_real_path;
224 if (real_path [real_path.len()-1] != '/') {
225 real_path = real_path.cat("/").cat(right);
228 real_path = real_path.cat(right);
231 // Else the entire path exists, now we have the "real" one...
233 real_path = (char *)temp_real_path;
240 _tt_isdir(const _Tt_string &path)
242 if (path.len() == 0) {
245 struct stat stat_buf;
246 if (stat((char *)path, &stat_buf) != 0) {
249 return S_ISDIR(stat_buf.st_mode);
253 * Returns the the best guess of the absolute network path of the specified
254 * path without using the TT DB Server. This is accomplished by using
255 * _tt_realpath on the specified path and then by finding best mount
256 * table entry match to the path and exchanging the local partition path
257 * with the mounted partition path.
259 _Tt_string _tt_local_network_path(const _Tt_string &path)
261 _Tt_string network_path;
264 _Tt_string real_path = _tt_realpath(path);
266 printf("DEBUG _tt_local_network_path: real_path initialized to %s\n",
269 _Tt_file_system file_system;
270 _Tt_file_system_entry_ptr entry =
271 file_system.bestMatchToPath(real_path);
273 _Tt_string hostname = entry->getHostname();
275 printf("DEBUG _tt_local_network_path: hostname = %s\n",
278 _Tt_string loop_back_mount_point =
279 entry->getLoopBackMountPoint();
281 printf("DEBUG _tt_local_network_path: loop_back_mount_point = %s\n",
282 (char *) loop_back_mount_point == NULL ? "(null)" : (char *) loop_back_mount_point);
284 _Tt_string mount_point;
285 if (loop_back_mount_point.len() > 0) {
286 mount_point = loop_back_mount_point;
288 printf("DEBUG _tt_local_network_path: ! isLocal 1: mount_point = %s\n",
289 (char *) mount_point);
292 mount_point = entry->getMountPoint();
294 printf("DEBUG _tt_local_network_path: ! isLocal 2: mount_point = %s\n",
295 (char *) mount_point);
299 if (entry->isLocal()) {
300 if (loop_back_mount_point.len() > 0) {
302 printf("DEBUG _tt_local_network_path: isLocal 2: mount_point = %s\n",
303 (char *) mount_point);
305 // Get the path info after the loop back
307 real_path = real_path.right(real_path.len() -
310 printf("DEBUG _tt_local_network_path: isLocal 2: real_path = %s\n",
313 // Replace the loop back mount point path
314 // with the mount point path.
315 if (mount_point != "/") {
316 real_path = mount_point.cat(real_path);
319 printf("DEBUG _tt_local_network_path: isLocal 3: real_path = %s\n",
324 _Tt_string partition = entry->getPartition();
326 printf("DEBUG _tt_local_network_path: ! isLocal: partition = %s\n",
329 // Get the path info after the mount point path
331 real_path.right(real_path.len()-mount_point.len());
333 printf("DEBUG _tt_local_network_path: ! isLocal: real_path = %s\n",
336 // Replace the mount point path with the exported
338 real_path = partition.cat(real_path);
340 printf("DEBUG _tt_local_network_path: ! isLocal: real_path = %s\n",
344 network_path = hostname.cat(":").cat(real_path);
346 printf("DEBUG _tt_local_network_path: network_path = %s\n",
347 (char *) network_path);
355 /* Converts a path from the network form to a local form:
365 * If the path cannot be mapped out through the local mount tables,
366 * it converted to the form:
371 _tt_network_path_to_local_path(const _Tt_string &network_path)
373 // We initialize _tt_global here if necessary. When this call is exposed,
374 // we don\'t want to require that tt_open be called first.
377 _tt_global = new _Tt_global;
380 _Tt_string local_path;
382 if (!network_path.len()) {
388 _Tt_host_ptr localtthost;
391 path = path.split(':', hostname);
393 if (!_tt_global->get_local_host(localtthost)) {
394 // If we don\'t even know who we are, we must not be networked
395 // (I have no evidence this ever happens...)
398 _Tt_host_equiv_ptr eq_p = new _Tt_host_equiv;
400 if (eq_p->hostname_equiv(localtthost->name(), hostname) == 1) {
401 // If we own the file, we can just use this path
404 _Tt_file_system file_system;
405 _Tt_file_system_entry_ptr entry;
406 entry = file_system.findMountEntry(network_path);
407 if (entry.is_null()) {
409 char * tmp_path = getenv("DTMOUNTPOINT");
411 // Can\'t find a usable mount. In desperation,
412 // try to invoke the automounter. If the
413 // DTMOUNTPOINT env. variable exists, use
414 // it as the root of the path, otherwise /net.
416 if (tmp_path == (char *)0) {
417 local_path = "/net/";
419 local_path = tmp_path;
421 // Be user friendly; ensure there
422 // is a trailing slash...
423 if (strcmp((char *) local_path.right(1), "/") != 0) {
424 local_path = local_path.cat('/');
427 // Ensure we don't use qualified hostname.
428 hostname = eq_p->prefix_host(hostname,
429 localtthost->name());
431 local_path = local_path.cat(hostname).cat(path);
433 _Tt_string mount_point = entry->getMountPoint();
434 _Tt_string partition = entry->getPartition();
436 // Get the path info after the partition path
437 if (strcmp((char *) partition, "/") != 0) {
438 path = path.right(path.len()-partition.len());
441 // Replace the partition path with the mount point path
442 local_path = mount_point.cat(path);
447 path = _tt_realpath(local_path);
449 #ifdef OPT_AUTOMOUNT_PATH_FIX
451 // Extract the automount point which is introduced by a
452 // call to realpath() when an NFS automounter is used:
453 // /DTAUTOMOUNTPOINT/DTMOUNTPOINT/host/path
456 // /DTMOUNTPOINT/host/path
459 // Fetch automount prefix
460 _Tt_string automnt_prefix = getenv("DTAUTOMOUNTPOINT");
461 if (!automnt_prefix.len()) {
463 automnt_prefix = "/tmp_mnt/";
466 // fix up users prefix. Providing an ending slash
467 // delineates the directory element.
468 if (strcmp((char *) automnt_prefix.right(1), "/") != 0) {
469 automnt_prefix = automnt_prefix.cat('/');
473 // Pull out automount prefix from start of path
474 int index = path.index(automnt_prefix);
476 // the path starts with the prefix, so rip it out
477 // minus the one trailing prefix slash.
478 path = path.right(path.len() - (automnt_prefix.len() - 1));
480 #endif /* OPT_AUTOMOUNT_PATH_FIX */
486 bool_t _tt_is_network_path (const _Tt_string &path)
488 int slash_index = path.index('/');
489 if (slash_index > -1) {
490 int colon_index = path.index(':');
491 if ((colon_index > 0) && (slash_index == colon_index+1)) {
500 // This function looks for the specified file in the user, system and network
501 // database directories. It returns the path of the existing file with the
502 // highest precedence (user > system > network). If the environement variable
503 // specified by "user_env" contains the path pf a file that exists, it is
504 // the highest precedence. If the TTPATH environment variable is specified
505 // the directories in it are used to look for the file before the standard
506 // user/system/network directories are looked at. If "system_only" is TRUE,
507 // then only the system path is obtained (user and network are ignored). If
508 // the returned path is a NULL string, then no file was found.
510 _Tt_string _tt_user_path (_Tt_string file,
515 struct stat stat_buf;
517 // If the user evnironment variable is set, that takes priority
518 if (user_env.len()) {
519 path = getenv(user_env);
521 if (!stat((char *)path, &stat_buf)) {
529 // Only do more of a file was specified...
531 _Tt_string tt_path = getenv("TTPATH");
532 _Tt_string user_path = (char *)0;
533 _Tt_string system_path = (char *)0;
534 _Tt_string network_path = (char *)0;
536 // Parse the user:system:network from path variable
537 int n = tt_path.index(':');
540 system_path = (char *)0;
541 network_path = (char *)0;
544 user_path = tt_path.left(n);
545 tt_path = tt_path.right(tt_path.len() - n - 1);
547 n = tt_path.index(':');
549 system_path = tt_path;
550 network_path = (char *)0;
553 system_path = tt_path.left(n);
554 tt_path = tt_path.right(tt_path.len() - n - 1);
556 n = tt_path.index(':');
558 network_path = (char *)0;
561 network_path = tt_path;
566 // If the paths are not directories, strip off the file at the
568 if (user_path.len() && !_tt_isdir(user_path)) {
569 n = user_path.rindex('/');
570 user_path = user_path.left(n);
572 if (system_path.len() && !_tt_isdir(system_path)) {
573 n = system_path.rindex('/');
574 system_path = system_path.left(n);
576 if (network_path.len() && !_tt_isdir(network_path)) {
577 n = network_path.rindex('/');
578 network_path = network_path.left(n);
581 // Get the user file...
583 if (user_path.len()) {
584 path = user_path.cat("/").cat(file);
585 if (!stat((char *)path, &stat_buf)) {
590 path = getenv("HOME");
591 path = path.cat("/.tt/").cat(file);
592 if (!stat((char *)path, &stat_buf)) {
597 // Get the system file...
598 if (system_path.len()) {
599 path = system_path.cat("/").cat(file);
600 if (!stat((char *)path, &stat_buf)) {
606 path = path.cat(file);
607 if (!stat((char *)path, &stat_buf)) {
611 // Get the network file...
613 if (network_path.len()) {
614 path = network_path.cat("/").cat(file);
615 if (!stat((char *)path, &stat_buf)) {
620 path = getenv("OPENWINHOME");
622 path = path.cat("/etc/tt/").cat(file);
623 if (!stat((char *)path, &stat_buf)) {