pathName.C

Go to the documentation of this file.
00001 /*
00002  * See the dyninst/COPYRIGHT file for copyright information.
00003  * 
00004  * We provide the Paradyn Tools (below described as "Paradyn")
00005  * on an AS IS basis, and do not warrant its validity or performance.
00006  * We reserve the right to update, modify, or discontinue this
00007  * software at any time.  We shall have no obligation to supply such
00008  * updates or modifications or any other form of support to you.
00009  * 
00010  * By your use of Paradyn, you understand and agree that we (or any
00011  * other person or entity with proprietary rights in Paradyn) are
00012  * under no obligation to provide either maintenance services,
00013  * update services, notices of latent defects, or correction of
00014  * defects for Paradyn.
00015  * 
00016  * This library is free software; you can redistribute it and/or
00017  * modify it under the terms of the GNU Lesser General Public
00018  * License as published by the Free Software Foundation; either
00019  * version 2.1 of the License, or (at your option) any later version.
00020  * 
00021  * This library is distributed in the hope that it will be useful,
00022  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00023  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00024  * Lesser General Public License for more details.
00025  * 
00026  * You should have received a copy of the GNU Lesser General Public
00027  * License along with this library; if not, write to the Free Software
00028  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
00029  */
00030 
00031 // pathName.C
00032 #include "common/h/headers.h"  // P_strrchr()
00033 #include <ctype.h>
00034 #include <assert.h>
00035 #include <limits.h>
00036 #include "common/h/pathName.h"
00037 
00038 #if defined(os_windows) //ccw 20 july 2000 : 29 mar 2001
00039 
00040 #define S_ISDIR(x) ((x) & _S_IFDIR)
00041 
00042 std::string expand_tilde_pathname(const std::string &dir) {
00043    return dir;
00044 }
00045 
00046 #else
00047 
00048 #include <sys/types.h>
00049 #include <sys/stat.h>
00050 #include <unistd.h>
00051 
00052 #include <pwd.h>
00053 
00054 std::string expand_tilde_pathname(const std::string &dir) {
00055    // e.g. convert "~tamches/hello" to "/u/t/a/tamches/hello",
00056    // or convert "~/hello" to same.
00057    // In the spirit of Tcl_TildeSubst
00058    if (dir.length()==0)
00059       return dir;
00060 
00061    const char *dir_cstr = dir.c_str();
00062    if (dir_cstr[0] != '~')
00063       return dir;
00064 
00065    // Now, there are two possibilities: a tilde by itself (e.g. ~/x/y or ~), or
00066    // a tilde followed by a username.
00067    if (dir_cstr[1] == '/' || dir_cstr[1] == '\0') {
00068       // It's the first case.  We need to find the environment vrble HOME and use it.
00069       // It it doesn't exist (but it always does, I think) then I don't know what
00070       // to do.
00071       char *home_dir = getenv("HOME");
00072       if (home_dir == NULL)
00073          return dir; // yikes
00074 
00075       if (home_dir[strlen(home_dir)-1] == '/' && dir_cstr[1] != '\0')
00076          return std::string(home_dir) + &dir_cstr[2];
00077       else
00078          return std::string(home_dir) + &dir_cstr[1];
00079    }
00080 
00081    // It's the second case.  We need to find the username.  It starts at
00082    // dir_cstr[1] and ends at (but not including) the first '/' or '\0'.
00083    std::string userName;
00084 
00085    const char *ptr = strchr(&dir_cstr[1], '/');
00086    if (ptr == NULL)
00087       userName = std::string(&dir_cstr[1]);
00088    else {
00089       char user_name_buffer[200];
00090       unsigned user_name_len = ptr - &dir_cstr[1];
00091 
00092       for (unsigned j=0; j < user_name_len; j++)
00093      user_name_buffer[j] = dir_cstr[1+j];
00094 
00095       user_name_buffer[user_name_len] = '\0';
00096       userName = user_name_buffer;
00097    }
00098 
00099    struct passwd *pwPtr = getpwnam(userName.c_str());
00100    if (pwPtr == NULL) {
00101       endpwent();
00102       return dir; // something better needed...
00103    }
00104 
00105    std::string result = std::string(pwPtr->pw_dir) + std::string(ptr);
00106    endpwent();
00107    return result;
00108 }
00109 #endif
00110 
00111 static std::string concat_pathname_components_simple(const std::string &comp1, const std::string &comp2)
00112 {
00113    std::string result = (comp1.length() ? comp1 : comp2);
00114    return result;
00115 }
00116 
00117 std::string concat_pathname_components(const std::string &comp1, const std::string &comp2)
00118 {
00119    if (comp1.length() == 0 || comp2.length() == 0)
00120       return concat_pathname_components_simple(comp1, comp2);
00121 
00122    bool needToAddSlash = true; // so far
00123 
00124    // if comp1 ends in a "/" then no need to add slash
00125    const char *temp = comp1.c_str();
00126    if (temp[comp1.length()-1] == '/')
00127       needToAddSlash = false;
00128 
00129    // if comp2 begins with a "/" then no need to add slash
00130    if (comp2.length() && comp2[0] == '/')
00131        needToAddSlash = false;
00132 #if 0
00133    if (comp2.prefixed_by("/"))
00134       needToAddSlash = false;
00135 #endif
00136 
00137    std::string result = comp1;
00138    if (needToAddSlash)
00139       result += "/";
00140    result += comp2;
00141 
00142    return result;
00143 }
00144 
00145 bool extractNextPathElem(const char * &ptr, std::string &result)
00146 {
00147    // assumes that "ptr" points to the value of the PATH environment
00148    // variable.  Extracts the next element (writing to result, updating
00149    // ptr, returning true) if available else returns false;
00150 
00151    if ( ptr == NULL )
00152       return false;
00153 
00154    while (isspace(*ptr))
00155       ptr++;
00156 
00157    if (*ptr == '\0')
00158       return false;
00159    
00160    // collect from "ptr" upto but not including the next ":" or end-of-string
00161    const char *start_ptr = ptr;
00162 
00163    while (*ptr != ':' && *ptr != '\0')
00164       ptr++;
00165 
00166    unsigned len = ptr - start_ptr;
00167 
00168    result = std::string(start_ptr, len);
00169 
00170    // ptr now points at a ":" or end-of-string
00171    assert(*ptr == ':' || *ptr == '\0');
00172    if (*ptr == ':')
00173       ptr++;
00174 
00175 //   cerr << "extractNextPathElem returning " << result << endl;
00176 
00177    return true;
00178 }
00179 
00180 bool exists_executable(const std::string &fullpathname)
00181 {
00182    struct stat stat_buffer;
00183    int result = stat(fullpathname.c_str(), &stat_buffer);
00184 
00185    if (result == -1)
00186       return false;
00187 
00188    if (S_ISDIR(stat_buffer.st_mode))
00189       return false; // that was a directory, not an executable
00190 
00191    // more checks needed to be sure this is an executable file...
00192 
00193    return true;
00194 }
00195 
00196 bool executableFromArgv0AndPathAndCwd(std::string &result,
00197       const std::string &i_argv0,
00198       const std::string &path,
00199       const std::string &cwd) 
00200 {
00201    // return true iff successful.
00202    // if successful, writes to result.
00203    // "path" is the value of the PATH env var
00204    // "cwd" is the current working directory, presumably from the PWD env var
00205 
00206    // 0) if argv0 empty then forget it
00207    if (i_argv0.length() == 0)
00208       return false;
00209 
00210    const std::string &argv0 = expand_tilde_pathname(i_argv0);
00211 
00212    // 1) If argv0 starts with a slash then we sink or swim with argv0
00213 
00214    if ((argv0.c_str())[0] == '/') 
00215    {
00216       if (exists_executable(argv0)) 
00217       {
00218          result = argv0;
00219          return true;
00220       }
00221    }
00222 
00223    // 2) search the path, trying (dir + argv0) for each path component.
00224    //    But only search the path if argv0 doesn't contain any slashes.
00225    //    Why?  Because if it does contain a slash than at least one
00226    //    directory component prefixes the executable name, and the path
00227    //    is only supposed to be searched when an executable name is specifed
00228    //    alone.
00229 
00230    bool contains_slash = false;
00231    const char *ptr = argv0.c_str();
00232 
00233    while (*ptr != '\0')
00234    {
00235       if (*ptr++ == '/') 
00236       {
00237          contains_slash = true;
00238          break;
00239       }
00240    }
00241 
00242    if (!contains_slash) 
00243    {
00244       // search the path to see what directory argv0 came from.  If found, then
00245       // use dir + argv0 else use argv0.
00246       ptr = path.c_str();
00247       std::string pathelem;
00248 
00249       while (extractNextPathElem(ptr, pathelem)) 
00250       {
00251          std::string trystr = concat_pathname_components(pathelem, argv0);
00252 
00253          if (exists_executable(trystr)) 
00254          {
00255             result = trystr;
00256             return true;
00257          }
00258       }
00259    }
00260 
00261    // well, if we've gotten this far without success: couldn't find argv0 in the
00262    // path and argv0 wasn't a full path.  Last resort: try current directory + argv0
00263    std::string trystr = concat_pathname_components(cwd, argv0);
00264 
00265    if (exists_executable(trystr)) 
00266    {
00267       result = trystr;
00268       return true;
00269    }
00270    return false;
00271 }
00272 
00273 #if defined(os_windows)
00274 #define PATH_SEP ('\\')
00275 #define SECOND_PATH_SEP ('/')
00276 #else
00277 #define PATH_SEP ('/')
00278 #endif
00279 
00280 std::string extract_pathname_tail(const std::string &path)
00281 {
00282     if (!path.length())
00283     {
00284         return std::string("");
00285     }
00286 
00287    const char *path_str = path.c_str();
00288    if (!path_str)
00289     {
00290         return std::string("");
00291     }
00292 
00293    const char *path_sep = P_strrchr(path_str, PATH_SEP);
00294 
00295 #if defined(SECOND_PATH_SEP)
00296    const char *sec_path_sep = P_strrchr(path_str, SECOND_PATH_SEP);
00297    if (sec_path_sep && (!path_sep || sec_path_sep > path_sep))
00298       path_sep = sec_path_sep;
00299 #endif
00300 
00301    std::string ret = (path_sep) ? (path_sep + 1) : (path_str);
00302    return ret;
00303 }
00304 
00305 #if !defined (os_windows)
00306 static
00307 char *resolve_file_path_local(const char *fname, char *resolved_path)
00308 {
00309    // (1) realpath doesn't always return errors when the last element
00310    // of fname doesn't exist -- make sure it exists first to allow
00311    // consistent results of this function across platforms
00312    struct stat stat_buf;
00313    if( -1 == stat(fname, &stat_buf) ) {
00314        return NULL;
00315    }
00316 
00317    // (2)  use realpath() to resolve any . or ..'s, or symbolic links
00318    if (NULL == realpath(fname, resolved_path)) {
00319       return NULL;
00320    }
00321 
00322    // (3) if no slashes, try CWD
00323    if (!strpbrk(resolved_path, "/\\")) {
00324       char cwd[PATH_MAX];
00325       if (NULL == getcwd(cwd, PATH_MAX)) {
00326          return NULL;
00327       }
00328       char resolved_path_bak[PATH_MAX];
00329       strcpy(resolved_path_bak, resolved_path);
00330       sprintf(resolved_path, "%s/%s", cwd, resolved_path_bak);
00331    }
00332 
00333    // (4) if it has a tilde, expand tilde pathname
00334    if (!strpbrk(resolved_path, "~")) {
00335       std::string td_pathname = std::string(resolved_path);
00336       std::string no_td_pathname = expand_tilde_pathname(td_pathname);
00337       strcpy(resolved_path, no_td_pathname.c_str());
00338    }
00339 
00340    return resolved_path;
00341 }
00342 
00343 std::string resolve_file_path(const char *fname) {
00344     char path_buf[PATH_MAX];
00345     char *result = resolve_file_path_local(fname, path_buf);
00346     if ( result == NULL ) {
00347         return std::string();
00348     }
00349     std::string ret = result;
00350     return ret;
00351 }
00352 
00353 #else
00354 std::string resolve_file_path(const char *fname) {
00355     assert(!"UNIMPLEMENTED ON WINDOWS");
00356     return std::string("");
00357 }
00358 #endif
00359 
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

Generated on 12 Jul 2013 for SymtabAPI by  doxygen 1.6.1