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);
}