Wed Apr 6 11:29:40 2011

Asterisk developer's documentation


asterisk.c

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

Generated on Wed Apr 6 11:29:40 2011 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7