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