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