int main()

in lib/erl_interface/src/prog/erl_call.c [133:668]


int main(int argc, char *argv[])
{
    int i = 1,fd,creation;
    struct hostent *hp;
    char host_name[EI_MAXHOSTNAMELEN+1];
    char nodename[MAXNODELEN+1];
    char *p = NULL;
    int modsize = 0;
    char *host = NULL;
    char *module = NULL;
    char *modname = NULL;
    struct call_flags flags = {0}; /* Default 0 and NULL in all fields */
    char* progname = argv[0];
    ei_cnode ec;
    flags.port = -1;
    flags.hostname = NULL;

    ei_init();

    /* Get the command line options */
    while (i < argc) {
	if (argv[i][0] != '-') {
	    usage_error(progname, argv[i]);
	}

	if (strcmp(argv[i], "-sname") == 0) { /* -sname NAME */
	    if (i+1 >= argc) {
		usage_arg(progname, "-sname ");
	    }

	    flags.node = ei_chk_strdup(argv[i+1]);
	    i++;
	    flags.use_long_name = 0;
	} else if (strcmp(argv[i], "-name") == 0) {  /* -name NAME */
	    if (i+1 >= argc) {
		usage_arg(progname, "-name ");
	    }

	    flags.node = ei_chk_strdup(argv[i+1]);
	    i++;
	    flags.use_long_name = 1;
	} else if (strcmp(argv[i], "-address") == 0) {  /* -address [HOST:]PORT */
	    if (i+1 >= argc) {
		usage_arg(progname, "-address ");
	    }
            {
                char* hostname_port_arg = ei_chk_strdup(argv[i+1]);
                char* address_string_end = strchr(hostname_port_arg, ':');
                if (address_string_end == NULL) {
                    flags.port = strtol(hostname_port_arg, NULL, 10);
                } else {
                    flags.port = strtol(address_string_end + 1, NULL, 10);
                    /* Remove port part from hostname_port_arg*/
                    *address_string_end = '\0';
                    if (strlen(hostname_port_arg) > 0) {
                        flags.hostname = hostname_port_arg;
                    }
                }

                if (flags.port < 1 || flags.port > 65535) {
                    usage_error(progname, "-address");
                }
                i++;
            }
        } else if (strcmp(argv[i], "-timeout") == 0) {
            long timeout;

            if (i+1 >= argc) {
                usage_arg(progname, "-timeout ");
            }

            timeout = strtol(argv[i+1], NULL, 10);
            if (timeout <= 0 || timeout >= (1 << 20)) {
                usage_error(progname, "-timeout");
            }

            start_timeout(timeout);
            i++;
        } else if (strcmp(argv[i], "-__uh_test__") == 0) {
            /* Fakes a failure in the call to ei_gethostbyname(h_hostname) so
             * we can test the localhost fallback. */
            flags.use_localhost_fallback = 1;
	} else {
	    if (strlen(argv[i]) != 2) {
		usage_error(progname, argv[i]);
	    }
		    
	    switch (argv[i][1]) {
	    case 's':
		flags.startp = 1;
		break;
	    case 'q':
		flags.haltp = 1;
		break;
	    case 'v':
		flags.verbosep = 1;
		break;
	    case 'd':
		flags.debugp = 1;
		break;
	    case 'r':
		flags.randomp = 1;
		break;
            case 'R':
                flags.dynamic_name = 1;
                break;
	    case 'e':
		flags.evalp = 1;
		break;
	    case 'm':
		flags.modp = 1;
		break;
	    case 'c':
		if (i+1 >= argc) {
		    usage_arg(progname, "-c ");
		}
		flags.cookiep = 1;
		flags.cookie = ei_chk_strdup(argv[i+1]);
		i++;
		break;
	    case 'n':
		if (i+1 >= argc) {
		    usage_arg(progname, "-n ");
		}
		flags.node = ei_chk_strdup(argv[i+1]);
		flags.use_long_name = 1;
		i++;
		break;
	    case 'h':
		if (i+1 >= argc) {
		    usage_arg(progname, "-h ");
		}
		flags.hidden = ei_chk_strdup(argv[i+1]);
		i++;
		break;
	    case 'x':
		if (i+1 >= argc) {
		    usage_arg(progname, "-x ");
		}
		flags.script = ei_chk_strdup(argv[i+1]);
		i++;
		break;
	    case 'a':
		if (i+1 >= argc) {
		    usage_arg(progname, "-a ");
		}
		flags.apply = ei_chk_strdup(argv[i+1]);
		i++;
		break;
	    case '?':
		usage(progname);
	    default:
		usage_error(progname, argv[i]);
	    }
	}
	i++;

    } /* while */

    /*
     * Can't have them both !
     */
    if ((flags.modp && flags.evalp) ||
        (flags.port != -1 && flags.startp) ||
        (flags.port != -1 && flags.node)) {
      usage(progname);
    }

    /*
     * Read an Erlang module from stdin.
     */
    if (flags.modp) {
      modsize = get_module(&module, &modname);
    }

    if (flags.verbosep || flags.debugp) {
	fprintf(stderr,"erl_call: "
		"node = %s\nCookie = %s\n"
		"flags = %s %s %s\n"
		"module: name = %s , size = %d\n"
		"apply = %s\n",
		(flags.node ? flags.node : ""),
		(flags.cookie ? flags.cookie : ""),
		(flags.startp ? "startp" : ""),
		(flags.verbosep ? "verbosep" : ""),
		(flags.debugp ? "debugp" : ""),
		(modname ? modname : ""), modsize,
		(flags.apply ? flags.apply : "" ));
    }

    /* 
     * What we, at least, requires !
     */
    if (flags.node == NULL && flags.port == -1) {
	usage(progname);
    }

    if (!flags.cookiep) {
	flags.cookie = NULL;
    }

    creation = time(NULL) + 1; /* "random" */

    if (flags.hidden == NULL && !flags.dynamic_name) {
      /* As default we are c17@gethostname */
      i = flags.randomp ? (time(NULL) % 997) : 17;
      flags.hidden = (char *) ei_chk_malloc(10 + 2 ); /* c17 or cXYZ */
      sprintf(flags.hidden, "c%d",
	  i < 0 ?  (int) getpid() : i);
    }
    {
      /* A name for our hidden node was specified */
      char h_hostname[EI_MAXHOSTNAMELEN+1];
      char h_nodename_buf[MAXNODELEN+1];
      char *h_nodename = h_nodename_buf;
      char *h_alivename = flags.hidden;
      struct in_addr h_ipadr;

      /* gethostname requires len to be max(hostname) + 1 */
      if (gethostname(h_hostname, EI_MAXHOSTNAMELEN+1) < 0) {
          fprintf(stderr,"erl_call: failed to get host name: %d\n", errno);
          exit(1);
      }

      if (flags.use_localhost_fallback || (hp = ei_gethostbyname(h_hostname)) == 0) {
          /* Failed to resolve our own hostname; try binding to loopback and
           * hope for the best. */
          hp = ei_gethostbyname("localhost");
          flags.use_localhost_fallback = 1;

          format_node_hostname(&flags, h_hostname, h_hostname);
      } else {
          format_node_hostname(&flags, hp->h_name, h_hostname);
      }

      memcpy(&h_ipadr.s_addr, *hp->h_addr_list, sizeof(struct in_addr));
      if (h_alivename) {
          if (strlen(h_alivename) + strlen(h_hostname) + 2 > sizeof(h_nodename_buf)) {
              fprintf(stderr,"erl_call: hostname too long: %s\n", h_hostname);
              exit(1);
          }
          sprintf(h_nodename, "%s@%s", h_alivename, h_hostname);
      }
      else {
          /* dynamic node name */
          h_nodename = NULL;
      }
      
      if (ei_connect_xinit(&ec, h_hostname, h_alivename, h_nodename,
			   (Erl_IpAddr)&h_ipadr, flags.cookie, 
			   (short) creation) < 0) {
	  fprintf(stderr,"erl_call: can't create C node %s; %d\n",
		  h_nodename, erl_errno);
      	  exit(1);
      }

    }
    if (flags.port != -1 && flags.hostname != NULL) {
        host = flags.hostname;
        strcpy(host_name, flags.hostname);
    } else if ((flags.port != -1 && flags.hostname == NULL) ||
        (strchr((const char *)flags.node, (int) '@') == 0)) {
	strcpy(host_name, ei_thishostname(&ec));
	host = host_name;
    } else {
        p = strchr((const char *)flags.node, (int) '@');
	*p = 0;
	host = p+1;
    }

    if (flags.use_localhost_fallback && strcmp(host, ei_thishostname(&ec)) == 0) {
        /* We're on the same host *and* have used the localhost fallback, so we
         * skip canonical name resolution since it's bound to fail.
         *
         * `ei_connect` will do the right thing later on. */
        strcpy(host_name, ei_thishostname(&ec));
    } else {
        if ((hp = ei_gethostbyname(host)) == 0) {
            fprintf(stderr,"erl_call: can't ei_gethostbyname(%s)\n", host);
            exit(1);
        }

        format_node_hostname(&flags, hp->h_name, host_name);
    }

    if (flags.port == -1) {
        if (strlen(flags.node) + strlen(host_name) + 2 > sizeof(nodename)) {
            fprintf(stderr,"erl_call: nodename too long: %s\n", flags.node);
            exit(1);
        }
        sprintf(nodename, "%s@%s", flags.node, host_name);
    }
    /* 
     * Try to connect. Start an Erlang system if the
     * start option is on and no system is running.
     */
    if (flags.startp && !flags.haltp) {
	fd = do_connect(&ec, nodename, &flags);
    } else if (flags.port == -1) {
        if ((fd = ei_connect(&ec, nodename)) < 0) {
            /* We failed to connect ourself */
            /* FIXME do we really know we failed because of node not up? */
            if (flags.haltp) {
                exit(0);
            } else {
                fprintf(stderr,"erl_call: failed to connect to node %s\n",
                        nodename);
                exit(1);
            }
        }
    } else {
        /* Connect using address:port */
        if ((fd = ei_connect_host_port(&ec, host, (int)flags.port)) < 0) {
            /* We failed to connect ourself */
            /* FIXME do we really know we failed because of node not up? */
            if (flags.haltp) {
                exit(0);
            } else {
                fprintf(stderr,"erl_call: failed to connect to node with address \"%s:%ld\"\n",
                        flags.hostname == NULL ? "" : flags.hostname,
                        flags.port);
                exit(1);
            }
        }
    }

    /* If we are connected and the halt switch is set */
    if (fd && flags.haltp) {
	int i = 0;
	char *p;
	ei_x_buff reply;

	ei_encode_empty_list(NULL, &i);

	p = (char *)ei_chk_malloc(i);
	i = 0;		/* Reset */
	  
	ei_encode_empty_list(p, &i);

	ei_x_new_with_version(&reply);

	/* FIXME if fails we want to exit != 0 ? */
	ei_rpc(&ec, fd, "erlang", "halt", p, i, &reply);
	free(p);
	ei_x_free(&reply);
	exit(0);
    }

    if (flags.verbosep) {
        if (flags.port == -1) {
            fprintf(stderr,"erl_call: we are now connected to node \"%s\"\n",
                    nodename);
        } else {
            fprintf(stderr,"erl_call: we are now connected to node with address \"%s:%ld\"\n",
                    flags.hostname == NULL ? "": flags.hostname,
                    flags.port);
        }
    }

    /*
     * Compile the module read from stdin.
     */
    if (flags.modp && (modname != NULL)) {
      char fname[256];

      if (strlen(modname) + 4 + 1 > sizeof(fname)) {
      fprintf(stderr,"erl_call: module name too long: %s\n", modname);
      exit(1);
      }
      strcpy(fname, modname);
      strcat(fname, ".erl");

      /*
       * ei_format("[~s,~w]", fname, erl_mk_binary(module, modsize));
       */

      {
	  int i = 0;
	  char *p;
	  ei_x_buff reply;

	  ei_encode_list_header(NULL, &i, 2);
	  ei_encode_string(NULL, &i, fname);
	  ei_encode_binary(NULL, &i, module, modsize);
	  ei_encode_empty_list(NULL, &i);

	  p = (char *)ei_chk_malloc(i);
	  i = 0;		/* Reset */
	  
	  ei_encode_list_header(p, &i, 2);
	  ei_encode_string(p, &i, fname);
	  ei_encode_binary(p, &i, module, modsize);
	  ei_encode_empty_list(p, &i);

	  ei_x_new_with_version(&reply);

	  if (ei_rpc(&ec, fd, "file", "write_file", p, i, &reply) < 0) {
	      free(p);
	      ei_x_free(&reply);
	      fprintf(stderr,"erl_call: can't write to source file %s\n",
		      fname);
	      exit(1);
	  }
	  free(p);
	  ei_x_free(&reply);
      }
     
      /* Compile AND load file on other node */

      {
	  int i = 0;
	  char *p;
	  ei_x_buff reply;

	  ei_encode_list_header(NULL, &i, 2);
	  ei_encode_atom(NULL, &i, fname);
	  ei_encode_empty_list(NULL, &i);
	  ei_encode_empty_list(NULL, &i);

	  p = (char *)ei_chk_malloc(i);
	  i = 0;		/* Reset */
	  
	  ei_encode_list_header(p, &i, 2);
	  ei_encode_atom(p, &i, fname);
	  ei_encode_empty_list(p, &i);
	  ei_encode_empty_list(p, &i);

	  ei_x_new_with_version(&reply);

	  /* erl_format("[~a,[]]", modname) */

	  if (ei_rpc(&ec, fd, "c", "c", p, i, &reply) < 0) {
	      free(p);
	      ei_x_free(&reply);
	      fprintf(stderr,"erl_call: can't compile file %s\n", fname);
	  }
	  free(p);
	  /* FIXME complete this code
	     FIXME print out error message as term
	  if (!erl_match(erl_format("{ok,_}"), reply)) {
	      fprintf(stderr,"erl_call: compiler errors\n");
	  }
	  */
	  ei_x_free(&reply);
      }
     
    }

    /*
     * If we loaded any module source code, we can free the buffer
     * now. This buffer was allocated in read_stdin().
     */
    if (module != NULL) {
        free(module);
    }

    /*
     * Eval the Erlang functions read from stdin/
     */
    if (flags.evalp) {
      char *evalbuf;
      int len;

      len = read_stdin(&evalbuf);
      {
	  int i = 0;
	  char *p;
	  ei_x_buff reply;

	  ei_encode_list_header(NULL, &i, 1);
	  ei_encode_binary(NULL, &i, evalbuf, len);
	  ei_encode_empty_list(NULL, &i);

	  p = (char *)ei_chk_malloc(i);
	  i = 0;		/* Reset */
	  
	  ei_encode_list_header(p, &i, 1);
	  ei_encode_binary(p, &i, evalbuf, len);
	  ei_encode_empty_list(p, &i);

	  ei_x_new_with_version(&reply);

	  /* erl_format("[~w]", erl_mk_binary(evalbuf,len))) */

	  if (ei_rpc(&ec, fd, "erl_eval", "eval_str", p, i, &reply) < 0) {
	      fprintf(stderr,"erl_call: evaluating input failed: %s\n",
		      evalbuf);
	      free(p);
	      free(evalbuf);	/* Allocated in read_stdin() */
	      ei_x_free(&reply);
	      exit(1);
	  }
	  i = 0;
	  ei_print_term(stdout,reply.buff,&i);
	  free(p);
	  free(evalbuf);	/* Allocated in read_stdin() */
	  ei_x_free(&reply);
      }
    }
    /*
     * Any Erlang call to be made ?
     */
    if (flags.apply != NULL) {
      char *mod,*fun,*args;
      ei_x_buff e, reply;

      split_apply_string(flags.apply, &mod, &fun, &args);
      if (flags.verbosep) {
	  fprintf(stderr,"erl_call: module = %s, function = %s, args = %s\n",
		  mod, fun, args);
      }

      ei_x_new(&e);		/* No version to ei_rpc() */
      
      if (ei_x_format_wo_ver(&e, args) < 0) {
	  /* FIXME no error message and why -1 ? */
	  exit(-1);
      }

      ei_x_new_with_version(&reply);

      if (ei_rpc(&ec, fd, mod, fun, e.buff, e.index, &reply) < 0) {
	  /* FIXME no error message and why -1 ? */
	  ei_x_free(&e);
	  ei_x_free(&reply);
	  exit(-1);
      } else {
	  int i = 0;
	  ei_print_term(stdout,reply.buff,&i);
	  ei_x_free(&e);
	  ei_x_free(&reply);
      }
    }

    return(0);
}