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 __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 }