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