deploy-stub.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726
  1. /* Python interpreter main program for frozen scripts */
  2. #include "Python.h"
  3. #ifdef _WIN32
  4. # include "malloc.h"
  5. # include <Shlobj.h>
  6. #else
  7. # include <sys/mman.h>
  8. # include <pwd.h>
  9. #endif
  10. #ifdef __FreeBSD__
  11. # include <sys/sysctl.h>
  12. #endif
  13. #ifdef __APPLE__
  14. # include <mach-o/dyld.h>
  15. # include <libgen.h>
  16. #endif
  17. #include <stdio.h>
  18. #include <stdint.h>
  19. #include <fcntl.h>
  20. #if PY_MAJOR_VERSION >= 3
  21. # include <locale.h>
  22. # if PY_MINOR_VERSION < 5
  23. # define Py_DecodeLocale _Py_char2wchar
  24. # endif
  25. #endif
  26. /* Leave room for future expansion. We only read pointer 0, but there are
  27. other pointers that are being read by configPageManager.cxx. */
  28. #define MAX_NUM_POINTERS 24
  29. /* Stored in the flags field of the blobinfo structure below. */
  30. enum Flags {
  31. F_log_append = 1,
  32. };
  33. /* Define an exposed symbol where we store the offset to the module data. */
  34. #ifdef _MSC_VER
  35. __declspec(dllexport)
  36. #else
  37. __attribute__((__visibility__("default"), used))
  38. #endif
  39. volatile struct {
  40. uint64_t blob_offset;
  41. uint64_t blob_size;
  42. uint16_t version;
  43. uint16_t num_pointers;
  44. uint16_t codepage;
  45. uint16_t flags;
  46. uint64_t reserved;
  47. void *pointers[MAX_NUM_POINTERS];
  48. // The reason we initialize it to -1 is because otherwise, smart linkers may
  49. // end up putting it in the .bss section for zero-initialized data.
  50. } blobinfo = {(uint64_t)-1};
  51. #ifdef MS_WINDOWS
  52. # define WIN32_LEAN_AND_MEAN
  53. # include <windows.h>
  54. extern void PyWinFreeze_ExeInit(void);
  55. extern void PyWinFreeze_ExeTerm(void);
  56. static struct _inittab extensions[] = {
  57. {0, 0},
  58. };
  59. #if PY_MAJOR_VERSION >= 3
  60. # define WIN_UNICODE
  61. #endif
  62. #endif
  63. #ifdef _WIN32
  64. static wchar_t *log_pathw = NULL;
  65. #endif
  66. #if defined(_WIN32) && PY_VERSION_HEX < 0x03060000
  67. static int supports_code_page(UINT cp) {
  68. if (cp == 0) {
  69. cp = GetACP();
  70. }
  71. /* Shortcut, because we know that these encodings are bundled by default--
  72. * see FreezeTool.py and Python's encodings/aliases.py */
  73. if (cp != 0 && cp != 1252 && cp != 367 && cp != 437 && cp != 850 && cp != 819) {
  74. const struct _frozen *moddef;
  75. char codec[100];
  76. /* Check if the codec was frozen into the program. We can't check this
  77. * using _PyCodec_Lookup, since Python hasn't been initialized yet. */
  78. PyOS_snprintf(codec, sizeof(codec), "encodings.cp%u", (unsigned int)cp);
  79. moddef = PyImport_FrozenModules;
  80. while (moddef->name) {
  81. if (strcmp(moddef->name, codec) == 0) {
  82. return 1;
  83. }
  84. ++moddef;
  85. }
  86. return 0;
  87. }
  88. return 1;
  89. }
  90. #endif
  91. /**
  92. * Sets the main_dir field of the blobinfo structure, but only if it wasn't
  93. * already set.
  94. */
  95. static void set_main_dir(char *main_dir) {
  96. if (blobinfo.num_pointers >= 10) {
  97. if (blobinfo.num_pointers == 10) {
  98. ++blobinfo.num_pointers;
  99. blobinfo.pointers[10] = NULL;
  100. }
  101. if (blobinfo.pointers[10] == NULL) {
  102. blobinfo.pointers[10] = main_dir;
  103. }
  104. }
  105. }
  106. /**
  107. * Creates the parent directories of the given path. Returns 1 on success.
  108. */
  109. #ifdef _WIN32
  110. static int mkdir_parent(const wchar_t *path) {
  111. // Copy the path to a temporary buffer.
  112. wchar_t buffer[4096];
  113. size_t buflen = wcslen(path);
  114. if (buflen + 1 >= _countof(buffer)) {
  115. return 0;
  116. }
  117. wcscpy_s(buffer, _countof(buffer), path);
  118. // Seek back to find the last path separator.
  119. while (buflen-- > 0) {
  120. if (buffer[buflen] == '/' || buffer[buflen] == '\\') {
  121. buffer[buflen] = 0;
  122. break;
  123. }
  124. }
  125. if (buflen == (size_t)-1 || buflen == 0) {
  126. // There was no path separator, or this was the root directory.
  127. return 0;
  128. }
  129. if (CreateDirectoryW(buffer, NULL) != 0) {
  130. // Success!
  131. return 1;
  132. }
  133. // Failed.
  134. DWORD last_error = GetLastError();
  135. if (last_error == ERROR_ALREADY_EXISTS) {
  136. // Not really an error: the directory is already there.
  137. return 1;
  138. }
  139. if (last_error == ERROR_PATH_NOT_FOUND) {
  140. // We need to make the parent directory first.
  141. if (mkdir_parent(buffer)) {
  142. // Parent successfully created. Try again to make the child.
  143. if (CreateDirectoryW(buffer, NULL) != 0) {
  144. // Got it!
  145. return 1;
  146. }
  147. }
  148. }
  149. return 0;
  150. }
  151. #else
  152. static int mkdir_parent(const char *path) {
  153. // Copy the path to a temporary buffer.
  154. char buffer[4096];
  155. size_t buflen = strlen(path);
  156. if (buflen + 1 >= sizeof(buffer)) {
  157. return 0;
  158. }
  159. strcpy(buffer, path);
  160. // Seek back to find the last path separator.
  161. while (buflen-- > 0) {
  162. if (buffer[buflen] == '/') {
  163. buffer[buflen] = 0;
  164. break;
  165. }
  166. }
  167. if (buflen == (size_t)-1 || buflen == 0) {
  168. // There was no path separator, or this was the root directory.
  169. return 0;
  170. }
  171. if (mkdir(buffer, 0755) == 0) {
  172. // Success!
  173. return 1;
  174. }
  175. // Failed.
  176. if (errno == EEXIST) {
  177. // Not really an error: the directory is already there.
  178. return 1;
  179. }
  180. if (errno == ENOENT || errno == EACCES) {
  181. // We need to make the parent directory first.
  182. if (mkdir_parent(buffer)) {
  183. // Parent successfully created. Try again to make the child.
  184. if (mkdir(buffer, 0755) == 0) {
  185. // Got it!
  186. return 1;
  187. }
  188. }
  189. }
  190. return 0;
  191. }
  192. #endif
  193. /**
  194. * Redirects the output streams to point to the log file with the given path.
  195. *
  196. * @param path specifies the location of log file, may start with ~
  197. * @param append should be nonzero if it should not truncate the log file.
  198. */
  199. static int setup_logging(const char *path, int append) {
  200. #ifdef _WIN32
  201. // Does it start with a tilde? Perform tilde expansion if so.
  202. wchar_t *pathw = (wchar_t *)malloc(sizeof(wchar_t) * MAX_PATH);
  203. pathw[0] = 0;
  204. size_t offset = 0;
  205. if (path[0] == '~' && (path[1] == 0 || path[1] == '/' || path[1] == '\\')) {
  206. // Strip off the tilde.
  207. ++path;
  208. // Get the home directory path for the current user.
  209. if (!SUCCEEDED(SHGetFolderPathW(NULL, CSIDL_PROFILE, NULL, 0, pathw))) {
  210. free(pathw);
  211. return 0;
  212. }
  213. offset = wcslen(pathw);
  214. }
  215. // We need to convert the rest of the path from UTF-8 to UTF-16.
  216. if (MultiByteToWideChar(CP_UTF8, 0, path, -1, pathw + offset,
  217. (int)(MAX_PATH - offset)) == 0) {
  218. free(pathw);
  219. return 0;
  220. }
  221. DWORD access = append ? FILE_APPEND_DATA : (GENERIC_READ | GENERIC_WRITE);
  222. int creation = append ? OPEN_ALWAYS : CREATE_ALWAYS;
  223. HANDLE handle = CreateFileW(pathw, access, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
  224. NULL, creation, FILE_ATTRIBUTE_NORMAL, NULL);
  225. if (handle == INVALID_HANDLE_VALUE) {
  226. // Make the parent directories first.
  227. mkdir_parent(pathw);
  228. handle = CreateFileW(pathw, access, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
  229. NULL, creation, FILE_ATTRIBUTE_NORMAL, NULL);
  230. }
  231. if (handle == INVALID_HANDLE_VALUE) {
  232. free(pathw);
  233. return 0;
  234. }
  235. log_pathw = pathw;
  236. if (append) {
  237. SetFilePointer(handle, 0, NULL, FILE_END);
  238. }
  239. SetStdHandle(STD_OUTPUT_HANDLE, handle);
  240. SetStdHandle(STD_ERROR_HANDLE, handle);
  241. // If we are running under the UCRT in a GUI application, we can't be sure
  242. // that we have valid fds for stdout and stderr, so we have to set them up.
  243. // One way to do this is to reopen them to something silly (like NUL).
  244. if (_fileno(stdout) < 0) {
  245. _close(1);
  246. _wfreopen(L"\\\\.\\NUL", L"w", stdout);
  247. }
  248. if (_fileno(stderr) < 0) {
  249. _close(2);
  250. _wfreopen(L"\\\\.\\NUL", L"w", stderr);
  251. }
  252. // Now replace the stdout and stderr file descriptors with one pointing to
  253. // our desired handle.
  254. int fd = _open_osfhandle((intptr_t)handle, _O_WRONLY | _O_TEXT | _O_APPEND);
  255. _dup2(fd, _fileno(stdout));
  256. _dup2(fd, _fileno(stderr));
  257. _close(fd);
  258. return 1;
  259. #else
  260. // Does it start with a tilde? Perform tilde expansion if so.
  261. char buffer[PATH_MAX * 2];
  262. size_t offset = 0;
  263. if (path[0] == '~' && (path[1] == 0 || path[1] == '/')) {
  264. // Strip off the tilde.
  265. ++path;
  266. // Get the home directory path for the current user.
  267. const char *home_dir = getenv("HOME");
  268. if (home_dir == NULL) {
  269. home_dir = getpwuid(getuid())->pw_dir;
  270. }
  271. offset = strlen(home_dir);
  272. assert(offset < sizeof(buffer));
  273. strncpy(buffer, home_dir, sizeof(buffer));
  274. }
  275. // Copy over the rest of the path.
  276. strcpy(buffer + offset, path);
  277. mode_t mode = O_CREAT | O_WRONLY | (append ? O_APPEND : O_TRUNC);
  278. int fd = open(buffer, mode, 0644);
  279. if (fd == -1) {
  280. // Make the parent directories first.
  281. mkdir_parent(buffer);
  282. fd = open(buffer, mode, 0644);
  283. }
  284. if (fd == -1) {
  285. perror(buffer);
  286. return 0;
  287. }
  288. fflush(stdout);
  289. fflush(stderr);
  290. dup2(fd, 1);
  291. dup2(fd, 2);
  292. close(fd);
  293. return 1;
  294. #endif
  295. }
  296. /* Main program */
  297. #ifdef WIN_UNICODE
  298. int Py_FrozenMain(int argc, wchar_t **argv)
  299. #else
  300. int Py_FrozenMain(int argc, char **argv)
  301. #endif
  302. {
  303. char *p;
  304. int n, sts = 1;
  305. int inspect = 0;
  306. int unbuffered = 0;
  307. #if PY_MAJOR_VERSION >= 3 && !defined(WIN_UNICODE)
  308. int i;
  309. char *oldloc;
  310. wchar_t **argv_copy = NULL;
  311. /* We need a second copies, as Python might modify the first one. */
  312. wchar_t **argv_copy2 = NULL;
  313. if (argc > 0) {
  314. argv_copy = (wchar_t **)alloca(sizeof(wchar_t *) * argc);
  315. argv_copy2 = (wchar_t **)alloca(sizeof(wchar_t *) * argc);
  316. }
  317. #endif
  318. #if defined(MS_WINDOWS) && PY_VERSION_HEX >= 0x03040000 && PY_VERSION_HEX < 0x03060000
  319. if (!supports_code_page(GetConsoleOutputCP()) ||
  320. !supports_code_page(GetConsoleCP())) {
  321. /* Revert to the active codepage, and tell Python to use the 'mbcs'
  322. * encoding (which always uses the active codepage). In 99% of cases,
  323. * this will be the same thing anyway. */
  324. UINT acp = GetACP();
  325. SetConsoleCP(acp);
  326. SetConsoleOutputCP(acp);
  327. Py_SetStandardStreamEncoding("mbcs", NULL);
  328. }
  329. #endif
  330. Py_FrozenFlag = 1; /* Suppress errors from getpath.c */
  331. Py_NoSiteFlag = 0;
  332. Py_NoUserSiteDirectory = 1;
  333. if ((p = Py_GETENV("PYTHONINSPECT")) && *p != '\0')
  334. inspect = 1;
  335. if ((p = Py_GETENV("PYTHONUNBUFFERED")) && *p != '\0')
  336. unbuffered = 1;
  337. if (unbuffered) {
  338. setbuf(stdin, (char *)NULL);
  339. setbuf(stdout, (char *)NULL);
  340. setbuf(stderr, (char *)NULL);
  341. }
  342. #if PY_MAJOR_VERSION >= 3 && !defined(WIN_UNICODE)
  343. oldloc = setlocale(LC_ALL, NULL);
  344. setlocale(LC_ALL, "");
  345. for (i = 0; i < argc; i++) {
  346. argv_copy[i] = Py_DecodeLocale(argv[i], NULL);
  347. argv_copy2[i] = argv_copy[i];
  348. if (!argv_copy[i]) {
  349. fprintf(stderr, "Unable to decode the command line argument #%i\n",
  350. i + 1);
  351. argc = i;
  352. goto error;
  353. }
  354. }
  355. setlocale(LC_ALL, oldloc);
  356. #endif
  357. #ifdef MS_WINDOWS
  358. PyImport_ExtendInittab(extensions);
  359. #endif /* MS_WINDOWS */
  360. if (argc >= 1) {
  361. #if PY_MAJOR_VERSION >= 3 && !defined(WIN_UNICODE)
  362. Py_SetProgramName(argv_copy[0]);
  363. #else
  364. Py_SetProgramName(argv[0]);
  365. #endif
  366. }
  367. Py_Initialize();
  368. #ifdef MS_WINDOWS
  369. PyWinFreeze_ExeInit();
  370. #endif
  371. #if defined(MS_WINDOWS) && PY_VERSION_HEX < 0x03040000
  372. /* We can't rely on our overriding of the standard I/O to work on older
  373. * versions of Python, since they are compiled with an incompatible CRT.
  374. * The best solution I've found was to just replace sys.stdout/stderr with
  375. * the log file reopened in append mode (which requires not locking it for
  376. * write, and also passing in _O_APPEND above, and disabling buffering).
  377. * It's not the most elegant solution, but it's better than crashing. */
  378. #if PY_MAJOR_VERSION < 3
  379. if (log_pathw != NULL) {
  380. PyObject *uniobj = PyUnicode_FromWideChar(log_pathw, (Py_ssize_t)wcslen(log_pathw));
  381. PyObject *file = PyObject_CallFunction((PyObject*)&PyFile_Type, "Nsi", uniobj, "a", 0);
  382. if (file != NULL) {
  383. PyFile_SetEncodingAndErrors(file, "utf-8", NULL);
  384. PySys_SetObject("stdout", file);
  385. PySys_SetObject("stderr", file);
  386. PySys_SetObject("__stdout__", file);
  387. PySys_SetObject("__stderr__", file);
  388. /* Be sure to disable buffering, otherwise we'll get overlap */
  389. setbuf(stdout, (char *)NULL);
  390. setbuf(stderr, (char *)NULL);
  391. }
  392. }
  393. else
  394. #endif
  395. if (!supports_code_page(GetConsoleOutputCP()) ||
  396. !supports_code_page(GetConsoleCP())) {
  397. /* Same hack as before except for Python 2.7, which doesn't seem to have
  398. * a way to set the encoding ahead of time, and setting PYTHONIOENCODING
  399. * doesn't seem to work. Fortunately, Python 2.7 doesn't usually start
  400. * causing codec errors until the first print statement. */
  401. PyObject *sys_stream;
  402. UINT acp = GetACP();
  403. SetConsoleCP(acp);
  404. SetConsoleOutputCP(acp);
  405. sys_stream = PySys_GetObject("stdin");
  406. if (sys_stream && PyFile_Check(sys_stream)) {
  407. PyFile_SetEncodingAndErrors(sys_stream, "mbcs", NULL);
  408. }
  409. sys_stream = PySys_GetObject("stdout");
  410. if (sys_stream && PyFile_Check(sys_stream)) {
  411. PyFile_SetEncodingAndErrors(sys_stream, "mbcs", NULL);
  412. }
  413. sys_stream = PySys_GetObject("stderr");
  414. if (sys_stream && PyFile_Check(sys_stream)) {
  415. PyFile_SetEncodingAndErrors(sys_stream, "mbcs", NULL);
  416. }
  417. }
  418. #endif
  419. if (Py_VerboseFlag)
  420. fprintf(stderr, "Python %s\n%s\n",
  421. Py_GetVersion(), Py_GetCopyright());
  422. #if PY_MAJOR_VERSION >= 3 && !defined(WIN_UNICODE)
  423. PySys_SetArgv(argc, argv_copy);
  424. #else
  425. PySys_SetArgv(argc, argv);
  426. #endif
  427. #ifdef MACOS_APP_BUNDLE
  428. // Add the Frameworks directory to sys.path.
  429. char buffer[PATH_MAX];
  430. uint32_t bufsize = sizeof(buffer);
  431. if (_NSGetExecutablePath(buffer, &bufsize) != 0) {
  432. assert(false);
  433. return 1;
  434. }
  435. char resolved[PATH_MAX];
  436. if (!realpath(buffer, resolved)) {
  437. perror("realpath");
  438. return 1;
  439. }
  440. const char *dir = dirname(resolved);
  441. sprintf(buffer, "%s/../Frameworks", dir);
  442. PyObject *sys_path = PyList_New(1);
  443. #if PY_MAJOR_VERSION >= 3
  444. PyList_SET_ITEM(sys_path, 0, PyUnicode_FromString(buffer));
  445. #else
  446. PyList_SET_ITEM(sys_path, 0, PyString_FromString(buffer));
  447. #endif
  448. PySys_SetObject("path", sys_path);
  449. Py_DECREF(sys_path);
  450. // Now, store a path to the Resources directory into the main_dir pointer,
  451. // for ConfigPageManager to read out and assign to MAIN_DIR.
  452. sprintf(buffer, "%s/../Resources", dir);
  453. set_main_dir(buffer);
  454. #endif
  455. n = PyImport_ImportFrozenModule("__main__");
  456. if (n == 0)
  457. Py_FatalError("__main__ not frozen");
  458. if (n < 0) {
  459. PyErr_Print();
  460. sts = 1;
  461. }
  462. else
  463. sts = 0;
  464. if (inspect && isatty((int)fileno(stdin)))
  465. sts = PyRun_AnyFile(stdin, "<stdin>") != 0;
  466. #ifdef MS_WINDOWS
  467. PyWinFreeze_ExeTerm();
  468. #endif
  469. Py_Finalize();
  470. #if PY_MAJOR_VERSION >= 3 && !defined(WIN_UNICODE)
  471. error:
  472. if (argv_copy2) {
  473. for (i = 0; i < argc; i++) {
  474. #if PY_MINOR_VERSION >= 4
  475. PyMem_RawFree(argv_copy2[i]);
  476. #else
  477. PyMem_Free(argv_copy2[i]);
  478. #endif
  479. }
  480. }
  481. #endif
  482. return sts;
  483. }
  484. /**
  485. * Maps the binary blob at the given memory address to memory, and returns the
  486. * pointer to the beginning of it.
  487. */
  488. static void *map_blob(off_t offset, size_t size) {
  489. void *blob;
  490. FILE *runtime;
  491. #ifdef _WIN32
  492. wchar_t buffer[2048];
  493. GetModuleFileNameW(NULL, buffer, 2048);
  494. runtime = _wfopen(buffer, L"rb");
  495. #elif defined(__FreeBSD__)
  496. size_t bufsize = 4096;
  497. char buffer[4096];
  498. int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1};
  499. mib[3] = getpid();
  500. if (sysctl(mib, 4, (void *)buffer, &bufsize, NULL, 0) == -1) {
  501. perror("sysctl");
  502. return NULL;
  503. }
  504. runtime = fopen(buffer, "rb");
  505. #elif defined(__APPLE__)
  506. char buffer[4096];
  507. uint32_t bufsize = sizeof(buffer);
  508. if (_NSGetExecutablePath(buffer, &bufsize) != 0) {
  509. return NULL;
  510. }
  511. runtime = fopen(buffer, "rb");
  512. #else
  513. char buffer[4096];
  514. ssize_t pathlen = readlink("/proc/self/exe", buffer, sizeof(buffer) - 1);
  515. if (pathlen <= 0) {
  516. perror("readlink(/proc/self/exe)");
  517. return NULL;
  518. }
  519. buffer[pathlen] = '\0';
  520. runtime = fopen(buffer, "rb");
  521. #endif
  522. // Get offsets. In version 0, we read it from the end of the file.
  523. if (blobinfo.version == 0) {
  524. uint64_t end, begin;
  525. fseek(runtime, -8, SEEK_END);
  526. end = ftell(runtime);
  527. fread(&begin, 8, 1, runtime);
  528. offset = (off_t)begin;
  529. size = (size_t)(end - begin);
  530. }
  531. // mmap the section indicated by the offset (or malloc/fread on windows)
  532. #ifdef _WIN32
  533. blob = (void *)malloc(size);
  534. assert(blob != NULL);
  535. fseek(runtime, (long)offset, SEEK_SET);
  536. fread(blob, size, 1, runtime);
  537. #else
  538. blob = (void *)mmap(0, size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fileno(runtime), offset);
  539. assert(blob != MAP_FAILED);
  540. #endif
  541. fclose(runtime);
  542. return blob;
  543. }
  544. /**
  545. * The inverse of map_blob.
  546. */
  547. static void unmap_blob(void *blob) {
  548. if (blob) {
  549. #ifdef _WIN32
  550. free(blob);
  551. #else
  552. munmap(blob, blobinfo.blob_size);
  553. #endif
  554. }
  555. }
  556. /**
  557. * Main entry point to deploy-stub.
  558. */
  559. #if defined(_WIN32) && PY_MAJOR_VERSION >= 3
  560. int wmain(int argc, wchar_t *argv[]) {
  561. #else
  562. int main(int argc, char *argv[]) {
  563. #endif
  564. int retval;
  565. struct _frozen *moddef;
  566. const char *log_filename;
  567. void *blob = NULL;
  568. log_filename = NULL;
  569. /*
  570. printf("blob_offset: %d\n", (int)blobinfo.blob_offset);
  571. printf("blob_size: %d\n", (int)blobinfo.blob_size);
  572. printf("version: %d\n", (int)blobinfo.version);
  573. printf("num_pointers: %d\n", (int)blobinfo.num_pointers);
  574. printf("codepage: %d\n", (int)blobinfo.codepage);
  575. printf("flags: %d\n", (int)blobinfo.flags);
  576. printf("reserved: %d\n", (int)blobinfo.reserved);
  577. */
  578. // If we have a blob offset, we have to map the blob to memory.
  579. if (blobinfo.version == 0 || blobinfo.blob_offset != 0) {
  580. void *blob = map_blob((off_t)blobinfo.blob_offset, (size_t)blobinfo.blob_size);
  581. assert(blob != NULL);
  582. // Offset the pointers in the header using the base mmap address.
  583. if (blobinfo.version > 0 && blobinfo.num_pointers > 0) {
  584. uint32_t i;
  585. assert(blobinfo.num_pointers <= MAX_NUM_POINTERS);
  586. for (i = 0; i < blobinfo.num_pointers; ++i) {
  587. // Only offset if the pointer is non-NULL. Except for the first
  588. // pointer, which may never be NULL and usually (but not always)
  589. // points to the beginning of the blob.
  590. if (i == 0 || blobinfo.pointers[i] != 0) {
  591. blobinfo.pointers[i] = (void *)((uintptr_t)blobinfo.pointers[i] + (uintptr_t)blob);
  592. }
  593. }
  594. if (blobinfo.num_pointers >= 12) {
  595. log_filename = blobinfo.pointers[11];
  596. }
  597. } else {
  598. blobinfo.pointers[0] = blob;
  599. }
  600. // Offset the pointers in the module table using the base mmap address.
  601. moddef = blobinfo.pointers[0];
  602. while (moddef->name) {
  603. moddef->name = (char *)((uintptr_t)moddef->name + (uintptr_t)blob);
  604. if (moddef->code != 0) {
  605. moddef->code = (unsigned char *)((uintptr_t)moddef->code + (uintptr_t)blob);
  606. }
  607. //printf("MOD: %s %p %d\n", moddef->name, (void*)moddef->code, moddef->size);
  608. moddef++;
  609. }
  610. }
  611. if (log_filename != NULL) {
  612. setup_logging(log_filename, (blobinfo.flags & F_log_append) != 0);
  613. }
  614. #ifdef _WIN32
  615. if (blobinfo.codepage != 0) {
  616. SetConsoleCP(blobinfo.codepage);
  617. SetConsoleOutputCP(blobinfo.codepage);
  618. }
  619. #endif
  620. // Run frozen application
  621. PyImport_FrozenModules = blobinfo.pointers[0];
  622. retval = Py_FrozenMain(argc, argv);
  623. unmap_blob(blob);
  624. return retval;
  625. }
  626. #ifdef WIN_UNICODE
  627. int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, wchar_t *lpCmdLine, int nCmdShow) {
  628. return wmain(__argc, __wargv);
  629. }
  630. #elif defined(_WIN32)
  631. int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, char *lpCmdLine, int nCmdShow) {
  632. return main(__argc, __argv);
  633. }
  634. #endif