Panda3D

executionEnvironment.cxx

00001 // Filename: executionEnvironment.cxx
00002 // Created by:  drose (15May00)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) Carnegie Mellon University.  All rights reserved.
00008 //
00009 // All use of this software is subject to the terms of the revised BSD
00010 // license.  You should have received a copy of this license along
00011 // with this source code in a file named "LICENSE."
00012 //
00013 ////////////////////////////////////////////////////////////////////
00014 
00015 #include "executionEnvironment.h"
00016 #include "pandaVersion.h"
00017 #include <assert.h>
00018 #include <errno.h>
00019 #include <stdio.h>  // for perror
00020 
00021 #ifdef __APPLE__
00022 #include <sys/param.h>  // for realpath
00023 #endif  // __APPLE__
00024 
00025 #ifdef WIN32_VC
00026 // Windows requires this for getcwd().
00027 #include <direct.h>
00028 #define getcwd _getcwd
00029 
00030 // And this is for GetModuleFileName().
00031 #include <windows.h>
00032 #endif
00033 
00034 #ifdef __APPLE__
00035 // This is for _NSGetExecutablePath() and _NSGetEnviron().
00036 #include <mach-o/dyld.h>
00037 #ifndef BUILD_IPHONE
00038 #include <crt_externs.h>  // For some reason, not in the IPhone SDK.
00039 #endif
00040 #define environ (*_NSGetEnviron())
00041 #endif
00042 
00043 #ifdef IS_LINUX
00044 // extern char **environ is defined here:
00045 #include <unistd.h>
00046 #endif
00047 
00048 #ifdef IS_FREEBSD
00049 extern char **environ;
00050 
00051 // For Link_map and dlinfo.
00052 #include <link.h>
00053 #include <dlfcn.h>
00054 
00055 // This is for sysctl.
00056 #include <sys/types.h>
00057 #include <sys/sysctl.h>
00058 #endif
00059 
00060 #ifdef HAVE_PYTHON
00061 #include "Python.h"
00062 #endif
00063 
00064 // We define the symbol PREREAD_ENVIRONMENT if we cannot rely on
00065 // getenv() to read environment variables at static init time.  In
00066 // this case, we must read all of the environment variables directly
00067 // and cache them locally.
00068 
00069 #ifndef STATIC_INIT_GETENV
00070 #define PREREAD_ENVIRONMENT
00071 #endif
00072 
00073 
00074 // We define the symbol HAVE_GLOBAL_ARGV if we have global variables
00075 // named GLOBAL_ARGC/GLOBAL_ARGV that we can read at static init time
00076 // to determine our command-line arguments.
00077 
00078 #if defined(HAVE_GLOBAL_ARGV) && defined(PROTOTYPE_GLOBAL_ARGV)
00079 extern char **GLOBAL_ARGV;
00080 extern int GLOBAL_ARGC;
00081 #endif
00082 
00083 // Linux with GNU libc does have global argv/argc variables, but we
00084 // can't safely access them at stat init time--at least, not in libc5.
00085 // (It does seem to work with glibc2, however.)
00086 
00087 ExecutionEnvironment *ExecutionEnvironment::_global_ptr = NULL;
00088 
00089 
00090 ////////////////////////////////////////////////////////////////////
00091 //     Function: ExecutionEnvironment::Constructor
00092 //       Access: Private
00093 //  Description: You shouldn't need to construct one of these; there's
00094 //               only one and it constructs itself.
00095 ////////////////////////////////////////////////////////////////////
00096 ExecutionEnvironment::
00097 ExecutionEnvironment() {
00098   read_environment_variables();
00099   read_args();
00100 }
00101 
00102 ////////////////////////////////////////////////////////////////////
00103 //     Function: ExecutionEnviroment::expand_string
00104 //       Access: Public, Static
00105 //  Description: Reads the string, looking for environment variable
00106 //               names marked by a $.  Expands all such variable
00107 //               names.  A repeated dollar sign ($$) is mapped to a
00108 //               single dollar sign.
00109 //
00110 //               Returns the expanded string.
00111 ////////////////////////////////////////////////////////////////////
00112 string ExecutionEnvironment::
00113 expand_string(const string &str) {
00114   string result;
00115 
00116   size_t last = 0;
00117   size_t dollar = str.find('$');
00118   while (dollar != string::npos && dollar + 1 < str.length()) {
00119     size_t start = dollar + 1;
00120 
00121     if (str[start] == '$') {
00122       // A double dollar sign maps to a single dollar sign.
00123       result += str.substr(last, start - last);
00124       last = start + 1;
00125 
00126     } else {
00127       string varname;
00128       size_t end = start;
00129 
00130       if (str[start] == '{') {
00131         // Curly braces delimit the variable name explicitly.
00132         end = str.find('}', start + 1);
00133         if (end != string::npos) {
00134           varname = str.substr(start + 1, end - (start + 1));
00135           end++;
00136         }
00137       }
00138 
00139       if (end == start) {
00140         // Scan for the end of the variable name.
00141         while (end < str.length() && (isalnum(str[end]) || str[end] == '_')) {
00142           end++;
00143         }
00144         varname = str.substr(start, end - start);
00145       }
00146 
00147       string subst =
00148       result += str.substr(last, dollar - last);
00149       result += get_environment_variable(varname);
00150       last = end;
00151     }
00152 
00153     dollar = str.find('$', last);
00154   }
00155 
00156   result += str.substr(last);
00157 
00158   return result;
00159 }
00160 
00161 ////////////////////////////////////////////////////////////////////
00162 //     Function: ExecutionEnviroment::get_cwd
00163 //       Access: Public, Static
00164 //  Description: Returns the name of the current working directory.
00165 ////////////////////////////////////////////////////////////////////
00166 Filename ExecutionEnvironment::
00167 get_cwd() {
00168 #ifdef WIN32_VC
00169   // getcwd() requires us to allocate a dynamic buffer and grow it on
00170   // demand.
00171   static size_t bufsize = 1024;
00172   static wchar_t *buffer = NULL;
00173 
00174   if (buffer == (wchar_t *)NULL) {
00175     buffer = new wchar_t[bufsize];
00176   }
00177 
00178   while (_wgetcwd(buffer, bufsize) == (wchar_t *)NULL) {
00179     if (errno != ERANGE) {
00180       perror("getcwd");
00181       return string();
00182     }
00183     delete[] buffer;
00184     bufsize = bufsize * 2;
00185     buffer = new wchar_t[bufsize];
00186     assert(buffer != (wchar_t *)NULL);
00187   }
00188 
00189   Filename cwd = Filename::from_os_specific_w(buffer);
00190   cwd.make_true_case();
00191   return cwd;
00192 #else  // WIN32_VC
00193   // getcwd() requires us to allocate a dynamic buffer and grow it on
00194   // demand.
00195   static size_t bufsize = 1024;
00196   static char *buffer = NULL;
00197 
00198   if (buffer == (char *)NULL) {
00199     buffer = new char[bufsize];
00200   }
00201 
00202   while (getcwd(buffer, bufsize) == (char *)NULL) {
00203     if (errno != ERANGE) {
00204       perror("getcwd");
00205       return string();
00206     }
00207     delete[] buffer;
00208     bufsize = bufsize * 2;
00209     buffer = new char[bufsize];
00210     assert(buffer != (char *)NULL);
00211   }
00212 
00213   Filename cwd = Filename::from_os_specific(buffer);
00214   cwd.make_true_case();
00215   return cwd;
00216 #endif  // WIN32_VC
00217 }
00218 
00219 ////////////////////////////////////////////////////////////////////
00220 //     Function: ExecutionEnvironment::ns_has_environment_variable
00221 //       Access: Private
00222 //  Description: Returns true if the indicated environment variable
00223 //               is defined.  The nonstatic implementation.
00224 ////////////////////////////////////////////////////////////////////
00225 bool ExecutionEnvironment::
00226 ns_has_environment_variable(const string &var) const {
00227 #ifdef PREREAD_ENVIRONMENT
00228   return _variables.count(var) != 0;
00229 #else
00230   return getenv(var.c_str()) != (char *)NULL;
00231 #endif
00232 }
00233 
00234 ////////////////////////////////////////////////////////////////////
00235 //     Function: ExecutionEnvironment::ns_get_environment_variable
00236 //       Access: Private
00237 //  Description: Returns the definition of the indicated environment
00238 //               variable, or the empty string if the variable is
00239 //               undefined.  The nonstatic implementation.
00240 ////////////////////////////////////////////////////////////////////
00241 string ExecutionEnvironment::
00242 ns_get_environment_variable(const string &var) const {
00243   EnvironmentVariables::const_iterator evi;
00244   evi = _variables.find(var);
00245   if (evi != _variables.end()) {
00246     return (*evi).second;
00247   }
00248 
00249   // Some special case variables.  We virtually stuff these values
00250   // into the Panda environment, shadowing whatever values they have
00251   // in the true environment, so they can be used in config files.
00252   if (var == "HOME") {
00253     return Filename::get_home_directory().to_os_specific();
00254   } else if (var == "TEMP") {
00255     return Filename::get_temp_directory().to_os_specific();
00256   } else if (var == "USER_APPDATA") {
00257     return Filename::get_user_appdata_directory().to_os_specific();
00258   } else if (var == "COMMON_APPDATA") {
00259     return Filename::get_common_appdata_directory().to_os_specific();
00260   } else if (var == "MAIN_DIR") {
00261 #ifdef HAVE_PYTHON
00262     // If we're running from Python code, read out sys.argv.
00263     if (!ns_has_environment_variable("PANDA_INCOMPATIBLE_PYTHON") && Py_IsInitialized()) {
00264       // Since we might have gotten to this point from a function call
00265       // marked BLOCKING, which releases the Python thread state, we
00266       // have to temporarily re-establish our thread state in the
00267       // Python interpreter.
00268       PyGILState_STATE state = PyGILState_Ensure();
00269 
00270       Filename main_dir;
00271       PyObject *obj = PySys_GetObject((char*) "argv");  // borrowed reference
00272       if (obj != NULL && PyList_Check(obj)) {
00273         PyObject *item = PyList_GetItem(obj, 0);  // borrowed reference
00274         // Hmm, could this ever be a Unicode object?
00275         if (item != NULL && PyString_Check(item)) {
00276           char *str = PyString_AsString(item);
00277           if (str != (char *)NULL) {
00278             main_dir = Filename::from_os_specific(str);
00279           }
00280         }
00281       }
00282       
00283       PyGILState_Release(state);
00284 
00285       if (main_dir.empty()) {
00286         // We must be running in the Python interpreter directly, so return the CWD.
00287         return get_cwd().to_os_specific();
00288       }
00289       main_dir.make_absolute();
00290       return Filename(main_dir.get_dirname()).to_os_specific();
00291     }
00292 #endif
00293 
00294     // Otherwise, Return the binary name's parent directory.
00295     if (!_binary_name.empty()) {
00296       Filename main_dir (_binary_name);
00297       main_dir.make_absolute();
00298       return Filename(main_dir.get_dirname()).to_os_specific();
00299     }
00300   }
00301 
00302 #ifdef PREREAD_ENVIRONMENT
00303   return string();
00304 #else
00305   const char *def = getenv(var.c_str());
00306   if (def != (char *)NULL) {
00307     return def;
00308   }
00309   return string();
00310 #endif
00311 }
00312 
00313 ////////////////////////////////////////////////////////////////////
00314 //     Function: ExecutionEnvironment::ns_set_environment_variable
00315 //       Access: Private
00316 //  Description: Changes the definition of the indicated environment
00317 //               variable.  The nonstatic implementation.
00318 ////////////////////////////////////////////////////////////////////
00319 void ExecutionEnvironment::
00320 ns_set_environment_variable(const string &var, const string &value) {
00321   _variables[var] = value;
00322   string putstr = var + "=" + value;
00323 
00324   // putenv() requires us to malloc a new C-style string.
00325   char *put = (char *)malloc(putstr.length() + 1);
00326   strcpy(put, putstr.c_str());
00327   putenv(put);
00328 }
00329 
00330 ////////////////////////////////////////////////////////////////////
00331 //     Function: ExecutionEnvironment::ns_shadow_environment_variable
00332 //       Access: Private
00333 //  Description:
00334 ////////////////////////////////////////////////////////////////////
00335 void ExecutionEnvironment::
00336 ns_shadow_environment_variable(const string &var, const string &value) {
00337   _variables[var] = value;
00338   string putstr = var + "=" + value;
00339 }
00340 
00341 ////////////////////////////////////////////////////////////////////
00342 //     Function: ExecutionEnvironment::ns_clear_shadow
00343 //       Access: Private
00344 //  Description:
00345 ////////////////////////////////////////////////////////////////////
00346 void ExecutionEnvironment::
00347 ns_clear_shadow(const string &var) {
00348   EnvironmentVariables::iterator vi = _variables.find(var);
00349   if (vi == _variables.end()) {
00350     return;
00351   }
00352 
00353 #ifdef PREREAD_ENVIRONMENT
00354   // Now we have to replace the value in the table.
00355   const char *def = getenv(var.c_str());
00356   if (def != (char *)NULL) {
00357     (*vi).second = def;
00358   } else {
00359     _variables.erase(vi);
00360   }
00361 #endif  // PREREAD_ENVIRONMENT
00362 }
00363 
00364 ////////////////////////////////////////////////////////////////////
00365 //     Function: ExecutionEnvironment::ns_get_num_args
00366 //       Access: Private
00367 //  Description: Returns the number of command-line arguments
00368 //               available, not counting arg 0, the binary name.  The
00369 //               nonstatic implementation.
00370 ////////////////////////////////////////////////////////////////////
00371 int ExecutionEnvironment::
00372 ns_get_num_args() const {
00373   return _args.size();
00374 }
00375 
00376 ////////////////////////////////////////////////////////////////////
00377 //     Function: ExecutionEnvironment::ns_get_arg
00378 //       Access: Private
00379 //  Description: Returns the nth command-line argument.  The index n
00380 //               must be in the range [0 .. get_num_args()).  The
00381 //               first parameter, n == 0, is the first actual
00382 //               parameter, not the binary name.  The nonstatic
00383 //               implementation.
00384 ////////////////////////////////////////////////////////////////////
00385 string ExecutionEnvironment::
00386 ns_get_arg(int n) const {
00387   assert(n >= 0 && n < ns_get_num_args());
00388   return _args[n];
00389 }
00390 
00391 ////////////////////////////////////////////////////////////////////
00392 //     Function: ExecutionEnvironment::ns_get_binary_name
00393 //       Access: Private
00394 //  Description: Returns the name of the binary executable that
00395 //               started this program, if it can be determined.  The
00396 //               nonstatic implementation.
00397 ////////////////////////////////////////////////////////////////////
00398 string ExecutionEnvironment::
00399 ns_get_binary_name() const {
00400   if (_binary_name.empty()) {
00401     return "unknown";
00402   }
00403   return _binary_name;
00404 }
00405 
00406 ////////////////////////////////////////////////////////////////////
00407 //     Function: ExecutionEnvironment::ns_get_dtool_name
00408 //       Access: Private
00409 //  Description: Returns the name of the libdtool DLL that
00410 //               is used in this program, if it can be determined.  The
00411 //               nonstatic implementation.
00412 ////////////////////////////////////////////////////////////////////
00413 string ExecutionEnvironment::
00414 ns_get_dtool_name() const {
00415   if (_dtool_name.empty()) {
00416     return "unknown";
00417   }
00418   return _dtool_name;
00419 }
00420 
00421 ////////////////////////////////////////////////////////////////////
00422 //     Function: ExecutionEnvironment::get_ptr
00423 //       Access: Private, Static
00424 //  Description: Returns a static pointer that may be used to access
00425 //               the global ExecutionEnvironment object.
00426 ////////////////////////////////////////////////////////////////////
00427 ExecutionEnvironment *ExecutionEnvironment::
00428 get_ptr() {
00429   if (_global_ptr == (ExecutionEnvironment *)NULL) {
00430     _global_ptr = new ExecutionEnvironment;
00431   }
00432   return _global_ptr;
00433 }
00434 
00435 
00436 ////////////////////////////////////////////////////////////////////
00437 //     Function: ExecutionEnvironment::read_environment_variables
00438 //       Access: Private
00439 //  Description: Fills up the internal table of existing environment
00440 //               variables, if we are in PREREAD_ENVIRONMENT mode.
00441 //               Otherwise, does nothing.
00442 ////////////////////////////////////////////////////////////////////
00443 void ExecutionEnvironment::
00444 read_environment_variables() {
00445 #ifdef PREREAD_ENVIRONMENT
00446 #if defined(IS_OSX) || defined(IS_FREEBSD) || defined(IS_LINUX)
00447   // In the case of Mac, we'll try reading _NSGetEnviron().
00448   // In the case of FreeBSD and Linux, use the "environ" variable.
00449 
00450   char **envp;
00451   for (envp = environ; envp && *envp; envp++) {
00452     string variable;
00453     string value;
00454 
00455     char *envc;
00456     for (envc = *envp; envc && *envc && strncmp(envc, "=", 1) != 0; envc++) {
00457       variable += (char) *envc;
00458     }
00459 
00460     if (strncmp(envc, "=", 1) == 0) {
00461       for (envc++; envc && *envc; envc++) {
00462         value += (char) *envc;
00463       }
00464     }
00465 
00466     if (!variable.empty()) {
00467       _variables[variable] = value;
00468     }
00469   }
00470 #elif defined(HAVE_PROC_SELF_ENVIRON)
00471   // In some cases, we may have a file called /proc/self/environ
00472   // that may be read to determine all of our environment variables.
00473 
00474   pifstream proc("/proc/self/environ");
00475   if (proc.fail()) {
00476     cerr << "Cannot read /proc/self/environ; environment variables unavailable.\n";
00477     return;
00478   }
00479 
00480   int ch = proc.get();
00481   while (!proc.eof() && !proc.fail()) {
00482     string variable;
00483     string value;
00484 
00485     while (!proc.eof() && !proc.fail() && ch != '=' && ch != '\0') {
00486       variable += (char)ch;
00487       ch = proc.get();
00488     }
00489 
00490     if (ch == '=') {
00491       ch = proc.get();
00492       while (!proc.eof() && !proc.fail() && ch != '\0') {
00493         value += (char)ch;
00494         ch = proc.get();
00495       }
00496     }
00497 
00498     if (!variable.empty()) {
00499       _variables[variable] = value;
00500     }
00501     ch = proc.get();
00502   }
00503 #else
00504   cerr << "Warning: environment variables unavailable to dconfig.\n";
00505 #endif
00506 #endif // PREREAD_ENVIRONMENT
00507 }
00508 
00509 ////////////////////////////////////////////////////////////////////
00510 //     Function: ExecutionEnvironment::read_args
00511 //       Access: Private
00512 //  Description: Reads all the command-line arguments and the name of
00513 //               the binary file, if possible.
00514 ////////////////////////////////////////////////////////////////////
00515 void ExecutionEnvironment::
00516 read_args() {
00517 
00518   // First, we need to fill in _dtool_name.  This contains
00519   // the full path to the p3dtool library.
00520 
00521 #ifdef WIN32_VC
00522 #ifdef _DEBUG
00523   HMODULE dllhandle = GetModuleHandle("libp3dtool_d.dll");
00524 #else
00525   HMODULE dllhandle = GetModuleHandle("libp3dtool.dll");
00526 #endif
00527   if (dllhandle != 0) {
00528     static const DWORD buffer_size = 1024;
00529     wchar_t buffer[buffer_size];
00530     DWORD size = GetModuleFileNameW(dllhandle, buffer, buffer_size);
00531     if (size != 0) {
00532       Filename tmp = Filename::from_os_specific_w(wstring(buffer, size));
00533       tmp.make_true_case();
00534       _dtool_name = tmp;
00535     }
00536   }
00537 #endif
00538 
00539 #if defined(__APPLE__)
00540   // And on OSX we don't have /proc/self/maps, but some _dyld_* functions.
00541 
00542   if (_dtool_name.empty()) {
00543     uint32_t ic = _dyld_image_count();
00544     for (uint32_t i = 0; i < ic; ++i) {
00545       const char *buffer = _dyld_get_image_name(i);
00546       const char *tail = strrchr(buffer, '/');
00547       if (tail && (strcmp(tail, "/libp3dtool." PANDA_ABI_VERSION_STR ".dylib") == 0
00548                 || strcmp(tail, "/libp3dtool.dylib") == 0
00549                 || strcmp(tail, "/libdtool.dylib") == 0)) {
00550         _dtool_name = buffer;
00551       }
00552     }
00553   }
00554 #endif
00555 
00556 #if defined(IS_FREEBSD)
00557   // On FreeBSD, we can use dlinfo to get the linked libraries.
00558 
00559   if (_dtool_name.empty()) {
00560     Link_map *map;
00561     dlinfo(RTLD_SELF, RTLD_DI_LINKMAP, &map);
00562 
00563     while (map != NULL) {
00564       char *tail = strrchr(map->l_name, '/');
00565       char *head = strchr(map->l_name, '/');
00566       if (tail && head && (strcmp(tail, "/libp3dtool.so." PANDA_ABI_VERSION_STR) == 0
00567                         || strcmp(tail, "/libp3dtool.so") == 0
00568                         || strcmp(tail, "/libdtool.so") == 0)) {
00569         _dtool_name = head;
00570       }
00571       map = map->l_next;
00572     }
00573   }
00574 #endif
00575 
00576 #if defined(HAVE_PROC_SELF_MAPS) || defined(HAVE_PROC_CURPROC_MAP)
00577   // Some operating systems provide a file in the /proc filesystem.
00578 
00579   if (_dtool_name.empty()) {
00580 #ifdef HAVE_PROC_CURPROC_MAP
00581     pifstream maps("/proc/curproc/map");
00582 #else
00583     pifstream maps("/proc/self/maps");
00584 #endif
00585     while (!maps.fail() && !maps.eof()) {
00586       char buffer[PATH_MAX];
00587       buffer[0] = 0;
00588       maps.getline(buffer, PATH_MAX);
00589       char *tail = strrchr(buffer, '/');
00590       char *head = strchr(buffer, '/');
00591       if (tail && head && (strcmp(tail, "/libp3dtool.so." PANDA_ABI_VERSION_STR) == 0
00592                         || strcmp(tail, "/libp3dtool.so") == 0
00593                         || strcmp(tail, "/libdtool.so") == 0)) {
00594         _dtool_name = head;
00595       }
00596     }
00597     maps.close();
00598   }
00599 #endif
00600 
00601   // Now, we need to fill in _binary_name.  This contains
00602   // the full path to the currently running executable.
00603 
00604 #ifdef WIN32_VC
00605   if (_binary_name.empty()) {
00606     static const DWORD buffer_size = 1024;
00607     wchar_t buffer[buffer_size];
00608     DWORD size = GetModuleFileNameW(NULL, buffer, buffer_size);
00609     if (size != 0) {
00610       Filename tmp = Filename::from_os_specific_w(wstring(buffer, size));
00611       tmp.make_true_case();
00612       _binary_name = tmp;
00613     }
00614   }
00615 #endif
00616 
00617 #if defined(__APPLE__)
00618   // And on Mac, we have _NSGetExecutablePath.
00619   if (_binary_name.empty()) {
00620     char *pathbuf = new char[PATH_MAX];
00621     uint32_t bufsize = PATH_MAX;
00622     if (_NSGetExecutablePath(pathbuf, &bufsize) == 0) {
00623       _binary_name = pathbuf;
00624     }
00625     delete[] pathbuf;
00626   }
00627 #endif
00628 
00629 #if defined(IS_FREEBSD)
00630   // In FreeBSD, we can use sysctl to determine the pathname.
00631 
00632   if (_binary_name.empty()) {
00633     size_t bufsize = 4096;
00634     char buffer[4096];
00635     int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1};
00636     mib[3] = getpid();
00637     if (sysctl(mib, 4, (void*) buffer, &bufsize, NULL, 0) == -1) {
00638       perror("sysctl");
00639     } else {
00640       _binary_name = buffer;
00641     }
00642   }
00643 #endif
00644 
00645 #if defined(HAVE_PROC_SELF_EXE) || defined(HAVE_PROC_CURPROC_FILE)
00646   // Some operating systems provide a symbolic link to the executable
00647   // in the /proc filesystem.  Use readlink to resolve that link.
00648 
00649   if (_binary_name.empty()) {
00650     char readlinkbuf [PATH_MAX];
00651 #ifdef HAVE_PROC_CURPROC_FILE
00652     int pathlen = readlink("/proc/curproc/file", readlinkbuf, PATH_MAX - 1);
00653 #else
00654     int pathlen = readlink("/proc/self/exe", readlinkbuf, PATH_MAX - 1);
00655 #endif
00656     if (pathlen > 0) {
00657       readlinkbuf[pathlen] = 0;
00658       _binary_name = readlinkbuf;
00659     }
00660   }
00661 #endif
00662 
00663   // Next we need to fill in _args, which is a vector containing
00664   // the command-line arguments that the executable was invoked with.
00665 
00666 #if defined(IS_FREEBSD)
00667   // In FreeBSD, we can use sysctl to determine the command-line arguments.
00668 
00669   size_t bufsize = 4096;
00670   char buffer[4096];
00671   int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_ARGS, 0};
00672   mib[3] = getpid();
00673   if (sysctl(mib, 4, (void*) buffer, &bufsize, NULL, 0) == -1) {
00674     perror("sysctl");
00675   } else {
00676     if (_binary_name.empty()) {
00677       _binary_name = buffer;
00678     }
00679     int idx = strlen(buffer) + 1;
00680     while (idx < bufsize) {
00681       _args.push_back((char*)(buffer + idx));
00682       int newidx = strlen(buffer + idx);
00683       idx += newidx + 1;
00684     }
00685   }
00686 
00687 #elif defined(HAVE_GLOBAL_ARGV)
00688   int argc = GLOBAL_ARGC;
00689 
00690   if (_binary_name.empty() && argc > 0) {
00691     _binary_name = GLOBAL_ARGV[0];
00692     // This really needs to be resolved against PATH.
00693   }
00694 
00695   for (int i = 1; i < argc; i++) {
00696     _args.push_back(GLOBAL_ARGV[i]);
00697   }
00698 
00699 #elif defined(HAVE_PROC_SELF_CMDLINE) || defined(HAVE_PROC_CURPROC_CMDLINE)
00700   // In Linux, and possibly in other systems as well, we might not be
00701   // able to use the global ARGC/ARGV variables at static init time.
00702   // However, we may be lucky and have a file called
00703   // /proc/self/cmdline that may be read to determine all of our
00704   // command-line arguments.
00705 
00706 #ifdef HAVE_PROC_CURPROC_CMDLINE
00707   pifstream proc("/proc/curproc/cmdline");
00708   if (proc.fail()) {
00709     cerr << "Cannot read /proc/curproc/cmdline; command-line arguments unavailable to config.\n";
00710 #else
00711   pifstream proc("/proc/self/cmdline");
00712   if (proc.fail()) {
00713     cerr << "Cannot read /proc/self/cmdline; command-line arguments unavailable to config.\n";
00714 #endif
00715   } else {
00716     int ch = proc.get();
00717     int index = 0;
00718     while (!proc.eof() && !proc.fail()) {
00719       string arg;
00720 
00721       while (!proc.eof() && !proc.fail() && ch != '\0') {
00722         arg += (char)ch;
00723         ch = proc.get();
00724       }
00725 
00726       if (index == 0) {
00727         if (_binary_name.empty())
00728           _binary_name = arg;
00729       } else {
00730         _args.push_back(arg);
00731       }
00732       index++;
00733 
00734       ch = proc.get();
00735     }
00736   }
00737 #endif
00738 
00739 #ifndef WIN32
00740   // Try to use realpath to get cleaner paths.
00741 
00742   if (!_binary_name.empty()) {
00743     char newpath [PATH_MAX + 1];
00744     if (realpath(_binary_name.c_str(), newpath) != NULL) {
00745       _binary_name = newpath;
00746     }
00747   }
00748 
00749   if (!_dtool_name.empty()) {
00750     char newpath [PATH_MAX + 1];
00751     if (realpath(_dtool_name.c_str(), newpath) != NULL) {
00752       _dtool_name = newpath;
00753     }
00754   }
00755 #endif
00756 
00757   if (_dtool_name.empty()) {
00758     _dtool_name = _binary_name;
00759   }
00760 }
 All Classes Functions Variables Enumerations