PageRenderTime 54ms CodeModel.GetById 12ms RepoModel.GetById 1ms app.codeStats 0ms

/erts/etc/common/erlexec.c

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