1 /*
2  * %CopyrightBegin%
3  *
4  * Copyright Ericsson AB 1996-2020. All Rights Reserved.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *
18  * %CopyrightEnd%
19  *
20 
21  */
22 /*
23  * Description: This file implements the erl_call command line
24  * utility. The erl_call command can be used to:
25  *
26  * * Execute code on an Erlang node and get the result back
27  * * Start and stop Erlang nodes
28  * * Upload and compile a module on an Erlang node
29  *
30  * See the erl_call man page or HTML documentation for additional
31  * information.
32  *
33  */
34 
35 /* An exception from using eidef.h, use config.h directly */
36 #include "config.h"
37 
38 #ifdef __WIN32__
39 #include <winsock2.h>
40 #include <direct.h>
41 #include <windows.h>
42 #include <winbase.h>
43 
44 #else /* unix */
45 
46 #include <arpa/inet.h>
47 #include <errno.h>
48 #include <netdb.h>
49 #include <netinet/in.h>
50 #include <signal.h>
51 #include <stdio.h>
52 #include <string.h>
53 #include <sys/param.h>
54 #include <sys/socket.h>
55 #include <sys/stat.h>
56 #include <sys/time.h>
57 #include <sys/times.h>
58 #include <sys/types.h>
59 #include <sys/uio.h>
60 #include <sys/wait.h>
61 #include <time.h>
62 #include <unistd.h>
63 
64 #if TIME_WITH_SYS_TIME
65 # include <sys/time.h>
66 # include <time.h>
67 #else
68 # if HAVE_SYS_TIME_H
69 #  include <sys/time.h>
70 # else
71 #  include <time.h>
72 # endif
73 #endif
74 
75 #endif
76 
77 #include <sys/types.h>
78 
79 #include <stdio.h>
80 #include <stdlib.h>
81 
82 #include <string.h>
83 #include <ctype.h>
84 #include <fcntl.h>
85 #include <signal.h>
86 
87 #include "ei.h"
88 #include "ei_resolve.h"
89 
90 #define ERL_START_MSG "gurka" /* make something up */
91 #define ERL_START_TIME 10000   /* wait this long (ms) */
92 #define ERL_START_LOGFILE ".erl_start.out" /* basename of logfile */
93 
94 /* flags used by erl_connect and erl_xconnect */
95 #define ERL_START_ENODE   0x0001
96 #define ERL_START_EPMD    0x0002
97 #define ERL_START_LONG    0x0004
98 #define ERL_START_COOKIE  0x0008
99 #define ERL_START_DEBUG   0x0010
100 #define ERL_START_VERBOSE 0x0020
101 #define ERL_START_REMOTE  0x0040
102 
103 /* error return values */
104 #define ERL_S_TIMEOUT    -51  /* a timeout occurred */
105 #define ERL_BADARG     -52  /* an argument contained an incorrect value */
106 #define ERL_SYS_ERROR  -99  /* a system error occurred (check errno) */
107 
108 struct call_flags {
109     int startp;
110     int cookiep;
111     int modp;
112     int evalp;
113     int randomp;
114     int dynamic_name;
115     int use_long_name;	/* indicates if -name was used, else -sname or -n */
116     int use_localhost_fallback;
117     int debugp;
118     int verbosep;
119     int haltp;
120     int fetch_stdout;
121     int print_result_term;
122     long port;
123     char *hostname;
124     char *cookie;
125     char *node;
126     char *hidden;
127     char *apply;
128     char *script;
129 };
130 
131 /* start an erlang system */
132 int erl_start_sys(ei_cnode *ec, char *alive, Erl_IpAddr addr, int flags,
133 		  char *erl, char *add_args[]);
134 static void usage_arg(const char *progname, const char *switchname);
135 static void usage_error(const char *progname, const char *switchname);
136 static void usage(const char *progname);
137 static int get_module(char **mbuf, char **mname);
138 static int do_connect(ei_cnode *ec, char *nodename, struct call_flags *flags);
139 static int read_stdin(char **buf);
140 static void split_apply_string(char *str, char **mod,
141 			       char **fun, char **args);
142 static void* ei_chk_malloc(size_t size);
143 static void* ei_chk_calloc(size_t nmemb, size_t size);
144 static void* ei_chk_realloc(void *old, size_t size);
145 static char* ei_chk_strdup(char *s);
146 static int rpc_print_node_stdout(ei_cnode* ec, int fd, char *mod,
147                                  char *fun, const char* inbuf,
148                                  int inbuflen, ei_x_buff* x);
149 static void exit_free_flags_fields(int exit_status, struct call_flags* flags);
150 
151 /* Converts the given hostname to a shortname, if required. */
format_node_hostname(const struct call_flags * flags,const char * hostname,char dst[EI_MAXHOSTNAMELEN+1])152 static void format_node_hostname(const struct call_flags *flags,
153                                  const char *hostname,
154                                  char dst[EI_MAXHOSTNAMELEN + 1])
155 {
156     char *ct;
157 
158     strncpy(dst, hostname, EI_MAXHOSTNAMELEN);
159     dst[EI_MAXHOSTNAMELEN] = '\0';
160 
161     /* If shortnames, cut off the name at first '.' */
162     if (flags->use_long_name == 0 && (ct = strchr(dst, '.'))) {
163         *ct = '\0';
164     }
165 }
166 
167 static void start_timeout(int timeout);
168 
169 /***************************************************************************
170  *
171  *  XXXXX
172  *
173  ***************************************************************************/
174 
main(int argc,char * argv[])175 int main(int argc, char *argv[])
176 {
177     int i = 1,fd,creation;
178     struct hostent *hp;
179     char host_name[EI_MAXHOSTNAMELEN+1];
180     char nodename[MAXNODELEN+1];
181     char *p = NULL;
182     int modsize = 0;
183     char *host = NULL;
184     char *module = NULL;
185     char *modname = NULL;
186     struct call_flags flags = {0}; /* Default 0 and NULL in all fields */
187     char* progname = argv[0];
188     ei_cnode ec;
189     flags.port = -1;
190     flags.hostname = NULL;
191     flags.fetch_stdout = 0;
192     flags.print_result_term = 1;
193     flags.script = NULL;
194     flags.hidden = NULL;
195     flags.apply = NULL;
196     flags.cookie = NULL;
197     flags.node = NULL;
198 
199     ei_init();
200 
201     /* Get the command line options */
202     while (i < argc) {
203 	if (argv[i][0] != '-') {
204 	    usage_error(progname, argv[i]);
205 	}
206 
207 	if (strcmp(argv[i], "-sname") == 0) { /* -sname NAME */
208 	    if (i+1 >= argc) {
209 		usage_arg(progname, "-sname ");
210 	    }
211             if (flags.node != NULL) {
212                 free(flags.node);
213             }
214 	    flags.node = ei_chk_strdup(argv[i+1]);
215 	    i++;
216 	    flags.use_long_name = 0;
217 	} else if (strcmp(argv[i], "-name") == 0) {  /* -name NAME */
218 	    if (i+1 >= argc) {
219 		usage_arg(progname, "-name ");
220 	    }
221             if (flags.node != NULL) {
222                 free(flags.node);
223             }
224 	    flags.node = ei_chk_strdup(argv[i+1]);
225 	    i++;
226 	    flags.use_long_name = 1;
227 	} else if (strcmp(argv[i], "-address") == 0) {  /* -address [HOST:]PORT */
228 	    if (i+1 >= argc) {
229 		usage_arg(progname, "-address ");
230 	    }
231             {
232                 char* hostname_port_arg = ei_chk_strdup(argv[i+1]);
233                 char* address_string_end = strchr(hostname_port_arg, ':');
234                 if (address_string_end == NULL) {
235                     flags.port = strtol(hostname_port_arg, NULL, 10);
236                     free(hostname_port_arg);
237                     hostname_port_arg = NULL;
238                 } else {
239                     flags.port = strtol(address_string_end + 1, NULL, 10);
240                     /* Remove port part from hostname_port_arg*/
241                     *address_string_end = '\0';
242                     if (strlen(hostname_port_arg) > 0) {
243                         flags.hostname = hostname_port_arg;
244                     } else {
245                         free(hostname_port_arg);
246                         hostname_port_arg = NULL;
247                     }
248                 }
249 
250                 if (flags.port < 1 || flags.port > 65535) {
251                     if (hostname_port_arg != NULL) {
252                         free(hostname_port_arg);
253                     }
254                     usage_error(progname, "-address");
255                 }
256                 i++;
257             }
258         } else if (strcmp(argv[i], "-timeout") == 0) {
259             long timeout;
260 
261             if (i+1 >= argc) {
262                 usage_arg(progname, "-timeout ");
263             }
264 
265             timeout = strtol(argv[i+1], NULL, 10);
266             if (timeout <= 0 || timeout >= (1 << 20)) {
267                 usage_error(progname, "-timeout");
268             }
269 
270             start_timeout(timeout);
271             i++;
272         } else if (strcmp(argv[i], "-fetch_stdout") == 0) {
273             flags.fetch_stdout = 1;
274         } else if (strcmp(argv[i], "-no_result_term") == 0) {
275             flags.print_result_term = 0;
276         } else if (strcmp(argv[i], "-__uh_test__") == 0) {
277             /* Fakes a failure in the call to ei_gethostbyname(h_hostname) so
278              * we can test the localhost fallback. */
279             flags.use_localhost_fallback = 1;
280 	} else {
281 	    if (strlen(argv[i]) != 2) {
282 		usage_error(progname, argv[i]);
283 	    }
284 
285 	    switch (argv[i][1]) {
286 	    case 's':
287 		flags.startp = 1;
288 		break;
289 	    case 'q':
290 		flags.haltp = 1;
291 		break;
292 	    case 'v':
293 		flags.verbosep = 1;
294 		break;
295 	    case 'd':
296 		flags.debugp = 1;
297 		break;
298 	    case 'r':
299 		flags.randomp = 1;
300 		break;
301             case 'R':
302                 flags.dynamic_name = 1;
303                 break;
304 	    case 'e':
305 		flags.evalp = 1;
306 		break;
307 	    case 'm':
308 		flags.modp = 1;
309 		break;
310 	    case 'c':
311 		if (i+1 >= argc) {
312 		    usage_arg(progname, "-c ");
313 		}
314 		flags.cookiep = 1;
315                 if (flags.cookie != NULL) {
316                     free(flags.cookie);
317                 }
318 		flags.cookie = ei_chk_strdup(argv[i+1]);
319 		i++;
320 		break;
321 	    case 'n':
322 		if (i+1 >= argc) {
323 		    usage_arg(progname, "-n ");
324 		}
325                 if (flags.node != NULL) {
326                     free(flags.node);
327                 }
328 		flags.node = ei_chk_strdup(argv[i+1]);
329 		flags.use_long_name = 1;
330 		i++;
331 		break;
332 	    case 'h':
333 		if (i+1 >= argc) {
334 		    usage_arg(progname, "-h ");
335 		}
336                 if (flags.hidden != NULL) {
337                     free(flags.hidden);
338                 }
339 		flags.hidden = ei_chk_strdup(argv[i+1]);
340 		i++;
341 		break;
342 	    case 'x':
343 		if (i+1 >= argc) {
344 		    usage_arg(progname, "-x ");
345 		}
346                 if (flags.script != NULL) {
347                     free(flags.script);
348                 }
349 		flags.script = ei_chk_strdup(argv[i+1]);
350 		i++;
351 		break;
352 	    case 'a':
353 		if (i+1 >= argc) {
354 		    usage_arg(progname, "-a ");
355 		}
356                 if (flags.apply != NULL) {
357                     free(flags.apply);
358                 }
359 		flags.apply = ei_chk_strdup(argv[i+1]);
360 		i++;
361 		break;
362 	    case '?':
363 		usage(progname);
364 	    default:
365 		usage_error(progname, argv[i]);
366 	    }
367 	}
368 	i++;
369 
370     } /* while */
371 
372     /*
373      * Can't have them both !
374      */
375     if ((flags.modp && flags.evalp) ||
376         (flags.port != -1 && flags.startp) ||
377         (flags.port != -1 && flags.node)) {
378       usage(progname);
379     }
380 
381     /*
382      * Read an Erlang module from stdin.
383      */
384     if (flags.modp) {
385       modsize = get_module(&module, &modname);
386     }
387 
388     if (flags.verbosep || flags.debugp) {
389 	fprintf(stderr,"erl_call: "
390 		"node = %s\nCookie = %s\n"
391 		"flags = %s %s %s\n"
392 		"module: name = %s , size = %d\n"
393 		"apply = %s\n",
394 		(flags.node ? flags.node : ""),
395 		(flags.cookie ? flags.cookie : ""),
396 		(flags.startp ? "startp" : ""),
397 		(flags.verbosep ? "verbosep" : ""),
398 		(flags.debugp ? "debugp" : ""),
399 		(modname ? modname : ""), modsize,
400 		(flags.apply ? flags.apply : "" ));
401     }
402 
403     /*
404      * What we, at least, requires !
405      */
406     if (flags.node == NULL && flags.port == -1) {
407 	usage(progname);
408     }
409 
410     if (!flags.cookiep) {
411 	flags.cookie = NULL;
412     }
413 
414     creation = time(NULL) + 1; /* "random" */
415 
416     if (flags.hidden == NULL && !flags.dynamic_name) {
417       /* As default we are c17@gethostname */
418       i = flags.randomp ? (time(NULL) % 997) : 17;
419       flags.hidden = (char *) ei_chk_malloc(10 + 2 ); /* c17 or cXYZ */
420       sprintf(flags.hidden, "c%d",
421 	  i < 0 ?  (int) getpid() : i);
422     }
423     {
424       /* A name for our hidden node was specified */
425       char h_hostname[EI_MAXHOSTNAMELEN+1];
426       char h_nodename_buf[MAXNODELEN+1];
427       char *h_nodename = h_nodename_buf;
428       char *h_alivename = flags.hidden;
429       struct in_addr h_ipadr;
430 
431       /* gethostname requires len to be max(hostname) + 1 */
432       if (gethostname(h_hostname, EI_MAXHOSTNAMELEN+1) < 0) {
433           fprintf(stderr,"erl_call: failed to get host name: %d\n", errno);
434           exit_free_flags_fields(1, &flags);
435       }
436 
437       if (flags.use_localhost_fallback || (hp = ei_gethostbyname(h_hostname)) == 0) {
438           /* Failed to resolve our own hostname; try binding to loopback and
439            * hope for the best. */
440           hp = ei_gethostbyname("localhost");
441           flags.use_localhost_fallback = 1;
442 
443           format_node_hostname(&flags, h_hostname, h_hostname);
444       } else {
445           format_node_hostname(&flags, hp->h_name, h_hostname);
446       }
447 
448       memcpy(&h_ipadr.s_addr, *hp->h_addr_list, sizeof(struct in_addr));
449       if (h_alivename) {
450           if (strlen(h_alivename) + strlen(h_hostname) + 2 > sizeof(h_nodename_buf)) {
451               fprintf(stderr,"erl_call: hostname too long: %s\n", h_hostname);
452               exit_free_flags_fields(1, &flags);
453           }
454           sprintf(h_nodename, "%s@%s", h_alivename, h_hostname);
455       }
456       else {
457           /* dynamic node name */
458           h_nodename = NULL;
459       }
460 
461       if (ei_connect_xinit(&ec, h_hostname, h_alivename, h_nodename,
462 			   (Erl_IpAddr)&h_ipadr, flags.cookie,
463 			   (short) creation) < 0) {
464 	  fprintf(stderr,"erl_call: can't create C node %s; %d\n",
465 		  h_nodename, erl_errno);
466           exit_free_flags_fields(1, &flags);
467       }
468 
469     }
470     if (flags.port != -1 && flags.hostname != NULL) {
471         host = flags.hostname;
472         strcpy(host_name, flags.hostname);
473     } else if ((flags.port != -1 && flags.hostname == NULL) ||
474         (strchr((const char *)flags.node, (int) '@') == 0)) {
475 	strcpy(host_name, ei_thishostname(&ec));
476 	host = host_name;
477     } else {
478         p = strchr((const char *)flags.node, (int) '@');
479 	*p = 0;
480 	host = p+1;
481     }
482 
483     if (flags.use_localhost_fallback && strcmp(host, ei_thishostname(&ec)) == 0) {
484         /* We're on the same host *and* have used the localhost fallback, so we
485          * skip canonical name resolution since it's bound to fail.
486          *
487          * `ei_connect` will do the right thing later on. */
488         strcpy(host_name, ei_thishostname(&ec));
489     } else {
490         if ((hp = ei_gethostbyname(host)) == 0) {
491             fprintf(stderr,"erl_call: can't ei_gethostbyname(%s)\n", host);
492             exit_free_flags_fields(1, &flags);
493         }
494 
495         format_node_hostname(&flags, hp->h_name, host_name);
496     }
497 
498     if (flags.port == -1) {
499         if (strlen(flags.node) + strlen(host_name) + 2 > sizeof(nodename)) {
500             fprintf(stderr,"erl_call: nodename too long: %s\n", flags.node);
501             exit_free_flags_fields(1, &flags);
502         }
503         sprintf(nodename, "%s@%s", flags.node, host_name);
504     }
505     /*
506      * Try to connect. Start an Erlang system if the
507      * start option is on and no system is running.
508      */
509     if (flags.startp && !flags.haltp) {
510 	fd = do_connect(&ec, nodename, &flags);
511     } else if (flags.port == -1) {
512         if ((fd = ei_connect(&ec, nodename)) < 0) {
513             /* We failed to connect ourself */
514             /* FIXME do we really know we failed because of node not up? */
515             if (flags.haltp) {
516                 exit_free_flags_fields(0, &flags);
517             } else {
518                 fprintf(stderr,"erl_call: failed to connect to node %s\n",
519                         nodename);
520                 exit_free_flags_fields(1, &flags);
521             }
522         }
523     } else {
524         /* Connect using address:port */
525         if ((fd = ei_connect_host_port(&ec, host, (int)flags.port)) < 0) {
526             /* We failed to connect ourself */
527             /* FIXME do we really know we failed because of node not up? */
528             if (flags.haltp) {
529                 exit_free_flags_fields(0, &flags);
530             } else {
531                 fprintf(stderr,"erl_call: failed to connect to node with address \"%s:%ld\"\n",
532                         flags.hostname == NULL ? "" : flags.hostname,
533                         flags.port);
534                 exit_free_flags_fields(1, &flags);
535             }
536         }
537     }
538 
539     /* If we are connected and the halt switch is set */
540     if (fd && flags.haltp) {
541 	int i = 0;
542 	char *p;
543 	ei_x_buff reply;
544 
545 	ei_encode_empty_list(NULL, &i);
546 
547 	p = (char *)ei_chk_malloc(i);
548 	i = 0;		/* Reset */
549 
550 	ei_encode_empty_list(p, &i);
551 
552 	ei_x_new_with_version(&reply);
553 
554 	/* FIXME if fails we want to exit != 0 ? */
555 	ei_rpc(&ec, fd, "erlang", "halt", p, i, &reply);
556 	free(p);
557 	ei_x_free(&reply);
558         exit_free_flags_fields(0, &flags);
559     }
560 
561     if (flags.verbosep) {
562         if (flags.port == -1) {
563             fprintf(stderr,"erl_call: we are now connected to node \"%s\"\n",
564                     nodename);
565         } else {
566             fprintf(stderr,"erl_call: we are now connected to node with address \"%s:%ld\"\n",
567                     flags.hostname == NULL ? "": flags.hostname,
568                     flags.port);
569         }
570     }
571 
572     /*
573      * Compile the module read from stdin.
574      */
575     if (flags.modp && (modname != NULL)) {
576       char fname[256];
577 
578       if (strlen(modname) + 4 + 1 > sizeof(fname)) {
579       fprintf(stderr,"erl_call: module name too long: %s\n", modname);
580       exit_free_flags_fields(1, &flags);
581       }
582       strcpy(fname, modname);
583       strcat(fname, ".erl");
584 
585       /*
586        * ei_format("[~s,~w]", fname, erl_mk_binary(module, modsize));
587        */
588 
589       {
590 	  int i = 0;
591 	  char *p;
592 	  ei_x_buff reply;
593 
594 	  ei_encode_list_header(NULL, &i, 2);
595 	  ei_encode_string(NULL, &i, fname);
596 	  ei_encode_binary(NULL, &i, module, modsize);
597 	  ei_encode_empty_list(NULL, &i);
598 
599 	  p = (char *)ei_chk_malloc(i);
600 	  i = 0;		/* Reset */
601 
602 	  ei_encode_list_header(p, &i, 2);
603 	  ei_encode_string(p, &i, fname);
604 	  ei_encode_binary(p, &i, module, modsize);
605 	  ei_encode_empty_list(p, &i);
606 
607 	  ei_x_new_with_version(&reply);
608 
609 	  if (ei_rpc(&ec, fd, "file", "write_file", p, i, &reply) < 0) {
610 	      free(p);
611 	      ei_x_free(&reply);
612 	      fprintf(stderr,"erl_call: can't write to source file %s\n",
613 		      fname);
614               exit_free_flags_fields(1, &flags);
615 	  }
616 	  free(p);
617 	  ei_x_free(&reply);
618       }
619 
620       /* Compile AND load file on other node */
621 
622       {
623 	  int i = 0;
624 	  char *p;
625 	  ei_x_buff reply;
626 
627 	  ei_encode_list_header(NULL, &i, 2);
628 	  ei_encode_atom(NULL, &i, fname);
629 	  ei_encode_empty_list(NULL, &i);
630 	  ei_encode_empty_list(NULL, &i);
631 
632 	  p = (char *)ei_chk_malloc(i);
633 	  i = 0;		/* Reset */
634 
635 	  ei_encode_list_header(p, &i, 2);
636 	  ei_encode_atom(p, &i, fname);
637 	  ei_encode_empty_list(p, &i);
638 	  ei_encode_empty_list(p, &i);
639 
640 	  ei_x_new_with_version(&reply);
641 
642 	  /* erl_format("[~a,[]]", modname) */
643 
644 	  if (ei_rpc(&ec, fd, "c", "c", p, i, &reply) < 0) {
645 	      free(p);
646 	      ei_x_free(&reply);
647 	      fprintf(stderr,"erl_call: can't compile file %s\n", fname);
648 	  }
649 	  free(p);
650 	  /* FIXME complete this code
651 	     FIXME print out error message as term
652 	  if (!erl_match(erl_format("{ok,_}"), reply)) {
653 	      fprintf(stderr,"erl_call: compiler errors\n");
654 	  }
655 	  */
656 	  ei_x_free(&reply);
657       }
658 
659     }
660 
661     /*
662      * If we loaded any module source code, we can free the buffer
663      * now. This buffer was allocated in read_stdin().
664      */
665     if (module != NULL) {
666         free(module);
667     }
668 
669     /*
670      * Eval the Erlang functions read from stdin/
671      */
672     if (flags.evalp) {
673       char *evalbuf;
674       int len;
675 
676       len = read_stdin(&evalbuf);
677       {
678 	  int i = 0;
679           int rpc_res;
680           char *p;
681 	  ei_x_buff reply;
682 
683 	  ei_encode_list_header(NULL, &i, 1);
684 	  ei_encode_binary(NULL, &i, evalbuf, len);
685 	  ei_encode_empty_list(NULL, &i);
686 
687 	  p = (char *)ei_chk_malloc(i);
688 	  i = 0;		/* Reset */
689 
690 	  ei_encode_list_header(p, &i, 1);
691 	  ei_encode_binary(p, &i, evalbuf, len);
692 	  ei_encode_empty_list(p, &i);
693 
694 	  ei_x_new_with_version(&reply);
695 	  /* erl_format("[~w]", erl_mk_binary(evalbuf,len))) */
696 
697           if (flags.fetch_stdout) {
698               rpc_res = rpc_print_node_stdout(&ec, fd, "erl_eval", "eval_str", p, i, &reply);
699           } else {
700               rpc_res = ei_rpc(&ec, fd, "erl_eval", "eval_str", p, i, &reply);
701           }
702 
703 	  if (rpc_res < 0) {
704 	      fprintf(stderr,"erl_call: evaluating input failed: %s\n",
705 		      evalbuf);
706 	      free(p);
707 	      free(evalbuf);	/* Allocated in read_stdin() */
708 	      ei_x_free(&reply);
709               exit_free_flags_fields(1, &flags);
710 	  }
711           if (flags.print_result_term) {
712               i = 0;
713               ei_print_term(stdout,reply.buff,&i);
714           }
715 	  free(p);
716 	  free(evalbuf);	/* Allocated in read_stdin() */
717 	  ei_x_free(&reply);
718       }
719     }
720     /*
721      * Any Erlang call to be made ?
722      */
723     if (flags.apply != NULL) {
724       char *mod,*fun,*args;
725       ei_x_buff e, reply;
726       int rpc_res;
727       split_apply_string(flags.apply, &mod, &fun, &args);
728       if (flags.verbosep) {
729 	  fprintf(stderr,"erl_call: module = %s, function = %s, args = %s\n",
730 		  mod, fun, args);
731       }
732 
733       ei_x_new(&e);		/* No version to ei_rpc() */
734 
735       if (ei_x_format_wo_ver(&e, args) < 0) {
736           fprintf(stderr, "erl_call: Failed to parse arguments,\n"
737                   "see the documentation for allowed term types.\n"
738                   "Arguments: %s\n", args);
739           free(mod);
740           free(fun);
741           free(args);
742           exit_free_flags_fields(-1, &flags);
743       }
744       free(args);
745       ei_x_new_with_version(&reply);
746 
747       if (flags.fetch_stdout) {
748           rpc_res = rpc_print_node_stdout(&ec, fd, mod, fun, e.buff, e.index, &reply);
749       } else {
750           rpc_res = ei_rpc(&ec, fd, mod, fun, e.buff, e.index, &reply);
751       }
752       if (rpc_res < 0) {
753 	  /* FIXME no error message and why -1 ? */
754 	  ei_x_free(&e);
755 	  ei_x_free(&reply);
756           free(mod);
757           free(fun);
758           exit_free_flags_fields(-1, &flags);
759       } else {
760           if (flags.print_result_term) {
761               int i = 0;
762               ei_print_term(stdout,reply.buff,&i);
763           }
764 	  ei_x_free(&e);
765 	  ei_x_free(&reply);
766       }
767       free(mod);
768       free(fun);
769     }
770     exit_free_flags_fields(0, &flags);
771     return(0);
772 }
773 
774 
775 /***************************************************************************
776  *
777  *  XXXXX
778  *
779  ***************************************************************************/
780 
781 
782 /*
783  * This function does only return on success.
784  */
do_connect(ei_cnode * ec,char * nodename,struct call_flags * flags)785 static int do_connect(ei_cnode *ec, char *nodename, struct call_flags *flags)
786 {
787     int fd;
788     int start_flags;
789     int r;
790 
791     start_flags = ERL_START_ENODE |
792 	(flags->use_long_name? ERL_START_LONG : 0) |
793 	(flags->verbosep? ERL_START_VERBOSE : 0) |
794 	(flags->debugp? ERL_START_DEBUG : 0);
795 
796     if ((fd = ei_connect(ec, nodename)) >= 0) {
797 	/* success */
798 	if (flags->verbosep) {
799 	    fprintf(stderr,"erl_call: now connected to node %s\n", nodename);
800 	}
801     } else {
802 	char alive[EI_MAXALIVELEN+1];
803 	char *hostname;
804 	struct hostent *h;
805 	char *cookieargs[3];
806 	char **args;
807 
808 	cookieargs[0] = "-setcookie";
809 	cookieargs[1] = flags->cookie;
810 	cookieargs[2] = NULL;
811 
812 	args = (flags->cookie) ? cookieargs : NULL;
813 
814 	if (!(hostname = strrchr(nodename,'@'))) {
815 	    return ERL_BADARG;
816 	}
817 	strncpy(alive,nodename,hostname-nodename);
818 	alive[hostname-nodename] = 0x0;
819 	hostname++;
820 
821 	h = ei_gethostbyname(hostname);
822 
823 
824 	if ((r=erl_start_sys(ec,alive,(Erl_IpAddr)(h->h_addr_list[0]),
825 			     start_flags,flags->script,args)) < 0) {
826 	    fprintf(stderr,"erl_call: unable to start node, error = %d\n", r);
827             exit_free_flags_fields(1, flags);
828 	}
829 
830 	if ((fd=ei_connect(ec, nodename)) >= 0) {
831 	    /* success */
832 	    if (flags->verbosep) {
833 		fprintf(stderr,"erl_call: now connected to node \"%s\"\n",
834 			nodename);
835 	    }
836 	} else {
837 	    /* (failure) */
838 	    switch (fd) {
839 	    case ERL_NO_DAEMON:
840 		fprintf(stderr,"erl_call: no epmd running\n");
841                 exit_free_flags_fields(1, flags);
842 	    case ERL_CONNECT_FAIL:
843 		fprintf(stderr,"erl_call: connect failed\n");
844                 exit_free_flags_fields(1, flags);
845 	    case ERL_NO_PORT:
846 		fprintf(stderr,"erl_call: node is not running\n");
847                 exit_free_flags_fields(1, flags);
848 	    case ERL_TIMEOUT:
849 		fprintf(stderr,"erl_call: connect timed out\n");
850                 exit_free_flags_fields(1, flags);
851 	    default:
852 		fprintf(stderr,"erl_call: error during connect\n");
853                 exit_free_flags_fields(1, flags);
854 	    }
855 	}
856     }
857 
858     return fd;
859 } /* do_connect */
860 
861 #define SKIP_SPACE(s) while(isspace((int)*(s))) (s)++
862 #define EAT(s) while (!isspace((int)*(s)) && (*(s) != '\0')) (s)++
863 
split_apply_string(char * str,char ** mod,char ** fun,char ** args)864 static void split_apply_string(char *str,
865 			       char **mod,
866 			       char **fun,
867 			       char **args)
868 {
869   char *begin=str;
870   char *start="start";
871   char *empty_list="[]";
872   int len;
873 
874   SKIP_SPACE(str);
875   if (*str == '\0') {
876       fprintf(stderr,"erl_call: wrong format of apply string (1)\n");
877       exit(1);
878   }
879 
880   EAT(str);
881   len = str-begin;
882   *mod = (char *) ei_chk_calloc(len + 1, sizeof(char));
883   memcpy(*mod, begin, len);
884 
885   SKIP_SPACE(str);
886   if (*str == '\0') {
887     *fun = ei_chk_strdup(start);
888     *args = ei_chk_strdup(empty_list);
889     return;
890   }
891   begin = str;
892   EAT(str);
893   len = str-begin;
894   *fun = (char *) ei_chk_calloc(len + 1, sizeof(char));
895   memcpy(*fun, begin, len);
896 
897   SKIP_SPACE(str);
898   if (*str == '\0') {
899     *args = ei_chk_strdup(empty_list);
900     return;
901   }
902 
903   *args = ei_chk_strdup(str);
904 
905   return;
906 
907 } /* split_apply_string */
908 
909 
910 /*
911  * Read from stdin until EOF is reached.
912  * Allocate the buffer needed.
913  */
read_stdin(char ** buf)914 static int read_stdin(char **buf)
915 {
916     int bsize = BUFSIZ;
917     int len = 0;
918     int i;
919     char *tmp = (char *) ei_chk_malloc(bsize);
920 
921     while (1) {
922 	if ((i = read(0, &tmp[len], bsize-len)) < 0) {
923 	    fprintf(stderr,"erl_call: can't read stdin, errno = %d", errno);
924 	    exit(1);
925 	} else if (i == 0) {
926 	    break;
927 	} else {
928 	    len += i;
929 	    if ((len+50) > bsize) {
930 		bsize = len * 2;
931 		tmp = (char *) ei_chk_realloc(tmp, bsize);
932 	    } else {
933 		continue;
934 	    }
935 	}
936     } /* while */
937     *buf = tmp;
938     return len;
939 
940 } /* read_stdin */
941 
942 /*
943  * Get the module from stdin.
944  */
get_module(char ** mbuf,char ** mname)945 static int get_module(char **mbuf, char **mname)
946 {
947   char *tmp;
948   int len,i;
949 
950   len = read_stdin(mbuf);
951   /*
952    * Now, get the module name.
953    */
954   if ((tmp = strstr(*mbuf, "-module(")) != NULL) {
955     char *start;
956     tmp += strlen("-module(");
957     while ((*tmp) == ' ') tmp++; /* eat space */
958     start = tmp;
959     while (1) {
960       if (isalnum((int)*tmp) || (*tmp == '_')) {
961 	tmp++;
962 	continue;
963       } else {
964 	  break;
965       }
966     } /* while */
967     i = tmp - start;
968     *mname = (char *) ei_chk_calloc(i+1, sizeof(char));
969     memcpy(*mname, start, i);
970   }
971 
972   return len;
973 
974 } /* get_module */
975 
976 #ifdef __WIN32__
timer_thread(void * data)977 static DWORD WINAPI timer_thread(void *data) {
978     DWORD_PTR timeout = (DWORD_PTR)data * 1000;
979 
980     Sleep(timeout);
981     exit(1);
982 }
983 
start_timeout(int timeout)984 static void start_timeout(int timeout) {
985     if (CreateThread(NULL, 0, timer_thread, (void*)timeout, 0, NULL) == NULL) {
986         fprintf(stderr,"erl_call: Failed to start timer thread\n");
987         exit(1);
988     }
989 }
990 #else
start_timeout(int timeout)991 static void start_timeout(int timeout) {
992     alarm(timeout);
993 }
994 #endif
995 
996 /***************************************************************************
997  *
998  *  Different error reporting functions that output usage
999  *
1000  ***************************************************************************/
1001 
usage_noexit(const char * progname)1002 static void usage_noexit(const char *progname) {
1003   fprintf(stderr,"\nUsage: %s [-[demqrsv]] [-c Cookie] [-h HiddenName] \n", progname);
1004   fprintf(stderr,"            [-x ErlScript] [-a [Mod [Fun [Args]]]] [-timeout Secs]\n");
1005   fprintf(stderr,"            (-n Node | -sname Node | -name Node | -address [HOSTNAME:]PORT)\n\n");
1006 #ifdef __WIN32__
1007   fprintf(stderr,"  where: -a  apply(Mod,Fun,Args) (e.g -a \"erlang length [[a,b,c]]\"\n");
1008 #else
1009   fprintf(stderr,"  where: -a  apply(Mod,Fun,Args) (e.g -a 'erlang length [[a,b,c]]'\n");
1010 #endif
1011   fprintf(stderr,"         -c  cookie string; by default read from ~/.erlang.cookie\n");
1012   fprintf(stderr,"         -d  direct Erlang output to ~/.erl_call.out.<Nodename>\n");
1013   fprintf(stderr,"         -e  evaluate contents of standard input (e.g., echo \"X=1,Y=2,{X,Y}.\"|%s -e ...)\n",
1014           progname);
1015   fprintf(stderr,
1016           "         -fetch_stdout\n"
1017           "           execute the code, specified with the -a or -e option, in a new\n"
1018           "           process that has a group leader that forwards all stdout (standard\n"
1019           "           output) data so that it is printed to stdout of the\n"
1020           "           %s process. See the %s man page for additional information.\n",
1021           progname, progname);
1022   fprintf(stderr,"         -h  specify a name for the erl_call client node\n");
1023   fprintf(stderr,"         -m  read and compile Erlang module from stdin\n");
1024   fprintf(stderr,"         -n  name of Erlang node, same as -name\n");
1025   fprintf(stderr,"         -name  name of Erlang node, expanded to a fully qualified\n");
1026   fprintf(stderr,"         -sname name of Erlang node, short form will be used\n");
1027   fprintf(stderr,"         -address [HOSTNAME:]PORT of Erlang node\n"
1028           "                  (the default hostname is the hostname of the local manchine)\n"
1029           "                  (e.g., %s -address my_host:36303 ...)\n"
1030           "                  (cannot be combinated with -s, -n, -name and -sname)\n",
1031           progname);
1032   fprintf(stderr,"         -no_result_term  do not print the result term\n");
1033   fprintf(stderr,"         -timeout  command timeout, in seconds\n");
1034   fprintf(stderr,"         -q  halt the Erlang node (overrides the -s switch)\n");
1035   fprintf(stderr,"         -r  use a random name for the erl_call client node\n");
1036   fprintf(stderr,"         -s  start a new Erlang node if necessary\n");
1037   fprintf(stderr,"         -v  verbose mode, i.e print some information on stderr\n");
1038   fprintf(stderr,"         -x  use specified erl start script, default is erl\n");
1039 }
1040 
usage_arg(const char * progname,const char * switchname)1041 static void usage_arg(const char *progname, const char *switchname) {
1042   fprintf(stderr, "Missing argument(s) for \'%s\'.\n", switchname);
1043   usage_noexit(progname);
1044   exit(1);
1045 }
1046 
usage_error(const char * progname,const char * switchname)1047 static void usage_error(const char *progname, const char *switchname) {
1048   fprintf(stderr, "Illegal argument \'%s\'.\n", switchname);
1049   usage_noexit(progname);
1050   exit(1);
1051 }
1052 
usage(const char * progname)1053 static void usage(const char *progname) {
1054   usage_noexit(progname);
1055   exit(0);
1056 }
1057 
1058 /***************************************************************************
1059  *
1060  *  Utility functions
1061  *
1062  ***************************************************************************/
1063 
ei_chk_malloc(size_t size)1064 static void* ei_chk_malloc(size_t size)
1065 {
1066     void *p = malloc(size);
1067     if (p == NULL) {
1068         fprintf(stderr,"erl_call: insufficient memory\n");
1069         exit(1);
1070     }
1071     return p;
1072 }
1073 
ei_chk_calloc(size_t nmemb,size_t size)1074 static void* ei_chk_calloc(size_t nmemb, size_t size)
1075 {
1076     void *p = calloc(nmemb, size);
1077     if (p == NULL) {
1078         fprintf(stderr,"erl_call: insufficient memory\n");
1079         exit(1);
1080     }
1081     return p;
1082 }
1083 
ei_chk_realloc(void * old,size_t size)1084 static void* ei_chk_realloc(void *old, size_t size)
1085 {
1086     void *p = realloc(old, size);
1087     if (!p) {
1088         fprintf(stderr, "erl_call: cannot reallocate %u bytes of memory from %p\n",
1089                 (unsigned) size, old);
1090         exit (1);
1091     }
1092     return p;
1093 }
1094 
ei_chk_strdup(char * s)1095 static char* ei_chk_strdup(char *s)
1096 {
1097     char *p = strdup(s);
1098     if (p == NULL) {
1099         fprintf(stderr,"erl_call: insufficient memory\n");
1100         exit(1);
1101     }
1102     return p;
1103 }
1104 
1105 /*
1106  * Helper function that that:
1107  *
1108  * 1. Executes a function on a remote node
1109  *
1110  * 2. Forwards what the executed function and its subprocesses prints
1111  *    to stdout of this process
1112  *
1113  * 3. Returns the result of the executed function (the result term is
1114  *    written to the buffer pointed to by x)
1115  *
1116  * This function is similar to (and is based on) the function ei_rpc
1117  */
rpc_print_node_stdout(ei_cnode * ec,int fd,char * mod,char * fun,const char * inbuf,int inbuflen,ei_x_buff * x)1118 static int rpc_print_node_stdout(ei_cnode* ec, int fd, char *mod,
1119                                  char *fun, const char* inbuf,
1120                                  int inbuflen, ei_x_buff* x)
1121 {
1122     int i, index;
1123     int got_rex_response = 0;
1124     int initial_buff_index = x->index;
1125     ei_term t;
1126     erlang_msg msg;
1127     char rex[MAXATOMLEN];
1128 
1129     if (ei_xrpc_to(ec, fd, mod, fun, inbuf, inbuflen, EI_RPC_FETCH_STDOUT) < 0) {
1130 	return ERL_ERROR;
1131     }
1132 
1133     while (!got_rex_response) {
1134         /* ei_rpc_from() responds with a tick if it gets one... */
1135         while ((i = ei_rpc_from(ec, fd, ERL_NO_TIMEOUT, &msg, x)) == ERL_TICK)
1136             ;
1137 
1138         if (i == ERL_ERROR) return i;
1139 
1140         index = 0;
1141         if (ei_decode_version(x->buff, &index, &i) < 0)
1142             goto ebadmsg;
1143 
1144         if (ei_decode_ei_term(x->buff, &index, &t) < 0)
1145             goto ebadmsg;
1146 
1147         if (t.ei_type != ERL_SMALL_TUPLE_EXT && t.ei_type != ERL_LARGE_TUPLE_EXT)
1148             goto ebadmsg;
1149 
1150         if (t.arity != 2)
1151             goto ebadmsg;
1152 
1153         if (ei_decode_atom(x->buff, &index, rex) < 0)
1154             goto ebadmsg;
1155 
1156         if (strcmp("rex_stdout", rex) == 0) {
1157             int type;
1158             int size;
1159             char* binary_buff;
1160             long actual_size;
1161             ei_get_type(x->buff, &index, &type, &size);
1162             if(type != ERL_BINARY_EXT) {
1163                 goto ebadmsg;
1164             }
1165             binary_buff = ei_chk_malloc(size + 1);
1166             ei_decode_binary(x->buff, &index, binary_buff, &actual_size);
1167             binary_buff[size] = '\0';
1168             printf("%s", binary_buff);
1169             free(binary_buff);
1170             /* Reset the buffer as we need to read more and we have no
1171                use for what we have already read */
1172             x->index = initial_buff_index;
1173         } else {
1174             if(strcmp("rex", rex) != 0)
1175                 goto ebadmsg;
1176             got_rex_response = 1;
1177         }
1178     }
1179     /* remove header */
1180     x->index -= index;
1181     memmove(x->buff, &x->buff[index], x->index);
1182     return 0;
1183 
1184 ebadmsg:
1185 
1186     return ERL_ERROR;
1187 }
1188 
1189 
exit_free_flags_fields(int exit_status,struct call_flags * flags)1190 void exit_free_flags_fields(int exit_status, struct call_flags* flags) {
1191     if (flags->script != NULL) {
1192         free(flags->script);
1193     }
1194     if (flags->hidden != NULL) {
1195         free(flags->hidden);
1196     }
1197     if (flags->cookie != NULL) {
1198         free(flags->cookie);
1199     }
1200     if (flags->apply != NULL) {
1201         free(flags->apply);
1202     }
1203     if (flags->hostname != NULL) {
1204         free(flags->hostname);
1205     }
1206     exit(exit_status);
1207 }
1208 
1209 
1210 /* Constants and helper functions used by erl_start_sys */
1211 
1212 /* FIXME is this a case a vfork can be used? */
1213 #if !HAVE_WORKING_VFORK
1214 # define vfork fork
1215 #endif
1216 
1217 #ifndef MAXPATHLEN
1218 #define MAXPATHLEN 1024
1219 #endif
1220 
1221 #ifndef RSH
1222 #define RSH "/usr/bin/ssh"
1223 #endif
1224 
1225 #ifndef HAVE_SOCKLEN_T
1226 typedef int SocklenType;
1227 #else
1228 typedef socklen_t SocklenType;
1229 #endif
1230 
1231 /* FIXME check errors from malloc */
1232 
1233 static struct in_addr *get_addr(const char *hostname, struct in_addr *oaddr);
1234 
1235 static int wait_for_erlang(int sockd, int magic, struct timeval *timeout);
1236 #if defined(__WIN32__)
1237 static int unique_id(void);
1238 static HANDLE spawn_erlang_epmd(ei_cnode *ec,
1239 				       char *alive,
1240 				       Erl_IpAddr adr,
1241 				       int flags,
1242 				       char *erl_or_epmd,
1243 				       char *args[],
1244 				       int port,
1245 				       int is_erlang);
1246 #else
1247 static int exec_erlang(ei_cnode *ec, char *alive, Erl_IpAddr adr, int flags,
1248 		       char *erl, char *args[],int port);
1249 #endif
1250 
1251 #if defined(__WIN32__)
1252 #define DEF_ERL_COMMAND "erl"
1253 #define DEF_EPMD_COMMAND "epmd"
1254 #define ERL_REPLY_FMT   "-s erl_reply reply \"%s\" \"%d\" \"%d\""
1255 #define ERL_NAME_FMT    "-noinput -name %s"
1256 #define ERL_SNAME_FMT   "-noinput -sname %s"
1257 
1258 #define IP_ADDR_CHARS 15
1259 #define FORMATTED_INT_LEN 10
1260 
unique_id(void)1261 static int unique_id(void){
1262     return (int) GetCurrentThreadId();
1263 }
1264 
enquote_args(char ** oargs,char *** qargs)1265 static int enquote_args(char **oargs, char ***qargs){
1266     char **args;
1267     int len;
1268     int i;
1269     int qwhole;
1270     int extra;
1271     char *ptr;
1272     char *ptr2;
1273 
1274     if(oargs == NULL){
1275 	*qargs = malloc(sizeof(char *));
1276 	**qargs = NULL;
1277 	return 0;
1278     };
1279 
1280     for(len=0;oargs[len] != NULL; ++len)
1281 	;
1282     args = malloc(sizeof(char *) * (len + 1));
1283 
1284     for(i = 0; i < len; ++i){
1285 	qwhole = strchr(oargs[i],' ') != NULL;
1286 	extra = qwhole * 2;
1287 	for(ptr = oargs[i]; *ptr != '\0'; ++ptr)
1288 	    extra += (*ptr == '"');
1289 	args[i] = malloc(strlen(oargs[i]) +
1290 			     extra +
1291 			     1);
1292 	ptr2 = args[i];
1293 	if(qwhole)
1294 	    *(ptr2++) = '"';
1295 	for(ptr = oargs[i]; *ptr != '\0'; ++ptr){
1296 	    if(*ptr == '"')
1297 		*(ptr2++) = '\\';
1298 	    *(ptr2++) = *ptr;
1299 	}
1300 	if(qwhole)
1301 	    *(ptr2++) = '"';
1302 	*ptr2 = '\0';
1303     }
1304     args[len] = NULL;
1305     *qargs = args;
1306     return len;
1307 }
1308 
free_args(char ** args)1309 static void free_args(char **args){
1310     char **ptr = args;
1311     while(*ptr != NULL)
1312 	free(*(ptr++));
1313     free(args);
1314 }
1315 
1316 /* In NT we cannot fork(), Erlang and Epmd gets
1317    spawned by this function instead. */
1318 
spawn_erlang_epmd(ei_cnode * ec,char * alive,Erl_IpAddr adr,int flags,char * erl_or_epmd,char * args[],int port,int is_erlang)1319 static HANDLE spawn_erlang_epmd(ei_cnode *ec,
1320 				       char *alive,
1321 				       Erl_IpAddr adr,
1322 				       int flags,
1323 				       char *erl_or_epmd,
1324 				       char *args[],
1325 				       int port,
1326 				       int is_erlang)
1327 {
1328     STARTUPINFO sinfo;
1329     SECURITY_ATTRIBUTES sa;
1330     PROCESS_INFORMATION pinfo;
1331     char *cmdbuf;
1332     int cmdlen;
1333     char *ptr;
1334     int i;
1335     int num_args;
1336     char *name_format;
1337     struct in_addr myaddr;
1338     struct in_addr *hisaddr = (struct in_addr *)adr;
1339     char iaddrbuf[IP_ADDR_CHARS + 1];
1340     HANDLE ret;
1341 
1342     if(is_erlang){
1343 	get_addr(ei_thishostname(ec), &myaddr);
1344 	if((ptr = inet_ntoa(myaddr)) == NULL)
1345 	    return INVALID_HANDLE_VALUE;
1346 	else
1347 	    strcpy(iaddrbuf,ptr);
1348     }
1349     if ((flags & ERL_START_REMOTE) ||
1350 	(is_erlang && (hisaddr->s_addr != myaddr.s_addr))) {
1351 	return INVALID_HANDLE_VALUE;
1352     } else {
1353 	num_args = enquote_args(args, &args);
1354 	for(cmdlen = i = 0; args[i] != NULL; ++i)
1355 	    cmdlen += strlen(args[i]) + 1;
1356 	if(!erl_or_epmd)
1357 	    erl_or_epmd = (is_erlang) ? DEF_ERL_COMMAND :
1358 	    DEF_EPMD_COMMAND;
1359 	if(is_erlang){
1360 	    name_format = (flags & ERL_START_LONG) ? ERL_NAME_FMT :
1361 		ERL_SNAME_FMT;
1362 	    cmdlen +=
1363 		strlen(erl_or_epmd) + (*erl_or_epmd != '\0') +
1364 		strlen(name_format) + 1 + strlen(alive) +
1365 		strlen(ERL_REPLY_FMT) + 1 + strlen(iaddrbuf) + 2 * FORMATTED_INT_LEN + 1;
1366 	    ptr = cmdbuf = malloc(cmdlen);
1367 	    if(*erl_or_epmd != '\0')
1368 		ptr += sprintf(ptr,"%s ",erl_or_epmd);
1369 	    ptr += sprintf(ptr, name_format,
1370 			   alive);
1371 	    ptr += sprintf(ptr, " " ERL_REPLY_FMT,
1372 		       iaddrbuf, port, unique_id());
1373 	} else { /* epmd */
1374 	    cmdlen += strlen(erl_or_epmd) + (*erl_or_epmd != '\0') + 1;
1375 	    ptr = cmdbuf = malloc(cmdlen);
1376 	    if(*erl_or_epmd != '\0')
1377 		ptr += sprintf(ptr,"%s ",erl_or_epmd);
1378 	    else
1379 		*(ptr++) = '\0';
1380 	}
1381 	for(i= 0; args[i] != NULL; ++i){
1382 	    *(ptr++) = ' ';
1383 	    strcpy(ptr,args[i]);
1384 	    ptr += strlen(args[i]);
1385 	}
1386 	free_args(args);
1387 	if (flags & ERL_START_VERBOSE) {
1388 	    fprintf(stderr,"erl_call: commands are %s\n",cmdbuf);
1389 	}
1390 	/* OK, one single command line... */
1391 	/* Hmmm, hidden or unhidden window??? */
1392 	memset(&sinfo,0,sizeof(sinfo));
1393 	sinfo.cb = sizeof(STARTUPINFO);
1394 	sinfo.dwFlags = STARTF_USESHOWWINDOW /*|
1395 	    STARTF_USESTDHANDLES*/;
1396 	sinfo.wShowWindow = SW_HIDE; /* Hidden! */
1397 	sinfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
1398 	sinfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
1399 	sinfo.hStdError = GetStdHandle(STD_ERROR_HANDLE);
1400 	sa.nLength = sizeof(sa);
1401 	sa.lpSecurityDescriptor = NULL;
1402 	sa.bInheritHandle = /*TRUE*/ FALSE;
1403 	if(!CreateProcess(
1404 			  NULL,
1405 			  cmdbuf,
1406 			  &sa,
1407 			  NULL,
1408 			  /*TRUE*/ FALSE,
1409 			  0 | CREATE_NEW_CONSOLE,
1410 			  NULL,
1411 			  NULL,
1412 			  &sinfo,
1413 			  &pinfo))
1414 	    ret = INVALID_HANDLE_VALUE;
1415 	else
1416 	    ret = pinfo.hProcess;
1417 	free(cmdbuf);
1418 	return ret;
1419     }
1420     /* NOTREACHED */
1421 }
1422 #else /* Unix */
1423 
1424 /* call this from the child process to start an erlang system. This
1425  * function just builds the erlang command line and then calls it.
1426  *
1427  * node - the nodename for the new node
1428  * flags - various options that can be set (see erl_start.h)
1429  * erl - name of the erlang executable, or NULL for default ("erl")
1430  * args - additional arguments to pass to erlang executable
1431  * port - the port number where we wait for acknowledgment from the enode
1432  *
1433  * we have a potential problem if args conflicts with any of the
1434  * arguments we use here.
1435  */
exec_erlang(ei_cnode * ec,char * alive,Erl_IpAddr adr,int flags,char * erl,char * args[],int port)1436 static int exec_erlang(ei_cnode *ec,
1437 		       char *alive,
1438 		       Erl_IpAddr adr,
1439 		       int flags,
1440 		       char *erl,
1441 		       char *args[],
1442 		       int port)
1443 {
1444 #if !defined(__WIN32__)
1445   int fd,len,l,i;
1446   char **s;
1447   char *argv[4];
1448   char argbuf[BUFSIZ];
1449   struct in_addr myaddr;
1450   struct in_addr *hisaddr = (struct in_addr *)adr;
1451 
1452   if (!get_addr(ei_thishostname(ec), &myaddr)) {
1453       fprintf(stderr,"erl_call: failed to find hostname\r\n");
1454       return ERL_SYS_ERROR;
1455   }
1456 
1457   /* on this host? */
1458   /* compare ip addresses, unless forced by flag setting to use rsh */
1459   if ((flags & ERL_START_REMOTE) || (hisaddr->s_addr != myaddr.s_addr)) {
1460     argv[0] = RSH;
1461     len = strlen(inet_ntoa(*hisaddr));
1462     argv[1] = malloc(len+1);
1463     strcpy(argv[1],inet_ntoa(*hisaddr));
1464   }
1465   else {
1466   /* Yes - use sh to start local Erlang */
1467     argv[0] = "sh";
1468     argv[1] = "-c";
1469   }
1470   argv[2] = argbuf;
1471   argv[3] = NULL;
1472 
1473   len = 0;
1474   *argbuf=(char)0;
1475 
1476   sprintf(argbuf,"exec %s ", (erl? erl: "erl"));
1477   len = strlen(argbuf);
1478 
1479   /* *must* be noinput or node (seems to) hang... */
1480   /* long or short names? */
1481   sprintf(&argbuf[len], "-noinput %s %s ",
1482 	  ((flags & ERL_START_LONG) ? "-name" : "-sname"),
1483 	  alive);
1484   len = strlen(argbuf);
1485 
1486   /* now make the new node report back when it's ready */
1487   /* add: myip, myport and replymsg */
1488   sprintf(&argbuf[len],
1489 	  "-s erl_reply reply %s %d %d ",
1490 	  inet_ntoa(myaddr),port,(int)getpid());
1491 #ifdef HARD_DEBUG
1492   fprintf(stderr,"erl_call: debug %s\n",&argbuf[len]);
1493 #endif
1494   len = strlen(argbuf);
1495 
1496   /* additional arguments to be passed to the other system */
1497   /* make sure that they will fit first */
1498   for (l=0, s = args; s && *s; s++) l+= strlen(*s) + 1;
1499 
1500   if (len + l + 1 > BUFSIZ) return ERL_BADARG;
1501   else {
1502     for (s = args; s && *s; s++) {
1503       strcat(argbuf," ");
1504       strcat(argbuf,*s);
1505     }
1506     len += l + 1;
1507   }
1508 
1509   if (flags & ERL_START_VERBOSE) {
1510     fprintf(stderr,"erl_call: %s %s %s\n",argv[0],argv[1],argv[2]);
1511   }
1512 
1513   /* close all descriptors in child */
1514   for (i=0; i<64; i++) close(i);
1515 
1516   /* debug output to file? */
1517   if (flags & ERL_START_DEBUG) {
1518     char debugfile[MAXPATHLEN+1];
1519     char *home=getenv("HOME");
1520     sprintf(debugfile,"%s/%s.%s",home,ERL_START_LOGFILE,alive);
1521     if ((fd=open(debugfile, O_WRONLY | O_CREAT | O_APPEND, 0644)) >= 0) {
1522       time_t t = time(NULL);
1523       dup2(fd,1);
1524       dup2(fd,2);
1525       fprintf(stderr,"\n\n===== Log started ======\n%s \n",ctime(&t));
1526       fprintf(stderr,"erl_call: %s %s %s\n",argv[0],argv[1],argv[2]);
1527     }
1528   }
1529 
1530   /* start the system */
1531   execvp(argv[0], argv);
1532 
1533   if (flags & ERL_START_DEBUG) {
1534     fprintf(stderr,"erl_call: exec failed: (%d) %s %s %s\n",
1535 	    errno,argv[0],argv[1],argv[2]);
1536   }
1537 
1538 #endif
1539   /* (hopefully) NOT REACHED */
1540   return ERL_SYS_ERROR;
1541 } /* exec_erlang() */
1542 
1543 #endif /* defined(WINDOWS) */
1544 
1545 #if defined(__WIN32__)
gettimeofday(struct timeval * now,void * dummy)1546 static void gettimeofday(struct timeval *now,void *dummy){
1547     SYSTEMTIME systime;
1548 	FILETIME ft;
1549     DWORD x;
1550     GetSystemTime(&systime);
1551     SystemTimeToFileTime(&systime,&ft);
1552     x = ft.dwLowDateTime / 10;
1553     now->tv_sec = x / 1000000;
1554     now->tv_usec = x % 1000000;
1555 }
1556 
1557 #endif
1558 
1559 
1560 /* wait for the remote system to reply */
1561 /*
1562  * sockd - an open socket where we expect a connection from the e-node
1563  * magic - sign on message the e-node must provide for verification
1564  * timeout - how long to wait before returning failure
1565  *
1566  * OBS: the socket is blocking, and there is a potential deadlock if we
1567  * get an accept but the peer sends no data (and does not close).
1568  * in normal cases the timeout will work ok however, i.e. either we
1569  * never get any connection, or we get connection then close().
1570  */
wait_for_erlang(int sockd,int magic,struct timeval * timeout)1571 static int wait_for_erlang(int sockd, int magic, struct timeval *timeout)
1572 {
1573   struct timeval to;
1574   struct timeval stop_time;
1575   struct timeval now;
1576   fd_set rdset;
1577   int fd;
1578   int n,i;
1579   char buf[16];
1580   struct sockaddr_in peer;
1581   SocklenType len = (SocklenType) sizeof(peer);
1582 
1583   /* determine when we should exit this function */
1584   gettimeofday(&now,NULL);
1585   stop_time.tv_sec = now.tv_sec + timeout->tv_sec;
1586   stop_time.tv_usec = now.tv_usec + timeout->tv_usec;
1587   while (stop_time.tv_usec > 1000000) {
1588     stop_time.tv_sec++;
1589     stop_time.tv_usec -= 1000000;
1590   }
1591 
1592 #ifdef HARD_DEBUG
1593   fprintf(stderr,"erl_call: debug time is %ld.%06ld, "
1594 	  "will timeout at %ld.%06ld\n",
1595 	  now.tv_sec,now.tv_usec,stop_time.tv_sec,stop_time.tv_usec);
1596 #endif
1597 
1598   while (1) {
1599     FD_ZERO(&rdset);
1600     FD_SET(sockd,&rdset);
1601 
1602     /* adjust the timeout to (stoptime - now) */
1603     gettimeofday(&now,NULL);
1604     to.tv_sec = stop_time.tv_sec - now.tv_sec;
1605     to.tv_usec = stop_time.tv_usec - now.tv_usec;
1606     while ((to.tv_usec < 0) && (to.tv_sec > 0)) {
1607       to.tv_usec += 1000000;
1608       to.tv_sec--;
1609     }
1610     if (to.tv_sec < 0) return ERL_TIMEOUT;
1611 
1612 #ifdef HARD_DEBUG
1613     fprintf(stderr,"erl_call: debug remaining to timeout: %ld.%06ld\n",
1614 	    to.tv_sec,to.tv_usec);
1615 #endif
1616     switch ((i = select(sockd+1,&rdset,NULL,NULL,&to))) {
1617     case -1:
1618       return ERL_SYS_ERROR;
1619       break;
1620 
1621     case 0: /* timeout */
1622 #ifdef HARD_DEBUG
1623       gettimeofday(&now,NULL);
1624       fprintf(stderr,"erl_call: debug timed out at %ld.%06ld\n",
1625 	      now.tv_sec,now.tv_usec);
1626 #endif
1627       return ERL_TIMEOUT;
1628       break;
1629 
1630     default: /* ready descriptors */
1631 #ifdef HARD_DEBUG
1632       gettimeofday(&now,NULL);
1633       fprintf(stderr,"erl_call: debug got select at %ld.%06ld\n",
1634 	      now.tv_sec,now.tv_usec);
1635 #endif
1636       if (FD_ISSET(sockd,&rdset)) {
1637 	if ((fd = accept(sockd,(struct sockaddr *)&peer,&len)) < 0)
1638 	  return ERL_SYS_ERROR;
1639 
1640 	/* now get sign-on message and terminate it */
1641 #if defined(__WIN32__)
1642 	if ((n=recv(fd,buf,16,0)) >= 0) buf[n]=0x0;
1643 	closesocket(fd);
1644 #else
1645 	if ((n=read(fd,buf,16)) >= 0) buf[n]=0x0;
1646 	close(fd);
1647 #endif
1648 #ifdef HARD_DEBUG
1649 	fprintf(stderr,"erl_call: debug got %d, expected %d\n",
1650 		atoi(buf),magic);
1651 #endif
1652 	if (atoi(buf) == magic) return 0; /* success */
1653       } /* if FD_SET */
1654     } /* switch */
1655   } /* while */
1656 
1657   /* unreached? */
1658   return ERL_SYS_ERROR;
1659 } /* wait_for_erlang() */
1660 
1661 
get_addr(const char * hostname,struct in_addr * oaddr)1662 static struct in_addr *get_addr(const char *hostname, struct in_addr *oaddr)
1663 {
1664   struct hostent *hp;
1665 
1666 #if !defined (__WIN32__)
1667   char buf[1024];
1668   struct hostent host;
1669   int herror;
1670 
1671   hp = ei_gethostbyname_r(hostname,&host,buf,1024,&herror);
1672 #else
1673   hp = ei_gethostbyname(hostname);
1674 #endif
1675 
1676   if (hp) {
1677     memmove(oaddr,hp->h_addr_list[0],sizeof(*oaddr));
1678     return oaddr;
1679   }
1680   return NULL;
1681 }
1682 
1683 /* Start an Erlang node. return value 0 indicates that node was
1684  * started successfully, negative values indicate error.
1685  *
1686  * node -  the name of the remote node to start (alivename@hostname).
1687  * flags - turn on or off certain options. See erl_start.h for a list.
1688  * erl -  is the name of the erl script to call. If NULL, the default
1689  * name "erl" will be used.
1690  * args - a NULL-terminated list of strings containing
1691  * additional arguments to be sent to the remote Erlang node. These
1692  * strings are simply appended to the end of the command line, so any
1693  * quoting of special characters, etc must be done by the caller.
1694  * There may be some conflicts between some of these arguments and the
1695  * default arguments hard-coded into this function, so be careful.
1696  */
erl_start_sys(ei_cnode * ec,char * alive,Erl_IpAddr adr,int flags,char * erl,char * args[])1697 int erl_start_sys(ei_cnode *ec, char *alive, Erl_IpAddr adr, int flags,
1698 		  char *erl, char *args[])
1699 {
1700   struct timeval timeout;
1701   struct sockaddr_in addr;
1702   SocklenType namelen;
1703   int port;
1704   int sockd = 0;
1705   int one = 1;
1706 #if defined(__WIN32__)
1707   HANDLE pid;
1708 #else
1709   int pid;
1710 #endif
1711   int r = 0;
1712 
1713   if (((sockd = socket(AF_INET, SOCK_STREAM, 0)) < 0) ||
1714       (setsockopt(sockd, SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof(one)) < 0)) {
1715     r = ERL_SYS_ERROR;
1716     goto done;
1717   }
1718 
1719   memset(&addr,0,sizeof(addr));
1720   addr.sin_family = AF_INET;
1721   addr.sin_addr.s_addr = htonl(INADDR_ANY);
1722   addr.sin_port = 0;
1723 
1724   if (bind(sockd,(struct sockaddr *)&addr,sizeof(addr))<0) {
1725       return ERL_SYS_ERROR;
1726   }
1727   namelen = sizeof(addr);
1728   if (getsockname(sockd,(struct sockaddr *)&addr,&namelen)<0) {
1729       return ERL_SYS_ERROR;
1730   }
1731   port = ntohs(addr.sin_port);
1732 
1733   listen(sockd,5);
1734 
1735 #if defined(__WIN32__)
1736   pid = spawn_erlang_epmd(ec,alive,adr,flags,erl,args,port,1);
1737   if (pid == INVALID_HANDLE_VALUE)
1738      return ERL_SYS_ERROR;
1739   timeout.tv_usec = 0;
1740   timeout.tv_sec = 10; /* ignoring ERL_START_TIME */
1741   if((r = wait_for_erlang(sockd,unique_id(),&timeout))
1742      == ERL_TIMEOUT) {
1743       /* Well, this is not a nice way to do it, and it does not
1744 	 always kill the emulator, but the alternatives are few.*/
1745       TerminateProcess(pid,1);
1746   }
1747 #else /* Unix */
1748   switch ((pid = fork())) {
1749   case -1:
1750     r = ERL_SYS_ERROR;
1751     break;
1752 
1753   case 0:
1754     /* child - start the erlang node */
1755     exec_erlang(ec, alive, adr, flags, erl, args, port);
1756 
1757     /* error if reached - parent reports back to caller after timeout
1758        so we just exit here */
1759     exit(1);
1760     break;
1761 
1762   default:
1763 
1764     /* parent - waits for response from Erlang node */
1765     /* child pid used here as magic number */
1766     timeout.tv_usec = 0;
1767     timeout.tv_sec = 10; /* ignoring ERL_START_TIME */
1768     if ((r = wait_for_erlang(sockd,pid,&timeout)) == ERL_TIMEOUT) {
1769       /* kill child if no response */
1770       kill(pid,SIGINT);
1771       sleep(1);
1772       if (waitpid(pid,NULL,WNOHANG) != pid) {
1773 	/* no luck - try harder */
1774 	kill(pid,SIGKILL);
1775 	sleep(1);
1776 	waitpid(pid,NULL,WNOHANG);
1777       }
1778     }
1779 
1780   }
1781 #endif /* defined(__WIN32__) */
1782 
1783 done:
1784 #if defined(__WIN32__)
1785   if (sockd) closesocket(sockd);
1786 #else
1787   if (sockd) close(sockd);
1788 #endif
1789   return r;
1790 } /* erl_start_sys() */
1791