98af3cc91913807568f1c6bddb3b2aed3c42a394
[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 <asterisk/logger.h>
17 #include <asterisk/options.h>
18 #include <asterisk/cli.h>
19 #include <asterisk/channel.h>
20 #include <asterisk/ulaw.h>
21 #include <asterisk/alaw.h>
22 #include <asterisk/callerid.h>
23 #include <asterisk/module.h>
24 #include <asterisk/image.h>
25 #include <asterisk/tdd.h>
26 #include <asterisk/term.h>
27 #include <asterisk/manager.h>
28 #include <asterisk/pbx.h>
29 #include <asterisk/enum.h>
30 #include <asterisk/rtp.h>
31 #include <sys/resource.h>
32 #include <fcntl.h>
33 #include <stdio.h>
34 #include <signal.h>
35 #include <sched.h>
36 #include <asterisk/io.h>
37 #include <pthread.h>
38 #include <sys/socket.h>
39 #include <sys/un.h>
40 #include <sys/select.h>
41 #include <string.h>
42 #include <errno.h>
43 #include <ctype.h>
44 #include "editline/histedit.h"
45 #include "asterisk.h"
46 #include <asterisk/config.h>
47
48 #define AST_MAX_CONNECTS 128
49 #define NUM_MSGS 64
50
51 int option_verbose=0;
52 int option_debug=0;
53 int option_nofork=0;
54 int option_quiet=0;
55 int option_console=0;
56 int option_highpriority=0;
57 int option_remote=0;
58 int option_exec=0;
59 int option_initcrypto=0;
60 int option_nocolor;
61 int option_dumpcore = 0;
62 int option_overrideconfig = 0;
63 int fully_booted = 0;
64
65 static int ast_socket = -1;             /* UNIX Socket for allowing remote control */
66 static int ast_consock = -1;            /* UNIX Socket for controlling another asterisk */
67 static int mainpid;
68 struct console {
69         int fd;                                 /* File descriptor */
70         int p[2];                               /* Pipe */
71         pthread_t t;                    /* Thread of handler */
72 };
73
74 time_t ast_startuptime;
75 time_t ast_lastreloadtime;
76
77 static History *el_hist = NULL;
78 static EditLine *el = NULL;
79 static char *remotehostname;
80
81 struct console consoles[AST_MAX_CONNECTS];
82
83 char defaultlanguage[MAX_LANGUAGE] = DEFAULT_LANGUAGE;
84
85 static int ast_el_add_history(char *);
86 static int ast_el_read_history(char *);
87 static int ast_el_write_history(char *);
88
89 char ast_config_AST_CONFIG_DIR[AST_CONFIG_MAX_PATH];
90 char ast_config_AST_CONFIG_FILE[AST_CONFIG_MAX_PATH];
91 char ast_config_AST_MODULE_DIR[AST_CONFIG_MAX_PATH];
92 char ast_config_AST_SPOOL_DIR[AST_CONFIG_MAX_PATH];
93 char ast_config_AST_VAR_DIR[AST_CONFIG_MAX_PATH];
94 char ast_config_AST_LOG_DIR[AST_CONFIG_MAX_PATH];
95 char ast_config_AST_AGI_DIR[AST_CONFIG_MAX_PATH];
96 char ast_config_AST_DB[AST_CONFIG_MAX_PATH];
97 char ast_config_AST_KEY_DIR[AST_CONFIG_MAX_PATH];
98 char ast_config_AST_PID[AST_CONFIG_MAX_PATH];
99 char ast_config_AST_SOCKET[AST_CONFIG_MAX_PATH];
100 char ast_config_AST_RUN_DIR[AST_CONFIG_MAX_PATH];
101
102 static int fdprint(int fd, const char *s)
103 {
104         return write(fd, s, strlen(s) + 1);
105 }
106
107 static void network_verboser(const char *s, int pos, int replace, int complete)
108 {
109         int x;
110         for (x=0;x<AST_MAX_CONNECTS; x++) {
111                 if (consoles[x].fd > -1) 
112                         fdprint(consoles[x].p[1], s);
113         }
114 }
115
116 static pthread_t lthread;
117
118 static void *netconsole(void *vconsole)
119 {
120         struct console *con = vconsole;
121         char hostname[256];
122         char tmp[512];
123         int res;
124         int max;
125         fd_set rfds;
126         
127         if (gethostname(hostname, sizeof(hostname)))
128                 strncpy(hostname, "<Unknown>", sizeof(hostname)-1);
129         snprintf(tmp, sizeof(tmp), "%s/%d/%s\n", hostname, mainpid, ASTERISK_VERSION);
130         fdprint(con->fd, tmp);
131         for(;;) {
132                 FD_ZERO(&rfds); 
133                 FD_SET(con->fd, &rfds);
134                 FD_SET(con->p[0], &rfds);
135                 max = con->fd;
136                 if (con->p[0] > max)
137                         max = con->p[0];
138                 res = ast_select(max + 1, &rfds, NULL, NULL, NULL);
139                 if (res < 0) {
140                         ast_log(LOG_WARNING, "select returned < 0: %s\n", strerror(errno));
141                         continue;
142                 }
143                 if (FD_ISSET(con->fd, &rfds)) {
144                         res = read(con->fd, tmp, sizeof(tmp));
145                         if (res < 1) {
146                                 break;
147                         }
148                         tmp[res] = 0;
149                         ast_cli_command(con->fd, tmp);
150                 }
151                 if (FD_ISSET(con->p[0], &rfds)) {
152                         res = read(con->p[0], tmp, sizeof(tmp));
153                         if (res < 1) {
154                                 ast_log(LOG_ERROR, "read returned %d\n", res);
155                                 break;
156                         }
157                         res = write(con->fd, tmp, res);
158                         if (res < 1)
159                                 break;
160                 }
161         }
162         if (option_verbose > 2) 
163                 ast_verbose(VERBOSE_PREFIX_3 "Remote UNIX connection disconnected\n");
164         close(con->fd);
165         close(con->p[0]);
166         close(con->p[1]);
167         con->fd = -1;
168         
169         return NULL;
170 }
171
172 static void *listener(void *unused)
173 {
174         struct sockaddr_un sun;
175         int s;
176         int len;
177         int x;
178         int flags;
179         pthread_attr_t attr;
180         pthread_attr_init(&attr);
181         pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
182         for(;;) {
183                 if (ast_socket < 0)
184                         return NULL;
185                 len = sizeof(sun);
186                 s = accept(ast_socket, (struct sockaddr *)&sun, &len);
187                 if (s < 0) {
188                         ast_log(LOG_WARNING, "Accept retured %d: %s\n", s, strerror(errno));
189                 } else {
190                         for (x=0;x<AST_MAX_CONNECTS;x++) {
191                                 if (consoles[x].fd < 0) {
192                                         if (socketpair(AF_LOCAL, SOCK_STREAM, 0, consoles[x].p)) {
193                                                 ast_log(LOG_ERROR, "Unable to create pipe: %s\n", strerror(errno));
194                                                 consoles[x].fd = -1;
195                                                 fdprint(s, "Server failed to create pipe\n");
196                                                 close(s);
197                                                 break;
198                                         }
199                                         flags = fcntl(consoles[x].p[1], F_GETFL);
200                                         fcntl(consoles[x].p[1], F_SETFL, flags | O_NONBLOCK);
201                                         consoles[x].fd = s;
202                                         if (pthread_create(&consoles[x].t, &attr, netconsole, &consoles[x])) {
203                                                 ast_log(LOG_ERROR, "Unable to spawn thread to handle connection\n");
204                                                 consoles[x].fd = -1;
205                                                 fdprint(s, "Server failed to spawn thread\n");
206                                                 close(s);
207                                         }
208                                         break;
209                                 }
210                         }
211                         if (x >= AST_MAX_CONNECTS) {
212                                 fdprint(s, "No more connections allowed\n");
213                                 ast_log(LOG_WARNING, "No more connections allowed\n");
214                                 close(s);
215                         } else if (consoles[x].fd > -1) {
216                                 if (option_verbose > 2) 
217                                         ast_verbose(VERBOSE_PREFIX_3 "Remote UNIX connection\n");
218                         }
219                 }
220         }
221         return NULL;
222 }
223
224 static int ast_makesocket(void)
225 {
226         struct sockaddr_un sun;
227         int res;
228         int x;
229         for (x=0;x<AST_MAX_CONNECTS;x++)        
230                 consoles[x].fd = -1;
231         unlink((char *)ast_config_AST_SOCKET);
232         ast_socket = socket(PF_LOCAL, SOCK_STREAM, 0);
233         if (ast_socket < 0) {
234                 ast_log(LOG_WARNING, "Unable to create control socket: %s\n", strerror(errno));
235                 return -1;
236         }               
237         memset(&sun, 0, sizeof(sun));
238         sun.sun_family = AF_LOCAL;
239         strncpy(sun.sun_path, (char *)ast_config_AST_SOCKET, sizeof(sun.sun_path)-1);
240         res = bind(ast_socket, (struct sockaddr *)&sun, sizeof(sun));
241         if (res) {
242                 ast_log(LOG_WARNING, "Unable to bind socket to %s: %s\n", (char *)ast_config_AST_SOCKET, strerror(errno));
243                 close(ast_socket);
244                 ast_socket = -1;
245                 return -1;
246         }
247         res = listen(ast_socket, 2);
248         if (res < 0) {
249                 ast_log(LOG_WARNING, "Unable to listen on socket %s: %s\n", (char *)ast_config_AST_SOCKET, strerror(errno));
250                 close(ast_socket);
251                 ast_socket = -1;
252                 return -1;
253         }
254         ast_register_verbose(network_verboser);
255         pthread_create(&lthread, NULL, listener, NULL);
256         return 0;
257 }
258
259 static int ast_tryconnect(void)
260 {
261         struct sockaddr_un sun;
262         int res;
263         ast_consock = socket(PF_LOCAL, SOCK_STREAM, 0);
264         if (ast_consock < 0) {
265                 ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno));
266                 return 0;
267         }
268         memset(&sun, 0, sizeof(sun));
269         sun.sun_family = AF_LOCAL;
270         strncpy(sun.sun_path, (char *)ast_config_AST_SOCKET, sizeof(sun.sun_path)-1);
271         res = connect(ast_consock, (struct sockaddr *)&sun, sizeof(sun));
272         if (res) {
273                 close(ast_consock);
274                 ast_consock = -1;
275                 return 0;
276         } else
277                 return 1;
278 }
279
280 static void urg_handler(int num)
281 {
282         /* Called by soft_hangup to interrupt the select, read, or other
283            system call.  We don't actually need to do anything though.  */
284         if (option_debug) 
285                 ast_log(LOG_DEBUG, "Urgent handler\n");
286         signal(num, urg_handler);
287         return;
288 }
289
290 static void hup_handler(int num)
291 {
292         if (option_verbose > 1) 
293                 ast_verbose(VERBOSE_PREFIX_2 "Received HUP signal -- Reloading configs\n");
294         ast_module_reload();
295 }
296
297
298 static void pipe_handler(int num)
299 {
300         /* Ignore sigpipe */
301 }
302 static void set_title(char *text)
303 {
304         /* Set an X-term or screen title */
305         if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
306                 fprintf(stdout, "\033]2;%s\007", text);
307 }
308
309 static void set_icon(char *text)
310 {
311         if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
312                 fprintf(stdout, "\033]1;%s\007", text);
313 }
314
315 static int set_priority(int pri)
316 {
317         struct sched_param sched;
318         memset(&sched, 0, sizeof(sched));
319         /* We set ourselves to a high priority, that we might pre-empt everything
320            else.  If your PBX has heavy activity on it, this is a good thing.  */
321 #ifdef __linux__
322         if (pri) {  
323                 sched.sched_priority = 10;
324                 if (sched_setscheduler(0, SCHED_RR, &sched)) {
325                         ast_log(LOG_WARNING, "Unable to set high priority\n");
326                         return -1;
327                 } else
328                         if (option_verbose)
329                                 ast_verbose("Set to realtime thread\n");
330         } else {
331                 sched.sched_priority = 0;
332                 if (sched_setscheduler(0, SCHED_OTHER, &sched)) {
333                         ast_log(LOG_WARNING, "Unable to set normal priority\n");
334                         return -1;
335                 }
336         }
337 #else
338         if (pri) {
339                 if (setpriority(PRIO_PROCESS, 0, -10) == -1) {
340                         ast_log(LOG_WARNING, "Unable to set high priority\n");
341                         return -1;
342                 } else
343                         if (option_verbose)
344                                 ast_verbose("Set to high priority\n");
345         } else {
346                 if (setpriority(PRIO_PROCESS, 0, 0) == -1) {
347                         ast_log(LOG_WARNING, "Unable to set normal priority\n");
348                         return -1;
349                 }
350         }
351 #endif
352         return 0;
353 }
354
355 static char *_argv[256];
356
357 static int shuttingdown = 0;
358
359 static void quit_handler(int num, int nice, int safeshutdown, int restart)
360 {
361         char filename[80] = "";
362         time_t s,e;
363         int x;
364         if (safeshutdown) {
365                 shuttingdown = 1;
366                 if (!nice) {
367                         /* Begin shutdown routine, hanging up active channels */
368                         ast_begin_shutdown(1);
369                         if (option_verbose && option_console)
370                                 ast_verbose("Beginning asterisk %s....\n", restart ? "restart" : "shutdown");
371                         time(&s);
372                         for(;;) {
373                                 time(&e);
374                                 /* Wait up to 15 seconds for all channels to go away */
375                                 if ((e - s) > 15)
376                                         break;
377                                 if (!ast_active_channels())
378                                         break;
379                                 if (!shuttingdown)
380                                         break;
381                                 /* Sleep 1/10 of a second */
382                                 usleep(100000);
383                         }
384                 } else {
385                         if (nice < 2)
386                                 ast_begin_shutdown(0);
387                         if (option_verbose && option_console)
388                                 ast_verbose("Waiting for inactivity to perform %s...\n", restart ? "restart" : "halt");
389                         for(;;) {
390                                 if (!ast_active_channels())
391                                         break;
392                                 if (!shuttingdown)
393                                         break;
394                                 sleep(1);
395                         }
396                 }
397
398                 if (!shuttingdown) {
399                         if (option_verbose && option_console)
400                                 ast_verbose("Asterisk %s cancelled.\n", restart ? "restart" : "shutdown");
401                         return;
402                 }
403         }
404         if (option_console || option_remote) {
405                 if (getenv("HOME")) 
406                         snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
407                 if (strlen(filename))
408                         ast_el_write_history(filename);
409                 if (el != NULL)
410                         el_end(el);
411                 if (el_hist != NULL)
412                         history_end(el_hist);
413         }
414         /* Called on exit */
415         if (option_verbose && option_console)
416                 ast_verbose("Asterisk %s ending (%d).\n", ast_active_channels() ? "uncleanly" : "cleanly", num);
417         else if (option_debug)
418                 ast_log(LOG_DEBUG, "Asterisk ending (%d).\n", num);
419         manager_event(EVENT_FLAG_SYSTEM, "Shutdown", "Shutdown: %s\r\nRestart: %s\r\n", ast_active_channels() ? "Uncleanly" : "Cleanly", restart ? "True" : "False");
420         if (ast_socket > -1) {
421                 close(ast_socket);
422                 ast_socket = -1;
423         }
424         if (ast_consock > -1)
425                 close(ast_consock);
426         if (ast_socket > -1)
427                 unlink((char *)ast_config_AST_SOCKET);
428         unlink((char *)ast_config_AST_PID);
429         printf(term_quit());
430         if (restart) {
431                 if (option_verbose || option_console)
432                         ast_verbose("Preparing for Asterisk restart...\n");
433                 /* Mark all FD's for closing on exec */
434                 for (x=3;x<32768;x++) {
435                         fcntl(x, F_SETFD, FD_CLOEXEC);
436                 }
437                 if (option_verbose || option_console)
438                         ast_verbose("Restarting Asterisk NOW...\n");
439                 execvp(_argv[0], _argv);
440         } else
441                 exit(0);
442 }
443
444 static void __quit_handler(int num)
445 {
446         quit_handler(num, 0, 1, 0);
447 }
448
449 static pthread_t consolethread = -1;
450
451 static int fix_header(char *outbuf, int maxout, char **s, char *cmp)
452 {
453         if (!strncmp(*s, cmp, strlen(cmp))) {
454                 *s += strlen(cmp);
455                 term_color(outbuf, cmp, COLOR_GRAY, 0, maxout);
456                 return 1;
457         }
458         return 0;
459 }
460
461 static void console_verboser(const char *s, int pos, int replace, int complete)
462 {
463         char tmp[80];
464         /* Return to the beginning of the line */
465         if (!pos) {
466                 fprintf(stdout, "\r");
467                 if (fix_header(tmp, sizeof(tmp), &s, VERBOSE_PREFIX_4) ||
468                         fix_header(tmp, sizeof(tmp), &s, VERBOSE_PREFIX_3) ||
469                         fix_header(tmp, sizeof(tmp), &s, VERBOSE_PREFIX_2) ||
470                         fix_header(tmp, sizeof(tmp), &s, VERBOSE_PREFIX_1))
471                         fputs(tmp, stdout);
472         }
473         fputs(s + pos,stdout);
474         fflush(stdout);
475         if (complete)
476         /* Wake up a select()ing console */
477                 if (consolethread > -1)
478                         pthread_kill(consolethread, SIGURG);
479 }
480
481 static void consolehandler(char *s)
482 {
483         printf(term_end());
484         fflush(stdout);
485         /* Called when readline data is available */
486         if (s && strlen(s))
487                 ast_el_add_history(s);
488         /* Give the console access to the shell */
489         if (s) {
490                 if (s[0] == '!') {
491                         if (s[1])
492                                 system(s+1);
493                         else
494                                 system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
495                 } else 
496                 ast_cli_command(STDOUT_FILENO, s);
497                 if (!strcasecmp(s, "help"))
498                         fprintf(stdout, "          !<command>   Executes a given shell command\n");
499         } else
500                 fprintf(stdout, "\nUse \"quit\" to exit\n");
501 }
502
503 static int remoteconsolehandler(char *s)
504 {
505         int ret = 0;
506         /* Called when readline data is available */
507         if (s && strlen(s))
508                 ast_el_add_history(s);
509         /* Give the console access to the shell */
510         if (s) {
511                 if (s[0] == '!') {
512                         if (s[1])
513                                 system(s+1);
514                         else
515                                 system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
516                         ret = 1;
517                 }
518                 if (!strcasecmp(s, "help")) {
519                         fprintf(stdout, "          !<command>   Executes a given shell command\n");
520                         ret = 0;
521                 }
522                 if (!strcasecmp(s, "quit")) {
523                         quit_handler(0, 0, 0, 0);
524                         ret = 1;
525                 }
526                 if (!strcasecmp(s, "exit")) {
527                         quit_handler(0, 0, 0, 0);
528                         ret = 1;
529                 }
530         } else
531                 fprintf(stdout, "\nUse \"quit\" to exit\n");
532
533         return ret;
534 }
535
536 static char quit_help[] = 
537 "Usage: quit\n"
538 "       Exits Asterisk.\n";
539
540 static char abort_halt_help[] = 
541 "Usage: abort shutdown\n"
542 "       Causes Asterisk to abort an executing shutdown or restart, and resume normal\n"
543 "       call operations.\n";
544
545 static char shutdown_now_help[] = 
546 "Usage: stop now\n"
547 "       Shuts down a running Asterisk immediately, hanging up all active calls .\n";
548
549 static char shutdown_gracefully_help[] = 
550 "Usage: stop gracefully\n"
551 "       Causes Asterisk to not accept new calls, and exit when all\n"
552 "       active calls have terminated normally.\n";
553
554 static char shutdown_when_convenient_help[] = 
555 "Usage: stop when convenient\n"
556 "       Causes Asterisk to perform a shutdown when all active calls have ended.\n";
557
558 static char restart_now_help[] = 
559 "Usage: restart now\n"
560 "       Causes Asterisk to hangup all calls and exec() itself performing a cold.\n"
561 "       restart.\n";
562
563 static char restart_gracefully_help[] = 
564 "Usage: restart gracefully\n"
565 "       Causes Asterisk to stop accepting new calls and exec() itself performing a cold.\n"
566 "       restart when all active calls have ended.\n";
567
568 static char restart_when_convenient_help[] = 
569 "Usage: restart when convenient\n"
570 "       Causes Asterisk to perform a cold restart when all active calls have ended.\n";
571
572 #if 0
573 static int handle_quit(int fd, int argc, char *argv[])
574 {
575         if (argc != 1)
576                 return RESULT_SHOWUSAGE;
577         quit_handler(0, 0, 1, 0);
578         return RESULT_SUCCESS;
579 }
580 #endif
581
582 static int no_more_quit(int fd, int argc, char *argv[])
583 {
584         if (argc != 1)
585                 return RESULT_SHOWUSAGE;
586         ast_cli(fd, "The QUIT and EXIT commands may no longer be used to shutdown the PBX.\n"
587                     "Please use STOP NOW instead, if you wish to shutdown the PBX.\n");
588         return RESULT_SUCCESS;
589 }
590
591 static int handle_shutdown_now(int fd, int argc, char *argv[])
592 {
593         if (argc != 2)
594                 return RESULT_SHOWUSAGE;
595         quit_handler(0, 0 /* Not nice */, 1 /* safely */, 0 /* not restart */);
596         return RESULT_SUCCESS;
597 }
598
599 static int handle_shutdown_gracefully(int fd, int argc, char *argv[])
600 {
601         if (argc != 2)
602                 return RESULT_SHOWUSAGE;
603         quit_handler(0, 1 /* nicely */, 1 /* safely */, 0 /* no restart */);
604         return RESULT_SUCCESS;
605 }
606
607 static int handle_shutdown_when_convenient(int fd, int argc, char *argv[])
608 {
609         if (argc != 3)
610                 return RESULT_SHOWUSAGE;
611         quit_handler(0, 2 /* really nicely */, 1 /* safely */, 0 /* don't restart */);
612         return RESULT_SUCCESS;
613 }
614
615 static int handle_restart_now(int fd, int argc, char *argv[])
616 {
617         if (argc != 2)
618                 return RESULT_SHOWUSAGE;
619         quit_handler(0, 0 /* not nicely */, 1 /* safely */, 1 /* restart */);
620         return RESULT_SUCCESS;
621 }
622
623 static int handle_restart_gracefully(int fd, int argc, char *argv[])
624 {
625         if (argc != 2)
626                 return RESULT_SHOWUSAGE;
627         quit_handler(0, 1 /* nicely */, 1 /* safely */, 1 /* restart */);
628         return RESULT_SUCCESS;
629 }
630
631 static int handle_restart_when_convenient(int fd, int argc, char *argv[])
632 {
633         if (argc != 3)
634                 return RESULT_SHOWUSAGE;
635         quit_handler(0, 2 /* really nicely */, 1 /* safely */, 1 /* restart */);
636         return RESULT_SUCCESS;
637 }
638
639 static int handle_abort_halt(int fd, int argc, char *argv[])
640 {
641         if (argc != 2)
642                 return RESULT_SHOWUSAGE;
643         ast_cancel_shutdown();
644         shuttingdown = 0;
645         return RESULT_SUCCESS;
646 }
647
648 #define ASTERISK_PROMPT "*CLI> "
649
650 #define ASTERISK_PROMPT2 "%s*CLI> "
651
652 static struct ast_cli_entry aborthalt = { { "abort", "halt", NULL }, handle_abort_halt, "Cancel a running halt", abort_halt_help };
653
654 static struct ast_cli_entry quit =      { { "quit", NULL }, no_more_quit, "Exit Asterisk", quit_help };
655 static struct ast_cli_entry astexit =   { { "exit", NULL }, no_more_quit, "Exit Asterisk", quit_help };
656
657 static struct ast_cli_entry astshutdownnow =    { { "stop", "now", NULL }, handle_shutdown_now, "Shut down Asterisk imediately", shutdown_now_help };
658 static struct ast_cli_entry astshutdowngracefully =     { { "stop", "gracefully", NULL }, handle_shutdown_gracefully, "Gracefully shut down Asterisk", shutdown_gracefully_help };
659 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 };
660 static struct ast_cli_entry astrestartnow =     { { "restart", "now", NULL }, handle_restart_now, "Restart Asterisk immediately", restart_now_help };
661 static struct ast_cli_entry astrestartgracefully =      { { "restart", "gracefully", NULL }, handle_restart_gracefully, "Restart Asterisk gracefully", restart_gracefully_help };
662 static struct ast_cli_entry astrestartwhenconvenient=   { { "restart", "when", "convenient", NULL }, handle_restart_when_convenient, "Restart Asterisk at empty call volume", restart_when_convenient_help };
663
664 static int ast_el_read_char(EditLine *el, char *cp)
665 {
666         int num_read=0;
667         int lastpos=0;
668         fd_set rfds;
669         int res;
670         int max;
671         char buf[512];
672
673         for (;;) {
674                 FD_ZERO(&rfds);
675                 FD_SET(ast_consock, &rfds);
676                 max = ast_consock;
677                 if (!option_exec) {
678                         FD_SET(STDIN_FILENO, &rfds);
679                         if (STDIN_FILENO > max)
680                                 max = STDIN_FILENO;
681                 }
682                 res = ast_select(max+1, &rfds, NULL, NULL, NULL);
683                 if (res < 0) {
684                         if (errno == EINTR)
685                                 continue;
686                         ast_log(LOG_ERROR, "select failed: %s\n", strerror(errno));
687                         break;
688                 }
689
690                 if (FD_ISSET(STDIN_FILENO, &rfds)) {
691                         num_read = read(STDIN_FILENO, cp, 1);
692                         if (num_read < 1) {
693                                 break;
694                         } else 
695                                 return (num_read);
696                 }
697                 if (FD_ISSET(ast_consock, &rfds)) {
698                         res = read(ast_consock, buf, sizeof(buf) - 1);
699                         /* if the remote side disappears exit */
700                         if (res < 1) {
701                                 fprintf(stderr, "\nDisconnected from Asterisk server\n");
702                                 quit_handler(0, 0, 0, 0);
703                         }
704
705                         buf[res] = '\0';
706
707                         if (!option_exec && !lastpos)
708                                 write(STDOUT_FILENO, "\r", 1);
709                         write(STDOUT_FILENO, buf, res);
710                         if ((buf[res-1] == '\n') || (buf[res-2] == '\n')) {
711                                 *cp = CC_REFRESH;
712                                 return(1);
713                         } else {
714                                 lastpos = 1;
715                         }
716                 }
717         }
718
719         *cp = '\0';
720         return (0);
721 }
722
723 static char *cli_prompt(EditLine *el)
724 {
725         static char prompt[80];
726
727         if (remotehostname)
728                 snprintf(prompt, sizeof(prompt), ASTERISK_PROMPT2, remotehostname);
729         else
730                 snprintf(prompt, sizeof(prompt), ASTERISK_PROMPT);
731
732         return(prompt); 
733 }
734
735 static char **ast_el_strtoarr(char *buf)
736 {
737         char **match_list = NULL, *retstr;
738         size_t match_list_len;
739         int matches = 0;
740
741         match_list_len = 1;
742         while ( (retstr = strsep(&buf, " ")) != NULL) {
743
744                 if (matches + 1 >= match_list_len) {
745                         match_list_len <<= 1;
746                         match_list = realloc(match_list, match_list_len * sizeof(char *));
747                 }
748
749                 match_list[matches++] = retstr;
750         }
751
752         if (!match_list)
753                 return (char **) NULL;
754
755         if (matches>= match_list_len)
756                 match_list = realloc(match_list, (match_list_len + 1) * sizeof(char *));
757
758         match_list[matches] = (char *) NULL;
759
760         return match_list;
761 }
762
763 static int ast_el_sort_compare(const void *i1, const void *i2)
764 {
765         char *s1, *s2;
766
767         s1 = ((char **)i1)[0];
768         s2 = ((char **)i2)[0];
769
770         return strcasecmp(s1, s2);
771 }
772
773 static int ast_cli_display_match_list(char **matches, int len, int max)
774 {
775         int i, idx, limit, count;
776         int screenwidth = 0;
777         int numoutput = 0, numoutputline = 0;
778
779         screenwidth = ast_get_termcols(STDOUT_FILENO);
780
781         /* find out how many entries can be put on one line, with two spaces between strings */
782         limit = screenwidth / (max + 2);
783         if (limit == 0)
784                 limit = 1;
785
786         /* how many lines of output */
787         count = len / limit;
788         if (count * limit < len)
789                 count++;
790
791         idx = 1;
792
793         qsort(&matches[0], (size_t)(len + 1), sizeof(char *), ast_el_sort_compare);
794
795         for (; count > 0; count--) {
796                 numoutputline = 0;
797                 for (i=0; i < limit && matches[idx]; i++, idx++) {
798
799                         /* Don't print dupes */
800                         if ( (matches[idx+1] != NULL && strcmp(matches[idx], matches[idx+1]) == 0 ) ) {
801                                 i--;
802                                 continue;
803                         }
804
805                         numoutput++;  numoutputline++;
806                         fprintf(stdout, "%-*s  ", max, matches[idx]);
807                 }
808                 if (numoutputline > 0)
809                         fprintf(stdout, "\n");
810         }
811
812         return numoutput;
813 }
814
815
816 static char *cli_complete(EditLine *el, int ch)
817 {
818         int len=0;
819         char *ptr;
820         int nummatches = 0;
821         char **matches;
822         int retval = CC_ERROR;
823         char buf[1024];
824         int res;
825
826         LineInfo *lf = (LineInfo *)el_line(el);
827
828         *lf->cursor = '\0';
829         ptr = (char *)lf->cursor;
830         if (ptr) {
831                 while (ptr > lf->buffer) {
832                         if (isspace(*ptr)) {
833                                 ptr++;
834                                 break;
835                         }
836                         ptr--;
837                 }
838         }
839
840         len = lf->cursor - ptr;
841
842         if (option_remote) {
843                 snprintf(buf, sizeof(buf),"_COMMAND NUMMATCHES \"%s\" \"%s\"", lf->buffer, ptr); 
844                 fdprint(ast_consock, buf);
845                 res = read(ast_consock, buf, sizeof(buf));
846                 buf[res] = '\0';
847                 nummatches = atoi(buf);
848
849                 if (nummatches > 0) {
850                         snprintf(buf, sizeof(buf),"_COMMAND MATCHESARRAY \"%s\" \"%s\"", lf->buffer, ptr); 
851                         fdprint(ast_consock, buf);
852                         res = read(ast_consock, buf, sizeof(buf));
853                         buf[res] = '\0';
854
855                         matches = ast_el_strtoarr(buf);
856                 } else
857                         matches = (char **) NULL;
858
859
860         }  else {
861
862                 nummatches = ast_cli_generatornummatches((char *)lf->buffer,ptr);
863                 matches = ast_cli_completion_matches((char *)lf->buffer,ptr);
864         }
865
866         if (matches) {
867                 int i;
868                 int matches_num, maxlen, match_len;
869
870                 if (matches[0][0] != '\0') {
871                         el_deletestr(el, (int) len);
872                         el_insertstr(el, matches[0]);
873                         retval = CC_REFRESH;
874                 }
875
876                 if (nummatches == 1) {
877                         /* Found an exact match */
878                         el_insertstr(el, " ");
879                         retval = CC_REFRESH;
880                 } else {
881                         /* Must be more than one match */
882                         for (i=1, maxlen=0; matches[i]; i++) {
883                                 match_len = strlen(matches[i]);
884                                 if (match_len > maxlen)
885                                         maxlen = match_len;
886                         }
887                         matches_num = i - 1;
888                         if (matches_num >1) {
889                                 fprintf(stdout, "\n");
890                                 ast_cli_display_match_list(matches, nummatches, maxlen);
891                                 retval = CC_REDISPLAY;
892                         } else { 
893                                 el_insertstr(el," ");
894                                 retval = CC_REFRESH;
895                         }
896                 }
897         free(matches);
898         }
899
900         return (char *)retval;
901 }
902
903 static int ast_el_initialize(void)
904 {
905         HistEvent ev;
906
907         if (el != NULL)
908                 el_end(el);
909         if (el_hist != NULL)
910                 history_end(el_hist);
911
912         el = el_init("asterisk", stdin, stdout, stderr);
913         el_set(el, EL_PROMPT, cli_prompt);
914
915         el_set(el, EL_EDITMODE, 1);             
916         el_set(el, EL_EDITOR, "emacs");         
917         el_hist = history_init();
918         if (!el || !el_hist)
919                 return -1;
920
921         /* setup history with 100 entries */
922         history(el_hist, &ev, H_SETSIZE, 100);
923
924         el_set(el, EL_HIST, history, el_hist);
925
926         el_set(el, EL_ADDFN, "ed-complete", "Complete argument", cli_complete);
927         /* Bind <tab> to command completion */
928         el_set(el, EL_BIND, "^I", "ed-complete", NULL);
929         /* Bind ? to command completion */
930         el_set(el, EL_BIND, "?", "ed-complete", NULL);
931
932         return 0;
933 }
934
935 static int ast_el_add_history(char *buf)
936 {
937         HistEvent ev;
938
939         if (el_hist == NULL || el == NULL)
940                 ast_el_initialize();
941
942         return (history(el_hist, &ev, H_ENTER, buf));
943 }
944
945 static int ast_el_write_history(char *filename)
946 {
947         HistEvent ev;
948
949         if (el_hist == NULL || el == NULL)
950                 ast_el_initialize();
951
952         return (history(el_hist, &ev, H_SAVE, filename));
953 }
954
955 static int ast_el_read_history(char *filename)
956 {
957         char buf[256];
958         FILE *f;
959         int ret = -1;
960
961         if (el_hist == NULL || el == NULL)
962                 ast_el_initialize();
963
964         if ((f = fopen(filename, "r")) == NULL)
965                 return ret;
966
967         while (!feof(f)) {
968                 fgets(buf, sizeof(buf), f);
969                 if (!strcmp(buf, "_HiStOrY_V2_\n"))
970                         continue;
971                 if ((ret = ast_el_add_history(buf)) == -1)
972                         break;
973         }
974         fclose(f);
975
976         return ret;
977 }
978
979 static void ast_remotecontrol(char * data)
980 {
981         char buf[80];
982         int res;
983         char filename[80] = "";
984         char *hostname;
985         char *cpid;
986         char *version;
987         int pid;
988         char tmp[80];
989         char *stringp=NULL;
990
991         char *ebuf;
992         int num = 0;
993
994         read(ast_consock, buf, sizeof(buf));
995         if (data)
996                 write(ast_consock, data, strlen(data) + 1);
997         stringp=buf;
998         hostname = strsep(&stringp, "/");
999         cpid = strsep(&stringp, "/");
1000         version = strsep(&stringp, "/");
1001         if (!version)
1002                 version = "<Version Unknown>";
1003         stringp=hostname;
1004         strsep(&stringp, ".");
1005         if (cpid)
1006                 pid = atoi(cpid);
1007         else
1008                 pid = -1;
1009         snprintf(tmp, sizeof(tmp), "set verbose atleast %d", option_verbose);
1010         fdprint(ast_consock, tmp);
1011         ast_verbose("Connected to Asterisk %s currently running on %s (pid = %d)\n", version, hostname, pid);
1012         remotehostname = hostname;
1013         if (getenv("HOME")) 
1014                 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
1015         if (el_hist == NULL || el == NULL)
1016                 ast_el_initialize();
1017
1018         el_set(el, EL_GETCFN, ast_el_read_char);
1019
1020         if (strlen(filename))
1021                 ast_el_read_history(filename);
1022
1023         ast_cli_register(&quit);
1024         ast_cli_register(&astexit);
1025 #if 0
1026         ast_cli_register(&astshutdown);
1027 #endif  
1028         if (option_exec && data) {  /* hack to print output then exit if asterisk -rx is used */
1029                 char tempchar;
1030                 ast_el_read_char(el, &tempchar);
1031                 return;
1032         }
1033         for(;;) {
1034                 ebuf = (char *)el_gets(el, &num);
1035
1036                 if (ebuf && strlen(ebuf)) {
1037                         if (ebuf[strlen(ebuf)-1] == '\n')
1038                                 ebuf[strlen(ebuf)-1] = '\0';
1039                         if (!remoteconsolehandler(ebuf)) {
1040                                 res = write(ast_consock, ebuf, strlen(ebuf) + 1);
1041                                 if (res < 1) {
1042                                         ast_log(LOG_WARNING, "Unable to write: %s\n", strerror(errno));
1043                                         break;
1044                                 }
1045                         }
1046                 }
1047         }
1048         printf("\nDisconnected from Asterisk server\n");
1049 }
1050
1051 static int show_cli_help(void) {
1052         printf("Asterisk " ASTERISK_VERSION ", Copyright (C) 2000-2002, Digium.\n");
1053         printf("Usage: asterisk [OPTIONS]\n");
1054         printf("Valid Options:\n");
1055         printf("   -h           This help screen\n");
1056         printf("   -r           Connect to Asterisk on this machine\n");
1057         printf("   -f           Do not fork\n");
1058         printf("   -n           Disable console colorization\n");
1059         printf("   -p           Run as pseudo-realtime thread\n");
1060         printf("   -v           Increase verbosity (multiple v's = more verbose)\n");
1061         printf("   -q           Quiet mode (supress output)\n");
1062         printf("   -g           Dump core in case of a crash\n");
1063         printf("   -x <cmd>     Execute command <cmd> (only valid with -r)\n");
1064         printf("   -i           Initializie crypto keys at startup\n");
1065         printf("   -c           Provide console CLI\n");
1066         printf("   -d           Enable extra debugging\n");
1067         printf("\n");
1068         return 0;
1069 }
1070
1071 static void ast_readconfig(void) {
1072         struct ast_config *cfg;
1073         struct ast_variable *v;
1074         char *config = ASTCONFPATH;
1075
1076         if (option_overrideconfig == 1) {
1077             cfg = ast_load((char *)ast_config_AST_CONFIG_FILE);
1078         } else {
1079             cfg = ast_load(config);
1080         }
1081
1082         /* init with buildtime config */
1083         strncpy((char *)ast_config_AST_CONFIG_DIR,AST_CONFIG_DIR,sizeof(ast_config_AST_CONFIG_DIR)-1);
1084         strncpy((char *)ast_config_AST_SPOOL_DIR,AST_SPOOL_DIR,sizeof(ast_config_AST_SPOOL_DIR)-1);
1085         strncpy((char *)ast_config_AST_MODULE_DIR,AST_MODULE_DIR,sizeof(ast_config_AST_VAR_DIR)-1);
1086         strncpy((char *)ast_config_AST_VAR_DIR,AST_VAR_DIR,sizeof(ast_config_AST_VAR_DIR)-1);
1087         strncpy((char *)ast_config_AST_LOG_DIR,AST_LOG_DIR,sizeof(ast_config_AST_LOG_DIR)-1);
1088         strncpy((char *)ast_config_AST_AGI_DIR,AST_AGI_DIR,sizeof(ast_config_AST_AGI_DIR)-1);
1089         strncpy((char *)ast_config_AST_DB,AST_DB,sizeof(ast_config_AST_DB)-1);
1090         strncpy((char *)ast_config_AST_KEY_DIR,AST_KEY_DIR,sizeof(ast_config_AST_KEY_DIR)-1);
1091         strncpy((char *)ast_config_AST_PID,AST_PID,sizeof(ast_config_AST_PID)-1);
1092         strncpy((char *)ast_config_AST_SOCKET,AST_SOCKET,sizeof(ast_config_AST_SOCKET)-1);
1093         strncpy((char *)ast_config_AST_RUN_DIR,AST_RUN_DIR,sizeof(ast_config_AST_RUN_DIR)-1);
1094         
1095         /* no asterisk.conf? no problem, use buildtime config! */
1096         if (!cfg) {
1097             return;
1098         }
1099         v = ast_variable_browse(cfg, "directories");
1100         while(v) {
1101                 if (!strcasecmp(v->name, "astetcdir")) {
1102                     strncpy((char *)ast_config_AST_CONFIG_DIR,v->value,sizeof(ast_config_AST_CONFIG_DIR)-1);
1103                 } else if (!strcasecmp(v->name, "astspooldir")) {
1104                     strncpy((char *)ast_config_AST_SPOOL_DIR,v->value,sizeof(ast_config_AST_SPOOL_DIR)-1);
1105                 } else if (!strcasecmp(v->name, "astvarlibdir")) {
1106                     strncpy((char *)ast_config_AST_VAR_DIR,v->value,sizeof(ast_config_AST_VAR_DIR)-1);
1107                     snprintf((char *)ast_config_AST_DB,sizeof(ast_config_AST_DB)-1,"%s/%s",v->value,"astdb");    
1108                 } else if (!strcasecmp(v->name, "astlogdir")) {
1109                     strncpy((char *)ast_config_AST_LOG_DIR,v->value,sizeof(ast_config_AST_LOG_DIR)-1);
1110                 } else if (!strcasecmp(v->name, "astagidir")) {
1111                     strncpy((char *)ast_config_AST_AGI_DIR,v->value,sizeof(ast_config_AST_AGI_DIR)-1);
1112                 } else if (!strcasecmp(v->name, "astrundir")) {
1113                     snprintf((char *)ast_config_AST_PID,sizeof(ast_config_AST_PID)-1,"%s/%s",v->value,"asterisk.pid");    
1114                     snprintf((char *)ast_config_AST_SOCKET,sizeof(ast_config_AST_SOCKET)-1,"%s/%s",v->value,"asterisk.ctl");    
1115                     strncpy((char *)ast_config_AST_RUN_DIR,v->value,sizeof(ast_config_AST_RUN_DIR)-1);
1116                 } else if (!strcasecmp(v->name, "astmoddir")) {
1117                     strncpy((char *)ast_config_AST_MODULE_DIR,v->value,sizeof(ast_config_AST_MODULE_DIR)-1);
1118                 }
1119                 v = v->next;
1120         }
1121         ast_destroy(cfg);
1122 }
1123
1124 int main(int argc, char *argv[])
1125 {
1126         char c;
1127         char filename[80] = "";
1128         char hostname[256];
1129         char tmp[80];
1130         char * xarg = NULL;
1131         int x;
1132         FILE *f;
1133         sigset_t sigs;
1134         int num;
1135         char *buf;
1136
1137         /* Remember original args for restart */
1138         if (argc > sizeof(_argv) / sizeof(_argv[0]) - 1) {
1139                 fprintf(stderr, "Truncating argument size to %d\n", sizeof(_argv) / sizeof(_argv[0]) - 1);
1140                 argc = sizeof(_argv) / sizeof(_argv[0]) - 1;
1141         }
1142         for (x=0;x<argc;x++)
1143                 _argv[x] = argv[x];
1144         _argv[x] = NULL;
1145
1146         if (gethostname(hostname, sizeof(hostname)))
1147                 strncpy(hostname, "<Unknown>", sizeof(hostname)-1);
1148         mainpid = getpid();
1149         ast_ulaw_init();
1150         ast_alaw_init();
1151         callerid_init();
1152         tdd_init();
1153         if (getenv("HOME")) 
1154                 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
1155         /* Check if we're root */
1156         /*
1157         if (geteuid()) {
1158                 ast_log(LOG_ERROR, "Must be run as root\n");
1159                 exit(1);
1160         }
1161         */
1162         /* Check for options */
1163         while((c=getopt(argc, argv, "hfdvqprgcinx:C:")) != EOF) {
1164                 switch(c) {
1165                 case 'd':
1166                         option_debug++;
1167                         option_nofork++;
1168                         break;
1169                 case 'c':
1170                         option_console++;
1171                         option_nofork++;
1172                         break;
1173                 case 'f':
1174                         option_nofork++;
1175                         break;
1176                 case 'n':
1177                         option_nocolor++;
1178                         break;
1179                 case 'r':
1180                         option_remote++;
1181                         option_nofork++;
1182                         break;
1183                 case 'p':
1184                         option_highpriority++;
1185                         break;
1186                 case 'v':
1187                         option_verbose++;
1188                         option_nofork++;
1189                         break;
1190                 case 'q':
1191                         option_quiet++;
1192                         break;
1193                 case 'x':
1194                         option_exec++;
1195                         xarg = optarg;
1196                         break;
1197                 case 'C':
1198                         strncpy((char *)ast_config_AST_CONFIG_FILE,optarg,sizeof(ast_config_AST_CONFIG_FILE));
1199                         option_overrideconfig++;
1200                         break;
1201                 case 'i':
1202                         option_initcrypto++;
1203                         break;
1204                 case'g':
1205                         option_dumpcore++;
1206                         break;
1207                 case 'h':
1208                         show_cli_help();
1209                         exit(0);
1210                 case '?':
1211                         exit(1);
1212                 }
1213         }
1214
1215         if (option_dumpcore) {
1216                 struct rlimit l;
1217                 memset(&l, 0, sizeof(l));
1218                 l.rlim_cur = RLIM_INFINITY;
1219                 l.rlim_max = RLIM_INFINITY;
1220                 if (setrlimit(RLIMIT_CORE, &l)) {
1221                         ast_log(LOG_WARNING, "Unable to disable core size resource limit: %s\n", strerror(errno));
1222                 }
1223         }
1224
1225         term_init();
1226         printf(term_end());
1227         fflush(stdout);
1228         if (option_console && !option_verbose) 
1229                 ast_verbose("[ Reading Master Configuration ]");
1230         ast_readconfig();
1231
1232         if (option_console) {
1233                 if (el_hist == NULL || el == NULL)
1234                         ast_el_initialize();
1235
1236                 if (strlen(filename))
1237                         ast_el_read_history(filename);
1238         }
1239
1240         if (ast_tryconnect()) {
1241                 /* One is already running */
1242                 if (option_remote) {
1243                         if (option_exec) {
1244                                 ast_remotecontrol(xarg);
1245                                 quit_handler(0, 0, 0, 0);
1246                                 exit(0);
1247                         }
1248                         printf(term_quit());
1249                         ast_register_verbose(console_verboser);
1250                         ast_verbose( "Asterisk " ASTERISK_VERSION ", Copyright (C) 1999-2001 Linux Support Services, Inc.\n");
1251                         ast_verbose( "Written by Mark Spencer <markster@linux-support.net>\n");
1252                         ast_verbose( "=========================================================================\n");
1253                         ast_remotecontrol(NULL);
1254                         quit_handler(0, 0, 0, 0);
1255                         exit(0);
1256                 } else {
1257                         ast_log(LOG_ERROR, "Asterisk already running on %s.  Use 'asterisk -r' to connect.\n", (char *)ast_config_AST_SOCKET);
1258                         printf(term_quit());
1259                         exit(1);
1260                 }
1261         } else if (option_remote || option_exec) {
1262                 ast_log(LOG_ERROR, "Unable to connect to remote asterisk\n");
1263                 printf(term_quit());
1264                 exit(1);
1265         }
1266         /* Blindly write pid file since we couldn't connect */
1267         unlink((char *)ast_config_AST_PID);
1268         f = fopen((char *)ast_config_AST_PID, "w");
1269         if (f) {
1270                 fprintf(f, "%d\n", getpid());
1271                 fclose(f);
1272         } else
1273                 ast_log(LOG_WARNING, "Unable to open pid file '%s': %s\n", (char *)ast_config_AST_PID, strerror(errno));
1274
1275         if (!option_verbose && !option_debug && !option_nofork && !option_console) {
1276 #if 1
1277                 daemon(0,0);
1278 #else   
1279                 pid = fork();
1280                 if (pid < 0) {
1281                         ast_log(LOG_ERROR, "Unable to fork(): %s\n", strerror(errno));
1282                         printf(term_quit());
1283                         exit(1);
1284                 }
1285                 if (pid) 
1286                         exit(0);
1287 #endif                  
1288         }
1289
1290         ast_makesocket();
1291         sigemptyset(&sigs);
1292         sigaddset(&sigs, SIGHUP);
1293         sigaddset(&sigs, SIGTERM);
1294         sigaddset(&sigs, SIGINT);
1295         sigaddset(&sigs, SIGPIPE);
1296         sigaddset(&sigs, SIGWINCH);
1297         pthread_sigmask(SIG_BLOCK, &sigs, NULL);
1298         if (option_console || option_verbose || option_remote)
1299                 ast_register_verbose(console_verboser);
1300         /* Print a welcome message if desired */
1301         if (option_verbose || option_console) {
1302                 ast_verbose( "Asterisk " ASTERISK_VERSION ", Copyright (C) 1999-2001 Linux Support Services, Inc.\n");
1303                 ast_verbose( "Written by Mark Spencer <markster@linux-support.net>\n");
1304                 ast_verbose( "=========================================================================\n");
1305         }
1306         if (option_console && !option_verbose) 
1307                 ast_verbose("[ Booting...");
1308         signal(SIGURG, urg_handler);
1309         signal(SIGINT, __quit_handler);
1310         signal(SIGTERM, __quit_handler);
1311         signal(SIGHUP, hup_handler);
1312         signal(SIGPIPE, pipe_handler);
1313         if (set_priority(option_highpriority)) {
1314                 printf(term_quit());
1315                 exit(1);
1316         }
1317         if (init_logger()) {
1318                 printf(term_quit());
1319                 exit(1);
1320         }
1321         if (init_manager()) {
1322                 printf(term_quit());
1323                 exit(1);
1324         }
1325         ast_rtp_init();
1326         if (ast_image_init()) {
1327                 printf(term_quit());
1328                 exit(1);
1329         }
1330         if (load_pbx()) {
1331                 printf(term_quit());
1332                 exit(1);
1333         }
1334         if (load_modules()) {
1335                 printf(term_quit());
1336                 exit(1);
1337         }
1338         if (init_framer()) {
1339                 printf(term_quit());
1340                 exit(1);
1341         }
1342         if (astdb_init()) {
1343                 printf(term_quit());
1344                 exit(1);
1345         }
1346         if (ast_enum_init()) {
1347                 printf(term_quit());
1348                 exit(1);
1349         }
1350         /* We might have the option of showing a console, but for now just
1351            do nothing... */
1352         if (option_console && !option_verbose)
1353                 ast_verbose(" ]\n");
1354         if (option_verbose || option_console)
1355                 ast_verbose(term_color(tmp, "Asterisk Ready.\n", COLOR_BRWHITE, COLOR_BLACK, sizeof(tmp)));
1356         fully_booted = 1;
1357         pthread_sigmask(SIG_UNBLOCK, &sigs, NULL);
1358 #ifdef __AST_DEBUG_MALLOC
1359         __ast_mm_init();
1360 #endif  
1361         time(&ast_startuptime);
1362         ast_cli_register(&astshutdownnow);
1363         ast_cli_register(&astshutdowngracefully);
1364         ast_cli_register(&astrestartnow);
1365         ast_cli_register(&astrestartgracefully);
1366         ast_cli_register(&astrestartwhenconvenient);
1367         ast_cli_register(&astshutdownwhenconvenient);
1368         ast_cli_register(&aborthalt);
1369         if (option_console) {
1370                 /* Console stuff now... */
1371                 /* Register our quit function */
1372                 char title[256];
1373                 set_icon("Asterisk");
1374                 snprintf(title, sizeof(title), "Asterisk Console on '%s' (pid %d)", hostname, mainpid);
1375                 set_title(title);
1376             ast_cli_register(&quit);
1377             ast_cli_register(&astexit);
1378                 consolethread = pthread_self();
1379
1380                 for (;;) {
1381                         buf = (char *)el_gets(el, &num);
1382                         if (buf) {
1383                                 if (buf[strlen(buf)-1] == '\n')
1384                                         buf[strlen(buf)-1] = '\0';
1385
1386                                 consolehandler((char *)buf);
1387                         } else
1388                                 ast_cli(STDOUT_FILENO, "\nUse EXIT or QUIT to exist, or STOP NOW to shutdown Asterisk\n");
1389                 }
1390
1391         } else {
1392                 /* Do nothing */
1393                 ast_select(0,NULL,NULL,NULL,NULL);
1394         }
1395         return 0;
1396 }