PageRenderTime 59ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 1ms

/erts/etc/common/erlexec.c

https://github.com/cobusc/otp
C | 2326 lines | 2291 code | 8 blank | 27 comment | 5 complexity | 59fa0b011f9c20acbd797a77c7a01eb9 MD5 | raw file
Possible License(s): LGPL-2.1, MPL-2.0-no-copyleft-exception, Apache-2.0

Large files files are truncated, but you can click here to view the full file

  1. /*
  2. * %CopyrightBegin%
  3. *
  4. * Copyright Ericsson AB 1996-2018. All Rights Reserved.
  5. *
  6. * Licensed under the Apache License, Version 2.0 (the "License");
  7. * you may not use this file except in compliance with the License.
  8. * You may obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing, software
  13. * distributed under the License is distributed on an "AS IS" BASIS,
  14. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15. * See the License for the specific language governing permissions and
  16. * limitations under the License.
  17. *
  18. * %CopyrightEnd%
  19. */
  20. /*
  21. * This is a C version of the erl.exec Bourne shell script, including
  22. * additions required for Windows NT.
  23. */
  24. #include "etc_common.h"
  25. #include "erl_driver.h"
  26. #include "erl_misc_utils.h"
  27. #ifdef __WIN32__
  28. # include "erl_version.h"
  29. # include "init_file.h"
  30. # include <Shlobj.h>
  31. #endif
  32. #define NO 0
  33. #define YES 1
  34. #define DEFAULT_PROGNAME "erl"
  35. #ifdef __WIN32__
  36. #define INI_FILENAME L"erl.ini"
  37. #define INI_SECTION "erlang"
  38. #define DIRSEP "\\"
  39. #define PATHSEP ";"
  40. #define NULL_DEVICE "nul"
  41. #define BINARY_EXT ""
  42. #define DLL_EXT ".dll"
  43. #define EMULATOR_EXECUTABLE "beam.dll"
  44. #else
  45. #define PATHSEP ":"
  46. #define DIRSEP "/"
  47. #define NULL_DEVICE "/dev/null"
  48. #define BINARY_EXT ""
  49. #define EMULATOR_EXECUTABLE "beam"
  50. #endif
  51. #define QUOTE(s) s
  52. /* +M alloc_util allocators */
  53. static const char plusM_au_allocs[]= {
  54. 'u', /* all alloc_util allocators */
  55. 'B', /* binary_alloc */
  56. 'I', /* literal_alloc */
  57. 'D', /* std_alloc */
  58. 'E', /* ets_alloc */
  59. 'F', /* fix_alloc */
  60. 'H', /* eheap_alloc */
  61. 'L', /* ll_alloc */
  62. 'R', /* driver_alloc */
  63. 'S', /* sl_alloc */
  64. 'T', /* temp_alloc */
  65. 'X', /* exec_alloc */
  66. 'Z', /* test_alloc */
  67. '\0'
  68. };
  69. /* +M alloc_util allocator specific arguments */
  70. static char *plusM_au_alloc_switches[] = {
  71. "as",
  72. "asbcst",
  73. "atags",
  74. "acul",
  75. "acnl",
  76. "acfml",
  77. "e",
  78. "t",
  79. "lmbcs",
  80. "mbcgs",
  81. "mbsd",
  82. "mmbcs",
  83. "mmmbc",
  84. "mmsbc",
  85. "msbclt",
  86. "ramv",
  87. "rmbcmt",
  88. "rsbcmt",
  89. "rsbcst",
  90. "sbct",
  91. "smbcs",
  92. NULL
  93. };
  94. /* +M other arguments */
  95. static char *plusM_other_switches[] = {
  96. "ea",
  97. "ummc",
  98. "uycs",
  99. "usac",
  100. "im",
  101. "is",
  102. "it",
  103. "lpm",
  104. "Mamcbf",
  105. "Mrmcbf",
  106. "Mmcs",
  107. "Mscs",
  108. "Mscrfsd",
  109. "Msco",
  110. "Mscrpm",
  111. "Ye",
  112. "Ym",
  113. "Ytp",
  114. "Ytt",
  115. "Iscs",
  116. "Xscs",
  117. NULL
  118. };
  119. /* +s arguments with values */
  120. static char *pluss_val_switches[] = {
  121. "bt",
  122. "bwtdcpu",
  123. "bwtdio",
  124. "bwt",
  125. "cl",
  126. "ct",
  127. "ecio",
  128. "fwi",
  129. "tbt",
  130. "wct",
  131. "wtdcpu",
  132. "wtdio",
  133. "wt",
  134. "ws",
  135. "ss",
  136. "ssdcpu",
  137. "ssdio",
  138. "pp",
  139. "ub",
  140. NULL
  141. };
  142. /* +h arguments with values */
  143. static char *plush_val_switches[] = {
  144. "ms",
  145. "mbs",
  146. "pds",
  147. "max",
  148. "maxk",
  149. "maxel",
  150. "mqd",
  151. "",
  152. NULL
  153. };
  154. /* +r arguments with values */
  155. static char *plusr_val_switches[] = {
  156. "g",
  157. NULL
  158. };
  159. /* +z arguments with values */
  160. static char *plusz_val_switches[] = {
  161. "dbbl",
  162. "dntgc",
  163. "ebwt",
  164. NULL
  165. };
  166. /*
  167. * Define sleep(seconds) in terms of Sleep() on Windows.
  168. */
  169. #ifdef __WIN32__
  170. #define sleep(seconds) Sleep(seconds*1000)
  171. #endif
  172. #define SMP_SUFFIX ".smp"
  173. void usage(const char *switchname);
  174. static void usage_format(char *format, ...);
  175. void start_epmd(char *epmd);
  176. void error(char* format, ...);
  177. /*
  178. * Local functions.
  179. */
  180. static void usage_notsup(const char *switchname, const char *alt);
  181. static char **build_args_from_env(char *env_var);
  182. static char **build_args_from_string(char *env_var);
  183. static void initial_argv_massage(int *argc, char ***argv);
  184. static void get_parameters(int argc, char** argv);
  185. static void add_arg(char *new_arg);
  186. static void add_args(char *first_arg, ...);
  187. static void ensure_EargsSz(int sz);
  188. static void add_Eargs(char *new_arg);
  189. static void *emalloc(size_t size);
  190. static void *erealloc(void *p, size_t size);
  191. static void efree(void *p);
  192. static char* strsave(char* string);
  193. static int is_one_of_strings(char *str, char *strs[]);
  194. static char *write_str(char *to, const char *from);
  195. static void get_home(void);
  196. static void add_epmd_port(void);
  197. #ifdef __WIN32__
  198. static void get_start_erl_data(char *);
  199. static char* get_value(HKEY key, char* value_name, BOOL mustExit);
  200. static char* possibly_quote(char* arg);
  201. /*
  202. * Functions from win_erlexec.c
  203. */
  204. int start_win_emulator(char* emu, char *startprog,char** argv, int start_detached);
  205. int start_emulator(char* emu, char*start_prog, char** argv, int start_detached);
  206. #endif
  207. /*
  208. * Variables.
  209. */
  210. int nohup = 0;
  211. int keep_window = 0;
  212. static char **Eargsp = NULL; /* Emulator arguments (to appear first). */
  213. static int EargsSz = 0; /* Size of Eargsp */
  214. static int EargsCnt = 0; /* Number of emulator arguments. */
  215. static char **argsp = NULL; /* Common arguments. */
  216. static int argsCnt = 0; /* Number of common arguments */
  217. static int argsSz = 0; /* Size of argsp */
  218. static char tmpStr[10240]; /* Temporary string buffer. */
  219. static int verbose = 0; /* If non-zero, print some extra information. */
  220. static int start_detached = 0; /* If non-zero, the emulator should be
  221. * started detached (in the background).
  222. */
  223. static int start_smp_emu = 1; /* Start the smp emulator. */
  224. static const char* emu_type = 0; /* Type of emulator (lcnt, valgrind, etc) */
  225. #ifdef __WIN32__
  226. static char *start_emulator_program = NULL; /* For detachec mode -
  227. erl.exe/werl.exe */
  228. static char* key_val_name = ERLANG_VERSION; /* Used by the registry
  229. * access functions.
  230. */
  231. static char* boot_script = NULL; /* used by option -start_erl and -boot */
  232. static char* config_script = NULL; /* used by option -start_erl and -config */
  233. static HANDLE this_module_handle;
  234. static int run_werl;
  235. static WCHAR *utf8_to_utf16(unsigned char *bytes);
  236. static char *utf16_to_utf8(WCHAR *wstr);
  237. static WCHAR *latin1_to_utf16(char *str);
  238. #endif
  239. /*
  240. * Needed parameters to be fetched from the environment (Unix)
  241. * or the ini file (Win32).
  242. */
  243. static char* bindir; /* Location of executables. */
  244. static char* rootdir; /* Root location of Erlang installation. */
  245. static char* emu; /* Emulator to run. */
  246. static char* progname; /* Name of this program. */
  247. static char* home; /* Path of user's home directory. */
  248. static void
  249. set_env(char *key, char *value)
  250. {
  251. #ifdef __WIN32__
  252. WCHAR *wkey = latin1_to_utf16(key);
  253. WCHAR *wvalue = utf8_to_utf16(value);
  254. if (!SetEnvironmentVariableW(wkey, wvalue))
  255. error("SetEnvironmentVariable(\"%s\", \"%s\") failed!", key, value);
  256. efree(wkey);
  257. efree(wvalue);
  258. #else
  259. size_t size = strlen(key) + 1 + strlen(value) + 1;
  260. char *str = emalloc(size);
  261. sprintf(str, "%s=%s", key, value);
  262. if (putenv(str) != 0)
  263. error("putenv(\"%s\") failed!", str);
  264. #ifdef HAVE_COPYING_PUTENV
  265. efree(str);
  266. #endif
  267. #endif
  268. }
  269. static char *
  270. get_env(char *key)
  271. {
  272. #ifdef __WIN32__
  273. DWORD size = 32;
  274. WCHAR *value = NULL;
  275. WCHAR *wkey = latin1_to_utf16(key);
  276. char *res;
  277. while (1) {
  278. DWORD nsz;
  279. if (value)
  280. efree(value);
  281. value = emalloc(size*sizeof(WCHAR));
  282. SetLastError(0);
  283. nsz = GetEnvironmentVariableW(wkey, value, size);
  284. if (nsz == 0 && GetLastError() == ERROR_ENVVAR_NOT_FOUND) {
  285. efree(value);
  286. efree(wkey);
  287. return NULL;
  288. }
  289. if (nsz <= size) {
  290. efree(wkey);
  291. res = utf16_to_utf8(value);
  292. efree(value);
  293. return res;
  294. }
  295. size = nsz;
  296. }
  297. #else
  298. return getenv(key);
  299. #endif
  300. }
  301. static void
  302. free_env_val(char *value)
  303. {
  304. #ifdef __WIN32__
  305. if (value)
  306. free(value);
  307. #endif
  308. }
  309. /*
  310. * Add the type and architecture suffix to the program name if needed.
  311. * On Windows, we insert it just before ".DLL".
  312. */
  313. static char*
  314. add_extra_suffixes(char *prog)
  315. {
  316. char *res;
  317. char *p;
  318. int len;
  319. #ifdef __WIN32__
  320. char *dll_p;
  321. int dll = 0;
  322. #endif
  323. len = strlen(prog);
  324. /* Allocate enough extra space for suffixes */
  325. p = emalloc(len + 100);
  326. res = p;
  327. p = write_str(p, prog);
  328. #ifdef __WIN32__
  329. dll_p = res + len - 4;
  330. if (dll_p >= res) {
  331. if (dll_p[0] == '.' &&
  332. (dll_p[1] == 'd' || dll_p[1] == 'D') &&
  333. (dll_p[2] == 'l' || dll_p[2] == 'L') &&
  334. (dll_p[3] == 'l' || dll_p[3] == 'L')) {
  335. p = dll_p;
  336. dll = 1;
  337. }
  338. }
  339. #endif
  340. if (emu_type) {
  341. p = write_str(p, ".");
  342. p = write_str(p, emu_type);
  343. }
  344. if (start_smp_emu) {
  345. p = write_str(p, SMP_SUFFIX);
  346. }
  347. #ifdef __WIN32__
  348. if (dll) {
  349. p = write_str(p, DLL_EXT);
  350. }
  351. #endif
  352. return res;
  353. }
  354. #ifdef __WIN32__
  355. __declspec(dllexport) int win_erlexec(int argc, char **argv, HANDLE module, int windowed)
  356. #else
  357. int main(int argc, char **argv)
  358. #endif
  359. {
  360. int haltAfterwards = 0; /* If true, put 's erlang halt' at the end
  361. * of the arguments. */
  362. int isdistributed = 0;
  363. int no_epmd = 0;
  364. int i;
  365. char* s;
  366. char *epmd_prog = NULL;
  367. char *malloc_lib;
  368. int process_args = 1;
  369. int print_args_exit = 0;
  370. int print_qouted_cmd_exit = 0;
  371. erts_cpu_info_t *cpuinfo = NULL;
  372. char* emu_name;
  373. #ifdef __WIN32__
  374. this_module_handle = module;
  375. run_werl = windowed;
  376. /* if we started this erl just to get a detached emulator,
  377. * the arguments are already prepared for beam, so we skip
  378. * directly to start_emulator */
  379. s = get_env("ERL_CONSOLE_MODE");
  380. if (s != NULL && strcmp(s, "detached")==0) {
  381. free_env_val(s);
  382. s = get_env("ERL_EMULATOR_DLL");
  383. if (s != NULL) {
  384. argv[0] = strsave(s);
  385. } else {
  386. argv[0] = strsave(EMULATOR_EXECUTABLE);
  387. }
  388. ensure_EargsSz(argc + 1);
  389. memcpy((void *) Eargsp, (void *) argv, argc * sizeof(char *));
  390. Eargsp[argc] = NULL;
  391. emu = argv[0];
  392. start_emulator_program = strsave(argv[0]);
  393. goto skip_arg_massage;
  394. }
  395. free_env_val(s);
  396. #else
  397. int reset_cerl_detached = 0;
  398. s = get_env("CERL_DETACHED_PROG");
  399. if (s && strcmp(s, "") != 0) {
  400. emu = s;
  401. start_detached = 1;
  402. reset_cerl_detached = 1;
  403. ensure_EargsSz(argc + 1);
  404. memcpy((void *) Eargsp, (void *) argv, argc * sizeof(char *));
  405. Eargsp[argc] = emu;
  406. Eargsp[argc] = NULL;
  407. goto skip_arg_massage;
  408. }
  409. free_env_val(s);
  410. #endif
  411. initial_argv_massage(&argc, &argv); /* Merge with env; expand -args_file */
  412. i = 1;
  413. #ifdef __WIN32__
  414. /* Not used? /rickard */
  415. if ((argc > 2) && (strcmp(argv[i], "-regkey") == 0)) {
  416. key_val_name = strsave(argv[i+1]);
  417. i = 3;
  418. }
  419. #endif
  420. get_parameters(argc, argv);
  421. /*
  422. * Construct the path of the executable.
  423. */
  424. cpuinfo = erts_cpu_info_create();
  425. #if defined(__WIN32__) && defined(WIN32_ALWAYS_DEBUG)
  426. emu_type = "debug";
  427. #endif
  428. /* We need to do this before the ordinary processing. */
  429. malloc_lib = get_env("ERL_MALLOC_LIB");
  430. while (i < argc) {
  431. if (argv[i][0] == '+') {
  432. if (argv[i][1] == 'M' && argv[i][2] == 'Y' && argv[i][3] == 'm') {
  433. if (argv[i][4] == '\0') {
  434. if (++i < argc)
  435. malloc_lib = argv[i];
  436. else
  437. usage("+MYm");
  438. }
  439. else
  440. malloc_lib = &argv[i][4];
  441. }
  442. }
  443. else if (argv[i][0] == '-') {
  444. if (strcmp(argv[i], "-smp") == 0) {
  445. if (i + 1 >= argc)
  446. goto smp;
  447. if (strcmp(argv[i+1], "auto") == 0) {
  448. i++;
  449. } else if (strcmp(argv[i+1], "enable") == 0) {
  450. i++;
  451. smp_enable:
  452. ;
  453. } else if (strcmp(argv[i+1], "disable") == 0) {
  454. i++;
  455. smp_disable:
  456. usage_notsup("-smp disable", " Use \"+S 1\" instead.");
  457. } else {
  458. smp:
  459. ;
  460. }
  461. } else if (strcmp(argv[i], "-smpenable") == 0) {
  462. goto smp_enable;
  463. } else if (strcmp(argv[i], "-smpauto") == 0) {
  464. ;
  465. } else if (strcmp(argv[i], "-smpdisable") == 0) {
  466. goto smp_disable;
  467. } else if (strcmp(argv[i], "-extra") == 0) {
  468. break;
  469. } else if (strcmp(argv[i], "-emu_type") == 0) {
  470. if (i + 1 >= argc) {
  471. usage(argv[i]);
  472. }
  473. emu_type = argv[i+1];
  474. i++;
  475. }
  476. }
  477. i++;
  478. }
  479. erts_cpu_info_destroy(cpuinfo);
  480. cpuinfo = NULL;
  481. if (malloc_lib) {
  482. if (strcmp(malloc_lib, "libc") != 0)
  483. usage("+MYm");
  484. }
  485. emu = add_extra_suffixes(emu);
  486. emu_name = strsave(emu);
  487. erts_snprintf(tmpStr, sizeof(tmpStr), "%s" DIRSEP "%s" BINARY_EXT, bindir, emu);
  488. emu = strsave(tmpStr);
  489. s = get_env("ESCRIPT_NAME");
  490. if(s) {
  491. add_Eargs(s); /* argv[0] = scriptname*/
  492. } else {
  493. add_Eargs(emu); /* argv[0] = erl or cerl */
  494. }
  495. /* Add the bindir to the front of the PATH, and remove all subsequent
  496. * occurrences to avoid ballooning it on repeated up/downgrades. */
  497. s = get_env("PATH");
  498. if (s == NULL) {
  499. erts_snprintf(tmpStr, sizeof(tmpStr),
  500. "%s" PATHSEP "%s" DIRSEP "bin" PATHSEP, bindir, rootdir);
  501. } else if (strstr(s, rootdir) == NULL) {
  502. erts_snprintf(tmpStr, sizeof(tmpStr),
  503. "%s" PATHSEP "%s" DIRSEP "bin" PATHSEP "%s", bindir, rootdir, s);
  504. } else {
  505. const char *bindir_slug, *bindir_slug_index;
  506. int bindir_slug_length;
  507. const char *in_index;
  508. char *out_index;
  509. erts_snprintf(tmpStr, sizeof(tmpStr), "%s" PATHSEP, bindir);
  510. bindir_slug = strsave(tmpStr);
  511. bindir_slug_length = strlen(bindir_slug);
  512. out_index = &tmpStr[bindir_slug_length];
  513. in_index = s;
  514. while ((bindir_slug_index = strstr(in_index, bindir_slug))) {
  515. int block_length = (bindir_slug_index - in_index);
  516. memcpy(out_index, in_index, block_length);
  517. in_index = bindir_slug_index + bindir_slug_length;
  518. out_index += block_length;
  519. }
  520. strcpy(out_index, in_index);
  521. }
  522. free_env_val(s);
  523. set_env("PATH", tmpStr);
  524. i = 1;
  525. #ifdef __WIN32__
  526. #define ADD_BOOT_CONFIG \
  527. if (boot_script) \
  528. add_args("-boot", boot_script, NULL); \
  529. if (config_script) \
  530. add_args("-config", config_script, NULL);
  531. #else
  532. #define ADD_BOOT_CONFIG
  533. #endif
  534. get_home();
  535. add_args("-home", home, NULL);
  536. add_epmd_port();
  537. add_arg("--");
  538. while (i < argc) {
  539. if (!process_args) { /* Copy arguments after '-extra' */
  540. add_arg(argv[i]);
  541. i++;
  542. } else {
  543. switch (argv[i][0]) {
  544. case '-':
  545. switch (argv[i][1]) {
  546. #ifdef __WIN32__
  547. case 'b':
  548. if (strcmp(argv[i], "-boot") == 0) {
  549. if (boot_script)
  550. error("Conflicting -start_erl and -boot options");
  551. if (i+1 >= argc)
  552. usage("-boot");
  553. boot_script = strsave(argv[i+1]);
  554. i++;
  555. }
  556. else {
  557. add_arg(argv[i]);
  558. }
  559. break;
  560. #endif
  561. case 'c':
  562. if (strcmp(argv[i], "-compile") == 0) {
  563. /*
  564. * Note that the shell script erl.exec does an recursive call
  565. * on itself here. We'll avoid doing that.
  566. */
  567. add_args("-noshell", "-noinput", "-s", "c", "lc_batch",
  568. NULL);
  569. add_Eargs("-B");
  570. haltAfterwards = 0;
  571. }
  572. #ifdef __WIN32__
  573. else if (strcmp(argv[i], "-config") == 0){
  574. if (config_script)
  575. error("Conflicting -start_erl and -config options");
  576. if (i+1 >= argc)
  577. usage("-config");
  578. config_script = strsave(argv[i+1]);
  579. i++;
  580. }
  581. #endif
  582. else {
  583. add_arg(argv[i]);
  584. }
  585. break;
  586. case 'd':
  587. if (strcmp(argv[i], "-detached") != 0) {
  588. add_arg(argv[i]);
  589. } else {
  590. start_detached = 1;
  591. add_args("-noshell", "-noinput", NULL);
  592. }
  593. break;
  594. case 'i':
  595. if (strcmp(argv[i], "-instr") == 0) {
  596. add_Eargs("-Mim");
  597. add_Eargs("true");
  598. }
  599. else
  600. add_arg(argv[i]);
  601. break;
  602. case 'e':
  603. if (strcmp(argv[i], "-extra") == 0) {
  604. process_args = 0;
  605. ADD_BOOT_CONFIG;
  606. add_arg(argv[i]);
  607. } else if (strcmp(argv[i], "-emu_args") == 0) { /* -emu_args */
  608. verbose = 1;
  609. } else if (strcmp(argv[i], "-emu_args_exit") == 0) {
  610. print_args_exit = 1;
  611. } else if (strcmp(argv[i], "-emu_name_exit") == 0) {
  612. printf("%s\n", emu_name);
  613. exit(0);
  614. } else if (strcmp(argv[i], "-emu_qouted_cmd_exit") == 0) {
  615. print_qouted_cmd_exit = 1;
  616. } else if (strcmp(argv[i], "-env") == 0) { /* -env VARNAME VARVALUE */
  617. if (i+2 >= argc)
  618. usage("-env");
  619. set_env(argv[i+1], argv[i+2]);
  620. i += 2;
  621. } else if (strcmp(argv[i], "-epmd") == 0) {
  622. if (i+1 >= argc)
  623. usage("-epmd");
  624. epmd_prog = argv[i+1];
  625. ++i;
  626. } else {
  627. add_arg(argv[i]);
  628. }
  629. break;
  630. case 'k':
  631. if (strcmp(argv[i], "-keep_window") == 0) {
  632. keep_window = 1;
  633. } else
  634. add_arg(argv[i]);
  635. break;
  636. case 'm':
  637. /*
  638. * Note that the shell script erl.exec does an recursive call
  639. * on itself here. We'll avoid doing that.
  640. */
  641. if (strcmp(argv[i], "-make") == 0) {
  642. add_args("-noshell", "-noinput", "-s", "make", "all_or_nothing", NULL);
  643. add_Eargs("-B");
  644. haltAfterwards = 1;
  645. i = argc; /* Skip rest of command line */
  646. } else if (strcmp(argv[i], "-man") == 0) {
  647. #if defined(__WIN32__)
  648. error("-man not supported on Windows");
  649. #else
  650. argv[i] = "man";
  651. erts_snprintf(tmpStr, sizeof(tmpStr), "%s/man", rootdir);
  652. set_env("MANPATH", tmpStr);
  653. execvp("man", argv+i);
  654. error("Could not execute the 'man' command.");
  655. #endif
  656. } else
  657. add_arg(argv[i]);
  658. break;
  659. case 'n':
  660. if (strcmp(argv[i], "-name") == 0) { /* -name NAME */
  661. if (i+1 >= argc)
  662. usage("-name");
  663. /*
  664. * Note: Cannot use add_args() here, due to non-defined
  665. * evaluation order.
  666. */
  667. add_arg(argv[i]);
  668. add_arg(argv[i+1]);
  669. isdistributed = 1;
  670. i++;
  671. } else if (strcmp(argv[i], "-noinput") == 0) {
  672. add_args("-noshell", "-noinput", NULL);
  673. } else if (strcmp(argv[i], "-nohup") == 0) {
  674. add_arg("-nohup");
  675. nohup = 1;
  676. } else if (strcmp(argv[i], "-no_epmd") == 0) {
  677. add_arg("-no_epmd");
  678. no_epmd = 1;
  679. } else {
  680. add_arg(argv[i]);
  681. }
  682. break;
  683. case 's': /* -sname NAME */
  684. if (strcmp(argv[i], "-sname") == 0) {
  685. if (i+1 >= argc)
  686. usage("-sname");
  687. add_arg(argv[i]);
  688. add_arg(argv[i+1]);
  689. isdistributed = 1;
  690. i++;
  691. }
  692. #ifdef __WIN32__
  693. else if (strcmp(argv[i], "-service_event") == 0) {
  694. add_arg(argv[i]);
  695. add_arg(argv[i+1]);
  696. i++;
  697. }
  698. else if (strcmp(argv[i], "-start_erl") == 0) {
  699. if (i+1 < argc && argv[i+1][0] != '-') {
  700. get_start_erl_data(argv[i+1]);
  701. i++;
  702. } else
  703. get_start_erl_data((char *) NULL);
  704. }
  705. #endif
  706. else if (strcmp(argv[i], "-start_epmd") == 0) {
  707. if (i+1 >= argc)
  708. usage("-start_epmd");
  709. if (strcmp(argv[i+1], "true") == 0) {
  710. /* The default */
  711. no_epmd = 0;
  712. }
  713. else if (strcmp(argv[i+1], "false") == 0) {
  714. no_epmd = 1;
  715. }
  716. else
  717. usage_format("Expected boolean argument for \'-start_epmd\'.\n");
  718. add_arg(argv[i]);
  719. add_arg(argv[i+1]);
  720. i++;
  721. }
  722. else
  723. add_arg(argv[i]);
  724. break;
  725. case 'v': /* -version */
  726. if (strcmp(argv[i], "-version") == 0) {
  727. add_Eargs("-V");
  728. } else {
  729. add_arg(argv[i]);
  730. }
  731. break;
  732. default:
  733. add_arg(argv[i]);
  734. break;
  735. } /* switch(argv[i][1] */
  736. break;
  737. case '+':
  738. switch (argv[i][1]) {
  739. case '#':
  740. case 'a':
  741. case 'A':
  742. case 'b':
  743. case 'C':
  744. case 'e':
  745. case 'i':
  746. case 'n':
  747. case 'P':
  748. case 'Q':
  749. case 't':
  750. case 'T':
  751. case 'R':
  752. case 'W':
  753. case 'K':
  754. if (argv[i][2] != '\0')
  755. goto the_default;
  756. if (i+1 >= argc)
  757. usage(argv[i]);
  758. argv[i][0] = '-';
  759. add_Eargs(argv[i]);
  760. add_Eargs(argv[i+1]);
  761. i++;
  762. break;
  763. case 'I':
  764. if (argv[i][2] == 'O' && (argv[i][3] == 't' || argv[i][3] == 'p')) {
  765. if (argv[i][4] != '\0')
  766. goto the_default;
  767. argv[i][0] = '-';
  768. add_Eargs(argv[i]);
  769. add_Eargs(argv[i+1]);
  770. i++;
  771. break;
  772. }
  773. if (argv[i][2] == 'O' && argv[i][3] == 'P' &&
  774. (argv[i][4] == 't' || argv[i][4] == 'p')) {
  775. if (argv[i][5] != '\0')
  776. goto the_default;
  777. argv[i][0] = '-';
  778. add_Eargs(argv[i]);
  779. add_Eargs(argv[i+1]);
  780. i++;
  781. break;
  782. }
  783. usage(argv[i]);
  784. break;
  785. case 'S':
  786. if (argv[i][2] == 'P') {
  787. if (argv[i][3] != '\0')
  788. goto the_default;
  789. }
  790. else if (argv[i][2] == 'D') {
  791. char* type = argv[i]+3;
  792. if (strncmp(type, "cpu", 3) != 0 &&
  793. strncmp(type, "Pcpu", 4) != 0 &&
  794. strncmp(type, "io", 2) != 0)
  795. usage(argv[i]);
  796. if ((argv[i][3] == 'c' && argv[i][6] != '\0') ||
  797. (argv[i][3] == 'P' && argv[i][7] != '\0') ||
  798. (argv[i][3] == 'i' && argv[i][5] != '\0'))
  799. goto the_default;
  800. }
  801. else if (argv[i][2] != '\0')
  802. goto the_default;
  803. if (i+1 >= argc)
  804. usage(argv[i]);
  805. argv[i][0] = '-';
  806. add_Eargs(argv[i]);
  807. add_Eargs(argv[i+1]);
  808. i++;
  809. break;
  810. case 'B':
  811. argv[i][0] = '-';
  812. if (argv[i][2] != '\0') {
  813. if ((argv[i][2] != 'i') &&
  814. (argv[i][2] != 'c') &&
  815. (argv[i][2] != 'd')) {
  816. usage(argv[i]);
  817. } else {
  818. add_Eargs(argv[i]);
  819. break;
  820. }
  821. }
  822. if (i+1 < argc) {
  823. if ((argv[i+1][0] != '-') &&
  824. (argv[i+1][0] != '+')) {
  825. if (argv[i+1][0] == 'i') {
  826. add_Eargs(argv[i]);
  827. add_Eargs(argv[i+1]);
  828. i++;
  829. break;
  830. } else {
  831. usage(argv[i]);
  832. }
  833. }
  834. }
  835. add_Eargs(argv[i]);
  836. break;
  837. case 'c':
  838. argv[i][0] = '-';
  839. if (argv[i][2] == '\0' && i+1 < argc) {
  840. if (strcmp(argv[i+1], "true") == 0
  841. || strcmp(argv[i+1], "false") == 0) {
  842. add_Eargs(argv[i]);
  843. add_Eargs(argv[i+1]);
  844. i++;
  845. break;
  846. }
  847. }
  848. add_Eargs(argv[i]);
  849. break;
  850. case 'M': {
  851. int x;
  852. for (x = 0; plusM_au_allocs[x]; x++)
  853. if (plusM_au_allocs[x] == argv[i][2])
  854. break;
  855. if ((plusM_au_allocs[x]
  856. && is_one_of_strings(&argv[i][3],
  857. plusM_au_alloc_switches))
  858. || is_one_of_strings(&argv[i][2],
  859. plusM_other_switches)) {
  860. if (i+1 >= argc
  861. || argv[i+1][0] == '-'
  862. || argv[i+1][0] == '+')
  863. usage(argv[i]);
  864. argv[i][0] = '-';
  865. add_Eargs(argv[i]);
  866. add_Eargs(argv[i+1]);
  867. i++;
  868. }
  869. else
  870. goto the_default;
  871. break;
  872. }
  873. case 'h':
  874. if (!is_one_of_strings(&argv[i][2], plush_val_switches)) {
  875. goto the_default;
  876. } else {
  877. if (i+1 >= argc
  878. || argv[i+1][0] == '-'
  879. || argv[i+1][0] == '+')
  880. usage(argv[i]);
  881. argv[i][0] = '-';
  882. add_Eargs(argv[i]);
  883. add_Eargs(argv[i+1]);
  884. i++;
  885. }
  886. break;
  887. case 'r':
  888. if (!is_one_of_strings(&argv[i][2],
  889. plusr_val_switches))
  890. goto the_default;
  891. else {
  892. if (i+1 >= argc
  893. || argv[i+1][0] == '-'
  894. || argv[i+1][0] == '+')
  895. usage(argv[i]);
  896. argv[i][0] = '-';
  897. add_Eargs(argv[i]);
  898. add_Eargs(argv[i+1]);
  899. i++;
  900. }
  901. break;
  902. case 's':
  903. if (!is_one_of_strings(&argv[i][2],
  904. pluss_val_switches))
  905. goto the_default;
  906. else {
  907. if (i+1 >= argc
  908. || argv[i+1][0] == '-'
  909. || argv[i+1][0] == '+')
  910. usage(argv[i]);
  911. argv[i][0] = '-';
  912. add_Eargs(argv[i]);
  913. add_Eargs(argv[i+1]);
  914. i++;
  915. }
  916. break;
  917. case 'p':
  918. if (argv[i][2] != 'c' || argv[i][3] != '\0')
  919. goto the_default;
  920. if (i+1 >= argc)
  921. usage(argv[i]);
  922. argv[i][0] = '-';
  923. add_Eargs(argv[i]);
  924. add_Eargs(argv[i+1]);
  925. i++;
  926. break;
  927. case 'z':
  928. if (!is_one_of_strings(&argv[i][2], plusz_val_switches)) {
  929. goto the_default;
  930. } else {
  931. if (i+1 >= argc
  932. || argv[i+1][0] == '-'
  933. || argv[i+1][0] == '+')
  934. usage(argv[i]);
  935. argv[i][0] = '-';
  936. add_Eargs(argv[i]);
  937. add_Eargs(argv[i+1]);
  938. i++;
  939. }
  940. break;
  941. default:
  942. the_default:
  943. argv[i][0] = '-'; /* Change +option to -option. */
  944. add_Eargs(argv[i]);
  945. }
  946. break;
  947. default:
  948. add_arg(argv[i]);
  949. } /* switch(argv[i][0] */
  950. i++;
  951. }
  952. }
  953. if (process_args) {
  954. ADD_BOOT_CONFIG;
  955. }
  956. #undef ADD_BOOT_CONFIG
  957. /* Doesn't conflict with -extra, since -make skips all the rest of
  958. the arguments. */
  959. if (haltAfterwards) {
  960. add_args("-s", "erlang", "halt", NULL);
  961. }
  962. if (isdistributed && !no_epmd)
  963. start_epmd(epmd_prog);
  964. #if (! defined(__WIN32__)) && defined(DEBUG)
  965. if (start_detached && get_env("ERL_CONSOLE_MODE")) {
  966. /* Start the emulator within an xterm.
  967. * Move up all arguments and insert
  968. * "xterm -e " first.
  969. * The path must be searched for this
  970. * to work, i.e execvp() must be used.
  971. */
  972. ensure_EargsSz(EargsCnt+2);
  973. for (i = EargsCnt; i > 0; i--)
  974. Eargsp[i+1] = Eargsp[i-1]; /* Two args to insert */
  975. EargsCnt += 2; /* Two args to insert */
  976. Eargsp[0] = emu = "xterm";
  977. Eargsp[1] = "-e";
  978. }
  979. #endif
  980. add_Eargs("--");
  981. add_Eargs("-root");
  982. add_Eargs(rootdir);
  983. add_Eargs("-progname");
  984. add_Eargs(progname);
  985. add_Eargs("--");
  986. ensure_EargsSz(EargsCnt + argsCnt + 1);
  987. for (i = 0; i < argsCnt; i++)
  988. Eargsp[EargsCnt++] = argsp[i];
  989. Eargsp[EargsCnt] = NULL;
  990. if (print_qouted_cmd_exit) {
  991. printf("\"%s\" ", emu);
  992. for (i = 1; i < EargsCnt; i++)
  993. printf("\"%s\" ", Eargsp[i]);
  994. printf("\n");
  995. exit(0);
  996. }
  997. if (print_args_exit) {
  998. for (i = 1; i < EargsCnt; i++)
  999. printf("%s\n", Eargsp[i]);
  1000. exit(0);
  1001. }
  1002. if (verbose) {
  1003. printf("Executing: %s", emu);
  1004. for (i = 0; i < EargsCnt; i++)
  1005. printf(" %s", Eargsp[i]);
  1006. printf("\n\n");
  1007. }
  1008. #ifdef __WIN32__
  1009. if (EargsSz != EargsCnt + 1)
  1010. Eargsp = (char **) erealloc((void *) Eargsp, (EargsCnt + 1) *
  1011. sizeof(char *));
  1012. efree((void *) argsp);
  1013. skip_arg_massage:
  1014. /*DebugBreak();*/
  1015. if (run_werl) {
  1016. if (start_detached) {
  1017. char *p;
  1018. /* transform werl to erl */
  1019. p = start_emulator_program+strlen(start_emulator_program);
  1020. while (--p >= start_emulator_program && *p != '/' && *p != '\\' &&
  1021. *p != 'W' && *p != 'w')
  1022. ;
  1023. if (p >= start_emulator_program && (*p == 'W' || *p == 'w') &&
  1024. (p[1] == 'E' || p[1] == 'e') && (p[2] == 'R' || p[2] == 'r') &&
  1025. (p[3] == 'L' || p[3] == 'l')) {
  1026. memmove(p,p+1,strlen(p));
  1027. }
  1028. }
  1029. return start_win_emulator(emu, start_emulator_program, Eargsp, start_detached);
  1030. } else {
  1031. return start_emulator(emu, start_emulator_program, Eargsp, start_detached);
  1032. }
  1033. #else
  1034. skip_arg_massage:
  1035. if (start_detached) {
  1036. int status = fork();
  1037. if (status != 0) /* Parent */
  1038. return 0;
  1039. if (reset_cerl_detached)
  1040. putenv("CERL_DETACHED_PROG=");
  1041. /* Detach from controlling terminal */
  1042. #ifdef HAVE_SETSID
  1043. setsid();
  1044. #elif defined(TIOCNOTTY)
  1045. {
  1046. int fd = open("/dev/tty", O_RDWR);
  1047. if (fd >= 0) {
  1048. ioctl(fd, TIOCNOTTY, NULL);
  1049. close(fd);
  1050. }
  1051. }
  1052. #endif
  1053. status = fork();
  1054. if (status != 0) /* Parent */
  1055. return 0;
  1056. /*
  1057. * Grandchild.
  1058. */
  1059. close(0);
  1060. open("/dev/null", O_RDONLY);
  1061. close(1);
  1062. open("/dev/null", O_WRONLY);
  1063. close(2);
  1064. open("/dev/null", O_WRONLY);
  1065. #ifdef DEBUG
  1066. execvp(emu, Eargsp); /* "xterm ..." needs to search the path */
  1067. #endif
  1068. }
  1069. #ifdef DEBUG
  1070. else
  1071. #endif
  1072. {
  1073. execv(emu, Eargsp);
  1074. }
  1075. if (errno == ENOENT) {
  1076. error("The emulator \'%s\' does not exist.", emu);
  1077. } else {
  1078. error("Error %d executing \'%s\'.", errno, emu);
  1079. }
  1080. return 1;
  1081. #endif
  1082. }
  1083. static void
  1084. usage_aux(void)
  1085. {
  1086. fprintf(stderr,
  1087. "Usage: erl [-version] [-sname NAME | -name NAME] "
  1088. "[-noshell] [-noinput] [-env VAR VALUE] [-compile file ...] "
  1089. #ifdef __WIN32__
  1090. "[-start_erl [datafile]] "
  1091. #endif
  1092. "[-make] [-man [manopts] MANPAGE] [-x] [-emu_args] [-start_epmd BOOLEAN] "
  1093. "[-args_file FILENAME] [+A THREADS] [+a SIZE] [+B[c|d|i]] [+c [BOOLEAN]] "
  1094. "[+C MODE] [+h HEAP_SIZE_OPTION] [+K BOOLEAN] "
  1095. "[+l] [+M<SUBSWITCH> <ARGUMENT>] [+P MAX_PROCS] [+Q MAX_PORTS] "
  1096. "[+R COMPAT_REL] "
  1097. "[+r] [+rg READER_GROUPS_LIMIT] [+s SCHEDULER_OPTION] "
  1098. "[+S NO_SCHEDULERS:NO_SCHEDULERS_ONLINE] "
  1099. "[+SP PERCENTAGE_SCHEDULERS:PERCENTAGE_SCHEDULERS_ONLINE] "
  1100. "[+T LEVEL] [+V] [+v] "
  1101. "[+W<i|w|e>] [+z MISC_OPTION] [args ...]\n");
  1102. exit(1);
  1103. }
  1104. void
  1105. usage(const char *switchname)
  1106. {
  1107. fprintf(stderr, "Missing argument(s) for \'%s\'.\n", switchname);
  1108. usage_aux();
  1109. }
  1110. static void
  1111. usage_notsup(const char *switchname, const char *alt)
  1112. {
  1113. fprintf(stderr, "Argument \'%s\' not supported.%s\n", switchname, alt);
  1114. usage_aux();
  1115. }
  1116. static void
  1117. usage_format(char *format, ...)
  1118. {
  1119. va_list args;
  1120. va_start(args, format);
  1121. vfprintf(stderr, format, args);
  1122. va_end(args);
  1123. usage_aux();
  1124. }
  1125. void
  1126. start_epmd(char *epmd)
  1127. {
  1128. char epmd_cmd[MAXPATHLEN+100];
  1129. #ifdef __WIN32__
  1130. char* arg1 = NULL;
  1131. #endif
  1132. int result;
  1133. if (!epmd) {
  1134. epmd = epmd_cmd;
  1135. #ifdef __WIN32__
  1136. erts_snprintf(epmd_cmd, sizeof(epmd_cmd), "%s" DIRSEP "epmd", bindir);
  1137. arg1 = "-daemon";
  1138. #else
  1139. erts_snprintf(epmd_cmd, sizeof(epmd_cmd), "\"%s" DIRSEP "epmd\" -daemon", bindir);
  1140. #endif
  1141. }
  1142. #ifdef __WIN32__
  1143. if (arg1 != NULL) {
  1144. strcat(epmd, " ");
  1145. strcat(epmd, arg1);
  1146. }
  1147. {
  1148. wchar_t wcepmd[MAXPATHLEN+100];
  1149. STARTUPINFOW start;
  1150. PROCESS_INFORMATION pi;
  1151. memset(&start, 0, sizeof (start));
  1152. start.cb = sizeof (start);
  1153. MultiByteToWideChar(CP_UTF8, 0, epmd, -1, wcepmd, MAXPATHLEN+100);
  1154. if (!CreateProcessW(NULL, wcepmd, NULL, NULL, FALSE,
  1155. CREATE_DEFAULT_ERROR_MODE | DETACHED_PROCESS,
  1156. NULL, NULL, &start, &pi))
  1157. result = -1;
  1158. else
  1159. result = 0;
  1160. }
  1161. #else
  1162. result = system(epmd);
  1163. #endif
  1164. if (result == -1) {
  1165. fprintf(stderr, "Error spawning %s (error %d)\n", epmd_cmd,errno);
  1166. exit(1);
  1167. }
  1168. }
  1169. static void
  1170. add_arg(char *new_arg)
  1171. {
  1172. if (argsCnt >= argsSz)
  1173. argsp = (char **) erealloc((void *) argsp,
  1174. sizeof(char *) * (argsSz += 20));
  1175. argsp[argsCnt++] = QUOTE(new_arg);
  1176. }
  1177. static void
  1178. add_args(char *first_arg, ...)
  1179. {
  1180. va_list ap;
  1181. char* arg;
  1182. add_arg(first_arg);
  1183. va_start(ap, first_arg);
  1184. while ((arg = va_arg(ap, char *)) != NULL) {
  1185. add_arg(arg);
  1186. }
  1187. va_end(ap);
  1188. }
  1189. static void
  1190. ensure_EargsSz(int sz)
  1191. {
  1192. if (EargsSz < sz)
  1193. Eargsp = (char **) erealloc((void *) Eargsp,
  1194. sizeof(char *) * (EargsSz = sz));
  1195. }
  1196. static void
  1197. add_Eargs(char *new_arg)
  1198. {
  1199. if (EargsCnt >= EargsSz)
  1200. Eargsp = (char **) erealloc((void *) Eargsp,
  1201. sizeof(char *) * (EargsSz += 20));
  1202. Eargsp[EargsCnt++] = QUOTE(new_arg);
  1203. }
  1204. #if !defined(__WIN32__)
  1205. void error(char* format, ...)
  1206. {
  1207. char sbuf[1024];
  1208. va_list ap;
  1209. va_start(ap, format);
  1210. erts_vsnprintf(sbuf, sizeof(sbuf), format, ap);
  1211. va_end(ap);
  1212. fprintf(stderr, "erlexec: %s\n", sbuf);
  1213. exit(1);
  1214. }
  1215. #endif
  1216. static void *
  1217. emalloc(size_t size)
  1218. {
  1219. void *p = malloc(size);
  1220. if (p == NULL)
  1221. error("Insufficient memory");
  1222. return p;
  1223. }
  1224. static void *
  1225. erealloc(void *p, size_t size)
  1226. {
  1227. void *res = realloc(p, size);
  1228. if (res == NULL)
  1229. error("Insufficient memory");
  1230. return res;
  1231. }
  1232. static void
  1233. efree(void *p)
  1234. {
  1235. free(p);
  1236. }
  1237. static int
  1238. is_one_of_strings(char *str, char *strs[])
  1239. {
  1240. int i, j;
  1241. for (i = 0; strs[i]; i++) {
  1242. for (j = 0; str[j] && strs[i][j] && str[j] == strs[i][j]; j++);
  1243. if (!str[j] && !strs[i][j])
  1244. return 1;
  1245. }
  1246. return 0;
  1247. }
  1248. static char *write_str(char *to, const char *from)
  1249. {
  1250. while (*from)
  1251. *(to++) = *(from++);
  1252. *to = '\0';
  1253. return to;
  1254. }
  1255. char*
  1256. strsave(char* string)
  1257. {
  1258. char* p = emalloc(strlen(string)+1);
  1259. strcpy(p, string);
  1260. return p;
  1261. }
  1262. #if defined(__WIN32__)
  1263. static void get_start_erl_data(char *file)
  1264. {
  1265. int fp;
  1266. char tmpbuffer[512];
  1267. char start_erl_data[512];
  1268. int bytesread;
  1269. char* env;
  1270. char* reldir;
  1271. char* otpstring;
  1272. char* tprogname;
  1273. if (boot_script)
  1274. error("Conflicting -start_erl and -boot options");
  1275. if (config_script)
  1276. error("Conflicting -start_erl and -config options");
  1277. env = get_env("RELDIR");
  1278. if (env)
  1279. reldir = strsave(env);
  1280. else {
  1281. erts_snprintf(tmpbuffer, sizeof(tmpbuffer), "%s/releases", rootdir);
  1282. reldir = strsave(tmpbuffer);
  1283. }
  1284. free_env_val(env);
  1285. if (file == NULL)
  1286. erts_snprintf(start_erl_data, sizeof(start_erl_data), "%s/start_erl.data", reldir);
  1287. else
  1288. erts_snprintf(start_erl_data, sizeof(start_erl_data), "%s", file);
  1289. fp = _open(start_erl_data, _O_RDONLY );
  1290. if( fp == -1 )
  1291. error( "open failed on %s",start_erl_data );
  1292. else {
  1293. if( ( bytesread = _read( fp, tmpbuffer, 512 ) ) <= 0 )
  1294. error( "Problem reading file %s", start_erl_data );
  1295. else {
  1296. tmpbuffer[bytesread]='\0';
  1297. if ((otpstring = strchr(tmpbuffer,' ')) != NULL) {
  1298. *otpstring = '\0';
  1299. otpstring++;
  1300. /*
  1301. * otpstring is the otpversion
  1302. * tmpbuffer is the emuversion
  1303. */
  1304. }
  1305. }
  1306. }
  1307. tprogname = otpstring;
  1308. while (*tprogname) {
  1309. if (*tprogname <= ' ') {
  1310. *tprogname='\0';
  1311. break;
  1312. }
  1313. tprogname++;
  1314. }
  1315. bindir = emalloc(512);
  1316. erts_snprintf(bindir,512,"%s/erts-%s/bin",rootdir,tmpbuffer);
  1317. /* BINDIR=$ROOTDIR/erts-$ERTS_VSN/bin */
  1318. tprogname = progname;
  1319. progname = emalloc(strlen(tprogname) + 20);
  1320. erts_snprintf(progname,strlen(tprogname) + 20,"%s -start_erl",tprogname);
  1321. boot_script = emalloc(512);
  1322. config_script = emalloc(512);
  1323. erts_snprintf(boot_script, 512, "%s/%s/start", reldir, otpstring);
  1324. erts_snprintf(config_script, 512, "%s/%s/sys", reldir, otpstring);
  1325. }
  1326. static wchar_t *replace_filename(wchar_t *path, wchar_t *new_base)
  1327. {
  1328. int plen = wcslen(path);
  1329. wchar_t *res = (wchar_t *) emalloc((plen+wcslen(new_base)+1)*sizeof(wchar_t));
  1330. wchar_t *p;
  1331. wcscpy(res,path);
  1332. for (p = res+plen-1 ;p >= res && *p != L'\\'; --p)
  1333. ;
  1334. *(p+1) =L'\0';
  1335. wcscat(res,new_base);
  1336. return res;
  1337. }
  1338. static char *path_massage(wchar_t *long_path)
  1339. {
  1340. char *p;
  1341. int len;
  1342. len = WideCharToMultiByte(CP_UTF8, 0, long_path, -1, NULL, 0, NULL, NULL);
  1343. p = emalloc(len*sizeof(char));
  1344. WideCharToMultiByte(CP_UTF8, 0, long_path, -1, p, len, NULL, NULL);
  1345. return p;
  1346. }
  1347. static char *do_lookup_in_section(InitSection *inis, char *name,
  1348. char *section, wchar_t *filename, int is_path)
  1349. {
  1350. char *p = lookup_init_entry(inis, name);
  1351. if (p == NULL) {
  1352. error("Could not find key %s in section %s of file %S",
  1353. name,section,filename);
  1354. }
  1355. return strsave(p);
  1356. }
  1357. // Setup bindir, rootdir and progname as utf8 buffers
  1358. static void get_parameters(int argc, char** argv)
  1359. {
  1360. wchar_t *p;
  1361. wchar_t buffer[MAX_PATH];
  1362. wchar_t *ini_filename;
  1363. HANDLE module = GetModuleHandle(NULL); /* This might look strange, but we want the erl.ini
  1364. that resides in the same dir as erl.exe, not
  1365. an erl.ini in our directory */
  1366. InitFile *inif;
  1367. InitSection *inis;
  1368. if (module == NULL) {
  1369. error("Cannot GetModuleHandle()");
  1370. }
  1371. if (GetModuleFileNameW(module,buffer,MAX_PATH) == 0) {
  1372. error("Could not GetModuleFileName");
  1373. }
  1374. ini_filename = replace_filename(buffer,INI_FILENAME);
  1375. if ((inif = load_init_file(ini_filename)) == NULL) {
  1376. wchar_t wbindir[MAX_PATH];
  1377. wchar_t wrootdir[MAX_PATH];
  1378. /* Assume that the path is absolute and that
  1379. it does not contain any symbolic link */
  1380. /* Determine bindir */
  1381. if (GetEnvironmentVariableW(L"ERLEXEC_DIR", buffer, MAX_PATH) == 0) {
  1382. wcscpy(buffer, ini_filename);
  1383. for (p = buffer+wcslen(buffer)-1; p >= buffer && *p != L'\\'; --p)
  1384. ;
  1385. *p = L'\0';
  1386. }
  1387. bindir = path_massage(buffer);
  1388. /* Determine rootdir */
  1389. for (p = buffer+wcslen(buffer)-1; p >= buffer && *p != L'\\'; --p)
  1390. ;
  1391. p--;
  1392. for (;p >= buffer && *p != L'\\'; --p)
  1393. ;
  1394. *p =L'\0';
  1395. rootdir = path_massage(buffer);
  1396. /* Hardcoded progname */
  1397. progname = strsave(DEFAULT_PROGNAME);
  1398. } else {
  1399. if ((inis = lookup_init_section(inif,INI_SECTION)) == NULL) {
  1400. error("Could not find section %s in init file %s",
  1401. INI_SECTION, ini_filename);
  1402. }
  1403. bindir = do_lookup_in_section(inis, "Bindir", INI_SECTION, ini_filename,1);
  1404. rootdir = do_lookup_in_section(inis, "Rootdir", INI_SECTION,
  1405. ini_filename,1);
  1406. progname = do_lookup_in_section(inis, "Progname", INI_SECTION,
  1407. ini_filename,0);
  1408. free_init_file(inif);
  1409. }
  1410. emu = EMULATOR_EXECUTABLE;
  1411. start_emulator_program = strsave(argv[0]);
  1412. free(ini_filename);
  1413. }
  1414. static void
  1415. get_home(void)
  1416. {
  1417. wchar_t *profile;
  1418. char* homedrive;
  1419. char* homepath;
  1420. homedrive = get_env("HOMEDRIVE");
  1421. homepath = get_env("HOMEPATH");
  1422. if (!homedrive || !homepath) {
  1423. if (SHGetKnownFolderPath(&FOLDERID_Profile, 0, NULL, &profile) == S_OK) {
  1424. home = utf16_to_utf8(profile);
  1425. /* CoTaskMemFree(profile); */
  1426. } else
  1427. error("HOMEDRIVE or HOMEPATH is not set and GetWindowsDir failed");
  1428. } else {
  1429. home = emalloc(strlen(homedrive)+strlen(homepath)+1);
  1430. strcpy(home, homedrive);
  1431. strcat(home, homepath);
  1432. }
  1433. free_env_val(homedrive);
  1434. free_env_val(homepath);
  1435. }
  1436. #else
  1437. static void
  1438. get_parameters(int argc, char** argv)
  1439. {
  1440. progname = get_env("PROGNAME");
  1441. if (!progname) {
  1442. progname = strsave(DEFAULT_PROGNAME);
  1443. }
  1444. emu = get_env("EMU");
  1445. if (!emu) {
  1446. emu = strsave(EMULATOR_EXECUTABLE);
  1447. }
  1448. bindir = get_env("BINDIR");
  1449. if (!bindir) {
  1450. /* Determine bindir from absolute path to executable */
  1451. char *p;
  1452. char buffer[PATH_MAX];
  1453. strncpy(buffer, argv[0], sizeof(buffer));
  1454. buffer[sizeof(buffer)-1] = '\0';
  1455. for (p = buffer+strlen(buffer)-1 ; p >= buffer && *p != '/'; --p)
  1456. ;
  1457. *p ='\0';
  1458. bindir = strsave(buffer);
  1459. }
  1460. rootdir = get_env("ROOTDIR");
  1461. if (!rootdir) {
  1462. /* Determine rootdir from absolute path to bindir */
  1463. char *p;
  1464. char buffer[PATH_MAX];
  1465. strncpy(buffer, bindir, sizeof(buffer));
  1466. buffer[sizeof(buffer)-1] = '\0';
  1467. for (p = buffer+strlen(buffer)-1; p >= buffer && *p != '/'; --p)
  1468. ;
  1469. p--;
  1470. for (; p >= buffer && *p != '/'; --p)
  1471. ;
  1472. *p ='\0';
  1473. rootdir = strsave(buffer);
  1474. }
  1475. if (!progname || !emu || !rootdir || !bindir) {
  1476. error("PROGNAME, EMU, ROOTDIR and BINDIR must be set");
  1477. }
  1478. }
  1479. static void
  1480. get_home(void)
  1481. {
  1482. home = get_env("HOME");
  1483. if (home == NULL)
  1484. error("HOME must be set");
  1485. }
  1486. #endif
  1487. static void add_epmd_port(void)
  1488. {
  1489. char* port = get_env("ERL_EPMD_PORT");
  1490. if (port != NULL) {
  1491. add_args("-epmd_port", port, NULL);
  1492. }
  1493. }
  1494. static char **build_args_from_env(char *env_var)
  1495. {
  1496. char *value = get_env(env_var);
  1497. char **res = build_args_from_string(value);
  1498. free_env_val(value);
  1499. return res;
  1500. }
  1501. static char **build_args_from_string(char *string)
  1502. {
  1503. int argc = 0;
  1504. char **argv = NULL;
  1505. int alloced = 0;
  1506. char **cur_s = NULL; /* Initialized to avoid warning. */
  1507. int s_alloced = 0;
  1508. int s_pos = 0;
  1509. char *p = string;
  1510. enum {Start, Build, Build0, BuildSQuoted, BuildDQuoted, AcceptNext} state;
  1511. #define ENSURE() \
  1512. if (s_pos >= s_alloced) { \
  1513. if (!*cur_s) { \
  1514. *cur_s = emalloc(s_alloced = 20); \
  1515. } else { \
  1516. *cur_s = erealloc(*cur_s, s_alloced += 20); \
  1517. } \
  1518. }
  1519. if (!p)
  1520. return NULL;
  1521. argv = emalloc(sizeof(char *) * (alloced = 10));
  1522. state = Start;
  1523. for(;;) {
  1524. switch (state) {
  1525. case Start:
  1526. if (!*p)
  1527. goto done;
  1528. if (argc >= alloced - 1) { /* Make room for extra NULL */
  1529. argv = erealloc(argv, (alloced += 10) * sizeof(char *));
  1530. }
  1531. cur_s = argc + argv;
  1532. *cur_s = NULL;
  1533. s_pos = 0;
  1534. s_alloced = 0;
  1535. state = Build0;
  1536. break;
  1537. case Build0:
  1538. switch (*p) {
  1539. case ' ':
  1540. ++p;
  1541. break;
  1542. case '\0':
  1543. state = Start;
  1544. break;
  1545. default:
  1546. state = Build;
  1547. break;
  1548. }
  1549. break;
  1550. case Build:
  1551. switch (*p) {
  1552. case ' ':
  1553. case '\0':
  1554. ENSURE();
  1555. (*cur_s)[s_pos] = '\0';
  1556. ++argc;
  1557. state = Start;
  1558. break;
  1559. case '"':
  1560. ++p;
  1561. state = BuildDQuoted;
  1562. break;
  1563. case '\'':
  1564. ++p;
  1565. state = BuildSQuoted;
  1566. break;
  1567. case '\\':
  1568. ++p;
  1569. state = AcceptNext;
  1570. break;
  1571. default:
  1572. ENSURE();
  1573. (*cur_s)[s_pos++] = *p++;
  1574. break;
  1575. }
  1576. break;
  1577. case BuildDQuoted:
  1578. switch (*p) {
  1579. case '"':
  1580. ++p;
  1581. /* fall through */
  1582. case '\0':
  1583. state = Build;
  1584. break;
  1585. default:
  1586. ENSURE();
  1587. (*cur_s)[s_pos++] = *p++;
  1588. break;
  1589. }
  1590. break;
  1591. case BuildSQuoted:
  1592. switch (*p) {
  1593. case '\'':
  1594. ++p;
  1595. /* fall through */
  1596. case '\0':
  1597. state = Build;
  1598. break;
  1599. default:
  1600. ENSURE();
  1601. (*cur_s)[s_pos++] = *p++;
  1602. break;
  1603. }
  1604. break;
  1605. case AcceptNext:
  1606. if (!*p) {
  1607. state = Build;
  1608. } else {
  1609. ENSURE();
  1610. (*cur_s)[s_pos++] = *p++;
  1611. }
  1612. state = Build;
  1613. break;
  1614. }
  1615. }
  1616. done:
  1617. argv[argc] = NULL; /* Sure to be large enough */
  1618. if (!argc) {
  1619. efree(argv);
  1620. return NULL;
  1621. }
  1622. return argv;
  1623. #undef ENSURE
  1624. }
  1625. static char *
  1626. errno_string(void)
  1627. {
  1628. char *str = strerror(errno);
  1629. if (!str)
  1630. return "unknown error";
  1631. return str;
  1632. }
  1633. static char **
  1634. read_args_file(char *filename)
  1635. {
  1636. int c, aix = 0, quote = 0, cmnt = 0, asize = 0;
  1637. char **res, *astr = NULL;
  1638. FILE *file;
  1639. #undef EAF_CMNT
  1640. #undef EAF_QUOTE
  1641. #undef SAVE_CHAR
  1642. #define EAF_CMNT (1 << 8)
  1643. #define EAF_QUOTE (1 << 9)
  1644. #define SAVE_CHAR(C) \
  1645. do { \
  1646. if (!astr) \
  1647. astr = emalloc(sizeof(char)*(asize = 20)); \
  1648. if (aix == asize) \
  1649. astr = erealloc(astr, sizeof(char)*(asize += 20)); \
  1650. if (' ' != (char) (C)) \
  1651. astr[aix++] = (char) (C); \
  1652. else if (aix > 0 && astr[aix-1] != ' ') \
  1653. astr[aix++] = ' '; \
  1654. } while (0)
  1655. do {
  1656. errno = 0;
  1657. file = fopen(filename, "r");
  1658. } while (!file && errno == EINTR);
  1659. if (!file) {
  1660. usage_format("Failed to open arguments file \"%s\": %s\n",
  1661. filename,
  1662. errno_string());
  1663. }
  1664. while (1) {
  1665. c = getc(file);
  1666. if (c == EOF) {
  1667. if (ferror(file)) {
  1668. if (errno == EINTR) {
  1669. clearerr(file);
  1670. continue;
  1671. }
  1672. usage_format("Failed to read arguments file \"%s\": %s\n",
  1673. filename,
  1674. errno_string());
  1675. }
  1676. break;
  1677. }
  1678. switch (quote | cmnt | c) {
  1679. case '\\':
  1680. quote = EAF_QUOTE;
  1681. break;
  1682. case '#':
  1683. cmnt = EAF_CMNT;
  1684. break;
  1685. case EAF_CMNT|'\n':
  1686. cmnt = 0;
  1687. /* Fall through... */
  1688. case '\n':
  1689. case '\f':
  1690. case '\r':
  1691. case '\t':
  1692. case '\v':
  1693. if (!quote)
  1694. c = ' ';
  1695. /* Fall through... */
  1696. default:
  1697. if (!cmnt)
  1698. SAVE_CHAR(c);
  1699. quote = 0;
  1700. break;
  1701. }
  1702. }
  1703. SAVE_CHAR('\0');
  1704. fclose(file);
  1705. if (astr[0] == '\0')
  1706. res = NULL;
  1707. else
  1708. res = build_args_from_string(astr);
  1709. efree(astr);
  1710. return res;
  1711. #undef EAF_CMNT
  1712. #undef EAF_QUOTE
  1713. #undef SAVE_CHAR
  1714. }
  1715. typedef struct {
  1716. char **argv;
  1717. int argc;
  1718. int size;
  1719. } argv_buf;
  1720. static void
  1721. trim_argv_buf(argv_buf *abp)
  1722. {
  1723. abp->argv = erealloc(abp->argv, sizeof(char *)*(abp->size = abp->argc));
  1724. }
  1725. static void
  1726. save_arg(argv_buf *abp, char *arg)
  1727. {
  1728. if (abp->size <= abp->argc) {
  1729. if (!abp->argv)
  1730. abp->argv = emalloc(sizeof(char *)*(abp->size = 100));
  1731. else
  1732. abp->argv = erealloc(abp->argv, sizeof(char *)*(abp->size += 100));
  1733. }
  1734. abp->argv[abp->argc++] = arg;
  1735. }
  1736. #define DEF_ARGV_STACK_SIZE 10
  1737. #define ARGV_STACK_SIZE_INCR 50
  1738. typedef struct {
  1739. char **argv;
  1740. int ix;
  1741. } argv_stack_element;
  1742. typedef struct {
  1743. int top_ix;
  1744. int size;
  1745. argv_stack_element *base;
  1746. argv_stack_element def_buf[DEF_ARGV_STACK_SIZE];
  1747. } argv_stack;
  1748. #define ARGV_STACK_INIT(S) \
  1749. do { \
  1750. (S)->top_ix = 0; \
  1751. (S)->size = DEF_ARGV_STACK_SIZE; \
  1752. (S)->base = &(S)->def_buf[0]; \
  1753. } while (0)
  1754. static void
  1755. push_argv(argv_stack *stck, char **argv, int ix)
  1756. {
  1757. if (stck->top_ix == stck->size) {
  1758. if (stck->base != &stck->def_buf[0]) {
  1759. stck->size += ARGV_STACK_SIZE_INCR;
  1760. stck->base = erealloc(stck->base,
  1761. sizeof(argv_stack_element)*stck->size);
  1762. }
  1763. else {
  1764. argv_stack_element *base;
  1765. base = emalloc(sizeof(argv_stack_element)
  1766. *(stck->size + ARGV_STACK_SIZE_INCR));
  1767. memcpy((void *) base,
  1768. (void *) stck->base,
  1769. sizeof(argv_stack_element)*stck->size);
  1770. stck->base = base;
  1771. stck->size += ARGV_STACK_SIZE_INCR;
  1772. }
  1773. }
  1774. stck->base[stck->top_ix].argv = argv;
  1775. stck->base[stck->top_ix++].ix = ix;
  1776. }
  1777. static void
  1778. pop_argv(argv_stack *stck, char ***argvp, int *ixp)
  1779. {
  1780. if (stck->top_ix == 0) {
  1781. *argvp = NULL;
  1782. *ixp = 0;
  1783. }
  1784. else {
  1785. *argvp = stck->base[--stck->top_ix].argv;
  1786. *ixp = stck->base[stck->top_ix].ix;
  1787. if (stck->top_ix == 0 && stck->base != &stck->def_buf[0]) {
  1788. efree(stck->base);
  1789. stck->base = &stck->def_buf[0];
  1790. stck->size = DEF_ARGV_STACK_SIZE;
  1791. }
  1792. }
  1793. }
  1794. static void
  1795. get_file_args(char *filename, argv_buf *abp, argv_buf *xabp)
  1796. {
  1797. argv_stack stck;
  1798. int i;
  1799. char **argv;
  1800. ARGV_STACK_INIT(&stck);
  1801. i = 0;
  1802. argv = read_args_file(filename);
  1803. while (argv) {
  1804. while (argv[i]) {
  1805. if (strcmp(argv[i], "-args_file") == 0) {
  1806. char **new_argv;
  1807. char *fname;
  1808. if (!argv[++i])
  1809. usage("-args_file");
  1810. fname = argv[i++];
  1811. new_argv = read_args_file(fname);
  1812. if (new_argv) {
  1813. if (argv[i])
  1814. push_argv(&stck, argv, i);
  1815. else
  1816. efree(argv);
  1817. i = 0;
  1818. argv = new_argv;
  1819. }
  1820. }
  1821. else {
  1822. if (strcmp(argv[i], "-extra") == 0) {
  1823. i++;
  1824. while (argv[i])
  1825. save_arg(xabp, argv[i++]);
  1826. break;
  1827. }
  1828. save_arg(abp, argv[i++]);
  1829. }
  1830. }
  1831. efree(argv);
  1832. pop_argv(&stck, &argv, &i);
  1833. }
  1834. }
  1835. static void
  1836. initial_argv_massage(int *argc, char ***argv)
  1837. {
  1838. argv_buf ab = {0}, xab = {0};
  1839. int ix, vix, ac;
  1840. char **av;
  1841. struct {
  1842. int argc;
  1843. char **argv;
  1844. } avv[] = {{INT_MAX, NULL}, {INT_MAX, NULL}, {INT_MAX, NULL},
  1845. {INT_MAX, NULL}, {INT_MAX, NULL}, {INT_MAX, NULL}};
  1846. /*
  1847. * The environment flag containing OTP release is intentionally
  1848. * undocumented and intended for OTP internal use only.
  1849. */
  1850. vix = 0;
  1851. av = build_args_from_env("ERL_OTP" OTP_SYSTEM_VERSION "_FLAGS");
  1852. if (av)
  1853. avv[vix++].argv = av;
  1854. av = build_args_from_env("ERL_AFLAGS");
  1855. if (av)
  1856. avv[vix++].argv = av;
  1857. /* command line */
  1858. if (*argc > 1) {
  1859. avv[vix].argc = *argc - 1;
  1860. avv[vix++].argv = &(*argv)[1];
  1861. }
  1862. av = build_args_from_env("ERL_FLAGS");
  1863. if (av)
  1864. avv[vix++].argv = av;
  1865. av = build_args_from_env("ERL_ZFLAGS");
  1866. if (av)
  1867. avv[vix++].argv = av;
  1868. if (vix == (*argc > 1 ? 1 : 0)) {
  1869. /* Only command line argv; check if we can use argv as it is... */
  1870. ac = *argc;
  1871. av = *argv;
  1872. for (ix = 1; ix < ac; ix++) {
  1873. if (strcmp(av[ix], "-args_file") == 0) {
  1874. /* ... no; we need to expand arguments from
  1875. file into argument list */
  1876. goto build_new_argv;
  1877. }
  1878. if (strcmp(av[ix], "-extra") == 0) {
  1879. break;
  1880. }
  1881. }
  1882. /* ... yes; we can use argv as it is. */
  1883. return;
  1884. }
  1885. build_new_argv:
  1886. save_arg(&ab, (*argv)[0]);
  1887. vix = 0;
  1888. while (avv[vix].argv) {
  1889. ac = avv[vix].argc;
  1890. av = avv[vix].argv;
  1891. ix = 0;
  1892. while (ix < ac && av[ix]) {
  1893. if (strcmp(av[ix], "-args_file") == 0) {
  1894. if (++ix == ac)
  1895. usage("-args_file");
  1896. get_file_args(av[ix++], &ab, &xab);
  1897. }
  1898. else {
  1899. if (strcmp(av[ix], "-extra") == 0) {
  1900. ix++;
  1901. while (ix < ac && av[ix])
  1902. save_arg(&xab, av[ix++]);
  1903. break;
  1904. }
  1905. save_arg(&ab, av[ix++]);
  1906. }
  1907. }
  1908. vix++;
  1909. }
  1910. vix = 0;
  1911. while (avv[vix].argv) {
  1912. if (avv[vix].argc == INT_MAX) /* not command line */
  1913. efree(avv[vix].argv);
  1914. vix++;
  1915. }
  1916. if (xab.argc) {
  1917. save_arg(&ab, "-extra");
  1918. for (ix = 0; ix < xab.argc; ix++)
  1919. save_arg(&ab, xab.argv[ix]);
  1920. efree(xab.argv);
  1921. }
  1922. save_arg(&ab, NULL);
  1923. trim_argv_buf(&ab);
  1924. *argv = ab.argv;
  1925. *argc = ab.argc - 1;
  1926. }
  1927. #ifdef __WIN32__
  1928. static char*
  1929. possibly_quote(char* arg)
  1930. {
  1931. int mustQuote = NO;
  1932. int n = 0;
  1933. char* s;
  1934. char* narg;
  1935. /*
  1936. * Scan the string to find out if it needs quoting and return
  1937. * the original argument if not.
  1938. */
  1939. for (s = arg; *s; s++, n++) {
  1940. if (*s == ' ' || *s == '"') {
  1941. mustQuote = YES;
  1942. n++;
  1943. }
  1944. }
  1945. if (!mustQuote) {
  1946. return arg;
  1947. }
  1948. /*
  1949. * Insert the quotes and put a backslash in front of every quote
  1950. * inside the string.
  1951. */
  1952. s = narg = emalloc(n+2+1);
  1953. for (*s++ = '"'; *arg; arg++, s++) {
  1954. if (*s == '"') {
  1955. *s++ = '\\';
  1956. }
  1957. *s = *arg;
  1958. }
  1959. *s++ = '"';
  1960. *s = '\0';
  1961. return narg;
  1962. }
  1963. /*
  1964. * Unicode helpers to handle environment and command line parameters on
  1965. * Windows. We internally handle all environment variables in UTF8,
  1966. * but put and get the environment using the WCHAR (limited UTF16) interface
  1967. *
  1968. * These are simplified to only handle Unicode characters that can fit in
  1969. * Windows simplified UTF16, i.e. characters that fit in 16 bits.
  1970. */
  1971. static int utf8_len(unsigned char first)
  1972. {
  1973. if ((first & ((unsigned char) 0x80)) == 0) {
  1974. return 1;
  1975. } else if ((first & ((unsigned char) 0xE0)) == 0xC0) {
  1976. return 2;
  1977. } else if ((first & ((unsigned char) 0xF0)) == 0xE0) {
  1978. return 3;
  1979. } else if ((first & ((unsigned char) 0xF8)) == 0xF0) {
  1980. return 4;
  1981. }
  1982. return 1; /* will be a '?' */
  1983. }
  1984. static WCHAR *utf8_to_utf16(unsigned char *bytes)
  1985. {
  1986. unsigned int unipoint;
  1987. unsigned char *tmp = bytes;
  1988. WCHAR *target, *res;
  1989. int num = 0;
  1990. while (*tmp) {
  1991. num++;
  1992. tmp += utf8_len(*tmp);
  1993. }
  1994. res = target = emalloc((num + 1) * sizeof(WCHAR));
  1995. while (*bytes) {
  1996. if (((*bytes) & ((unsigned char) 0x80)) == 0) {
  1997. unipoint = (unsigned int) *bytes;
  1998. ++bytes;
  1999. } else if (((*bytes) & ((unsigned char) 0xE0)) == 0xC0) {
  2000. unipoint =
  2001. (((unsigned int) ((*bytes) & ((unsigned char) 0x1F))) << 6) |
  2002. ((unsigned int) (bytes[1] & ((

Large files files are truncated, but you can click here to view the full file