PageRenderTime 62ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/erts/etc/common/erlexec.c

https://github.com/bsmr-erlang/otp
C | 2309 lines | 2274 code | 8 blank | 27 comment | 5 complexity | d4931068f5e4e6c8234c0684cf5cc16d MD5 | raw file
Possible License(s): BSD-3-Clause, 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. char* emu_name;
  372. #ifdef __WIN32__
  373. this_module_handle = module;
  374. run_werl = windowed;
  375. /* if we started this erl just to get a detached emulator,
  376. * the arguments are already prepared for beam, so we skip
  377. * directly to start_emulator */
  378. s = get_env("ERL_CONSOLE_MODE");
  379. if (s != NULL && strcmp(s, "detached")==0) {
  380. free_env_val(s);
  381. s = get_env("ERL_EMULATOR_DLL");
  382. if (s != NULL) {
  383. argv[0] = strsave(s);
  384. } else {
  385. argv[0] = strsave(EMULATOR_EXECUTABLE);
  386. }
  387. ensure_EargsSz(argc + 1);
  388. memcpy((void *) Eargsp, (void *) argv, argc * sizeof(char *));
  389. Eargsp[argc] = NULL;
  390. emu = argv[0];
  391. start_emulator_program = strsave(argv[0]);
  392. goto skip_arg_massage;
  393. }
  394. free_env_val(s);
  395. #else
  396. int reset_cerl_detached = 0;
  397. s = get_env("CERL_DETACHED_PROG");
  398. if (s && strcmp(s, "") != 0) {
  399. emu = s;
  400. start_detached = 1;
  401. reset_cerl_detached = 1;
  402. ensure_EargsSz(argc + 1);
  403. memcpy((void *) Eargsp, (void *) argv, argc * sizeof(char *));
  404. Eargsp[argc] = emu;
  405. Eargsp[argc] = NULL;
  406. goto skip_arg_massage;
  407. }
  408. free_env_val(s);
  409. #endif
  410. initial_argv_massage(&argc, &argv); /* Merge with env; expand -args_file */
  411. i = 1;
  412. #ifdef __WIN32__
  413. /* Not used? /rickard */
  414. if ((argc > 2) && (strcmp(argv[i], "-regkey") == 0)) {
  415. key_val_name = strsave(argv[i+1]);
  416. i = 3;
  417. }
  418. #endif
  419. get_parameters(argc, argv);
  420. /*
  421. * Construct the path of the executable.
  422. */
  423. #if defined(__WIN32__) && defined(WIN32_ALWAYS_DEBUG)
  424. emu_type = "debug";
  425. #endif
  426. /* We need to do this before the ordinary processing. */
  427. malloc_lib = get_env("ERL_MALLOC_LIB");
  428. while (i < argc) {
  429. if (argv[i][0] == '+') {
  430. if (argv[i][1] == 'M' && argv[i][2] == 'Y' && argv[i][3] == 'm') {
  431. if (argv[i][4] == '\0') {
  432. if (++i < argc)
  433. malloc_lib = argv[i];
  434. else
  435. usage("+MYm");
  436. }
  437. else
  438. malloc_lib = &argv[i][4];
  439. }
  440. }
  441. else if (argv[i][0] == '-') {
  442. if (strcmp(argv[i], "-smp") == 0) {
  443. if (i + 1 >= argc)
  444. goto smp;
  445. if (strcmp(argv[i+1], "auto") == 0) {
  446. i++;
  447. } else if (strcmp(argv[i+1], "enable") == 0) {
  448. i++;
  449. smp_enable:
  450. ;
  451. } else if (strcmp(argv[i+1], "disable") == 0) {
  452. i++;
  453. smp_disable:
  454. usage_notsup("-smp disable", " Use \"+S 1\" instead.");
  455. } else {
  456. smp:
  457. ;
  458. }
  459. } else if (strcmp(argv[i], "-smpenable") == 0) {
  460. goto smp_enable;
  461. } else if (strcmp(argv[i], "-smpauto") == 0) {
  462. ;
  463. } else if (strcmp(argv[i], "-smpdisable") == 0) {
  464. goto smp_disable;
  465. } else if (strcmp(argv[i], "-extra") == 0) {
  466. break;
  467. } else if (strcmp(argv[i], "-emu_type") == 0) {
  468. if (i + 1 >= argc) {
  469. usage(argv[i]);
  470. }
  471. emu_type = argv[i+1];
  472. i++;
  473. }
  474. }
  475. i++;
  476. }
  477. if (malloc_lib) {
  478. if (strcmp(malloc_lib, "libc") != 0)
  479. usage("+MYm");
  480. }
  481. emu = add_extra_suffixes(emu);
  482. emu_name = strsave(emu);
  483. erts_snprintf(tmpStr, sizeof(tmpStr), "%s" DIRSEP "%s" BINARY_EXT, bindir, emu);
  484. emu = strsave(tmpStr);
  485. s = get_env("ESCRIPT_NAME");
  486. if(s) {
  487. add_Eargs(s); /* argv[0] = scriptname*/
  488. } else {
  489. add_Eargs(emu); /* argv[0] = erl or cerl */
  490. }
  491. /* Add the bindir to the front of the PATH, and remove all subsequent
  492. * occurrences to avoid ballooning it on repeated up/downgrades. */
  493. s = get_env("PATH");
  494. if (s == NULL) {
  495. erts_snprintf(tmpStr, sizeof(tmpStr),
  496. "%s" PATHSEP "%s" DIRSEP "bin" PATHSEP, bindir, rootdir);
  497. } else if (strstr(s, rootdir) == NULL) {
  498. erts_snprintf(tmpStr, sizeof(tmpStr),
  499. "%s" PATHSEP "%s" DIRSEP "bin" PATHSEP "%s", bindir, rootdir, s);
  500. } else {
  501. const char *bindir_slug, *bindir_slug_index;
  502. int bindir_slug_length;
  503. const char *in_index;
  504. char *out_index;
  505. erts_snprintf(tmpStr, sizeof(tmpStr), "%s" PATHSEP, bindir);
  506. bindir_slug = strsave(tmpStr);
  507. bindir_slug_length = strlen(bindir_slug);
  508. out_index = &tmpStr[bindir_slug_length];
  509. in_index = s;
  510. while ((bindir_slug_index = strstr(in_index, bindir_slug))) {
  511. int block_length = (bindir_slug_index - in_index);
  512. memcpy(out_index, in_index, block_length);
  513. in_index = bindir_slug_index + bindir_slug_length;
  514. out_index += block_length;
  515. }
  516. strcpy(out_index, in_index);
  517. }
  518. free_env_val(s);
  519. set_env("PATH", tmpStr);
  520. i = 1;
  521. #ifdef __WIN32__
  522. #define ADD_BOOT_CONFIG \
  523. if (boot_script) \
  524. add_args("-boot", boot_script, NULL); \
  525. if (config_script) \
  526. add_args("-config", config_script, NULL);
  527. #else
  528. #define ADD_BOOT_CONFIG
  529. #endif
  530. get_home();
  531. add_args("-home", home, NULL);
  532. add_epmd_port();
  533. add_arg("--");
  534. while (i < argc) {
  535. if (!process_args) { /* Copy arguments after '-extra' */
  536. add_arg(argv[i]);
  537. i++;
  538. } else {
  539. switch (argv[i][0]) {
  540. case '-':
  541. switch (argv[i][1]) {
  542. #ifdef __WIN32__
  543. case 'b':
  544. if (strcmp(argv[i], "-boot") == 0) {
  545. if (boot_script)
  546. error("Conflicting -start_erl and -boot options");
  547. if (i+1 >= argc)
  548. usage("-boot");
  549. boot_script = strsave(argv[i+1]);
  550. i++;
  551. }
  552. else {
  553. add_arg(argv[i]);
  554. }
  555. break;
  556. #endif
  557. case 'c':
  558. if (strcmp(argv[i], "-compile") == 0) {
  559. /*
  560. * Note that the shell script erl.exec does an recursive call
  561. * on itself here. We'll avoid doing that.
  562. */
  563. add_args("-noshell", "-noinput", "-s", "c", "lc_batch",
  564. NULL);
  565. add_Eargs("-B");
  566. haltAfterwards = 0;
  567. }
  568. #ifdef __WIN32__
  569. else if (strcmp(argv[i], "-config") == 0){
  570. if (config_script)
  571. error("Conflicting -start_erl and -config options");
  572. if (i+1 >= argc)
  573. usage("-config");
  574. config_script = strsave(argv[i+1]);
  575. i++;
  576. }
  577. #endif
  578. else {
  579. add_arg(argv[i]);
  580. }
  581. break;
  582. case 'd':
  583. if (strcmp(argv[i], "-detached") != 0) {
  584. add_arg(argv[i]);
  585. } else {
  586. start_detached = 1;
  587. add_args("-noshell", "-noinput", NULL);
  588. }
  589. break;
  590. case 'e':
  591. if (strcmp(argv[i], "-extra") == 0) {
  592. process_args = 0;
  593. ADD_BOOT_CONFIG;
  594. add_arg(argv[i]);
  595. } else if (strcmp(argv[i], "-emu_args") == 0) { /* -emu_args */
  596. verbose = 1;
  597. } else if (strcmp(argv[i], "-emu_args_exit") == 0) {
  598. print_args_exit = 1;
  599. } else if (strcmp(argv[i], "-emu_name_exit") == 0) {
  600. printf("%s\n", emu_name);
  601. exit(0);
  602. } else if (strcmp(argv[i], "-emu_qouted_cmd_exit") == 0) {
  603. print_qouted_cmd_exit = 1;
  604. } else if (strcmp(argv[i], "-env") == 0) { /* -env VARNAME VARVALUE */
  605. if (i+2 >= argc)
  606. usage("-env");
  607. set_env(argv[i+1], argv[i+2]);
  608. i += 2;
  609. } else if (strcmp(argv[i], "-epmd") == 0) {
  610. if (i+1 >= argc)
  611. usage("-epmd");
  612. epmd_prog = argv[i+1];
  613. ++i;
  614. } else {
  615. add_arg(argv[i]);
  616. }
  617. break;
  618. case 'k':
  619. if (strcmp(argv[i], "-keep_window") == 0) {
  620. keep_window = 1;
  621. } else
  622. add_arg(argv[i]);
  623. break;
  624. case 'm':
  625. /*
  626. * Note that the shell script erl.exec does an recursive call
  627. * on itself here. We'll avoid doing that.
  628. */
  629. if (strcmp(argv[i], "-make") == 0) {
  630. add_args("-noshell", "-noinput", "-s", "make", "all_or_nothing", NULL);
  631. add_Eargs("-B");
  632. haltAfterwards = 1;
  633. i = argc; /* Skip rest of command line */
  634. } else if (strcmp(argv[i], "-man") == 0) {
  635. #if defined(__WIN32__)
  636. error("-man not supported on Windows");
  637. #else
  638. argv[i] = "man";
  639. erts_snprintf(tmpStr, sizeof(tmpStr), "%s/man", rootdir);
  640. set_env("MANPATH", tmpStr);
  641. execvp("man", argv+i);
  642. error("Could not execute the 'man' command.");
  643. #endif
  644. } else
  645. add_arg(argv[i]);
  646. break;
  647. case 'n':
  648. if (strcmp(argv[i], "-name") == 0) { /* -name NAME */
  649. if (i+1 >= argc)
  650. usage("-name");
  651. /*
  652. * Note: Cannot use add_args() here, due to non-defined
  653. * evaluation order.
  654. */
  655. add_arg(argv[i]);
  656. add_arg(argv[i+1]);
  657. isdistributed = 1;
  658. i++;
  659. } else if (strcmp(argv[i], "-noinput") == 0) {
  660. add_args("-noshell", "-noinput", NULL);
  661. } else if (strcmp(argv[i], "-nohup") == 0) {
  662. add_arg("-nohup");
  663. nohup = 1;
  664. } else if (strcmp(argv[i], "-no_epmd") == 0) {
  665. add_arg("-no_epmd");
  666. no_epmd = 1;
  667. } else {
  668. add_arg(argv[i]);
  669. }
  670. break;
  671. case 's': /* -sname NAME */
  672. if (strcmp(argv[i], "-sname") == 0) {
  673. if (i+1 >= argc)
  674. usage("-sname");
  675. add_arg(argv[i]);
  676. add_arg(argv[i+1]);
  677. isdistributed = 1;
  678. i++;
  679. }
  680. #ifdef __WIN32__
  681. else if (strcmp(argv[i], "-service_event") == 0) {
  682. add_arg(argv[i]);
  683. add_arg(argv[i+1]);
  684. i++;
  685. }
  686. else if (strcmp(argv[i], "-start_erl") == 0) {
  687. if (i+1 < argc && argv[i+1][0] != '-') {
  688. get_start_erl_data(argv[i+1]);
  689. i++;
  690. } else
  691. get_start_erl_data((char *) NULL);
  692. }
  693. #endif
  694. else if (strcmp(argv[i], "-start_epmd") == 0) {
  695. if (i+1 >= argc)
  696. usage("-start_epmd");
  697. if (strcmp(argv[i+1], "true") == 0) {
  698. /* The default */
  699. no_epmd = 0;
  700. }
  701. else if (strcmp(argv[i+1], "false") == 0) {
  702. no_epmd = 1;
  703. }
  704. else
  705. usage_format("Expected boolean argument for \'-start_epmd\'.\n");
  706. add_arg(argv[i]);
  707. add_arg(argv[i+1]);
  708. i++;
  709. }
  710. else
  711. add_arg(argv[i]);
  712. break;
  713. case 'v': /* -version */
  714. if (strcmp(argv[i], "-version") == 0) {
  715. add_Eargs("-V");
  716. } else {
  717. add_arg(argv[i]);
  718. }
  719. break;
  720. default:
  721. add_arg(argv[i]);
  722. break;
  723. } /* switch(argv[i][1] */
  724. break;
  725. case '+':
  726. switch (argv[i][1]) {
  727. case 'a':
  728. case 'A':
  729. case 'C':
  730. case 'e':
  731. case 'i':
  732. case 'n':
  733. case 'P':
  734. case 'Q':
  735. case 't':
  736. case 'T':
  737. case 'R':
  738. case 'W':
  739. case 'K':
  740. if (argv[i][2] != '\0')
  741. goto the_default;
  742. if (i+1 >= argc)
  743. usage(argv[i]);
  744. argv[i][0] = '-';
  745. add_Eargs(argv[i]);
  746. add_Eargs(argv[i+1]);
  747. i++;
  748. break;
  749. case 'I':
  750. if (argv[i][2] == 'O' && (argv[i][3] == 't' || argv[i][3] == 'p')) {
  751. if (argv[i][4] != '\0')
  752. goto the_default;
  753. argv[i][0] = '-';
  754. add_Eargs(argv[i]);
  755. add_Eargs(argv[i+1]);
  756. i++;
  757. break;
  758. }
  759. if (argv[i][2] == 'O' && argv[i][3] == 'P' &&
  760. (argv[i][4] == 't' || argv[i][4] == 'p')) {
  761. if (argv[i][5] != '\0')
  762. goto the_default;
  763. argv[i][0] = '-';
  764. add_Eargs(argv[i]);
  765. add_Eargs(argv[i+1]);
  766. i++;
  767. break;
  768. }
  769. usage(argv[i]);
  770. break;
  771. case 'S':
  772. if (argv[i][2] == 'P') {
  773. if (argv[i][3] != '\0')
  774. goto the_default;
  775. }
  776. else if (argv[i][2] == 'D') {
  777. char* type = argv[i]+3;
  778. if (strncmp(type, "cpu", 3) != 0 &&
  779. strncmp(type, "Pcpu", 4) != 0 &&
  780. strncmp(type, "io", 2) != 0)
  781. usage(argv[i]);
  782. if ((argv[i][3] == 'c' && argv[i][6] != '\0') ||
  783. (argv[i][3] == 'P' && argv[i][7] != '\0') ||
  784. (argv[i][3] == 'i' && argv[i][5] != '\0'))
  785. goto the_default;
  786. }
  787. else if (argv[i][2] != '\0')
  788. goto the_default;
  789. if (i+1 >= argc)
  790. usage(argv[i]);
  791. argv[i][0] = '-';
  792. add_Eargs(argv[i]);
  793. add_Eargs(argv[i+1]);
  794. i++;
  795. break;
  796. case 'B':
  797. argv[i][0] = '-';
  798. if (argv[i][2] != '\0') {
  799. if ((argv[i][2] != 'i') &&
  800. (argv[i][2] != 'c') &&
  801. (argv[i][2] != 'd')) {
  802. usage(argv[i]);
  803. } else {
  804. add_Eargs(argv[i]);
  805. break;
  806. }
  807. }
  808. if (i+1 < argc) {
  809. if ((argv[i+1][0] != '-') &&
  810. (argv[i+1][0] != '+')) {
  811. if (argv[i+1][0] == 'i') {
  812. add_Eargs(argv[i]);
  813. add_Eargs(argv[i+1]);
  814. i++;
  815. break;
  816. } else {
  817. usage(argv[i]);
  818. }
  819. }
  820. }
  821. add_Eargs(argv[i]);
  822. break;
  823. case 'c':
  824. argv[i][0] = '-';
  825. if (argv[i][2] == '\0' && i+1 < argc) {
  826. if (strcmp(argv[i+1], "true") == 0
  827. || strcmp(argv[i+1], "false") == 0) {
  828. add_Eargs(argv[i]);
  829. add_Eargs(argv[i+1]);
  830. i++;
  831. break;
  832. }
  833. }
  834. add_Eargs(argv[i]);
  835. break;
  836. case 'M': {
  837. int x;
  838. for (x = 0; plusM_au_allocs[x]; x++)
  839. if (plusM_au_allocs[x] == argv[i][2])
  840. break;
  841. if ((plusM_au_allocs[x]
  842. && is_one_of_strings(&argv[i][3],
  843. plusM_au_alloc_switches))
  844. || is_one_of_strings(&argv[i][2],
  845. plusM_other_switches)) {
  846. if (i+1 >= argc
  847. || argv[i+1][0] == '-'
  848. || argv[i+1][0] == '+')
  849. usage(argv[i]);
  850. argv[i][0] = '-';
  851. add_Eargs(argv[i]);
  852. add_Eargs(argv[i+1]);
  853. i++;
  854. }
  855. else
  856. goto the_default;
  857. break;
  858. }
  859. case 'h':
  860. if (!is_one_of_strings(&argv[i][2], plush_val_switches)) {
  861. goto the_default;
  862. } else {
  863. if (i+1 >= argc
  864. || argv[i+1][0] == '-'
  865. || argv[i+1][0] == '+')
  866. usage(argv[i]);
  867. argv[i][0] = '-';
  868. add_Eargs(argv[i]);
  869. add_Eargs(argv[i+1]);
  870. i++;
  871. }
  872. break;
  873. case 'r':
  874. if (!is_one_of_strings(&argv[i][2],
  875. plusr_val_switches))
  876. goto the_default;
  877. else {
  878. if (i+1 >= argc
  879. || argv[i+1][0] == '-'
  880. || argv[i+1][0] == '+')
  881. usage(argv[i]);
  882. argv[i][0] = '-';
  883. add_Eargs(argv[i]);
  884. add_Eargs(argv[i+1]);
  885. i++;
  886. }
  887. break;
  888. case 's':
  889. if (!is_one_of_strings(&argv[i][2],
  890. pluss_val_switches))
  891. goto the_default;
  892. else {
  893. if (i+1 >= argc
  894. || argv[i+1][0] == '-'
  895. || argv[i+1][0] == '+')
  896. usage(argv[i]);
  897. argv[i][0] = '-';
  898. add_Eargs(argv[i]);
  899. add_Eargs(argv[i+1]);
  900. i++;
  901. }
  902. break;
  903. case 'p':
  904. if (argv[i][2] != 'c' || argv[i][3] != '\0')
  905. goto the_default;
  906. if (i+1 >= argc)
  907. usage(argv[i]);
  908. argv[i][0] = '-';
  909. add_Eargs(argv[i]);
  910. add_Eargs(argv[i+1]);
  911. i++;
  912. break;
  913. case 'z':
  914. if (!is_one_of_strings(&argv[i][2], plusz_val_switches)) {
  915. goto the_default;
  916. } else {
  917. if (i+1 >= argc
  918. || argv[i+1][0] == '-'
  919. || argv[i+1][0] == '+')
  920. usage(argv[i]);
  921. argv[i][0] = '-';
  922. add_Eargs(argv[i]);
  923. add_Eargs(argv[i+1]);
  924. i++;
  925. }
  926. break;
  927. default:
  928. the_default:
  929. argv[i][0] = '-'; /* Change +option to -option. */
  930. add_Eargs(argv[i]);
  931. }
  932. break;
  933. default:
  934. add_arg(argv[i]);
  935. } /* switch(argv[i][0] */
  936. i++;
  937. }
  938. }
  939. if (process_args) {
  940. ADD_BOOT_CONFIG;
  941. }
  942. #undef ADD_BOOT_CONFIG
  943. /* Doesn't conflict with -extra, since -make skips all the rest of
  944. the arguments. */
  945. if (haltAfterwards) {
  946. add_args("-s", "erlang", "halt", NULL);
  947. }
  948. if (isdistributed && !no_epmd)
  949. start_epmd(epmd_prog);
  950. #if (! defined(__WIN32__)) && defined(DEBUG)
  951. if (start_detached && get_env("ERL_CONSOLE_MODE")) {
  952. /* Start the emulator within an xterm.
  953. * Move up all arguments and insert
  954. * "xterm -e " first.
  955. * The path must be searched for this
  956. * to work, i.e execvp() must be used.
  957. */
  958. ensure_EargsSz(EargsCnt+2);
  959. for (i = EargsCnt; i > 0; i--)
  960. Eargsp[i+1] = Eargsp[i-1]; /* Two args to insert */
  961. EargsCnt += 2; /* Two args to insert */
  962. Eargsp[0] = emu = "xterm";
  963. Eargsp[1] = "-e";
  964. }
  965. #endif
  966. add_Eargs("--");
  967. add_Eargs("-root");
  968. add_Eargs(rootdir);
  969. add_Eargs("-progname");
  970. add_Eargs(progname);
  971. add_Eargs("--");
  972. ensure_EargsSz(EargsCnt + argsCnt + 1);
  973. for (i = 0; i < argsCnt; i++)
  974. Eargsp[EargsCnt++] = argsp[i];
  975. Eargsp[EargsCnt] = NULL;
  976. if (print_qouted_cmd_exit) {
  977. printf("\"%s\" ", emu);
  978. for (i = 1; i < EargsCnt; i++)
  979. printf("\"%s\" ", Eargsp[i]);
  980. printf("\n");
  981. exit(0);
  982. }
  983. if (print_args_exit) {
  984. for (i = 1; i < EargsCnt; i++)
  985. printf("%s\n", Eargsp[i]);
  986. exit(0);
  987. }
  988. if (verbose) {
  989. printf("Executing: %s", emu);
  990. for (i = 0; i < EargsCnt; i++)
  991. printf(" %s", Eargsp[i]);
  992. printf("\n\n");
  993. }
  994. #ifdef __WIN32__
  995. if (EargsSz != EargsCnt + 1)
  996. Eargsp = (char **) erealloc((void *) Eargsp, (EargsCnt + 1) *
  997. sizeof(char *));
  998. efree((void *) argsp);
  999. skip_arg_massage:
  1000. /*DebugBreak();*/
  1001. if (run_werl) {
  1002. if (start_detached) {
  1003. char *p;
  1004. /* transform werl to erl */
  1005. p = start_emulator_program+strlen(start_emulator_program);
  1006. while (--p >= start_emulator_program && *p != '/' && *p != '\\' &&
  1007. *p != 'W' && *p != 'w')
  1008. ;
  1009. if (p >= start_emulator_program && (*p == 'W' || *p == 'w') &&
  1010. (p[1] == 'E' || p[1] == 'e') && (p[2] == 'R' || p[2] == 'r') &&
  1011. (p[3] == 'L' || p[3] == 'l')) {
  1012. memmove(p,p+1,strlen(p));
  1013. }
  1014. }
  1015. return start_win_emulator(emu, start_emulator_program, Eargsp, start_detached);
  1016. } else {
  1017. return start_emulator(emu, start_emulator_program, Eargsp, start_detached);
  1018. }
  1019. #else
  1020. skip_arg_massage:
  1021. if (start_detached) {
  1022. int status = fork();
  1023. if (status != 0) /* Parent */
  1024. return 0;
  1025. if (reset_cerl_detached)
  1026. putenv("CERL_DETACHED_PROG=");
  1027. /* Detach from controlling terminal */
  1028. #ifdef HAVE_SETSID
  1029. setsid();
  1030. #elif defined(TIOCNOTTY)
  1031. {
  1032. int fd = open("/dev/tty", O_RDWR);
  1033. if (fd >= 0) {
  1034. ioctl(fd, TIOCNOTTY, NULL);
  1035. close(fd);
  1036. }
  1037. }
  1038. #endif
  1039. status = fork();
  1040. if (status != 0) /* Parent */
  1041. return 0;
  1042. /*
  1043. * Grandchild.
  1044. */
  1045. close(0);
  1046. open("/dev/null", O_RDONLY);
  1047. close(1);
  1048. open("/dev/null", O_WRONLY);
  1049. close(2);
  1050. open("/dev/null", O_WRONLY);
  1051. #ifdef DEBUG
  1052. execvp(emu, Eargsp); /* "xterm ..." needs to search the path */
  1053. #endif
  1054. }
  1055. #ifdef DEBUG
  1056. else
  1057. #endif
  1058. {
  1059. execv(emu, Eargsp);
  1060. }
  1061. if (errno == ENOENT) {
  1062. error("The emulator \'%s\' does not exist.", emu);
  1063. } else {
  1064. error("Error %d executing \'%s\'.", errno, emu);
  1065. }
  1066. return 1;
  1067. #endif
  1068. }
  1069. static void
  1070. usage_aux(void)
  1071. {
  1072. fprintf(stderr,
  1073. "Usage: erl [-version] [-sname NAME | -name NAME] "
  1074. "[-noshell] [-noinput] [-env VAR VALUE] [-compile file ...] "
  1075. #ifdef __WIN32__
  1076. "[-start_erl [datafile]] "
  1077. #endif
  1078. "[-make] [-man [manopts] MANPAGE] [-x] [-emu_args] [-start_epmd BOOLEAN] "
  1079. "[-args_file FILENAME] [+A THREADS] [+a SIZE] [+B[c|d|i]] [+c [BOOLEAN]] "
  1080. "[+C MODE] [+h HEAP_SIZE_OPTION] [+K BOOLEAN] "
  1081. "[+l] [+M<SUBSWITCH> <ARGUMENT>] [+P MAX_PROCS] [+Q MAX_PORTS] "
  1082. "[+R COMPAT_REL] "
  1083. "[+r] [+rg READER_GROUPS_LIMIT] [+s SCHEDULER_OPTION] "
  1084. "[+S NO_SCHEDULERS:NO_SCHEDULERS_ONLINE] "
  1085. "[+SP PERCENTAGE_SCHEDULERS:PERCENTAGE_SCHEDULERS_ONLINE] "
  1086. "[+T LEVEL] [+V] [+v] "
  1087. "[+W<i|w|e>] [+z MISC_OPTION] [args ...]\n");
  1088. exit(1);
  1089. }
  1090. void
  1091. usage(const char *switchname)
  1092. {
  1093. fprintf(stderr, "Missing argument(s) for \'%s\'.\n", switchname);
  1094. usage_aux();
  1095. }
  1096. static void
  1097. usage_notsup(const char *switchname, const char *alt)
  1098. {
  1099. fprintf(stderr, "Argument \'%s\' not supported.%s\n", switchname, alt);
  1100. usage_aux();
  1101. }
  1102. static void
  1103. usage_format(char *format, ...)
  1104. {
  1105. va_list args;
  1106. va_start(args, format);
  1107. vfprintf(stderr, format, args);
  1108. va_end(args);
  1109. usage_aux();
  1110. }
  1111. void
  1112. start_epmd(char *epmd)
  1113. {
  1114. char epmd_cmd[MAXPATHLEN+100];
  1115. #ifdef __WIN32__
  1116. char* arg1 = NULL;
  1117. #endif
  1118. int result;
  1119. if (!epmd) {
  1120. epmd = epmd_cmd;
  1121. #ifdef __WIN32__
  1122. erts_snprintf(epmd_cmd, sizeof(epmd_cmd), "%s" DIRSEP "epmd", bindir);
  1123. arg1 = "-daemon";
  1124. #else
  1125. erts_snprintf(epmd_cmd, sizeof(epmd_cmd), "\"%s" DIRSEP "epmd\" -daemon", bindir);
  1126. #endif
  1127. }
  1128. #ifdef __WIN32__
  1129. if (arg1 != NULL) {
  1130. strcat(epmd, " ");
  1131. strcat(epmd, arg1);
  1132. }
  1133. {
  1134. wchar_t wcepmd[MAXPATHLEN+100];
  1135. STARTUPINFOW start;
  1136. PROCESS_INFORMATION pi;
  1137. memset(&start, 0, sizeof (start));
  1138. start.cb = sizeof (start);
  1139. MultiByteToWideChar(CP_UTF8, 0, epmd, -1, wcepmd, MAXPATHLEN+100);
  1140. if (!CreateProcessW(NULL, wcepmd, NULL, NULL, FALSE,
  1141. CREATE_DEFAULT_ERROR_MODE | DETACHED_PROCESS,
  1142. NULL, NULL, &start, &pi))
  1143. result = -1;
  1144. else
  1145. result = 0;
  1146. }
  1147. #else
  1148. result = system(epmd);
  1149. #endif
  1150. if (result == -1) {
  1151. fprintf(stderr, "Error spawning %s (error %d)\n", epmd_cmd,errno);
  1152. exit(1);
  1153. }
  1154. }
  1155. static void
  1156. add_arg(char *new_arg)
  1157. {
  1158. if (argsCnt >= argsSz)
  1159. argsp = (char **) erealloc((void *) argsp,
  1160. sizeof(char *) * (argsSz += 20));
  1161. argsp[argsCnt++] = QUOTE(new_arg);
  1162. }
  1163. static void
  1164. add_args(char *first_arg, ...)
  1165. {
  1166. va_list ap;
  1167. char* arg;
  1168. add_arg(first_arg);
  1169. va_start(ap, first_arg);
  1170. while ((arg = va_arg(ap, char *)) != NULL) {
  1171. add_arg(arg);
  1172. }
  1173. va_end(ap);
  1174. }
  1175. static void
  1176. ensure_EargsSz(int sz)
  1177. {
  1178. if (EargsSz < sz)
  1179. Eargsp = (char **) erealloc((void *) Eargsp,
  1180. sizeof(char *) * (EargsSz = sz));
  1181. }
  1182. static void
  1183. add_Eargs(char *new_arg)
  1184. {
  1185. if (EargsCnt >= EargsSz)
  1186. Eargsp = (char **) erealloc((void *) Eargsp,
  1187. sizeof(char *) * (EargsSz += 20));
  1188. Eargsp[EargsCnt++] = QUOTE(new_arg);
  1189. }
  1190. #if !defined(__WIN32__)
  1191. void error(char* format, ...)
  1192. {
  1193. char sbuf[1024];
  1194. va_list ap;
  1195. va_start(ap, format);
  1196. erts_vsnprintf(sbuf, sizeof(sbuf), format, ap);
  1197. va_end(ap);
  1198. fprintf(stderr, "erlexec: %s\n", sbuf);
  1199. exit(1);
  1200. }
  1201. #endif
  1202. static void *
  1203. emalloc(size_t size)
  1204. {
  1205. void *p = malloc(size);
  1206. if (p == NULL)
  1207. error("Insufficient memory");
  1208. return p;
  1209. }
  1210. static void *
  1211. erealloc(void *p, size_t size)
  1212. {
  1213. void *res = realloc(p, size);
  1214. if (res == NULL)
  1215. error("Insufficient memory");
  1216. return res;
  1217. }
  1218. static void
  1219. efree(void *p)
  1220. {
  1221. free(p);
  1222. }
  1223. static int
  1224. is_one_of_strings(char *str, char *strs[])
  1225. {
  1226. int i, j;
  1227. for (i = 0; strs[i]; i++) {
  1228. for (j = 0; str[j] && strs[i][j] && str[j] == strs[i][j]; j++);
  1229. if (!str[j] && !strs[i][j])
  1230. return 1;
  1231. }
  1232. return 0;
  1233. }
  1234. static char *write_str(char *to, const char *from)
  1235. {
  1236. while (*from)
  1237. *(to++) = *(from++);
  1238. *to = '\0';
  1239. return to;
  1240. }
  1241. char*
  1242. strsave(char* string)
  1243. {
  1244. char* p = emalloc(strlen(string)+1);
  1245. strcpy(p, string);
  1246. return p;
  1247. }
  1248. #if defined(__WIN32__)
  1249. static void get_start_erl_data(char *file)
  1250. {
  1251. int fp;
  1252. char tmpbuffer[512];
  1253. char start_erl_data[512];
  1254. int bytesread;
  1255. char* env;
  1256. char* reldir;
  1257. char* otpstring;
  1258. char* tprogname;
  1259. if (boot_script)
  1260. error("Conflicting -start_erl and -boot options");
  1261. if (config_script)
  1262. error("Conflicting -start_erl and -config options");
  1263. env = get_env("RELDIR");
  1264. if (env)
  1265. reldir = strsave(env);
  1266. else {
  1267. erts_snprintf(tmpbuffer, sizeof(tmpbuffer), "%s/releases", rootdir);
  1268. reldir = strsave(tmpbuffer);
  1269. }
  1270. free_env_val(env);
  1271. if (file == NULL)
  1272. erts_snprintf(start_erl_data, sizeof(start_erl_data), "%s/start_erl.data", reldir);
  1273. else
  1274. erts_snprintf(start_erl_data, sizeof(start_erl_data), "%s", file);
  1275. fp = _open(start_erl_data, _O_RDONLY );
  1276. if( fp == -1 )
  1277. error( "open failed on %s",start_erl_data );
  1278. else {
  1279. if( ( bytesread = _read( fp, tmpbuffer, 512 ) ) <= 0 )
  1280. error( "Problem reading file %s", start_erl_data );
  1281. else {
  1282. tmpbuffer[bytesread]='\0';
  1283. if ((otpstring = strchr(tmpbuffer,' ')) != NULL) {
  1284. *otpstring = '\0';
  1285. otpstring++;
  1286. /*
  1287. * otpstring is the otpversion
  1288. * tmpbuffer is the emuversion
  1289. */
  1290. }
  1291. }
  1292. }
  1293. tprogname = otpstring;
  1294. while (*tprogname) {
  1295. if (*tprogname <= ' ') {
  1296. *tprogname='\0';
  1297. break;
  1298. }
  1299. tprogname++;
  1300. }
  1301. bindir = emalloc(512);
  1302. erts_snprintf(bindir,512,"%s/erts-%s/bin",rootdir,tmpbuffer);
  1303. /* BINDIR=$ROOTDIR/erts-$ERTS_VSN/bin */
  1304. tprogname = progname;
  1305. progname = emalloc(strlen(tprogname) + 20);
  1306. erts_snprintf(progname,strlen(tprogname) + 20,"%s -start_erl",tprogname);
  1307. boot_script = emalloc(512);
  1308. config_script = emalloc(512);
  1309. erts_snprintf(boot_script, 512, "%s/%s/start", reldir, otpstring);
  1310. erts_snprintf(config_script, 512, "%s/%s/sys", reldir, otpstring);
  1311. }
  1312. static wchar_t *replace_filename(wchar_t *path, wchar_t *new_base)
  1313. {
  1314. int plen = wcslen(path);
  1315. wchar_t *res = (wchar_t *) emalloc((plen+wcslen(new_base)+1)*sizeof(wchar_t));
  1316. wchar_t *p;
  1317. wcscpy(res,path);
  1318. for (p = res+plen-1 ;p >= res && *p != L'\\'; --p)
  1319. ;
  1320. *(p+1) =L'\0';
  1321. wcscat(res,new_base);
  1322. return res;
  1323. }
  1324. static char *path_massage(wchar_t *long_path)
  1325. {
  1326. char *p;
  1327. int len;
  1328. len = WideCharToMultiByte(CP_UTF8, 0, long_path, -1, NULL, 0, NULL, NULL);
  1329. p = emalloc(len*sizeof(char));
  1330. WideCharToMultiByte(CP_UTF8, 0, long_path, -1, p, len, NULL, NULL);
  1331. return p;
  1332. }
  1333. static char *do_lookup_in_section(InitSection *inis, char *name,
  1334. char *section, wchar_t *filename, int is_path)
  1335. {
  1336. char *p = lookup_init_entry(inis, name);
  1337. if (p == NULL) {
  1338. error("Could not find key %s in section %s of file %S",
  1339. name,section,filename);
  1340. }
  1341. return strsave(p);
  1342. }
  1343. // Setup bindir, rootdir and progname as utf8 buffers
  1344. static void get_parameters(int argc, char** argv)
  1345. {
  1346. wchar_t *p;
  1347. wchar_t buffer[MAX_PATH];
  1348. wchar_t *ini_filename;
  1349. HANDLE module = GetModuleHandle(NULL); /* This might look strange, but we want the erl.ini
  1350. that resides in the same dir as erl.exe, not
  1351. an erl.ini in our directory */
  1352. InitFile *inif;
  1353. InitSection *inis;
  1354. if (module == NULL) {
  1355. error("Cannot GetModuleHandle()");
  1356. }
  1357. if (GetModuleFileNameW(module,buffer,MAX_PATH) == 0) {
  1358. error("Could not GetModuleFileName");
  1359. }
  1360. ini_filename = replace_filename(buffer,INI_FILENAME);
  1361. if ((inif = load_init_file(ini_filename)) == NULL) {
  1362. wchar_t wbindir[MAX_PATH];
  1363. wchar_t wrootdir[MAX_PATH];
  1364. /* Assume that the path is absolute and that
  1365. it does not contain any symbolic link */
  1366. /* Determine bindir */
  1367. if (GetEnvironmentVariableW(L"ERLEXEC_DIR", buffer, MAX_PATH) == 0) {
  1368. wcscpy(buffer, ini_filename);
  1369. for (p = buffer+wcslen(buffer)-1; p >= buffer && *p != L'\\'; --p)
  1370. ;
  1371. *p = L'\0';
  1372. }
  1373. bindir = path_massage(buffer);
  1374. /* Determine rootdir */
  1375. for (p = buffer+wcslen(buffer)-1; p >= buffer && *p != L'\\'; --p)
  1376. ;
  1377. p--;
  1378. for (;p >= buffer && *p != L'\\'; --p)
  1379. ;
  1380. *p =L'\0';
  1381. rootdir = path_massage(buffer);
  1382. /* Hardcoded progname */
  1383. progname = strsave(DEFAULT_PROGNAME);
  1384. } else {
  1385. if ((inis = lookup_init_section(inif,INI_SECTION)) == NULL) {
  1386. error("Could not find section %s in init file %s",
  1387. INI_SECTION, ini_filename);
  1388. }
  1389. bindir = do_lookup_in_section(inis, "Bindir", INI_SECTION, ini_filename,1);
  1390. rootdir = do_lookup_in_section(inis, "Rootdir", INI_SECTION,
  1391. ini_filename,1);
  1392. progname = do_lookup_in_section(inis, "Progname", INI_SECTION,
  1393. ini_filename,0);
  1394. free_init_file(inif);
  1395. }
  1396. emu = EMULATOR_EXECUTABLE;
  1397. start_emulator_program = strsave(argv[0]);
  1398. free(ini_filename);
  1399. }
  1400. static void
  1401. get_home(void)
  1402. {
  1403. wchar_t *profile;
  1404. char* homedrive;
  1405. char* homepath;
  1406. homedrive = get_env("HOMEDRIVE");
  1407. homepath = get_env("HOMEPATH");
  1408. if (!homedrive || !homepath) {
  1409. if (SHGetKnownFolderPath(&FOLDERID_Profile, 0, NULL, &profile) == S_OK) {
  1410. home = utf16_to_utf8(profile);
  1411. /* CoTaskMemFree(profile); */
  1412. } else
  1413. error("HOMEDRIVE or HOMEPATH is not set and GetWindowsDir failed");
  1414. } else {
  1415. home = emalloc(strlen(homedrive)+strlen(homepath)+1);
  1416. strcpy(home, homedrive);
  1417. strcat(home, homepath);
  1418. }
  1419. free_env_val(homedrive);
  1420. free_env_val(homepath);
  1421. }
  1422. #else
  1423. static void
  1424. get_parameters(int argc, char** argv)
  1425. {
  1426. progname = get_env("PROGNAME");
  1427. if (!progname) {
  1428. progname = strsave(DEFAULT_PROGNAME);
  1429. }
  1430. emu = get_env("EMU");
  1431. if (!emu) {
  1432. emu = strsave(EMULATOR_EXECUTABLE);
  1433. }
  1434. bindir = get_env("BINDIR");
  1435. if (!bindir) {
  1436. /* Determine bindir from absolute path to executable */
  1437. char *p;
  1438. char buffer[PATH_MAX];
  1439. strncpy(buffer, argv[0], sizeof(buffer));
  1440. buffer[sizeof(buffer)-1] = '\0';
  1441. for (p = buffer+strlen(buffer)-1 ; p >= buffer && *p != '/'; --p)
  1442. ;
  1443. *p ='\0';
  1444. bindir = strsave(buffer);
  1445. }
  1446. rootdir = get_env("ROOTDIR");
  1447. if (!rootdir) {
  1448. /* Determine rootdir from absolute path to bindir */
  1449. char *p;
  1450. char buffer[PATH_MAX];
  1451. strncpy(buffer, bindir, sizeof(buffer));
  1452. buffer[sizeof(buffer)-1] = '\0';
  1453. for (p = buffer+strlen(buffer)-1; p >= buffer && *p != '/'; --p)
  1454. ;
  1455. p--;
  1456. for (; p >= buffer && *p != '/'; --p)
  1457. ;
  1458. *p ='\0';
  1459. rootdir = strsave(buffer);
  1460. }
  1461. if (!progname || !emu || !rootdir || !bindir) {
  1462. error("PROGNAME, EMU, ROOTDIR and BINDIR must be set");
  1463. }
  1464. }
  1465. static void
  1466. get_home(void)
  1467. {
  1468. home = get_env("HOME");
  1469. if (home == NULL)
  1470. error("HOME must be set");
  1471. }
  1472. #endif
  1473. static void add_epmd_port(void)
  1474. {
  1475. char* port = get_env("ERL_EPMD_PORT");
  1476. if (port != NULL) {
  1477. add_args("-epmd_port", port, NULL);
  1478. }
  1479. }
  1480. static char **build_args_from_env(char *env_var)
  1481. {
  1482. char *value = get_env(env_var);
  1483. char **res = build_args_from_string(value);
  1484. free_env_val(value);
  1485. return res;
  1486. }
  1487. static char **build_args_from_string(char *string)
  1488. {
  1489. int argc = 0;
  1490. char **argv = NULL;
  1491. int alloced = 0;
  1492. char **cur_s = NULL; /* Initialized to avoid warning. */
  1493. int s_alloced = 0;
  1494. int s_pos = 0;
  1495. char *p = string;
  1496. enum {Start, Build, Build0, BuildSQuoted, BuildDQuoted, AcceptNext} state;
  1497. #define ENSURE() \
  1498. if (s_pos >= s_alloced) { \
  1499. if (!*cur_s) { \
  1500. *cur_s = emalloc(s_alloced = 20); \
  1501. } else { \
  1502. *cur_s = erealloc(*cur_s, s_alloced += 20); \
  1503. } \
  1504. }
  1505. if (!p)
  1506. return NULL;
  1507. argv = emalloc(sizeof(char *) * (alloced = 10));
  1508. state = Start;
  1509. for(;;) {
  1510. switch (state) {
  1511. case Start:
  1512. if (!*p)
  1513. goto done;
  1514. if (argc >= alloced - 1) { /* Make room for extra NULL */
  1515. argv = erealloc(argv, (alloced += 10) * sizeof(char *));
  1516. }
  1517. cur_s = argc + argv;
  1518. *cur_s = NULL;
  1519. s_pos = 0;
  1520. s_alloced = 0;
  1521. state = Build0;
  1522. break;
  1523. case Build0:
  1524. switch (*p) {
  1525. case ' ':
  1526. ++p;
  1527. break;
  1528. case '\0':
  1529. state = Start;
  1530. break;
  1531. default:
  1532. state = Build;
  1533. break;
  1534. }
  1535. break;
  1536. case Build:
  1537. switch (*p) {
  1538. case ' ':
  1539. case '\0':
  1540. ENSURE();
  1541. (*cur_s)[s_pos] = '\0';
  1542. ++argc;
  1543. state = Start;
  1544. break;
  1545. case '"':
  1546. ++p;
  1547. state = BuildDQuoted;
  1548. break;
  1549. case '\'':
  1550. ++p;
  1551. state = BuildSQuoted;
  1552. break;
  1553. case '\\':
  1554. ++p;
  1555. state = AcceptNext;
  1556. break;
  1557. default:
  1558. ENSURE();
  1559. (*cur_s)[s_pos++] = *p++;
  1560. break;
  1561. }
  1562. break;
  1563. case BuildDQuoted:
  1564. switch (*p) {
  1565. case '"':
  1566. ++p;
  1567. /* fall through */
  1568. case '\0':
  1569. state = Build;
  1570. break;
  1571. default:
  1572. ENSURE();
  1573. (*cur_s)[s_pos++] = *p++;
  1574. break;
  1575. }
  1576. break;
  1577. case BuildSQuoted:
  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 AcceptNext:
  1592. if (!*p) {
  1593. state = Build;
  1594. } else {
  1595. ENSURE();
  1596. (*cur_s)[s_pos++] = *p++;
  1597. }
  1598. state = Build;
  1599. break;
  1600. }
  1601. }
  1602. done:
  1603. argv[argc] = NULL; /* Sure to be large enough */
  1604. if (!argc) {
  1605. efree(argv);
  1606. return NULL;
  1607. }
  1608. return argv;
  1609. #undef ENSURE
  1610. }
  1611. static char *
  1612. errno_string(void)
  1613. {
  1614. char *str = strerror(errno);
  1615. if (!str)
  1616. return "unknown error";
  1617. return str;
  1618. }
  1619. static char **
  1620. read_args_file(char *filename)
  1621. {
  1622. int c, aix = 0, quote = 0, cmnt = 0, asize = 0;
  1623. char **res, *astr = NULL;
  1624. FILE *file;
  1625. #undef EAF_CMNT
  1626. #undef EAF_QUOTE
  1627. #undef SAVE_CHAR
  1628. #define EAF_CMNT (1 << 8)
  1629. #define EAF_QUOTE (1 << 9)
  1630. #define SAVE_CHAR(C) \
  1631. do { \
  1632. if (!astr) \
  1633. astr = emalloc(sizeof(char)*(asize = 20)); \
  1634. if (aix == asize) \
  1635. astr = erealloc(astr, sizeof(char)*(asize += 20)); \
  1636. if (' ' != (char) (C)) \
  1637. astr[aix++] = (char) (C); \
  1638. else if (aix > 0 && astr[aix-1] != ' ') \
  1639. astr[aix++] = ' '; \
  1640. } while (0)
  1641. do {
  1642. errno = 0;
  1643. file = fopen(filename, "r");
  1644. } while (!file && errno == EINTR);
  1645. if (!file) {
  1646. usage_format("Failed to open arguments file \"%s\": %s\n",
  1647. filename,
  1648. errno_string());
  1649. }
  1650. while (1) {
  1651. c = getc(file);
  1652. if (c == EOF) {
  1653. if (ferror(file)) {
  1654. if (errno == EINTR) {
  1655. clearerr(file);
  1656. continue;
  1657. }
  1658. usage_format("Failed to read arguments file \"%s\": %s\n",
  1659. filename,
  1660. errno_string());
  1661. }
  1662. break;
  1663. }
  1664. switch (quote | cmnt | c) {
  1665. case '\\':
  1666. quote = EAF_QUOTE;
  1667. break;
  1668. case '#':
  1669. cmnt = EAF_CMNT;
  1670. break;
  1671. case EAF_CMNT|'\n':
  1672. cmnt = 0;
  1673. /* Fall through... */
  1674. case '\n':
  1675. case '\f':
  1676. case '\r':
  1677. case '\t':
  1678. case '\v':
  1679. if (!quote)
  1680. c = ' ';
  1681. /* Fall through... */
  1682. default:
  1683. if (!cmnt)
  1684. SAVE_CHAR(c);
  1685. quote = 0;
  1686. break;
  1687. }
  1688. }
  1689. SAVE_CHAR('\0');
  1690. fclose(file);
  1691. if (astr[0] == '\0')
  1692. res = NULL;
  1693. else
  1694. res = build_args_from_string(astr);
  1695. efree(astr);
  1696. return res;
  1697. #undef EAF_CMNT
  1698. #undef EAF_QUOTE
  1699. #undef SAVE_CHAR
  1700. }
  1701. typedef struct {
  1702. char **argv;
  1703. int argc;
  1704. int size;
  1705. } argv_buf;
  1706. static void
  1707. trim_argv_buf(argv_buf *abp)
  1708. {
  1709. abp->argv = erealloc(abp->argv, sizeof(char *)*(abp->size = abp->argc));
  1710. }
  1711. static void
  1712. save_arg(argv_buf *abp, char *arg)
  1713. {
  1714. if (abp->size <= abp->argc) {
  1715. if (!abp->argv)
  1716. abp->argv = emalloc(sizeof(char *)*(abp->size = 100));
  1717. else
  1718. abp->argv = erealloc(abp->argv, sizeof(char *)*(abp->size += 100));
  1719. }
  1720. abp->argv[abp->argc++] = arg;
  1721. }
  1722. #define DEF_ARGV_STACK_SIZE 10
  1723. #define ARGV_STACK_SIZE_INCR 50
  1724. typedef struct {
  1725. char **argv;
  1726. int ix;
  1727. } argv_stack_element;
  1728. typedef struct {
  1729. int top_ix;
  1730. int size;
  1731. argv_stack_element *base;
  1732. argv_stack_element def_buf[DEF_ARGV_STACK_SIZE];
  1733. } argv_stack;
  1734. #define ARGV_STACK_INIT(S) \
  1735. do { \
  1736. (S)->top_ix = 0; \
  1737. (S)->size = DEF_ARGV_STACK_SIZE; \
  1738. (S)->base = &(S)->def_buf[0]; \
  1739. } while (0)
  1740. static void
  1741. push_argv(argv_stack *stck, char **argv, int ix)
  1742. {
  1743. if (stck->top_ix == stck->size) {
  1744. if (stck->base != &stck->def_buf[0]) {
  1745. stck->size += ARGV_STACK_SIZE_INCR;
  1746. stck->base = erealloc(stck->base,
  1747. sizeof(argv_stack_element)*stck->size);
  1748. }
  1749. else {
  1750. argv_stack_element *base;
  1751. base = emalloc(sizeof(argv_stack_element)
  1752. *(stck->size + ARGV_STACK_SIZE_INCR));
  1753. memcpy((void *) base,
  1754. (void *) stck->base,
  1755. sizeof(argv_stack_element)*stck->size);
  1756. stck->base = base;
  1757. stck->size += ARGV_STACK_SIZE_INCR;
  1758. }
  1759. }
  1760. stck->base[stck->top_ix].argv = argv;
  1761. stck->base[stck->top_ix++].ix = ix;
  1762. }
  1763. static void
  1764. pop_argv(argv_stack *stck, char ***argvp, int *ixp)
  1765. {
  1766. if (stck->top_ix == 0) {
  1767. *argvp = NULL;
  1768. *ixp = 0;
  1769. }
  1770. else {
  1771. *argvp = stck->base[--stck->top_ix].argv;
  1772. *ixp = stck->base[stck->top_ix].ix;
  1773. if (stck->top_ix == 0 && stck->base != &stck->def_buf[0]) {
  1774. efree(stck->base);
  1775. stck->base = &stck->def_buf[0];
  1776. stck->size = DEF_ARGV_STACK_SIZE;
  1777. }
  1778. }
  1779. }
  1780. static void
  1781. get_file_args(char *filename, argv_buf *abp, argv_buf *xabp)
  1782. {
  1783. argv_stack stck;
  1784. int i;
  1785. char **argv;
  1786. ARGV_STACK_INIT(&stck);
  1787. i = 0;
  1788. argv = read_args_file(filename);
  1789. while (argv) {
  1790. while (argv[i]) {
  1791. if (strcmp(argv[i], "-args_file") == 0) {
  1792. char **new_argv;
  1793. char *fname;
  1794. if (!argv[++i])
  1795. usage("-args_file");
  1796. fname = argv[i++];
  1797. new_argv = read_args_file(fname);
  1798. if (new_argv) {
  1799. if (argv[i])
  1800. push_argv(&stck, argv, i);
  1801. else
  1802. efree(argv);
  1803. i = 0;
  1804. argv = new_argv;
  1805. }
  1806. }
  1807. else {
  1808. if (strcmp(argv[i], "-extra") == 0) {
  1809. i++;
  1810. while (argv[i])
  1811. save_arg(xabp, argv[i++]);
  1812. break;
  1813. }
  1814. save_arg(abp, argv[i++]);
  1815. }
  1816. }
  1817. efree(argv);
  1818. pop_argv(&stck, &argv, &i);
  1819. }
  1820. }
  1821. static void
  1822. initial_argv_massage(int *argc, char ***argv)
  1823. {
  1824. argv_buf ab = {0}, xab = {0};
  1825. int ix, vix, ac;
  1826. char **av;
  1827. struct {
  1828. int argc;
  1829. char **argv;
  1830. } avv[] = {{INT_MAX, NULL}, {INT_MAX, NULL}, {INT_MAX, NULL},
  1831. {INT_MAX, NULL}, {INT_MAX, NULL}, {INT_MAX, NULL}};
  1832. /*
  1833. * The environment flag containing OTP release is intentionally
  1834. * undocumented and intended for OTP internal use only.
  1835. */
  1836. vix = 0;
  1837. av = build_args_from_env("ERL_OTP" OTP_SYSTEM_VERSION "_FLAGS");
  1838. if (av)
  1839. avv[vix++].argv = av;
  1840. av = build_args_from_env("ERL_AFLAGS");
  1841. if (av)
  1842. avv[vix++].argv = av;
  1843. /* command line */
  1844. if (*argc > 1) {
  1845. avv[vix].argc = *argc - 1;
  1846. avv[vix++].argv = &(*argv)[1];
  1847. }
  1848. av = build_args_from_env("ERL_FLAGS");
  1849. if (av)
  1850. avv[vix++].argv = av;
  1851. av = build_args_from_env("ERL_ZFLAGS");
  1852. if (av)
  1853. avv[vix++].argv = av;
  1854. if (vix == (*argc > 1 ? 1 : 0)) {
  1855. /* Only command line argv; check if we can use argv as it is... */
  1856. ac = *argc;
  1857. av = *argv;
  1858. for (ix = 1; ix < ac; ix++) {
  1859. if (strcmp(av[ix], "-args_file") == 0) {
  1860. /* ... no; we need to expand arguments from
  1861. file into argument list */
  1862. goto build_new_argv;
  1863. }
  1864. if (strcmp(av[ix], "-extra") == 0) {
  1865. break;
  1866. }
  1867. }
  1868. /* ... yes; we can use argv as it is. */
  1869. return;
  1870. }
  1871. build_new_argv:
  1872. save_arg(&ab, (*argv)[0]);
  1873. vix = 0;
  1874. while (avv[vix].argv) {
  1875. ac = avv[vix].argc;
  1876. av = avv[vix].argv;
  1877. ix = 0;
  1878. while (ix < ac && av[ix]) {
  1879. if (strcmp(av[ix], "-args_file") == 0) {
  1880. if (++ix == ac)
  1881. usage("-args_file");
  1882. get_file_args(av[ix++], &ab, &xab);
  1883. }
  1884. else {
  1885. if (strcmp(av[ix], "-extra") == 0) {
  1886. ix++;
  1887. while (ix < ac && av[ix])
  1888. save_arg(&xab, av[ix++]);
  1889. break;
  1890. }
  1891. save_arg(&ab, av[ix++]);
  1892. }
  1893. }
  1894. vix++;
  1895. }
  1896. vix = 0;
  1897. while (avv[vix].argv) {
  1898. if (avv[vix].argc == INT_MAX) /* not command line */
  1899. efree(avv[vix].argv);
  1900. vix++;
  1901. }
  1902. if (xab.argc) {
  1903. save_arg(&ab, "-extra");
  1904. for (ix = 0; ix < xab.argc; ix++)
  1905. save_arg(&ab, xab.argv[ix]);
  1906. efree(xab.argv);
  1907. }
  1908. save_arg(&ab, NULL);
  1909. trim_argv_buf(&ab);
  1910. *argv = ab.argv;
  1911. *argc = ab.argc - 1;
  1912. }
  1913. #ifdef __WIN32__
  1914. static char*
  1915. possibly_quote(char* arg)
  1916. {
  1917. int mustQuote = NO;
  1918. int n = 0;
  1919. char* s;
  1920. char* narg;
  1921. /*
  1922. * Scan the string to find out if it needs quoting and return
  1923. * the original argument if not.
  1924. */
  1925. for (s = arg; *s; s++, n++) {
  1926. if (*s == ' ' || *s == '"') {
  1927. mustQuote = YES;
  1928. n++;
  1929. }
  1930. }
  1931. if (!mustQuote) {
  1932. return arg;
  1933. }
  1934. /*
  1935. * Insert the quotes and put a backslash in front of every quote
  1936. * inside the string.
  1937. */
  1938. s = narg = emalloc(n+2+1);
  1939. for (*s++ = '"'; *arg; arg++, s++) {
  1940. if (*s == '"') {
  1941. *s++ = '\\';
  1942. }
  1943. *s = *arg;
  1944. }
  1945. *s++ = '"';
  1946. *s = '\0';
  1947. return narg;
  1948. }
  1949. /*
  1950. * Unicode helpers to handle environment and command line parameters on
  1951. * Windows. We internally handle all environment variables in UTF8,
  1952. * but put and get the environment using the WCHAR (limited UTF16) interface
  1953. *
  1954. * These are simplified to only handle Unicode characters that can fit in
  1955. * Windows simplified UTF16, i.e. characters that fit in 16 bits.
  1956. */
  1957. static int utf8_len(unsigned char first)
  1958. {
  1959. if ((first & ((unsigned char) 0x80)) == 0) {
  1960. return 1;
  1961. } else if ((first & ((unsigned char) 0xE0)) == 0xC0) {
  1962. return 2;
  1963. } else if ((first & ((unsigned char) 0xF0)) == 0xE0) {
  1964. return 3;
  1965. } else if ((first & ((unsigned char) 0xF8)) == 0xF0) {
  1966. return 4;
  1967. }
  1968. return 1; /* will be a '?' */
  1969. }
  1970. static WCHAR *utf8_to_utf16(unsigned char *bytes)
  1971. {
  1972. unsigned int unipoint;
  1973. unsigned char *tmp = bytes;
  1974. WCHAR *target, *res;
  1975. int num = 0;
  1976. while (*tmp) {
  1977. num++;
  1978. tmp += utf8_len(*tmp);
  1979. }
  1980. res = target = emalloc((num + 1) * sizeof(WCHAR));
  1981. while (*bytes) {
  1982. if (((*bytes) & ((unsigned char) 0x80)) == 0) {
  1983. unipoint = (unsigned int) *bytes;
  1984. ++bytes;
  1985. } else if (((*bytes) & ((unsigned char) 0xE0)) == 0xC0) {
  1986. unipoint =
  1987. (((unsigned int) ((*bytes) & ((unsigned char) 0x1F))) << 6) |
  1988. ((unsigned int) (bytes[1] & ((unsigned char) 0x3F)));
  1989. bytes += 2;
  1990. } else if (((*bytes) & ((unsigned char) 0xF0)) == 0xE0) {
  1991. unipoint =
  1992. (((unsigned int) ((*bytes) & ((unsigned char) 0xF))) << 12) |
  1993. (((unsigned int) (bytes[1] & ((unsigned char) 0x3F))) << 6) |
  1994. ((unsigned int) (bytes[2] & ((unsigned char) 0x3F)));
  1995. if (unipoin

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