Merge major BSD mutex and symbol conflict patches (bug #1816) (link patch still pending)
[asterisk/asterisk.git] / asterisk.c
1 /*
2  * Asterisk -- A telephony toolkit for Linux.
3  *
4  * Top level source file for asterisk
5  * 
6  * Copyright (C) 1999, Mark Spencer
7  *
8  * Mark Spencer <markster@linux-support.net>
9  *
10  * This program is free software, distributed under the terms of
11  * the GNU General Public License
12  */
13
14 #include <unistd.h>
15 #include <stdlib.h>
16 #include <sys/poll.h>
17 #include <asterisk/logger.h>
18 #include <asterisk/options.h>
19 #include <asterisk/cli.h>
20 #include <asterisk/channel.h>
21 #include <asterisk/ulaw.h>
22 #include <asterisk/alaw.h>
23 #include <asterisk/callerid.h>
24 #include <asterisk/module.h>
25 #include <asterisk/image.h>
26 #include <asterisk/tdd.h>
27 #include <asterisk/term.h>
28 #include <asterisk/manager.h>
29 #include <asterisk/pbx.h>
30 #include <asterisk/enum.h>
31 #include <asterisk/rtp.h>
32 #include <asterisk/app.h>
33 #include <asterisk/lock.h>
34 #include <asterisk/utils.h>
35 #include <sys/resource.h>
36 #include <fcntl.h>
37 #include <stdio.h>
38 #include <signal.h>
39 #include <sched.h>
40 #include <asterisk/io.h>
41 #include <asterisk/lock.h>
42 #include <sys/socket.h>
43 #include <sys/un.h>
44 #include <sys/wait.h>
45 #include <string.h>
46 #include <errno.h>
47 #include <ctype.h>
48 #include "editline/histedit.h"
49 #include "asterisk.h"
50 #include <asterisk/config.h>
51 #include <asterisk/config_pvt.h>
52 #include <sys/resource.h>
53
54 #if  defined(__FreeBSD__)
55 #include <netdb.h>
56 #endif
57
58 #define AST_MAX_CONNECTS 128
59 #define NUM_MSGS 64
60
61 int option_verbose=0;
62 int option_debug=0;
63 int option_nofork=0;
64 int option_quiet=0;
65 int option_console=0;
66 int option_highpriority=0;
67 int option_remote=0;
68 int option_exec=0;
69 int option_initcrypto=0;
70 int option_nocolor;
71 int option_dumpcore = 0;
72 int option_overrideconfig = 0;
73 int fully_booted = 0;
74
75 static int ast_socket = -1;             /* UNIX Socket for allowing remote control */
76 static int ast_consock = -1;            /* UNIX Socket for controlling another asterisk */
77 int ast_mainpid;
78 struct console {
79         int fd;                                 /* File descriptor */
80         int p[2];                               /* Pipe */
81         pthread_t t;                    /* Thread of handler */
82 };
83
84 static struct ast_atexit {
85         void (*func)(void);
86         struct ast_atexit *next;
87 } *atexits = NULL;
88 AST_MUTEX_DEFINE_STATIC(atexitslock);
89
90 time_t ast_startuptime;
91 time_t ast_lastreloadtime;
92
93 static History *el_hist = NULL;
94 static EditLine *el = NULL;
95 static char *remotehostname;
96
97 struct console consoles[AST_MAX_CONNECTS];
98
99 char defaultlanguage[MAX_LANGUAGE] = DEFAULT_LANGUAGE;
100
101 static int ast_el_add_history(char *);
102 static int ast_el_read_history(char *);
103 static int ast_el_write_history(char *);
104
105 char ast_config_AST_CONFIG_DIR[AST_CONFIG_MAX_PATH];
106 char ast_config_AST_CONFIG_FILE[AST_CONFIG_MAX_PATH];
107 char ast_config_AST_MODULE_DIR[AST_CONFIG_MAX_PATH];
108 char ast_config_AST_SPOOL_DIR[AST_CONFIG_MAX_PATH];
109 char ast_config_AST_VAR_DIR[AST_CONFIG_MAX_PATH];
110 char ast_config_AST_LOG_DIR[AST_CONFIG_MAX_PATH];
111 char ast_config_AST_AGI_DIR[AST_CONFIG_MAX_PATH];
112 char ast_config_AST_DB[AST_CONFIG_MAX_PATH];
113 char ast_config_AST_KEY_DIR[AST_CONFIG_MAX_PATH];
114 char ast_config_AST_PID[AST_CONFIG_MAX_PATH];
115 char ast_config_AST_SOCKET[AST_CONFIG_MAX_PATH];
116 char ast_config_AST_RUN_DIR[AST_CONFIG_MAX_PATH];
117
118 static char *_argv[256];
119 static int shuttingdown = 0;
120 static int restartnow = 0;
121 static pthread_t consolethread = AST_PTHREADT_NULL;
122
123 int ast_register_atexit(void (*func)(void))
124 {
125         int res = -1;
126         struct ast_atexit *ae;
127         ast_unregister_atexit(func);
128         ae = malloc(sizeof(struct ast_atexit));
129         ast_mutex_lock(&atexitslock);
130         if (ae) {
131                 memset(ae, 0, sizeof(struct ast_atexit));
132                 ae->next = atexits;
133                 ae->func = func;
134                 atexits = ae;
135                 res = 0;
136         }
137         ast_mutex_unlock(&atexitslock);
138         return res;
139 }
140
141 void ast_unregister_atexit(void (*func)(void))
142 {
143         struct ast_atexit *ae, *prev = NULL;
144         ast_mutex_lock(&atexitslock);
145         ae = atexits;
146         while(ae) {
147                 if (ae->func == func) {
148                         if (prev)
149                                 prev->next = ae->next;
150                         else
151                                 atexits = ae->next;
152                         break;
153                 }
154                 prev = ae;
155                 ae = ae->next;
156         }
157         ast_mutex_unlock(&atexitslock);
158 }
159
160 static int fdprint(int fd, const char *s)
161 {
162         return write(fd, s, strlen(s) + 1);
163 }
164
165 int ast_safe_system(const char *s)
166 {
167         /* XXX This function needs some optimization work XXX */
168         pid_t pid;
169         int x;
170         int res;
171         struct rusage rusage;
172         int status;
173         pid = fork();
174         if (pid == 0) {
175                 /* Close file descriptors and launch system command */
176                 for (x=STDERR_FILENO + 1; x<4096;x++) {
177                         close(x);
178                 }
179                 res = execl("/bin/sh", "/bin/sh", "-c", s, NULL);
180                 exit(1);
181         } else if (pid > 0) {
182                 for(;;) {
183                         res = wait4(pid, &status, 0, &rusage);
184                         if (res > -1) {
185                                 if (WIFEXITED(status))
186                                         res = WEXITSTATUS(status);
187                                 else
188                                         res = -1;
189                                 break;
190                         } else {
191                                 if (errno != EINTR) 
192                                         break;
193                         }
194                 }
195         } else {
196                 ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno));
197                 res = -1;
198         }
199         return res;
200 }
201
202 /*
203  * write the string to all attached console clients
204  */
205 static void ast_network_puts(const char *string)
206 {
207     int x;
208     for (x=0;x<AST_MAX_CONNECTS; x++) {
209         if (consoles[x].fd > -1) 
210             fdprint(consoles[x].p[1], string);
211     }
212 }
213
214
215 /*
216  * write the string to the console, and all attached
217  * console clients
218  */
219 void ast_console_puts(const char *string)
220 {
221     fputs(string, stdout);
222     fflush(stdout);
223     ast_network_puts(string);
224 }
225
226 static void network_verboser(const char *s, int pos, int replace, int complete)
227      /* ARGUSED */
228 {
229     ast_network_puts(s);
230 }
231
232 static pthread_t lthread;
233
234 static void *netconsole(void *vconsole)
235 {
236         struct console *con = vconsole;
237         char hostname[256];
238         char tmp[512];
239         int res;
240         struct pollfd fds[2];
241         
242         if (gethostname(hostname, sizeof(hostname)))
243                 strncpy(hostname, "<Unknown>", sizeof(hostname)-1);
244         snprintf(tmp, sizeof(tmp), "%s/%d/%s\n", hostname, ast_mainpid, ASTERISK_VERSION);
245         fdprint(con->fd, tmp);
246         for(;;) {
247                 fds[0].fd = con->fd;
248                 fds[0].events = POLLIN;
249                 fds[1].fd = con->p[0];
250                 fds[1].events = POLLIN;
251
252                 res = poll(fds, 2, -1);
253                 if (res < 0) {
254                         if (errno != EINTR)
255                                 ast_log(LOG_WARNING, "poll returned < 0: %s\n", strerror(errno));
256                         continue;
257                 }
258                 if (fds[0].revents) {
259                         res = read(con->fd, tmp, sizeof(tmp));
260                         if (res < 1) {
261                                 break;
262                         }
263                         tmp[res] = 0;
264                         ast_cli_command(con->fd, tmp);
265                 }
266                 if (fds[1].revents) {
267                         res = read(con->p[0], tmp, sizeof(tmp));
268                         if (res < 1) {
269                                 ast_log(LOG_ERROR, "read returned %d\n", res);
270                                 break;
271                         }
272                         res = write(con->fd, tmp, res);
273                         if (res < 1)
274                                 break;
275                 }
276         }
277         if (option_verbose > 2) 
278                 ast_verbose(VERBOSE_PREFIX_3 "Remote UNIX connection disconnected\n");
279         close(con->fd);
280         close(con->p[0]);
281         close(con->p[1]);
282         con->fd = -1;
283         
284         return NULL;
285 }
286
287 static void *listener(void *unused)
288 {
289         struct sockaddr_un sun;
290         int s;
291         int len;
292         int x;
293         int flags;
294         struct pollfd fds[1];
295         pthread_attr_t attr;
296         pthread_attr_init(&attr);
297         pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
298         for(;;) {
299                 if (ast_socket < 0)
300                         return NULL;
301                 fds[0].fd = ast_socket;
302                 fds[0].events= POLLIN;
303                 s = poll(fds, 1, -1);
304                 if (s < 0) {
305                         if (errno != EINTR)
306                                 ast_log(LOG_WARNING, "poll returned error: %s\n", strerror(errno));
307                         continue;
308                 }
309                 len = sizeof(sun);
310                 s = accept(ast_socket, (struct sockaddr *)&sun, &len);
311                 if (s < 0) {
312                         if (errno != EINTR)
313                                 ast_log(LOG_WARNING, "Accept returned %d: %s\n", s, strerror(errno));
314                 } else {
315                         for (x=0;x<AST_MAX_CONNECTS;x++) {
316                                 if (consoles[x].fd < 0) {
317                                         if (socketpair(AF_LOCAL, SOCK_STREAM, 0, consoles[x].p)) {
318                                                 ast_log(LOG_ERROR, "Unable to create pipe: %s\n", strerror(errno));
319                                                 consoles[x].fd = -1;
320                                                 fdprint(s, "Server failed to create pipe\n");
321                                                 close(s);
322                                                 break;
323                                         }
324                                         flags = fcntl(consoles[x].p[1], F_GETFL);
325                                         fcntl(consoles[x].p[1], F_SETFL, flags | O_NONBLOCK);
326                                         consoles[x].fd = s;
327                                         if (pthread_create(&consoles[x].t, &attr, netconsole, &consoles[x])) {
328                                                 ast_log(LOG_ERROR, "Unable to spawn thread to handle connection: %s\n", strerror(errno));
329                                                 consoles[x].fd = -1;
330                                                 fdprint(s, "Server failed to spawn thread\n");
331                                                 close(s);
332                                         }
333                                         break;
334                                 }
335                         }
336                         if (x >= AST_MAX_CONNECTS) {
337                                 fdprint(s, "No more connections allowed\n");
338                                 ast_log(LOG_WARNING, "No more connections allowed\n");
339                                 close(s);
340                         } else if (consoles[x].fd > -1) {
341                                 if (option_verbose > 2) 
342                                         ast_verbose(VERBOSE_PREFIX_3 "Remote UNIX connection\n");
343                         }
344                 }
345         }
346         return NULL;
347 }
348
349 static int ast_makesocket(void)
350 {
351         struct sockaddr_un sun;
352         int res;
353         int x;
354         for (x=0;x<AST_MAX_CONNECTS;x++)        
355                 consoles[x].fd = -1;
356         unlink((char *)ast_config_AST_SOCKET);
357         ast_socket = socket(PF_LOCAL, SOCK_STREAM, 0);
358         if (ast_socket < 0) {
359                 ast_log(LOG_WARNING, "Unable to create control socket: %s\n", strerror(errno));
360                 return -1;
361         }               
362         memset(&sun, 0, sizeof(sun));
363         sun.sun_family = AF_LOCAL;
364         strncpy(sun.sun_path, (char *)ast_config_AST_SOCKET, sizeof(sun.sun_path)-1);
365         res = bind(ast_socket, (struct sockaddr *)&sun, sizeof(sun));
366         if (res) {
367                 ast_log(LOG_WARNING, "Unable to bind socket to %s: %s\n", (char *)ast_config_AST_SOCKET, strerror(errno));
368                 close(ast_socket);
369                 ast_socket = -1;
370                 return -1;
371         }
372         res = listen(ast_socket, 2);
373         if (res < 0) {
374                 ast_log(LOG_WARNING, "Unable to listen on socket %s: %s\n", (char *)ast_config_AST_SOCKET, strerror(errno));
375                 close(ast_socket);
376                 ast_socket = -1;
377                 return -1;
378         }
379         ast_register_verbose(network_verboser);
380         pthread_create(&lthread, NULL, listener, NULL);
381         return 0;
382 }
383
384 static int ast_tryconnect(void)
385 {
386         struct sockaddr_un sun;
387         int res;
388         ast_consock = socket(PF_LOCAL, SOCK_STREAM, 0);
389         if (ast_consock < 0) {
390                 ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno));
391                 return 0;
392         }
393         memset(&sun, 0, sizeof(sun));
394         sun.sun_family = AF_LOCAL;
395         strncpy(sun.sun_path, (char *)ast_config_AST_SOCKET, sizeof(sun.sun_path)-1);
396         res = connect(ast_consock, (struct sockaddr *)&sun, sizeof(sun));
397         if (res) {
398                 close(ast_consock);
399                 ast_consock = -1;
400                 return 0;
401         } else
402                 return 1;
403 }
404
405 static void urg_handler(int num)
406 {
407         /* Called by soft_hangup to interrupt the poll, read, or other
408            system call.  We don't actually need to do anything though.  */
409         /* Cannot EVER ast_log from within a signal handler */
410         if (option_debug) 
411                 printf("Urgent handler\n");
412         signal(num, urg_handler);
413         return;
414 }
415
416 static void hup_handler(int num)
417 {
418         if (option_verbose > 1) 
419                 printf("Received HUP signal -- Reloading configs\n");
420         if (restartnow)
421                 execvp(_argv[0], _argv);
422         /* XXX This could deadlock XXX */
423         ast_module_reload();
424 }
425
426 static void child_handler(int sig)
427 {
428         /* Must not ever ast_log or ast_verbose within signal handler */
429         int n, status;
430
431         /*
432          * Reap all dead children -- not just one
433          */
434         for (n = 0; wait4(-1, &status, WNOHANG, NULL) > 0; n++)
435                 ;
436         if (n == 0 && option_debug)     
437                 printf("Huh?  Child handler, but nobody there?\n");
438 }
439
440 static void set_title(char *text)
441 {
442         /* Set an X-term or screen title */
443         if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
444                 fprintf(stdout, "\033]2;%s\007", text);
445 }
446
447 static void set_icon(char *text)
448 {
449         if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
450                 fprintf(stdout, "\033]1;%s\007", text);
451 }
452
453 static int set_priority(int pri)
454 {
455         struct sched_param sched;
456         memset(&sched, 0, sizeof(sched));
457         /* We set ourselves to a high priority, that we might pre-empt everything
458            else.  If your PBX has heavy activity on it, this is a good thing.  */
459 #ifdef __linux__
460         if (pri) {  
461                 sched.sched_priority = 10;
462                 if (sched_setscheduler(0, SCHED_RR, &sched)) {
463                         ast_log(LOG_WARNING, "Unable to set high priority\n");
464                         return -1;
465                 } else
466                         if (option_verbose)
467                                 ast_verbose("Set to realtime thread\n");
468         } else {
469                 sched.sched_priority = 0;
470                 if (sched_setscheduler(0, SCHED_OTHER, &sched)) {
471                         ast_log(LOG_WARNING, "Unable to set normal priority\n");
472                         return -1;
473                 }
474         }
475 #else
476         if (pri) {
477                 if (setpriority(PRIO_PROCESS, 0, -10) == -1) {
478                         ast_log(LOG_WARNING, "Unable to set high priority\n");
479                         return -1;
480                 } else
481                         if (option_verbose)
482                                 ast_verbose("Set to high priority\n");
483         } else {
484                 if (setpriority(PRIO_PROCESS, 0, 0) == -1) {
485                         ast_log(LOG_WARNING, "Unable to set normal priority\n");
486                         return -1;
487                 }
488         }
489 #endif
490         return 0;
491 }
492
493 static void ast_run_atexits(void)
494 {
495         struct ast_atexit *ae;
496         ast_mutex_lock(&atexitslock);
497         ae = atexits;
498         while(ae) {
499                 if (ae->func) 
500                         ae->func();
501                 ae = ae->next;
502         }
503         ast_mutex_unlock(&atexitslock);
504 }
505
506 static void quit_handler(int num, int nice, int safeshutdown, int restart)
507 {
508         char filename[80] = "";
509         time_t s,e;
510         int x;
511         if (safeshutdown) {
512                 shuttingdown = 1;
513                 if (!nice) {
514                         /* Begin shutdown routine, hanging up active channels */
515                         ast_begin_shutdown(1);
516                         if (option_verbose && option_console)
517                                 ast_verbose("Beginning asterisk %s....\n", restart ? "restart" : "shutdown");
518                         time(&s);
519                         for(;;) {
520                                 time(&e);
521                                 /* Wait up to 15 seconds for all channels to go away */
522                                 if ((e - s) > 15)
523                                         break;
524                                 if (!ast_active_channels())
525                                         break;
526                                 if (!shuttingdown)
527                                         break;
528                                 /* Sleep 1/10 of a second */
529                                 usleep(100000);
530                         }
531                 } else {
532                         if (nice < 2)
533                                 ast_begin_shutdown(0);
534                         if (option_verbose && option_console)
535                                 ast_verbose("Waiting for inactivity to perform %s...\n", restart ? "restart" : "halt");
536                         for(;;) {
537                                 if (!ast_active_channels())
538                                         break;
539                                 if (!shuttingdown)
540                                         break;
541                                 sleep(1);
542                         }
543                 }
544
545                 if (!shuttingdown) {
546                         if (option_verbose && option_console)
547                                 ast_verbose("Asterisk %s cancelled.\n", restart ? "restart" : "shutdown");
548                         return;
549                 }
550         }
551         if (option_console || option_remote) {
552                 if (getenv("HOME")) 
553                         snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
554                 if (!ast_strlen_zero(filename))
555                         ast_el_write_history(filename);
556                 if (el != NULL)
557                         el_end(el);
558                 if (el_hist != NULL)
559                         history_end(el_hist);
560         }
561         if (option_verbose)
562                 ast_verbose("Executing last minute cleanups\n");
563         ast_run_atexits();
564         /* Called on exit */
565         if (option_verbose && option_console)
566                 ast_verbose("Asterisk %s ending (%d).\n", ast_active_channels() ? "uncleanly" : "cleanly", num);
567         else if (option_debug)
568                 ast_log(LOG_DEBUG, "Asterisk ending (%d).\n", num);
569         manager_event(EVENT_FLAG_SYSTEM, "Shutdown", "Shutdown: %s\r\nRestart: %s\r\n", ast_active_channels() ? "Uncleanly" : "Cleanly", restart ? "True" : "False");
570         if (ast_socket > -1) {
571                 close(ast_socket);
572                 ast_socket = -1;
573         }
574         if (ast_consock > -1)
575                 close(ast_consock);
576         if (ast_socket > -1)
577                 unlink((char *)ast_config_AST_SOCKET);
578         if (!option_remote) unlink((char *)ast_config_AST_PID);
579         printf(term_quit());
580         if (restart) {
581                 if (option_verbose || option_console)
582                         ast_verbose("Preparing for Asterisk restart...\n");
583                 /* Mark all FD's for closing on exec */
584                 for (x=3;x<32768;x++) {
585                         fcntl(x, F_SETFD, FD_CLOEXEC);
586                 }
587                 if (option_verbose || option_console)
588                         ast_verbose("Restarting Asterisk NOW...\n");
589                 restartnow = 1;
590
591                 /* close logger */
592                 close_logger();
593
594                 /* If there is a consolethread running send it a SIGHUP 
595                    so it can execvp, otherwise we can do it ourselves */
596                 if (consolethread != AST_PTHREADT_NULL) {
597                         pthread_kill(consolethread, SIGHUP);
598                         /* Give the signal handler some time to complete */
599                         sleep(2);
600                 } else
601                         execvp(_argv[0], _argv);
602         
603         } else {
604                 /* close logger */
605                 close_logger();
606         }
607         exit(0);
608 }
609
610 static void __quit_handler(int num)
611 {
612         quit_handler(num, 0, 1, 0);
613 }
614
615 static const char *fix_header(char *outbuf, int maxout, const char *s, char *cmp)
616 {
617         const char *c;
618         if (!strncmp(s, cmp, strlen(cmp))) {
619                 c = s + strlen(cmp);
620                 term_color(outbuf, cmp, COLOR_GRAY, 0, maxout);
621                 return c;
622         }
623         return NULL;
624 }
625
626 static void console_verboser(const char *s, int pos, int replace, int complete)
627 {
628         char tmp[80];
629         const char *c=NULL;
630         /* Return to the beginning of the line */
631         if (!pos) {
632                 fprintf(stdout, "\r");
633                 if ((c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_4)) ||
634                         (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_3)) ||
635                         (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_2)) ||
636                         (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_1)))
637                         fputs(tmp, stdout);
638         }
639         if (c)
640                 fputs(c + pos,stdout);
641         else
642                 fputs(s + pos,stdout);
643         fflush(stdout);
644         if (complete)
645         /* Wake up a poll()ing console */
646                 if (option_console && consolethread != AST_PTHREADT_NULL)
647                         pthread_kill(consolethread, SIGURG);
648 }
649
650 static void consolehandler(char *s)
651 {
652         printf(term_end());
653         fflush(stdout);
654         /* Called when readline data is available */
655         if (s && !ast_strlen_zero(s))
656                 ast_el_add_history(s);
657         /* Give the console access to the shell */
658         if (s) {
659                 /* The real handler for bang */
660                 if (s[0] == '!') {
661                         if (s[1])
662                                 ast_safe_system(s+1);
663                         else
664                                 ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
665                 } else 
666                 ast_cli_command(STDOUT_FILENO, s);
667         } else
668                 fprintf(stdout, "\nUse \"quit\" to exit\n");
669 }
670
671 static int remoteconsolehandler(char *s)
672 {
673         int ret = 0;
674         /* Called when readline data is available */
675         if (s && !ast_strlen_zero(s))
676                 ast_el_add_history(s);
677         /* Give the console access to the shell */
678         if (s) {
679                 /* The real handler for bang */
680                 if (s[0] == '!') {
681                         if (s[1])
682                                 ast_safe_system(s+1);
683                         else
684                                 ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
685                         ret = 1;
686                 }
687                 if ((strncasecmp(s, "quit", 4) == 0 || strncasecmp(s, "exit", 4) == 0) &&
688                     (s[4] == '\0' || isspace(s[4]))) {
689                         quit_handler(0, 0, 0, 0);
690                         ret = 1;
691                 }
692         } else
693                 fprintf(stdout, "\nUse \"quit\" to exit\n");
694
695         return ret;
696 }
697
698 static char quit_help[] = 
699 "Usage: quit\n"
700 "       Exits Asterisk.\n";
701
702 static char abort_halt_help[] = 
703 "Usage: abort shutdown\n"
704 "       Causes Asterisk to abort an executing shutdown or restart, and resume normal\n"
705 "       call operations.\n";
706
707 static char shutdown_now_help[] = 
708 "Usage: stop now\n"
709 "       Shuts down a running Asterisk immediately, hanging up all active calls .\n";
710
711 static char shutdown_gracefully_help[] = 
712 "Usage: stop gracefully\n"
713 "       Causes Asterisk to not accept new calls, and exit when all\n"
714 "       active calls have terminated normally.\n";
715
716 static char shutdown_when_convenient_help[] = 
717 "Usage: stop when convenient\n"
718 "       Causes Asterisk to perform a shutdown when all active calls have ended.\n";
719
720 static char restart_now_help[] = 
721 "Usage: restart now\n"
722 "       Causes Asterisk to hangup all calls and exec() itself performing a cold.\n"
723 "       restart.\n";
724
725 static char restart_gracefully_help[] = 
726 "Usage: restart gracefully\n"
727 "       Causes Asterisk to stop accepting new calls and exec() itself performing a cold.\n"
728 "       restart when all active calls have ended.\n";
729
730 static char restart_when_convenient_help[] = 
731 "Usage: restart when convenient\n"
732 "       Causes Asterisk to perform a cold restart when all active calls have ended.\n";
733
734 static char bang_help[] =
735 "Usage: !<command>\n"
736 "       Executes a given shell command\n";
737
738 #if 0
739 static int handle_quit(int fd, int argc, char *argv[])
740 {
741         if (argc != 1)
742                 return RESULT_SHOWUSAGE;
743         quit_handler(0, 0, 1, 0);
744         return RESULT_SUCCESS;
745 }
746 #endif
747
748 static int no_more_quit(int fd, int argc, char *argv[])
749 {
750         if (argc != 1)
751                 return RESULT_SHOWUSAGE;
752         ast_cli(fd, "The QUIT and EXIT commands may no longer be used to shutdown the PBX.\n"
753                     "Please use STOP NOW instead, if you wish to shutdown the PBX.\n");
754         return RESULT_SUCCESS;
755 }
756
757 static int handle_shutdown_now(int fd, int argc, char *argv[])
758 {
759         if (argc != 2)
760                 return RESULT_SHOWUSAGE;
761         quit_handler(0, 0 /* Not nice */, 1 /* safely */, 0 /* not restart */);
762         return RESULT_SUCCESS;
763 }
764
765 static int handle_shutdown_gracefully(int fd, int argc, char *argv[])
766 {
767         if (argc != 2)
768                 return RESULT_SHOWUSAGE;
769         quit_handler(0, 1 /* nicely */, 1 /* safely */, 0 /* no restart */);
770         return RESULT_SUCCESS;
771 }
772
773 static int handle_shutdown_when_convenient(int fd, int argc, char *argv[])
774 {
775         if (argc != 3)
776                 return RESULT_SHOWUSAGE;
777         quit_handler(0, 2 /* really nicely */, 1 /* safely */, 0 /* don't restart */);
778         return RESULT_SUCCESS;
779 }
780
781 static int handle_restart_now(int fd, int argc, char *argv[])
782 {
783         if (argc != 2)
784                 return RESULT_SHOWUSAGE;
785         quit_handler(0, 0 /* not nicely */, 1 /* safely */, 1 /* restart */);
786         return RESULT_SUCCESS;
787 }
788
789 static int handle_restart_gracefully(int fd, int argc, char *argv[])
790 {
791         if (argc != 2)
792                 return RESULT_SHOWUSAGE;
793         quit_handler(0, 1 /* nicely */, 1 /* safely */, 1 /* restart */);
794         return RESULT_SUCCESS;
795 }
796
797 static int handle_restart_when_convenient(int fd, int argc, char *argv[])
798 {
799         if (argc != 3)
800                 return RESULT_SHOWUSAGE;
801         quit_handler(0, 2 /* really nicely */, 1 /* safely */, 1 /* restart */);
802         return RESULT_SUCCESS;
803 }
804
805 static int handle_abort_halt(int fd, int argc, char *argv[])
806 {
807         if (argc != 2)
808                 return RESULT_SHOWUSAGE;
809         ast_cancel_shutdown();
810         shuttingdown = 0;
811         return RESULT_SUCCESS;
812 }
813
814 static int handle_bang(int fd, int argc, char *argv[])
815 {
816         return RESULT_SUCCESS;
817 }
818
819 #define ASTERISK_PROMPT "*CLI> "
820
821 #define ASTERISK_PROMPT2 "%s*CLI> "
822
823 static struct ast_cli_entry aborthalt = { { "abort", "halt", NULL }, handle_abort_halt, "Cancel a running halt", abort_halt_help };
824
825 static struct ast_cli_entry quit =      { { "quit", NULL }, no_more_quit, "Exit Asterisk", quit_help };
826 static struct ast_cli_entry astexit =   { { "exit", NULL }, no_more_quit, "Exit Asterisk", quit_help };
827
828 static struct ast_cli_entry astshutdownnow =    { { "stop", "now", NULL }, handle_shutdown_now, "Shut down Asterisk immediately", shutdown_now_help };
829 static struct ast_cli_entry astshutdowngracefully =     { { "stop", "gracefully", NULL }, handle_shutdown_gracefully, "Gracefully shut down Asterisk", shutdown_gracefully_help };
830 static struct ast_cli_entry astshutdownwhenconvenient =         { { "stop", "when","convenient", NULL }, handle_shutdown_when_convenient, "Shut down Asterisk at empty call volume", shutdown_when_convenient_help };
831 static struct ast_cli_entry astrestartnow =     { { "restart", "now", NULL }, handle_restart_now, "Restart Asterisk immediately", restart_now_help };
832 static struct ast_cli_entry astrestartgracefully =      { { "restart", "gracefully", NULL }, handle_restart_gracefully, "Restart Asterisk gracefully", restart_gracefully_help };
833 static struct ast_cli_entry astrestartwhenconvenient=   { { "restart", "when", "convenient", NULL }, handle_restart_when_convenient, "Restart Asterisk at empty call volume", restart_when_convenient_help };
834 static struct ast_cli_entry astbang = { { "!", NULL }, handle_bang, "Execute a shell command", bang_help };
835
836 static int ast_el_read_char(EditLine *el, char *cp)
837 {
838     int num_read=0;
839         int lastpos=0;
840         struct pollfd fds[2];
841         int res;
842         int max;
843         char buf[512];
844
845         for (;;) {
846                 max = 1;
847                 fds[0].fd = ast_consock;
848                 fds[0].events = POLLIN;
849                 if (!option_exec) {
850                         fds[1].fd = STDIN_FILENO;
851                         fds[1].events = POLLIN;
852                         max++;
853                 }
854                 res = poll(fds, max, -1);
855                 if (res < 0) {
856                         if (errno == EINTR)
857                                 continue;
858                         ast_log(LOG_ERROR, "poll failed: %s\n", strerror(errno));
859                         break;
860                 }
861
862                 if (!option_exec && fds[1].revents) {
863                         num_read = read(STDIN_FILENO, cp, 1);
864                         if (num_read < 1) {
865                                 break;
866                         } else 
867                                 return (num_read);
868                 }
869                 if (fds[0].revents) {
870                         res = read(ast_consock, buf, sizeof(buf) - 1);
871                         /* if the remote side disappears exit */
872                         if (res < 1) {
873                                 fprintf(stderr, "\nDisconnected from Asterisk server\n");
874                                 quit_handler(0, 0, 0, 0);
875                         }
876
877                         buf[res] = '\0';
878
879                         if (!option_exec && !lastpos)
880                                 write(STDOUT_FILENO, "\r", 1);
881                         write(STDOUT_FILENO, buf, res);
882                         if ((buf[res-1] == '\n') || (buf[res-2] == '\n')) {
883                                 *cp = CC_REFRESH;
884                                 return(1);
885                         } else {
886                                 lastpos = 1;
887                         }
888                 }
889         }
890
891         *cp = '\0';
892         return (0);
893 }
894
895 static char *cli_prompt(EditLine *el)
896 {
897         static char prompt[200];
898         char *pfmt;
899         int color_used=0;
900         char term_code[20];
901
902         if ((pfmt = getenv("ASTERISK_PROMPT"))) {
903                 char *t = pfmt, *p = prompt;
904                 memset(prompt, 0, sizeof(prompt));
905                 while (*t != '\0' && *p < sizeof(prompt)) {
906                         if (*t == '%') {
907                                 char hostname[256];
908                                 int i;
909                                 struct timeval tv;
910                                 struct tm tm;
911 #ifdef linux
912                                 FILE *LOADAVG;
913 #endif
914                                 int fgcolor = COLOR_WHITE, bgcolor = COLOR_BLACK;
915
916                                 t++;
917                                 switch (*t) {
918                                         case 'C': /* color */
919                                                 t++;
920                                                 if (sscanf(t, "%d;%d%n", &fgcolor, &bgcolor, &i) == 2) {
921                                                         strncat(p, term_color_code(term_code, fgcolor, bgcolor, sizeof(term_code)),sizeof(prompt) - strlen(prompt));
922                                                         t += i - 1;
923                                                 } else if (sscanf(t, "%d%n", &fgcolor, &i) == 1) {
924                                                         strncat(p, term_color_code(term_code, fgcolor, 0, sizeof(term_code)),sizeof(prompt) - strlen(prompt));
925                                                         t += i - 1;
926                                                 }
927
928                                                 /* If the color has been reset correctly, then there's no need to reset it later */
929                                                 if ((fgcolor == COLOR_WHITE) && (bgcolor == COLOR_BLACK)) {
930                                                         color_used = 0;
931                                                 } else {
932                                                         color_used = 1;
933                                                 }
934                                                 break;
935                                         case 'd': /* date */
936                                                 memset(&tm, 0, sizeof(struct tm));
937                                                 gettimeofday(&tv, NULL);
938                                                 if (localtime_r(&(tv.tv_sec), &tm)) {
939                                                         strftime(p, sizeof(prompt) - strlen(prompt), "%Y-%m-%d", &tm);
940                                                 }
941                                                 break;
942                                         case 'h': /* hostname */
943                                                 if (!gethostname(hostname, sizeof(hostname) - 1)) {
944                                                         strncat(p, hostname, sizeof(prompt) - strlen(prompt));
945                                                 } else {
946                                                         strncat(p, "localhost", sizeof(prompt) - strlen(prompt));
947                                                 }
948                                                 break;
949                                         case 'H': /* short hostname */
950                                                 if (!gethostname(hostname, sizeof(hostname) - 1)) {
951                                                         for (i=0;i<sizeof(hostname);i++) {
952                                                                 if (hostname[i] == '.') {
953                                                                         hostname[i] = '\0';
954                                                                         break;
955                                                                 }
956                                                         }
957                                                         strncat(p, hostname, sizeof(prompt) - strlen(prompt));
958                                                 } else {
959                                                         strncat(p, "localhost", sizeof(prompt) - strlen(prompt));
960                                                 }
961                                                 break;
962 #ifdef linux
963                                         case 'l': /* load avg */
964                                                 t++;
965                                                 if ((LOADAVG = fopen("/proc/loadavg", "r"))) {
966                                                         float avg1, avg2, avg3;
967                                                         int actproc, totproc, npid, which;
968                                                         fscanf(LOADAVG, "%f %f %f %d/%d %d",
969                                                                 &avg1, &avg2, &avg3, &actproc, &totproc, &npid);
970                                                         if (sscanf(t, "%d", &which) == 1) {
971                                                                 switch (which) {
972                                                                         case 1:
973                                                                                 snprintf(p, sizeof(prompt) - strlen(prompt), "%.2f", avg1);
974                                                                                 break;
975                                                                         case 2:
976                                                                                 snprintf(p, sizeof(prompt) - strlen(prompt), "%.2f", avg2);
977                                                                                 break;
978                                                                         case 3:
979                                                                                 snprintf(p, sizeof(prompt) - strlen(prompt), "%.2f", avg3);
980                                                                                 break;
981                                                                         case 4:
982                                                                                 snprintf(p, sizeof(prompt) - strlen(prompt), "%d/%d", actproc, totproc);
983                                                                                 break;
984                                                                         case 5:
985                                                                                 snprintf(p, sizeof(prompt) - strlen(prompt), "%d", npid);
986                                                                                 break;
987                                                                 }
988                                                         }
989                                                 }
990                                                 break;
991 #endif
992                                         case 't': /* time */
993                                                 memset(&tm, 0, sizeof(struct tm));
994                                                 gettimeofday(&tv, NULL);
995                                                 if (localtime_r(&(tv.tv_sec), &tm)) {
996                                                         strftime(p, sizeof(prompt) - strlen(prompt), "%H:%M:%S", &tm);
997                                                 }
998                                                 break;
999                                         case '#': /* process console or remote? */
1000                                                 if (! option_remote) {
1001                                                         strncat(p, "#", sizeof(prompt) - strlen(prompt));
1002                                                 } else {
1003                                                         strncat(p, ">", sizeof(prompt) - strlen(prompt));
1004                                                 }
1005                                                 break;
1006                                         case '%': /* literal % */
1007                                                 strncat(p, "%", sizeof(prompt) - strlen(prompt));
1008                                                 break;
1009                                         case '\0': /* % is last character - prevent bug */
1010                                                 t--;
1011                                                 break;
1012                                 }
1013                                 while (*p != '\0') {
1014                                         p++;
1015                                 }
1016                                 t++;
1017                         } else {
1018                                 *p = *t;
1019                                 p++;
1020                                 t++;
1021                         }
1022                 }
1023                 if (color_used) {
1024                         /* Force colors back to normal at end */
1025                         term_color_code(term_code, COLOR_WHITE, COLOR_BLACK, sizeof(term_code));
1026                         if (strlen(term_code) > sizeof(prompt) - strlen(prompt)) {
1027                                 strncat(prompt + sizeof(prompt) - strlen(term_code) - 1, term_code, strlen(term_code));
1028                         } else {
1029                                 strncat(p, term_code, sizeof(term_code));
1030                         }
1031                 }
1032         } else if (remotehostname)
1033                 snprintf(prompt, sizeof(prompt), ASTERISK_PROMPT2, remotehostname);
1034         else
1035                 snprintf(prompt, sizeof(prompt), ASTERISK_PROMPT);
1036
1037         return(prompt); 
1038 }
1039
1040 static char **ast_el_strtoarr(char *buf)
1041 {
1042         char **match_list = NULL, *retstr;
1043         size_t match_list_len;
1044         int matches = 0;
1045
1046         match_list_len = 1;
1047         while ( (retstr = strsep(&buf, " ")) != NULL) {
1048
1049                 if (!strcmp(retstr, AST_CLI_COMPLETE_EOF))
1050                         break;
1051                 if (matches + 1 >= match_list_len) {
1052                         match_list_len <<= 1;
1053                         match_list = realloc(match_list, match_list_len * sizeof(char *));
1054                 }
1055
1056                 match_list[matches++] = strdup(retstr);
1057         }
1058
1059         if (!match_list)
1060                 return (char **) NULL;
1061
1062         if (matches>= match_list_len)
1063                 match_list = realloc(match_list, (match_list_len + 1) * sizeof(char *));
1064
1065         match_list[matches] = (char *) NULL;
1066
1067         return match_list;
1068 }
1069
1070 static int ast_el_sort_compare(const void *i1, const void *i2)
1071 {
1072         char *s1, *s2;
1073
1074         s1 = ((char **)i1)[0];
1075         s2 = ((char **)i2)[0];
1076
1077         return strcasecmp(s1, s2);
1078 }
1079
1080 static int ast_cli_display_match_list(char **matches, int len, int max)
1081 {
1082         int i, idx, limit, count;
1083         int screenwidth = 0;
1084         int numoutput = 0, numoutputline = 0;
1085
1086         screenwidth = ast_get_termcols(STDOUT_FILENO);
1087
1088         /* find out how many entries can be put on one line, with two spaces between strings */
1089         limit = screenwidth / (max + 2);
1090         if (limit == 0)
1091                 limit = 1;
1092
1093         /* how many lines of output */
1094         count = len / limit;
1095         if (count * limit < len)
1096                 count++;
1097
1098         idx = 1;
1099
1100         qsort(&matches[0], (size_t)(len + 1), sizeof(char *), ast_el_sort_compare);
1101
1102         for (; count > 0; count--) {
1103                 numoutputline = 0;
1104                 for (i=0; i < limit && matches[idx]; i++, idx++) {
1105
1106                         /* Don't print dupes */
1107                         if ( (matches[idx+1] != NULL && strcmp(matches[idx], matches[idx+1]) == 0 ) ) {
1108                                 i--;
1109                                 continue;
1110                         }
1111
1112                         numoutput++;  numoutputline++;
1113                         fprintf(stdout, "%-*s  ", max, matches[idx]);
1114                 }
1115                 if (numoutputline > 0)
1116                         fprintf(stdout, "\n");
1117         }
1118
1119         return numoutput;
1120 }
1121
1122
1123 static char *cli_complete(EditLine *el, int ch)
1124 {
1125         int len=0;
1126         char *ptr;
1127         int nummatches = 0;
1128         char **matches;
1129         int retval = CC_ERROR;
1130         char buf[2048];
1131         int res;
1132
1133         LineInfo *lf = (LineInfo *)el_line(el);
1134
1135         *(char *)lf->cursor = '\0';
1136         ptr = (char *)lf->cursor;
1137         if (ptr) {
1138                 while (ptr > lf->buffer) {
1139                         if (isspace(*ptr)) {
1140                                 ptr++;
1141                                 break;
1142                         }
1143                         ptr--;
1144                 }
1145         }
1146
1147         len = lf->cursor - ptr;
1148
1149         if (option_remote) {
1150                 snprintf(buf, sizeof(buf),"_COMMAND NUMMATCHES \"%s\" \"%s\"", lf->buffer, ptr); 
1151                 fdprint(ast_consock, buf);
1152                 res = read(ast_consock, buf, sizeof(buf));
1153                 buf[res] = '\0';
1154                 nummatches = atoi(buf);
1155
1156                 if (nummatches > 0) {
1157                         char *mbuf;
1158                         int mlen = 0, maxmbuf = 2048;
1159                         /* Start with a 2048 byte buffer */
1160                         mbuf = malloc(maxmbuf);
1161                         if (!mbuf)
1162                                 return (char *)(CC_ERROR);
1163                         snprintf(buf, sizeof(buf),"_COMMAND MATCHESARRAY \"%s\" \"%s\"", lf->buffer, ptr); 
1164                         fdprint(ast_consock, buf);
1165                         res = 0;
1166                         mbuf[0] = '\0';
1167                         while (!strstr(mbuf, AST_CLI_COMPLETE_EOF) && res != -1) {
1168                                 if (mlen + 1024 > maxmbuf) {
1169                                         /* Every step increment buffer 1024 bytes */
1170                                         maxmbuf += 1024;
1171                                         mbuf = realloc(mbuf, maxmbuf);
1172                                         if (!mbuf)
1173                                                 return (char *)(CC_ERROR);
1174                                 }
1175                                 /* Only read 1024 bytes at a time */
1176                                 res = read(ast_consock, mbuf + mlen, 1024);
1177                                 if (res > 0)
1178                                         mlen += res;
1179                         }
1180                         mbuf[mlen] = '\0';
1181
1182                         matches = ast_el_strtoarr(mbuf);
1183                         free(mbuf);
1184                 } else
1185                         matches = (char **) NULL;
1186
1187
1188         }  else {
1189
1190                 nummatches = ast_cli_generatornummatches((char *)lf->buffer,ptr);
1191                 matches = ast_cli_completion_matches((char *)lf->buffer,ptr);
1192         }
1193
1194         if (matches) {
1195                 int i;
1196                 int matches_num, maxlen, match_len;
1197
1198                 if (matches[0][0] != '\0') {
1199                         el_deletestr(el, (int) len);
1200                         el_insertstr(el, matches[0]);
1201                         retval = CC_REFRESH;
1202                 }
1203
1204                 if (nummatches == 1) {
1205                         /* Found an exact match */
1206                         el_insertstr(el, " ");
1207                         retval = CC_REFRESH;
1208                 } else {
1209                         /* Must be more than one match */
1210                         for (i=1, maxlen=0; matches[i]; i++) {
1211                                 match_len = strlen(matches[i]);
1212                                 if (match_len > maxlen)
1213                                         maxlen = match_len;
1214                         }
1215                         matches_num = i - 1;
1216                         if (matches_num >1) {
1217                                 fprintf(stdout, "\n");
1218                                 ast_cli_display_match_list(matches, nummatches, maxlen);
1219                                 retval = CC_REDISPLAY;
1220                         } else { 
1221                                 el_insertstr(el," ");
1222                                 retval = CC_REFRESH;
1223                         }
1224                 }
1225         free(matches);
1226         }
1227
1228         return (char *)(long)retval;
1229 }
1230
1231 static int ast_el_initialize(void)
1232 {
1233         HistEvent ev;
1234
1235         if (el != NULL)
1236                 el_end(el);
1237         if (el_hist != NULL)
1238                 history_end(el_hist);
1239
1240         el = el_init("asterisk", stdin, stdout, stderr);
1241         el_set(el, EL_PROMPT, cli_prompt);
1242
1243         el_set(el, EL_EDITMODE, 1);             
1244         el_set(el, EL_EDITOR, "emacs");         
1245         el_hist = history_init();
1246         if (!el || !el_hist)
1247                 return -1;
1248
1249         /* setup history with 100 entries */
1250         history(el_hist, &ev, H_SETSIZE, 100);
1251
1252         el_set(el, EL_HIST, history, el_hist);
1253
1254         el_set(el, EL_ADDFN, "ed-complete", "Complete argument", cli_complete);
1255         /* Bind <tab> to command completion */
1256         el_set(el, EL_BIND, "^I", "ed-complete", NULL);
1257         /* Bind ? to command completion */
1258         el_set(el, EL_BIND, "?", "ed-complete", NULL);
1259         /* Bind ^D to redisplay */
1260         el_set(el, EL_BIND, "^D", "ed-redisplay", NULL);
1261
1262         return 0;
1263 }
1264
1265 static int ast_el_add_history(char *buf)
1266 {
1267         HistEvent ev;
1268
1269         if (el_hist == NULL || el == NULL)
1270                 ast_el_initialize();
1271         if (strlen(buf) > 256)
1272                 return 0;
1273         return (history(el_hist, &ev, H_ENTER, buf));
1274 }
1275
1276 static int ast_el_write_history(char *filename)
1277 {
1278         HistEvent ev;
1279
1280         if (el_hist == NULL || el == NULL)
1281                 ast_el_initialize();
1282
1283         return (history(el_hist, &ev, H_SAVE, filename));
1284 }
1285
1286 static int ast_el_read_history(char *filename)
1287 {
1288         char buf[256];
1289         FILE *f;
1290         int ret = -1;
1291
1292         if (el_hist == NULL || el == NULL)
1293                 ast_el_initialize();
1294
1295         if ((f = fopen(filename, "r")) == NULL)
1296                 return ret;
1297
1298         while (!feof(f)) {
1299                 fgets(buf, sizeof(buf), f);
1300                 if (!strcmp(buf, "_HiStOrY_V2_\n"))
1301                         continue;
1302                 if ((ret = ast_el_add_history(buf)) == -1)
1303                         break;
1304         }
1305         fclose(f);
1306
1307         return ret;
1308 }
1309
1310 static void ast_remotecontrol(char * data)
1311 {
1312         char buf[80];
1313         int res;
1314         char filename[80] = "";
1315         char *hostname;
1316         char *cpid;
1317         char *version;
1318         int pid;
1319         char tmp[80];
1320         char *stringp=NULL;
1321
1322         char *ebuf;
1323         int num = 0;
1324
1325         read(ast_consock, buf, sizeof(buf));
1326         if (data)
1327                 write(ast_consock, data, strlen(data) + 1);
1328         stringp=buf;
1329         hostname = strsep(&stringp, "/");
1330         cpid = strsep(&stringp, "/");
1331         version = strsep(&stringp, "\n");
1332         if (!version)
1333                 version = "<Version Unknown>";
1334         stringp=hostname;
1335         strsep(&stringp, ".");
1336         if (cpid)
1337                 pid = atoi(cpid);
1338         else
1339                 pid = -1;
1340         snprintf(tmp, sizeof(tmp), "set verbose atleast %d", option_verbose);
1341         fdprint(ast_consock, tmp);
1342         ast_verbose("Connected to Asterisk %s currently running on %s (pid = %d)\n", version, hostname, pid);
1343         remotehostname = hostname;
1344         if (getenv("HOME")) 
1345                 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
1346         if (el_hist == NULL || el == NULL)
1347                 ast_el_initialize();
1348
1349         el_set(el, EL_GETCFN, ast_el_read_char);
1350
1351         if (!ast_strlen_zero(filename))
1352                 ast_el_read_history(filename);
1353
1354         ast_cli_register(&quit);
1355         ast_cli_register(&astexit);
1356 #if 0
1357         ast_cli_register(&astshutdown);
1358 #endif  
1359         if (option_exec && data) {  /* hack to print output then exit if asterisk -rx is used */
1360                 char tempchar;
1361                 ast_el_read_char(el, &tempchar);
1362                 return;
1363         }
1364         for(;;) {
1365                 ebuf = (char *)el_gets(el, &num);
1366
1367                 if (ebuf && !ast_strlen_zero(ebuf)) {
1368                         if (ebuf[strlen(ebuf)-1] == '\n')
1369                                 ebuf[strlen(ebuf)-1] = '\0';
1370                         if (!remoteconsolehandler(ebuf)) {
1371                                 res = write(ast_consock, ebuf, strlen(ebuf) + 1);
1372                                 if (res < 1) {
1373                                         ast_log(LOG_WARNING, "Unable to write: %s\n", strerror(errno));
1374                                         break;
1375                                 }
1376                         }
1377                 }
1378         }
1379         printf("\nDisconnected from Asterisk server\n");
1380 }
1381
1382 static int show_cli_help(void) {
1383         printf("Asterisk " ASTERISK_VERSION ", Copyright (C) 2000-2004, Digium.\n");
1384         printf("Usage: asterisk [OPTIONS]\n");
1385         printf("Valid Options:\n");
1386         printf("   -C <configfile> Use an alternate configuration file\n");
1387         printf("   -c              Provide console CLI\n");
1388         printf("   -d              Enable extra debugging\n");
1389         printf("   -f              Do not fork\n");
1390         printf("   -g              Dump core in case of a crash\n");
1391         printf("   -h              This help screen\n");
1392         printf("   -i              Initializie crypto keys at startup\n");
1393         printf("   -n              Disable console colorization\n");
1394         printf("   -p              Run as pseudo-realtime thread\n");
1395         printf("   -q              Quiet mode (supress output)\n");
1396         printf("   -r              Connect to Asterisk on this machine\n");
1397         printf("   -v              Increase verbosity (multiple v's = more verbose)\n");
1398         printf("   -x <cmd>        Execute command <cmd> (only valid with -r)\n");
1399         printf("\n");
1400         return 0;
1401 }
1402
1403 static void ast_readconfig(void) {
1404         struct ast_config *cfg;
1405         struct ast_variable *v;
1406         char *config = ASTCONFPATH;
1407
1408         if (option_overrideconfig == 1) {
1409             cfg = ast_load((char *)ast_config_AST_CONFIG_FILE);
1410         } else {
1411             cfg = ast_load(config);
1412         }
1413
1414         /* init with buildtime config */
1415         strncpy((char *)ast_config_AST_CONFIG_DIR,AST_CONFIG_DIR,sizeof(ast_config_AST_CONFIG_DIR)-1);
1416         strncpy((char *)ast_config_AST_SPOOL_DIR,AST_SPOOL_DIR,sizeof(ast_config_AST_SPOOL_DIR)-1);
1417         strncpy((char *)ast_config_AST_MODULE_DIR,AST_MODULE_DIR,sizeof(ast_config_AST_VAR_DIR)-1);
1418         strncpy((char *)ast_config_AST_VAR_DIR,AST_VAR_DIR,sizeof(ast_config_AST_VAR_DIR)-1);
1419         strncpy((char *)ast_config_AST_LOG_DIR,AST_LOG_DIR,sizeof(ast_config_AST_LOG_DIR)-1);
1420         strncpy((char *)ast_config_AST_AGI_DIR,AST_AGI_DIR,sizeof(ast_config_AST_AGI_DIR)-1);
1421         strncpy((char *)ast_config_AST_DB,AST_DB,sizeof(ast_config_AST_DB)-1);
1422         strncpy((char *)ast_config_AST_KEY_DIR,AST_KEY_DIR,sizeof(ast_config_AST_KEY_DIR)-1);
1423         strncpy((char *)ast_config_AST_PID,AST_PID,sizeof(ast_config_AST_PID)-1);
1424         strncpy((char *)ast_config_AST_SOCKET,AST_SOCKET,sizeof(ast_config_AST_SOCKET)-1);
1425         strncpy((char *)ast_config_AST_RUN_DIR,AST_RUN_DIR,sizeof(ast_config_AST_RUN_DIR)-1);
1426         
1427         /* no asterisk.conf? no problem, use buildtime config! */
1428         if (!cfg) {
1429             return;
1430         }
1431         v = ast_variable_browse(cfg, "directories");
1432         while(v) {
1433                 if (!strcasecmp(v->name, "astetcdir")) {
1434                     strncpy((char *)ast_config_AST_CONFIG_DIR,v->value,sizeof(ast_config_AST_CONFIG_DIR)-1);
1435                 } else if (!strcasecmp(v->name, "astspooldir")) {
1436                     strncpy((char *)ast_config_AST_SPOOL_DIR,v->value,sizeof(ast_config_AST_SPOOL_DIR)-1);
1437                 } else if (!strcasecmp(v->name, "astvarlibdir")) {
1438                     strncpy((char *)ast_config_AST_VAR_DIR,v->value,sizeof(ast_config_AST_VAR_DIR)-1);
1439                     snprintf((char *)ast_config_AST_DB,sizeof(ast_config_AST_DB)-1,"%s/%s",v->value,"astdb");    
1440                 } else if (!strcasecmp(v->name, "astlogdir")) {
1441                     strncpy((char *)ast_config_AST_LOG_DIR,v->value,sizeof(ast_config_AST_LOG_DIR)-1);
1442                 } else if (!strcasecmp(v->name, "astagidir")) {
1443                     strncpy((char *)ast_config_AST_AGI_DIR,v->value,sizeof(ast_config_AST_AGI_DIR)-1);
1444                 } else if (!strcasecmp(v->name, "astrundir")) {
1445                     snprintf((char *)ast_config_AST_PID,sizeof(ast_config_AST_PID)-1,"%s/%s",v->value,"asterisk.pid");    
1446                     snprintf((char *)ast_config_AST_SOCKET,sizeof(ast_config_AST_SOCKET)-1,"%s/%s",v->value,"asterisk.ctl");    
1447                     strncpy((char *)ast_config_AST_RUN_DIR,v->value,sizeof(ast_config_AST_RUN_DIR)-1);
1448                 } else if (!strcasecmp(v->name, "astmoddir")) {
1449                     strncpy((char *)ast_config_AST_MODULE_DIR,v->value,sizeof(ast_config_AST_MODULE_DIR)-1);
1450                 }
1451                 v = v->next;
1452         }
1453         ast_destroy(cfg);
1454 }
1455
1456 int main(int argc, char *argv[])
1457 {
1458         int c;
1459         char filename[80] = "";
1460         char hostname[256];
1461         char tmp[80];
1462         char * xarg = NULL;
1463         int x;
1464         FILE *f;
1465         sigset_t sigs;
1466         int num;
1467         char *buf;
1468
1469         /* Remember original args for restart */
1470         if (argc > sizeof(_argv) / sizeof(_argv[0]) - 1) {
1471                 fprintf(stderr, "Truncating argument size to %d\n", (int)(sizeof(_argv) / sizeof(_argv[0])) - 1);
1472                 argc = sizeof(_argv) / sizeof(_argv[0]) - 1;
1473         }
1474         for (x=0;x<argc;x++)
1475                 _argv[x] = argv[x];
1476         _argv[x] = NULL;
1477
1478         /* if the progname is rasterisk consider it a remote console */
1479         if ( argv[0] && (strstr(argv[0], "rasterisk")) != NULL)  {
1480                 option_remote++;
1481                 option_nofork++;
1482         }
1483         if (gethostname(hostname, sizeof(hostname)))
1484                 strncpy(hostname, "<Unknown>", sizeof(hostname)-1);
1485         ast_mainpid = getpid();
1486         ast_ulaw_init();
1487         ast_alaw_init();
1488         callerid_init();
1489         tdd_init();
1490         if (getenv("HOME")) 
1491                 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
1492         /* Check if we're root */
1493         /*
1494         if (geteuid()) {
1495                 ast_log(LOG_ERROR, "Must be run as root\n");
1496                 exit(1);
1497         }
1498         */
1499         /* Check for options */
1500         while((c=getopt(argc, argv, "hfdvqprgcinx:C:")) != -1) {
1501                 switch(c) {
1502                 case 'd':
1503                         option_debug++;
1504                         option_nofork++;
1505                         break;
1506                 case 'c':
1507                         option_console++;
1508                         option_nofork++;
1509                         break;
1510                 case 'f':
1511                         option_nofork++;
1512                         break;
1513                 case 'n':
1514                         option_nocolor++;
1515                         break;
1516                 case 'r':
1517                         option_remote++;
1518                         option_nofork++;
1519                         break;
1520                 case 'p':
1521                         option_highpriority++;
1522                         break;
1523                 case 'v':
1524                         option_verbose++;
1525                         option_nofork++;
1526                         break;
1527                 case 'q':
1528                         option_quiet++;
1529                         break;
1530                 case 'x':
1531                         option_exec++;
1532                         xarg = optarg;
1533                         break;
1534                 case 'C':
1535                         strncpy((char *)ast_config_AST_CONFIG_FILE,optarg,sizeof(ast_config_AST_CONFIG_FILE));
1536                         option_overrideconfig++;
1537                         break;
1538                 case 'i':
1539                         option_initcrypto++;
1540                         break;
1541                 case'g':
1542                         option_dumpcore++;
1543                         break;
1544                 case 'h':
1545                         show_cli_help();
1546                         exit(0);
1547                 case '?':
1548                         exit(1);
1549                 }
1550         }
1551
1552         if (option_dumpcore) {
1553                 struct rlimit l;
1554                 memset(&l, 0, sizeof(l));
1555                 l.rlim_cur = RLIM_INFINITY;
1556                 l.rlim_max = RLIM_INFINITY;
1557                 if (setrlimit(RLIMIT_CORE, &l)) {
1558                         ast_log(LOG_WARNING, "Unable to disable core size resource limit: %s\n", strerror(errno));
1559                 }
1560         }
1561
1562         term_init();
1563         printf(term_end());
1564         fflush(stdout);
1565
1566         /* Test recursive mutex locking. */
1567         if(test_for_thread_safety())
1568                 ast_verbose("Warning! Asterisk is not thread safe.\n");
1569
1570         if (option_console && !option_verbose) 
1571                 ast_verbose("[ Reading Master Configuration ]");
1572         ast_readconfig();
1573
1574         if (option_console && !option_verbose) 
1575                 ast_verbose("[ Initializing Custom Configuration Options]");
1576         /* custom config setup */
1577         register_config_cli();
1578         read_ast_cust_config();
1579         
1580
1581         if (option_console) {
1582                 if (el_hist == NULL || el == NULL)
1583                         ast_el_initialize();
1584
1585                 if (!ast_strlen_zero(filename))
1586                         ast_el_read_history(filename);
1587         }
1588
1589         if (ast_tryconnect()) {
1590                 /* One is already running */
1591                 if (option_remote) {
1592                         if (option_exec) {
1593                                 ast_remotecontrol(xarg);
1594                                 quit_handler(0, 0, 0, 0);
1595                                 exit(0);
1596                         }
1597                         printf(term_quit());
1598                         ast_register_verbose(console_verboser);
1599                         ast_verbose( "Asterisk " ASTERISK_VERSION ", Copyright (C) 1999-2004 Digium.\n");
1600                         ast_verbose( "Written by Mark Spencer <markster@digium.com>\n");
1601                         ast_verbose( "=========================================================================\n");
1602                         ast_remotecontrol(NULL);
1603                         quit_handler(0, 0, 0, 0);
1604                         exit(0);
1605                 } else {
1606                         ast_log(LOG_ERROR, "Asterisk already running on %s.  Use 'asterisk -r' to connect.\n", (char *)ast_config_AST_SOCKET);
1607                         printf(term_quit());
1608                         exit(1);
1609                 }
1610         } else if (option_remote || option_exec) {
1611                 ast_log(LOG_ERROR, "Unable to connect to remote asterisk\n");
1612                 printf(term_quit());
1613                 exit(1);
1614         }
1615         /* Blindly write pid file since we couldn't connect */
1616         unlink((char *)ast_config_AST_PID);
1617         f = fopen((char *)ast_config_AST_PID, "w");
1618         if (f) {
1619                 fprintf(f, "%d\n", getpid());
1620                 fclose(f);
1621         } else
1622                 ast_log(LOG_WARNING, "Unable to open pid file '%s': %s\n", (char *)ast_config_AST_PID, strerror(errno));
1623
1624         if (!option_verbose && !option_debug && !option_nofork && !option_console) {
1625                 daemon(0,0);
1626                 /* Blindly re-write pid file since we are forking */
1627                 unlink((char *)ast_config_AST_PID);
1628                 f = fopen((char *)ast_config_AST_PID, "w");
1629                 if (f) {
1630                         fprintf(f, "%d\n", getpid());
1631                         fclose(f);
1632                 } else
1633                         ast_log(LOG_WARNING, "Unable to open pid file '%s': %s\n", (char *)ast_config_AST_PID, strerror(errno));
1634         }
1635
1636         ast_makesocket();
1637         sigemptyset(&sigs);
1638         sigaddset(&sigs, SIGHUP);
1639         sigaddset(&sigs, SIGTERM);
1640         sigaddset(&sigs, SIGINT);
1641         sigaddset(&sigs, SIGPIPE);
1642         sigaddset(&sigs, SIGWINCH);
1643         pthread_sigmask(SIG_BLOCK, &sigs, NULL);
1644         if (option_console || option_verbose || option_remote)
1645                 ast_register_verbose(console_verboser);
1646         /* Print a welcome message if desired */
1647         if (option_verbose || option_console) {
1648                 ast_verbose( "Asterisk " ASTERISK_VERSION ", Copyright (C) 1999-2004 Digium.\n");
1649                 ast_verbose( "Written by Mark Spencer <markster@digium.com>\n");
1650                 ast_verbose( "=========================================================================\n");
1651         }
1652         if (option_console && !option_verbose) 
1653                 ast_verbose("[ Booting...");
1654
1655         signal(SIGURG, urg_handler);
1656         signal(SIGINT, __quit_handler);
1657         signal(SIGTERM, __quit_handler);
1658         signal(SIGHUP, hup_handler);
1659         signal(SIGCHLD, child_handler);
1660         signal(SIGPIPE, SIG_IGN);
1661
1662         if (set_priority(option_highpriority)) {
1663                 printf(term_quit());
1664                 exit(1);
1665         }
1666         if (init_logger()) {
1667                 printf(term_quit());
1668                 exit(1);
1669         }
1670         if (init_manager()) {
1671                 printf(term_quit());
1672                 exit(1);
1673         }
1674         ast_rtp_init();
1675         if (ast_image_init()) {
1676                 printf(term_quit());
1677                 exit(1);
1678         }
1679         if (load_pbx()) {
1680                 printf(term_quit());
1681                 exit(1);
1682         }
1683         if (load_modules()) {
1684                 printf(term_quit());
1685                 exit(1);
1686         }
1687         if (init_framer()) {
1688                 printf(term_quit());
1689                 exit(1);
1690         }
1691         if (astdb_init()) {
1692                 printf(term_quit());
1693                 exit(1);
1694         }
1695         if (ast_enum_init()) {
1696                 printf(term_quit());
1697                 exit(1);
1698         }
1699         /* reload logger in case a custom config handler binded to logger.conf*/
1700         reload_logger(0);
1701
1702         /* We might have the option of showing a console, but for now just
1703            do nothing... */
1704         if (option_console && !option_verbose)
1705                 ast_verbose(" ]\n");
1706         if (option_verbose || option_console)
1707                 ast_verbose(term_color(tmp, "Asterisk Ready.\n", COLOR_BRWHITE, COLOR_BLACK, sizeof(tmp)));
1708         if (option_nofork)
1709                 consolethread = pthread_self();
1710         fully_booted = 1;
1711         pthread_sigmask(SIG_UNBLOCK, &sigs, NULL);
1712 #ifdef __AST_DEBUG_MALLOC
1713         __ast_mm_init();
1714 #endif  
1715         time(&ast_startuptime);
1716         ast_cli_register(&astshutdownnow);
1717         ast_cli_register(&astshutdowngracefully);
1718         ast_cli_register(&astrestartnow);
1719         ast_cli_register(&astrestartgracefully);
1720         ast_cli_register(&astrestartwhenconvenient);
1721         ast_cli_register(&astshutdownwhenconvenient);
1722         ast_cli_register(&aborthalt);
1723         ast_cli_register(&astbang);
1724         if (option_console) {
1725                 /* Console stuff now... */
1726                 /* Register our quit function */
1727                 char title[256];
1728                 set_icon("Asterisk");
1729                 snprintf(title, sizeof(title), "Asterisk Console on '%s' (pid %d)", hostname, ast_mainpid);
1730                 set_title(title);
1731             ast_cli_register(&quit);
1732             ast_cli_register(&astexit);
1733
1734                 for (;;) {
1735                         buf = (char *)el_gets(el, &num);
1736                         if (buf) {
1737                                 if (buf[strlen(buf)-1] == '\n')
1738                                         buf[strlen(buf)-1] = '\0';
1739
1740                                 consolehandler((char *)buf);
1741                         } else {
1742                                 if (option_remote)
1743                                         ast_cli(STDOUT_FILENO, "\nUse EXIT or QUIT to exit the asterisk console\n");
1744                         }
1745                 }
1746
1747         } else {
1748                 /* Do nothing */
1749                 for(;;) 
1750                         poll(NULL,0, -1);
1751         }
1752         return 0;
1753 }