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