PageRenderTime 67ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/erts/etc/common/erlexec.c

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