Thu Oct 11 06:42:01 2012

Asterisk developer's documentation


asterisk.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 1999 - 2010, Digium, Inc.
00005  *
00006  * Mark Spencer <markster@digium.com>
00007  *
00008  * See http://www.asterisk.org for more information about
00009  * the Asterisk project. Please do not directly contact
00010  * any of the maintainers of this project for assistance;
00011  * the project provides a web site, mailing lists and IRC
00012  * channels for your use.
00013  *
00014  * This program is free software, distributed under the terms of
00015  * the GNU General Public License Version 2. See the LICENSE file
00016  * at the top of the source tree.
00017  */
00018 
00019 
00020 /* Doxygenified Copyright Header */
00021 /*!
00022  * \mainpage Asterisk -- An Open Source Telephony Toolkit
00023  *
00024  * \par Developer Documentation for Asterisk
00025  * This is the main developer documentation for Asterisk. It is 
00026  * generated by running "make progdocs".
00027  * \par Additional documentation
00028  * \arg \ref Licensing
00029  * \arg \ref DevDoc 
00030  * \arg \ref ConfigFiles
00031  *
00032  * \section copyright Copyright and author
00033  *
00034  * Copyright (C) 1999 - 2009, Digium, Inc.
00035  * Asterisk is a trademark registered by Digium, Inc.
00036  *
00037  * \author Mark Spencer <markster@digium.com>
00038  * Also see \ref AstCREDITS
00039  *
00040  * See http://www.asterisk.org for more information about
00041  * the Asterisk project. Please do not directly contact
00042  * any of the maintainers of this project for assistance;
00043  * the project provides a web site, mailing lists and IRC
00044  * channels for your use.
00045  */
00046 
00047 /*! \file
00048   \brief Top level source file for Asterisk  - the Open Source PBX. Implementation
00049   of PBX core functions and CLI interface.
00050   
00051  */
00052 
00053 #include "asterisk.h"
00054 
00055 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 312285 $")
00056 
00057 #undef sched_setscheduler
00058 #undef setpriority
00059 #include <unistd.h>
00060 #include <stdlib.h>
00061 #include <sys/time.h>
00062 #include <fcntl.h>
00063 #include <stdio.h>
00064 #include <signal.h>
00065 #include <sched.h>
00066 #include <sys/socket.h>
00067 #include <sys/un.h>
00068 #include <sys/wait.h>
00069 #include <string.h>
00070 #include <errno.h>
00071 #include <ctype.h>
00072 #include <sys/resource.h>
00073 #include <grp.h>
00074 #include <pwd.h>
00075 #include <sys/stat.h>
00076 
00077 #if defined(HAVE_ZAPTEL) || defined (HAVE_DAHDI)
00078 #include <sys/ioctl.h>
00079 #include "asterisk/dahdi_compat.h"
00080 #endif
00081 
00082 #ifdef linux
00083 #include <sys/prctl.h>
00084 #ifdef HAVE_CAP
00085 #include <sys/capability.h>
00086 #endif /* HAVE_CAP */
00087 #endif /* linux */
00088 #include <regex.h>
00089 
00090 #if  defined(__FreeBSD__) || defined( __NetBSD__ ) || defined(SOLARIS)
00091 #include <netdb.h>
00092 #if defined(SOLARIS)
00093 int daemon(int, int);  /* defined in libresolv of all places */
00094 #endif
00095 #endif
00096 
00097 #include "asterisk/logger.h"
00098 #include "asterisk/options.h"
00099 #include "asterisk/cli.h"
00100 #include "asterisk/channel.h"
00101 #include "asterisk/ulaw.h"
00102 #include "asterisk/alaw.h"
00103 #include "asterisk/callerid.h"
00104 #include "asterisk/image.h"
00105 #include "asterisk/tdd.h"
00106 #include "asterisk/term.h"
00107 #include "asterisk/manager.h"
00108 #include "asterisk/cdr.h"
00109 #include "asterisk/pbx.h"
00110 #include "asterisk/enum.h"
00111 #include "asterisk/rtp.h"
00112 #include "asterisk/http.h"
00113 #include "asterisk/udptl.h"
00114 #include "asterisk/app.h"
00115 #include "asterisk/lock.h"
00116 #include "asterisk/utils.h"
00117 #include "asterisk/file.h"
00118 #include "asterisk/io.h"
00119 #include "asterisk/lock.h"
00120 #include "editline/histedit.h"
00121 #include "asterisk/config.h"
00122 #include "asterisk/version.h"
00123 #include "asterisk/linkedlists.h"
00124 #include "asterisk/devicestate.h"
00125 #include "asterisk/module.h"
00126 #include "asterisk/poll-compat.h"
00127 
00128 #include "asterisk/doxyref.h"    /* Doxygen documentation */
00129 
00130 #include "../defaults.h"
00131 
00132 #ifndef AF_LOCAL
00133 #define AF_LOCAL AF_UNIX
00134 #define PF_LOCAL PF_UNIX
00135 #endif
00136 
00137 #define AST_MAX_CONNECTS 128
00138 #define NUM_MSGS 64
00139 
00140 /*! \brief Welcome message when starting a CLI interface */
00141 #define WELCOME_MESSAGE \
00142    ast_verbose("Asterisk " ASTERISK_VERSION ", Copyright (C) 1999 - 2010 Digium, Inc. and others.\n"); \
00143    ast_verbose("Created by Mark Spencer <markster@digium.com>\n"); \
00144    ast_verbose("Asterisk comes with ABSOLUTELY NO WARRANTY; type 'core show warranty' for details.\n"); \
00145    ast_verbose("This is free software, with components licensed under the GNU General Public\n"); \
00146    ast_verbose("License version 2 and other licenses; you are welcome to redistribute it under\n"); \
00147    ast_verbose("certain conditions. Type 'core show license' for details.\n"); \
00148    ast_verbose("=========================================================================\n")
00149 
00150 /*! \defgroup main_options Main Configuration Options
00151  \brief Main configuration options from \ref Config_ast "asterisk.conf" or 
00152   the operating system command line when starting Asterisk 
00153   Some of them can be changed in the CLI 
00154  */
00155 /*! @{ */
00156 
00157 struct ast_flags ast_options = { AST_DEFAULT_OPTIONS };
00158 
00159 int option_verbose;           /*!< Verbosity level */
00160 int option_debug;          /*!< Debug level */
00161 
00162 double option_maxload;           /*!< Max load avg on system */
00163 int option_maxcalls;          /*!< Max number of active calls */
00164 /*! @} */
00165 
00166 char record_cache_dir[AST_CACHE_DIR_LEN] = AST_TMP_DIR;
00167 char debug_filename[AST_FILENAME_MAX] = "";
00168 #ifdef HAVE_ZAPTEL
00169 static char _dahdi_chan_name[AST_CHANNEL_NAME] = "Zap";
00170 static size_t _dahdi_chan_name_len = 3;
00171 static enum dahdi_chan_modes _dahdi_chan_mode = CHAN_ZAP_MODE;
00172 #else
00173 static char _dahdi_chan_name[AST_CHANNEL_NAME] = "DAHDI";
00174 static size_t _dahdi_chan_name_len = 5;
00175 static enum dahdi_chan_modes _dahdi_chan_mode = CHAN_DAHDI_PLUS_ZAP_MODE;
00176 #endif
00177 const char *dahdi_chan_name;
00178 const size_t *dahdi_chan_name_len;
00179 const enum dahdi_chan_modes *dahdi_chan_mode;
00180 
00181 static int ast_socket = -1;      /*!< UNIX Socket for allowing remote control */
00182 static int ast_consock = -1;     /*!< UNIX Socket for controlling another asterisk */
00183 pid_t ast_mainpid;
00184 struct console {
00185    int fd;           /*!< File descriptor */
00186    int p[2];         /*!< Pipe */
00187    pthread_t t;         /*!< Thread of handler */
00188    int mute;         /*!< Is the console muted for logs */
00189 };
00190 
00191 struct ast_atexit {
00192    void (*func)(void);
00193    AST_LIST_ENTRY(ast_atexit) list;
00194 };
00195 
00196 static AST_LIST_HEAD_STATIC(atexits, ast_atexit);
00197 
00198 time_t ast_startuptime;
00199 time_t ast_lastreloadtime;
00200 
00201 static History *el_hist;
00202 static EditLine *el;
00203 static char *remotehostname;
00204 
00205 struct console consoles[AST_MAX_CONNECTS];
00206 
00207 char defaultlanguage[MAX_LANGUAGE] = DEFAULT_LANGUAGE;
00208 
00209 static int ast_el_add_history(char *);
00210 static int ast_el_read_history(char *);
00211 static int ast_el_write_history(char *);
00212 
00213 char ast_config_AST_CONFIG_DIR[PATH_MAX];
00214 char ast_config_AST_CONFIG_FILE[PATH_MAX];
00215 char ast_config_AST_MODULE_DIR[PATH_MAX];
00216 char ast_config_AST_SPOOL_DIR[PATH_MAX];
00217 char ast_config_AST_MONITOR_DIR[PATH_MAX];
00218 char ast_config_AST_VAR_DIR[PATH_MAX];
00219 char ast_config_AST_DATA_DIR[PATH_MAX];
00220 char ast_config_AST_LOG_DIR[PATH_MAX];
00221 char ast_config_AST_AGI_DIR[PATH_MAX];
00222 char ast_config_AST_DB[PATH_MAX];
00223 char ast_config_AST_KEY_DIR[PATH_MAX];
00224 char ast_config_AST_PID[PATH_MAX];
00225 char ast_config_AST_SOCKET[PATH_MAX];
00226 char ast_config_AST_RUN_DIR[PATH_MAX];
00227 char ast_config_AST_RUN_USER[PATH_MAX];
00228 char ast_config_AST_RUN_GROUP[PATH_MAX];
00229 char ast_config_AST_CTL_PERMISSIONS[PATH_MAX];
00230 char ast_config_AST_CTL_OWNER[PATH_MAX] = "\0";
00231 char ast_config_AST_CTL_GROUP[PATH_MAX] = "\0";
00232 char ast_config_AST_CTL[PATH_MAX] = "asterisk.ctl";
00233 char ast_config_AST_SYSTEM_NAME[20] = "";
00234 
00235 extern const char *ast_build_hostname;
00236 extern const char *ast_build_kernel;
00237 extern const char *ast_build_machine;
00238 extern const char *ast_build_os;
00239 extern const char *ast_build_date;
00240 extern const char *ast_build_user;
00241 
00242 unsigned int ast_FD_SETSIZE = FD_SETSIZE;
00243 
00244 static char *_argv[256];
00245 static int shuttingdown;
00246 static int restartnow;
00247 static pthread_t consolethread = AST_PTHREADT_NULL;
00248 static pthread_t mon_sig_flags;
00249 
00250 static char randompool[256];
00251 
00252 static int sig_alert_pipe[2] = { -1, -1 };
00253 static struct {
00254     unsigned int need_reload:1;
00255     unsigned int need_quit:1;
00256 } sig_flags;
00257 
00258 #if !defined(LOW_MEMORY)
00259 struct file_version {
00260    AST_LIST_ENTRY(file_version) list;
00261    const char *file;
00262    char *version;
00263 };
00264 
00265 #ifndef AST_MUTEX_INIT_W_CONSTRUCTORS
00266 static AST_LIST_HEAD_STATIC(file_versions, file_version);
00267 #else
00268 static AST_LIST_HEAD(file_versions, file_version) file_versions;
00269 static pthread_once_t file_versions_once = PTHREAD_ONCE_INIT;
00270 static void file_versions_init(void)
00271 {
00272    AST_LIST_HEAD_INIT(&file_versions);
00273 }
00274 #endif
00275 
00276 void ast_register_file_version(const char *file, const char *version)
00277 {
00278    struct file_version *new;
00279    char *work;
00280    size_t version_length;
00281 
00282    work = ast_strdupa(version);
00283    work = ast_strip(ast_strip_quoted(work, "$", "$"));
00284    version_length = strlen(work) + 1;
00285    
00286    if (!(new = ast_calloc(1, sizeof(*new) + version_length)))
00287       return;
00288 
00289    new->file = file;
00290    new->version = (char *) new + sizeof(*new);
00291    memcpy(new->version, work, version_length);
00292 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
00293    pthread_once(&file_versions_once, file_versions_init);
00294 #endif
00295    AST_LIST_LOCK(&file_versions);
00296    AST_LIST_INSERT_HEAD(&file_versions, new, list);
00297    AST_LIST_UNLOCK(&file_versions);
00298 }
00299 
00300 void ast_unregister_file_version(const char *file)
00301 {
00302    struct file_version *find;
00303 
00304    AST_LIST_LOCK(&file_versions);
00305    AST_LIST_TRAVERSE_SAFE_BEGIN(&file_versions, find, list) {
00306       if (!strcasecmp(find->file, file)) {
00307          AST_LIST_REMOVE_CURRENT(&file_versions, list);
00308          break;
00309       }
00310    }
00311    AST_LIST_TRAVERSE_SAFE_END;
00312    AST_LIST_UNLOCK(&file_versions);
00313    if (find)
00314       free(find);
00315 }
00316 
00317 struct thread_list_t {
00318    AST_LIST_ENTRY(thread_list_t) list;
00319    char *name;
00320    pthread_t id;
00321 };
00322 
00323 static AST_LIST_HEAD_STATIC(thread_list, thread_list_t);
00324 
00325 static char show_threads_help[] =
00326 "Usage: core show threads\n"
00327 "       List threads currently active in the system.\n";
00328 
00329 void ast_register_thread(char *name)
00330 { 
00331    struct thread_list_t *new = ast_calloc(1, sizeof(*new));
00332 
00333    if (!new)
00334       return;
00335    new->id = pthread_self();
00336    new->name = name; /* steal the allocated memory for the thread name */
00337    AST_LIST_LOCK(&thread_list);
00338    AST_LIST_INSERT_HEAD(&thread_list, new, list);
00339    AST_LIST_UNLOCK(&thread_list);
00340 }
00341 
00342 void ast_unregister_thread(void *id)
00343 {
00344    struct thread_list_t *x;
00345 
00346    AST_LIST_LOCK(&thread_list);
00347    AST_LIST_TRAVERSE_SAFE_BEGIN(&thread_list, x, list) {
00348       if ((void *) x->id == id) {
00349          AST_LIST_REMOVE_CURRENT(&thread_list, list);
00350          break;
00351       }
00352    }
00353    AST_LIST_TRAVERSE_SAFE_END;
00354    AST_LIST_UNLOCK(&thread_list);
00355    if (x) {
00356       free(x->name);
00357       free(x);
00358    }
00359 }
00360 
00361 static int handle_show_threads(int fd, int argc, char *argv[])
00362 {
00363    int count = 0;
00364    struct thread_list_t *cur;
00365 
00366    AST_LIST_LOCK(&thread_list);
00367    AST_LIST_TRAVERSE(&thread_list, cur, list) {
00368       ast_cli(fd, "%p %s\n", (void *)cur->id, cur->name);
00369       count++;
00370    }
00371         AST_LIST_UNLOCK(&thread_list);
00372    ast_cli(fd, "%d threads listed.\n", count);
00373    return 0;
00374 }
00375 
00376 struct profile_entry {
00377    const char *name;
00378    uint64_t scale;   /* if non-zero, values are scaled by this */
00379    int64_t  mark;
00380    int64_t  value;
00381    int64_t  events;
00382 };
00383 
00384 struct profile_data {
00385    int entries;
00386    int max_size;
00387    struct profile_entry e[0];
00388 };
00389 
00390 static struct profile_data *prof_data;
00391 
00392 /*! \brief allocates a counter with a given name and scale.
00393  * \return Returns the identifier of the counter.
00394  */
00395 int ast_add_profile(const char *name, uint64_t scale)
00396 {
00397    int l = sizeof(struct profile_data);
00398    int n = 10; /* default entries */
00399 
00400    if (prof_data == NULL) {
00401       prof_data = ast_calloc(1, l + n*sizeof(struct profile_entry));
00402       if (prof_data == NULL)
00403          return -1;
00404       prof_data->entries = 0;
00405       prof_data->max_size = n;
00406    }
00407    if (prof_data->entries >= prof_data->max_size) {
00408       void *p;
00409       n = prof_data->max_size + 20;
00410       p = ast_realloc(prof_data, l + n*sizeof(struct profile_entry));
00411       if (p == NULL)
00412          return -1;
00413       prof_data = p;
00414       prof_data->max_size = n;
00415    }
00416    n = prof_data->entries++;
00417    prof_data->e[n].name = ast_strdup(name);
00418    prof_data->e[n].value = 0;
00419    prof_data->e[n].events = 0;
00420    prof_data->e[n].mark = 0;
00421    prof_data->e[n].scale = scale;
00422    return n;
00423 }
00424 
00425 int64_t ast_profile(int i, int64_t delta)
00426 {
00427    if (!prof_data || i < 0 || i > prof_data->entries) /* invalid index */
00428       return 0;
00429    if (prof_data->e[i].scale > 1)
00430       delta /= prof_data->e[i].scale;
00431    prof_data->e[i].value += delta;
00432    prof_data->e[i].events++;
00433    return prof_data->e[i].value;
00434 }
00435 
00436 /* The RDTSC instruction was introduced on the Pentium processor and is not
00437  * implemented on certain clones, like the Cyrix 586. Hence, the previous
00438  * expectation of __i386__ was in error. */
00439 #if defined ( __i686__) && (defined(__FreeBSD__) || defined(linux))
00440 #if defined(__FreeBSD__)
00441 #include <machine/cpufunc.h>
00442 #elif defined(linux)
00443 static __inline uint64_t
00444 rdtsc(void)
00445 { 
00446    uint64_t rv;
00447 
00448    __asm __volatile(".byte 0x0f, 0x31" : "=A" (rv));
00449    return (rv);
00450 }
00451 #endif
00452 #else /* supply a dummy function on other platforms */
00453 static __inline uint64_t
00454 rdtsc(void)
00455 {
00456    return 0;
00457 }
00458 #endif
00459 
00460 int64_t ast_mark(int i, int startstop)
00461 {
00462    if (!prof_data || i < 0 || i > prof_data->entries) /* invalid index */
00463       return 0;
00464    if (startstop == 1)
00465       prof_data->e[i].mark = rdtsc();
00466    else {
00467       prof_data->e[i].mark = (rdtsc() - prof_data->e[i].mark);
00468       if (prof_data->e[i].scale > 1)
00469          prof_data->e[i].mark /= prof_data->e[i].scale;
00470       prof_data->e[i].value += prof_data->e[i].mark;
00471       prof_data->e[i].events++;
00472    }
00473    return prof_data->e[i].mark;
00474 }
00475 
00476 static int handle_show_profile_deprecated(int fd, int argc, char *argv[])
00477 {
00478    int i, min, max;
00479    char *search = NULL;
00480 
00481    if (prof_data == NULL)
00482       return 0;
00483 
00484    min = 0;
00485    max = prof_data->entries;
00486    if  (argc >= 3) { /* specific entries */
00487       if (isdigit(argv[2][0])) {
00488          min = atoi(argv[2]);
00489          if (argc == 4 && strcmp(argv[3], "-"))
00490             max = atoi(argv[3]);
00491       } else
00492          search = argv[2];
00493    }
00494    if (max > prof_data->entries)
00495       max = prof_data->entries;
00496    if (!strcmp(argv[0], "clear")) {
00497       for (i= min; i < max; i++) {
00498          if (!search || strstr(prof_data->e[i].name, search)) {
00499             prof_data->e[i].value = 0;
00500             prof_data->e[i].events = 0;
00501          }
00502       }
00503       return 0;
00504    }
00505    ast_cli(fd, "profile values (%d, allocated %d)\n-------------------\n",
00506       prof_data->entries, prof_data->max_size);
00507    ast_cli(fd, "%6s   %8s  %10s %12s %12s  %s\n", "ID", "Scale", "Events",
00508          "Value", "Average", "Name");
00509    for (i = min; i < max; i++) {
00510       struct profile_entry *e = &prof_data->e[i];
00511       if (!search || strstr(prof_data->e[i].name, search))
00512           ast_cli(fd, "%6d: [%8ld] %10ld %12lld %12lld  %s\n",
00513          i,
00514          (long)e->scale,
00515          (long)e->events, (long long)e->value,
00516          (long long)(e->events ? e->value / e->events : e->value),
00517          e->name);
00518    }
00519    return 0;
00520 }
00521 
00522 static int handle_show_profile(int fd, int argc, char *argv[])
00523 {
00524    int i, min, max;
00525    char *search = NULL;
00526 
00527    if (prof_data == NULL)
00528       return 0;
00529 
00530    min = 0;
00531    max = prof_data->entries;
00532    if  (argc > 3) { /* specific entries */
00533       if (isdigit(argv[3][0])) {
00534          min = atoi(argv[3]);
00535          if (argc == 5 && strcmp(argv[4], "-"))
00536             max = atoi(argv[4]);
00537       } else
00538          search = argv[3];
00539    }
00540    if (max > prof_data->entries)
00541       max = prof_data->entries;
00542    if (!strcmp(argv[1], "clear")) {
00543       for (i= min; i < max; i++) {
00544          if (!search || strstr(prof_data->e[i].name, search)) {
00545             prof_data->e[i].value = 0;
00546             prof_data->e[i].events = 0;
00547          }
00548       }
00549       return 0;
00550    }
00551    ast_cli(fd, "profile values (%d, allocated %d)\n-------------------\n",
00552       prof_data->entries, prof_data->max_size);
00553    ast_cli(fd, "%6s   %8s  %10s %12s %12s  %s\n", "ID", "Scale", "Events",
00554          "Value", "Average", "Name");
00555    for (i = min; i < max; i++) {
00556       struct profile_entry *e = &prof_data->e[i];
00557       if (!search || strstr(prof_data->e[i].name, search))
00558           ast_cli(fd, "%6d: [%8ld] %10ld %12lld %12lld  %s\n",
00559          i,
00560          (long)e->scale,
00561          (long)e->events, (long long)e->value,
00562          (long long)(e->events ? e->value / e->events : e->value),
00563          e->name);
00564    }
00565    return 0;
00566 }
00567 
00568 static char show_version_files_help[] = 
00569 "Usage: core show file version [like <pattern>]\n"
00570 "       Lists the revision numbers of the files used to build this copy of Asterisk.\n"
00571 "       Optional regular expression pattern is used to filter the file list.\n";
00572 
00573 /*! \brief CLI command to list module versions */
00574 static int handle_show_version_files_deprecated(int fd, int argc, char *argv[])
00575 {
00576 #define FORMAT "%-25.25s %-40.40s\n"
00577    struct file_version *iterator;
00578    regex_t regexbuf;
00579    int havepattern = 0;
00580    int havename = 0;
00581    int count_files = 0;
00582 
00583    switch (argc) {
00584    case 5:
00585       if (!strcasecmp(argv[3], "like")) {
00586          if (regcomp(&regexbuf, argv[4], REG_EXTENDED | REG_NOSUB))
00587             return RESULT_SHOWUSAGE;
00588          havepattern = 1;
00589       } else
00590          return RESULT_SHOWUSAGE;
00591       break;
00592    case 4:
00593       havename = 1;
00594       break;
00595    case 3:
00596       break;
00597    default:
00598       return RESULT_SHOWUSAGE;
00599    }
00600 
00601    ast_cli(fd, FORMAT, "File", "Revision");
00602    ast_cli(fd, FORMAT, "----", "--------");
00603    AST_LIST_LOCK(&file_versions);
00604    AST_LIST_TRAVERSE(&file_versions, iterator, list) {
00605       if (havename && strcasecmp(iterator->file, argv[3]))
00606          continue;
00607 
00608       if (havepattern && regexec(&regexbuf, iterator->file, 0, NULL, 0))
00609          continue;
00610 
00611       ast_cli(fd, FORMAT, iterator->file, iterator->version);
00612       count_files++;
00613       if (havename)
00614          break;
00615    }
00616    AST_LIST_UNLOCK(&file_versions);
00617    if (!havename) {
00618       ast_cli(fd, "%d files listed.\n", count_files);
00619    }
00620 
00621    if (havepattern)
00622       regfree(&regexbuf);
00623 
00624    return RESULT_SUCCESS;
00625 #undef FORMAT
00626 }
00627 
00628 static int handle_show_version_files(int fd, int argc, char *argv[])
00629 {
00630 #define FORMAT "%-25.25s %-40.40s\n"
00631    struct file_version *iterator;
00632    regex_t regexbuf;
00633    int havepattern = 0;
00634    int havename = 0;
00635    int count_files = 0;
00636 
00637    switch (argc) {
00638    case 6:
00639       if (!strcasecmp(argv[4], "like")) {
00640          if (regcomp(&regexbuf, argv[5], REG_EXTENDED | REG_NOSUB))
00641             return RESULT_SHOWUSAGE;
00642          havepattern = 1;
00643       } else
00644          return RESULT_SHOWUSAGE;
00645       break;
00646    case 5:
00647       havename = 1;
00648       break;
00649    case 4:
00650       break;
00651    default:
00652       return RESULT_SHOWUSAGE;
00653    }
00654 
00655    ast_cli(fd, FORMAT, "File", "Revision");
00656    ast_cli(fd, FORMAT, "----", "--------");
00657    AST_LIST_LOCK(&file_versions);
00658    AST_LIST_TRAVERSE(&file_versions, iterator, list) {
00659       if (havename && strcasecmp(iterator->file, argv[4]))
00660          continue;
00661       
00662       if (havepattern && regexec(&regexbuf, iterator->file, 0, NULL, 0))
00663          continue;
00664 
00665       ast_cli(fd, FORMAT, iterator->file, iterator->version);
00666       count_files++;
00667       if (havename)
00668          break;
00669    }
00670    AST_LIST_UNLOCK(&file_versions);
00671    if (!havename) {
00672       ast_cli(fd, "%d files listed.\n", count_files);
00673    }
00674 
00675    if (havepattern)
00676       regfree(&regexbuf);
00677 
00678    return RESULT_SUCCESS;
00679 #undef FORMAT
00680 }
00681 
00682 static char *complete_show_version_files_deprecated(const char *line, const char *word, int pos, int state)
00683 {
00684    struct file_version *find;
00685    int which = 0;
00686    char *ret = NULL;
00687    int matchlen = strlen(word);
00688 
00689    if (pos != 3)
00690       return NULL;
00691 
00692    AST_LIST_LOCK(&file_versions);
00693    AST_LIST_TRAVERSE(&file_versions, find, list) {
00694       if (!strncasecmp(word, find->file, matchlen) && ++which > state) {
00695          ret = ast_strdup(find->file);
00696          break;
00697       }
00698    }
00699    AST_LIST_UNLOCK(&file_versions);
00700 
00701    return ret;
00702 }
00703 
00704 static char *complete_show_version_files(const char *line, const char *word, int pos, int state)
00705 {
00706    struct file_version *find;
00707    int which = 0;
00708    char *ret = NULL;
00709    int matchlen = strlen(word);
00710    
00711    if (pos != 4)
00712       return NULL;
00713 
00714    AST_LIST_LOCK(&file_versions);
00715    AST_LIST_TRAVERSE(&file_versions, find, list) {
00716       if (!strncasecmp(word, find->file, matchlen) && ++which > state) {
00717          ret = ast_strdup(find->file);
00718          break;
00719       }
00720    }
00721    AST_LIST_UNLOCK(&file_versions);
00722 
00723    return ret;
00724 }
00725 
00726 #endif /* ! LOW_MEMORY */
00727 
00728 int ast_register_atexit(void (*func)(void))
00729 {
00730    struct ast_atexit *ae;
00731 
00732    if (!(ae = ast_calloc(1, sizeof(*ae))))
00733       return -1;
00734 
00735    ae->func = func;
00736 
00737    ast_unregister_atexit(func);  
00738 
00739    AST_LIST_LOCK(&atexits);
00740    AST_LIST_INSERT_HEAD(&atexits, ae, list);
00741    AST_LIST_UNLOCK(&atexits);
00742 
00743    return 0;
00744 }
00745 
00746 void ast_unregister_atexit(void (*func)(void))
00747 {
00748    struct ast_atexit *ae = NULL;
00749 
00750    AST_LIST_LOCK(&atexits);
00751    AST_LIST_TRAVERSE_SAFE_BEGIN(&atexits, ae, list) {
00752       if (ae->func == func) {
00753          AST_LIST_REMOVE_CURRENT(&atexits, list);
00754          break;
00755       }
00756    }
00757    AST_LIST_TRAVERSE_SAFE_END
00758    AST_LIST_UNLOCK(&atexits);
00759 
00760    if (ae)
00761       free(ae);
00762 }
00763 
00764 /* Sending commands from consoles back to the daemon requires a terminating NULL */
00765 static int fdsend(int fd, const char *s)
00766 {
00767    return write(fd, s, strlen(s) + 1);
00768 }
00769 
00770 /* Sending messages from the daemon back to the display requires _excluding_ the terminating NULL */
00771 static int fdprint(int fd, const char *s)
00772 {
00773    return write(fd, s, strlen(s));
00774 }
00775 
00776 /*! \brief NULL handler so we can collect the child exit status */
00777 static void _null_sig_handler(int signal)
00778 {
00779 
00780 }
00781 
00782 static struct sigaction null_sig_handler = {
00783    .sa_handler = _null_sig_handler,
00784    .sa_flags = SA_RESTART,
00785 };
00786 
00787 AST_MUTEX_DEFINE_STATIC(safe_system_lock);
00788 /*! \brief Keep track of how many threads are currently trying to wait*() on
00789  *  a child process */
00790 static unsigned int safe_system_level = 0;
00791 static struct sigaction safe_system_prev_handler;
00792 
00793 void ast_replace_sigchld(void)
00794 {
00795    unsigned int level;
00796 
00797    ast_mutex_lock(&safe_system_lock);
00798    level = safe_system_level++;
00799 
00800    /* only replace the handler if it has not already been done */
00801    if (level == 0) {
00802       sigaction(SIGCHLD, &null_sig_handler, &safe_system_prev_handler);
00803    }
00804 
00805    ast_mutex_unlock(&safe_system_lock);
00806 }
00807 
00808 void ast_unreplace_sigchld(void)
00809 {
00810    unsigned int level;
00811 
00812    ast_mutex_lock(&safe_system_lock);
00813    level = --safe_system_level;
00814 
00815    /* only restore the handler if we are the last one */
00816    if (level == 0) {
00817       sigaction(SIGCHLD, &safe_system_prev_handler, NULL);
00818    }
00819 
00820    ast_mutex_unlock(&safe_system_lock);
00821 }
00822 
00823 int ast_safe_system(const char *s)
00824 {
00825    pid_t pid;
00826 #ifdef HAVE_WORKING_FORK
00827    int x;
00828 #endif
00829    int res;
00830    struct rusage rusage;
00831    int status;
00832 
00833 #if defined(HAVE_WORKING_FORK) || defined(HAVE_WORKING_VFORK)
00834    ast_replace_sigchld();
00835 
00836 #ifdef HAVE_WORKING_FORK
00837    pid = fork();
00838 #else
00839    pid = vfork();
00840 #endif   
00841 
00842    if (pid == 0) {
00843 #ifdef HAVE_CAP
00844       cap_t cap = cap_from_text("cap_net_admin-eip");
00845 
00846       if (cap_set_proc(cap)) {
00847          /* Careful with order! Logging cannot happen after we close FDs */
00848          ast_log(LOG_WARNING, "Unable to remove capabilities.\n");
00849       }
00850       cap_free(cap);
00851 #endif
00852 #ifdef HAVE_WORKING_FORK
00853       if (ast_opt_high_priority)
00854          ast_set_priority(0);
00855       /* Close file descriptors and launch system command */
00856       for (x = STDERR_FILENO + 1; x < 4096; x++)
00857          close(x);
00858 #endif
00859       execl("/bin/sh", "/bin/sh", "-c", s, (char *) NULL);
00860       _exit(1);
00861    } else if (pid > 0) {
00862       for(;;) {
00863          res = wait4(pid, &status, 0, &rusage);
00864          if (res > -1) {
00865             res = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
00866             break;
00867          } else if (errno != EINTR) 
00868             break;
00869       }
00870    } else {
00871       ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno));
00872       res = -1;
00873    }
00874 
00875    ast_unreplace_sigchld();
00876 #else /* !defined(HAVE_WORKING_FORK) && !defined(HAVE_WORKING_VFORK) */
00877    res = -1;
00878 #endif
00879 
00880    return res;
00881 }
00882 
00883 /*!
00884  * \brief mute or unmute a console from logging
00885  */
00886 void ast_console_toggle_mute(int fd, int silent) {
00887    int x;
00888    for (x = 0;x < AST_MAX_CONNECTS; x++) {
00889       if (fd == consoles[x].fd) {
00890          if (consoles[x].mute) {
00891             consoles[x].mute = 0;
00892             if (!silent)
00893                ast_cli(fd, "Console is not muted anymore.\n");
00894          } else {
00895             consoles[x].mute = 1;
00896             if (!silent)
00897                ast_cli(fd, "Console is muted.\n");
00898          }
00899          return;
00900       }
00901    }
00902    ast_cli(fd, "Couldn't find remote console.\n");
00903 }
00904 
00905 /*!
00906  * \brief log the string to all attached console clients
00907  */
00908 static void ast_network_puts_mutable(const char *string)
00909 {
00910    int x;
00911    for (x = 0;x < AST_MAX_CONNECTS; x++) {
00912       if (consoles[x].mute)
00913          continue;
00914       if (consoles[x].fd > -1) 
00915          fdprint(consoles[x].p[1], string);
00916    }
00917 }
00918 
00919 /*!
00920  * \brief log the string to the console, and all attached
00921  * console clients
00922  */
00923 void ast_console_puts_mutable(const char *string)
00924 {
00925    fputs(string, stdout);
00926    fflush(stdout);
00927    ast_network_puts_mutable(string);
00928 }
00929 
00930 /*!
00931  * \brief write the string to all attached console clients
00932  */
00933 static void ast_network_puts(const char *string)
00934 {
00935    int x;
00936    for (x=0; x < AST_MAX_CONNECTS; x++) {
00937       if (consoles[x].fd > -1) 
00938          fdprint(consoles[x].p[1], string);
00939    }
00940 }
00941 
00942 /*!
00943  * write the string to the console, and all attached
00944  * console clients
00945  */
00946 void ast_console_puts(const char *string)
00947 {
00948    fputs(string, stdout);
00949    fflush(stdout);
00950    ast_network_puts(string);
00951 }
00952 
00953 static void network_verboser(const char *s)
00954 {
00955    ast_network_puts_mutable(s);
00956 }
00957 
00958 static pthread_t lthread;
00959 
00960 static void *netconsole(void *vconsole)
00961 {
00962    struct console *con = vconsole;
00963    char hostname[MAXHOSTNAMELEN] = "";
00964    char tmp[512];
00965    int res;
00966    struct pollfd fds[2];
00967    
00968    if (gethostname(hostname, sizeof(hostname)-1))
00969       ast_copy_string(hostname, "<Unknown>", sizeof(hostname));
00970    snprintf(tmp, sizeof(tmp), "%s/%ld/%s\n", hostname, (long)ast_mainpid, ASTERISK_VERSION);
00971    fdprint(con->fd, tmp);
00972    for(;;) {
00973       fds[0].fd = con->fd;
00974       fds[0].events = POLLIN;
00975       fds[0].revents = 0;
00976       fds[1].fd = con->p[0];
00977       fds[1].events = POLLIN;
00978       fds[1].revents = 0;
00979 
00980       res = ast_poll(fds, 2, -1);
00981       if (res < 0) {
00982          if (errno != EINTR)
00983             ast_log(LOG_WARNING, "poll returned < 0: %s\n", strerror(errno));
00984          continue;
00985       }
00986       if (fds[0].revents) {
00987          res = read(con->fd, tmp, sizeof(tmp) - 1);
00988          if (res < 1) {
00989             break;
00990          }
00991          tmp[res] = 0;
00992          ast_cli_command_multiple(con->fd, res, tmp);
00993       }
00994       if (fds[1].revents) {
00995          res = read(con->p[0], tmp, sizeof(tmp));
00996          if (res < 1) {
00997             ast_log(LOG_ERROR, "read returned %d\n", res);
00998             break;
00999          }
01000          res = write(con->fd, tmp, res);
01001          if (res < 1)
01002             break;
01003       }
01004    }
01005    if (option_verbose > 2) 
01006       ast_verbose(VERBOSE_PREFIX_3 "Remote UNIX connection disconnected\n");
01007    close(con->fd);
01008    close(con->p[0]);
01009    close(con->p[1]);
01010    con->fd = -1;
01011    
01012    return NULL;
01013 }
01014 
01015 static void *listener(void *unused)
01016 {
01017    struct sockaddr_un sunaddr;
01018    int s;
01019    socklen_t len;
01020    int x;
01021    int flags;
01022    struct pollfd fds[1];
01023    pthread_attr_t attr;
01024    pthread_attr_init(&attr);
01025    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
01026    for (;;) {
01027       if (ast_socket < 0)
01028          return NULL;
01029       fds[0].fd = ast_socket;
01030       fds[0].events = POLLIN;
01031       s = ast_poll(fds, 1, -1);
01032       pthread_testcancel();
01033       if (s < 0) {
01034          if (errno != EINTR)
01035             ast_log(LOG_WARNING, "poll returned error: %s\n", strerror(errno));
01036          continue;
01037       }
01038       len = sizeof(sunaddr);
01039       s = accept(ast_socket, (struct sockaddr *)&sunaddr, &len);
01040       if (s < 0) {
01041          if (errno != EINTR)
01042             ast_log(LOG_WARNING, "Accept returned %d: %s\n", s, strerror(errno));
01043       } else {
01044          for (x = 0; x < AST_MAX_CONNECTS; x++) {
01045             if (consoles[x].fd < 0) {
01046                if (socketpair(AF_LOCAL, SOCK_STREAM, 0, consoles[x].p)) {
01047                   ast_log(LOG_ERROR, "Unable to create pipe: %s\n", strerror(errno));
01048                   consoles[x].fd = -1;
01049                   fdprint(s, "Server failed to create pipe\n");
01050                   close(s);
01051                   break;
01052                }
01053                flags = fcntl(consoles[x].p[1], F_GETFL);
01054                fcntl(consoles[x].p[1], F_SETFL, flags | O_NONBLOCK);
01055                consoles[x].fd = s;
01056                consoles[x].mute = 1; /* Default is muted, we will un-mute if necessary */
01057                if (ast_pthread_create_background(&consoles[x].t, &attr, netconsole, &consoles[x])) {
01058                   ast_log(LOG_ERROR, "Unable to spawn thread to handle connection: %s\n", strerror(errno));
01059                   close(consoles[x].p[0]);
01060                   close(consoles[x].p[1]);
01061                   consoles[x].fd = -1;
01062                   fdprint(s, "Server failed to spawn thread\n");
01063                   close(s);
01064                }
01065                break;
01066             }
01067          }
01068          if (x >= AST_MAX_CONNECTS) {
01069             fdprint(s, "No more connections allowed\n");
01070             ast_log(LOG_WARNING, "No more connections allowed\n");
01071             close(s);
01072          } else if (consoles[x].fd > -1) {
01073             if (option_verbose > 2) 
01074                ast_verbose(VERBOSE_PREFIX_3 "Remote UNIX connection\n");
01075          }
01076       }
01077    }
01078    return NULL;
01079 }
01080 
01081 static int ast_makesocket(void)
01082 {
01083    struct sockaddr_un sunaddr;
01084    int res;
01085    int x;
01086    uid_t uid = -1;
01087    gid_t gid = -1;
01088 
01089    for (x = 0; x < AST_MAX_CONNECTS; x++) 
01090       consoles[x].fd = -1;
01091    unlink(ast_config_AST_SOCKET);
01092    ast_socket = socket(PF_LOCAL, SOCK_STREAM, 0);
01093    if (ast_socket < 0) {
01094       ast_log(LOG_WARNING, "Unable to create control socket: %s\n", strerror(errno));
01095       return -1;
01096    }     
01097    memset(&sunaddr, 0, sizeof(sunaddr));
01098    sunaddr.sun_family = AF_LOCAL;
01099    ast_copy_string(sunaddr.sun_path, ast_config_AST_SOCKET, sizeof(sunaddr.sun_path));
01100    res = bind(ast_socket, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
01101    if (res) {
01102       ast_log(LOG_WARNING, "Unable to bind socket to %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
01103       close(ast_socket);
01104       ast_socket = -1;
01105       return -1;
01106    }
01107    res = listen(ast_socket, 2);
01108    if (res < 0) {
01109       ast_log(LOG_WARNING, "Unable to listen on socket %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
01110       close(ast_socket);
01111       ast_socket = -1;
01112       return -1;
01113    }
01114    ast_register_verbose(network_verboser);
01115    ast_pthread_create_background(&lthread, NULL, listener, NULL);
01116 
01117    if (!ast_strlen_zero(ast_config_AST_CTL_OWNER)) {
01118       struct passwd *pw;
01119       if ((pw = getpwnam(ast_config_AST_CTL_OWNER)) == NULL) {
01120          ast_log(LOG_WARNING, "Unable to find uid of user %s\n", ast_config_AST_CTL_OWNER);
01121       } else {
01122          uid = pw->pw_uid;
01123       }
01124    }
01125       
01126    if (!ast_strlen_zero(ast_config_AST_CTL_GROUP)) {
01127       struct group *grp;
01128       if ((grp = getgrnam(ast_config_AST_CTL_GROUP)) == NULL) {
01129          ast_log(LOG_WARNING, "Unable to find gid of group %s\n", ast_config_AST_CTL_GROUP);
01130       } else {
01131          gid = grp->gr_gid;
01132       }
01133    }
01134 
01135    if (chown(ast_config_AST_SOCKET, uid, gid) < 0)
01136       ast_log(LOG_WARNING, "Unable to change ownership of %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
01137 
01138    if (!ast_strlen_zero(ast_config_AST_CTL_PERMISSIONS)) {
01139       int p1;
01140       mode_t p;
01141       sscanf(ast_config_AST_CTL_PERMISSIONS, "%30o", &p1);
01142       p = p1;
01143       if ((chmod(ast_config_AST_SOCKET, p)) < 0)
01144          ast_log(LOG_WARNING, "Unable to change file permissions of %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
01145    }
01146 
01147    return 0;
01148 }
01149 
01150 static int ast_tryconnect(void)
01151 {
01152    struct sockaddr_un sunaddr;
01153    int res;
01154    ast_consock = socket(PF_LOCAL, SOCK_STREAM, 0);
01155    if (ast_consock < 0) {
01156       ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno));
01157       return 0;
01158    }
01159    memset(&sunaddr, 0, sizeof(sunaddr));
01160    sunaddr.sun_family = AF_LOCAL;
01161    ast_copy_string(sunaddr.sun_path, (char *)ast_config_AST_SOCKET, sizeof(sunaddr.sun_path));
01162    res = connect(ast_consock, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
01163    if (res) {
01164       close(ast_consock);
01165       ast_consock = -1;
01166       return 0;
01167    } else
01168       return 1;
01169 }
01170 
01171 /*! \brief Urgent handler
01172 
01173  Called by soft_hangup to interrupt the poll, read, or other
01174  system call.  We don't actually need to do anything though.  
01175  Remember: Cannot EVER ast_log from within a signal handler 
01176  */
01177 static void _urg_handler(int num)
01178 {
01179    return;
01180 }
01181 
01182 static struct sigaction urg_handler = {
01183    .sa_handler = _urg_handler,
01184    .sa_flags = SA_RESTART,
01185 };
01186 
01187 static void _hup_handler(int num)
01188 {
01189    int a = 0;
01190    if (option_verbose > 1) 
01191       printf("Received HUP signal -- Reloading configs\n");
01192    if (restartnow)
01193       execvp(_argv[0], _argv);
01194    sig_flags.need_reload = 1;
01195    if (sig_alert_pipe[1] != -1) {
01196       if (write(sig_alert_pipe[1], &a, sizeof(a)) < 0) {
01197          fprintf(stderr, "hup_handler: write() failed: %s\n", strerror(errno));
01198       }
01199    }
01200 }
01201 
01202 static struct sigaction hup_handler = {
01203    .sa_handler = _hup_handler,
01204    .sa_flags = SA_RESTART,
01205 };
01206 
01207 static void _child_handler(int sig)
01208 {
01209    /* Must not ever ast_log or ast_verbose within signal handler */
01210    int n, status;
01211 
01212    /*
01213     * Reap all dead children -- not just one
01214     */
01215    for (n = 0; wait4(-1, &status, WNOHANG, NULL) > 0; n++)
01216       ;
01217    if (n == 0 && option_debug)   
01218       printf("Huh?  Child handler, but nobody there?\n");
01219 }
01220 
01221 static struct sigaction child_handler = {
01222    .sa_handler = _child_handler,
01223    .sa_flags = SA_RESTART,
01224 };
01225 
01226 /*! \brief Set an X-term or screen title */
01227 static void set_title(char *text)
01228 {
01229    if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
01230       fprintf(stdout, "\033]2;%s\007", text);
01231 }
01232 
01233 static void set_icon(char *text)
01234 {
01235    if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
01236       fprintf(stdout, "\033]1;%s\007", text);
01237 }
01238 
01239 /*! \brief We set ourselves to a high priority, that we might pre-empt everything
01240    else.  If your PBX has heavy activity on it, this is a good thing.  */
01241 int ast_set_priority(int pri)
01242 {
01243    struct sched_param sched;
01244    memset(&sched, 0, sizeof(sched));
01245 #ifdef __linux__
01246    if (pri) {  
01247       sched.sched_priority = 10;
01248       if (sched_setscheduler(0, SCHED_RR, &sched)) {
01249          ast_log(LOG_WARNING, "Unable to set high priority\n");
01250          return -1;
01251       } else
01252          if (option_verbose)
01253             ast_verbose("Set to realtime thread\n");
01254    } else {
01255       sched.sched_priority = 0;
01256       /* According to the manpage, these parameters can never fail. */
01257       sched_setscheduler(0, SCHED_OTHER, &sched);
01258    }
01259 #else
01260    if (pri) {
01261       if (setpriority(PRIO_PROCESS, 0, -10) == -1) {
01262          ast_log(LOG_WARNING, "Unable to set high priority\n");
01263          return -1;
01264       } else
01265          if (option_verbose)
01266             ast_verbose("Set to high priority\n");
01267    } else {
01268       /* According to the manpage, these parameters can never fail. */
01269       setpriority(PRIO_PROCESS, 0, 0);
01270    }
01271 #endif
01272    return 0;
01273 }
01274 
01275 static void ast_run_atexits(void)
01276 {
01277    struct ast_atexit *ae;
01278    AST_LIST_LOCK(&atexits);
01279    AST_LIST_TRAVERSE(&atexits, ae, list) {
01280       if (ae->func) 
01281          ae->func();
01282    }
01283    AST_LIST_UNLOCK(&atexits);
01284 }
01285 
01286 static void quit_handler(int num, int nice, int safeshutdown, int restart)
01287 {
01288    char filename[80] = "";
01289    time_t s,e;
01290    int x;
01291    /* Try to get as many CDRs as possible submitted to the backend engines (if in batch mode) */
01292    ast_cdr_engine_term();
01293    if (safeshutdown) {
01294       shuttingdown = 1;
01295       if (!nice) {
01296          /* Begin shutdown routine, hanging up active channels */
01297          ast_begin_shutdown(1);
01298          if (option_verbose && ast_opt_console)
01299             ast_verbose("Beginning asterisk %s....\n", restart ? "restart" : "shutdown");
01300          time(&s);
01301          for (;;) {
01302             time(&e);
01303             /* Wait up to 15 seconds for all channels to go away */
01304             if ((e - s) > 15)
01305                break;
01306             if (!ast_active_channels())
01307                break;
01308             if (!shuttingdown)
01309                break;
01310             /* Sleep 1/10 of a second */
01311             usleep(100000);
01312          }
01313       } else {
01314          if (nice < 2)
01315             ast_begin_shutdown(0);
01316          if (option_verbose && ast_opt_console)
01317             ast_verbose("Waiting for inactivity to perform %s...\n", restart ? "restart" : "halt");
01318          for (;;) {
01319             if (!ast_active_channels())
01320                break;
01321             if (!shuttingdown)
01322                break;
01323             sleep(1);
01324          }
01325       }
01326 
01327       if (!shuttingdown) {
01328          if (option_verbose && ast_opt_console)
01329             ast_verbose("Asterisk %s cancelled.\n", restart ? "restart" : "shutdown");
01330          return;
01331       }
01332 
01333       if (nice)
01334          ast_module_shutdown();
01335    }
01336    if (ast_opt_console || ast_opt_remote) {
01337       pthread_t thisthread = pthread_self();
01338       if (getenv("HOME")) {
01339          snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
01340       }
01341       if (!ast_strlen_zero(filename)) {
01342          ast_el_write_history(filename);
01343       }
01344       if (consolethread == AST_PTHREADT_NULL || consolethread == thisthread || mon_sig_flags == thisthread) {
01345          /* Only end if we are the consolethread or signal handler, otherwise there's a race with that thread. */
01346          if (el != NULL) {
01347             el_end(el);
01348          }
01349          if (el_hist != NULL) {
01350             history_end(el_hist);
01351          }
01352       }
01353    }
01354    if (option_verbose)
01355       ast_verbose("Executing last minute cleanups\n");
01356    ast_run_atexits();
01357    /* Called on exit */
01358    if (option_verbose && ast_opt_console)
01359       ast_verbose("Asterisk %s ending (%d).\n", ast_active_channels() ? "uncleanly" : "cleanly", num);
01360    if (option_debug)
01361       ast_log(LOG_DEBUG, "Asterisk ending (%d).\n", num);
01362    manager_event(EVENT_FLAG_SYSTEM, "Shutdown", "Shutdown: %s\r\nRestart: %s\r\n", ast_active_channels() ? "Uncleanly" : "Cleanly", restart ? "True" : "False");
01363    if (ast_socket > -1) {
01364       pthread_cancel(lthread);
01365       close(ast_socket);
01366       ast_socket = -1;
01367       unlink(ast_config_AST_SOCKET);
01368    }
01369    if (ast_consock > -1)
01370       close(ast_consock);
01371    if (!ast_opt_remote)
01372       unlink(ast_config_AST_PID);
01373    printf("%s", term_quit());
01374    if (restart) {
01375       if (option_verbose || ast_opt_console)
01376          ast_verbose("Preparing for Asterisk restart...\n");
01377       /* Mark all FD's for closing on exec */
01378       for (x=3; x < 32768; x++) {
01379          fcntl(x, F_SETFD, FD_CLOEXEC);
01380       }
01381       if (option_verbose || ast_opt_console)
01382          ast_verbose("Asterisk is now restarting...\n");
01383       restartnow = 1;
01384 
01385       /* close logger */
01386       close_logger();
01387 
01388       /* If there is a consolethread running send it a SIGHUP 
01389          so it can execvp, otherwise we can do it ourselves */
01390       if ((consolethread != AST_PTHREADT_NULL) && (consolethread != pthread_self())) {
01391          pthread_kill(consolethread, SIGHUP);
01392          /* Give the signal handler some time to complete */
01393          sleep(2);
01394       } else
01395          execvp(_argv[0], _argv);
01396    
01397    } else {
01398       /* close logger */
01399       close_logger();
01400    }
01401    exit(0);
01402 }
01403 
01404 static void __quit_handler(int num)
01405 {
01406    int a = 0;
01407    sig_flags.need_quit = 1;
01408    if (sig_alert_pipe[1] != -1) {
01409       if (write(sig_alert_pipe[1], &a, sizeof(a)) < 0) {
01410          fprintf(stderr, "quit_handler: write() failed: %s\n", strerror(errno));
01411       }
01412    }
01413    /* There is no need to restore the signal handler here, since the app
01414     * is going to exit */
01415 }
01416 
01417 static void __remote_quit_handler(int num)
01418 {
01419    sig_flags.need_quit = 1;
01420 }
01421 
01422 static const char *fix_header(char *outbuf, int maxout, const char *s, char *cmp)
01423 {
01424    const char *c;
01425 
01426    /* Check for verboser preamble */
01427    if (*s == 127) {
01428       s++;
01429    }
01430 
01431    if (!strncmp(s, cmp, strlen(cmp))) {
01432       c = s + strlen(cmp);
01433       term_color(outbuf, cmp, COLOR_GRAY, 0, maxout);
01434       return c;
01435    }
01436    return NULL;
01437 }
01438 
01439 static void console_verboser(const char *s)
01440 {
01441    char tmp[80];
01442    const char *c = NULL;
01443 
01444    if ((c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_4)) ||
01445        (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_3)) ||
01446        (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_2)) ||
01447        (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_1))) {
01448       fputs(tmp, stdout);
01449       fputs(c, stdout);
01450    } else {
01451       if (*s == 127) {
01452          s++;
01453       }
01454       fputs(s, stdout);
01455    }
01456 
01457    fflush(stdout);
01458    
01459    /* Wake up a poll()ing console */
01460    if (ast_opt_console && consolethread != AST_PTHREADT_NULL)
01461       pthread_kill(consolethread, SIGURG);
01462 }
01463 
01464 static int ast_all_zeros(char *s)
01465 {
01466    while (*s) {
01467       if (*s > 32)
01468          return 0;
01469       s++;  
01470    }
01471    return 1;
01472 }
01473 
01474 static void consolehandler(char *s)
01475 {
01476    printf("%s", term_end());
01477    fflush(stdout);
01478 
01479    /* Called when readline data is available */
01480    if (!ast_all_zeros(s))
01481       ast_el_add_history(s);
01482    /* The real handler for bang */
01483    if (s[0] == '!') {
01484       if (s[1])
01485          ast_safe_system(s+1);
01486       else
01487          ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
01488    } else 
01489       ast_cli_command(STDOUT_FILENO, s);
01490 }
01491 
01492 static int remoteconsolehandler(char *s)
01493 {
01494    int ret = 0;
01495 
01496    /* Called when readline data is available */
01497    if (!ast_all_zeros(s))
01498       ast_el_add_history(s);
01499    /* The real handler for bang */
01500    if (s[0] == '!') {
01501       if (s[1])
01502          ast_safe_system(s+1);
01503       else
01504          ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
01505       ret = 1;
01506    }
01507    if ((strncasecmp(s, "quit", 4) == 0 || strncasecmp(s, "exit", 4) == 0) &&
01508        (s[4] == '\0' || isspace(s[4]))) {
01509       quit_handler(0, 0, 0, 0);
01510       ret = 1;
01511    }
01512 
01513    return ret;
01514 }
01515 
01516 static char abort_halt_help[] = 
01517 "Usage: abort shutdown\n"
01518 "       Causes Asterisk to abort an executing shutdown or restart, and resume normal\n"
01519 "       call operations.\n";
01520 
01521 static char shutdown_now_help[] = 
01522 "Usage: stop now\n"
01523 "       Shuts down a running Asterisk immediately, hanging up all active calls .\n";
01524 
01525 static char shutdown_gracefully_help[] = 
01526 "Usage: stop gracefully\n"
01527 "       Causes Asterisk to not accept new calls, and exit when all\n"
01528 "       active calls have terminated normally.\n";
01529 
01530 static char shutdown_when_convenient_help[] = 
01531 "Usage: stop when convenient\n"
01532 "       Causes Asterisk to perform a shutdown when all active calls have ended.\n";
01533 
01534 static char restart_now_help[] = 
01535 "Usage: restart now\n"
01536 "       Causes Asterisk to hangup all calls and exec() itself performing a cold\n"
01537 "       restart.\n";
01538 
01539 static char restart_gracefully_help[] = 
01540 "Usage: restart gracefully\n"
01541 "       Causes Asterisk to stop accepting new calls and exec() itself performing a cold\n"
01542 "       restart when all active calls have ended.\n";
01543 
01544 static char restart_when_convenient_help[] = 
01545 "Usage: restart when convenient\n"
01546 "       Causes Asterisk to perform a cold restart when all active calls have ended.\n";
01547 
01548 static char bang_help[] =
01549 "Usage: !<command>\n"
01550 "       Executes a given shell command\n";
01551 
01552 static char show_warranty_help[] =
01553 "Usage: core show warranty\n"
01554 "  Shows the warranty (if any) for this copy of Asterisk.\n";
01555 
01556 static char show_license_help[] =
01557 "Usage: core show license\n"
01558 "  Shows the license(s) for this copy of Asterisk.\n";
01559 
01560 static char version_help[] =
01561 "Usage: core show version\n"
01562 "       Shows Asterisk version information.\n";
01563 
01564 static int handle_version_deprecated(int fd, int argc, char *argv[])
01565 {
01566    if (argc != 2)
01567       return RESULT_SHOWUSAGE;
01568    ast_cli(fd, "Asterisk %s built by %s @ %s on a %s running %s on %s\n",
01569       ASTERISK_VERSION, ast_build_user, ast_build_hostname,
01570       ast_build_machine, ast_build_os, ast_build_date);
01571    return RESULT_SUCCESS;
01572 }
01573 
01574 static int handle_version(int fd, int argc, char *argv[])
01575 {
01576    if (argc != 3)
01577       return RESULT_SHOWUSAGE;
01578    ast_cli(fd, "Asterisk %s built by %s @ %s on a %s running %s on %s\n",
01579       ASTERISK_VERSION, ast_build_user, ast_build_hostname,
01580       ast_build_machine, ast_build_os, ast_build_date);
01581    return RESULT_SUCCESS;
01582 }
01583 
01584 #if 0
01585 static int handle_quit(int fd, int argc, char *argv[])
01586 {
01587    if (argc != 1)
01588       return RESULT_SHOWUSAGE;
01589    quit_handler(0, 0, 1, 0);
01590    return RESULT_SUCCESS;
01591 }
01592 #endif
01593 
01594 static int handle_shutdown_now(int fd, int argc, char *argv[])
01595 {
01596    if (argc != 2)
01597       return RESULT_SHOWUSAGE;
01598    quit_handler(0, 0 /* Not nice */, 1 /* safely */, 0 /* not restart */);
01599    return RESULT_SUCCESS;
01600 }
01601 
01602 static int handle_shutdown_gracefully(int fd, int argc, char *argv[])
01603 {
01604    if (argc != 2)
01605       return RESULT_SHOWUSAGE;
01606    quit_handler(0, 1 /* nicely */, 1 /* safely */, 0 /* no restart */);
01607    return RESULT_SUCCESS;
01608 }
01609 
01610 static int handle_shutdown_when_convenient(int fd, int argc, char *argv[])
01611 {
01612    if (argc != 3)
01613       return RESULT_SHOWUSAGE;
01614    ast_cli(fd, "Waiting for inactivity to perform halt\n");
01615    quit_handler(0, 2 /* really nicely */, 1 /* safely */, 0 /* don't restart */);
01616    return RESULT_SUCCESS;
01617 }
01618 
01619 static int handle_restart_now(int fd, int argc, char *argv[])
01620 {
01621    if (argc != 2)
01622       return RESULT_SHOWUSAGE;
01623    quit_handler(0, 0 /* not nicely */, 1 /* safely */, 1 /* restart */);
01624    return RESULT_SUCCESS;
01625 }
01626 
01627 static int handle_restart_gracefully(int fd, int argc, char *argv[])
01628 {
01629    if (argc != 2)
01630       return RESULT_SHOWUSAGE;
01631    quit_handler(0, 1 /* nicely */, 1 /* safely */, 1 /* restart */);
01632    return RESULT_SUCCESS;
01633 }
01634 
01635 static int handle_restart_when_convenient(int fd, int argc, char *argv[])
01636 {
01637    if (argc != 3)
01638       return RESULT_SHOWUSAGE;
01639    ast_cli(fd, "Waiting for inactivity to perform restart\n");
01640    quit_handler(0, 2 /* really nicely */, 1 /* safely */, 1 /* restart */);
01641    return RESULT_SUCCESS;
01642 }
01643 
01644 static int handle_abort_halt(int fd, int argc, char *argv[])
01645 {
01646    if (argc != 2)
01647       return RESULT_SHOWUSAGE;
01648    ast_cancel_shutdown();
01649    shuttingdown = 0;
01650    return RESULT_SUCCESS;
01651 }
01652 
01653 static int handle_bang(int fd, int argc, char *argv[])
01654 {
01655    return RESULT_SUCCESS;
01656 }
01657 static const char *warranty_lines[] = {
01658    "\n",
01659    "            NO WARRANTY\n",
01660    "\n",
01661    "BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\n",
01662    "FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN\n",
01663    "OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\n",
01664    "PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\n",
01665    "OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n",
01666    "MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS\n",
01667    "TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE\n",
01668    "PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\n",
01669    "REPAIR OR CORRECTION.\n",
01670    "\n",
01671    "IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\n",
01672    "WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\n",
01673    "REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\n",
01674    "INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\n",
01675    "OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\n",
01676    "TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\n",
01677    "YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\n",
01678    "PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\n",
01679    "POSSIBILITY OF SUCH DAMAGES.\n",
01680 };
01681 
01682 static int show_warranty(int fd, int argc, char *argv[])
01683 {
01684    int x;
01685 
01686    for (x = 0; x < ARRAY_LEN(warranty_lines); x++)
01687       ast_cli(fd, "%s", (char *) warranty_lines[x]);
01688 
01689    return RESULT_SUCCESS;
01690 }
01691 
01692 static const char *license_lines[] = {
01693    "\n",
01694    "This program is free software; you can redistribute it and/or modify\n",
01695    "it under the terms of the GNU General Public License version 2 as\n",
01696    "published by the Free Software Foundation.\n",
01697    "\n",
01698    "This program also contains components licensed under other licenses.\n",
01699    "They include:\n",
01700    "\n",
01701    "This program is distributed in the hope that it will be useful,\n",
01702    "but WITHOUT ANY WARRANTY; without even the implied warranty of\n",
01703    "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n",
01704    "GNU General Public License for more details.\n",
01705    "\n",
01706    "You should have received a copy of the GNU General Public License\n",
01707    "along with this program; if not, write to the Free Software\n",
01708    "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\n",
01709 };
01710 
01711 static int show_license(int fd, int argc, char *argv[])
01712 {
01713    int x;
01714 
01715    for (x = 0; x < ARRAY_LEN(license_lines); x++)
01716       ast_cli(fd, "%s", (char *) license_lines[x]);
01717 
01718    return RESULT_SUCCESS;
01719 }
01720 
01721 #define ASTERISK_PROMPT "*CLI> "
01722 
01723 #define ASTERISK_PROMPT2 "%s*CLI> "
01724 
01725 static struct ast_cli_entry cli_show_version_deprecated = {
01726    { "show", "version", NULL },
01727    handle_version_deprecated, "Display version info",
01728    version_help };
01729 
01730 #if !defined(LOW_MEMORY)
01731 static struct ast_cli_entry cli_show_version_files_deprecated = {
01732    { "show", "version", "files", NULL },
01733    handle_show_version_files_deprecated, NULL,
01734    NULL, complete_show_version_files_deprecated };
01735 
01736 static struct ast_cli_entry cli_show_profile_deprecated = {
01737    { "show", "profile", NULL },
01738    handle_show_profile_deprecated, NULL,
01739    NULL };
01740 
01741 static struct ast_cli_entry cli_clear_profile_deprecated = {
01742    { "clear", "profile", NULL },
01743    handle_show_profile_deprecated, NULL,
01744    NULL };
01745 #endif /* ! LOW_MEMORY */
01746 
01747 static struct ast_cli_entry cli_asterisk[] = {
01748    { { "abort", "halt", NULL },
01749    handle_abort_halt, "Cancel a running halt",
01750    abort_halt_help },
01751 
01752    { { "stop", "now", NULL },
01753    handle_shutdown_now, "Shut down Asterisk immediately",
01754    shutdown_now_help },
01755 
01756    { { "stop", "gracefully", NULL },
01757    handle_shutdown_gracefully, "Gracefully shut down Asterisk",
01758    shutdown_gracefully_help },
01759 
01760    { { "stop", "when", "convenient", NULL },
01761    handle_shutdown_when_convenient, "Shut down Asterisk at empty call volume",
01762    shutdown_when_convenient_help },
01763 
01764    { { "restart", "now", NULL },
01765    handle_restart_now, "Restart Asterisk immediately", restart_now_help },
01766 
01767    { { "restart", "gracefully", NULL },
01768    handle_restart_gracefully, "Restart Asterisk gracefully",
01769    restart_gracefully_help },
01770 
01771    { { "restart", "when", "convenient", NULL },
01772    handle_restart_when_convenient, "Restart Asterisk at empty call volume",
01773    restart_when_convenient_help },
01774 
01775    { { "core", "show", "warranty", NULL },
01776    show_warranty, "Show the warranty (if any) for this copy of Asterisk",
01777    show_warranty_help },
01778 
01779    { { "core", "show", "license", NULL },
01780    show_license, "Show the license(s) for this copy of Asterisk",
01781    show_license_help },
01782 
01783    { { "core", "show", "version", NULL },
01784    handle_version, "Display version info",
01785    version_help, NULL, &cli_show_version_deprecated },
01786 
01787    { { "!", NULL },
01788    handle_bang, "Execute a shell command",
01789    bang_help },
01790 
01791 #if !defined(LOW_MEMORY)
01792    { { "core", "show", "file", "version", NULL },
01793    handle_show_version_files, "List versions of files used to build Asterisk",
01794    show_version_files_help, complete_show_version_files, &cli_show_version_files_deprecated },
01795 
01796    { { "core", "show", "threads", NULL },
01797    handle_show_threads, "Show running threads",
01798    show_threads_help },
01799 
01800    { { "core", "show", "profile", NULL },
01801    handle_show_profile, "Display profiling info",
01802    NULL, NULL, &cli_show_profile_deprecated },
01803 
01804    { { "core", "clear", "profile", NULL },
01805    handle_show_profile, "Clear profiling info",
01806    NULL, NULL, &cli_clear_profile_deprecated },
01807 #endif /* ! LOW_MEMORY */
01808 };
01809 
01810 static int ast_el_read_char(EditLine *el, char *cp)
01811 {
01812    int num_read = 0;
01813    int lastpos = 0;
01814    struct pollfd fds[2];
01815    int res;
01816    int max;
01817 #define EL_BUF_SIZE 512
01818    char buf[EL_BUF_SIZE];
01819 
01820    for (;;) {
01821       max = 1;
01822       fds[0].fd = ast_consock;
01823       fds[0].events = POLLIN;
01824       if (!ast_opt_exec) {
01825          fds[1].fd = STDIN_FILENO;
01826          fds[1].events = POLLIN;
01827          max++;
01828       }
01829       res = ast_poll(fds, max, -1);
01830       if (res < 0) {
01831          if (sig_flags.need_quit)
01832             break;
01833          if (errno == EINTR)
01834             continue;
01835          ast_log(LOG_ERROR, "poll failed: %s\n", strerror(errno));
01836          break;
01837       }
01838 
01839       if (!ast_opt_exec && fds[1].revents) {
01840          num_read = read(STDIN_FILENO, cp, 1);
01841          if (num_read < 1) {
01842             break;
01843          } else 
01844             return (num_read);
01845       }
01846       if (fds[0].revents) {
01847          char *tmp;
01848          res = read(ast_consock, buf, sizeof(buf) - 1);
01849          /* if the remote side disappears exit */
01850          if (res < 1) {
01851             fprintf(stderr, "\nDisconnected from Asterisk server\n");
01852             if (!ast_opt_reconnect) {
01853                quit_handler(0, 0, 0, 0);
01854             } else {
01855                int tries;
01856                int reconnects_per_second = 20;
01857                fprintf(stderr, "Attempting to reconnect for 30 seconds\n");
01858                for (tries=0; tries < 30 * reconnects_per_second; tries++) {
01859                   if (ast_tryconnect()) {
01860                      fprintf(stderr, "Reconnect succeeded after %.3f seconds\n", 1.0 / reconnects_per_second * tries);
01861                      printf("%s", term_quit());
01862                      WELCOME_MESSAGE;
01863                      if (!ast_opt_mute)
01864                         fdsend(ast_consock, "logger mute silent");
01865                      else 
01866                         printf("log and verbose output currently muted ('logger mute' to unmute)\n");
01867                      break;
01868                   } else {
01869                      usleep(1000000 / reconnects_per_second);
01870                   }
01871                }
01872                if (tries >= 30 * reconnects_per_second) {
01873                   fprintf(stderr, "Failed to reconnect for 30 seconds.  Quitting.\n");
01874                   quit_handler(0, 0, 0, 0);
01875                }
01876             }
01877          }
01878 
01879          buf[res] = '\0';
01880 
01881          /* Strip preamble from asynchronous events, too */
01882          for (tmp = buf; *tmp; tmp++) {
01883             if (*tmp == 127) {
01884                memmove(tmp, tmp + 1, strlen(tmp));
01885                tmp--;
01886                res--;
01887             }
01888          }
01889 
01890          /* Write over the CLI prompt */
01891          if (!ast_opt_exec && !lastpos) {
01892             if (write(STDOUT_FILENO, "\r", 5) < 0) {
01893             }
01894          }
01895          if (write(STDOUT_FILENO, buf, res) < 0) {
01896          }
01897          if ((res < EL_BUF_SIZE - 1) && ((buf[res-1] == '\n') || (buf[res-2] == '\n'))) {
01898             *cp = CC_REFRESH;
01899             return(1);
01900          } else {
01901             lastpos = 1;
01902          }
01903       }
01904    }
01905 
01906    *cp = '\0';
01907    return (0);
01908 }
01909 
01910 static char *cli_prompt(EditLine *el)
01911 {
01912    static char prompt[200];
01913    char *pfmt;
01914    int color_used = 0;
01915    char term_code[20];
01916 
01917    if ((pfmt = getenv("ASTERISK_PROMPT"))) {
01918       char *t = pfmt, *p = prompt;
01919       memset(prompt, 0, sizeof(prompt));
01920       while (*t != '\0' && *p < sizeof(prompt)) {
01921          if (*t == '%') {
01922             char hostname[MAXHOSTNAMELEN]="";
01923             int i;
01924             time_t ts;
01925             struct tm tm;
01926 #ifdef linux
01927             FILE *LOADAVG;
01928 #endif
01929             int fgcolor = COLOR_WHITE, bgcolor = COLOR_BLACK;
01930 
01931             t++;
01932             switch (*t) {
01933             case 'C': /* color */
01934                t++;
01935                if (sscanf(t, "%30d;%30d%n", &fgcolor, &bgcolor, &i) == 2) {
01936                   strncat(p, term_color_code(term_code, fgcolor, bgcolor, sizeof(term_code)),sizeof(prompt) - strlen(prompt) - 1);
01937                   t += i - 1;
01938                } else if (sscanf(t, "%30d%n", &fgcolor, &i) == 1) {
01939                   strncat(p, term_color_code(term_code, fgcolor, 0, sizeof(term_code)),sizeof(prompt) - strlen(prompt) - 1);
01940                   t += i - 1;
01941                }
01942 
01943                /* If the color has been reset correctly, then there's no need to reset it later */
01944                if ((fgcolor == COLOR_WHITE) && (bgcolor == COLOR_BLACK)) {
01945                   color_used = 0;
01946                } else {
01947                   color_used = 1;
01948                }
01949                break;
01950             case 'd': /* date */
01951                memset(&tm, 0, sizeof(tm));
01952                time(&ts);
01953                if (ast_localtime(&ts, &tm, NULL)) {
01954                   strftime(p, sizeof(prompt) - strlen(prompt), "%Y-%m-%d", &tm);
01955                }
01956                break;
01957             case 'h': /* hostname */
01958                if (!gethostname(hostname, sizeof(hostname) - 1)) {
01959                   strncat(p, hostname, sizeof(prompt) - strlen(prompt) - 1);
01960                } else {
01961                   strncat(p, "localhost", sizeof(prompt) - strlen(prompt) - 1);
01962                }
01963                break;
01964             case 'H': /* short hostname */
01965                if (!gethostname(hostname, sizeof(hostname) - 1)) {
01966                   for (i = 0; i < sizeof(hostname); i++) {
01967                      if (hostname[i] == '.') {
01968                         hostname[i] = '\0';
01969                         break;
01970                      }
01971                   }
01972                   strncat(p, hostname, sizeof(prompt) - strlen(prompt) - 1);
01973                } else {
01974                   strncat(p, "localhost", sizeof(prompt) - strlen(prompt) - 1);
01975                }
01976                break;
01977 #ifdef linux
01978             case 'l': /* load avg */
01979                t++;
01980                if ((LOADAVG = fopen("/proc/loadavg", "r"))) {
01981                   float avg1, avg2, avg3;
01982                   int actproc, totproc, npid, which;
01983 
01984                   if (fscanf(LOADAVG, "%30f %30f %30f %30d/%30d %30d",
01985                         &avg1, &avg2, &avg3, &actproc, &totproc, &npid) != 6) {
01986                      ast_log(LOG_WARNING, "parsing /proc/loadavg failed\n");
01987                      fclose(LOADAVG);
01988                      break;
01989                   }
01990                   if (sscanf(t, "%30d", &which) == 1) {
01991                      switch (which) {
01992                      case 1:
01993                         snprintf(p, sizeof(prompt) - strlen(prompt), "%.2f", avg1);
01994                         break;
01995                      case 2:
01996                         snprintf(p, sizeof(prompt) - strlen(prompt), "%.2f", avg2);
01997                         break;
01998                      case 3:
01999                         snprintf(p, sizeof(prompt) - strlen(prompt), "%.2f", avg3);
02000                         break;
02001                      case 4:
02002                         snprintf(p, sizeof(prompt) - strlen(prompt), "%d/%d", actproc, totproc);
02003                         break;
02004                      case 5:
02005                         snprintf(p, sizeof(prompt) - strlen(prompt), "%d", npid);
02006                         break;
02007                      }
02008                   }
02009                   fclose(LOADAVG);
02010                }
02011                break;
02012 #endif
02013             case 's': /* Asterisk system name (from asterisk.conf) */
02014                strncat(p, ast_config_AST_SYSTEM_NAME, sizeof(prompt) - strlen(prompt) - 1);
02015                break;
02016             case 't': /* time */
02017                memset(&tm, 0, sizeof(tm));
02018                time(&ts);
02019                if (ast_localtime(&ts, &tm, NULL)) {
02020                   strftime(p, sizeof(prompt) - strlen(prompt), "%H:%M:%S", &tm);
02021                }
02022                break;
02023             case '#': /* process console or remote? */
02024                if (!ast_opt_remote) {
02025                   strncat(p, "#", sizeof(prompt) - strlen(prompt) - 1);
02026                } else {
02027                   strncat(p, ">", sizeof(prompt) - strlen(prompt) - 1);
02028                }
02029                break;
02030             case '%': /* literal % */
02031                strncat(p, "%", sizeof(prompt) - strlen(prompt) - 1);
02032                break;
02033             case '\0': /* % is last character - prevent bug */
02034                t--;
02035                break;
02036             }
02037             while (*p != '\0') {
02038                p++;
02039             }
02040             t++;
02041          } else {
02042             *p = *t;
02043             p++;
02044             t++;
02045          }
02046       }
02047       if (color_used) {
02048          /* Force colors back to normal at end */
02049          term_color_code(term_code, COLOR_WHITE, COLOR_BLACK, sizeof(term_code));
02050          if (strlen(term_code) > sizeof(prompt) - strlen(prompt) - 1) {
02051             ast_copy_string(prompt + sizeof(prompt) - strlen(term_code) - 1, term_code, strlen(term_code) + 1);
02052          } else {
02053             /* This looks wrong, but we've already checked the length of term_code to ensure it's safe */
02054             strncat(p, term_code, sizeof(term_code));
02055          }
02056       }
02057    } else if (remotehostname)
02058       snprintf(prompt, sizeof(prompt), ASTERISK_PROMPT2, remotehostname);
02059    else
02060       snprintf(prompt, sizeof(prompt), ASTERISK_PROMPT);
02061 
02062    return(prompt);   
02063 }
02064 
02065 static char **ast_el_strtoarr(char *buf)
02066 {
02067    char **match_list = NULL, *retstr;
02068    size_t match_list_len;
02069    int matches = 0;
02070 
02071    match_list_len = 1;
02072    while ( (retstr = strsep(&buf, " ")) != NULL) {
02073 
02074       if (!strcmp(retstr, AST_CLI_COMPLETE_EOF))
02075          break;
02076       if (matches + 1 >= match_list_len) {
02077          match_list_len <<= 1;
02078          if (!(match_list = ast_realloc(match_list, match_list_len * sizeof(char *)))) {
02079             /* TODO: Handle memory allocation failure */
02080          }
02081       }
02082 
02083       match_list[matches++] = strdup(retstr);
02084    }
02085 
02086    if (!match_list)
02087       return (char **) NULL;
02088 
02089    if (matches >= match_list_len) {
02090       if (!(match_list = ast_realloc(match_list, (match_list_len + 1) * sizeof(char *)))) {
02091          /* TODO: Handle memory allocation failure */
02092       }
02093    }
02094 
02095    match_list[matches] = (char *) NULL;
02096 
02097    return match_list;
02098 }
02099 
02100 static int ast_el_sort_compare(const void *i1, const void *i2)
02101 {
02102    char *s1, *s2;
02103 
02104    s1 = ((char **)i1)[0];
02105    s2 = ((char **)i2)[0];
02106 
02107    return strcasecmp(s1, s2);
02108 }
02109 
02110 static int ast_cli_display_match_list(char **matches, int len, int max)
02111 {
02112    int i, idx, limit, count;
02113    int screenwidth = 0;
02114    int numoutput = 0, numoutputline = 0;
02115 
02116    screenwidth = ast_get_termcols(STDOUT_FILENO);
02117 
02118    /* find out how many entries can be put on one line, with two spaces between strings */
02119    limit = screenwidth / (max + 2);
02120    if (limit == 0)
02121       limit = 1;
02122 
02123    /* how many lines of output */
02124    count = len / limit;
02125    if (count * limit < len)
02126       count++;
02127 
02128    idx = 1;
02129 
02130    qsort(&matches[0], (size_t)(len), sizeof(char *), ast_el_sort_compare);
02131 
02132    for (; count > 0; count--) {
02133       numoutputline = 0;
02134       for (i=0; i < limit && matches[idx]; i++, idx++) {
02135 
02136          /* Don't print dupes */
02137          if ( (matches[idx+1] != NULL && strcmp(matches[idx], matches[idx+1]) == 0 ) ) {
02138             i--;
02139             free(matches[idx]);
02140             matches[idx] = NULL;
02141             continue;
02142          }
02143 
02144          numoutput++;
02145          numoutputline++;
02146          fprintf(stdout, "%-*s  ", max, matches[idx]);
02147          free(matches[idx]);
02148          matches[idx] = NULL;
02149       }
02150       if (numoutputline > 0)
02151          fprintf(stdout, "\n");
02152    }
02153 
02154    return numoutput;
02155 }
02156 
02157 
02158 static char *cli_complete(EditLine *el, int ch)
02159 {
02160    int len = 0;
02161    char *ptr;
02162    int nummatches = 0;
02163    char **matches;
02164    int retval = CC_ERROR;
02165    char buf[2048], savechr;
02166    int res;
02167 
02168    LineInfo *lf = (LineInfo *)el_line(el);
02169 
02170    savechr = *(char *)lf->cursor;
02171    *(char *)lf->cursor = '\0';
02172    ptr = (char *)lf->cursor;
02173    if (ptr) {
02174       while (ptr > lf->buffer) {
02175          if (isspace(*ptr)) {
02176             ptr++;
02177             break;
02178          }
02179          ptr--;
02180       }
02181    }
02182 
02183    len = lf->cursor - ptr;
02184 
02185    if (ast_opt_remote) {
02186       snprintf(buf, sizeof(buf),"_COMMAND NUMMATCHES \"%s\" \"%s\"", lf->buffer, ptr); 
02187       fdsend(ast_consock, buf);
02188       res = read(ast_consock, buf, sizeof(buf) - 1);
02189       buf[res] = '\0';
02190       nummatches = atoi(buf);
02191 
02192       if (nummatches > 0) {
02193          char *mbuf;
02194          int mlen = 0, maxmbuf = 2048;
02195          /* Start with a 2048 byte buffer */       
02196          if (!(mbuf = ast_malloc(maxmbuf))) {
02197             lf->cursor[0] = savechr;
02198             return (char *)(CC_ERROR);
02199          }
02200          snprintf(buf, sizeof(buf),"_COMMAND MATCHESARRAY \"%s\" \"%s\"", lf->buffer, ptr); 
02201          fdsend(ast_consock, buf);
02202          res = 0;
02203          mbuf[0] = '\0';
02204          while (!strstr(mbuf, AST_CLI_COMPLETE_EOF) && res != -1) {
02205             if (mlen + 1024 > maxmbuf) {
02206                /* Every step increment buffer 1024 bytes */
02207                maxmbuf += 1024;              
02208                if (!(mbuf = ast_realloc(mbuf, maxmbuf))) {
02209                   lf->cursor[0] = savechr;
02210                   return (char *)(CC_ERROR);
02211                }
02212             }
02213             /* Only read 1024 bytes at a time */
02214             res = read(ast_consock, mbuf + mlen, 1024);
02215             if (res > 0)
02216                mlen += res;
02217          }
02218          mbuf[mlen] = '\0';
02219 
02220          matches = ast_el_strtoarr(mbuf);
02221          free(mbuf);
02222       } else
02223          matches = (char **) NULL;
02224    } else {
02225       char **p, *oldbuf=NULL;
02226       nummatches = 0;
02227       matches = ast_cli_completion_matches((char *)lf->buffer,ptr);
02228       for (p = matches; p && *p; p++) {
02229          if (!oldbuf || strcmp(*p,oldbuf))
02230             nummatches++;
02231          oldbuf = *p;
02232       }
02233    }
02234 
02235    if (matches) {
02236       int i;
02237       int matches_num, maxlen, match_len;
02238 
02239       if (matches[0][0] != '\0') {
02240          el_deletestr(el, (int) len);
02241          el_insertstr(el, matches[0]);
02242          retval = CC_REFRESH;
02243       }
02244 
02245       if (nummatches == 1) {
02246          /* Found an exact match */
02247          el_insertstr(el, " ");
02248          retval = CC_REFRESH;
02249       } else {
02250          /* Must be more than one match */
02251          for (i=1, maxlen=0; matches[i]; i++) {
02252             match_len = strlen(matches[i]);
02253             if (match_len > maxlen)
02254                maxlen = match_len;
02255          }
02256          matches_num = i - 1;
02257          if (matches_num >1) {
02258             fprintf(stdout, "\n");
02259             ast_cli_display_match_list(matches, nummatches, maxlen);
02260             retval = CC_REDISPLAY;
02261          } else { 
02262             el_insertstr(el," ");
02263             retval = CC_REFRESH;
02264          }
02265       }
02266       for (i = 0; matches[i]; i++)
02267          free(matches[i]);
02268       free(matches);
02269    }
02270 
02271    lf->cursor[0] = savechr;
02272 
02273    return (char *)(long)retval;
02274 }
02275 
02276 static int ast_el_initialize(void)
02277 {
02278    HistEvent ev;
02279    char *editor = getenv("AST_EDITOR");
02280 
02281    if (el != NULL)
02282       el_end(el);
02283    if (el_hist != NULL)
02284       history_end(el_hist);
02285 
02286    el = el_init("asterisk", stdin, stdout, stderr);
02287    el_set(el, EL_PROMPT, cli_prompt);
02288 
02289    el_set(el, EL_EDITMODE, 1);      
02290    el_set(el, EL_EDITOR, editor ? editor : "emacs");     
02291    el_hist = history_init();
02292    if (!el || !el_hist)
02293       return -1;
02294 
02295    /* setup history with 100 entries */
02296    history(el_hist, &ev, H_SETSIZE, 100);
02297 
02298    el_set(el, EL_HIST, history, el_hist);
02299 
02300    el_set(el, EL_ADDFN, "ed-complete", "Complete argument", cli_complete);
02301    /* Bind <tab> to command completion */
02302    el_set(el, EL_BIND, "^I", "ed-complete", NULL);
02303    /* Bind ? to command completion */
02304    el_set(el, EL_BIND, "?", "ed-complete", NULL);
02305    /* Bind ^D to redisplay */
02306    el_set(el, EL_BIND, "^D", "ed-redisplay", NULL);
02307 
02308    return 0;
02309 }
02310 
02311 static int ast_el_add_history(char *buf)
02312 {
02313    HistEvent ev;
02314 
02315    if (el_hist == NULL || el == NULL)
02316       ast_el_initialize();
02317    if (strlen(buf) > 256)
02318       return 0;
02319    return (history(el_hist, &ev, H_ENTER, buf));
02320 }
02321 
02322 static int ast_el_write_history(char *filename)
02323 {
02324    HistEvent ev;
02325 
02326    if (el_hist == NULL || el == NULL)
02327       ast_el_initialize();
02328 
02329    return (history(el_hist, &ev, H_SAVE, filename));
02330 }
02331 
02332 static int ast_el_read_history(char *filename)
02333 {
02334    char buf[256];
02335    FILE *f;
02336    int ret = -1;
02337 
02338    if (el_hist == NULL || el == NULL)
02339       ast_el_initialize();
02340 
02341    if ((f = fopen(filename, "r")) == NULL)
02342       return ret;
02343 
02344    while (!feof(f)) {
02345       if (!fgets(buf, sizeof(buf), f)) {
02346          continue;
02347       }
02348       if (!strcmp(buf, "_HiStOrY_V2_\n"))
02349          continue;
02350       if (ast_all_zeros(buf))
02351          continue;
02352       if ((ret = ast_el_add_history(buf)) == -1)
02353          break;
02354    }
02355    fclose(f);
02356 
02357    return ret;
02358 }
02359 
02360 static void ast_remotecontrol(char *data)
02361 {
02362    char buf[80];
02363    int res;
02364    char filename[80] = "";
02365    char *hostname;
02366    char *cpid;
02367    char *version;
02368    int pid;
02369    char tmp[80];
02370    char *stringp = NULL;
02371 
02372    char *ebuf;
02373    int num = 0;
02374 
02375    memset(&sig_flags, 0, sizeof(sig_flags));
02376    signal(SIGINT, __remote_quit_handler);
02377    signal(SIGTERM, __remote_quit_handler);
02378    signal(SIGHUP, __remote_quit_handler);
02379 
02380    if (read(ast_consock, buf, sizeof(buf)) < 0) {
02381       ast_log(LOG_ERROR, "read() failed: %s\n", strerror(errno));
02382       return;
02383    }
02384    if (data) {
02385       if (write(ast_consock, data, strlen(data) + 1) < 0) {
02386          ast_log(LOG_ERROR, "write() failed: %s\n", strerror(errno));
02387          if (sig_flags.need_quit == 1) {
02388             return;
02389          }
02390       }
02391    }
02392    stringp = buf;
02393    hostname = strsep(&stringp, "/");
02394    cpid = strsep(&stringp, "/");
02395    version = strsep(&stringp, "\n");
02396    if (!version)
02397       version = "<Version Unknown>";
02398    stringp = hostname;
02399    strsep(&stringp, ".");
02400    if (cpid)
02401       pid = atoi(cpid);
02402    else
02403       pid = -1;
02404    if (!data) {
02405       snprintf(tmp, sizeof(tmp), "core set verbose atleast %d", option_verbose);
02406       fdsend(ast_consock, tmp);
02407       snprintf(tmp, sizeof(tmp), "core set debug atleast %d", option_debug);
02408       fdsend(ast_consock, tmp);
02409       if (!ast_opt_mute)
02410          fdsend(ast_consock, "logger mute silent");
02411       else 
02412          printf("log and verbose output currently muted ('logger mute' to unmute)\n");
02413    }
02414    ast_verbose("Connected to Asterisk %s currently running on %s (pid = %d)\n", version, hostname, pid);
02415    remotehostname = hostname;
02416    if (getenv("HOME")) 
02417       snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
02418    if (el_hist == NULL || el == NULL)
02419       ast_el_initialize();
02420 
02421    el_set(el, EL_GETCFN, ast_el_read_char);
02422 
02423    if (!ast_strlen_zero(filename))
02424       ast_el_read_history(filename);
02425 
02426    if (ast_opt_exec && data) {  /* hack to print output then exit if asterisk -rx is used */
02427       struct pollfd fds;
02428       fds.fd = ast_consock;
02429       fds.events = POLLIN;
02430       fds.revents = 0;
02431       while (ast_poll(&fds, 1, 500) > 0) {
02432          char buf[512] = "", *curline = buf, *nextline;
02433          int not_written = 1;
02434 
02435          if (sig_flags.need_quit == 1) {
02436             break;
02437          }
02438 
02439          if (read(ast_consock, buf, sizeof(buf) - 1) <= 0) {
02440             break;
02441          }
02442 
02443          do {
02444             if ((nextline = strchr(curline, '\n'))) {
02445                nextline++;
02446             } else {
02447                nextline = strchr(curline, '\0');
02448             }
02449 
02450             /* Skip verbose lines */
02451             if (*curline != 127) {
02452                not_written = 0;
02453                if (write(STDOUT_FILENO, curline, nextline - curline) < 0) {
02454                   ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno));
02455                }
02456             }
02457             curline = nextline;
02458          } while (!ast_strlen_zero(curline));
02459 
02460          /* No non-verbose output in 500ms */
02461          if (not_written) {
02462             break;
02463          }
02464       }
02465       return;
02466    }
02467    for (;;) {
02468       ebuf = (char *)el_gets(el, &num);
02469 
02470       if (sig_flags.need_quit == 1) {
02471          break;
02472       }
02473 
02474       if (!ebuf && write(1, "", 1) < 0)
02475          break;
02476 
02477       if (!ast_strlen_zero(ebuf)) {
02478          if (ebuf[strlen(ebuf)-1] == '\n')
02479             ebuf[strlen(ebuf)-1] = '\0';
02480          if (!remoteconsolehandler(ebuf)) {
02481             /* Strip preamble from output */
02482             char *tmp;
02483             for (tmp = ebuf; *tmp; tmp++) {
02484                if (*tmp == 127) {
02485                   memmove(tmp, tmp + 1, strlen(tmp));
02486                   tmp--;
02487                }
02488             }
02489             res = write(ast_consock, ebuf, strlen(ebuf) + 1);
02490             if (res < 1) {
02491                ast_log(LOG_WARNING, "Unable to write: %s\n", strerror(errno));
02492                break;
02493             }
02494          }
02495       }
02496    }
02497    printf("\nDisconnected from Asterisk server\n");
02498 }
02499 
02500 static int show_version(void)
02501 {
02502    printf("Asterisk " ASTERISK_VERSION "\n");
02503    return 0;
02504 }
02505 
02506 static int show_cli_help(void) {
02507    printf("Asterisk " ASTERISK_VERSION ", Copyright (C) 1999 - 2010, Digium, Inc. and others.\n");
02508    printf("Usage: asterisk [OPTIONS]\n");
02509    printf("Valid Options:\n");
02510    printf("   -V              Display version number and exit\n");
02511    printf("   -C <configfile> Use an alternate configuration file\n");
02512    printf("   -G <group>      Run as a group other than the caller\n");
02513    printf("   -U <user>       Run as a user other than the caller\n");
02514    printf("   -c              Provide console CLI\n");
02515    printf("   -d              Enable extra debugging\n");
02516 #if HAVE_WORKING_FORK
02517    printf("   -f              Do not fork\n");
02518    printf("   -F              Always fork\n");
02519 #endif
02520    printf("   -g              Dump core in case of a crash\n");
02521    printf("   -h              This help screen\n");
02522    printf("   -i              Initialize crypto keys at startup\n");
02523    printf("   -I              Enable internal timing if %s timer is available\n", dahdi_chan_name);
02524    printf("   -L <load>       Limit the maximum load average before rejecting new calls\n");
02525    printf("   -M <value>      Limit the maximum number of calls to the specified value\n");
02526    printf("   -m              Mute debugging and console output on the console\n");
02527    printf("   -n              Disable console colorization\n");
02528    printf("   -p              Run as pseudo-realtime thread\n");
02529    printf("   -q              Quiet mode (suppress output)\n");
02530    printf("   -r              Connect to Asterisk on this machine\n");
02531    printf("   -R              Same as -r, except attempt to reconnect if disconnected\n");
02532    printf("   -t              Record soundfiles in /var/tmp and move them where they\n");
02533    printf("                   belong after they are done\n");
02534    printf("   -T              Display the time in [Mmm dd hh:mm:ss] format for each line\n");
02535    printf("                   of output to the CLI\n");
02536    printf("   -v              Increase verbosity (multiple v's = more verbose)\n");
02537    printf("   -x <cmd>        Execute command <cmd> (only valid with -r)\n");
02538    printf("\n");
02539    return 0;
02540 }
02541 
02542 static void ast_readconfig(void) 
02543 {
02544    struct ast_config *cfg;
02545    struct ast_variable *v;
02546    char *config = AST_CONFIG_FILE;
02547 
02548    if (ast_opt_override_config) {
02549       cfg = ast_config_load(ast_config_AST_CONFIG_FILE);
02550       if (!cfg)
02551          ast_log(LOG_WARNING, "Unable to open specified master config file '%s', using built-in defaults\n", ast_config_AST_CONFIG_FILE);
02552    } else {
02553       cfg = ast_config_load(config);
02554    }
02555 
02556    /* init with buildtime config */
02557    ast_copy_string(ast_config_AST_CONFIG_DIR, AST_CONFIG_DIR, sizeof(ast_config_AST_CONFIG_DIR));
02558    ast_copy_string(ast_config_AST_SPOOL_DIR, AST_SPOOL_DIR, sizeof(ast_config_AST_SPOOL_DIR));
02559    ast_copy_string(ast_config_AST_MODULE_DIR, AST_MODULE_DIR, sizeof(ast_config_AST_MODULE_DIR));
02560    snprintf(ast_config_AST_MONITOR_DIR, sizeof(ast_config_AST_MONITOR_DIR) - 1, "%s/monitor", ast_config_AST_SPOOL_DIR);
02561    ast_copy_string(ast_config_AST_VAR_DIR, AST_VAR_DIR, sizeof(ast_config_AST_VAR_DIR));
02562    ast_copy_string(ast_config_AST_DATA_DIR, AST_DATA_DIR, sizeof(ast_config_AST_DATA_DIR));
02563    ast_copy_string(ast_config_AST_LOG_DIR, AST_LOG_DIR, sizeof(ast_config_AST_LOG_DIR));
02564    ast_copy_string(ast_config_AST_AGI_DIR, AST_AGI_DIR, sizeof(ast_config_AST_AGI_DIR));
02565    ast_copy_string(ast_config_AST_DB, AST_DB, sizeof(ast_config_AST_DB));
02566    ast_copy_string(ast_config_AST_KEY_DIR, AST_KEY_DIR, sizeof(ast_config_AST_KEY_DIR));
02567    ast_copy_string(ast_config_AST_PID, AST_PID, sizeof(ast_config_AST_PID));
02568    ast_copy_string(ast_config_AST_SOCKET, AST_SOCKET, sizeof(ast_config_AST_SOCKET));
02569    ast_copy_string(ast_config_AST_RUN_DIR, AST_RUN_DIR, sizeof(ast_config_AST_RUN_DIR));
02570 
02571    /* no asterisk.conf? no problem, use buildtime config! */
02572    if (!cfg) {
02573       return;
02574    }
02575 
02576    for (v = ast_variable_browse(cfg, "files"); v; v = v->next) {
02577       if (!strcasecmp(v->name, "astctlpermissions")) {
02578          ast_copy_string(ast_config_AST_CTL_PERMISSIONS, v->value, sizeof(ast_config_AST_CTL_PERMISSIONS));
02579       } else if (!strcasecmp(v->name, "astctlowner")) {
02580          ast_copy_string(ast_config_AST_CTL_OWNER, v->value, sizeof(ast_config_AST_CTL_OWNER));
02581       } else if (!strcasecmp(v->name, "astctlgroup")) {
02582          ast_copy_string(ast_config_AST_CTL_GROUP, v->value, sizeof(ast_config_AST_CTL_GROUP));
02583       } else if (!strcasecmp(v->name, "astctl")) {
02584          ast_copy_string(ast_config_AST_CTL, v->value, sizeof(ast_config_AST_CTL));
02585       }
02586    }
02587 
02588    for (v = ast_variable_browse(cfg, "directories"); v; v = v->next) {
02589       if (!strcasecmp(v->name, "astetcdir")) {
02590          ast_copy_string(ast_config_AST_CONFIG_DIR, v->value, sizeof(ast_config_AST_CONFIG_DIR));
02591       } else if (!strcasecmp(v->name, "astspooldir")) {
02592          ast_copy_string(ast_config_AST_SPOOL_DIR, v->value, sizeof(ast_config_AST_SPOOL_DIR));
02593          snprintf(ast_config_AST_MONITOR_DIR, sizeof(ast_config_AST_MONITOR_DIR) - 1, "%s/monitor", v->value);
02594       } else if (!strcasecmp(v->name, "astvarlibdir")) {
02595          ast_copy_string(ast_config_AST_VAR_DIR, v->value, sizeof(ast_config_AST_VAR_DIR));
02596          snprintf(ast_config_AST_DB, sizeof(ast_config_AST_DB), "%s/astdb", v->value);
02597       } else if (!strcasecmp(v->name, "astdatadir")) {
02598          ast_copy_string(ast_config_AST_DATA_DIR, v->value, sizeof(ast_config_AST_DATA_DIR));
02599          snprintf(ast_config_AST_KEY_DIR, sizeof(ast_config_AST_KEY_DIR), "%s/keys", v->value);
02600       } else if (!strcasecmp(v->name, "astlogdir")) {
02601          ast_copy_string(ast_config_AST_LOG_DIR, v->value, sizeof(ast_config_AST_LOG_DIR));
02602       } else if (!strcasecmp(v->name, "astagidir")) {
02603          ast_copy_string(ast_config_AST_AGI_DIR, v->value, sizeof(ast_config_AST_AGI_DIR));
02604       } else if (!strcasecmp(v->name, "astrundir")) {
02605          snprintf(ast_config_AST_PID, sizeof(ast_config_AST_PID), "%s/%s", v->value, "asterisk.pid");
02606          snprintf(ast_config_AST_SOCKET, sizeof(ast_config_AST_SOCKET), "%s/%s", v->value, ast_config_AST_CTL);
02607          ast_copy_string(ast_config_AST_RUN_DIR, v->value, sizeof(ast_config_AST_RUN_DIR));
02608       } else if (!strcasecmp(v->name, "astmoddir")) {
02609          ast_copy_string(ast_config_AST_MODULE_DIR, v->value, sizeof(ast_config_AST_MODULE_DIR));
02610       }
02611    }
02612 
02613    for (v = ast_variable_browse(cfg, "options"); v; v = v->next) {
02614       /* verbose level (-v at startup) */
02615       if (!strcasecmp(v->name, "verbose")) {
02616          option_verbose = atoi(v->value);
02617       /* whether or not to force timestamping in CLI verbose output. (-T at startup) */
02618       } else if (!strcasecmp(v->name, "timestamp")) {
02619          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TIMESTAMP);
02620       /* whether or not to support #exec in config files */
02621       } else if (!strcasecmp(v->name, "execincludes")) {
02622          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_EXEC_INCLUDES);
02623       /* debug level (-d at startup) */
02624       } else if (!strcasecmp(v->name, "debug")) {
02625          option_debug = 0;
02626          if (sscanf(v->value, "%30d", &option_debug) != 1) {
02627             option_debug = ast_true(v->value);
02628          }
02629 #if HAVE_WORKING_FORK
02630       /* Disable forking (-f at startup) */
02631       } else if (!strcasecmp(v->name, "nofork")) {
02632          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_FORK);
02633       /* Always fork, even if verbose or debug are enabled (-F at startup) */
02634       } else if (!strcasecmp(v->name, "alwaysfork")) {
02635          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_ALWAYS_FORK);
02636 #endif
02637       /* Run quietly (-q at startup ) */
02638       } else if (!strcasecmp(v->name, "quiet")) {
02639          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_QUIET);
02640       /* Run as console (-c at startup, implies nofork) */
02641       } else if (!strcasecmp(v->name, "console")) {
02642          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_CONSOLE);
02643       /* Run with high priority if the O/S permits (-p at startup) */
02644       } else if (!strcasecmp(v->name, "highpriority")) {
02645          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_HIGH_PRIORITY);
02646       /* Initialize RSA auth keys (IAX2) (-i at startup) */
02647       } else if (!strcasecmp(v->name, "initcrypto")) {
02648          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_INIT_KEYS);
02649       /* Disable ANSI colors for console (-c at startup) */
02650       } else if (!strcasecmp(v->name, "nocolor")) {
02651          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_COLOR);
02652       /* Disable some usage warnings for picky people :p */
02653       } else if (!strcasecmp(v->name, "dontwarn")) {
02654          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_DONT_WARN);
02655       /* Dump core in case of crash (-g) */
02656       } else if (!strcasecmp(v->name, "dumpcore")) {
02657          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_DUMP_CORE);
02658       /* Cache recorded sound files to another directory during recording */
02659       } else if (!strcasecmp(v->name, "cache_record_files")) {
02660          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_CACHE_RECORD_FILES);
02661       /* Specify cache directory */
02662       }  else if (!strcasecmp(v->name, "record_cache_dir")) {
02663          ast_copy_string(record_cache_dir, v->value, AST_CACHE_DIR_LEN);
02664       /* Build transcode paths via SLINEAR, instead of directly */
02665       } else if (!strcasecmp(v->name, "transcode_via_sln")) {
02666          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TRANSCODE_VIA_SLIN);
02667       /* Transmit SLINEAR silence while a channel is being recorded or DTMF is being generated on a channel */
02668       } else if (!strcasecmp(v->name, "transmit_silence_during_record") || !strcasecmp(v->name, "transmit_silence")) {
02669          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TRANSMIT_SILENCE);
02670       /* Enable internal timing */
02671       } else if (!strcasecmp(v->name, "internal_timing")) {
02672          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_INTERNAL_TIMING);
02673       } else if (!strcasecmp(v->name, "maxcalls")) {
02674          if ((sscanf(v->value, "%30d", &option_maxcalls) != 1) || (option_maxcalls < 0)) {
02675             option_maxcalls = 0;
02676          }
02677       } else if (!strcasecmp(v->name, "maxload")) {
02678          double test[1];
02679 
02680          if (getloadavg(test, 1) == -1) {
02681             ast_log(LOG_ERROR, "Cannot obtain load average on this system. 'maxload' option disabled.\n");
02682             option_maxload = 0.0;
02683          } else if ((sscanf(v->value, "%30lf", &option_maxload) != 1) || (option_maxload < 0.0)) {
02684             option_maxload = 0.0;
02685          }
02686       /* What user to run as */
02687       } else if (!strcasecmp(v->name, "runuser")) {
02688          ast_copy_string(ast_config_AST_RUN_USER, v->value, sizeof(ast_config_AST_RUN_USER));
02689       /* What group to run as */
02690       } else if (!strcasecmp(v->name, "rungroup")) {
02691          ast_copy_string(ast_config_AST_RUN_GROUP, v->value, sizeof(ast_config_AST_RUN_GROUP));
02692       } else if (!strcasecmp(v->name, "systemname")) {
02693          ast_copy_string(ast_config_AST_SYSTEM_NAME, v->value, sizeof(ast_config_AST_SYSTEM_NAME));
02694       } else if (!strcasecmp(v->name, "languageprefix")) {
02695          ast_language_is_prefix = ast_true(v->value);
02696       } else if (!strcasecmp(v->name, "dahdichanname")) {
02697 #ifdef HAVE_ZAPTEL
02698          if (ast_true(v->value)) {
02699             strcpy(_dahdi_chan_name, "DAHDI");
02700             _dahdi_chan_name_len = 5;
02701             _dahdi_chan_mode = CHAN_DAHDI_PLUS_ZAP_MODE;
02702          }
02703 #else
02704          if (ast_false(v->value)) {
02705             strcpy(_dahdi_chan_name, "Zap");
02706             _dahdi_chan_name_len = 3;
02707             _dahdi_chan_mode = CHAN_ZAP_MODE;
02708          }
02709 #endif
02710       } else if (!strcasecmp(v->name, "sendfullybooted")) {
02711          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_SEND_FULLYBOOTED);
02712       }
02713    }
02714    ast_config_destroy(cfg);
02715 }
02716 
02717 static void *monitor_sig_flags(void *unused)
02718 {
02719    for (;;) {
02720       struct pollfd p = { sig_alert_pipe[0], POLLIN, 0 };
02721       int a;
02722       ast_poll(&p, 1, -1);
02723       if (sig_flags.need_reload) {
02724          sig_flags.need_reload = 0;
02725          ast_module_reload(NULL);
02726       }
02727       if (sig_flags.need_quit) {
02728          sig_flags.need_quit = 0;
02729          quit_handler(0, 0, 1, 0);
02730       }
02731       if (read(sig_alert_pipe[0], &a, sizeof(a)) != sizeof(a)) {
02732       }
02733    }
02734 
02735    return NULL;
02736 }
02737 
02738 int main(int argc, char *argv[])
02739 {
02740    int c;
02741    char filename[80] = "";
02742    char hostname[MAXHOSTNAMELEN] = "";
02743    char tmp[80];
02744    char * xarg = NULL;
02745    int x;
02746    FILE *f;
02747    sigset_t sigs;
02748    int num;
02749    int isroot = 1, rundir_exists = 0;
02750    char *buf;
02751    char *runuser = NULL, *rungroup = NULL;
02752    struct rlimit l;
02753 
02754    /* Remember original args for restart */
02755    if (argc > sizeof(_argv) / sizeof(_argv[0]) - 1) {
02756       fprintf(stderr, "Truncating argument size to %d\n", (int)(sizeof(_argv) / sizeof(_argv[0])) - 1);
02757       argc = sizeof(_argv) / sizeof(_argv[0]) - 1;
02758    }
02759    for (x=0; x<argc; x++)
02760       _argv[x] = argv[x];
02761    _argv[x] = NULL;
02762 
02763    if (geteuid() != 0)
02764       isroot = 0;
02765 
02766    /* if the progname is rasterisk consider it a remote console */
02767    if (argv[0] && (strstr(argv[0], "rasterisk")) != NULL) {
02768       ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE);
02769    }
02770    if (gethostname(hostname, sizeof(hostname)-1))
02771       ast_copy_string(hostname, "<Unknown>", sizeof(hostname));
02772    ast_mainpid = getpid();
02773    ast_ulaw_init();
02774    ast_alaw_init();
02775    callerid_init();
02776    ast_builtins_init();
02777    ast_utils_init();
02778    tdd_init();
02779    ast_fd_init();
02780    ast_pbx_init();
02781 
02782    if (getenv("HOME")) 
02783       snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
02784    /* Check for options */
02785    while ((c = getopt(argc, argv, "mtThfFdvVqprRgciInx:U:G:C:L:M:")) != -1) {
02786       switch (c) {
02787 #if HAVE_WORKING_FORK
02788       case 'F':
02789          ast_set_flag(&ast_options, AST_OPT_FLAG_ALWAYS_FORK);
02790          break;
02791       case 'f':
02792          ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);
02793          break;
02794 #endif
02795       case 'd':
02796          option_debug++;
02797          ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);
02798          break;
02799       case 'c':
02800          ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_CONSOLE);
02801          break;
02802       case 'n':
02803          ast_set_flag(&ast_options, AST_OPT_FLAG_NO_COLOR);
02804          break;
02805       case 'r':
02806          ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE);
02807          break;
02808       case 'R':
02809          ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE | AST_OPT_FLAG_RECONNECT);
02810          break;
02811       case 'p':
02812          ast_set_flag(&ast_options, AST_OPT_FLAG_HIGH_PRIORITY);
02813          break;
02814       case 'v':
02815          option_verbose++;
02816          ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);
02817          break;
02818       case 'm':
02819          ast_set_flag(&ast_options, AST_OPT_FLAG_MUTE);
02820          break;
02821       case 'M':
02822          if ((sscanf(optarg, "%30d", &option_maxcalls) != 1) || (option_maxcalls < 0))
02823             option_maxcalls = 0;
02824          break;
02825       case 'L':
02826          if ((sscanf(optarg, "%30lf", &option_maxload) != 1) || (option_maxload < 0.0))
02827             option_maxload = 0.0;
02828          break;
02829       case 'q':
02830          ast_set_flag(&ast_options, AST_OPT_FLAG_QUIET);
02831          break;
02832       case 't':
02833          ast_set_flag(&ast_options, AST_OPT_FLAG_CACHE_RECORD_FILES);
02834          break;
02835       case 'T':
02836          ast_set_flag(&ast_options, AST_OPT_FLAG_TIMESTAMP);
02837          break;
02838       case 'x':
02839          ast_set_flag(&ast_options, AST_OPT_FLAG_EXEC | AST_OPT_FLAG_NO_COLOR);
02840          xarg = ast_strdupa(optarg);
02841          break;
02842       case 'C':
02843          ast_copy_string(ast_config_AST_CONFIG_FILE, optarg, sizeof(ast_config_AST_CONFIG_FILE));
02844          ast_set_flag(&ast_options, AST_OPT_FLAG_OVERRIDE_CONFIG);
02845          break;
02846       case 'I':
02847          ast_set_flag(&ast_options, AST_OPT_FLAG_INTERNAL_TIMING);
02848          break;
02849       case 'i':
02850          ast_set_flag(&ast_options, AST_OPT_FLAG_INIT_KEYS);
02851          break;
02852       case 'g':
02853          ast_set_flag(&ast_options, AST_OPT_FLAG_DUMP_CORE);
02854          break;
02855       case 'h':
02856          show_cli_help();
02857          exit(0);
02858       case 'V':
02859          show_version();
02860          exit(0);
02861       case 'U':
02862          runuser = ast_strdupa(optarg);
02863          break;
02864       case 'G':
02865          rungroup = ast_strdupa(optarg);
02866          break;
02867       case '?':
02868          exit(1);
02869       }
02870    }
02871 
02872    if (ast_opt_console || option_verbose || (ast_opt_remote && !ast_opt_exec)) {
02873       ast_register_verbose(console_verboser);
02874       WELCOME_MESSAGE;
02875    }
02876 
02877    if (ast_opt_console && !option_verbose) 
02878       ast_verbose("[ Booting...\n");
02879 
02880    /* For remote connections, change the name of the remote connection.
02881     * We do this for the benefit of init scripts (which need to know if/when
02882     * the main asterisk process has died yet). */
02883    if (ast_opt_remote) {
02884       strcpy(argv[0], "rasterisk");
02885       for (x = 1; x < argc; x++) {
02886          argv[x] = argv[0] + 10;
02887       }
02888    }
02889 
02890    if (ast_opt_console && !option_verbose) {
02891       ast_verbose("[ Reading Master Configuration ]\n");
02892    }
02893 
02894    ast_readconfig();
02895 
02896    if (ast_opt_always_fork && (ast_opt_remote || ast_opt_console)) {
02897       ast_log(LOG_WARNING, "'alwaysfork' is not compatible with console or remote console mode; ignored\n");
02898       ast_clear_flag(&ast_options, AST_OPT_FLAG_ALWAYS_FORK);
02899    }
02900 
02901    if (ast_opt_dump_core) {
02902       memset(&l, 0, sizeof(l));
02903       l.rlim_cur = RLIM_INFINITY;
02904       l.rlim_max = RLIM_INFINITY;
02905       if (setrlimit(RLIMIT_CORE, &l)) {
02906          ast_log(LOG_WARNING, "Unable to disable core size resource limit: %s\n", strerror(errno));
02907       }
02908    }
02909 
02910    if (getrlimit(RLIMIT_NOFILE, &l)) {
02911       ast_log(LOG_WARNING, "Unable to check file descriptor limit: %s\n", strerror(errno));
02912    }
02913 
02914 #if !defined(CONFIGURE_RAN_AS_ROOT)
02915    /* Check if select(2) will run with more file descriptors */
02916    do {
02917       int fd, fd2;
02918       ast_fdset readers;
02919       struct timeval tv = { 0, };
02920 
02921       if (l.rlim_cur <= FD_SETSIZE) {
02922          /* The limit of select()able FDs is irrelevant, because we'll never
02923           * open one that high. */
02924          break;
02925       }
02926 
02927       if (!(fd = open("/dev/null", O_RDONLY))) {
02928          ast_log(LOG_ERROR, "Cannot open a file descriptor at boot? %s\n", strerror(errno));
02929          break; /* XXX Should we exit() here? XXX */
02930       }
02931 
02932       fd2 = (l.rlim_cur > sizeof(readers) * 8 ? sizeof(readers) * 8 : l.rlim_cur) - 1;
02933       if (dup2(fd, fd2) < 0) {
02934          ast_log(LOG_WARNING, "Cannot open maximum file descriptor %d at boot? %s\n", fd2, strerror(errno));
02935          close(fd);
02936          break;
02937       }
02938 
02939       FD_ZERO(&readers);
02940       FD_SET(fd2, &readers);
02941       if (ast_select(fd2 + 1, &readers, NULL, NULL, &tv) < 0) {
02942          ast_log(LOG_WARNING, "Maximum select()able file descriptor is %d\n", FD_SETSIZE);
02943       }
02944       ast_FD_SETSIZE = l.rlim_cur > ast_FDMAX ? ast_FDMAX : l.rlim_cur;
02945       close(fd);
02946       close(fd2);
02947    } while (0);
02948 #elif defined(HAVE_VARIABLE_FDSET)
02949    ast_FD_SETSIZE = l.rlim_cur > ast_FDMAX ? ast_FDMAX : l.rlim_cur;
02950 #endif /* !defined(CONFIGURE_RAN_AS_ROOT) */
02951 
02952    if ((!rungroup) && !ast_strlen_zero(ast_config_AST_RUN_GROUP))
02953       rungroup = ast_config_AST_RUN_GROUP;
02954    if ((!runuser) && !ast_strlen_zero(ast_config_AST_RUN_USER))
02955       runuser = ast_config_AST_RUN_USER;
02956 
02957    /* It's common on some platforms to clear /var/run at boot.  Create the
02958     * socket file directory before we drop privileges. */
02959    if (mkdir(ast_config_AST_RUN_DIR, 0755)) {
02960       if (errno == EEXIST) {
02961          rundir_exists = 1;
02962       } else {
02963          ast_log(LOG_WARNING, "Unable to create socket file directory.  Remote consoles will not be able to connect! (%s)\n", strerror(x));
02964       }
02965    }
02966 
02967 #ifndef __CYGWIN__
02968 
02969    if (isroot) 
02970       ast_set_priority(ast_opt_high_priority);
02971 
02972    if (isroot && rungroup) {
02973       struct group *gr;
02974       gr = getgrnam(rungroup);
02975       if (!gr) {
02976          ast_log(LOG_WARNING, "No such group '%s'!\n", rungroup);
02977          exit(1);
02978       }
02979       if (!rundir_exists && chown(ast_config_AST_RUN_DIR, -1, gr->gr_gid)) {
02980          ast_log(LOG_WARNING, "Unable to chgrp run directory to %d (%s)\n", (int) gr->gr_gid, rungroup);
02981       }
02982       if (setgid(gr->gr_gid)) {
02983          ast_log(LOG_WARNING, "Unable to setgid to %d (%s)\n", (int)gr->gr_gid, rungroup);
02984          exit(1);
02985       }
02986       if (setgroups(0, NULL)) {
02987          ast_log(LOG_WARNING, "Unable to drop unneeded groups\n");
02988          exit(1);
02989       }
02990       if (option_verbose)
02991          ast_verbose("Running as group '%s'\n", rungroup);
02992    }
02993 
02994    if (runuser && !ast_test_flag(&ast_options, AST_OPT_FLAG_REMOTE)) {
02995 #ifdef HAVE_CAP
02996       int has_cap = 1;
02997 #endif /* HAVE_CAP */
02998       struct passwd *pw;
02999       pw = getpwnam(runuser);
03000       if (!pw) {
03001          ast_log(LOG_WARNING, "No such user '%s'!\n", runuser);
03002          exit(1);
03003       }
03004       if (chown(ast_config_AST_RUN_DIR, pw->pw_uid, -1)) {
03005          ast_log(LOG_WARNING, "Unable to chown run directory to %d (%s)\n", (int) pw->pw_uid, runuser);
03006       }
03007 #ifdef HAVE_CAP
03008       if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0)) {
03009          ast_log(LOG_WARNING, "Unable to keep capabilities.\n");
03010          has_cap = 0;
03011       }
03012 #endif /* HAVE_CAP */
03013       if (!isroot && pw->pw_uid != geteuid()) {
03014          ast_log(LOG_ERROR, "Asterisk started as nonroot, but runuser '%s' requested.\n", runuser);
03015          exit(1);
03016       }
03017       if (!rungroup) {
03018          if (setgid(pw->pw_gid)) {
03019             ast_log(LOG_WARNING, "Unable to setgid to %d!\n", (int)pw->pw_gid);
03020             exit(1);
03021          }
03022          if (isroot && initgroups(pw->pw_name, pw->pw_gid)) {
03023             ast_log(LOG_WARNING, "Unable to init groups for '%s'\n", runuser);
03024             exit(1);
03025          }
03026       }
03027       if (setuid(pw->pw_uid)) {
03028          ast_log(LOG_WARNING, "Unable to setuid to %d (%s)\n", (int)pw->pw_uid, runuser);
03029          exit(1);
03030       }
03031       if (option_verbose)
03032          ast_verbose("Running as user '%s'\n", runuser);
03033 #ifdef HAVE_CAP
03034       if (has_cap) {
03035          cap_t cap;
03036 
03037          cap = cap_from_text("cap_net_admin=eip");
03038 
03039          if (cap_set_proc(cap))
03040             ast_log(LOG_WARNING, "Unable to install capabilities.\n");
03041 
03042          if (cap_free(cap))
03043             ast_log(LOG_WARNING, "Unable to drop capabilities.\n");
03044       }
03045 #endif /* HAVE_CAP */
03046    }
03047 
03048 #endif /* __CYGWIN__ */
03049 
03050 #ifdef linux
03051    if (geteuid() && ast_opt_dump_core) {
03052       if (prctl(PR_SET_DUMPABLE, 1, 0, 0, 0) < 0) {
03053          ast_log(LOG_WARNING, "Unable to set the process for core dumps after changing to a non-root user. %s\n", strerror(errno));
03054       }  
03055    }
03056 #endif
03057 
03058    ast_term_init();
03059    printf("%s", term_end());
03060    fflush(stdout);
03061 
03062    if (ast_opt_console && !option_verbose) 
03063       ast_verbose("[ Initializing Custom Configuration Options ]\n");
03064    /* custom config setup */
03065    register_config_cli();
03066    read_config_maps();
03067    
03068    if (ast_opt_console) {
03069       if (el_hist == NULL || el == NULL)
03070          ast_el_initialize();
03071 
03072       if (!ast_strlen_zero(filename))
03073          ast_el_read_history(filename);
03074    }
03075 
03076    if (ast_tryconnect()) {
03077       /* One is already running */
03078       if (ast_opt_remote) {
03079          if (ast_opt_exec) {
03080             ast_remotecontrol(xarg);
03081             quit_handler(0, 0, 0, 0);
03082             exit(0);
03083          }
03084          printf("%s", term_quit());
03085          ast_remotecontrol(NULL);
03086          quit_handler(0, 0, 0, 0);
03087          exit(0);
03088       } else {
03089          ast_log(LOG_ERROR, "Asterisk already running on %s.  Use 'asterisk -r' to connect.\n", ast_config_AST_SOCKET);
03090          printf("%s", term_quit());
03091          exit(1);
03092       }
03093    } else if (ast_opt_remote || ast_opt_exec) {
03094       ast_log(LOG_ERROR, "Unable to connect to remote asterisk (does %s exist?)\n", ast_config_AST_SOCKET);
03095       printf("%s", term_quit());
03096       exit(1);
03097    }
03098    /* Blindly write pid file since we couldn't connect */
03099    unlink(ast_config_AST_PID);
03100    f = fopen(ast_config_AST_PID, "w");
03101    if (f) {
03102       fprintf(f, "%ld\n", (long)getpid());
03103       fclose(f);
03104    } else
03105       ast_log(LOG_WARNING, "Unable to open pid file '%s': %s\n", ast_config_AST_PID, strerror(errno));
03106 
03107 #if HAVE_WORKING_FORK
03108    if (ast_opt_always_fork || !ast_opt_no_fork) {
03109 #ifndef HAVE_SBIN_LAUNCHD
03110       if (daemon(1, 0) < 0) {
03111          ast_log(LOG_ERROR, "daemon() failed: %s\n", strerror(errno));
03112       }
03113       ast_mainpid = getpid();
03114       /* Blindly re-write pid file since we are forking */
03115       unlink(ast_config_AST_PID);
03116       f = fopen(ast_config_AST_PID, "w");
03117       if (f) {
03118          fprintf(f, "%ld\n", (long)ast_mainpid);
03119          fclose(f);
03120       } else
03121          ast_log(LOG_WARNING, "Unable to open pid file '%s': %s\n", ast_config_AST_PID, strerror(errno));
03122 #else
03123       ast_log(LOG_WARNING, "Mac OS X detected.  Use 'launchctl load /Library/LaunchDaemon/org.asterisk.asterisk.plist'.\n");
03124 #endif
03125    }
03126 #endif
03127 
03128 #ifdef TEST_FRAMEWORK
03129    if (ast_test_init()) {
03130       printf("%s", term_quit());
03131       exit(1);
03132    }
03133 #endif
03134 
03135    ast_makesocket();
03136    sigemptyset(&sigs);
03137    sigaddset(&sigs, SIGHUP);
03138    sigaddset(&sigs, SIGTERM);
03139    sigaddset(&sigs, SIGINT);
03140    sigaddset(&sigs, SIGPIPE);
03141    sigaddset(&sigs, SIGWINCH);
03142    pthread_sigmask(SIG_BLOCK, &sigs, NULL);
03143    sigaction(SIGURG, &urg_handler, NULL);
03144    signal(SIGINT, __quit_handler);
03145    signal(SIGTERM, __quit_handler);
03146    sigaction(SIGHUP, &hup_handler, NULL);
03147    sigaction(SIGCHLD, &child_handler, NULL);
03148    signal(SIGPIPE, SIG_IGN);
03149 
03150    /* ensure that the random number generators are seeded with a different value every time
03151       Asterisk is started
03152    */
03153    srand((unsigned int) getpid() + (unsigned int) time(NULL));
03154    initstate((unsigned int) getpid() * 65536 + (unsigned int) time(NULL), randompool, sizeof(randompool));
03155 
03156    if (init_logger()) {
03157       printf("%s", term_quit());
03158       exit(1);
03159    }
03160 
03161    dahdi_chan_name = _dahdi_chan_name;
03162    dahdi_chan_name_len = &_dahdi_chan_name_len;
03163    dahdi_chan_mode = &_dahdi_chan_mode;
03164 
03165 #ifdef HAVE_DAHDI
03166    {
03167       int fd;
03168       int x = 160;
03169       fd = open(DAHDI_FILE_TIMER, O_RDWR);
03170       if (fd >= 0) {
03171          if (ioctl(fd, DAHDI_TIMERCONFIG, &x)) {
03172             ast_log(LOG_ERROR, "You have " DAHDI_NAME
03173                   " built and drivers loaded, but the "
03174                   DAHDI_NAME " timer test failed to set DAHDI_TIMERCONFIG to %d.\n", x);
03175             exit(1);
03176          }
03177          if ((x = ast_wait_for_input(fd, 300)) < 0) {
03178             ast_log(LOG_ERROR, "You have " DAHDI_NAME 
03179                   "built and drivers loaded, but the " 
03180                   DAHDI_NAME " timer could not be polled during the " 
03181                   DAHDI_NAME " timer test.\n");
03182             exit(1);
03183          }
03184          if (!x) {
03185             const char dahdi_timer_error[] = {
03186                "Asterisk has detected a problem with your " DAHDI_NAME 
03187                   " configuration and will shutdown for your protection.  You have options:"
03188                "\n\t1. You only have to compile " DAHDI_NAME 
03189                   " support into Asterisk if you need it.  One option is to recompile without " 
03190                   DAHDI_NAME " support."
03191                "\n\t2. You only have to load " DAHDI_NAME " drivers if you want to take advantage of " 
03192                   DAHDI_NAME " services.  One option is to unload " 
03193                   DAHDI_NAME " modules if you don't need them."
03194                "\n\t3. If you need Zaptel services, you must correctly configure " DAHDI_NAME "."
03195             };
03196             ast_log(LOG_ERROR, "%s\n", dahdi_timer_error);
03197             exit(1);
03198          }
03199          close(fd);
03200       }
03201    }
03202 #endif
03203    threadstorage_init();
03204 
03205    astobj2_init();
03206 
03207    ast_autoservice_init();
03208 
03209    if (load_modules(1)) {
03210       printf("%s", term_quit());
03211       exit(1);
03212    }
03213 
03214    if (dnsmgr_init()) {
03215       printf("%s", term_quit());
03216       exit(1);
03217    }
03218 
03219    ast_http_init();
03220 
03221    ast_channels_init();
03222 
03223    if (init_manager()) {
03224       printf("%s", term_quit());
03225       exit(1);
03226    }
03227 
03228    if (ast_cdr_engine_init()) {
03229       printf("%s", term_quit());
03230       exit(1);
03231    }
03232 
03233    if (ast_device_state_engine_init()) {
03234       printf("%s", term_quit());
03235       exit(1);
03236    }
03237 
03238    ast_rtp_init();
03239 
03240    ast_udptl_init();
03241 
03242    if (ast_image_init()) {
03243       printf("%s", term_quit());
03244       exit(1);
03245    }
03246 
03247    if (ast_file_init()) {
03248       printf("%s", term_quit());
03249       exit(1);
03250    }
03251 
03252    if (load_pbx()) {
03253       printf("%s", term_quit());
03254       exit(1);
03255    }
03256 
03257    if (init_framer()) {
03258       printf("%s", term_quit());
03259       exit(1);
03260    }
03261 
03262    if (astdb_init()) {
03263       printf("%s", term_quit());
03264       exit(1);
03265    }
03266 
03267    if (ast_enum_init()) {
03268       printf("%s", term_quit());
03269       exit(1);
03270    }
03271 
03272    if (load_modules(0)) {
03273       printf("%s", term_quit());
03274       exit(1);
03275    }
03276 
03277    dnsmgr_start_refresh();
03278 
03279    /* We might have the option of showing a console, but for now just
03280       do nothing... */
03281    if (ast_opt_console && !option_verbose)
03282       ast_verbose(" ]\n");
03283    if (option_verbose || ast_opt_console)
03284       ast_verbose("%s", term_color(tmp, "Asterisk Ready.\n", COLOR_BRWHITE, COLOR_BLACK, sizeof(tmp)));
03285    if (ast_opt_no_fork)
03286       consolethread = pthread_self();
03287 
03288    if (pipe(sig_alert_pipe))
03289       sig_alert_pipe[0] = sig_alert_pipe[1] = -1;
03290 
03291    ast_set_flag(&ast_options, AST_OPT_FLAG_FULLY_BOOTED);
03292    if (ast_opt_send_fullybooted) {
03293       manager_event(EVENT_FLAG_SYSTEM, "FullyBooted", "Status: Fully Booted\r\n");
03294    }
03295 
03296    ast_process_pending_reloads();
03297 
03298    pthread_sigmask(SIG_UNBLOCK, &sigs, NULL);
03299 
03300 #ifdef __AST_DEBUG_MALLOC
03301    __ast_mm_init();
03302 #endif   
03303 
03304    time(&ast_startuptime);
03305    ast_cli_register_multiple(cli_asterisk, sizeof(cli_asterisk) / sizeof(struct ast_cli_entry));
03306 
03307    if (ast_opt_console) {
03308       /* Console stuff now... */
03309       /* Register our quit function */
03310       char title[256];
03311       pthread_attr_t attr;
03312 
03313       pthread_attr_init(&attr);
03314       pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
03315       ast_pthread_create(&mon_sig_flags, &attr, monitor_sig_flags, NULL);
03316       pthread_attr_destroy(&attr);
03317 
03318       set_icon("Asterisk");
03319       snprintf(title, sizeof(title), "Asterisk Console on '%s' (pid %ld)", hostname, (long)ast_mainpid);
03320       set_title(title);
03321 
03322       for (;;) {
03323          buf = (char *)el_gets(el, &num);
03324 
03325          if (!buf && write(1, "", 1) < 0)
03326             goto lostterm;
03327 
03328          if (buf) {
03329             if (buf[strlen(buf)-1] == '\n')
03330                buf[strlen(buf)-1] = '\0';
03331 
03332             consolehandler((char *)buf);
03333          } else if (ast_opt_remote && (write(STDOUT_FILENO, "\nUse EXIT or QUIT to exit the asterisk console\n",
03334                strlen("\nUse EXIT or QUIT to exit the asterisk console\n")) < 0)) {
03335             /* Whoa, stdout disappeared from under us... Make /dev/null's */
03336             int fd;
03337             fd = open("/dev/null", O_RDWR);
03338             if (fd > -1) {
03339                dup2(fd, STDOUT_FILENO);
03340                dup2(fd, STDIN_FILENO);
03341             } else
03342                ast_log(LOG_WARNING, "Failed to open /dev/null to recover from dead console. Bad things will happen!\n");
03343             break;
03344          }
03345       }
03346    }
03347 
03348    monitor_sig_flags(NULL);
03349 
03350 lostterm:
03351    return 0;
03352 }

Generated on Thu Oct 11 06:42:01 2012 for Asterisk - the Open Source PBX by  doxygen 1.5.6