e26e6a517a370f7dcff3fe2732738767feb773e7
[asterisk/asterisk.git] / asterisk.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2006, Digium, Inc.
5  *
6  * Mark Spencer <markster@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18
19
20 /* Doxygenified Copyright Header */
21 /*!
22  * \mainpage Asterisk -- An Open Source Telephony Toolkit
23  *
24  * \par Developer Documentation for Asterisk
25  * This is the main developer documentation for Asterisk. It is 
26  * generated by running "make progdocs".
27  * \par Additional documentation
28  * \arg \ref DevDoc 
29  * \arg \ref ConfigFiles
30  *
31  * \section copyright Copyright and author
32  *
33  * Copyright (C) 1999 - 2005, Digium, Inc.
34  * Asterisk is a trade mark registered by Digium, Inc.
35  *
36  * \author Mark Spencer <markster@digium.com>
37  * Also see \ref AstCREDITS
38  *
39  * \section license License
40  * See http://www.asterisk.org for more information about
41  * the Asterisk project. Please do not directly contact
42  * any of the maintainers of this project for assistance;
43  * the project provides a web site, mailing lists and IRC
44  * channels for your use.
45  *
46  * This program is free software, distributed under the terms of
47  * the GNU General Public License Version 2. See the LICENSE file
48  * at the top of the source tree.
49  *
50  * \verbinclude LICENSE
51  *
52  */
53
54 /*! \file
55   \brief Top level source file for Asterisk  - the Open Source PBX. Implementation
56   of PBX core functions and CLI interface.
57   
58  */
59
60 #include <unistd.h>
61 #include <stdlib.h>
62 #include <sys/time.h>
63 #include <fcntl.h>
64 #include <stdio.h>
65 #include <signal.h>
66 #include <sched.h>
67 #include <sys/socket.h>
68 #include <sys/un.h>
69 #include <sys/wait.h>
70 #include <string.h>
71 #include <errno.h>
72 #include <ctype.h>
73 #include <sys/resource.h>
74 #include <grp.h>
75 #include <pwd.h>
76 #include <sys/stat.h>
77 #include <regex.h>
78
79 #ifdef linux
80 #include <sys/prctl.h>
81 #endif
82
83 #if  defined(__FreeBSD__) || defined( __NetBSD__ ) || defined(SOLARIS)
84 #include <netdb.h>
85 #if defined(SOLARIS)
86 extern int daemon(int, int);  /* defined in libresolv of all places */
87 #endif
88 #endif
89
90 #include "asterisk.h"
91
92 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
93
94 #include "asterisk/logger.h"
95 #include "asterisk/options.h"
96 #include "asterisk/cli.h"
97 #include "asterisk/channel.h"
98 #include "asterisk/ulaw.h"
99 #include "asterisk/alaw.h"
100 #include "asterisk/callerid.h"
101 #include "asterisk/module.h"
102 #include "asterisk/image.h"
103 #include "asterisk/tdd.h"
104 #include "asterisk/term.h"
105 #include "asterisk/manager.h"
106 #include "asterisk/cdr.h"
107 #include "asterisk/pbx.h"
108 #include "asterisk/enum.h"
109 #include "asterisk/rtp.h"
110 #if defined(T38_SUPPORT)
111 #include "asterisk/udptl.h"
112 #endif
113 #include "asterisk/app.h"
114 #include "asterisk/lock.h"
115 #include "asterisk/utils.h"
116 #include "asterisk/file.h"
117 #include "asterisk/io.h"
118 #include "asterisk/lock.h"
119 #include "editline/histedit.h"
120 #include "asterisk/config.h"
121 #include "asterisk/version.h"
122 #include "asterisk/linkedlists.h"
123 #include "asterisk/devicestate.h"
124 #include "asterisk/compat.h"
125
126 #include "asterisk/doxyref.h"           /* Doxygen documentation */
127
128 #include "defaults.h"
129
130 #ifndef AF_LOCAL
131 #define AF_LOCAL AF_UNIX
132 #define PF_LOCAL PF_UNIX
133 #endif
134
135 #define AST_MAX_CONNECTS 128
136 #define NUM_MSGS 64
137
138 /*! \brief Welcome message when starting a CLI interface */
139 #define WELCOME_MESSAGE \
140         ast_verbose("Asterisk " ASTERISK_VERSION ", Copyright (C) 1999 - 2006 Digium, Inc. and others.\n"); \
141         ast_verbose("Created by Mark Spencer <markster@digium.com>\n"); \
142         ast_verbose("Asterisk comes with ABSOLUTELY NO WARRANTY; type 'show warranty' for details.\n"); \
143         ast_verbose("This is free software, with components licensed under the GNU General Public\n"); \
144         ast_verbose("License version 2 and other licenses; you are welcome to redistribute it under\n"); \
145         ast_verbose("certain conditions. Type 'show license' for details.\n"); \
146         ast_verbose("=========================================================================\n")
147
148 /*! \defgroup main_options 
149  \brief Main configuration options from \ref Config_ast "asterisk.conf" or 
150   the operating system command line when starting Asterisk 
151   Some of them can be changed in the CLI 
152  */
153 /*! @{ */
154
155 struct ast_flags ast_options = { AST_DEFAULT_OPTIONS };
156
157 int option_verbose = 0;                         /*!< Verbosity level */
158 int option_debug = 0;                           /*!< Debug level */
159
160 double option_maxload = 0.0;                    /*!< Max load avg on system */
161 int option_maxcalls = 0;                        /*!< Max number of active calls */
162
163 /*! @} */
164
165 char record_cache_dir[AST_CACHE_DIR_LEN] = AST_TMP_DIR;
166 char debug_filename[AST_FILENAME_MAX] = "";
167
168 static int ast_socket = -1;             /*!< UNIX Socket for allowing remote control */
169 static int ast_consock = -1;            /*!< UNIX Socket for controlling another asterisk */
170 int ast_mainpid;
171 struct console {
172         int fd;                         /*!< File descriptor */
173         int p[2];                       /*!< Pipe */
174         pthread_t t;                    /*!< Thread of handler */
175 };
176
177 struct ast_atexit {
178         void (*func)(void);
179         AST_LIST_ENTRY(ast_atexit) list;
180 };
181
182 static AST_LIST_HEAD_STATIC(atexits, ast_atexit);
183
184 time_t ast_startuptime;
185 time_t ast_lastreloadtime;
186
187 static History *el_hist = NULL;
188 static EditLine *el = NULL;
189 static char *remotehostname;
190
191 struct console consoles[AST_MAX_CONNECTS];
192
193 char defaultlanguage[MAX_LANGUAGE] = DEFAULT_LANGUAGE;
194
195 static int ast_el_add_history(char *);
196 static int ast_el_read_history(char *);
197 static int ast_el_write_history(char *);
198
199 char ast_config_AST_CONFIG_DIR[AST_CONFIG_MAX_PATH];
200 char ast_config_AST_CONFIG_FILE[AST_CONFIG_MAX_PATH];
201 char ast_config_AST_MODULE_DIR[AST_CONFIG_MAX_PATH];
202 char ast_config_AST_SPOOL_DIR[AST_CONFIG_MAX_PATH];
203 char ast_config_AST_MONITOR_DIR[AST_CONFIG_MAX_PATH];
204 char ast_config_AST_VAR_DIR[AST_CONFIG_MAX_PATH];
205 char ast_config_AST_LOG_DIR[AST_CONFIG_MAX_PATH];
206 char ast_config_AST_AGI_DIR[AST_CONFIG_MAX_PATH];
207 char ast_config_AST_DB[AST_CONFIG_MAX_PATH];
208 char ast_config_AST_KEY_DIR[AST_CONFIG_MAX_PATH];
209 char ast_config_AST_PID[AST_CONFIG_MAX_PATH];
210 char ast_config_AST_SOCKET[AST_CONFIG_MAX_PATH];
211 char ast_config_AST_RUN_DIR[AST_CONFIG_MAX_PATH];
212 char ast_config_AST_RUN_USER[AST_CONFIG_MAX_PATH];
213 char ast_config_AST_RUN_GROUP[AST_CONFIG_MAX_PATH];
214 char ast_config_AST_CTL_PERMISSIONS[AST_CONFIG_MAX_PATH];
215 char ast_config_AST_CTL_OWNER[AST_CONFIG_MAX_PATH] = "\0";
216 char ast_config_AST_CTL_GROUP[AST_CONFIG_MAX_PATH] = "\0";
217 char ast_config_AST_CTL[AST_CONFIG_MAX_PATH] = "asterisk.ctl";
218 char ast_config_AST_SYSTEM_NAME[20]="";
219
220 static char *_argv[256];
221 static int shuttingdown = 0;
222 static int restartnow = 0;
223 static pthread_t consolethread = AST_PTHREADT_NULL;
224
225 static char randompool[256];
226
227 #if !defined(LOW_MEMORY)
228 struct file_version {
229         AST_LIST_ENTRY(file_version) list;
230         const char *file;
231         char *version;
232 };
233
234 static AST_LIST_HEAD_STATIC(file_versions, file_version);
235
236 void ast_register_file_version(const char *file, const char *version)
237 {
238         struct file_version *new;
239         char *work;
240         size_t version_length;
241
242         work = ast_strdupa(version);
243         work = ast_strip(ast_strip_quoted(work, "$", "$"));
244         version_length = strlen(work) + 1;
245         
246         if (!(new = ast_calloc(1, sizeof(*new) + version_length)))
247                 return;
248
249         new->file = file;
250         new->version = (char *) new + sizeof(*new);
251         memcpy(new->version, work, version_length);
252         AST_LIST_LOCK(&file_versions);
253         AST_LIST_INSERT_HEAD(&file_versions, new, list);
254         AST_LIST_UNLOCK(&file_versions);
255 }
256
257 void ast_unregister_file_version(const char *file)
258 {
259         struct file_version *find;
260
261         AST_LIST_LOCK(&file_versions);
262         AST_LIST_TRAVERSE_SAFE_BEGIN(&file_versions, find, list) {
263                 if (!strcasecmp(find->file, file)) {
264                         AST_LIST_REMOVE_CURRENT(&file_versions, list);
265                         break;
266                 }
267         }
268         AST_LIST_TRAVERSE_SAFE_END;
269         AST_LIST_UNLOCK(&file_versions);
270         if (find)
271                 free(find);
272 }
273
274 static char show_version_files_help[] = 
275 "Usage: show version files [like <pattern>]\n"
276 "       Shows the revision numbers of the files used to build this copy of Asterisk.\n"
277 "       Optional regular expression pattern is used to filter the file list.\n";
278
279 /*! CLI command to list module versions */
280 static int handle_show_version_files(int fd, int argc, char *argv[])
281 {
282 #define FORMAT "%-25.25s %-40.40s\n"
283         struct file_version *iterator;
284         regex_t regexbuf;
285         int havepattern = 0;
286         int havename = 0;
287         int count_files = 0;
288
289         switch (argc) {
290         case 5:
291                 if (!strcasecmp(argv[3], "like")) {
292                         if (regcomp(&regexbuf, argv[4], REG_EXTENDED | REG_NOSUB))
293                                 return RESULT_SHOWUSAGE;
294                         havepattern = 1;
295                 } else
296                         return RESULT_SHOWUSAGE;
297                 break;
298         case 4:
299                 havename = 1;
300                 break;
301         case 3:
302                 break;
303         default:
304                 return RESULT_SHOWUSAGE;
305         }
306
307         ast_cli(fd, FORMAT, "File", "Revision");
308         ast_cli(fd, FORMAT, "----", "--------");
309         AST_LIST_LOCK(&file_versions);
310         AST_LIST_TRAVERSE(&file_versions, iterator, list) {
311                 if (havename && strcasecmp(iterator->file, argv[3]))
312                         continue;
313
314                 if (havepattern && regexec(&regexbuf, iterator->file, 0, NULL, 0))
315                         continue;
316
317                 ast_cli(fd, FORMAT, iterator->file, iterator->version);
318                 count_files++;
319                 if (havename)
320                         break;
321         }
322         AST_LIST_UNLOCK(&file_versions);
323         if (!havename) {
324                 ast_cli(fd, "%d files listed.\n", count_files);
325         }
326
327         if (havepattern)
328                 regfree(&regexbuf);
329
330         return RESULT_SUCCESS;
331 #undef FORMAT
332 }
333
334 static char *complete_show_version_files(const char *line, const char *word, int pos, int state)
335 {
336         struct file_version *find;
337         int which = 0;
338         char *ret = NULL;
339         int matchlen = strlen(word);
340
341         if (pos != 3)
342                 return NULL;
343
344         AST_LIST_LOCK(&file_versions);
345         AST_LIST_TRAVERSE(&file_versions, find, list) {
346                 if (!strncasecmp(word, find->file, matchlen)) {
347                         if (++which > state) {
348                                 ret = strdup(find->file);
349                                 break;
350                         }
351                 }
352         }
353         AST_LIST_UNLOCK(&file_versions);
354
355         return ret;
356 }
357 #endif /* ! LOW_MEMORY */
358
359 int ast_register_atexit(void (*func)(void))
360 {
361         int res = -1;
362         struct ast_atexit *ae;
363         ast_unregister_atexit(func);    
364         AST_LIST_LOCK(&atexits);
365         if ((ae = ast_calloc(1, sizeof(*ae)))) {
366                 AST_LIST_INSERT_HEAD(&atexits, ae, list);
367                 ae->func = func;
368                 res = 0;
369         }
370         AST_LIST_UNLOCK(&atexits);
371         return res;
372 }
373
374 void ast_unregister_atexit(void (*func)(void))
375 {
376         struct ast_atexit *ae;
377         AST_LIST_LOCK(&atexits);
378         AST_LIST_TRAVERSE_SAFE_BEGIN(&atexits, ae, list) {
379                 if (ae->func == func) {
380                         AST_LIST_REMOVE_CURRENT(&atexits, list);
381                         break;
382                 }
383         }
384         AST_LIST_TRAVERSE_SAFE_END
385         AST_LIST_UNLOCK(&atexits);
386 }
387
388 static int fdprint(int fd, const char *s)
389 {
390         return write(fd, s, strlen(s) + 1);
391 }
392
393 /*! NULL handler so we can collect the child exit status */
394 static void null_sig_handler(int signal)
395 {
396
397 }
398
399 AST_MUTEX_DEFINE_STATIC(safe_system_lock);
400 static unsigned int safe_system_level = 0;
401 static void *safe_system_prev_handler;
402
403 int ast_safe_system(const char *s)
404 {
405         pid_t pid;
406         int x;
407         int res;
408         struct rusage rusage;
409         int status;
410         unsigned int level;
411
412         /* keep track of how many ast_safe_system() functions
413            are running at this moment
414         */
415         ast_mutex_lock(&safe_system_lock);
416         level = safe_system_level++;
417
418         /* only replace the handler if it has not already been done */
419         if (level == 0)
420                 safe_system_prev_handler = signal(SIGCHLD, null_sig_handler);
421
422         ast_mutex_unlock(&safe_system_lock);
423
424         pid = fork();
425
426         if (pid == 0) {
427                 /* Close file descriptors and launch system command */
428                 for (x = STDERR_FILENO + 1; x < 4096; x++)
429                         close(x);
430                 execl("/bin/sh", "/bin/sh", "-c", s, NULL);
431                 exit(1);
432         } else if (pid > 0) {
433                 for(;;) {
434                         res = wait4(pid, &status, 0, &rusage);
435                         if (res > -1) {
436                                 res = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
437                                 break;
438                         } else if (errno != EINTR) 
439                                 break;
440                 }
441         } else {
442                 ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno));
443                 res = -1;
444         }
445
446         ast_mutex_lock(&safe_system_lock);
447         level = --safe_system_level;
448
449         /* only restore the handler if we are the last one */
450         if (level == 0)
451                 signal(SIGCHLD, safe_system_prev_handler);
452
453         ast_mutex_unlock(&safe_system_lock);
454
455         return res;
456 }
457
458 /*!
459  * write the string to all attached console clients
460  */
461 static void ast_network_puts(const char *string)
462 {
463         int x;
464         for (x=0;x<AST_MAX_CONNECTS; x++) {
465                 if (consoles[x].fd > -1) 
466                         fdprint(consoles[x].p[1], string);
467         }
468 }
469
470 /*!
471  * write the string to the console, and all attached
472  * console clients
473  */
474 void ast_console_puts(const char *string)
475 {
476         fputs(string, stdout);
477         fflush(stdout);
478         ast_network_puts(string);
479 }
480
481 static void network_verboser(const char *s, int pos, int replace, int complete)
482         /* ARGUSED */
483 {
484         if (replace) {
485                 char *t;
486                 if ((t = alloca(strlen(s) + 2))) {
487                         sprintf(t, "\r%s", s);
488                         if (complete)
489                                 ast_network_puts(t);
490                 } else {
491                         ast_log(LOG_ERROR, "Out of memory\n");
492                         ast_network_puts(s);
493                 }
494         } else {
495                 if (complete)
496                         ast_network_puts(s);
497         }
498 }
499
500 static pthread_t lthread;
501
502 static void *netconsole(void *vconsole)
503 {
504         struct console *con = vconsole;
505         char hostname[MAXHOSTNAMELEN]="";
506         char tmp[512];
507         int res;
508         struct pollfd fds[2];
509         
510         if (gethostname(hostname, sizeof(hostname)-1))
511                 ast_copy_string(hostname, "<Unknown>", sizeof(hostname));
512         snprintf(tmp, sizeof(tmp), "%s/%d/%s\n", hostname, ast_mainpid, ASTERISK_VERSION);
513         fdprint(con->fd, tmp);
514         for(;;) {
515                 fds[0].fd = con->fd;
516                 fds[0].events = POLLIN;
517                 fds[0].revents = 0;
518                 fds[1].fd = con->p[0];
519                 fds[1].events = POLLIN;
520                 fds[1].revents = 0;
521
522                 res = poll(fds, 2, -1);
523                 if (res < 0) {
524                         if (errno != EINTR)
525                                 ast_log(LOG_WARNING, "poll returned < 0: %s\n", strerror(errno));
526                         continue;
527                 }
528                 if (fds[0].revents) {
529                         res = read(con->fd, tmp, sizeof(tmp));
530                         if (res < 1) {
531                                 break;
532                         }
533                         tmp[res] = 0;
534                         ast_cli_command(con->fd, tmp);
535                 }
536                 if (fds[1].revents) {
537                         res = read(con->p[0], tmp, sizeof(tmp));
538                         if (res < 1) {
539                                 ast_log(LOG_ERROR, "read returned %d\n", res);
540                                 break;
541                         }
542                         res = write(con->fd, tmp, res);
543                         if (res < 1)
544                                 break;
545                 }
546         }
547         if (option_verbose > 2) 
548                 ast_verbose(VERBOSE_PREFIX_3 "Remote UNIX connection disconnected\n");
549         close(con->fd);
550         close(con->p[0]);
551         close(con->p[1]);
552         con->fd = -1;
553         
554         return NULL;
555 }
556
557 static void *listener(void *unused)
558 {
559         struct sockaddr_un sunaddr;
560         int s;
561         socklen_t len;
562         int x;
563         int flags;
564         struct pollfd fds[1];
565         pthread_attr_t attr;
566         pthread_attr_init(&attr);
567         pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
568         for(;;) {
569                 if (ast_socket < 0)
570                         return NULL;
571                 fds[0].fd = ast_socket;
572                 fds[0].events= POLLIN;
573                 s = poll(fds, 1, -1);
574                 if (s < 0) {
575                         if (errno != EINTR)
576                                 ast_log(LOG_WARNING, "poll returned error: %s\n", strerror(errno));
577                         continue;
578                 }
579                 len = sizeof(sunaddr);
580                 s = accept(ast_socket, (struct sockaddr *)&sunaddr, &len);
581                 if (s < 0) {
582                         if (errno != EINTR)
583                                 ast_log(LOG_WARNING, "Accept returned %d: %s\n", s, strerror(errno));
584                 } else {
585                         for (x=0;x<AST_MAX_CONNECTS;x++) {
586                                 if (consoles[x].fd < 0) {
587                                         if (socketpair(AF_LOCAL, SOCK_STREAM, 0, consoles[x].p)) {
588                                                 ast_log(LOG_ERROR, "Unable to create pipe: %s\n", strerror(errno));
589                                                 consoles[x].fd = -1;
590                                                 fdprint(s, "Server failed to create pipe\n");
591                                                 close(s);
592                                                 break;
593                                         }
594                                         flags = fcntl(consoles[x].p[1], F_GETFL);
595                                         fcntl(consoles[x].p[1], F_SETFL, flags | O_NONBLOCK);
596                                         consoles[x].fd = s;
597                                         if (ast_pthread_create(&consoles[x].t, &attr, netconsole, &consoles[x])) {
598                                                 ast_log(LOG_ERROR, "Unable to spawn thread to handle connection: %s\n", strerror(errno));
599                                                 consoles[x].fd = -1;
600                                                 fdprint(s, "Server failed to spawn thread\n");
601                                                 close(s);
602                                         }
603                                         break;
604                                 }
605                         }
606                         if (x >= AST_MAX_CONNECTS) {
607                                 fdprint(s, "No more connections allowed\n");
608                                 ast_log(LOG_WARNING, "No more connections allowed\n");
609                                 close(s);
610                         } else if (consoles[x].fd > -1) {
611                                 if (option_verbose > 2) 
612                                         ast_verbose(VERBOSE_PREFIX_3 "Remote UNIX connection\n");
613                         }
614                 }
615         }
616         return NULL;
617 }
618
619 static int ast_makesocket(void)
620 {
621         struct sockaddr_un sunaddr;
622         int res;
623         int x;
624         uid_t uid = -1;
625         gid_t gid = -1;
626
627         for (x = 0; x < AST_MAX_CONNECTS; x++)  
628                 consoles[x].fd = -1;
629         unlink(ast_config_AST_SOCKET);
630         ast_socket = socket(PF_LOCAL, SOCK_STREAM, 0);
631         if (ast_socket < 0) {
632                 ast_log(LOG_WARNING, "Unable to create control socket: %s\n", strerror(errno));
633                 return -1;
634         }               
635         memset(&sunaddr, 0, sizeof(sunaddr));
636         sunaddr.sun_family = AF_LOCAL;
637         ast_copy_string(sunaddr.sun_path, ast_config_AST_SOCKET, sizeof(sunaddr.sun_path));
638         res = bind(ast_socket, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
639         if (res) {
640                 ast_log(LOG_WARNING, "Unable to bind socket to %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
641                 close(ast_socket);
642                 ast_socket = -1;
643                 return -1;
644         }
645         res = listen(ast_socket, 2);
646         if (res < 0) {
647                 ast_log(LOG_WARNING, "Unable to listen on socket %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
648                 close(ast_socket);
649                 ast_socket = -1;
650                 return -1;
651         }
652         ast_register_verbose(network_verboser);
653         ast_pthread_create(&lthread, NULL, listener, NULL);
654
655         if (!ast_strlen_zero(ast_config_AST_CTL_OWNER)) {
656                 struct passwd *pw;
657                 if ((pw = getpwnam(ast_config_AST_CTL_OWNER)) == NULL) {
658                         ast_log(LOG_WARNING, "Unable to find uid of user %s\n", ast_config_AST_CTL_OWNER);
659                 } else {
660                         uid = pw->pw_uid;
661                 }
662         }
663                 
664         if (!ast_strlen_zero(ast_config_AST_CTL_GROUP)) {
665                 struct group *grp;
666                 if ((grp = getgrnam(ast_config_AST_CTL_GROUP)) == NULL) {
667                         ast_log(LOG_WARNING, "Unable to find gid of group %s\n", ast_config_AST_CTL_GROUP);
668                 } else {
669                         gid = grp->gr_gid;
670                 }
671         }
672
673         if (chown(ast_config_AST_SOCKET, uid, gid) < 0)
674                 ast_log(LOG_WARNING, "Unable to change ownership of %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
675
676         if (!ast_strlen_zero(ast_config_AST_CTL_PERMISSIONS)) {
677                 int p1;
678                 mode_t p;
679                 sscanf(ast_config_AST_CTL_PERMISSIONS, "%o", &p1);
680                 p = p1;
681                 if ((chmod(ast_config_AST_SOCKET, p)) < 0)
682                         ast_log(LOG_WARNING, "Unable to change file permissions of %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
683         }
684
685         return 0;
686 }
687
688 static int ast_tryconnect(void)
689 {
690         struct sockaddr_un sunaddr;
691         int res;
692         ast_consock = socket(PF_LOCAL, SOCK_STREAM, 0);
693         if (ast_consock < 0) {
694                 ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno));
695                 return 0;
696         }
697         memset(&sunaddr, 0, sizeof(sunaddr));
698         sunaddr.sun_family = AF_LOCAL;
699         ast_copy_string(sunaddr.sun_path, (char *)ast_config_AST_SOCKET, sizeof(sunaddr.sun_path));
700         res = connect(ast_consock, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
701         if (res) {
702                 close(ast_consock);
703                 ast_consock = -1;
704                 return 0;
705         } else
706                 return 1;
707 }
708
709 /*! Urgent handler
710  Called by soft_hangup to interrupt the poll, read, or other
711  system call.  We don't actually need to do anything though.  
712  Remember: Cannot EVER ast_log from within a signal handler 
713  SLD: seems to be some pthread activity relating to the printf anyway:
714  which is leading to a deadlock? 
715  */
716 static void urg_handler(int num)
717 {
718 #if 0
719         if (option_debug > 2) 
720                 printf("-- Asterisk Urgent handler\n");
721 #endif
722         signal(num, urg_handler);
723         return;
724 }
725
726 static void hup_handler(int num)
727 {
728         if (option_verbose > 1) 
729                 printf("Received HUP signal -- Reloading configs\n");
730         if (restartnow)
731                 execvp(_argv[0], _argv);
732         /* XXX This could deadlock XXX */
733         ast_module_reload(NULL);
734         signal(num, hup_handler);
735 }
736
737 static void child_handler(int sig)
738 {
739         /* Must not ever ast_log or ast_verbose within signal handler */
740         int n, status;
741
742         /*
743          * Reap all dead children -- not just one
744          */
745         for (n = 0; wait4(-1, &status, WNOHANG, NULL) > 0; n++)
746                 ;
747         if (n == 0 && option_debug)     
748                 printf("Huh?  Child handler, but nobody there?\n");
749         signal(sig, child_handler);
750 }
751
752 /*! Set an X-term or screen title */
753 static void set_title(char *text)
754 {
755         if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
756                 fprintf(stdout, "\033]2;%s\007", text);
757 }
758
759 static void set_icon(char *text)
760 {
761         if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
762                 fprintf(stdout, "\033]1;%s\007", text);
763 }
764
765 /*! We set ourselves to a high priority, that we might pre-empt everything
766    else.  If your PBX has heavy activity on it, this is a good thing.  */
767 int ast_set_priority(int pri)
768 {
769         struct sched_param sched;
770         memset(&sched, 0, sizeof(sched));
771 #ifdef __linux__
772         if (pri) {  
773                 sched.sched_priority = 10;
774                 if (sched_setscheduler(0, SCHED_RR, &sched)) {
775                         ast_log(LOG_WARNING, "Unable to set high priority\n");
776                         return -1;
777                 } else
778                         if (option_verbose)
779                                 ast_verbose("Set to realtime thread\n");
780         } else {
781                 sched.sched_priority = 0;
782                 if (sched_setscheduler(0, SCHED_OTHER, &sched)) {
783                         ast_log(LOG_WARNING, "Unable to set normal priority\n");
784                         return -1;
785                 }
786         }
787 #else
788         if (pri) {
789                 if (setpriority(PRIO_PROCESS, 0, -10) == -1) {
790                         ast_log(LOG_WARNING, "Unable to set high priority\n");
791                         return -1;
792                 } else
793                         if (option_verbose)
794                                 ast_verbose("Set to high priority\n");
795         } else {
796                 if (setpriority(PRIO_PROCESS, 0, 0) == -1) {
797                         ast_log(LOG_WARNING, "Unable to set normal priority\n");
798                         return -1;
799                 }
800         }
801 #endif
802         return 0;
803 }
804
805 static void ast_run_atexits(void)
806 {
807         struct ast_atexit *ae;
808         AST_LIST_LOCK(&atexits);
809         AST_LIST_TRAVERSE(&atexits, ae, list) {
810                 if (ae->func) 
811                         ae->func();
812         }
813         AST_LIST_UNLOCK(&atexits);
814 }
815
816 static void quit_handler(int num, int nice, int safeshutdown, int restart)
817 {
818         char filename[80] = "";
819         time_t s,e;
820         int x;
821         /* Try to get as many CDRs as possible submitted to the backend engines (if in batch mode) */
822         ast_cdr_engine_term();
823         if (safeshutdown) {
824                 shuttingdown = 1;
825                 if (!nice) {
826                         /* Begin shutdown routine, hanging up active channels */
827                         ast_begin_shutdown(1);
828                         if (option_verbose && ast_opt_console)
829                                 ast_verbose("Beginning asterisk %s....\n", restart ? "restart" : "shutdown");
830                         time(&s);
831                         for(;;) {
832                                 time(&e);
833                                 /* Wait up to 15 seconds for all channels to go away */
834                                 if ((e - s) > 15)
835                                         break;
836                                 if (!ast_active_channels())
837                                         break;
838                                 if (!shuttingdown)
839                                         break;
840                                 /* Sleep 1/10 of a second */
841                                 usleep(100000);
842                         }
843                 } else {
844                         if (nice < 2)
845                                 ast_begin_shutdown(0);
846                         if (option_verbose && ast_opt_console)
847                                 ast_verbose("Waiting for inactivity to perform %s...\n", restart ? "restart" : "halt");
848                         for(;;) {
849                                 if (!ast_active_channels())
850                                         break;
851                                 if (!shuttingdown)
852                                         break;
853                                 sleep(1);
854                         }
855                 }
856
857                 if (!shuttingdown) {
858                         if (option_verbose && ast_opt_console)
859                                 ast_verbose("Asterisk %s cancelled.\n", restart ? "restart" : "shutdown");
860                         return;
861                 }
862         }
863         if (ast_opt_console || ast_opt_remote) {
864                 if (getenv("HOME")) 
865                         snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
866                 if (!ast_strlen_zero(filename))
867                         ast_el_write_history(filename);
868                 if (el != NULL)
869                         el_end(el);
870                 if (el_hist != NULL)
871                         history_end(el_hist);
872         }
873         if (option_verbose)
874                 ast_verbose("Executing last minute cleanups\n");
875         ast_run_atexits();
876         /* Called on exit */
877         if (option_verbose && ast_opt_console)
878                 ast_verbose("Asterisk %s ending (%d).\n", ast_active_channels() ? "uncleanly" : "cleanly", num);
879         else if (option_debug)
880                 ast_log(LOG_DEBUG, "Asterisk ending (%d).\n", num);
881         manager_event(EVENT_FLAG_SYSTEM, "Shutdown", "Shutdown: %s\r\nRestart: %s\r\n", ast_active_channels() ? "Uncleanly" : "Cleanly", restart ? "True" : "False");
882         if (ast_socket > -1) {
883                 close(ast_socket);
884                 ast_socket = -1;
885                 unlink(ast_config_AST_SOCKET);
886                 pthread_cancel(lthread);
887         }
888         if (ast_consock > -1)
889                 close(ast_consock);
890         if (!ast_opt_remote)
891                 unlink(ast_config_AST_PID);
892         printf(term_quit());
893         if (restart) {
894                 if (option_verbose || ast_opt_console)
895                         ast_verbose("Preparing for Asterisk restart...\n");
896                 /* Mark all FD's for closing on exec */
897                 for (x=3;x<32768;x++) {
898                         fcntl(x, F_SETFD, FD_CLOEXEC);
899                 }
900                 if (option_verbose || ast_opt_console)
901                         ast_verbose("Restarting Asterisk NOW...\n");
902                 restartnow = 1;
903
904                 /* close logger */
905                 close_logger();
906
907                 /* If there is a consolethread running send it a SIGHUP 
908                    so it can execvp, otherwise we can do it ourselves */
909                 if ((consolethread != AST_PTHREADT_NULL) && (consolethread != pthread_self())) {
910                         pthread_kill(consolethread, SIGHUP);
911                         /* Give the signal handler some time to complete */
912                         sleep(2);
913                 } else
914                         execvp(_argv[0], _argv);
915         
916         } else {
917                 /* close logger */
918                 close_logger();
919         }
920         exit(0);
921 }
922
923 static void __quit_handler(int num)
924 {
925         quit_handler(num, 0, 1, 0);
926 }
927
928 static const char *fix_header(char *outbuf, int maxout, const char *s, char *cmp)
929 {
930         const char *c;
931         if (!strncmp(s, cmp, strlen(cmp))) {
932                 c = s + strlen(cmp);
933                 term_color(outbuf, cmp, COLOR_GRAY, 0, maxout);
934                 return c;
935         }
936         return NULL;
937 }
938
939 static void console_verboser(const char *s, int pos, int replace, int complete)
940 {
941         char tmp[80];
942         const char *c=NULL;
943         /* Return to the beginning of the line */
944         if (!pos) {
945                 fprintf(stdout, "\r");
946                 if ((c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_4)) ||
947                         (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_3)) ||
948                         (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_2)) ||
949                         (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_1)))
950                         fputs(tmp, stdout);
951         }
952         if (c)
953                 fputs(c + pos,stdout);
954         else
955                 fputs(s + pos,stdout);
956         fflush(stdout);
957         if (complete) {
958                 /* Wake up a poll()ing console */
959                 if (ast_opt_console && consolethread != AST_PTHREADT_NULL)
960                         pthread_kill(consolethread, SIGURG);
961         }
962 }
963
964 static int ast_all_zeros(char *s)
965 {
966         while(*s) {
967                 if (*s > 32)
968                         return 0;
969                 s++;  
970         }
971         return 1;
972 }
973
974 static void consolehandler(char *s)
975 {
976         printf(term_end());
977         fflush(stdout);
978         /* Called when readline data is available */
979         if (s && !ast_all_zeros(s))
980                 ast_el_add_history(s);
981         /* Give the console access to the shell */
982         if (s) {
983                 /* The real handler for bang */
984                 if (s[0] == '!') {
985                         if (s[1])
986                                 ast_safe_system(s+1);
987                         else
988                                 ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
989                 } else 
990                 ast_cli_command(STDOUT_FILENO, s);
991         } else
992                 fprintf(stdout, "\nUse \"quit\" to exit\n");
993 }
994
995 static int remoteconsolehandler(char *s)
996 {
997         int ret = 0;
998         /* Called when readline data is available */
999         if (s && !ast_all_zeros(s))
1000                 ast_el_add_history(s);
1001         /* Give the console access to the shell */
1002         if (s) {
1003                 /* The real handler for bang */
1004                 if (s[0] == '!') {
1005                         if (s[1])
1006                                 ast_safe_system(s+1);
1007                         else
1008                                 ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
1009                         ret = 1;
1010                 }
1011                 if ((strncasecmp(s, "quit", 4) == 0 || strncasecmp(s, "exit", 4) == 0) &&
1012                     (s[4] == '\0' || isspace(s[4]))) {
1013                         quit_handler(0, 0, 0, 0);
1014                         ret = 1;
1015                 }
1016         } else
1017                 fprintf(stdout, "\nUse \"quit\" to exit\n");
1018
1019         return ret;
1020 }
1021
1022 static char abort_halt_help[] = 
1023 "Usage: abort shutdown\n"
1024 "       Causes Asterisk to abort an executing shutdown or restart, and resume normal\n"
1025 "       call operations.\n";
1026
1027 static char shutdown_now_help[] = 
1028 "Usage: stop now\n"
1029 "       Shuts down a running Asterisk immediately, hanging up all active calls .\n";
1030
1031 static char shutdown_gracefully_help[] = 
1032 "Usage: stop gracefully\n"
1033 "       Causes Asterisk to not accept new calls, and exit when all\n"
1034 "       active calls have terminated normally.\n";
1035
1036 static char shutdown_when_convenient_help[] = 
1037 "Usage: stop when convenient\n"
1038 "       Causes Asterisk to perform a shutdown when all active calls have ended.\n";
1039
1040 static char restart_now_help[] = 
1041 "Usage: restart now\n"
1042 "       Causes Asterisk to hangup all calls and exec() itself performing a cold\n"
1043 "       restart.\n";
1044
1045 static char restart_gracefully_help[] = 
1046 "Usage: restart gracefully\n"
1047 "       Causes Asterisk to stop accepting new calls and exec() itself performing a cold\n"
1048 "       restart when all active calls have ended.\n";
1049
1050 static char restart_when_convenient_help[] = 
1051 "Usage: restart when convenient\n"
1052 "       Causes Asterisk to perform a cold restart when all active calls have ended.\n";
1053
1054 static char bang_help[] =
1055 "Usage: !<command>\n"
1056 "       Executes a given shell command\n";
1057
1058 static char show_warranty_help[] =
1059 "Usage: show warranty\n"
1060 "       Shows the warranty (if any) for this copy of Asterisk.\n";
1061
1062 static char show_license_help[] =
1063 "Usage: show license\n"
1064 "       Shows the license(s) for this copy of Asterisk.\n";
1065
1066 #if 0
1067 static int handle_quit(int fd, int argc, char *argv[])
1068 {
1069         if (argc != 1)
1070                 return RESULT_SHOWUSAGE;
1071         quit_handler(0, 0, 1, 0);
1072         return RESULT_SUCCESS;
1073 }
1074 #endif
1075
1076 static int handle_shutdown_now(int fd, int argc, char *argv[])
1077 {
1078         if (argc != 2)
1079                 return RESULT_SHOWUSAGE;
1080         quit_handler(0, 0 /* Not nice */, 1 /* safely */, 0 /* not restart */);
1081         return RESULT_SUCCESS;
1082 }
1083
1084 static int handle_shutdown_gracefully(int fd, int argc, char *argv[])
1085 {
1086         if (argc != 2)
1087                 return RESULT_SHOWUSAGE;
1088         quit_handler(0, 1 /* nicely */, 1 /* safely */, 0 /* no restart */);
1089         return RESULT_SUCCESS;
1090 }
1091
1092 static int handle_shutdown_when_convenient(int fd, int argc, char *argv[])
1093 {
1094         if (argc != 3)
1095                 return RESULT_SHOWUSAGE;
1096         ast_cli(fd, "Waiting for inactivity to perform halt\n");
1097         quit_handler(0, 2 /* really nicely */, 1 /* safely */, 0 /* don't restart */);
1098         return RESULT_SUCCESS;
1099 }
1100
1101 static int handle_restart_now(int fd, int argc, char *argv[])
1102 {
1103         if (argc != 2)
1104                 return RESULT_SHOWUSAGE;
1105         quit_handler(0, 0 /* not nicely */, 1 /* safely */, 1 /* restart */);
1106         return RESULT_SUCCESS;
1107 }
1108
1109 static int handle_restart_gracefully(int fd, int argc, char *argv[])
1110 {
1111         if (argc != 2)
1112                 return RESULT_SHOWUSAGE;
1113         quit_handler(0, 1 /* nicely */, 1 /* safely */, 1 /* restart */);
1114         return RESULT_SUCCESS;
1115 }
1116
1117 static int handle_restart_when_convenient(int fd, int argc, char *argv[])
1118 {
1119         if (argc != 3)
1120                 return RESULT_SHOWUSAGE;
1121         ast_cli(fd, "Waiting for inactivity to perform restart\n");
1122         quit_handler(0, 2 /* really nicely */, 1 /* safely */, 1 /* restart */);
1123         return RESULT_SUCCESS;
1124 }
1125
1126 static int handle_abort_halt(int fd, int argc, char *argv[])
1127 {
1128         if (argc != 2)
1129                 return RESULT_SHOWUSAGE;
1130         ast_cancel_shutdown();
1131         shuttingdown = 0;
1132         return RESULT_SUCCESS;
1133 }
1134
1135 static int handle_bang(int fd, int argc, char *argv[])
1136 {
1137         return RESULT_SUCCESS;
1138 }
1139 static const char *warranty_lines[] = {
1140         "\n",
1141         "                           NO WARRANTY\n",
1142         "\n",
1143         "BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\n",
1144         "FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN\n",
1145         "OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\n",
1146         "PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\n",
1147         "OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n",
1148         "MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS\n",
1149         "TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE\n",
1150         "PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\n",
1151         "REPAIR OR CORRECTION.\n",
1152         "\n",
1153         "IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\n",
1154         "WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\n",
1155         "REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\n",
1156         "INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\n",
1157         "OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\n",
1158         "TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\n",
1159         "YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\n",
1160         "PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\n",
1161         "POSSIBILITY OF SUCH DAMAGES.\n",
1162 };
1163
1164 static int show_warranty(int fd, int argc, char *argv[])
1165 {
1166         int x;
1167
1168         for (x = 0; x < sizeof(warranty_lines) / sizeof(warranty_lines[0]); x++)
1169                 ast_cli(fd, (char *) warranty_lines[x]);
1170
1171         return RESULT_SUCCESS;
1172 }
1173
1174 static const char *license_lines[] = {
1175         "\n",
1176         "This program is free software; you can redistribute it and/or modify\n",
1177         "it under the terms of the GNU General Public License version 2 as\n",
1178         "published by the Free Software Foundation.\n",
1179         "\n",
1180         "This program also contains components licensed under other licenses.\n",
1181         "They include:\n",
1182         "\n",
1183         "This program is distributed in the hope that it will be useful,\n",
1184         "but WITHOUT ANY WARRANTY; without even the implied warranty of\n",
1185         "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n",
1186         "GNU General Public License for more details.\n",
1187         "\n",
1188         "You should have received a copy of the GNU General Public License\n",
1189         "along with this program; if not, write to the Free Software\n",
1190         "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\n",
1191 };
1192
1193 static int show_license(int fd, int argc, char *argv[])
1194 {
1195         int x;
1196
1197         for (x = 0; x < sizeof(license_lines) / sizeof(license_lines[0]); x++)
1198                 ast_cli(fd, (char *) license_lines[x]);
1199
1200         return RESULT_SUCCESS;
1201 }
1202
1203 #define ASTERISK_PROMPT "*CLI> "
1204
1205 #define ASTERISK_PROMPT2 "%s*CLI> "
1206
1207 static struct ast_cli_entry core_cli[] = {
1208         { { "abort", "halt", NULL }, handle_abort_halt,
1209           "Cancel a running halt", abort_halt_help },
1210         { { "stop", "now", NULL }, handle_shutdown_now,
1211           "Shut down Asterisk immediately", shutdown_now_help },
1212         { { "stop", "gracefully", NULL }, handle_shutdown_gracefully,
1213           "Gracefully shut down Asterisk", shutdown_gracefully_help },
1214         { { "stop", "when","convenient", NULL }, handle_shutdown_when_convenient,
1215           "Shut down Asterisk at empty call volume", shutdown_when_convenient_help },
1216         { { "restart", "now", NULL }, handle_restart_now,
1217           "Restart Asterisk immediately", restart_now_help },
1218         { { "restart", "gracefully", NULL }, handle_restart_gracefully,
1219           "Restart Asterisk gracefully", restart_gracefully_help },
1220         { { "restart", "when", "convenient", NULL }, handle_restart_when_convenient,
1221           "Restart Asterisk at empty call volume", restart_when_convenient_help },
1222         { { "show", "warranty", NULL }, show_warranty,
1223           "Show the warranty (if any) for this copy of Asterisk", show_warranty_help },
1224         { { "show", "license", NULL }, show_license,
1225           "Show the license(s) for this copy of Asterisk", show_license_help },
1226         { { "!", NULL }, handle_bang,
1227           "Execute a shell command", bang_help },
1228 #if !defined(LOW_MEMORY)
1229         { { "show", "version", "files", NULL }, handle_show_version_files,
1230           "Show versions of files used to build Asterisk", show_version_files_help, complete_show_version_files },
1231 #endif /* ! LOW_MEMORY */
1232 };
1233
1234 static int ast_el_read_char(EditLine *el, char *cp)
1235 {
1236         int num_read=0;
1237         int lastpos=0;
1238         struct pollfd fds[2];
1239         int res;
1240         int max;
1241         char buf[512];
1242
1243         for (;;) {
1244                 max = 1;
1245                 fds[0].fd = ast_consock;
1246                 fds[0].events = POLLIN;
1247                 if (!ast_opt_exec) {
1248                         fds[1].fd = STDIN_FILENO;
1249                         fds[1].events = POLLIN;
1250                         max++;
1251                 }
1252                 res = poll(fds, max, -1);
1253                 if (res < 0) {
1254                         if (errno == EINTR)
1255                                 continue;
1256                         ast_log(LOG_ERROR, "poll failed: %s\n", strerror(errno));
1257                         break;
1258                 }
1259
1260                 if (!ast_opt_exec && fds[1].revents) {
1261                         num_read = read(STDIN_FILENO, cp, 1);
1262                         if (num_read < 1) {
1263                                 break;
1264                         } else 
1265                                 return (num_read);
1266                 }
1267                 if (fds[0].revents) {
1268                         res = read(ast_consock, buf, sizeof(buf) - 1);
1269                         /* if the remote side disappears exit */
1270                         if (res < 1) {
1271                                 fprintf(stderr, "\nDisconnected from Asterisk server\n");
1272                                 if (!ast_opt_reconnect) {
1273                                         quit_handler(0, 0, 0, 0);
1274                                 } else {
1275                                         int tries;
1276                                         int reconnects_per_second = 20;
1277                                         fprintf(stderr, "Attempting to reconnect for 30 seconds\n");
1278                                         for (tries=0;tries<30 * reconnects_per_second;tries++) {
1279                                                 if (ast_tryconnect()) {
1280                                                         fprintf(stderr, "Reconnect succeeded after %.3f seconds\n", 1.0 / reconnects_per_second * tries);
1281                                                         printf(term_quit());
1282                                                         WELCOME_MESSAGE;
1283                                                         break;
1284                                                 } else {
1285                                                         usleep(1000000 / reconnects_per_second);
1286                                                 }
1287                                         }
1288                                         if (tries >= 30 * reconnects_per_second) {
1289                                                 fprintf(stderr, "Failed to reconnect for 30 seconds.  Quitting.\n");
1290                                                 quit_handler(0, 0, 0, 0);
1291                                         }
1292                                 }
1293                         }
1294
1295                         buf[res] = '\0';
1296
1297                         if (!ast_opt_exec && !lastpos)
1298                                 write(STDOUT_FILENO, "\r", 1);
1299                         write(STDOUT_FILENO, buf, res);
1300                         if ((buf[res-1] == '\n') || (buf[res-2] == '\n')) {
1301                                 *cp = CC_REFRESH;
1302                                 return(1);
1303                         } else {
1304                                 lastpos = 1;
1305                         }
1306                 }
1307         }
1308
1309         *cp = '\0';
1310         return (0);
1311 }
1312
1313 static char *cli_prompt(EditLine *el)
1314 {
1315         static char prompt[200];
1316         char *pfmt;
1317         int color_used=0;
1318         char term_code[20];
1319
1320         if ((pfmt = getenv("ASTERISK_PROMPT"))) {
1321                 char *t = pfmt, *p = prompt;
1322                 memset(prompt, 0, sizeof(prompt));
1323                 while (*t != '\0' && *p < sizeof(prompt)) {
1324                         if (*t == '%') {
1325                                 char hostname[MAXHOSTNAMELEN]="";
1326                                 int i;
1327                                 time_t ts;
1328                                 struct tm tm;
1329 #ifdef linux
1330                                 FILE *LOADAVG;
1331 #endif
1332                                 int fgcolor = COLOR_WHITE, bgcolor = COLOR_BLACK;
1333
1334                                 t++;
1335                                 switch (*t) {
1336                                         case 'C': /* color */
1337                                                 t++;
1338                                                 if (sscanf(t, "%d;%d%n", &fgcolor, &bgcolor, &i) == 2) {
1339                                                         strncat(p, term_color_code(term_code, fgcolor, bgcolor, sizeof(term_code)),sizeof(prompt) - strlen(prompt) - 1);
1340                                                         t += i - 1;
1341                                                 } else if (sscanf(t, "%d%n", &fgcolor, &i) == 1) {
1342                                                         strncat(p, term_color_code(term_code, fgcolor, 0, sizeof(term_code)),sizeof(prompt) - strlen(prompt) - 1);
1343                                                         t += i - 1;
1344                                                 }
1345
1346                                                 /* If the color has been reset correctly, then there's no need to reset it later */
1347                                                 if ((fgcolor == COLOR_WHITE) && (bgcolor == COLOR_BLACK)) {
1348                                                         color_used = 0;
1349                                                 } else {
1350                                                         color_used = 1;
1351                                                 }
1352                                                 break;
1353                                         case 'd': /* date */
1354                                                 memset(&tm, 0, sizeof(tm));
1355                                                 time(&ts);
1356                                                 if (localtime_r(&ts, &tm)) {
1357                                                         strftime(p, sizeof(prompt) - strlen(prompt), "%Y-%m-%d", &tm);
1358                                                 }
1359                                                 break;
1360                                         case 'h': /* hostname */
1361                                                 if (!gethostname(hostname, sizeof(hostname) - 1)) {
1362                                                         strncat(p, hostname, sizeof(prompt) - strlen(prompt) - 1);
1363                                                 } else {
1364                                                         strncat(p, "localhost", sizeof(prompt) - strlen(prompt) - 1);
1365                                                 }
1366                                                 break;
1367                                         case 'H': /* short hostname */
1368                                                 if (!gethostname(hostname, sizeof(hostname) - 1)) {
1369                                                         for (i=0;i<sizeof(hostname);i++) {
1370                                                                 if (hostname[i] == '.') {
1371                                                                         hostname[i] = '\0';
1372                                                                         break;
1373                                                                 }
1374                                                         }
1375                                                         strncat(p, hostname, sizeof(prompt) - strlen(prompt) - 1);
1376                                                 } else {
1377                                                         strncat(p, "localhost", sizeof(prompt) - strlen(prompt) - 1);
1378                                                 }
1379                                                 break;
1380 #ifdef linux
1381                                         case 'l': /* load avg */
1382                                                 t++;
1383                                                 if ((LOADAVG = fopen("/proc/loadavg", "r"))) {
1384                                                         float avg1, avg2, avg3;
1385                                                         int actproc, totproc, npid, which;
1386                                                         fscanf(LOADAVG, "%f %f %f %d/%d %d",
1387                                                                 &avg1, &avg2, &avg3, &actproc, &totproc, &npid);
1388                                                         if (sscanf(t, "%d", &which) == 1) {
1389                                                                 switch (which) {
1390                                                                         case 1:
1391                                                                                 snprintf(p, sizeof(prompt) - strlen(prompt), "%.2f", avg1);
1392                                                                                 break;
1393                                                                         case 2:
1394                                                                                 snprintf(p, sizeof(prompt) - strlen(prompt), "%.2f", avg2);
1395                                                                                 break;
1396                                                                         case 3:
1397                                                                                 snprintf(p, sizeof(prompt) - strlen(prompt), "%.2f", avg3);
1398                                                                                 break;
1399                                                                         case 4:
1400                                                                                 snprintf(p, sizeof(prompt) - strlen(prompt), "%d/%d", actproc, totproc);
1401                                                                                 break;
1402                                                                         case 5:
1403                                                                                 snprintf(p, sizeof(prompt) - strlen(prompt), "%d", npid);
1404                                                                                 break;
1405                                                                 }
1406                                                         }
1407                                                 }
1408                                                 break;
1409 #endif
1410                                         case 't': /* time */
1411                                                 memset(&tm, 0, sizeof(tm));
1412                                                 time(&ts);
1413                                                 if (localtime_r(&ts, &tm)) {
1414                                                         strftime(p, sizeof(prompt) - strlen(prompt), "%H:%M:%S", &tm);
1415                                                 }
1416                                                 break;
1417                                         case '#': /* process console or remote? */
1418                                                 if (!ast_opt_remote) {
1419                                                         strncat(p, "#", sizeof(prompt) - strlen(prompt) - 1);
1420                                                 } else {
1421                                                         strncat(p, ">", sizeof(prompt) - strlen(prompt) - 1);
1422                                                 }
1423                                                 break;
1424                                         case '%': /* literal % */
1425                                                 strncat(p, "%", sizeof(prompt) - strlen(prompt) - 1);
1426                                                 break;
1427                                         case '\0': /* % is last character - prevent bug */
1428                                                 t--;
1429                                                 break;
1430                                 }
1431                                 while (*p != '\0') {
1432                                         p++;
1433                                 }
1434                                 t++;
1435                         } else {
1436                                 *p = *t;
1437                                 p++;
1438                                 t++;
1439                         }
1440                 }
1441                 if (color_used) {
1442                         /* Force colors back to normal at end */
1443                         term_color_code(term_code, COLOR_WHITE, COLOR_BLACK, sizeof(term_code));
1444                         if (strlen(term_code) > sizeof(prompt) - strlen(prompt)) {
1445                                 strncat(prompt + sizeof(prompt) - strlen(term_code) - 1, term_code, strlen(term_code));
1446                         } else {
1447                                 strncat(p, term_code, sizeof(term_code));
1448                         }
1449                 }
1450         } else if (remotehostname)
1451                 snprintf(prompt, sizeof(prompt), ASTERISK_PROMPT2, remotehostname);
1452         else
1453                 snprintf(prompt, sizeof(prompt), ASTERISK_PROMPT);
1454
1455         return(prompt); 
1456 }
1457
1458 static char **ast_el_strtoarr(char *buf)
1459 {
1460         char **match_list = NULL, *retstr;
1461         size_t match_list_len;
1462         int matches = 0;
1463
1464         match_list_len = 1;
1465         while ( (retstr = strsep(&buf, " ")) != NULL) {
1466
1467                 if (!strcmp(retstr, AST_CLI_COMPLETE_EOF))
1468                         break;
1469                 if (matches + 1 >= match_list_len) {
1470                         match_list_len <<= 1;
1471                         if (!(match_list = ast_realloc(match_list, match_list_len * sizeof(char *)))) {
1472                                 /* TODO: Handle memory allocation failure */
1473                         }
1474                 }
1475
1476                 match_list[matches++] = strdup(retstr);
1477         }
1478
1479         if (!match_list)
1480                 return (char **) NULL;
1481
1482         if (matches >= match_list_len) {
1483                 if (!(match_list = ast_realloc(match_list, (match_list_len + 1) * sizeof(char *)))) {
1484                         /* TODO: Handle memory allocation failure */
1485                 }
1486         }
1487
1488         match_list[matches] = (char *) NULL;
1489
1490         return match_list;
1491 }
1492
1493 static int ast_el_sort_compare(const void *i1, const void *i2)
1494 {
1495         char *s1, *s2;
1496
1497         s1 = ((char **)i1)[0];
1498         s2 = ((char **)i2)[0];
1499
1500         return strcasecmp(s1, s2);
1501 }
1502
1503 static int ast_cli_display_match_list(char **matches, int len, int max)
1504 {
1505         int i, idx, limit, count;
1506         int screenwidth = 0;
1507         int numoutput = 0, numoutputline = 0;
1508
1509         screenwidth = ast_get_termcols(STDOUT_FILENO);
1510
1511         /* find out how many entries can be put on one line, with two spaces between strings */
1512         limit = screenwidth / (max + 2);
1513         if (limit == 0)
1514                 limit = 1;
1515
1516         /* how many lines of output */
1517         count = len / limit;
1518         if (count * limit < len)
1519                 count++;
1520
1521         idx = 1;
1522
1523         qsort(&matches[0], (size_t)(len), sizeof(char *), ast_el_sort_compare);
1524
1525         for (; count > 0; count--) {
1526                 numoutputline = 0;
1527                 for (i=0; i < limit && matches[idx]; i++, idx++) {
1528
1529                         /* Don't print dupes */
1530                         if ( (matches[idx+1] != NULL && strcmp(matches[idx], matches[idx+1]) == 0 ) ) {
1531                                 i--;
1532                                 free(matches[idx]);
1533                                 matches[idx] = NULL;
1534                                 continue;
1535                         }
1536
1537                         numoutput++;
1538                         numoutputline++;
1539                         fprintf(stdout, "%-*s  ", max, matches[idx]);
1540                         free(matches[idx]);
1541                         matches[idx] = NULL;
1542                 }
1543                 if (numoutputline > 0)
1544                         fprintf(stdout, "\n");
1545         }
1546
1547         return numoutput;
1548 }
1549
1550
1551 static char *cli_complete(EditLine *el, int ch)
1552 {
1553         int len=0;
1554         char *ptr;
1555         int nummatches = 0;
1556         char **matches;
1557         int retval = CC_ERROR;
1558         char buf[2048];
1559         int res;
1560
1561         LineInfo *lf = (LineInfo *)el_line(el);
1562
1563         *(char *)lf->cursor = '\0';
1564         ptr = (char *)lf->cursor;
1565         if (ptr) {
1566                 while (ptr > lf->buffer) {
1567                         if (isspace(*ptr)) {
1568                                 ptr++;
1569                                 break;
1570                         }
1571                         ptr--;
1572                 }
1573         }
1574
1575         len = lf->cursor - ptr;
1576
1577         if (ast_opt_remote) {
1578                 snprintf(buf, sizeof(buf),"_COMMAND NUMMATCHES \"%s\" \"%s\"", lf->buffer, ptr); 
1579                 fdprint(ast_consock, buf);
1580                 res = read(ast_consock, buf, sizeof(buf));
1581                 buf[res] = '\0';
1582                 nummatches = atoi(buf);
1583
1584                 if (nummatches > 0) {
1585                         char *mbuf;
1586                         int mlen = 0, maxmbuf = 2048;
1587                         /* Start with a 2048 byte buffer */                     
1588                         if (!(mbuf = ast_malloc(maxmbuf)))
1589                                 return (char *)(CC_ERROR);
1590                         snprintf(buf, sizeof(buf),"_COMMAND MATCHESARRAY \"%s\" \"%s\"", lf->buffer, ptr); 
1591                         fdprint(ast_consock, buf);
1592                         res = 0;
1593                         mbuf[0] = '\0';
1594                         while (!strstr(mbuf, AST_CLI_COMPLETE_EOF) && res != -1) {
1595                                 if (mlen + 1024 > maxmbuf) {
1596                                         /* Every step increment buffer 1024 bytes */
1597                                         maxmbuf += 1024;                                        
1598                                         if (!(mbuf = ast_realloc(mbuf, maxmbuf)))
1599                                                 return (char *)(CC_ERROR);
1600                                 }
1601                                 /* Only read 1024 bytes at a time */
1602                                 res = read(ast_consock, mbuf + mlen, 1024);
1603                                 if (res > 0)
1604                                         mlen += res;
1605                         }
1606                         mbuf[mlen] = '\0';
1607
1608                         matches = ast_el_strtoarr(mbuf);
1609                         free(mbuf);
1610                 } else
1611                         matches = (char **) NULL;
1612         } else {
1613                 char **p, *oldbuf=NULL;
1614                 nummatches = 0;
1615                 matches = ast_cli_completion_matches((char *)lf->buffer,ptr);
1616                 for (p = matches; p && *p; p++) {
1617                         if (!oldbuf || strcmp(*p,oldbuf))
1618                                 nummatches++;
1619                         oldbuf = *p;
1620                 }
1621         }
1622
1623         if (matches) {
1624                 int i;
1625                 int matches_num, maxlen, match_len;
1626
1627                 if (matches[0][0] != '\0') {
1628                         el_deletestr(el, (int) len);
1629                         el_insertstr(el, matches[0]);
1630                         retval = CC_REFRESH;
1631                 }
1632
1633                 if (nummatches == 1) {
1634                         /* Found an exact match */
1635                         el_insertstr(el, " ");
1636                         retval = CC_REFRESH;
1637                 } else {
1638                         /* Must be more than one match */
1639                         for (i=1, maxlen=0; matches[i]; i++) {
1640                                 match_len = strlen(matches[i]);
1641                                 if (match_len > maxlen)
1642                                         maxlen = match_len;
1643                         }
1644                         matches_num = i - 1;
1645                         if (matches_num >1) {
1646                                 fprintf(stdout, "\n");
1647                                 ast_cli_display_match_list(matches, nummatches, maxlen);
1648                                 retval = CC_REDISPLAY;
1649                         } else { 
1650                                 el_insertstr(el," ");
1651                                 retval = CC_REFRESH;
1652                         }
1653                 }
1654                 free(matches);
1655         }
1656
1657         return (char *)(long)retval;
1658 }
1659
1660 static int ast_el_initialize(void)
1661 {
1662         HistEvent ev;
1663         char *editor = getenv("AST_EDITOR");
1664
1665         if (el != NULL)
1666                 el_end(el);
1667         if (el_hist != NULL)
1668                 history_end(el_hist);
1669
1670         el = el_init("asterisk", stdin, stdout, stderr);
1671         el_set(el, EL_PROMPT, cli_prompt);
1672
1673         el_set(el, EL_EDITMODE, 1);             
1674         el_set(el, EL_EDITOR, editor ? editor : "emacs");               
1675         el_hist = history_init();
1676         if (!el || !el_hist)
1677                 return -1;
1678
1679         /* setup history with 100 entries */
1680         history(el_hist, &ev, H_SETSIZE, 100);
1681
1682         el_set(el, EL_HIST, history, el_hist);
1683
1684         el_set(el, EL_ADDFN, "ed-complete", "Complete argument", cli_complete);
1685         /* Bind <tab> to command completion */
1686         el_set(el, EL_BIND, "^I", "ed-complete", NULL);
1687         /* Bind ? to command completion */
1688         el_set(el, EL_BIND, "?", "ed-complete", NULL);
1689         /* Bind ^D to redisplay */
1690         el_set(el, EL_BIND, "^D", "ed-redisplay", NULL);
1691
1692         return 0;
1693 }
1694
1695 static int ast_el_add_history(char *buf)
1696 {
1697         HistEvent ev;
1698
1699         if (el_hist == NULL || el == NULL)
1700                 ast_el_initialize();
1701         if (strlen(buf) > 256)
1702                 return 0;
1703         return (history(el_hist, &ev, H_ENTER, buf));
1704 }
1705
1706 static int ast_el_write_history(char *filename)
1707 {
1708         HistEvent ev;
1709
1710         if (el_hist == NULL || el == NULL)
1711                 ast_el_initialize();
1712
1713         return (history(el_hist, &ev, H_SAVE, filename));
1714 }
1715
1716 static int ast_el_read_history(char *filename)
1717 {
1718         char buf[256];
1719         FILE *f;
1720         int ret = -1;
1721
1722         if (el_hist == NULL || el == NULL)
1723                 ast_el_initialize();
1724
1725         if ((f = fopen(filename, "r")) == NULL)
1726                 return ret;
1727
1728         while (!feof(f)) {
1729                 fgets(buf, sizeof(buf), f);
1730                 if (!strcmp(buf, "_HiStOrY_V2_\n"))
1731                         continue;
1732                 if (ast_all_zeros(buf))
1733                         continue;
1734                 if ((ret = ast_el_add_history(buf)) == -1)
1735                         break;
1736         }
1737         fclose(f);
1738
1739         return ret;
1740 }
1741
1742 static void ast_remotecontrol(char * data)
1743 {
1744         char buf[80];
1745         int res;
1746         char filename[80] = "";
1747         char *hostname;
1748         char *cpid;
1749         char *version;
1750         int pid;
1751         char tmp[80];
1752         char *stringp=NULL;
1753
1754         char *ebuf;
1755         int num = 0;
1756
1757         read(ast_consock, buf, sizeof(buf));
1758         if (data)
1759                 write(ast_consock, data, strlen(data) + 1);
1760         stringp=buf;
1761         hostname = strsep(&stringp, "/");
1762         cpid = strsep(&stringp, "/");
1763         version = strsep(&stringp, "\n");
1764         if (!version)
1765                 version = "<Version Unknown>";
1766         stringp=hostname;
1767         strsep(&stringp, ".");
1768         if (cpid)
1769                 pid = atoi(cpid);
1770         else
1771                 pid = -1;
1772         snprintf(tmp, sizeof(tmp), "set verbose atleast %d", option_verbose);
1773         fdprint(ast_consock, tmp);
1774         snprintf(tmp, sizeof(tmp), "set debug atleast %d", option_debug);
1775         fdprint(ast_consock, tmp);
1776         ast_verbose("Connected to Asterisk %s currently running on %s (pid = %d)\n", version, hostname, pid);
1777         remotehostname = hostname;
1778         if (getenv("HOME")) 
1779                 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
1780         if (el_hist == NULL || el == NULL)
1781                 ast_el_initialize();
1782
1783         el_set(el, EL_GETCFN, ast_el_read_char);
1784
1785         if (!ast_strlen_zero(filename))
1786                 ast_el_read_history(filename);
1787
1788         if (ast_opt_exec && data) {  /* hack to print output then exit if asterisk -rx is used */
1789                 char tempchar;
1790                 struct pollfd fds[0];
1791                 fds[0].fd = ast_consock;
1792                 fds[0].events = POLLIN;
1793                 fds[0].revents = 0;
1794                 while(poll(fds, 1, 100) > 0) {
1795                         ast_el_read_char(el, &tempchar);
1796                 }
1797                 return;
1798         }
1799         for(;;) {
1800                 ebuf = (char *)el_gets(el, &num);
1801
1802                 if (!ast_strlen_zero(ebuf)) {
1803                         if (ebuf[strlen(ebuf)-1] == '\n')
1804                                 ebuf[strlen(ebuf)-1] = '\0';
1805                         if (!remoteconsolehandler(ebuf)) {
1806                                 res = write(ast_consock, ebuf, strlen(ebuf) + 1);
1807                                 if (res < 1) {
1808                                         ast_log(LOG_WARNING, "Unable to write: %s\n", strerror(errno));
1809                                         break;
1810                                 }
1811                         }
1812                 }
1813         }
1814         printf("\nDisconnected from Asterisk server\n");
1815 }
1816
1817 static int show_version(void)
1818 {
1819         printf("Asterisk " ASTERISK_VERSION "\n");
1820         return 0;
1821 }
1822
1823 static int show_cli_help(void) {
1824         printf("Asterisk " ASTERISK_VERSION ", Copyright (C) 1999 - 2005, Digium, Inc. and others.\n");
1825         printf("Usage: asterisk [OPTIONS]\n");
1826         printf("Valid Options:\n");
1827         printf("   -V              Display version number and exit\n");
1828         printf("   -C <configfile> Use an alternate configuration file\n");
1829         printf("   -G <group>      Run as a group other than the caller\n");
1830         printf("   -U <user>       Run as a user other than the caller\n");
1831         printf("   -c              Provide console CLI\n");
1832         printf("   -d              Enable extra debugging\n");
1833         printf("   -f              Do not fork\n");
1834         printf("   -g              Dump core in case of a crash\n");
1835         printf("   -h              This help screen\n");
1836         printf("   -i              Initialize crypto keys at startup\n");
1837         printf("   -n              Disable console colorization\n");
1838         printf("   -p              Run as pseudo-realtime thread\n");
1839         printf("   -q              Quiet mode (suppress output)\n");
1840         printf("   -r              Connect to Asterisk on this machine\n");
1841         printf("   -R              Connect to Asterisk, and attempt to reconnect if disconnected\n");
1842         printf("   -t              Record soundfiles in /var/tmp and move them where they belong after they are done.\n");
1843         printf("   -T              Display the time in [Mmm dd hh:mm:ss] format for each line of output to the CLI.\n");
1844         printf("   -v              Increase verbosity (multiple v's = more verbose)\n");
1845         printf("   -x <cmd>        Execute command <cmd> (only valid with -r)\n");
1846         printf("\n");
1847         return 0;
1848 }
1849
1850 static void ast_readconfig(void) {
1851         struct ast_config *cfg;
1852         struct ast_variable *v;
1853         char *config = AST_CONFIG_FILE;
1854
1855         if (ast_opt_override_config) {
1856                 cfg = ast_config_load(ast_config_AST_CONFIG_FILE);
1857                 if (!cfg)
1858                         ast_log(LOG_WARNING, "Unable to open specified master config file '%s', using built-in defaults\n", ast_config_AST_CONFIG_FILE);
1859         } else {
1860                 cfg = ast_config_load(config);
1861         }
1862
1863         /* init with buildtime config */
1864         ast_copy_string(ast_config_AST_CONFIG_DIR, AST_CONFIG_DIR, sizeof(ast_config_AST_CONFIG_DIR));
1865         ast_copy_string(ast_config_AST_SPOOL_DIR, AST_SPOOL_DIR, sizeof(ast_config_AST_SPOOL_DIR));
1866         ast_copy_string(ast_config_AST_MODULE_DIR, AST_MODULE_DIR, sizeof(ast_config_AST_VAR_DIR));
1867         snprintf(ast_config_AST_MONITOR_DIR, sizeof(ast_config_AST_MONITOR_DIR) - 1, "%s/monitor", ast_config_AST_SPOOL_DIR);
1868         ast_copy_string(ast_config_AST_VAR_DIR, AST_VAR_DIR, sizeof(ast_config_AST_VAR_DIR));
1869         ast_copy_string(ast_config_AST_LOG_DIR, AST_LOG_DIR, sizeof(ast_config_AST_LOG_DIR));
1870         ast_copy_string(ast_config_AST_AGI_DIR, AST_AGI_DIR, sizeof(ast_config_AST_AGI_DIR));
1871         ast_copy_string(ast_config_AST_DB, AST_DB, sizeof(ast_config_AST_DB));
1872         ast_copy_string(ast_config_AST_KEY_DIR, AST_KEY_DIR, sizeof(ast_config_AST_KEY_DIR));
1873         ast_copy_string(ast_config_AST_PID, AST_PID, sizeof(ast_config_AST_PID));
1874         ast_copy_string(ast_config_AST_SOCKET, AST_SOCKET, sizeof(ast_config_AST_SOCKET));
1875         ast_copy_string(ast_config_AST_RUN_DIR, AST_RUN_DIR, sizeof(ast_config_AST_RUN_DIR));
1876
1877         /* no asterisk.conf? no problem, use buildtime config! */
1878         if (!cfg) {
1879                 return;
1880         }
1881         v = ast_variable_browse(cfg, "files");
1882         while (v) {
1883                 if (!strcasecmp(v->name, "astctlpermissions")) {
1884                         ast_copy_string(ast_config_AST_CTL_PERMISSIONS, v->value, sizeof(ast_config_AST_CTL_PERMISSIONS));
1885                 } else if (!strcasecmp(v->name, "astctlowner")) {
1886                         ast_copy_string(ast_config_AST_CTL_OWNER, v->value, sizeof(ast_config_AST_CTL_OWNER));
1887                 } else if (!strcasecmp(v->name, "astctlgroup")) {
1888                         ast_copy_string(ast_config_AST_CTL_GROUP, v->value, sizeof(ast_config_AST_CTL_GROUP));
1889                 } else if (!strcasecmp(v->name, "astctl")) {
1890                         ast_copy_string(ast_config_AST_CTL, v->value, sizeof(ast_config_AST_CTL));
1891                 }
1892                 v = v->next;
1893         }
1894         v = ast_variable_browse(cfg, "directories");
1895         while(v) {
1896                 if (!strcasecmp(v->name, "astetcdir")) {
1897                         ast_copy_string(ast_config_AST_CONFIG_DIR, v->value, sizeof(ast_config_AST_CONFIG_DIR));
1898                 } else if (!strcasecmp(v->name, "astspooldir")) {
1899                         ast_copy_string(ast_config_AST_SPOOL_DIR, v->value, sizeof(ast_config_AST_SPOOL_DIR));
1900                         snprintf(ast_config_AST_MONITOR_DIR, sizeof(ast_config_AST_MONITOR_DIR) - 1, "%s/monitor", v->value);
1901                 } else if (!strcasecmp(v->name, "astvarlibdir")) {
1902                         ast_copy_string(ast_config_AST_VAR_DIR, v->value, sizeof(ast_config_AST_VAR_DIR));
1903                         snprintf(ast_config_AST_DB, sizeof(ast_config_AST_DB), "%s/astdb", v->value);
1904                         snprintf(ast_config_AST_KEY_DIR, sizeof(ast_config_AST_KEY_DIR), "%s/keys", v->value);
1905                 } else if (!strcasecmp(v->name, "astlogdir")) {
1906                         ast_copy_string(ast_config_AST_LOG_DIR, v->value, sizeof(ast_config_AST_LOG_DIR));
1907                 } else if (!strcasecmp(v->name, "astagidir")) {
1908                         ast_copy_string(ast_config_AST_AGI_DIR, v->value, sizeof(ast_config_AST_AGI_DIR));
1909                 } else if (!strcasecmp(v->name, "astrundir")) {
1910                         snprintf(ast_config_AST_PID, sizeof(ast_config_AST_PID), "%s/%s", v->value, "asterisk.pid");
1911                         snprintf(ast_config_AST_SOCKET, sizeof(ast_config_AST_SOCKET), "%s/%s", v->value, ast_config_AST_CTL);
1912                         ast_copy_string(ast_config_AST_RUN_DIR, v->value, sizeof(ast_config_AST_RUN_DIR));
1913                 } else if (!strcasecmp(v->name, "astmoddir")) {
1914                         ast_copy_string(ast_config_AST_MODULE_DIR, v->value, sizeof(ast_config_AST_MODULE_DIR));
1915                 }
1916                 v = v->next;
1917         }
1918         v = ast_variable_browse(cfg, "options");
1919         while(v) {
1920                 /* verbose level (-v at startup) */
1921                 if (!strcasecmp(v->name, "verbose")) {
1922                         option_verbose = atoi(v->value);
1923                 /* whether or not to force timestamping. (-T at startup) */
1924                 } else if (!strcasecmp(v->name, "timestamp")) {
1925                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TIMESTAMP);
1926                 /* whether or not to support #exec in config files */
1927                 } else if (!strcasecmp(v->name, "execincludes")) {
1928                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_EXEC_INCLUDES);
1929                 /* debug level (-d at startup) */
1930                 } else if (!strcasecmp(v->name, "debug")) {
1931                         option_debug = 0;
1932                         if (sscanf(v->value, "%d", &option_debug) != 1) {
1933                                 option_debug = ast_true(v->value);
1934                         }
1935                 /* Disable forking (-f at startup) */
1936                 } else if (!strcasecmp(v->name, "nofork")) {
1937                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_FORK);
1938                 /* Run quietly (-q at startup ) */
1939                 } else if (!strcasecmp(v->name, "quiet")) {
1940                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_QUIET);
1941                 /* Run as console (-c at startup, implies nofork) */
1942                 } else if (!strcasecmp(v->name, "console")) {
1943                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_CONSOLE);
1944                 /* Run with high priority if the O/S permits (-p at startup) */
1945                 } else if (!strcasecmp(v->name, "highpriority")) {
1946                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_HIGH_PRIORITY);
1947                 /* Initialize RSA auth keys (IAX2) (-i at startup) */
1948                 } else if (!strcasecmp(v->name, "initcrypto")) {
1949                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_INIT_KEYS);
1950                 /* Disable ANSI colors for console (-c at startup) */
1951                 } else if (!strcasecmp(v->name, "nocolor")) {
1952                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_COLOR);
1953                 /* Disable some usage warnings for picky people :p */
1954                 } else if (!strcasecmp(v->name, "dontwarn")) {
1955                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_DONT_WARN);
1956                 /* Dump core in case of crash (-g) */
1957                 } else if (!strcasecmp(v->name, "dumpcore")) {
1958                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_DUMP_CORE);
1959                 /* Cache recorded sound files to another directory during recording */
1960                 } else if (!strcasecmp(v->name, "cache_record_files")) {
1961                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_CACHE_RECORD_FILES);
1962                 /* Specify cache directory */
1963                 }  else if (!strcasecmp(v->name, "record_cache_dir")) {
1964                         ast_copy_string(record_cache_dir, v->value, AST_CACHE_DIR_LEN);
1965                 /* Build transcode paths via SLINEAR, instead of directly */
1966                 } else if (!strcasecmp(v->name, "transcode_via_sln")) {
1967                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TRANSCODE_VIA_SLIN);
1968                 /* Transmit SLINEAR silence while a channel is being recorded */
1969                 } else if (!strcasecmp(v->name, "transmit_silence_during_record")) {
1970                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TRANSMIT_SILENCE);
1971                 } else if (!strcasecmp(v->name, "maxcalls")) {
1972                         if ((sscanf(v->value, "%d", &option_maxcalls) != 1) || (option_maxcalls < 0)) {
1973                                 option_maxcalls = 0;
1974                         }
1975                 } else if (!strcasecmp(v->name, "maxload")) {
1976                         double test[1];
1977
1978                         if (getloadavg(test, 1) == -1) {
1979                                 ast_log(LOG_ERROR, "Cannot obtain load average on this system. 'maxload' option disabled.\n");
1980                                 option_maxload = 0.0;
1981                         } else if ((sscanf(v->value, "%lf", &option_maxload) != 1) || (option_maxload < 0.0)) {
1982                                 option_maxload = 0.0;
1983                         }
1984                 /* What user to run as */
1985                 } else if (!strcasecmp(v->name, "runuser")) {
1986                         ast_copy_string(ast_config_AST_RUN_USER, v->value, sizeof(ast_config_AST_RUN_USER));
1987                 /* What group to run as */
1988                 } else if (!strcasecmp(v->name, "rungroup")) {
1989                         ast_copy_string(ast_config_AST_RUN_GROUP, v->value, sizeof(ast_config_AST_RUN_GROUP));
1990                 } else if (!strcasecmp(v->name, "systemname")) {
1991                         ast_copy_string(ast_config_AST_SYSTEM_NAME, v->value, sizeof(ast_config_AST_SYSTEM_NAME));
1992                 }
1993                 v = v->next;
1994         }
1995         ast_config_destroy(cfg);
1996 }
1997
1998 int main(int argc, char *argv[])
1999 {
2000         int c;
2001         char filename[80] = "";
2002         char hostname[MAXHOSTNAMELEN]="";
2003         char tmp[80];
2004         char * xarg = NULL;
2005         int x;
2006         FILE *f;
2007         sigset_t sigs;
2008         int num;
2009         int is_child_of_nonroot=0;
2010         char *buf;
2011         char *runuser=NULL, *rungroup=NULL;
2012
2013         /* Remember original args for restart */
2014         if (argc > sizeof(_argv) / sizeof(_argv[0]) - 1) {
2015                 fprintf(stderr, "Truncating argument size to %d\n", (int)(sizeof(_argv) / sizeof(_argv[0])) - 1);
2016                 argc = sizeof(_argv) / sizeof(_argv[0]) - 1;
2017         }
2018         for (x=0;x<argc;x++)
2019                 _argv[x] = argv[x];
2020         _argv[x] = NULL;
2021
2022         /* if the progname is rasterisk consider it a remote console */
2023         if (argv[0] && (strstr(argv[0], "rasterisk")) != NULL) {
2024                 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE);
2025         }
2026         if (gethostname(hostname, sizeof(hostname)-1))
2027                 ast_copy_string(hostname, "<Unknown>", sizeof(hostname));
2028         ast_mainpid = getpid();
2029         ast_ulaw_init();
2030         ast_alaw_init();
2031         callerid_init();
2032         ast_utils_init();
2033         tdd_init();
2034         /* When Asterisk restarts after it has dropped the root privileges,
2035          * it can't issue setuid(), setgid(), setgroups() or set_priority() 
2036          * */
2037         if (getenv("ASTERISK_ALREADY_NONROOT"))
2038                 is_child_of_nonroot=1;
2039         if (getenv("HOME")) 
2040                 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
2041         /* Check if we're root */
2042         /*
2043         if (geteuid()) {
2044                 ast_log(LOG_ERROR, "Must be run as root\n");
2045                 exit(1);
2046         }
2047         */
2048         /* Check for options */
2049         while((c=getopt(argc, argv, "tThfdvVqprRgcinx:U:G:C:L:M:")) != -1) {
2050                 switch(c) {
2051                 case 'd':
2052                         option_debug++;
2053                         ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);
2054                         break;
2055                 case 'c':
2056                         ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_CONSOLE);
2057                         break;
2058                 case 'f':
2059                         ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);
2060                         break;
2061                 case 'n':
2062                         ast_set_flag(&ast_options, AST_OPT_FLAG_NO_COLOR);
2063                         break;
2064                 case 'r':
2065                         ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE);
2066                         break;
2067                 case 'R':
2068                         ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE | AST_OPT_FLAG_RECONNECT);
2069                         break;
2070                 case 'p':
2071                         ast_set_flag(&ast_options, AST_OPT_FLAG_HIGH_PRIORITY);
2072                         break;
2073                 case 'v':
2074                         option_verbose++;
2075                         ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);
2076                         break;
2077                 case 'M':
2078                         if ((sscanf(optarg, "%d", &option_maxcalls) != 1) || (option_maxcalls < 0))
2079                                 option_maxcalls = 0;
2080                         break;
2081                 case 'L':
2082                         if ((sscanf(optarg, "%lf", &option_maxload) != 1) || (option_maxload < 0.0))
2083                                 option_maxload = 0.0;
2084                         break;
2085                 case 'q':
2086                         ast_set_flag(&ast_options, AST_OPT_FLAG_QUIET);
2087                         break;
2088                 case 't':
2089                         ast_set_flag(&ast_options, AST_OPT_FLAG_CACHE_RECORD_FILES);
2090                         break;
2091                 case 'T':
2092                         ast_set_flag(&ast_options, AST_OPT_FLAG_TIMESTAMP);
2093                         break;
2094                 case 'x':
2095                         ast_set_flag(&ast_options, AST_OPT_FLAG_EXEC);
2096                         xarg = optarg;
2097                         break;
2098                 case 'C':
2099                         ast_copy_string(ast_config_AST_CONFIG_FILE, optarg, sizeof(ast_config_AST_CONFIG_FILE));
2100                         ast_set_flag(&ast_options, AST_OPT_FLAG_OVERRIDE_CONFIG);
2101                         break;
2102                 case 'i':
2103                         ast_set_flag(&ast_options, AST_OPT_FLAG_INIT_KEYS);
2104                         break;
2105                 case'g':
2106                         ast_set_flag(&ast_options, AST_OPT_FLAG_DUMP_CORE);
2107                         break;
2108                 case 'h':
2109                         show_cli_help();
2110                         exit(0);
2111                 case 'V':
2112                         show_version();
2113                         exit(0);
2114                 case 'U':
2115                         runuser = optarg;
2116                         break;
2117                 case 'G':
2118                         rungroup = optarg;
2119                         break;
2120                 case '?':
2121                         exit(1);
2122                 }
2123         }
2124
2125         /* For remote connections, change the name of the remote connection.
2126          * We do this for the benefit of init scripts (which need to know if/when
2127          * the main asterisk process has died yet). */
2128         if (ast_opt_remote) {
2129                 strcpy(argv[0], "rasterisk");
2130                 for (x = 1; x < argc; x++) {
2131                         argv[x] = argv[0] + 10;
2132                 }
2133         }
2134
2135         if (ast_opt_console && !option_verbose) 
2136                 ast_verbose("[ Reading Master Configuration ]");
2137         ast_readconfig();
2138
2139         if (ast_opt_dump_core) {
2140                 struct rlimit l;
2141                 memset(&l, 0, sizeof(l));
2142                 l.rlim_cur = RLIM_INFINITY;
2143                 l.rlim_max = RLIM_INFINITY;
2144                 if (setrlimit(RLIMIT_CORE, &l)) {
2145                         ast_log(LOG_WARNING, "Unable to disable core size resource limit: %s\n", strerror(errno));
2146                 }
2147         }
2148
2149         if ((!rungroup) && !ast_strlen_zero(ast_config_AST_RUN_GROUP))
2150                 rungroup = ast_config_AST_RUN_GROUP;
2151         if ((!runuser) && !ast_strlen_zero(ast_config_AST_RUN_USER))
2152                 runuser = ast_config_AST_RUN_USER;
2153 #ifndef __CYGWIN__
2154
2155         if (!is_child_of_nonroot) 
2156                 ast_set_priority(ast_opt_high_priority);
2157
2158         if (!is_child_of_nonroot && rungroup) {
2159                 struct group *gr;
2160                 gr = getgrnam(rungroup);
2161                 if (!gr) {
2162                         ast_log(LOG_WARNING, "No such group '%s'!\n", rungroup);
2163                         exit(1);
2164                 }
2165                 if (setgid(gr->gr_gid)) {
2166                         ast_log(LOG_WARNING, "Unable to setgid to %d (%s)\n", (int)gr->gr_gid, rungroup);
2167                         exit(1);
2168                 }
2169                 if (setgroups(0, NULL)) {
2170                         ast_log(LOG_WARNING, "Unable to drop unneeded groups\n");
2171                         exit(1);
2172                 }
2173                 if (option_verbose)
2174                         ast_verbose("Running as group '%s'\n", rungroup);
2175         }
2176
2177         if (!is_child_of_nonroot && runuser) {
2178                 struct passwd *pw;
2179                 pw = getpwnam(runuser);
2180                 if (!pw) {
2181                         ast_log(LOG_WARNING, "No such user '%s'!\n", runuser);
2182                         exit(1);
2183                 }
2184                 if (!rungroup) {
2185                         if (setgid(pw->pw_gid)) {
2186                                 ast_log(LOG_WARNING, "Unable to setgid to %d!\n", (int)pw->pw_gid);
2187                                 exit(1);
2188                         }
2189                         if (initgroups(pw->pw_name, pw->pw_gid)) {
2190                                 ast_log(LOG_WARNING, "Unable to init groups for '%s'\n", runuser);
2191                                 exit(1);
2192                         }
2193                 }
2194                 if (setuid(pw->pw_uid)) {
2195                         ast_log(LOG_WARNING, "Unable to setuid to %d (%s)\n", (int)pw->pw_uid, runuser);
2196                         exit(1);
2197                 }
2198                 setenv("ASTERISK_ALREADY_NONROOT","yes",1);
2199                 if (option_verbose)
2200                         ast_verbose("Running as user '%s'\n", runuser);
2201         }
2202
2203 #endif /* __CYGWIN__ */
2204
2205 #ifdef linux
2206         if (geteuid() && ast_opt_dump_core) {
2207                 if (prctl(PR_SET_DUMPABLE, 1, 0, 0, 0) < 0) {
2208                         ast_log(LOG_WARNING, "Unable to set the process for core dumps after changing to a non-root user. %s\n", strerror(errno));
2209                 }       
2210         }
2211 #endif
2212
2213         term_init();
2214         printf(term_end());
2215         fflush(stdout);
2216
2217         if (ast_opt_console && !option_verbose) 
2218                 ast_verbose("[ Initializing Custom Configuration Options ]");
2219         /* custom config setup */
2220         register_config_cli();
2221         read_config_maps();
2222         
2223
2224         if (ast_opt_console) {
2225                 if (el_hist == NULL || el == NULL)
2226                         ast_el_initialize();
2227
2228                 if (!ast_strlen_zero(filename))
2229                         ast_el_read_history(filename);
2230         }
2231
2232         if (ast_tryconnect()) {
2233                 /* One is already running */
2234                 if (ast_opt_remote) {
2235                         if (ast_opt_exec) {
2236                                 ast_remotecontrol(xarg);
2237                                 quit_handler(0, 0, 0, 0);
2238                                 exit(0);
2239                         }
2240                         printf(term_quit());
2241                         ast_register_verbose(console_verboser);
2242                         WELCOME_MESSAGE;
2243                         ast_remotecontrol(NULL);
2244                         quit_handler(0, 0, 0, 0);
2245                         exit(0);
2246                 } else {
2247                         ast_log(LOG_ERROR, "Asterisk already running on %s.  Use 'asterisk -r' to connect.\n", ast_config_AST_SOCKET);
2248                         printf(term_quit());
2249                         exit(1);
2250                 }
2251         } else if (ast_opt_remote || ast_opt_exec) {
2252                 ast_log(LOG_ERROR, "Unable to connect to remote asterisk (does %s exist?)\n",ast_config_AST_SOCKET);
2253                 printf(term_quit());
2254                 exit(1);
2255         }
2256         /* Blindly write pid file since we couldn't connect */
2257         unlink(ast_config_AST_PID);
2258         f = fopen(ast_config_AST_PID, "w");
2259         if (f) {
2260                 fprintf(f, "%d\n", (int)getpid());
2261                 fclose(f);
2262         } else
2263                 ast_log(LOG_WARNING, "Unable to open pid file '%s': %s\n", ast_config_AST_PID, strerror(errno));
2264
2265         if (!option_verbose && !option_debug && !ast_opt_no_fork && !ast_opt_console) {
2266                 daemon(0,0);
2267                 /* Blindly re-write pid file since we are forking */
2268                 unlink(ast_config_AST_PID);
2269                 f = fopen(ast_config_AST_PID, "w");
2270                 if (f) {
2271                         fprintf(f, "%d\n", (int)getpid());
2272                         fclose(f);
2273                 } else
2274                         ast_log(LOG_WARNING, "Unable to open pid file '%s': %s\n", ast_config_AST_PID, strerror(errno));
2275         }
2276
2277         /* Test recursive mutex locking. */
2278         if (test_for_thread_safety())
2279                 ast_verbose("Warning! Asterisk is not thread safe.\n");
2280
2281         ast_makesocket();
2282         sigemptyset(&sigs);
2283         sigaddset(&sigs, SIGHUP);
2284         sigaddset(&sigs, SIGTERM);
2285         sigaddset(&sigs, SIGINT);
2286         sigaddset(&sigs, SIGPIPE);
2287         sigaddset(&sigs, SIGWINCH);
2288         pthread_sigmask(SIG_BLOCK, &sigs, NULL);
2289         if (ast_opt_console || option_verbose || ast_opt_remote)
2290                 ast_register_verbose(console_verboser);
2291         /* Print a welcome message if desired */
2292         if (option_verbose || ast_opt_console) {
2293                 WELCOME_MESSAGE;
2294         }
2295         if (ast_opt_console && !option_verbose) 
2296                 ast_verbose("[ Booting...");
2297
2298         signal(SIGURG, urg_handler);
2299         signal(SIGINT, __quit_handler);
2300         signal(SIGTERM, __quit_handler);
2301         signal(SIGHUP, hup_handler);
2302         signal(SIGCHLD, child_handler);
2303         signal(SIGPIPE, SIG_IGN);
2304
2305         /* ensure that the random number generators are seeded with a different value every time
2306            Asterisk is started
2307         */
2308         srand((unsigned int) getpid() + (unsigned int) time(NULL));
2309         initstate((unsigned int) getpid() * 65536 + (unsigned int) time(NULL), randompool, sizeof(randompool));
2310
2311         if (init_logger()) {
2312                 printf(term_quit());
2313                 exit(1);
2314         }
2315         if (dnsmgr_init()) {
2316                 printf(term_quit());
2317                 exit(1);
2318         }
2319         /* load 'preload' modules, required for access to Realtime-mapped configuration files */
2320         if (load_modules(1)) {
2321                 printf(term_quit());
2322                 exit(1);
2323         }
2324         ast_channels_init();
2325         if (init_manager()) {
2326                 printf(term_quit());
2327                 exit(1);
2328         }
2329         if (ast_cdr_engine_init()) {
2330                 printf(term_quit());
2331                 exit(1);
2332         }
2333         if (ast_device_state_engine_init()) {
2334                 printf(term_quit());
2335                 exit(1);
2336         }
2337         ast_rtp_init();
2338 #if defined(T38_SUPPORT)
2339         ast_udptl_init();
2340 #endif
2341         if (ast_image_init()) {
2342                 printf(term_quit());
2343                 exit(1);
2344         }
2345         if (ast_file_init()) {
2346                 printf(term_quit());
2347                 exit(1);
2348         }
2349         if (load_pbx()) {
2350                 printf(term_quit());
2351                 exit(1);
2352         }
2353         if (load_modules(0)) {
2354                 printf(term_quit());
2355                 exit(1);
2356         }
2357         if (init_framer()) {
2358                 printf(term_quit());
2359                 exit(1);
2360         }
2361         if (astdb_init()) {
2362                 printf(term_quit());
2363                 exit(1);
2364         }
2365         if (ast_enum_init()) {
2366                 printf(term_quit());
2367                 exit(1);
2368         }
2369
2370         dnsmgr_start_refresh();
2371
2372 #if 0
2373         /* This should no longer be necessary */
2374         /* sync cust config and reload some internals in case a custom config handler binded to them */
2375         read_ast_cust_config();
2376         reload_logger(0);
2377         reload_manager();
2378         ast_enum_reload();
2379         ast_rtp_reload();
2380 #endif
2381
2382
2383         /* We might have the option of showing a console, but for now just
2384            do nothing... */
2385         if (ast_opt_console && !option_verbose)
2386                 ast_verbose(" ]\n");
2387         if (option_verbose || ast_opt_console)
2388                 ast_verbose(term_color(tmp, "Asterisk Ready.\n", COLOR_BRWHITE, COLOR_BLACK, sizeof(tmp)));
2389         if (ast_opt_no_fork)
2390                 consolethread = pthread_self();
2391         ast_set_flag(&ast_options, AST_OPT_FLAG_FULLY_BOOTED);
2392         pthread_sigmask(SIG_UNBLOCK, &sigs, NULL);
2393 #ifdef __AST_DEBUG_MALLOC
2394         __ast_mm_init();
2395 #endif  
2396         time(&ast_startuptime);
2397         ast_cli_register_multiple(core_cli, sizeof(core_cli) / sizeof(core_cli[0]));
2398         if (ast_opt_console) {
2399                 /* Console stuff now... */
2400                 /* Register our quit function */
2401                 char title[256];
2402                 set_icon("Asterisk");
2403                 snprintf(title, sizeof(title), "Asterisk Console on '%s' (pid %d)", hostname, ast_mainpid);
2404                 set_title(title);
2405
2406                 for (;;) {
2407                         buf = (char *)el_gets(el, &num);
2408                         if (buf) {
2409                                 if (buf[strlen(buf)-1] == '\n')
2410                                         buf[strlen(buf)-1] = '\0';
2411
2412                                 consolehandler((char *)buf);
2413                         } else {
2414                                 if (write(STDOUT_FILENO, "\nUse EXIT or QUIT to exit the asterisk console\n",
2415                                                                   strlen("\nUse EXIT or QUIT to exit the asterisk console\n")) < 0) {
2416                                         /* Whoa, stdout disappeared from under us... Make /dev/null's */
2417                                         int fd;
2418                                         fd = open("/dev/null", O_RDWR);
2419                                         if (fd > -1) {
2420                                                 dup2(fd, STDOUT_FILENO);
2421                                                 dup2(fd, STDIN_FILENO);
2422                                         } else
2423                                                 ast_log(LOG_WARNING, "Failed to open /dev/null to recover from dead console.  Bad things will happen!\n");
2424                                         break;
2425                                 }
2426                         }
2427                 }
2428
2429         }
2430         /* Do nothing */
2431         for(;;)  {      /* apparently needed for the MACos */
2432                 struct pollfd p = { -1 /* no descriptor */, 0, 0 };
2433                 poll(&p, 0, -1);
2434         }
2435         return 0;
2436 }