PageRenderTime 56ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/erts/etc/common/erlexec.c

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