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