PageRenderTime 99ms CodeModel.GetById 49ms RepoModel.GetById 1ms app.codeStats 0ms

/erts/etc/common/erlexec.c

http://github.com/erlang/otp
C | 2329 lines | 2294 code | 8 blank | 27 comment | 5 complexity | 1b5e0e8094308c60720b530478cded94 MD5 | raw file
Possible License(s): BSD-3-Clause, Apache-2.0, Unlicense, LGPL-2.1, MPL-2.0-no-copyleft-exception

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

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

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