int main()

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
}