PageRenderTime 51ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/erts/etc/common/erlexec.c

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