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