Fri Apr 29 2011 07:53:59

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