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  * Function: Makes it possible to send and receive Erlang
24  *    messages from the (Unix) command line.
25  *    Note: We don't free any memory at all since we only
26  *    live for a short while.
27  *
28  */
29 
30 #ifdef __WIN32__
31 #include <winsock2.h>
32 #include <direct.h>
33 #include <windows.h>
34 #include <winbase.h>
35 
36 #elif VXWORKS
37 
38 #include <stdio.h>
39 #include <string.h>
40 #include <vxWorks.h>
41 #include <hostLib.h>
42 #include <selectLib.h>
43 #include <ifLib.h>
44 #include <sockLib.h>
45 #include <taskLib.h>
46 #include <inetLib.h>
47 #include <unistd.h>
48 #include <sys/socket.h>
49 #include <netinet/in.h>
50 #include <netinet/tcp.h>
51 #include <time.h>
52 
53 #else /* unix */
54 
55 #include <sys/types.h>
56 #include <sys/uio.h>
57 #include <sys/time.h>
58 #include <unistd.h>
59 #include <sys/param.h>
60 #include <netdb.h>
61 #include <sys/times.h>
62 #include <sys/socket.h>
63 #include <netinet/in.h>
64 #include <arpa/inet.h>
65 
66 #if TIME_WITH_SYS_TIME
67 # include <sys/time.h>
68 # include <time.h>
69 #else
70 # if HAVE_SYS_TIME_H
71 #  include <sys/time.h>
72 # else
73 #  include <time.h>
74 # endif
75 #endif
76 
77 #endif
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 #include "erl_start.h"		/* FIXME remove dependency */
90 
91 /*
92  * Some nice global variables
93  * (I don't think "nice" is the right word actually... -gordon)
94  */
95 /* FIXME problem for threaded ? */
96 
97 struct call_flags {
98     int startp;
99     int cookiep;
100     int modp;
101     int evalp;
102     int randomp;
103     int use_long_name;	/* indicates if -name was used, else -sname or -n */
104     int debugp;
105     int verbosep;
106     int haltp;
107     char *cookie;
108     char *node;
109     char *hidden;
110     char *apply;
111     char *script;
112 };
113 
114 static void usage_arg(const char *progname, const char *switchname);
115 static void usage_error(const char *progname, const char *switchname);
116 static void usage(const char *progname);
117 static int get_module(char **mbuf, char **mname);
118 static int do_connect(ei_cnode *ec, char *nodename, struct call_flags *flags);
119 static int read_stdin(char **buf);
120 static void split_apply_string(char *str, char **mod,
121 			       char **fun, char **args);
122 static void* ei_chk_malloc(size_t size);
123 static void* ei_chk_calloc(size_t nmemb, size_t size);
124 static void* ei_chk_realloc(void *old, size_t size);
125 static char* ei_chk_strdup(char *s);
126 
127 
128 /***************************************************************************
129  *
130  *  XXXXX
131  *
132  ***************************************************************************/
133 
134 /* FIXME isn't VxWorks to handle arguments differently? */
135 
136 #if !defined(VXWORKS)
main(int argc,char * argv[])137 int main(int argc, char *argv[])
138 #else
139 int erl_call(int argc, char **argv)
140 #endif
141 {
142     int i = 1,fd,creation;
143     struct hostent *hp;
144     char host_name[EI_MAXHOSTNAMELEN+1];
145     char nodename[MAXNODELEN+1];
146     char *p = NULL;
147     char *ct = NULL; /* temporary used when truncating nodename */
148     int modsize = 0;
149     char *host = NULL;
150     char *module = NULL;
151     char *modname = NULL;
152     struct call_flags flags = {0}; /* Default 0 and NULL in all fields */
153     char* progname = argv[0];
154     ei_cnode ec;
155 
156     ei_init();
157 
158     /* Get the command line options */
159     while (i < argc) {
160 	if (argv[i][0] != '-') {
161 	    usage_error(progname, argv[i]);
162 	}
163 
164 	if (strcmp(argv[i], "-sname") == 0) { /* -sname NAME */
165 	    if (i+1 >= argc) {
166 		usage_arg(progname, "-sname ");
167 	    }
168 
169 	    flags.node = ei_chk_strdup(argv[i+1]);
170 	    i++;
171 	    flags.use_long_name = 0;
172 	} else if (strcmp(argv[i], "-name") == 0) {  /* -name NAME */
173 	    if (i+1 >= argc) {
174 		usage_arg(progname, "-name ");
175 	    }
176 
177 	    flags.node = ei_chk_strdup(argv[i+1]);
178 	    i++;
179 	    flags.use_long_name = 1;
180 	} else {
181 	    if (strlen(argv[i]) != 2) {
182 		usage_error(progname, argv[i]);
183 	    }
184 
185 	    switch (argv[i][1]) {
186 	    case 's':
187 		flags.startp = 1;
188 		break;
189 	    case 'q':
190 		flags.haltp = 1;
191 		break;
192 	    case 'v':
193 		flags.verbosep = 1;
194 		break;
195 	    case 'd':
196 		flags.debugp = 1;
197 		break;
198 	    case 'r':
199 		flags.randomp = 1;
200 		break;
201 	    case 'e':
202 		flags.evalp = 1;
203 		break;
204 	    case 'm':
205 		flags.modp = 1;
206 		break;
207 	    case 'c':
208 		if (i+1 >= argc) {
209 		    usage_arg(progname, "-c ");
210 		}
211 		flags.cookiep = 1;
212 		flags.cookie = ei_chk_strdup(argv[i+1]);
213 		i++;
214 		break;
215 	    case 'n':
216 		if (i+1 >= argc) {
217 		    usage_arg(progname, "-n ");
218 		}
219 		flags.node = ei_chk_strdup(argv[i+1]);
220 		flags.use_long_name = 1;
221 		i++;
222 		break;
223 	    case 'h':
224 		if (i+1 >= argc) {
225 		    usage_arg(progname, "-h ");
226 		}
227 		flags.hidden = ei_chk_strdup(argv[i+1]);
228 		i++;
229 		break;
230 	    case 'x':
231 		if (i+1 >= argc) {
232 		    usage_arg(progname, "-x ");
233 		}
234 		flags.script = ei_chk_strdup(argv[i+1]);
235 		i++;
236 		break;
237 	    case 'a':
238 		if (i+1 >= argc) {
239 		    usage_arg(progname, "-a ");
240 		}
241 		flags.apply = ei_chk_strdup(argv[i+1]);
242 		i++;
243 		break;
244 	    case '?':
245 		usage(progname);
246 	    default:
247 		usage_error(progname, argv[i]);
248 	    }
249 	}
250 	i++;
251 
252     } /* while */
253 
254 
255     /*
256      * Can't have them both !
257      */
258     if (flags.modp && flags.evalp) {
259       usage(progname);
260     }
261 
262     /*
263      * Read an Erlang module from stdin.
264      */
265     if (flags.modp) {
266       modsize = get_module(&module, &modname);
267     }
268 
269     if (flags.verbosep || flags.debugp) {
270 	fprintf(stderr,"erl_call: "
271 		"node = %s\nCookie = %s\n"
272 		"flags = %s %s %s\n"
273 		"module: name = %s , size = %d\n"
274 		"apply = %s\n",
275 		(flags.node ? flags.node : ""),
276 		(flags.cookie ? flags.cookie : ""),
277 		(flags.startp ? "startp" : ""),
278 		(flags.verbosep ? "verbosep" : ""),
279 		(flags.debugp ? "debugp" : ""),
280 		(modname ? modname : ""), modsize,
281 		(flags.apply ? flags.apply : "" ));
282     }
283 
284     /*
285      * What we, at least, requires !
286      */
287     if (flags.node == NULL) {
288 	usage(progname);
289     }
290 
291     if (!flags.cookiep) {
292 	flags.cookie = NULL;
293     }
294 
295     /* FIXME decide how many bits etc or leave to connect_xinit? */
296     creation = (time(NULL) % 3) + 1; /* "random" */
297 
298     if (flags.hidden == NULL) {
299       /* As default we are c17@gethostname */
300       i = flags.randomp ? (time(NULL) % 997) : 17;
301       flags.hidden = (char *) ei_chk_malloc(10 + 2 ); /* c17 or cXYZ */
302 #if defined(VXWORKS)
303       sprintf(flags.hidden, "c%d",
304 	  i < 0 ?  (int) taskIdSelf() : i);
305 #else
306       sprintf(flags.hidden, "c%d",
307 	  i < 0 ?  (int) getpid() : i);
308 #endif
309     }
310     {
311       /* A name for our hidden node was specified */
312       char h_hostname[EI_MAXHOSTNAMELEN+1];
313       char h_nodename[MAXNODELEN+1];
314       char *h_alivename=flags.hidden;
315       struct in_addr h_ipadr;
316       char* ct;
317 
318       /* gethostname requires len to be max(hostname) + 1 */
319       if (gethostname(h_hostname, EI_MAXHOSTNAMELEN+1) < 0) {
320 	  fprintf(stderr,"erl_call: failed to get host name: %d\n", errno);
321 	  exit(1);
322       }
323       if ((hp = ei_gethostbyname(h_hostname)) == 0) {
324 	  fprintf(stderr,"erl_call: can't resolve hostname %s\n", h_hostname);
325 	  exit(1);
326       }
327       /* If shortnames, cut off the name at first '.' */
328       if (flags.use_long_name == 0 && (ct = strchr(hp->h_name, '.')) != NULL) {
329 	  *ct = '\0';
330       }
331       strncpy(h_hostname, hp->h_name, EI_MAXHOSTNAMELEN);
332       h_hostname[EI_MAXHOSTNAMELEN] = '\0';
333       memcpy(&h_ipadr.s_addr, *hp->h_addr_list, sizeof(struct in_addr));
334       if (strlen(h_alivename) + strlen(h_hostname) + 2 > sizeof(h_nodename)) {
335 	  fprintf(stderr,"erl_call: hostname too long: %s\n", h_hostname);
336 	  exit(1);
337       }
338       sprintf(h_nodename, "%s@%s", h_alivename, h_hostname);
339 
340       if (ei_connect_xinit(&ec, h_hostname, h_alivename, h_nodename,
341 			   (Erl_IpAddr)&h_ipadr, flags.cookie,
342 			   (short) creation) < 0) {
343 	  fprintf(stderr,"erl_call: can't create C node %s; %d\n",
344 		  h_nodename, erl_errno);
345       	  exit(1);
346       }
347 
348     }
349     if ((p = strchr((const char *)flags.node, (int) '@')) == 0) {
350 	strcpy(host_name, ei_thishostname(&ec));
351 	host = host_name;
352     } else {
353 	*p = 0;
354 	host = p+1;
355     }
356 
357     /*
358      * Expand name to a real name (may be ip-address)
359      */
360     /* FIXME better error string */
361     if ((hp = ei_gethostbyname(host)) == 0) {
362 	fprintf(stderr,"erl_call: can't ei_gethostbyname(%s)\n", host);
363 	exit(1);
364     }
365     /* If shortnames, cut off the name at first '.' */
366     if (flags.use_long_name == 0 && (ct = strchr(hp->h_name, '.')) != NULL) {
367 	*ct = '\0';
368     }
369     strncpy(host_name, hp->h_name, EI_MAXHOSTNAMELEN);
370     host_name[EI_MAXHOSTNAMELEN] = '\0';
371     if (strlen(flags.node) + strlen(host_name) + 2 > sizeof(nodename)) {
372 	fprintf(stderr,"erl_call: nodename too long: %s\n", flags.node);
373 	exit(1);
374     }
375     sprintf(nodename, "%s@%s", flags.node, host_name);
376 
377     /*
378      * Try to connect. Start an Erlang system if the
379      * start option is on and no system is running.
380      */
381     if (flags.startp && !flags.haltp) {
382 	fd = do_connect(&ec, nodename, &flags);
383     } else if ((fd = ei_connect(&ec, nodename)) < 0) {
384 	/* We failed to connect ourself */
385 	/* FIXME do we really know we failed because of node not up? */
386 	if (flags.haltp) {
387 	    exit(0);
388 	} else {
389 	    fprintf(stderr,"erl_call: failed to connect to node %s\n",
390 		    nodename);
391 	    exit(1);
392 	}
393     }
394 
395     /* If we are connected and the halt switch is set */
396     if (fd && flags.haltp) {
397 	int i = 0;
398 	char *p;
399 	ei_x_buff reply;
400 
401 	ei_encode_empty_list(NULL, &i);
402 
403 	p = (char *)ei_chk_malloc(i);
404 	i = 0;		/* Reset */
405 
406 	ei_encode_empty_list(p, &i);
407 
408 	ei_x_new_with_version(&reply);
409 
410 	/* FIXME if fails we want to exit != 0 ? */
411 	ei_rpc(&ec, fd, "erlang", "halt", p, i, &reply);
412 	free(p);
413 	ei_x_free(&reply);
414 	exit(0);
415     }
416 
417     if (flags.verbosep) {
418 	fprintf(stderr,"erl_call: we are now connected to node \"%s\"\n",
419 		nodename);
420     }
421 
422     /*
423      * Compile the module read from stdin.
424      */
425     if (flags.modp && (modname != NULL)) {
426       char fname[256];
427 
428       if (strlen(modname) + 4 + 1 > sizeof(fname)) {
429       fprintf(stderr,"erl_call: module name too long: %s\n", modname);
430       exit(1);
431       }
432       strcpy(fname, modname);
433       strcat(fname, ".erl");
434 
435       /*
436        * ei_format("[~s,~w]", fname, erl_mk_binary(module, modsize));
437        */
438 
439       {
440 	  int i = 0;
441 	  char *p;
442 	  ei_x_buff reply;
443 
444 	  ei_encode_list_header(NULL, &i, 2);
445 	  ei_encode_string(NULL, &i, fname);
446 	  ei_encode_binary(NULL, &i, module, modsize);
447 	  ei_encode_empty_list(NULL, &i);
448 
449 	  p = (char *)ei_chk_malloc(i);
450 	  i = 0;		/* Reset */
451 
452 	  ei_encode_list_header(p, &i, 2);
453 	  ei_encode_string(p, &i, fname);
454 	  ei_encode_binary(p, &i, module, modsize);
455 	  ei_encode_empty_list(p, &i);
456 
457 	  ei_x_new_with_version(&reply);
458 
459 	  if (ei_rpc(&ec, fd, "file", "write_file", p, i, &reply) < 0) {
460 	      free(p);
461 	      ei_x_free(&reply);
462 	      fprintf(stderr,"erl_call: can't write to source file %s\n",
463 		      fname);
464 	      exit(1);
465 	  }
466 	  free(p);
467 	  ei_x_free(&reply);
468       }
469 
470       /* Compile AND load file on other node */
471 
472       {
473 	  int i = 0;
474 	  char *p;
475 	  ei_x_buff reply;
476 
477 	  ei_encode_list_header(NULL, &i, 2);
478 	  ei_encode_atom(NULL, &i, fname);
479 	  ei_encode_empty_list(NULL, &i);
480 	  ei_encode_empty_list(NULL, &i);
481 
482 	  p = (char *)ei_chk_malloc(i);
483 	  i = 0;		/* Reset */
484 
485 	  ei_encode_list_header(p, &i, 2);
486 	  ei_encode_atom(p, &i, fname);
487 	  ei_encode_empty_list(p, &i);
488 	  ei_encode_empty_list(p, &i);
489 
490 	  ei_x_new_with_version(&reply);
491 
492 	  /* erl_format("[~a,[]]", modname) */
493 
494 	  if (ei_rpc(&ec, fd, "c", "c", p, i, &reply) < 0) {
495 	      free(p);
496 	      ei_x_free(&reply);
497 	      fprintf(stderr,"erl_call: can't compile file %s\n", fname);
498 	  }
499 	  free(p);
500 	  /* FIXME complete this code
501 	     FIXME print out error message as term
502 	  if (!erl_match(erl_format("{ok,_}"), reply)) {
503 	      fprintf(stderr,"erl_call: compiler errors\n");
504 	  }
505 	  */
506 	  ei_x_free(&reply);
507       }
508 
509     }
510 
511     /*
512      * If we loaded any module source code, we can free the buffer
513      * now. This buffer was allocated in read_stdin().
514      */
515     if (module != NULL) {
516         free(module);
517     }
518 
519     /*
520      * Eval the Erlang functions read from stdin/
521      */
522     if (flags.evalp) {
523       char *evalbuf;
524       int len;
525 
526       len = read_stdin(&evalbuf);
527       {
528 	  int i = 0;
529 	  char *p;
530 	  ei_x_buff reply;
531 
532 	  ei_encode_list_header(NULL, &i, 1);
533 	  ei_encode_binary(NULL, &i, evalbuf, len);
534 	  ei_encode_empty_list(NULL, &i);
535 
536 	  p = (char *)ei_chk_malloc(i);
537 	  i = 0;		/* Reset */
538 
539 	  ei_encode_list_header(p, &i, 1);
540 	  ei_encode_binary(p, &i, evalbuf, len);
541 	  ei_encode_empty_list(p, &i);
542 
543 	  ei_x_new_with_version(&reply);
544 
545 	  /* erl_format("[~w]", erl_mk_binary(evalbuf,len))) */
546 
547 	  if (ei_rpc(&ec, fd, "erl_eval", "eval_str", p, i, &reply) < 0) {
548 	      fprintf(stderr,"erl_call: evaluating input failed: %s\n",
549 		      evalbuf);
550 	      free(p);
551 	      free(evalbuf);	/* Allocated in read_stdin() */
552 	      ei_x_free(&reply);
553 	      exit(1);
554 	  }
555 	  i = 0;
556 	  ei_print_term(stdout,reply.buff,&i);
557 	  free(p);
558 	  free(evalbuf);	/* Allocated in read_stdin() */
559 	  ei_x_free(&reply);
560       }
561     }
562     /*
563      * Any Erlang call to be made ?
564      */
565     if (flags.apply != NULL) {
566       char *mod,*fun,*args;
567       ei_x_buff e, reply;
568 
569       split_apply_string(flags.apply, &mod, &fun, &args);
570       if (flags.verbosep) {
571 	  fprintf(stderr,"erl_call: module = %s, function = %s, args = %s\n",
572 		  mod, fun, args);
573       }
574 
575       ei_x_new(&e);		/* No version to ei_rpc() */
576 
577       if (ei_x_format_wo_ver(&e, args) < 0) {
578 	  /* FIXME no error message and why -1 ? */
579 	  exit(-1);
580       }
581 
582       ei_x_new_with_version(&reply);
583 
584       if (ei_rpc(&ec, fd, mod, fun, e.buff, e.index, &reply) < 0) {
585 	  /* FIXME no error message and why -1 ? */
586 	  ei_x_free(&e);
587 	  ei_x_free(&reply);
588 	  exit(-1);
589       } else {
590 	  int i = 0;
591 	  ei_print_term(stdout,reply.buff,&i);
592 	  ei_x_free(&e);
593 	  ei_x_free(&reply);
594       }
595     }
596 
597     return(0);
598 }
599 
600 
601 /***************************************************************************
602  *
603  *  XXXXX
604  *
605  ***************************************************************************/
606 
607 
608 /*
609  * This function does only return on success.
610  */
do_connect(ei_cnode * ec,char * nodename,struct call_flags * flags)611 static int do_connect(ei_cnode *ec, char *nodename, struct call_flags *flags)
612 {
613     int fd;
614     int start_flags;
615     int r;
616 
617     start_flags = ERL_START_ENODE |
618 	(flags->use_long_name? ERL_START_LONG : 0) |
619 	(flags->verbosep? ERL_START_VERBOSE : 0) |
620 	(flags->debugp? ERL_START_DEBUG : 0);
621 
622     if ((fd = ei_connect(ec, nodename)) >= 0) {
623 	/* success */
624 	if (flags->verbosep) {
625 	    fprintf(stderr,"erl_call: now connected to node %s\n", nodename);
626 	}
627     } else {
628 	char alive[EI_MAXALIVELEN+1];
629 	char *hostname;
630 	struct hostent *h;
631 	char *cookieargs[3];
632 	char **args;
633 
634 	cookieargs[0] = "-setcookie";
635 	cookieargs[1] = flags->cookie;
636 	cookieargs[2] = NULL;
637 
638 	args = (flags->cookie) ? cookieargs : NULL;
639 
640 	if (!(hostname = strrchr(nodename,'@'))) {
641 	    return ERL_BADARG;
642 	}
643 	strncpy(alive,nodename,hostname-nodename);
644 	alive[hostname-nodename] = 0x0;
645 	hostname++;
646 
647 	h = ei_gethostbyname(hostname);
648 
649 
650 	if ((r=erl_start_sys(ec,alive,(Erl_IpAddr)(h->h_addr_list[0]),
651 			     start_flags,flags->script,args)) < 0) {
652 	    fprintf(stderr,"erl_call: unable to start node, error = %d\n", r);
653 	    exit(1);
654 	}
655 
656 	if ((fd=ei_connect(ec, nodename)) >= 0) {
657 	    /* success */
658 	    if (flags->verbosep) {
659 		fprintf(stderr,"erl_call: now connected to node \"%s\"\n",
660 			nodename);
661 	    }
662 	} else {
663 	    /* (failure) */
664 	    switch (fd) {
665 	    case ERL_NO_DAEMON:
666 		fprintf(stderr,"erl_call: no epmd running\n");
667 		exit(1);
668 	    case ERL_CONNECT_FAIL:
669 		fprintf(stderr,"erl_call: connect failed\n");
670 		exit(1);
671 	    case ERL_NO_PORT:
672 		fprintf(stderr,"erl_call: node is not running\n");
673 		exit(1);
674 	    case ERL_TIMEOUT:
675 		fprintf(stderr,"erl_call: connect timed out\n");
676 		exit(1);
677 	    default:
678 		fprintf(stderr,"erl_call: error during connect\n");
679 		exit(1);
680 	    }
681 	}
682     }
683 
684     return fd;
685 } /* do_connect */
686 
687 #define SKIP_SPACE(s) while(isspace((int)*(s))) (s)++
688 #define EAT(s) while (!isspace((int)*(s)) && (*(s) != '\0')) (s)++
689 
split_apply_string(char * str,char ** mod,char ** fun,char ** args)690 static void split_apply_string(char *str,
691 			       char **mod,
692 			       char **fun,
693 			       char **args)
694 {
695   char *begin=str;
696   char *start="start";
697   char *empty_list="[]";
698   int len;
699 
700   SKIP_SPACE(str);
701   if (*str == '\0') {
702       fprintf(stderr,"erl_call: wrong format of apply string (1)\n");
703       exit(1);
704   }
705 
706   EAT(str);
707   len = str-begin;
708   *mod = (char *) ei_chk_calloc(len + 1, sizeof(char));
709   memcpy(*mod, begin, len);
710 
711   SKIP_SPACE(str);
712   if (*str == '\0') {
713     *fun = ei_chk_strdup(start);
714     *args = ei_chk_strdup(empty_list);
715     return;
716   }
717   begin = str;
718   EAT(str);
719   len = str-begin;
720   *fun = (char *) ei_chk_calloc(len + 1, sizeof(char));
721   memcpy(*fun, begin, len);
722 
723   SKIP_SPACE(str);
724   if (*str == '\0') {
725     *args = ei_chk_strdup(empty_list);
726     return;
727   }
728 
729   *args = ei_chk_strdup(str);
730 
731   return;
732 
733 } /* split_apply_string */
734 
735 
736 /*
737  * Read from stdin until EOF is reached.
738  * Allocate the buffer needed.
739  */
read_stdin(char ** buf)740 static int read_stdin(char **buf)
741 {
742     int bsize = BUFSIZ;
743     int len = 0;
744     int i;
745     char *tmp = (char *) ei_chk_malloc(bsize);
746 
747     while (1) {
748 	if ((i = read(0, &tmp[len], bsize-len)) < 0) {
749 	    fprintf(stderr,"erl_call: can't read stdin, errno = %d", errno);
750 	    exit(1);
751 	} else if (i == 0) {
752 	    break;
753 	} else {
754 	    len += i;
755 	    if ((len+50) > bsize) {
756 		bsize = len * 2;
757 		tmp = (char *) ei_chk_realloc(tmp, bsize);
758 	    } else {
759 		continue;
760 	    }
761 	}
762     } /* while */
763     *buf = tmp;
764     return len;
765 
766 } /* read_stdin */
767 
768 /*
769  * Get the module from stdin.
770  */
get_module(char ** mbuf,char ** mname)771 static int get_module(char **mbuf, char **mname)
772 {
773   char *tmp;
774   int len,i;
775 
776   len = read_stdin(mbuf);
777   /*
778    * Now, get the module name.
779    */
780   if ((tmp = strstr(*mbuf, "-module(")) != NULL) {
781     char *start;
782     tmp += strlen("-module(");
783     while ((*tmp) == ' ') tmp++; /* eat space */
784     start = tmp;
785     while (1) {
786       if (isalnum((int)*tmp) || (*tmp == '_')) {
787 	tmp++;
788 	continue;
789       } else {
790 	  break;
791       }
792     } /* while */
793     i = tmp - start;
794     *mname = (char *) ei_chk_calloc(i+1, sizeof(char));
795     memcpy(*mname, start, i);
796   }
797 
798   return len;
799 
800 } /* get_module */
801 
802 
803 /***************************************************************************
804  *
805  *  Different error reporting functions that output usage
806  *
807  ***************************************************************************/
808 
usage_noexit(const char * progname)809 static void usage_noexit(const char *progname) {
810   fprintf(stderr,"\nUsage: %s [-[demqrsv]] [-c Cookie] [-h HiddenName] \n", progname);
811   fprintf(stderr,"            [-x ErlScript] [-a [Mod [Fun [Args]]]]\n");
812   fprintf(stderr,"            (-n Node | -sname Node | -name Node)\n\n");
813 #ifdef __WIN32__
814   fprintf(stderr,"  where: -a  apply(Mod,Fun,Args) (e.g -a \"erlang length [[a,b,c]]\"\n");
815 #else
816   fprintf(stderr,"  where: -a  apply(Mod,Fun,Args) (e.g -a 'erlang length [[a,b,c]]'\n");
817 #endif
818   fprintf(stderr,"         -c  cookie string; by default read from ~/.erlang.cookie\n");
819   fprintf(stderr,"         -d  direct Erlang output to ~/.erl_call.out.<Nodename>\n");
820   fprintf(stderr,"         -e  evaluate contents of standard input (e.g echo \"X=1,Y=2,{X,Y}.\"|erl_call -e ...)\n");
821   fprintf(stderr,"         -h  specify a name for the erl_call client node\n");
822   fprintf(stderr,"         -m  read and compile Erlang module from stdin\n");
823   fprintf(stderr,"         -n  name of Erlang node, same as -name\n");
824   fprintf(stderr,"         -name  name of Erlang node, expanded to a fully qualified\n");
825   fprintf(stderr,"         -sname name of Erlang node, short form will be used\n");
826   fprintf(stderr,"         -q  halt the Erlang node (overrides the -s switch)\n");
827   fprintf(stderr,"         -r  use a random name for the erl_call client node\n");
828   fprintf(stderr,"         -s  start a new Erlang node if necessary\n");
829   fprintf(stderr,"         -v  verbose mode, i.e print some information on stderr\n");
830   fprintf(stderr,"         -x  use specified erl start script, default is erl\n");
831 }
832 
usage_arg(const char * progname,const char * switchname)833 static void usage_arg(const char *progname, const char *switchname) {
834   fprintf(stderr, "Missing argument(s) for \'%s\'.\n", switchname);
835   usage_noexit(progname);
836   exit(1);
837 }
838 
usage_error(const char * progname,const char * switchname)839 static void usage_error(const char *progname, const char *switchname) {
840   fprintf(stderr, "Illegal argument \'%s\'.\n", switchname);
841   usage_noexit(progname);
842   exit(1);
843 }
844 
usage(const char * progname)845 static void usage(const char *progname) {
846   usage_noexit(progname);
847   exit(0);
848 }
849 
850 /***************************************************************************
851  *
852  *  Utility functions
853  *
854  ***************************************************************************/
855 
ei_chk_malloc(size_t size)856 static void* ei_chk_malloc(size_t size)
857 {
858     void *p = malloc(size);
859     if (p == NULL) {
860         fprintf(stderr,"erl_call: insufficient memory\n");
861         exit(1);
862     }
863     return p;
864 }
865 
ei_chk_calloc(size_t nmemb,size_t size)866 static void* ei_chk_calloc(size_t nmemb, size_t size)
867 {
868     void *p = calloc(nmemb, size);
869     if (p == NULL) {
870         fprintf(stderr,"erl_call: insufficient memory\n");
871         exit(1);
872     }
873     return p;
874 }
875 
ei_chk_realloc(void * old,size_t size)876 static void* ei_chk_realloc(void *old, size_t size)
877 {
878     void *p = realloc(old, size);
879     if (!p) {
880         fprintf(stderr, "erl_call: cannot reallocate %u bytes of memory from %p\n",
881                 (unsigned) size, old);
882         exit (1);
883     }
884     return p;
885 }
886 
ei_chk_strdup(char * s)887 static char* ei_chk_strdup(char *s)
888 {
889     char *p = strdup(s);
890     if (p == NULL) {
891         fprintf(stderr,"erl_call: insufficient memory\n");
892         exit(1);
893     }
894     return p;
895 }
896