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