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