Wed Nov 28 2012 04:18:03

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