in erts/etc/common/erlexec.c [417:1214]
int main(int argc, char **argv)
#endif
{
int haltAfterwards = 0; /* If true, put '-s erlang halt' at the end
* of the arguments. */
int isdistributed = 0;
int no_epmd = 0;
int i;
char* s;
char *epmd_prog = NULL;
int process_args = 1;
int print_args_exit = 0;
int print_qouted_cmd_exit = 0;
char* emu_name;
#ifdef __WIN32__
this_module_handle = module;
run_werl = windowed;
/* if we started this erl just to get a detached emulator,
* the arguments are already prepared for beam, so we skip
* directly to start_emulator */
s = get_env("ERL_CONSOLE_MODE");
if (s != NULL && strcmp(s, "detached")==0) {
free_env_val(s);
s = get_env("ERL_EMULATOR_DLL");
if (s != NULL) {
argv[0] = strsave(s);
} else {
argv[0] = strsave(EMULATOR_EXECUTABLE);
}
ensure_EargsSz(argc + 1);
memcpy((void *) Eargsp, (void *) argv, argc * sizeof(char *));
Eargsp[argc] = NULL;
emu = argv[0];
start_emulator_program = strsave(argv[0]);
goto skip_arg_massage;
}
free_env_val(s);
#else
int reset_cerl_detached = 0;
s = get_env("CERL_DETACHED_PROG");
if (s && strcmp(s, "") != 0) {
emu = s;
start_detached = 1;
reset_cerl_detached = 1;
ensure_EargsSz(argc + 1);
memcpy((void *) Eargsp, (void *) argv, argc * sizeof(char *));
Eargsp[argc] = emu;
Eargsp[argc] = NULL;
goto skip_arg_massage;
}
free_env_val(s);
#endif
initial_argv_massage(&argc, &argv); /* Merge with env; expand -args_file */
i = 1;
#ifdef __WIN32__
/* Not used? /rickard */
if ((argc > 2) && (strcmp(argv[i], "-regkey") == 0)) {
key_val_name = strsave(argv[i+1]);
i = 3;
}
#endif
get_parameters(argc, argv);
/*
* Construct the path of the executable.
*/
#if defined(__WIN32__) && defined(WIN32_ALWAYS_DEBUG)
emu_type = "debug";
#endif
/* We need to do this before the ordinary processing. */
while (i < argc) {
if (argv[i][0] == '-') {
if (strcmp(argv[i], "-smp") == 0) {
if (i + 1 >= argc)
goto smp;
if (strcmp(argv[i+1], "auto") == 0) {
i++;
} else if (strcmp(argv[i+1], "enable") == 0) {
i++;
smp_enable:
;
} else if (strcmp(argv[i+1], "disable") == 0) {
i++;
smp_disable:
usage_notsup("-smp disable", " Use \"+S 1\" instead.");
} else {
smp:
;
}
} else if (strcmp(argv[i], "-smpenable") == 0) {
goto smp_enable;
} else if (strcmp(argv[i], "-smpauto") == 0) {
;
} else if (strcmp(argv[i], "-smpdisable") == 0) {
goto smp_disable;
} else if (strcmp(argv[i], "-extra") == 0) {
break;
} else if (strcmp(argv[i], "-emu_type") == 0) {
if (i + 1 >= argc) {
usage(argv[i]);
}
emu_type = argv[i+1];
i++;
} else if (strcmp(argv[i], "-emu_flavor") == 0) {
if (i + 1 >= argc) {
usage(argv[i]);
}
emu_flavor = argv[i+1];
i++;
}
}
i++;
}
emu = add_extra_suffixes(emu);
emu_name = strsave(emu);
erts_snprintf(tmpStr, sizeof(tmpStr), "%s" DIRSEP "%s" BINARY_EXT, bindir, emu);
emu = strsave(tmpStr);
s = get_env("ESCRIPT_NAME");
if(s) {
add_Eargs(s); /* argv[0] = scriptname*/
} else {
add_Eargs(emu); /* argv[0] = erl or cerl */
}
/* Add the bindir to the front of the PATH, and remove all subsequent
* occurrences to avoid ballooning it on repeated up/downgrades. */
s = get_env("PATH");
if (s == NULL) {
erts_snprintf(tmpStr, sizeof(tmpStr),
"%s" PATHSEP "%s" DIRSEP "bin" PATHSEP, bindir, rootdir);
} else if (strstr(s, rootdir) == NULL) {
erts_snprintf(tmpStr, sizeof(tmpStr),
"%s" PATHSEP "%s" DIRSEP "bin" PATHSEP "%s", bindir, rootdir, s);
} else {
const char *bindir_slug, *bindir_slug_index;
int bindir_slug_length;
const char *in_index;
char *out_index;
erts_snprintf(tmpStr, sizeof(tmpStr), "%s" PATHSEP, bindir);
bindir_slug = strsave(tmpStr);
bindir_slug_length = strlen(bindir_slug);
out_index = &tmpStr[bindir_slug_length];
in_index = s;
while ((bindir_slug_index = strstr(in_index, bindir_slug))) {
int block_length = (bindir_slug_index - in_index);
memcpy(out_index, in_index, block_length);
in_index = bindir_slug_index + bindir_slug_length;
out_index += block_length;
}
strcpy(out_index, in_index);
}
free_env_val(s);
set_env("PATH", tmpStr);
i = 1;
get_home();
/* Add the home parameter when available. This is optional to support
systems that don't have the notion of a home directory and setups
that don't have the HOME environment variable set (ERL-476). */
if (home != NULL) {
add_args("-home", home, NULL);
}
add_epmd_port();
add_arg("--");
while (i < argc) {
if (!process_args) { /* Copy arguments after '-extra' */
add_arg(argv[i]);
i++;
} else {
switch (argv[i][0]) {
case '-':
switch (argv[i][1]) {
#ifdef __WIN32__
case 'b':
if (strcmp(argv[i], "-boot") == 0) {
if (boot_script)
error("Conflicting -boot options");
if (got_start_erl)
error("Conflicting -start_erl and -boot options");
if (i+1 >= argc)
usage("-boot");
boot_script = strsave(argv[i+1]);
i++;
}
else {
add_arg(argv[i]);
}
break;
#endif
case 'c':
if (strcmp(argv[i], "-compile") == 0) {
/*
* Note that the shell script erl.exec does a recursive call
* on itself here. We'll avoid doing that.
*/
add_args("-noshell", "-noinput", "-s", "c", "lc_batch",
NULL);
add_Eargs("-B");
haltAfterwards = 0;
}
#ifdef __WIN32__
else if (strcmp(argv[i], "-config") == 0){
if (got_start_erl)
error("Conflicting -start_erl and -config options");
if (i+1 >= argc)
usage("-config");
do {
config_script_cnt++;
config_scripts = erealloc(config_scripts,
config_script_cnt * sizeof(char*));
config_scripts[config_script_cnt-1] = strsave(argv[i+1]);
i++;
} while ((i+1) < argc && argv[i+1][0] != '-' && argv[i+1][0] != '+');
}
#endif
else {
add_arg(argv[i]);
}
break;
case 'd':
if (strcmp(argv[i], "-detached") != 0) {
add_arg(argv[i]);
} else {
start_detached = 1;
add_args("-noshell", "-noinput", NULL);
}
break;
case 'e':
if (strcmp(argv[i], "-extra") == 0) {
process_args = 0;
ADD_BOOT_CONFIG;
add_arg(argv[i]);
} else if (strcmp(argv[i], "-emu_args") == 0) { /* -emu_args */
verbose = 1;
} else if (strcmp(argv[i], "-emu_args_exit") == 0) {
print_args_exit = 1;
} else if (strcmp(argv[i], "-emu_name_exit") == 0) {
printf("%s\n", emu_name);
exit(0);
} else if (strcmp(argv[i], "-emu_qouted_cmd_exit") == 0) {
print_qouted_cmd_exit = 1;
} else if (strcmp(argv[i], "-env") == 0) { /* -env VARNAME VARVALUE */
if (i+2 >= argc)
usage("-env");
set_env(argv[i+1], argv[i+2]);
i += 2;
} else if (strcmp(argv[i], "-epmd") == 0) {
if (i+1 >= argc)
usage("-epmd");
epmd_prog = argv[i+1];
++i;
} else {
add_arg(argv[i]);
}
break;
case 'k':
if (strcmp(argv[i], "-keep_window") == 0) {
keep_window = 1;
} else
add_arg(argv[i]);
break;
case 'm':
/*
* Note that the shell script erl.exec does a recursive call
* on itself here. We'll avoid doing that.
*/
if (strcmp(argv[i], "-make") == 0) {
add_args("-noshell", "-noinput", "-s", "make", "all_or_nothing", NULL);
add_Eargs("-B");
haltAfterwards = 1;
i = argc; /* Skip rest of command line */
} else if (strcmp(argv[i], "-man") == 0) {
#if defined(__WIN32__)
error("-man not supported on Windows");
#else
argv[i] = "man";
erts_snprintf(tmpStr, sizeof(tmpStr), "%s/man", rootdir);
set_env("MANPATH", tmpStr);
execvp("man", argv+i);
error("Could not execute the 'man' command.");
#endif
} else
add_arg(argv[i]);
break;
case 'n':
if (strcmp(argv[i], "-name") == 0) { /* -name NAME */
if (i+1 >= argc)
usage("-name");
/*
* Note: Cannot use add_args() here, due to non-defined
* evaluation order.
*/
add_arg(argv[i]);
add_arg(argv[i+1]);
isdistributed = 1;
i++;
} else if (strcmp(argv[i], "-noinput") == 0) {
add_args("-noshell", "-noinput", NULL);
} else if (strcmp(argv[i], "-nohup") == 0) {
add_arg("-nohup");
nohup = 1;
} else if (strcmp(argv[i], "-no_epmd") == 0) {
add_arg("-no_epmd");
no_epmd = 1;
} else {
add_arg(argv[i]);
}
break;
case 's': /* -sname NAME */
if (strcmp(argv[i], "-sname") == 0) {
if (i+1 >= argc)
usage("-sname");
add_arg(argv[i]);
add_arg(argv[i+1]);
isdistributed = 1;
i++;
}
#ifdef __WIN32__
else if (strcmp(argv[i], "-service_event") == 0) {
add_arg(argv[i]);
add_arg(argv[i+1]);
i++;
}
else if (strcmp(argv[i], "-start_erl") == 0) {
if (i+1 < argc && argv[i+1][0] != '-') {
get_start_erl_data(argv[i+1]);
i++;
} else
get_start_erl_data((char *) NULL);
}
#endif
else if (strcmp(argv[i], "-start_epmd") == 0) {
if (i+1 >= argc)
usage("-start_epmd");
if (strcmp(argv[i+1], "true") == 0) {
/* The default */
no_epmd = 0;
}
else if (strcmp(argv[i+1], "false") == 0) {
no_epmd = 1;
}
else
usage_format("Expected boolean argument for \'-start_epmd\'.\n");
add_arg(argv[i]);
add_arg(argv[i+1]);
i++;
}
else
add_arg(argv[i]);
break;
case 'v': /* -version */
if (strcmp(argv[i], "-version") == 0) {
add_Eargs("-V");
} else {
add_arg(argv[i]);
}
break;
default:
add_arg(argv[i]);
break;
} /* switch(argv[i][1] */
break;
case '+':
switch (argv[i][1]) {
case 'a':
case 'A':
case 'C':
case 'e':
case 'i':
case 'n':
case 'P':
case 'Q':
case 't':
case 'T':
case 'R':
case 'W':
case 'K':
if (argv[i][2] != '\0')
goto the_default;
if (i+1 >= argc)
usage(argv[i]);
argv[i][0] = '-';
add_Eargs(argv[i]);
add_Eargs(argv[i+1]);
i++;
break;
case 'I':
if (argv[i][2] == 'O' && (argv[i][3] == 't' || argv[i][3] == 'p')) {
if (argv[i][4] != '\0')
goto the_default;
argv[i][0] = '-';
add_Eargs(argv[i]);
add_Eargs(argv[i+1]);
i++;
break;
}
if (argv[i][2] == 'O' && argv[i][3] == 'P' &&
(argv[i][4] == 't' || argv[i][4] == 'p')) {
if (argv[i][5] != '\0')
goto the_default;
argv[i][0] = '-';
add_Eargs(argv[i]);
add_Eargs(argv[i+1]);
i++;
break;
}
usage(argv[i]);
break;
case 'J':
if (i + 1 >= argc) {
usage(argv[i]);
}
argv[i][0] = '-';
add_Eargs(argv[i]);
add_Eargs(argv[i+1]);
i++;
break;
case 'S':
if (argv[i][2] == 'P') {
if (argv[i][3] != '\0')
goto the_default;
}
else if (argv[i][2] == 'D') {
char* type = argv[i]+3;
if (strncmp(type, "cpu", 3) != 0 &&
strncmp(type, "Pcpu", 4) != 0 &&
strncmp(type, "io", 2) != 0)
usage(argv[i]);
if ((argv[i][3] == 'c' && argv[i][6] != '\0') ||
(argv[i][3] == 'P' && argv[i][7] != '\0') ||
(argv[i][3] == 'i' && argv[i][5] != '\0'))
goto the_default;
}
else if (argv[i][2] != '\0')
goto the_default;
if (i+1 >= argc)
usage(argv[i]);
argv[i][0] = '-';
add_Eargs(argv[i]);
add_Eargs(argv[i+1]);
i++;
break;
case 'B':
argv[i][0] = '-';
if (argv[i][2] != '\0') {
if ((argv[i][2] != 'i') &&
(argv[i][2] != 'c') &&
(argv[i][2] != 'd')) {
usage(argv[i]);
} else {
add_Eargs(argv[i]);
break;
}
}
if (i+1 < argc) {
if ((argv[i+1][0] != '-') &&
(argv[i+1][0] != '+')) {
if (argv[i+1][0] == 'i') {
add_Eargs(argv[i]);
add_Eargs(argv[i+1]);
i++;
break;
} else {
usage(argv[i]);
}
}
}
add_Eargs(argv[i]);
break;
case 'c':
argv[i][0] = '-';
if (argv[i][2] == '\0' && i+1 < argc) {
if (strcmp(argv[i+1], "true") == 0
|| strcmp(argv[i+1], "false") == 0) {
add_Eargs(argv[i]);
add_Eargs(argv[i+1]);
i++;
break;
}
}
add_Eargs(argv[i]);
break;
case 'M': {
int x;
for (x = 0; plusM_au_allocs[x]; x++)
if (plusM_au_allocs[x] == argv[i][2])
break;
if ((plusM_au_allocs[x]
&& is_one_of_strings(&argv[i][3],
plusM_au_alloc_switches))
|| is_one_of_strings(&argv[i][2],
plusM_other_switches)) {
if (i+1 >= argc
|| argv[i+1][0] == '-'
|| argv[i+1][0] == '+')
usage(argv[i]);
argv[i][0] = '-';
add_Eargs(argv[i]);
add_Eargs(argv[i+1]);
i++;
}
else
goto the_default;
break;
}
case 'h':
if (!is_one_of_strings(&argv[i][2], plush_val_switches)) {
goto the_default;
} else {
if (i+1 >= argc
|| argv[i+1][0] == '-'
|| argv[i+1][0] == '+')
usage(argv[i]);
argv[i][0] = '-';
add_Eargs(argv[i]);
add_Eargs(argv[i+1]);
i++;
}
break;
case 'r':
if (!is_one_of_strings(&argv[i][2],
plusr_val_switches))
goto the_default;
else {
if (i+1 >= argc
|| argv[i+1][0] == '-'
|| argv[i+1][0] == '+')
usage(argv[i]);
argv[i][0] = '-';
add_Eargs(argv[i]);
add_Eargs(argv[i+1]);
i++;
}
break;
case 's':
if (!is_one_of_strings(&argv[i][2],
pluss_val_switches))
goto the_default;
else {
if (i+1 >= argc
|| argv[i+1][0] == '-'
|| argv[i+1][0] == '+')
usage(argv[i]);
argv[i][0] = '-';
add_Eargs(argv[i]);
add_Eargs(argv[i+1]);
i++;
}
break;
case 'p':
if (argv[i][2] != 'c' || argv[i][3] != '\0')
goto the_default;
if (i+1 >= argc)
usage(argv[i]);
argv[i][0] = '-';
add_Eargs(argv[i]);
add_Eargs(argv[i+1]);
i++;
break;
case 'z':
if (!is_one_of_strings(&argv[i][2], plusz_val_switches)) {
goto the_default;
} else {
if (i+1 >= argc
|| argv[i+1][0] == '-'
|| argv[i+1][0] == '+')
usage(argv[i]);
argv[i][0] = '-';
add_Eargs(argv[i]);
add_Eargs(argv[i+1]);
i++;
}
break;
default:
the_default:
argv[i][0] = '-'; /* Change +option to -option. */
add_Eargs(argv[i]);
}
break;
default:
add_arg(argv[i]);
} /* switch(argv[i][0] */
i++;
}
}
if (process_args) {
ADD_BOOT_CONFIG;
}
#undef ADD_BOOT_CONFIG
/* Doesn't conflict with -extra, since -make skips all the rest of
the arguments. */
if (haltAfterwards) {
add_args("-s", "erlang", "halt", NULL);
}
if (isdistributed && !no_epmd)
start_epmd(epmd_prog);
#if (! defined(__WIN32__)) && defined(DEBUG)
if (start_detached && get_env("ERL_CONSOLE_MODE")) {
/* Start the emulator within an xterm.
* Move up all arguments and insert
* "xterm -e " first.
* The path must be searched for this
* to work, i.e execvp() must be used.
*/
ensure_EargsSz(EargsCnt+2);
for (i = EargsCnt; i > 0; i--)
Eargsp[i+1] = Eargsp[i-1]; /* Two args to insert */
EargsCnt += 2; /* Two args to insert */
Eargsp[0] = emu = "xterm";
Eargsp[1] = "-e";
}
#endif
add_Eargs("--");
add_Eargs("-root");
add_Eargs(rootdir);
add_Eargs("-progname");
add_Eargs(progname);
add_Eargs("--");
ensure_EargsSz(EargsCnt + argsCnt + 1);
for (i = 0; i < argsCnt; i++)
Eargsp[EargsCnt++] = argsp[i];
Eargsp[EargsCnt] = NULL;
if (print_qouted_cmd_exit) {
printf("\"%s\" ", emu);
for (i = 1; i < EargsCnt; i++)
printf("\"%s\" ", Eargsp[i]);
printf("\n");
exit(0);
}
if (print_args_exit) {
for (i = 1; i < EargsCnt; i++)
printf("%s\n", Eargsp[i]);
exit(0);
}
if (verbose) {
printf("Executing: %s", emu);
for (i = 0; i < EargsCnt; i++)
printf(" %s", Eargsp[i]);
printf("\n\n");
}
#ifdef __WIN32__
if (EargsSz != EargsCnt + 1)
Eargsp = (char **) erealloc((void *) Eargsp, (EargsCnt + 1) *
sizeof(char *));
efree((void *) argsp);
skip_arg_massage:
/*DebugBreak();*/
if (run_werl) {
if (start_detached) {
char *p;
/* transform werl to erl */
p = start_emulator_program+strlen(start_emulator_program);
while (--p >= start_emulator_program && *p != '/' && *p != '\\' &&
*p != 'W' && *p != 'w')
;
if (p >= start_emulator_program && (*p == 'W' || *p == 'w') &&
(p[1] == 'E' || p[1] == 'e') && (p[2] == 'R' || p[2] == 'r') &&
(p[3] == 'L' || p[3] == 'l')) {
memmove(p,p+1,strlen(p));
}
}
return start_win_emulator(emu, start_emulator_program, Eargsp, start_detached);
} else {
return start_emulator(emu, start_emulator_program, Eargsp, start_detached);
}
#else
skip_arg_massage:
if (start_detached) {
int status = fork();
if (status != 0) /* Parent */
return 0;
if (reset_cerl_detached)
putenv("CERL_DETACHED_PROG=");
/* Detach from controlling terminal */
#ifdef HAVE_SETSID
setsid();
#elif defined(TIOCNOTTY)
{
int fd = open("/dev/tty", O_RDWR);
if (fd >= 0) {
ioctl(fd, TIOCNOTTY, NULL);
close(fd);
}
}
#endif
status = fork();
if (status != 0) /* Parent */
return 0;
/*
* Grandchild.
*/
close(0);
open("/dev/null", O_RDONLY);
close(1);
open("/dev/null", O_WRONLY);
close(2);
open("/dev/null", O_WRONLY);
#ifdef DEBUG
execvp(emu, Eargsp); /* "xterm ..." needs to search the path */
#endif
}
#ifdef DEBUG
else
#endif
{
execv(emu, Eargsp);
}
if (errno == ENOENT) {
if (strcmp(emu_flavor,DEFAULT_SUFFIX) || emu_type) {
/* The executable did not exist and a flavor/type flags was given.
* We collect the possible combinations and print that in the error
* in order to help the user.
*/
char buff[255], *currbuff = buff;
DIR *dp = opendir(bindir);
if (dp) {
struct dirent *ep;
while ((ep = readdir(dp)) != NULL) {
if (strncmp("beam",ep->d_name,4) == 0) {
char *type = strstr(ep->d_name,".") + 1;
char *flavor = strstr(type,".");
currbuff += sprintf(currbuff,"\n ");
if (flavor == NULL) {
flavor = type;
} else {
currbuff += sprintf(currbuff,"-emu_type %s ", strndup(type,flavor - type));
flavor++;
}
currbuff += sprintf(currbuff,"-emu_flavor %s", flavor);
}
}
closedir(dp);
}
error("Invalid emulator type or flavor. Available combinations are: %s\n",buff);
} else {
error("The emulator \'%s\' does not exist.");
}
} else {
error("Error %d executing \'%s\'.", errno, emu);
}
return 1;
#endif
}