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