00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "executionEnvironment.h"
00016 #include "pandaVersion.h"
00017 #include <assert.h>
00018 #include <errno.h>
00019 #include <stdio.h>
00020
00021 #ifdef __APPLE__
00022 #include <sys/param.h>
00023 #endif // __APPLE__
00024
00025 #ifdef WIN32_VC
00026
00027 #include <direct.h>
00028 #define getcwd _getcwd
00029
00030
00031 #include <windows.h>
00032 #endif
00033
00034 #ifdef __APPLE__
00035
00036 #include <mach-o/dyld.h>
00037 #ifndef BUILD_IPHONE
00038 #include <crt_externs.h>
00039 #endif
00040 #define environ (*_NSGetEnviron())
00041 #endif
00042
00043 #ifdef IS_LINUX
00044
00045 #include <unistd.h>
00046 #endif
00047
00048 #ifdef IS_FREEBSD
00049 extern char **environ;
00050
00051
00052 #include <link.h>
00053 #include <dlfcn.h>
00054
00055
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
00065
00066
00067
00068
00069 #ifndef STATIC_INIT_GETENV
00070 #define PREREAD_ENVIRONMENT
00071 #endif
00072
00073
00074
00075
00076
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
00084
00085
00086
00087 ExecutionEnvironment *ExecutionEnvironment::_global_ptr = NULL;
00088
00089
00090
00091
00092
00093
00094
00095
00096 ExecutionEnvironment::
00097 ExecutionEnvironment() {
00098 read_environment_variables();
00099 read_args();
00100 }
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
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
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
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
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
00163
00164
00165
00166 Filename ExecutionEnvironment::
00167 get_cwd() {
00168 #ifdef WIN32_VC
00169
00170
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
00194
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
00221
00222
00223
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
00236
00237
00238
00239
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
00250
00251
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
00263 if (!ns_has_environment_variable("PANDA_INCOMPATIBLE_PYTHON") && Py_IsInitialized()) {
00264
00265
00266
00267
00268 PyGILState_STATE state = PyGILState_Ensure();
00269
00270 Filename main_dir;
00271 PyObject *obj = PySys_GetObject((char*) "argv");
00272 if (obj != NULL && PyList_Check(obj)) {
00273 PyObject *item = PyList_GetItem(obj, 0);
00274
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
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
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
00315
00316
00317
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
00325 char *put = (char *)malloc(putstr.length() + 1);
00326 strcpy(put, putstr.c_str());
00327 putenv(put);
00328 }
00329
00330
00331
00332
00333
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
00343
00344
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
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
00366
00367
00368
00369
00370
00371 int ExecutionEnvironment::
00372 ns_get_num_args() const {
00373 return _args.size();
00374 }
00375
00376
00377
00378
00379
00380
00381
00382
00383
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
00393
00394
00395
00396
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
00408
00409
00410
00411
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
00423
00424
00425
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
00438
00439
00440
00441
00442
00443 void ExecutionEnvironment::
00444 read_environment_variables() {
00445 #ifdef PREREAD_ENVIRONMENT
00446 #if defined(IS_OSX) || defined(IS_FREEBSD) || defined(IS_LINUX)
00447
00448
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
00472
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
00511
00512
00513
00514
00515 void ExecutionEnvironment::
00516 read_args() {
00517
00518
00519
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
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
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
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
00602
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
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
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
00647
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
00664
00665
00666 #if defined(IS_FREEBSD)
00667
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
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
00701
00702
00703
00704
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
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 }