Sun Oct 16 2011 08:41:30

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: 332100 $")
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 - 2011 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     unsigned int need_quit_handler:1;
00292 } sig_flags;
00293 
00294 #if !defined(LOW_MEMORY)
00295 struct file_version {
00296    AST_RWLIST_ENTRY(file_version) list;
00297    const char *file;
00298    char *version;
00299 };
00300 
00301 static AST_RWLIST_HEAD_STATIC(file_versions, file_version);
00302 
00303 void ast_register_file_version(const char *file, const char *version)
00304 {
00305    struct file_version *new;
00306    char *work;
00307    size_t version_length;
00308 
00309    work = ast_strdupa(version);
00310    work = ast_strip(ast_strip_quoted(work, "$", "$"));
00311    version_length = strlen(work) + 1;
00312    
00313    if (!(new = ast_calloc(1, sizeof(*new) + version_length)))
00314       return;
00315 
00316    new->file = file;
00317    new->version = (char *) new + sizeof(*new);
00318    memcpy(new->version, work, version_length);
00319    AST_RWLIST_WRLOCK(&file_versions);
00320    AST_RWLIST_INSERT_HEAD(&file_versions, new, list);
00321    AST_RWLIST_UNLOCK(&file_versions);
00322 }
00323 
00324 void ast_unregister_file_version(const char *file)
00325 {
00326    struct file_version *find;
00327 
00328    AST_RWLIST_WRLOCK(&file_versions);
00329    AST_RWLIST_TRAVERSE_SAFE_BEGIN(&file_versions, find, list) {
00330       if (!strcasecmp(find->file, file)) {
00331          AST_RWLIST_REMOVE_CURRENT(list);
00332          break;
00333       }
00334    }
00335    AST_RWLIST_TRAVERSE_SAFE_END;
00336    AST_RWLIST_UNLOCK(&file_versions);
00337 
00338    if (find)
00339       ast_free(find);
00340 }
00341 
00342 char *ast_complete_source_filename(const char *partial, int n)
00343 {
00344    struct file_version *find;
00345    size_t len = strlen(partial);
00346    int count = 0;
00347    char *res = NULL;
00348 
00349    AST_RWLIST_RDLOCK(&file_versions);
00350    AST_RWLIST_TRAVERSE(&file_versions, find, list) {
00351       if (!strncasecmp(find->file, partial, len) && ++count > n) {
00352          res = ast_strdup(find->file);
00353          break;
00354       }
00355    }
00356    AST_RWLIST_UNLOCK(&file_versions);
00357    return res;
00358 }
00359 
00360 /*! \brief Find version for given module name */
00361 const char *ast_file_version_find(const char *file)
00362 {
00363    struct file_version *iterator;
00364 
00365    AST_RWLIST_WRLOCK(&file_versions);
00366    AST_RWLIST_TRAVERSE(&file_versions, iterator, list) {
00367       if (!strcasecmp(iterator->file, file))
00368          break;
00369    }
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 nprocs = 0;
00579    long uptime = 0;
00580    int totalswap = 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 /*!
01087  * \brief enable or disable a logging level to a specified console
01088  */
01089 void ast_console_toggle_loglevel(int fd, int level, int state)
01090 {
01091    int x;
01092    for (x = 0;x < AST_MAX_CONNECTS; x++) {
01093       if (fd == consoles[x].fd) {
01094          /*
01095           * Since the logging occurs when levels are false, set to
01096           * flipped iinput because this function accepts 0 as off and 1 as on
01097           */
01098          consoles[x].levels[level] = state ? 0 : 1;
01099          return;
01100       }
01101    }
01102 }
01103 
01104 /*!
01105  * \brief mute or unmute a console from logging
01106  */
01107 void ast_console_toggle_mute(int fd, int silent) {
01108    int x;
01109    for (x = 0;x < AST_MAX_CONNECTS; x++) {
01110       if (fd == consoles[x].fd) {
01111          if (consoles[x].mute) {
01112             consoles[x].mute = 0;
01113             if (!silent)
01114                ast_cli(fd, "Console is not muted anymore.\n");
01115          } else {
01116             consoles[x].mute = 1;
01117             if (!silent)
01118                ast_cli(fd, "Console is muted.\n");
01119          }
01120          return;
01121       }
01122    }
01123    ast_cli(fd, "Couldn't find remote console.\n");
01124 }
01125 
01126 /*!
01127  * \brief log the string to all attached console clients
01128  */
01129 static void ast_network_puts_mutable(const char *string, int level)
01130 {
01131    int x;
01132    for (x = 0;x < AST_MAX_CONNECTS; x++) {
01133       if (consoles[x].mute)
01134          continue;
01135       if (consoles[x].fd > -1) {
01136          if (!consoles[x].levels[level]) 
01137             fdprint(consoles[x].p[1], string);
01138       }
01139    }
01140 }
01141 
01142 /*!
01143  * \brief log the string to the console, and all attached
01144  * console clients
01145  */
01146 void ast_console_puts_mutable(const char *string, int level)
01147 {
01148    fputs(string, stdout);
01149    fflush(stdout);
01150    ast_network_puts_mutable(string, level);
01151 }
01152 
01153 /*!
01154  * \brief write the string to all attached console clients
01155  */
01156 static void ast_network_puts(const char *string)
01157 {
01158    int x;
01159    for (x = 0; x < AST_MAX_CONNECTS; x++) {
01160       if (consoles[x].fd > -1) 
01161          fdprint(consoles[x].p[1], string);
01162    }
01163 }
01164 
01165 /*!
01166  * write the string to the console, and all attached
01167  * console clients
01168  */
01169 void ast_console_puts(const char *string)
01170 {
01171    fputs(string, stdout);
01172    fflush(stdout);
01173    ast_network_puts(string);
01174 }
01175 
01176 static void network_verboser(const char *s)
01177 {
01178    ast_network_puts_mutable(s, __LOG_VERBOSE);
01179 }
01180 
01181 static pthread_t lthread;
01182 
01183 /*!
01184  * \brief read() function supporting the reception of user credentials.
01185  *
01186  * \param fd Socket file descriptor.
01187  * \param buffer Receive buffer.
01188  * \param size 'buffer' size.
01189  * \param con Console structure to set received credentials
01190  * \retval -1 on error
01191  * \retval the number of bytes received on success.
01192  */
01193 static int read_credentials(int fd, char *buffer, size_t size, struct console *con)
01194 {
01195 #if defined(SO_PEERCRED)
01196    struct ucred cred;
01197    socklen_t len = sizeof(cred);
01198 #endif
01199 #if defined(HAVE_GETPEEREID)
01200    uid_t uid;
01201    gid_t gid;
01202 #else
01203    int uid, gid;
01204 #endif
01205    int result;
01206 
01207    result = read(fd, buffer, size);
01208    if (result < 0) {
01209       return result;
01210    }
01211 
01212 #if defined(SO_PEERCRED) && (defined(HAVE_STRUCT_UCRED_UID) || defined(HAVE_STRUCT_UCRED_CR_UID))
01213    if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cred, &len)) {
01214       return result;
01215    }
01216 #if defined(HAVE_STRUCT_UCRED_UID)
01217    uid = cred.uid;
01218    gid = cred.gid;
01219 #else /* defined(HAVE_STRUCT_UCRED_CR_UID) */
01220    uid = cred.cr_uid;
01221    gid = cred.cr_gid;
01222 #endif /* defined(HAVE_STRUCT_UCRED_UID) */
01223 
01224 #elif defined(HAVE_GETPEEREID)
01225    if (getpeereid(fd, &uid, &gid)) {
01226       return result;
01227    }
01228 #else
01229    return result;
01230 #endif
01231    con->uid = uid;
01232    con->gid = gid;
01233 
01234    return result;
01235 }
01236 
01237 static void *netconsole(void *vconsole)
01238 {
01239    struct console *con = vconsole;
01240    char hostname[MAXHOSTNAMELEN] = "";
01241    char tmp[512];
01242    int res;
01243    struct pollfd fds[2];
01244    
01245    if (gethostname(hostname, sizeof(hostname)-1))
01246       ast_copy_string(hostname, "<Unknown>", sizeof(hostname));
01247    snprintf(tmp, sizeof(tmp), "%s/%ld/%s\n", hostname, (long)ast_mainpid, ast_get_version());
01248    fdprint(con->fd, tmp);
01249    for (;;) {
01250       fds[0].fd = con->fd;
01251       fds[0].events = POLLIN;
01252       fds[0].revents = 0;
01253       fds[1].fd = con->p[0];
01254       fds[1].events = POLLIN;
01255       fds[1].revents = 0;
01256 
01257       res = ast_poll(fds, 2, -1);
01258       if (res < 0) {
01259          if (errno != EINTR)
01260             ast_log(LOG_WARNING, "poll returned < 0: %s\n", strerror(errno));
01261          continue;
01262       }
01263       if (fds[0].revents) {
01264          res = read_credentials(con->fd, tmp, sizeof(tmp) - 1, con);
01265          if (res < 1) {
01266             break;
01267          }
01268          tmp[res] = 0;
01269          if (strncmp(tmp, "cli quit after ", 15) == 0) {
01270             ast_cli_command_multiple_full(con->uid, con->gid, con->fd, res - 15, tmp + 15);
01271             break;
01272          }
01273          ast_cli_command_multiple_full(con->uid, con->gid, con->fd, res, tmp);
01274       }
01275       if (fds[1].revents) {
01276          res = read_credentials(con->p[0], tmp, sizeof(tmp), con);
01277          if (res < 1) {
01278             ast_log(LOG_ERROR, "read returned %d\n", res);
01279             break;
01280          }
01281          res = write(con->fd, tmp, res);
01282          if (res < 1)
01283             break;
01284       }
01285    }
01286    if (!ast_opt_hide_connect) {
01287       ast_verb(3, "Remote UNIX connection disconnected\n");
01288    }
01289    close(con->fd);
01290    close(con->p[0]);
01291    close(con->p[1]);
01292    con->fd = -1;
01293    
01294    return NULL;
01295 }
01296 
01297 static void *listener(void *unused)
01298 {
01299    struct sockaddr_un sunaddr;
01300    int s;
01301    socklen_t len;
01302    int x;
01303    int flags;
01304    struct pollfd fds[1];
01305    for (;;) {
01306       if (ast_socket < 0)
01307          return NULL;
01308       fds[0].fd = ast_socket;
01309       fds[0].events = POLLIN;
01310       s = ast_poll(fds, 1, -1);
01311       pthread_testcancel();
01312       if (s < 0) {
01313          if (errno != EINTR)
01314             ast_log(LOG_WARNING, "poll returned error: %s\n", strerror(errno));
01315          continue;
01316       }
01317       len = sizeof(sunaddr);
01318       s = accept(ast_socket, (struct sockaddr *)&sunaddr, &len);
01319       if (s < 0) {
01320          if (errno != EINTR)
01321             ast_log(LOG_WARNING, "Accept returned %d: %s\n", s, strerror(errno));
01322       } else {
01323 #if !defined(SO_PASSCRED)
01324          {
01325 #else
01326          int sckopt = 1;
01327          /* turn on socket credentials passing. */
01328          if (setsockopt(s, SOL_SOCKET, SO_PASSCRED, &sckopt, sizeof(sckopt)) < 0) {
01329             ast_log(LOG_WARNING, "Unable to turn on socket credentials passing\n");
01330          } else {
01331 #endif
01332             for (x = 0; x < AST_MAX_CONNECTS; x++) {
01333                if (consoles[x].fd >= 0) {
01334                   continue;
01335                }
01336                if (socketpair(AF_LOCAL, SOCK_STREAM, 0, consoles[x].p)) {
01337                   ast_log(LOG_ERROR, "Unable to create pipe: %s\n", strerror(errno));
01338                   consoles[x].fd = -1;
01339                   fdprint(s, "Server failed to create pipe\n");
01340                   close(s);
01341                   break;
01342                }
01343                flags = fcntl(consoles[x].p[1], F_GETFL);
01344                fcntl(consoles[x].p[1], F_SETFL, flags | O_NONBLOCK);
01345                consoles[x].fd = s;
01346                consoles[x].mute = 1; /* Default is muted, we will un-mute if necessary */
01347                /* Default uid and gid to -2, so then in cli.c/cli_has_permissions() we will be able
01348                   to know if the user didn't send the credentials. */
01349                consoles[x].uid = -2;
01350                consoles[x].gid = -2;
01351                if (ast_pthread_create_detached_background(&consoles[x].t, NULL, netconsole, &consoles[x])) {
01352                   ast_log(LOG_ERROR, "Unable to spawn thread to handle connection: %s\n", strerror(errno));
01353                   close(consoles[x].p[0]);
01354                   close(consoles[x].p[1]);
01355                   consoles[x].fd = -1;
01356                   fdprint(s, "Server failed to spawn thread\n");
01357                   close(s);
01358                }
01359                break;
01360             }
01361             if (x >= AST_MAX_CONNECTS) {
01362                fdprint(s, "No more connections allowed\n");
01363                ast_log(LOG_WARNING, "No more connections allowed\n");
01364                close(s);
01365             } else if ((consoles[x].fd > -1) && (!ast_opt_hide_connect)) {
01366                ast_verb(3, "Remote UNIX connection\n");
01367             }
01368          }
01369       }
01370    }
01371    return NULL;
01372 }
01373 
01374 static int ast_makesocket(void)
01375 {
01376    struct sockaddr_un sunaddr;
01377    int res;
01378    int x;
01379    uid_t uid = -1;
01380    gid_t gid = -1;
01381 
01382    for (x = 0; x < AST_MAX_CONNECTS; x++) 
01383       consoles[x].fd = -1;
01384    unlink(ast_config_AST_SOCKET);
01385    ast_socket = socket(PF_LOCAL, SOCK_STREAM, 0);
01386    if (ast_socket < 0) {
01387       ast_log(LOG_WARNING, "Unable to create control socket: %s\n", strerror(errno));
01388       return -1;
01389    }     
01390    memset(&sunaddr, 0, sizeof(sunaddr));
01391    sunaddr.sun_family = AF_LOCAL;
01392    ast_copy_string(sunaddr.sun_path, ast_config_AST_SOCKET, sizeof(sunaddr.sun_path));
01393    res = bind(ast_socket, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
01394    if (res) {
01395       ast_log(LOG_WARNING, "Unable to bind socket to %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
01396       close(ast_socket);
01397       ast_socket = -1;
01398       return -1;
01399    }
01400    res = listen(ast_socket, 2);
01401    if (res < 0) {
01402       ast_log(LOG_WARNING, "Unable to listen on socket %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
01403       close(ast_socket);
01404       ast_socket = -1;
01405       return -1;
01406    }
01407    if (ast_register_verbose(network_verboser)) {
01408       ast_log(LOG_WARNING, "Unable to register network verboser?\n");
01409    }
01410 
01411    ast_pthread_create_background(&lthread, NULL, listener, NULL);
01412 
01413    if (!ast_strlen_zero(ast_config_AST_CTL_OWNER)) {
01414       struct passwd *pw;
01415       if ((pw = getpwnam(ast_config_AST_CTL_OWNER)) == NULL)
01416          ast_log(LOG_WARNING, "Unable to find uid of user %s\n", ast_config_AST_CTL_OWNER);
01417       else
01418          uid = pw->pw_uid;
01419    }
01420       
01421    if (!ast_strlen_zero(ast_config_AST_CTL_GROUP)) {
01422       struct group *grp;
01423       if ((grp = getgrnam(ast_config_AST_CTL_GROUP)) == NULL)
01424          ast_log(LOG_WARNING, "Unable to find gid of group %s\n", ast_config_AST_CTL_GROUP);
01425       else
01426          gid = grp->gr_gid;
01427    }
01428 
01429    if (chown(ast_config_AST_SOCKET, uid, gid) < 0)
01430       ast_log(LOG_WARNING, "Unable to change ownership of %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
01431 
01432    if (!ast_strlen_zero(ast_config_AST_CTL_PERMISSIONS)) {
01433       int p1;
01434       mode_t p;
01435       sscanf(ast_config_AST_CTL_PERMISSIONS, "%30o", &p1);
01436       p = p1;
01437       if ((chmod(ast_config_AST_SOCKET, p)) < 0)
01438          ast_log(LOG_WARNING, "Unable to change file permissions of %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
01439    }
01440 
01441    return 0;
01442 }
01443 
01444 static int ast_tryconnect(void)
01445 {
01446    struct sockaddr_un sunaddr;
01447    int res;
01448    ast_consock = socket(PF_LOCAL, SOCK_STREAM, 0);
01449    if (ast_consock < 0) {
01450       ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno));
01451       return 0;
01452    }
01453    memset(&sunaddr, 0, sizeof(sunaddr));
01454    sunaddr.sun_family = AF_LOCAL;
01455    ast_copy_string(sunaddr.sun_path, ast_config_AST_SOCKET, sizeof(sunaddr.sun_path));
01456    res = connect(ast_consock, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
01457    if (res) {
01458       close(ast_consock);
01459       ast_consock = -1;
01460       return 0;
01461    } else
01462       return 1;
01463 }
01464 
01465 /*! \brief Urgent handler
01466 
01467  Called by soft_hangup to interrupt the poll, read, or other
01468  system call.  We don't actually need to do anything though.  
01469  Remember: Cannot EVER ast_log from within a signal handler 
01470  */
01471 static void _urg_handler(int num)
01472 {
01473    return;
01474 }
01475 
01476 static struct sigaction urg_handler = {
01477    .sa_handler = _urg_handler,
01478    .sa_flags = SA_RESTART,
01479 };
01480 
01481 static void _hup_handler(int num)
01482 {
01483    int a = 0, save_errno = errno;
01484    if (option_verbose > 1) 
01485       printf("Received HUP signal -- Reloading configs\n");
01486    if (restartnow)
01487       execvp(_argv[0], _argv);
01488    sig_flags.need_reload = 1;
01489    if (sig_alert_pipe[1] != -1) {
01490       if (write(sig_alert_pipe[1], &a, sizeof(a)) < 0) {
01491          fprintf(stderr, "hup_handler: write() failed: %s\n", strerror(errno));
01492       }
01493    }
01494    errno = save_errno;
01495 }
01496 
01497 static struct sigaction hup_handler = {
01498    .sa_handler = _hup_handler,
01499    .sa_flags = SA_RESTART,
01500 };
01501 
01502 static void _child_handler(int sig)
01503 {
01504    /* Must not ever ast_log or ast_verbose within signal handler */
01505    int n, status, save_errno = errno;
01506 
01507    /*
01508     * Reap all dead children -- not just one
01509     */
01510    for (n = 0; wait4(-1, &status, WNOHANG, NULL) > 0; n++)
01511       ;
01512    if (n == 0 && option_debug)   
01513       printf("Huh?  Child handler, but nobody there?\n");
01514    errno = save_errno;
01515 }
01516 
01517 static struct sigaction child_handler = {
01518    .sa_handler = _child_handler,
01519    .sa_flags = SA_RESTART,
01520 };
01521 
01522 /*! \brief Set maximum open files */
01523 static void set_ulimit(int value)
01524 {
01525    struct rlimit l = {0, 0};
01526    
01527    if (value <= 0) {
01528       ast_log(LOG_WARNING, "Unable to change max files open to invalid value %i\n",value);
01529       return;
01530    }
01531    
01532    l.rlim_cur = value;
01533    l.rlim_max = value;
01534    
01535    if (setrlimit(RLIMIT_NOFILE, &l)) {
01536       ast_log(LOG_WARNING, "Unable to disable core size resource limit: %s\n",strerror(errno));
01537       return;
01538    }
01539    
01540    ast_log(LOG_NOTICE, "Setting max files open to %d\n",value);
01541    
01542    return;
01543 }
01544 
01545 /*! \brief Set an X-term or screen title */
01546 static void set_title(char *text)
01547 {
01548    if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
01549       fprintf(stdout, "\033]2;%s\007", text);
01550 }
01551 
01552 static void set_icon(char *text)
01553 {
01554    if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
01555       fprintf(stdout, "\033]1;%s\007", text);
01556 }
01557 
01558 /*! \brief We set ourselves to a high priority, that we might pre-empt everything
01559    else.  If your PBX has heavy activity on it, this is a good thing.  */
01560 int ast_set_priority(int pri)
01561 {
01562    struct sched_param sched;
01563    memset(&sched, 0, sizeof(sched));
01564 #ifdef __linux__
01565    if (pri) {  
01566       sched.sched_priority = 10;
01567       if (sched_setscheduler(0, SCHED_RR, &sched)) {
01568          ast_log(LOG_WARNING, "Unable to set high priority\n");
01569          return -1;
01570       } else
01571          if (option_verbose)
01572             ast_verbose("Set to realtime thread\n");
01573    } else {
01574       sched.sched_priority = 0;
01575       /* According to the manpage, these parameters can never fail. */
01576       sched_setscheduler(0, SCHED_OTHER, &sched);
01577    }
01578 #else
01579    if (pri) {
01580       if (setpriority(PRIO_PROCESS, 0, -10) == -1) {
01581          ast_log(LOG_WARNING, "Unable to set high priority\n");
01582          return -1;
01583       } else
01584          if (option_verbose)
01585             ast_verbose("Set to high priority\n");
01586    } else {
01587       /* According to the manpage, these parameters can never fail. */
01588       setpriority(PRIO_PROCESS, 0, 0);
01589    }
01590 #endif
01591    return 0;
01592 }
01593 
01594 static void ast_run_atexits(void)
01595 {
01596    struct ast_atexit *ae;
01597    AST_RWLIST_RDLOCK(&atexits);
01598    AST_RWLIST_TRAVERSE(&atexits, ae, list) {
01599       if (ae->func) 
01600          ae->func();
01601    }
01602    AST_RWLIST_UNLOCK(&atexits);
01603 }
01604 
01605 static void quit_handler(int num, int niceness, int safeshutdown, int restart)
01606 {
01607    char filename[80] = "";
01608    time_t s,e;
01609    int x;
01610    /* Try to get as many CDRs as possible submitted to the backend engines (if in batch mode) */
01611    ast_cdr_engine_term();
01612    if (safeshutdown) {
01613       shuttingdown = 1;
01614       if (!niceness) {
01615          /* Begin shutdown routine, hanging up active channels */
01616          ast_begin_shutdown(1);
01617          if (option_verbose && ast_opt_console)
01618             ast_verbose("Beginning asterisk %s....\n", restart ? "restart" : "shutdown");
01619          time(&s);
01620          for (;;) {
01621             time(&e);
01622             /* Wait up to 15 seconds for all channels to go away */
01623             if ((e - s) > 15)
01624                break;
01625             if (!ast_active_channels())
01626                break;
01627             if (!shuttingdown)
01628                break;
01629             /* Sleep 1/10 of a second */
01630             usleep(100000);
01631          }
01632       } else {
01633          if (niceness < 2)
01634             ast_begin_shutdown(0);
01635          if (option_verbose && ast_opt_console)
01636             ast_verbose("Waiting for inactivity to perform %s...\n", restart ? "restart" : "halt");
01637          for (;;) {
01638             if (!ast_active_channels())
01639                break;
01640             if (!shuttingdown)
01641                break;
01642             sleep(1);
01643          }
01644       }
01645 
01646       if (!shuttingdown) {
01647          if (option_verbose && ast_opt_console)
01648             ast_verbose("Asterisk %s cancelled.\n", restart ? "restart" : "shutdown");
01649          return;
01650       }
01651 
01652       if (niceness)
01653          ast_module_shutdown();
01654    }
01655    if (ast_opt_console || (ast_opt_remote && !ast_opt_exec)) {
01656       if (getenv("HOME")) {
01657          snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
01658       }
01659       if (!ast_strlen_zero(filename)) {
01660          ast_el_write_history(filename);
01661       }
01662       if (consolethread == AST_PTHREADT_NULL || consolethread == pthread_self()) {
01663          /* Only end if we are the consolethread, otherwise there's a race with that thread. */
01664          if (el != NULL) {
01665             el_end(el);
01666          }
01667          if (el_hist != NULL) {
01668             history_end(el_hist);
01669          }
01670       } else if (mon_sig_flags == pthread_self()) {
01671          if (consolethread != AST_PTHREADT_NULL) {
01672             pthread_kill(consolethread, SIGURG);
01673          }
01674       }
01675    }
01676    if (option_verbose)
01677       ast_verbose("Executing last minute cleanups\n");
01678    ast_run_atexits();
01679    /* Called on exit */
01680    if (option_verbose && ast_opt_console)
01681       ast_verbose("Asterisk %s ending (%d).\n", ast_active_channels() ? "uncleanly" : "cleanly", num);
01682    ast_debug(1, "Asterisk ending (%d).\n", num);
01683    manager_event(EVENT_FLAG_SYSTEM, "Shutdown", "Shutdown: %s\r\nRestart: %s\r\n", ast_active_channels() ? "Uncleanly" : "Cleanly", restart ? "True" : "False");
01684    if (ast_socket > -1) {
01685       pthread_cancel(lthread);
01686       close(ast_socket);
01687       ast_socket = -1;
01688       unlink(ast_config_AST_SOCKET);
01689    }
01690    if (ast_consock > -1)
01691       close(ast_consock);
01692    if (!ast_opt_remote)
01693       unlink(ast_config_AST_PID);
01694    printf("%s", term_quit());
01695    if (restart) {
01696       if (option_verbose || ast_opt_console)
01697          ast_verbose("Preparing for Asterisk restart...\n");
01698       /* Mark all FD's for closing on exec */
01699       for (x=3; x < 32768; x++) {
01700          fcntl(x, F_SETFD, FD_CLOEXEC);
01701       }
01702       if (option_verbose || ast_opt_console)
01703          ast_verbose("Asterisk is now restarting...\n");
01704       restartnow = 1;
01705 
01706       /* close logger */
01707       close_logger();
01708 
01709       /* If there is a consolethread running send it a SIGHUP 
01710          so it can execvp, otherwise we can do it ourselves */
01711       if ((consolethread != AST_PTHREADT_NULL) && (consolethread != pthread_self())) {
01712          pthread_kill(consolethread, SIGHUP);
01713          /* Give the signal handler some time to complete */
01714          sleep(2);
01715       } else
01716          execvp(_argv[0], _argv);
01717    
01718    } else {
01719       /* close logger */
01720       close_logger();
01721    }
01722    exit(0);
01723 }
01724 
01725 static void __quit_handler(int num)
01726 {
01727    int a = 0;
01728    sig_flags.need_quit = 1;
01729    if (sig_alert_pipe[1] != -1) {
01730       if (write(sig_alert_pipe[1], &a, sizeof(a)) < 0) {
01731          fprintf(stderr, "quit_handler: write() failed: %s\n", strerror(errno));
01732       }
01733    }
01734    /* There is no need to restore the signal handler here, since the app
01735     * is going to exit */
01736 }
01737 
01738 static void __remote_quit_handler(int num)
01739 {
01740    sig_flags.need_quit = 1;
01741 }
01742 
01743 static const char *fix_header(char *outbuf, int maxout, const char *s, char *cmp)
01744 {
01745    const char *c;
01746 
01747    /* Check for verboser preamble */
01748    if (*s == 127) {
01749       s++;
01750    }
01751 
01752    if (!strncmp(s, cmp, strlen(cmp))) {
01753       c = s + strlen(cmp);
01754       term_color(outbuf, cmp, COLOR_GRAY, 0, maxout);
01755       return c;
01756    }
01757    return NULL;
01758 }
01759 
01760 static void console_verboser(const char *s)
01761 {
01762    char tmp[80];
01763    const char *c = NULL;
01764 
01765    if ((c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_4)) ||
01766        (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_3)) ||
01767        (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_2)) ||
01768        (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_1))) {
01769       fputs(tmp, stdout);
01770       fputs(c, stdout);
01771    } else {
01772       if (*s == 127) {
01773          s++;
01774       }
01775       fputs(s, stdout);
01776    }
01777 
01778    fflush(stdout);
01779    
01780    /* Wake up a poll()ing console */
01781    if (ast_opt_console && consolethread != AST_PTHREADT_NULL)
01782       pthread_kill(consolethread, SIGURG);
01783 }
01784 
01785 static int ast_all_zeros(char *s)
01786 {
01787    while (*s) {
01788       if (*s > 32)
01789          return 0;
01790       s++;  
01791    }
01792    return 1;
01793 }
01794 
01795 static void consolehandler(char *s)
01796 {
01797    printf("%s", term_end());
01798    fflush(stdout);
01799 
01800    /* Called when readline data is available */
01801    if (!ast_all_zeros(s))
01802       ast_el_add_history(s);
01803    /* The real handler for bang */
01804    if (s[0] == '!') {
01805       if (s[1])
01806          ast_safe_system(s+1);
01807       else
01808          ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
01809    } else 
01810       ast_cli_command(STDOUT_FILENO, s);
01811 }
01812 
01813 static int remoteconsolehandler(char *s)
01814 {
01815    int ret = 0;
01816 
01817    /* Called when readline data is available */
01818    if (!ast_all_zeros(s))
01819       ast_el_add_history(s);
01820    /* The real handler for bang */
01821    if (s[0] == '!') {
01822       if (s[1])
01823          ast_safe_system(s+1);
01824       else
01825          ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
01826       ret = 1;
01827    }
01828    if ((strncasecmp(s, "quit", 4) == 0 || strncasecmp(s, "exit", 4) == 0) &&
01829        (s[4] == '\0' || isspace(s[4]))) {
01830       quit_handler(0, 0, 0, 0);
01831       ret = 1;
01832    }
01833 
01834    return ret;
01835 }
01836 
01837 static char *handle_version(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01838 {
01839    switch (cmd) {
01840    case CLI_INIT:
01841       e->command = "core show version";
01842       e->usage = 
01843          "Usage: core show version\n"
01844          "       Shows Asterisk version information.\n";
01845       return NULL;
01846    case CLI_GENERATE:
01847       return NULL;
01848    }
01849 
01850    if (a->argc != 3)
01851       return CLI_SHOWUSAGE;
01852    ast_cli(a->fd, "Asterisk %s built by %s @ %s on a %s running %s on %s\n",
01853       ast_get_version(), ast_build_user, ast_build_hostname,
01854       ast_build_machine, ast_build_os, ast_build_date);
01855    return CLI_SUCCESS;
01856 }
01857 
01858 #if 0
01859 static int handle_quit(int fd, int argc, char *argv[])
01860 {
01861    if (argc != 1)
01862       return RESULT_SHOWUSAGE;
01863    quit_handler(0, 0, 1, 0);
01864    return RESULT_SUCCESS;
01865 }
01866 #endif
01867 
01868 static char *handle_stop_now(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01869 {
01870    switch (cmd) {
01871    case CLI_INIT:
01872       e->command = "core stop now";
01873       e->usage = 
01874          "Usage: core stop now\n"
01875          "       Shuts down a running Asterisk immediately, hanging up all active calls .\n";
01876       return NULL;
01877    case CLI_GENERATE:
01878       return NULL;
01879    }
01880 
01881    if (a->argc != e->args)
01882       return CLI_SHOWUSAGE;
01883    quit_handler(0, 0 /* Not nice */, 1 /* safely */, 0 /* not restart */);
01884    return CLI_SUCCESS;
01885 }
01886 
01887 static char *handle_stop_gracefully(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01888 {
01889    switch (cmd) {
01890    case CLI_INIT:
01891       e->command = "core stop gracefully";
01892       e->usage = 
01893          "Usage: core stop gracefully\n"
01894          "       Causes Asterisk to not accept new calls, and exit when all\n"
01895          "       active calls have terminated normally.\n";
01896       return NULL;
01897    case CLI_GENERATE:
01898       return NULL;
01899    }
01900 
01901    if (a->argc != e->args)
01902       return CLI_SHOWUSAGE;
01903    quit_handler(0, 1 /* nicely */, 1 /* safely */, 0 /* no restart */);
01904    return CLI_SUCCESS;
01905 }
01906 
01907 static char *handle_stop_when_convenient(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01908 {
01909    switch (cmd) {
01910    case CLI_INIT:
01911       e->command = "core stop when convenient";
01912       e->usage = 
01913          "Usage: core stop when convenient\n"
01914          "       Causes Asterisk to perform a shutdown when all active calls have ended.\n";
01915       return NULL;
01916    case CLI_GENERATE:
01917       return NULL;
01918    }
01919 
01920    if (a->argc != e->args)
01921       return CLI_SHOWUSAGE;
01922    ast_cli(a->fd, "Waiting for inactivity to perform halt\n");
01923    quit_handler(0, 2 /* really nicely */, 1 /* safely */, 0 /* don't restart */);
01924    return CLI_SUCCESS;
01925 }
01926 
01927 static char *handle_restart_now(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01928 {
01929    switch (cmd) {
01930    case CLI_INIT:
01931       e->command = "core restart now";
01932       e->usage = 
01933          "Usage: core restart now\n"
01934          "       Causes Asterisk to hangup all calls and exec() itself performing a cold\n"
01935          "       restart.\n";
01936       return NULL;
01937    case CLI_GENERATE:
01938       return NULL;
01939    }
01940 
01941    if (a->argc != e->args)
01942       return CLI_SHOWUSAGE;
01943    quit_handler(0, 0 /* not nicely */, 1 /* safely */, 1 /* restart */);
01944    return CLI_SUCCESS;
01945 }
01946 
01947 static char *handle_restart_gracefully(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01948 {
01949    switch (cmd) {
01950    case CLI_INIT:
01951       e->command = "core restart gracefully";
01952       e->usage = 
01953          "Usage: core restart gracefully\n"
01954          "       Causes Asterisk to stop accepting new calls and exec() itself performing a cold\n"
01955          "       restart when all active calls have ended.\n";
01956       return NULL;
01957    case CLI_GENERATE:
01958       return NULL;
01959    }
01960 
01961    if (a->argc != e->args)
01962       return CLI_SHOWUSAGE;
01963    quit_handler(0, 1 /* nicely */, 1 /* safely */, 1 /* restart */);
01964    return CLI_SUCCESS;
01965 }
01966 
01967 static char *handle_restart_when_convenient(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01968 {
01969    switch (cmd) {
01970    case CLI_INIT:
01971       e->command = "core restart when convenient";
01972       e->usage = 
01973          "Usage: core restart when convenient\n"
01974          "       Causes Asterisk to perform a cold restart when all active calls have ended.\n";
01975       return NULL;
01976    case CLI_GENERATE:
01977       return NULL;
01978    }
01979 
01980    if (a->argc != e->args)
01981       return CLI_SHOWUSAGE;
01982    ast_cli(a->fd, "Waiting for inactivity to perform restart\n");
01983    quit_handler(0, 2 /* really nicely */, 1 /* safely */, 1 /* restart */);
01984    return CLI_SUCCESS;
01985 }
01986 
01987 static char *handle_abort_shutdown(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01988 {
01989    switch (cmd) {
01990    case CLI_INIT:
01991       e->command = "core abort shutdown";
01992       e->usage = 
01993          "Usage: core abort shutdown\n"
01994          "       Causes Asterisk to abort an executing shutdown or restart, and resume normal\n"
01995          "       call operations.\n";
01996       return NULL;
01997    case CLI_GENERATE:
01998       return NULL;
01999    }
02000 
02001    if (a->argc != e->args)
02002       return CLI_SHOWUSAGE;
02003    ast_cancel_shutdown();
02004    shuttingdown = 0;
02005    return CLI_SUCCESS;
02006 }
02007 
02008 static char *handle_bang(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
02009 {
02010    switch (cmd) {
02011    case CLI_INIT:
02012       e->command = "!";
02013       e->usage = 
02014          "Usage: !<command>\n"
02015          "       Executes a given shell command\n";
02016       return NULL;
02017    case CLI_GENERATE:
02018       return NULL;
02019    }
02020 
02021    return CLI_SUCCESS;
02022 }
02023 static const char warranty_lines[] = {
02024    "\n"
02025    "            NO WARRANTY\n"
02026    "\n"
02027    "BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\n"
02028    "FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN\n"
02029    "OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\n"
02030    "PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\n"
02031    "OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n"
02032    "MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS\n"
02033    "TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE\n"
02034    "PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\n"
02035    "REPAIR OR CORRECTION.\n"
02036    "\n"
02037    "IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\n"
02038    "WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\n"
02039    "REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\n"
02040    "INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\n"
02041    "OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\n"
02042    "TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\n"
02043    "YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\n"
02044    "PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\n"
02045    "POSSIBILITY OF SUCH DAMAGES.\n"
02046 };
02047 
02048 static char *show_warranty(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
02049 {
02050    switch (cmd) {
02051    case CLI_INIT:
02052       e->command = "core show warranty";
02053       e->usage = 
02054          "Usage: core show warranty\n"
02055          "       Shows the warranty (if any) for this copy of Asterisk.\n";
02056       return NULL;
02057    case CLI_GENERATE:
02058       return NULL;
02059    }
02060 
02061    ast_cli(a->fd, "%s", warranty_lines);
02062 
02063    return CLI_SUCCESS;
02064 }
02065 
02066 static const char license_lines[] = {
02067    "\n"
02068    "This program is free software; you can redistribute it and/or modify\n"
02069    "it under the terms of the GNU General Public License version 2 as\n"
02070    "published by the Free Software Foundation.\n"
02071    "\n"
02072    "This program also contains components licensed under other licenses.\n"
02073    "They include:\n"
02074    "\n"
02075    "This program is distributed in the hope that it will be useful,\n"
02076    "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
02077    "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
02078    "GNU General Public License for more details.\n"
02079    "\n"
02080    "You should have received a copy of the GNU General Public License\n"
02081    "along with this program; if not, write to the Free Software\n"
02082    "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\n"
02083 };
02084 
02085 static char *show_license(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
02086 {
02087    switch (cmd) {
02088    case CLI_INIT:
02089       e->command = "core show license";
02090       e->usage = 
02091          "Usage: core show license\n"
02092          "       Shows the license(s) for this copy of Asterisk.\n";
02093       return NULL;
02094    case CLI_GENERATE:
02095       return NULL;
02096    }
02097 
02098    ast_cli(a->fd, "%s", license_lines);
02099 
02100    return CLI_SUCCESS;
02101 }
02102 
02103 #define ASTERISK_PROMPT "*CLI> "
02104 
02105 #define ASTERISK_PROMPT2 "%s*CLI> "
02106 
02107 static struct ast_cli_entry cli_asterisk[] = {
02108    AST_CLI_DEFINE(handle_abort_shutdown, "Cancel a running shutdown"),
02109    AST_CLI_DEFINE(handle_stop_now, "Shut down Asterisk immediately"),
02110    AST_CLI_DEFINE(handle_stop_gracefully, "Gracefully shut down Asterisk"),
02111    AST_CLI_DEFINE(handle_stop_when_convenient, "Shut down Asterisk at empty call volume"),
02112    AST_CLI_DEFINE(handle_restart_now, "Restart Asterisk immediately"), 
02113    AST_CLI_DEFINE(handle_restart_gracefully, "Restart Asterisk gracefully"),
02114    AST_CLI_DEFINE(handle_restart_when_convenient, "Restart Asterisk at empty call volume"),
02115    AST_CLI_DEFINE(show_warranty, "Show the warranty (if any) for this copy of Asterisk"),
02116    AST_CLI_DEFINE(show_license, "Show the license(s) for this copy of Asterisk"),
02117    AST_CLI_DEFINE(handle_version, "Display version info"),
02118    AST_CLI_DEFINE(handle_bang, "Execute a shell command"),
02119 #if !defined(LOW_MEMORY)
02120    AST_CLI_DEFINE(handle_show_version_files, "List versions of files used to build Asterisk"),
02121    AST_CLI_DEFINE(handle_show_threads, "Show running threads"),
02122 #if defined(HAVE_SYSINFO) || defined(HAVE_SYSCTL)
02123    AST_CLI_DEFINE(handle_show_sysinfo, "Show System Information"),
02124 #endif
02125    AST_CLI_DEFINE(handle_show_profile, "Display profiling info"),
02126    AST_CLI_DEFINE(handle_show_settings, "Show some core settings"),
02127    AST_CLI_DEFINE(handle_clear_profile, "Clear profiling info"),
02128 #endif /* ! LOW_MEMORY */
02129 };
02130 
02131 static int ast_el_read_char(EditLine *editline, char *cp)
02132 {
02133    int num_read = 0;
02134    int lastpos = 0;
02135    struct pollfd fds[2];
02136    int res;
02137    int max;
02138 #define EL_BUF_SIZE 512
02139    char buf[EL_BUF_SIZE];
02140 
02141    for (;;) {
02142       max = 1;
02143       fds[0].fd = ast_consock;
02144       fds[0].events = POLLIN;
02145       if (!ast_opt_exec) {
02146          fds[1].fd = STDIN_FILENO;
02147          fds[1].events = POLLIN;
02148          max++;
02149       }
02150       res = ast_poll(fds, max, -1);
02151       if (res < 0) {
02152          if (sig_flags.need_quit || sig_flags.need_quit_handler)
02153             break;
02154          if (errno == EINTR)
02155             continue;
02156          ast_log(LOG_ERROR, "poll failed: %s\n", strerror(errno));
02157          break;
02158       }
02159 
02160       if (!ast_opt_exec && fds[1].revents) {
02161          num_read = read(STDIN_FILENO, cp, 1);
02162          if (num_read < 1) {
02163             break;
02164          } else 
02165             return (num_read);
02166       }
02167       if (fds[0].revents) {
02168          char *tmp;
02169          res = read(ast_consock, buf, sizeof(buf) - 1);
02170          /* if the remote side disappears exit */
02171          if (res < 1) {
02172             fprintf(stderr, "\nDisconnected from Asterisk server\n");
02173             if (!ast_opt_reconnect) {
02174                quit_handler(0, 0, 0, 0);
02175             } else {
02176                int tries;
02177                int reconnects_per_second = 20;
02178                fprintf(stderr, "Attempting to reconnect for 30 seconds\n");
02179                for (tries = 0; tries < 30 * reconnects_per_second; tries++) {
02180                   if (ast_tryconnect()) {
02181                      fprintf(stderr, "Reconnect succeeded after %.3f seconds\n", 1.0 / reconnects_per_second * tries);
02182                      printf("%s", term_quit());
02183                      WELCOME_MESSAGE;
02184                      if (!ast_opt_mute)
02185                         fdsend(ast_consock, "logger mute silent");
02186                      else 
02187                         printf("log and verbose output currently muted ('logger mute' to unmute)\n");
02188                      break;
02189                   } else
02190                      usleep(1000000 / reconnects_per_second);
02191                }
02192                if (tries >= 30 * reconnects_per_second) {
02193                   fprintf(stderr, "Failed to reconnect for 30 seconds.  Quitting.\n");
02194                   quit_handler(0, 0, 0, 0);
02195                }
02196             }
02197          }
02198 
02199          buf[res] = '\0';
02200 
02201          /* Strip preamble from asynchronous events, too */
02202          for (tmp = buf; *tmp; tmp++) {
02203             if (*tmp == 127) {
02204                memmove(tmp, tmp + 1, strlen(tmp));
02205                tmp--;
02206                res--;
02207             }
02208          }
02209 
02210          /* Write over the CLI prompt */
02211          if (!ast_opt_exec && !lastpos) {
02212             if (write(STDOUT_FILENO, "\r", 5) < 0) {
02213             }
02214          }
02215          if (write(STDOUT_FILENO, buf, res) < 0) {
02216          }
02217          if ((res < EL_BUF_SIZE - 1) && ((buf[res-1] == '\n') || (buf[res-2] == '\n'))) {
02218             *cp = CC_REFRESH;
02219             return(1);
02220          } else
02221             lastpos = 1;
02222       }
02223    }
02224 
02225    *cp = '\0';
02226    return (0);
02227 }
02228 
02229 static struct ast_str *prompt = NULL;
02230 
02231 static char *cli_prompt(EditLine *editline)
02232 {
02233    char tmp[100];
02234    char *pfmt;
02235    int color_used = 0;
02236    static int cli_prompt_changes = 0;
02237    char term_code[20];
02238    struct passwd *pw;
02239    struct group *gr;
02240 
02241    if (prompt == NULL) {
02242       prompt = ast_str_create(100);
02243    } else if (!cli_prompt_changes) {
02244       return ast_str_buffer(prompt);
02245    } else {
02246       ast_str_reset(prompt);
02247    }
02248 
02249    if ((pfmt = getenv("ASTERISK_PROMPT"))) {
02250       char *t = pfmt;
02251       struct timeval ts = ast_tvnow();
02252       while (*t != '\0') {
02253          if (*t == '%') {
02254             char hostname[MAXHOSTNAMELEN] = "";
02255             int i, which;
02256             struct ast_tm tm = { 0, };
02257             int fgcolor = COLOR_WHITE, bgcolor = COLOR_BLACK;
02258 
02259             t++;
02260             switch (*t) {
02261             case 'C': /* color */
02262                t++;
02263                if (sscanf(t, "%30d;%30d%n", &fgcolor, &bgcolor, &i) == 2) {
02264                   ast_str_append(&prompt, 0, "%s", term_color_code(term_code, fgcolor, bgcolor, sizeof(term_code)));
02265                   t += i - 1;
02266                } else if (sscanf(t, "%30d%n", &fgcolor, &i) == 1) {
02267                   ast_str_append(&prompt, 0, "%s", term_color_code(term_code, fgcolor, 0, sizeof(term_code)));
02268                   t += i - 1;
02269                }
02270 
02271                /* If the color has been reset correctly, then there's no need to reset it later */
02272                color_used = ((fgcolor == COLOR_WHITE) && (bgcolor == COLOR_BLACK)) ? 0 : 1;
02273                break;
02274             case 'd': /* date */
02275                if (ast_localtime(&ts, &tm, NULL)) {
02276                   ast_strftime(tmp, sizeof(tmp), "%Y-%m-%d", &tm);
02277                   ast_str_append(&prompt, 0, "%s", tmp);
02278                   cli_prompt_changes++;
02279                }
02280                break;
02281             case 'g': /* group */
02282                if ((gr = getgrgid(getgid()))) {
02283                   ast_str_append(&prompt, 0, "%s", gr->gr_name);
02284                }
02285                break;
02286             case 'h': /* hostname */
02287                if (!gethostname(hostname, sizeof(hostname) - 1)) {
02288                   ast_str_append(&prompt, 0, "%s", hostname);
02289                } else {
02290                   ast_str_append(&prompt, 0, "%s", "localhost");
02291                }
02292                break;
02293             case 'H': /* short hostname */
02294                if (!gethostname(hostname, sizeof(hostname) - 1)) {
02295                   char *dotptr;
02296                   if ((dotptr = strchr(hostname, '.'))) {
02297                      *dotptr = '\0';
02298                   }
02299                   ast_str_append(&prompt, 0, "%s", hostname);
02300                } else {
02301                   ast_str_append(&prompt, 0, "%s", "localhost");
02302                }
02303                break;
02304 #ifdef HAVE_GETLOADAVG
02305             case 'l': /* load avg */
02306                t++;
02307                if (sscanf(t, "%30d", &which) == 1 && which > 0 && which <= 3) {
02308                   double list[3];
02309                   getloadavg(list, 3);
02310                   ast_str_append(&prompt, 0, "%.2f", list[which - 1]);
02311                   cli_prompt_changes++;
02312                }
02313                break;
02314 #endif
02315             case 's': /* Asterisk system name (from asterisk.conf) */
02316                ast_str_append(&prompt, 0, "%s", ast_config_AST_SYSTEM_NAME);
02317                break;
02318             case 't': /* time */
02319                if (ast_localtime(&ts, &tm, NULL)) {
02320                   ast_strftime(tmp, sizeof(tmp), "%H:%M:%S", &tm);
02321                   ast_str_append(&prompt, 0, "%s", tmp);
02322                   cli_prompt_changes++;
02323                }
02324                break;
02325             case 'u': /* username */
02326                if ((pw = getpwuid(getuid()))) {
02327                   ast_str_append(&prompt, 0, "%s", pw->pw_name);
02328                }
02329                break;
02330             case '#': /* process console or remote? */
02331                ast_str_append(&prompt, 0, "%c", ast_opt_remote ? '>' : '#');
02332                break;
02333             case '%': /* literal % */
02334                ast_str_append(&prompt, 0, "%c", '%');
02335                break;
02336             case '\0': /* % is last character - prevent bug */
02337                t--;
02338                break;
02339             }
02340          } else {
02341             ast_str_append(&prompt, 0, "%c", *t);
02342          }
02343          t++;
02344       }
02345       if (color_used) {
02346          /* Force colors back to normal at end */
02347          ast_str_append(&prompt, 0, "%s", term_color_code(term_code, 0, 0, sizeof(term_code)));
02348       }
02349    } else if (remotehostname) {
02350       ast_str_set(&prompt, 0, ASTERISK_PROMPT2, remotehostname);
02351    } else {
02352       ast_str_set(&prompt, 0, "%s", ASTERISK_PROMPT);
02353    }
02354 
02355    return ast_str_buffer(prompt);   
02356 }
02357 
02358 static char **ast_el_strtoarr(char *buf)
02359 {
02360    char **match_list = NULL, **match_list_tmp, *retstr;
02361    size_t match_list_len;
02362    int matches = 0;
02363 
02364    match_list_len = 1;
02365    while ( (retstr = strsep(&buf, " ")) != NULL) {
02366 
02367       if (!strcmp(retstr, AST_CLI_COMPLETE_EOF))
02368          break;
02369       if (matches + 1 >= match_list_len) {
02370          match_list_len <<= 1;
02371          if ((match_list_tmp = ast_realloc(match_list, match_list_len * sizeof(char *)))) {
02372             match_list = match_list_tmp;
02373          } else {
02374             if (match_list)
02375                ast_free(match_list);
02376             return (char **) NULL;
02377          }
02378       }
02379 
02380       match_list[matches++] = ast_strdup(retstr);
02381    }
02382 
02383    if (!match_list)
02384       return (char **) NULL;
02385 
02386    if (matches >= match_list_len) {
02387       if ((match_list_tmp = ast_realloc(match_list, (match_list_len + 1) * sizeof(char *)))) {
02388          match_list = match_list_tmp;
02389       } else {
02390          if (match_list)
02391             ast_free(match_list);
02392          return (char **) NULL;
02393       }
02394    }
02395 
02396    match_list[matches] = (char *) NULL;
02397 
02398    return match_list;
02399 }
02400 
02401 static int ast_el_sort_compare(const void *i1, const void *i2)
02402 {
02403    char *s1, *s2;
02404 
02405    s1 = ((char **)i1)[0];
02406    s2 = ((char **)i2)[0];
02407 
02408    return strcasecmp(s1, s2);
02409 }
02410 
02411 static int ast_cli_display_match_list(char **matches, int len, int max)
02412 {
02413    int i, idx, limit, count;
02414    int screenwidth = 0;
02415    int numoutput = 0, numoutputline = 0;
02416 
02417    screenwidth = ast_get_termcols(STDOUT_FILENO);
02418 
02419    /* find out how many entries can be put on one line, with two spaces between strings */
02420    limit = screenwidth / (max + 2);
02421    if (limit == 0)
02422       limit = 1;
02423 
02424    /* how many lines of output */
02425    count = len / limit;
02426    if (count * limit < len)
02427       count++;
02428 
02429    idx = 1;
02430 
02431    qsort(&matches[0], (size_t)(len), sizeof(char *), ast_el_sort_compare);
02432 
02433    for (; count > 0; count--) {
02434       numoutputline = 0;
02435       for (i = 0; i < limit && matches[idx]; i++, idx++) {
02436 
02437          /* Don't print dupes */
02438          if ( (matches[idx+1] != NULL && strcmp(matches[idx], matches[idx+1]) == 0 ) ) {
02439             i--;
02440             ast_free(matches[idx]);
02441             matches[idx] = NULL;
02442             continue;
02443          }
02444 
02445          numoutput++;
02446          numoutputline++;
02447          fprintf(stdout, "%-*s  ", max, matches[idx]);
02448          ast_free(matches[idx]);
02449          matches[idx] = NULL;
02450       }
02451       if (numoutputline > 0)
02452          fprintf(stdout, "\n");
02453    }
02454 
02455    return numoutput;
02456 }
02457 
02458 
02459 static char *cli_complete(EditLine *editline, int ch)
02460 {
02461    int len = 0;
02462    char *ptr;
02463    int nummatches = 0;
02464    char **matches;
02465    int retval = CC_ERROR;
02466    char buf[2048], savechr;
02467    int res;
02468 
02469    LineInfo *lf = (LineInfo *)el_line(editline);
02470 
02471    savechr = *(char *)lf->cursor;
02472    *(char *)lf->cursor = '\0';
02473    ptr = (char *)lf->cursor;
02474    if (ptr) {
02475       while (ptr > lf->buffer) {
02476          if (isspace(*ptr)) {
02477             ptr++;
02478             break;
02479          }
02480          ptr--;
02481       }
02482    }
02483 
02484    len = lf->cursor - ptr;
02485 
02486    if (ast_opt_remote) {
02487       snprintf(buf, sizeof(buf), "_COMMAND NUMMATCHES \"%s\" \"%s\"", lf->buffer, ptr); 
02488       fdsend(ast_consock, buf);
02489       res = read(ast_consock, buf, sizeof(buf) - 1);
02490       buf[res] = '\0';
02491       nummatches = atoi(buf);
02492 
02493       if (nummatches > 0) {
02494          char *mbuf;
02495          int mlen = 0, maxmbuf = 2048;
02496          /* Start with a 2048 byte buffer */       
02497          if (!(mbuf = ast_malloc(maxmbuf))) {
02498             lf->cursor[0] = savechr;
02499             return (char *)(CC_ERROR);
02500          }
02501          snprintf(buf, sizeof(buf), "_COMMAND MATCHESARRAY \"%s\" \"%s\"", lf->buffer, ptr); 
02502          fdsend(ast_consock, buf);
02503          res = 0;
02504          mbuf[0] = '\0';
02505          while (!strstr(mbuf, AST_CLI_COMPLETE_EOF) && res != -1) {
02506             if (mlen + 1024 > maxmbuf) {
02507                /* Every step increment buffer 1024 bytes */
02508                maxmbuf += 1024;              
02509                if (!(mbuf = ast_realloc(mbuf, maxmbuf))) {
02510                   lf->cursor[0] = savechr;
02511                   return (char *)(CC_ERROR);
02512                }
02513             }
02514             /* Only read 1024 bytes at a time */
02515             res = read(ast_consock, mbuf + mlen, 1024);
02516             if (res > 0)
02517                mlen += res;
02518          }
02519          mbuf[mlen] = '\0';
02520 
02521          matches = ast_el_strtoarr(mbuf);
02522          ast_free(mbuf);
02523       } else
02524          matches = (char **) NULL;
02525    } else {
02526       char **p, *oldbuf=NULL;
02527       nummatches = 0;
02528       matches = ast_cli_completion_matches((char *)lf->buffer,ptr);
02529       for (p = matches; p && *p; p++) {
02530          if (!oldbuf || strcmp(*p,oldbuf))
02531             nummatches++;
02532          oldbuf = *p;
02533       }
02534    }
02535 
02536    if (matches) {
02537       int i;
02538       int matches_num, maxlen, match_len;
02539 
02540       if (matches[0][0] != '\0') {
02541          el_deletestr(editline, (int) len);
02542          el_insertstr(editline, matches[0]);
02543          retval = CC_REFRESH;
02544       }
02545 
02546       if (nummatches == 1) {
02547          /* Found an exact match */
02548          el_insertstr(editline, " ");
02549          retval = CC_REFRESH;
02550       } else {
02551          /* Must be more than one match */
02552          for (i = 1, maxlen = 0; matches[i]; i++) {
02553             match_len = strlen(matches[i]);
02554             if (match_len > maxlen)
02555                maxlen = match_len;
02556          }
02557          matches_num = i - 1;
02558          if (matches_num >1) {
02559             fprintf(stdout, "\n");
02560             ast_cli_display_match_list(matches, nummatches, maxlen);
02561             retval = CC_REDISPLAY;
02562          } else { 
02563             el_insertstr(editline," ");
02564             retval = CC_REFRESH;
02565          }
02566       }
02567       for (i = 0; matches[i]; i++)
02568          ast_free(matches[i]);
02569       ast_free(matches);
02570    }
02571 
02572    lf->cursor[0] = savechr;
02573 
02574    return (char *)(long)retval;
02575 }
02576 
02577 static int ast_el_initialize(void)
02578 {
02579    HistEvent ev;
02580    char *editor = getenv("AST_EDITOR");
02581 
02582    if (el != NULL)
02583       el_end(el);
02584    if (el_hist != NULL)
02585       history_end(el_hist);
02586 
02587    el = el_init("asterisk", stdin, stdout, stderr);
02588    el_set(el, EL_PROMPT, cli_prompt);
02589 
02590    el_set(el, EL_EDITMODE, 1);      
02591    el_set(el, EL_EDITOR, editor ? editor : "emacs");     
02592    el_hist = history_init();
02593    if (!el || !el_hist)
02594       return -1;
02595 
02596    /* setup history with 100 entries */
02597    history(el_hist, &ev, H_SETSIZE, 100);
02598 
02599    el_set(el, EL_HIST, history, el_hist);
02600 
02601    el_set(el, EL_ADDFN, "ed-complete", "Complete argument", cli_complete);
02602    /* Bind <tab> to command completion */
02603    el_set(el, EL_BIND, "^I", "ed-complete", NULL);
02604    /* Bind ? to command completion */
02605    el_set(el, EL_BIND, "?", "ed-complete", NULL);
02606    /* Bind ^D to redisplay */
02607    el_set(el, EL_BIND, "^D", "ed-redisplay", NULL);
02608 
02609    return 0;
02610 }
02611 
02612 #define MAX_HISTORY_COMMAND_LENGTH 256
02613 
02614 static int ast_el_add_history(char *buf)
02615 {
02616    HistEvent ev;
02617 
02618    if (el_hist == NULL || el == NULL)
02619       ast_el_initialize();
02620    if (strlen(buf) > (MAX_HISTORY_COMMAND_LENGTH - 1))
02621       return 0;
02622    return (history(el_hist, &ev, H_ENTER, ast_strip(ast_strdupa(buf))));
02623 }
02624 
02625 static int ast_el_write_history(char *filename)
02626 {
02627    HistEvent ev;
02628 
02629    if (el_hist == NULL || el == NULL)
02630       ast_el_initialize();
02631 
02632    return (history(el_hist, &ev, H_SAVE, filename));
02633 }
02634 
02635 static int ast_el_read_history(char *filename)
02636 {
02637    HistEvent ev;
02638 
02639    if (el_hist == NULL || el == NULL)
02640       ast_el_initialize();
02641 
02642    return (history(el_hist, &ev, H_LOAD, filename));
02643 }
02644 
02645 static void ast_remotecontrol(char *data)
02646 {
02647    char buf[80];
02648    int res;
02649    char filename[80] = "";
02650    char *hostname;
02651    char *cpid;
02652    char *version;
02653    int pid;
02654    char *stringp = NULL;
02655 
02656    char *ebuf;
02657    int num = 0;
02658 
02659    memset(&sig_flags, 0, sizeof(sig_flags));
02660    signal(SIGINT, __remote_quit_handler);
02661    signal(SIGTERM, __remote_quit_handler);
02662    signal(SIGHUP, __remote_quit_handler);
02663 
02664    if (read(ast_consock, buf, sizeof(buf)) < 0) {
02665       ast_log(LOG_ERROR, "read() failed: %s\n", strerror(errno));
02666       return;
02667    }
02668    if (data) {
02669       char prefix[] = "cli quit after ";
02670       char *tmp = alloca(strlen(data) + strlen(prefix) + 1);
02671       sprintf(tmp, "%s%s", prefix, data);
02672       if (write(ast_consock, tmp, strlen(tmp) + 1) < 0) {
02673          ast_log(LOG_ERROR, "write() failed: %s\n", strerror(errno));
02674          if (sig_flags.need_quit || sig_flags.need_quit_handler) {
02675             return;
02676          }
02677       }
02678    }
02679    stringp = buf;
02680    hostname = strsep(&stringp, "/");
02681    cpid = strsep(&stringp, "/");
02682    version = strsep(&stringp, "\n");
02683    if (!version)
02684       version = "<Version Unknown>";
02685    stringp = hostname;
02686    strsep(&stringp, ".");
02687    if (cpid)
02688       pid = atoi(cpid);
02689    else
02690       pid = -1;
02691    if (!data) {
02692       char tmp[80];
02693       snprintf(tmp, sizeof(tmp), "core set verbose atleast %d", option_verbose);
02694       fdsend(ast_consock, tmp);
02695       snprintf(tmp, sizeof(tmp), "core set debug atleast %d", option_debug);
02696       fdsend(ast_consock, tmp);
02697       if (!ast_opt_mute)
02698          fdsend(ast_consock, "logger mute silent");
02699       else 
02700          printf("log and verbose output currently muted ('logger mute' to unmute)\n");
02701    }
02702 
02703    if (ast_opt_exec && data) {  /* hack to print output then exit if asterisk -rx is used */
02704       struct pollfd fds;
02705       fds.fd = ast_consock;
02706       fds.events = POLLIN;
02707       fds.revents = 0;
02708       while (ast_poll(&fds, 1, 60000) > 0) {
02709          char buffer[512] = "", *curline = buffer, *nextline;
02710          int not_written = 1;
02711 
02712          if (sig_flags.need_quit || sig_flags.need_quit_handler) {
02713             break;
02714          }
02715 
02716          if (read(ast_consock, buffer, sizeof(buffer) - 1) <= 0) {
02717             break;
02718          }
02719 
02720          do {
02721             if ((nextline = strchr(curline, '\n'))) {
02722                nextline++;
02723             } else {
02724                nextline = strchr(curline, '\0');
02725             }
02726 
02727             /* Skip verbose lines */
02728             if (*curline != 127) {
02729                not_written = 0;
02730                if (write(STDOUT_FILENO, curline, nextline - curline) < 0) {
02731                   ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno));
02732                }
02733             }
02734             curline = nextline;
02735          } while (!ast_strlen_zero(curline));
02736 
02737          /* No non-verbose output in 60 seconds. */
02738          if (not_written) {
02739             break;
02740          }
02741       }
02742       return;
02743    }
02744 
02745    ast_verbose("Connected to Asterisk %s currently running on %s (pid = %d)\n", version, hostname, pid);
02746    remotehostname = hostname;
02747    if (getenv("HOME")) 
02748       snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
02749    if (el_hist == NULL || el == NULL)
02750       ast_el_initialize();
02751 
02752    el_set(el, EL_GETCFN, ast_el_read_char);
02753 
02754    if (!ast_strlen_zero(filename))
02755       ast_el_read_history(filename);
02756 
02757    for (;;) {
02758       ebuf = (char *)el_gets(el, &num);
02759 
02760       if (sig_flags.need_quit || sig_flags.need_quit_handler) {
02761          break;
02762       }
02763 
02764       if (!ebuf && write(1, "", 1) < 0)
02765          break;
02766 
02767       if (!ast_strlen_zero(ebuf)) {
02768          if (ebuf[strlen(ebuf)-1] == '\n')
02769             ebuf[strlen(ebuf)-1] = '\0';
02770          if (!remoteconsolehandler(ebuf)) {
02771             /* Strip preamble from output */
02772             char *temp;
02773             for (temp = ebuf; *temp; temp++) {
02774                if (*temp == 127) {
02775                   memmove(temp, temp + 1, strlen(temp));
02776                   temp--;
02777                }
02778             }
02779             res = write(ast_consock, ebuf, strlen(ebuf) + 1);
02780             if (res < 1) {
02781                ast_log(LOG_WARNING, "Unable to write: %s\n", strerror(errno));
02782                break;
02783             }
02784          }
02785       }
02786    }
02787    printf("\nDisconnected from Asterisk server\n");
02788 }
02789 
02790 static int show_version(void)
02791 {
02792    printf("Asterisk %s\n", ast_get_version());
02793    return 0;
02794 }
02795 
02796 static int show_cli_help(void) {
02797    printf("Asterisk %s, Copyright (C) 1999 - 2010, Digium, Inc. and others.\n", ast_get_version());
02798    printf("Usage: asterisk [OPTIONS]\n");
02799    printf("Valid Options:\n");
02800    printf("   -V              Display version number and exit\n");
02801    printf("   -C <configfile> Use an alternate configuration file\n");
02802    printf("   -G <group>      Run as a group other than the caller\n");
02803    printf("   -U <user>       Run as a user other than the caller\n");
02804    printf("   -c              Provide console CLI\n");
02805    printf("   -d              Enable extra debugging\n");
02806 #if HAVE_WORKING_FORK
02807    printf("   -f              Do not fork\n");
02808    printf("   -F              Always fork\n");
02809 #endif
02810    printf("   -g              Dump core in case of a crash\n");
02811    printf("   -h              This help screen\n");
02812    printf("   -i              Initialize crypto keys at startup\n");
02813    printf("   -I              Enable internal timing if DAHDI timer is available\n");
02814    printf("   -L <load>       Limit the maximum load average before rejecting new calls\n");
02815    printf("   -M <value>      Limit the maximum number of calls to the specified value\n");
02816    printf("   -m              Mute debugging and console output on the console\n");
02817    printf("   -n              Disable console colorization\n");
02818    printf("   -p              Run as pseudo-realtime thread\n");
02819    printf("   -q              Quiet mode (suppress output)\n");
02820    printf("   -r              Connect to Asterisk on this machine\n");
02821    printf("   -R              Same as -r, except attempt to reconnect if disconnected\n");
02822    printf("   -s <socket>     Connect to Asterisk via socket <socket> (only valid with -r)\n");
02823    printf("   -t              Record soundfiles in /var/tmp and move them where they\n");
02824    printf("                   belong after they are done\n");
02825    printf("   -T              Display the time in [Mmm dd hh:mm:ss] format for each line\n");
02826    printf("                   of output to the CLI\n");
02827    printf("   -v              Increase verbosity (multiple v's = more verbose)\n");
02828    printf("   -x <cmd>        Execute command <cmd> (only valid with -r)\n");
02829    printf("   -X              Execute includes by default (allows #exec in asterisk.conf)\n");
02830    printf("   -W              Adjust terminal colors to compensate for a light background\n");
02831    printf("\n");
02832    return 0;
02833 }
02834 
02835 static void ast_readconfig(void) 
02836 {
02837    struct ast_config *cfg;
02838    struct ast_variable *v;
02839    char *config = DEFAULT_CONFIG_FILE;
02840    char hostname[MAXHOSTNAMELEN] = "";
02841    struct ast_flags config_flags = { CONFIG_FLAG_NOREALTIME };
02842    struct {
02843       unsigned int dbdir:1;
02844       unsigned int keydir:1;
02845    } found = { 0, 0 };
02846 
02847    if (ast_opt_override_config) {
02848       cfg = ast_config_load2(ast_config_AST_CONFIG_FILE, "" /* core, can't reload */, config_flags);
02849       if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID)
02850          ast_log(LOG_WARNING, "Unable to open specified master config file '%s', using built-in defaults\n", ast_config_AST_CONFIG_FILE);
02851    } else 
02852       cfg = ast_config_load2(config, "" /* core, can't reload */, config_flags);
02853 
02854    /* init with buildtime config */
02855    ast_copy_string(cfg_paths.config_dir, DEFAULT_CONFIG_DIR, sizeof(cfg_paths.config_dir));
02856    ast_copy_string(cfg_paths.spool_dir, DEFAULT_SPOOL_DIR, sizeof(cfg_paths.spool_dir));
02857    ast_copy_string(cfg_paths.module_dir, DEFAULT_MODULE_DIR, sizeof(cfg_paths.module_dir));
02858    snprintf(cfg_paths.monitor_dir, sizeof(cfg_paths.monitor_dir), "%s/monitor", cfg_paths.spool_dir);
02859    ast_copy_string(cfg_paths.var_dir, DEFAULT_VAR_DIR, sizeof(cfg_paths.var_dir));
02860    ast_copy_string(cfg_paths.data_dir, DEFAULT_DATA_DIR, sizeof(cfg_paths.data_dir));
02861    ast_copy_string(cfg_paths.log_dir, DEFAULT_LOG_DIR, sizeof(cfg_paths.log_dir));
02862    ast_copy_string(cfg_paths.agi_dir, DEFAULT_AGI_DIR, sizeof(cfg_paths.agi_dir));
02863    ast_copy_string(cfg_paths.db_path, DEFAULT_DB, sizeof(cfg_paths.db_path));
02864    ast_copy_string(cfg_paths.key_dir, DEFAULT_KEY_DIR, sizeof(cfg_paths.key_dir));
02865    ast_copy_string(cfg_paths.pid_path, DEFAULT_PID, sizeof(cfg_paths.pid_path));
02866    ast_copy_string(cfg_paths.socket_path, DEFAULT_SOCKET, sizeof(cfg_paths.socket_path));
02867    ast_copy_string(cfg_paths.run_dir, DEFAULT_RUN_DIR, sizeof(cfg_paths.run_dir));
02868 
02869    ast_set_default_eid(&ast_eid_default);
02870 
02871    /* no asterisk.conf? no problem, use buildtime config! */
02872    if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) {
02873       return;
02874    }
02875 
02876    for (v = ast_variable_browse(cfg, "files"); v; v = v->next) {
02877       if (!strcasecmp(v->name, "astctlpermissions"))
02878          ast_copy_string(ast_config_AST_CTL_PERMISSIONS, v->value, sizeof(ast_config_AST_CTL_PERMISSIONS));
02879       else if (!strcasecmp(v->name, "astctlowner"))
02880          ast_copy_string(ast_config_AST_CTL_OWNER, v->value, sizeof(ast_config_AST_CTL_OWNER));
02881       else if (!strcasecmp(v->name, "astctlgroup"))
02882          ast_copy_string(ast_config_AST_CTL_GROUP, v->value, sizeof(ast_config_AST_CTL_GROUP));
02883       else if (!strcasecmp(v->name, "astctl"))
02884          ast_copy_string(ast_config_AST_CTL, v->value, sizeof(ast_config_AST_CTL));
02885    }
02886 
02887    for (v = ast_variable_browse(cfg, "directories"); v; v = v->next) {
02888       if (!strcasecmp(v->name, "astetcdir")) {
02889          ast_copy_string(cfg_paths.config_dir, v->value, sizeof(cfg_paths.config_dir));
02890       } else if (!strcasecmp(v->name, "astspooldir")) {
02891          ast_copy_string(cfg_paths.spool_dir, v->value, sizeof(cfg_paths.spool_dir));
02892          snprintf(cfg_paths.monitor_dir, sizeof(cfg_paths.monitor_dir), "%s/monitor", v->value);
02893       } else if (!strcasecmp(v->name, "astvarlibdir")) {
02894          ast_copy_string(cfg_paths.var_dir, v->value, sizeof(cfg_paths.var_dir));
02895          if (!found.dbdir)
02896             snprintf(cfg_paths.db_path, sizeof(cfg_paths.db_path), "%s/astdb", v->value);
02897       } else if (!strcasecmp(v->name, "astdbdir")) {
02898          snprintf(cfg_paths.db_path, sizeof(cfg_paths.db_path), "%s/astdb", v->value);
02899          found.dbdir = 1;
02900       } else if (!strcasecmp(v->name, "astdatadir")) {
02901          ast_copy_string(cfg_paths.data_dir, v->value, sizeof(cfg_paths.data_dir));
02902          if (!found.keydir)
02903             snprintf(cfg_paths.key_dir, sizeof(cfg_paths.key_dir), "%s/keys", v->value);
02904       } else if (!strcasecmp(v->name, "astkeydir")) {
02905          snprintf(cfg_paths.key_dir, sizeof(cfg_paths.key_dir), "%s/keys", v->value);
02906          found.keydir = 1;
02907       } else if (!strcasecmp(v->name, "astlogdir")) {
02908          ast_copy_string(cfg_paths.log_dir, v->value, sizeof(cfg_paths.log_dir));
02909       } else if (!strcasecmp(v->name, "astagidir")) {
02910          ast_copy_string(cfg_paths.agi_dir, v->value, sizeof(cfg_paths.agi_dir));
02911       } else if (!strcasecmp(v->name, "astrundir")) {
02912          snprintf(cfg_paths.pid_path, sizeof(cfg_paths.pid_path), "%s/%s", v->value, "asterisk.pid");
02913          snprintf(cfg_paths.socket_path, sizeof(cfg_paths.socket_path), "%s/%s", v->value, ast_config_AST_CTL);
02914          ast_copy_string(cfg_paths.run_dir, v->value, sizeof(cfg_paths.run_dir));
02915       } else if (!strcasecmp(v->name, "astmoddir")) {
02916          ast_copy_string(cfg_paths.module_dir, v->value, sizeof(cfg_paths.module_dir));
02917       }
02918    }
02919 
02920    for (v = ast_variable_browse(cfg, "options"); v; v = v->next) {
02921       /* verbose level (-v at startup) */
02922       if (!strcasecmp(v->name, "verbose")) {
02923          option_verbose = atoi(v->value);
02924       /* whether or not to force timestamping in CLI verbose output. (-T at startup) */
02925       } else if (!strcasecmp(v->name, "timestamp")) {
02926          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TIMESTAMP);
02927       /* whether or not to support #exec in config files */
02928       } else if (!strcasecmp(v->name, "execincludes")) {
02929          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_EXEC_INCLUDES);
02930       /* debug level (-d at startup) */
02931       } else if (!strcasecmp(v->name, "debug")) {
02932          option_debug = 0;
02933          if (sscanf(v->value, "%30d", &option_debug) != 1) {
02934             option_debug = ast_true(v->value);
02935          }
02936 #if HAVE_WORKING_FORK
02937       /* Disable forking (-f at startup) */
02938       } else if (!strcasecmp(v->name, "nofork")) {
02939          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_FORK);
02940       /* Always fork, even if verbose or debug are enabled (-F at startup) */
02941       } else if (!strcasecmp(v->name, "alwaysfork")) {
02942          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_ALWAYS_FORK);
02943 #endif
02944       /* Run quietly (-q at startup ) */
02945       } else if (!strcasecmp(v->name, "quiet")) {
02946          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_QUIET);
02947       /* Run as console (-c at startup, implies nofork) */
02948       } else if (!strcasecmp(v->name, "console")) {
02949          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_CONSOLE);
02950       /* Run with high priority if the O/S permits (-p at startup) */
02951       } else if (!strcasecmp(v->name, "highpriority")) {
02952          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_HIGH_PRIORITY);
02953       /* Initialize RSA auth keys (IAX2) (-i at startup) */
02954       } else if (!strcasecmp(v->name, "initcrypto")) {
02955          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_INIT_KEYS);
02956       /* Disable ANSI colors for console (-c at startup) */
02957       } else if (!strcasecmp(v->name, "nocolor")) {
02958          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_COLOR);
02959       /* Disable some usage warnings for picky people :p */
02960       } else if (!strcasecmp(v->name, "dontwarn")) {
02961          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_DONT_WARN);
02962       /* Dump core in case of crash (-g) */
02963       } else if (!strcasecmp(v->name, "dumpcore")) {
02964          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_DUMP_CORE);
02965       /* Cache recorded sound files to another directory during recording */
02966       } else if (!strcasecmp(v->name, "cache_record_files")) {
02967          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_CACHE_RECORD_FILES);
02968       /* Specify cache directory */
02969       }  else if (!strcasecmp(v->name, "record_cache_dir")) {
02970          ast_copy_string(record_cache_dir, v->value, AST_CACHE_DIR_LEN);
02971       /* Build transcode paths via SLINEAR, instead of directly */
02972       } else if (!strcasecmp(v->name, "transcode_via_sln")) {
02973          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TRANSCODE_VIA_SLIN);
02974       /* Transmit SLINEAR silence while a channel is being recorded or DTMF is being generated on a channel */
02975       } else if (!strcasecmp(v->name, "transmit_silence_during_record") || !strcasecmp(v->name, "transmit_silence")) {
02976          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TRANSMIT_SILENCE);
02977       /* Enable internal timing */
02978       } else if (!strcasecmp(v->name, "internal_timing")) {
02979          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_INTERNAL_TIMING);
02980       } else if (!strcasecmp(v->name, "maxcalls")) {
02981          if ((sscanf(v->value, "%30d", &option_maxcalls) != 1) || (option_maxcalls < 0)) {
02982             option_maxcalls = 0;
02983          }
02984       } else if (!strcasecmp(v->name, "maxload")) {
02985          double test[1];
02986 
02987          if (getloadavg(test, 1) == -1) {
02988             ast_log(LOG_ERROR, "Cannot obtain load average on this system. 'maxload' option disabled.\n");
02989             option_maxload = 0.0;
02990          } else if ((sscanf(v->value, "%30lf", &option_maxload) != 1) || (option_maxload < 0.0)) {
02991             option_maxload = 0.0;
02992          }
02993       /* Set the maximum amount of open files */
02994       } else if (!strcasecmp(v->name, "maxfiles")) {
02995          option_maxfiles = atoi(v->value);
02996          set_ulimit(option_maxfiles);
02997       /* What user to run as */
02998       } else if (!strcasecmp(v->name, "runuser")) {
02999          ast_copy_string(cfg_paths.run_user, v->value, sizeof(cfg_paths.run_user));
03000       /* What group to run as */
03001       } else if (!strcasecmp(v->name, "rungroup")) {
03002          ast_copy_string(cfg_paths.run_group, v->value, sizeof(cfg_paths.run_group));
03003       } else if (!strcasecmp(v->name, "systemname")) {
03004          ast_copy_string(cfg_paths.system_name, v->value, sizeof(cfg_paths.system_name));
03005       } else if (!strcasecmp(v->name, "autosystemname")) {
03006          if (ast_true(v->value)) {
03007             if (!gethostname(hostname, sizeof(hostname) - 1))
03008                ast_copy_string(cfg_paths.system_name, hostname, sizeof(cfg_paths.system_name));
03009             else {
03010                if (ast_strlen_zero(ast_config_AST_SYSTEM_NAME)){
03011                   ast_copy_string(cfg_paths.system_name, "localhost", sizeof(cfg_paths.system_name));
03012                }
03013                ast_log(LOG_ERROR, "Cannot obtain hostname for this system.  Using '%s' instead.\n", ast_config_AST_SYSTEM_NAME);
03014             }
03015          }
03016       } else if (!strcasecmp(v->name, "languageprefix")) {
03017          ast_language_is_prefix = ast_true(v->value);
03018       } else if (!strcasecmp(v->name, "lockmode")) {
03019          if (!strcasecmp(v->value, "lockfile")) {
03020             ast_set_lock_type(AST_LOCK_TYPE_LOCKFILE);
03021          } else if (!strcasecmp(v->value, "flock")) {
03022             ast_set_lock_type(AST_LOCK_TYPE_FLOCK);
03023          } else {
03024             ast_log(LOG_WARNING, "'%s' is not a valid setting for the lockmode option, "
03025                "defaulting to 'lockfile'\n", v->value);
03026             ast_set_lock_type(AST_LOCK_TYPE_LOCKFILE);
03027          }
03028 #if defined(HAVE_SYSINFO)
03029       } else if (!strcasecmp(v->name, "minmemfree")) {
03030          /* specify the minimum amount of free memory to retain.  Asterisk should stop accepting new calls
03031           * if the amount of free memory falls below this watermark */
03032          if ((sscanf(v->value, "%30ld", &option_minmemfree) != 1) || (option_minmemfree < 0)) {
03033             option_minmemfree = 0;
03034          }
03035 #endif
03036       } else if (!strcasecmp(v->name, "entityid")) {
03037          struct ast_eid tmp_eid;
03038          if (!ast_str_to_eid(&tmp_eid, v->value)) {
03039             ast_verbose("Successfully set global EID to '%s'\n", v->value);
03040             ast_eid_default = tmp_eid;
03041          } else
03042             ast_verbose("Invalid Entity ID '%s' provided\n", v->value);
03043       } else if (!strcasecmp(v->name, "lightbackground")) {
03044          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_LIGHT_BACKGROUND);
03045       } else if (!strcasecmp(v->name, "forceblackbackground")) {
03046          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_FORCE_BLACK_BACKGROUND);
03047       } else if (!strcasecmp(v->name, "hideconnect")) {
03048          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_HIDE_CONSOLE_CONNECT);
03049       } else if (!strcasecmp(v->name, "lockconfdir")) {
03050          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_LOCK_CONFIG_DIR);
03051       }
03052    }
03053    for (v = ast_variable_browse(cfg, "compat"); v; v = v->next) {
03054       float version;
03055       if (sscanf(v->value, "%30f", &version) != 1) {
03056          ast_log(LOG_WARNING, "Compatibility version for option '%s' is not a number: '%s'\n", v->name, v->value);
03057          continue;
03058       }
03059       if (!strcasecmp(v->name, "app_set")) {
03060          ast_set2_flag(&ast_compat, version < 1.5 ? 1 : 0, AST_COMPAT_APP_SET);
03061       } else if (!strcasecmp(v->name, "res_agi")) {
03062          ast_set2_flag(&ast_compat, version < 1.5 ? 1 : 0, AST_COMPAT_DELIM_RES_AGI);
03063       } else if (!strcasecmp(v->name, "pbx_realtime")) {
03064          ast_set2_flag(&ast_compat, version < 1.5 ? 1 : 0, AST_COMPAT_DELIM_PBX_REALTIME);
03065       }
03066    }
03067    ast_config_destroy(cfg);
03068 }
03069 
03070 static void *monitor_sig_flags(void *unused)
03071 {
03072    for (;;) {
03073       struct pollfd p = { sig_alert_pipe[0], POLLIN, 0 };
03074       int a;
03075       ast_poll(&p, 1, -1);
03076       if (sig_flags.need_reload) {
03077          sig_flags.need_reload = 0;
03078          ast_module_reload(NULL);
03079       }
03080       if (sig_flags.need_quit) {
03081          sig_flags.need_quit = 0;
03082          if (consolethread != AST_PTHREADT_NULL) {
03083             sig_flags.need_quit_handler = 1;
03084             pthread_kill(consolethread, SIGURG);
03085          } else {
03086             quit_handler(0, 0, 1, 0);
03087          }
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 | AST_OPT_FLAG_NO_COLOR);
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          close(fd);
03401          break;
03402       }
03403 
03404       FD_ZERO(&readers);
03405       FD_SET(fd2, &readers);
03406       if (ast_select(fd2 + 1, &readers, NULL, NULL, &tv) < 0) {
03407          ast_log(LOG_WARNING, "Maximum select()able file descriptor is %d\n", FD_SETSIZE);
03408       }
03409       ast_FD_SETSIZE = l.rlim_cur > ast_FDMAX ? ast_FDMAX : l.rlim_cur;
03410       close(fd);
03411       close(fd2);
03412    } while (0);
03413 #elif defined(HAVE_VARIABLE_FDSET)
03414    ast_FD_SETSIZE = l.rlim_cur > ast_FDMAX ? ast_FDMAX : l.rlim_cur;
03415 #endif /* !defined(CONFIGURE_RAN_AS_ROOT) */
03416 
03417    if ((!rungroup) && !ast_strlen_zero(ast_config_AST_RUN_GROUP))
03418       rungroup = ast_config_AST_RUN_GROUP;
03419    if ((!runuser) && !ast_strlen_zero(ast_config_AST_RUN_USER))
03420       runuser = ast_config_AST_RUN_USER;
03421 
03422    /* Must install this signal handler up here to ensure that if the canary
03423     * fails to execute that it doesn't kill the Asterisk process.
03424     */
03425    sigaction(SIGCHLD, &child_handler, NULL);
03426 
03427    /* It's common on some platforms to clear /var/run at boot.  Create the
03428     * socket file directory before we drop privileges. */
03429    if (mkdir(ast_config_AST_RUN_DIR, 0755)) {
03430       if (errno == EEXIST) {
03431          rundir_exists = 1;
03432       } else {
03433          ast_log(LOG_WARNING, "Unable to create socket file directory.  Remote consoles will not be able to connect! (%s)\n", strerror(x));
03434       }
03435    }
03436 
03437 #ifndef __CYGWIN__
03438 
03439    if (isroot) {
03440       ast_set_priority(ast_opt_high_priority);
03441    }
03442 
03443    if (isroot && rungroup) {
03444       struct group *gr;
03445       gr = getgrnam(rungroup);
03446       if (!gr) {
03447          ast_log(LOG_WARNING, "No such group '%s'!\n", rungroup);
03448          exit(1);
03449       }
03450       if (!rundir_exists && chown(ast_config_AST_RUN_DIR, -1, gr->gr_gid)) {
03451          ast_log(LOG_WARNING, "Unable to chgrp run directory to %d (%s)\n", (int) gr->gr_gid, rungroup);
03452       }
03453       if (setgid(gr->gr_gid)) {
03454          ast_log(LOG_WARNING, "Unable to setgid to %d (%s)\n", (int)gr->gr_gid, rungroup);
03455          exit(1);
03456       }
03457       if (setgroups(0, NULL)) {
03458          ast_log(LOG_WARNING, "Unable to drop unneeded groups\n");
03459          exit(1);
03460       }
03461       if (option_verbose)
03462          ast_verbose("Running as group '%s'\n", rungroup);
03463    }
03464 
03465    if (runuser && !ast_test_flag(&ast_options, AST_OPT_FLAG_REMOTE)) {
03466 #ifdef HAVE_CAP
03467       int has_cap = 1;
03468 #endif /* HAVE_CAP */
03469       struct passwd *pw;
03470       pw = getpwnam(runuser);
03471       if (!pw) {
03472          ast_log(LOG_WARNING, "No such user '%s'!\n", runuser);
03473          exit(1);
03474       }
03475       if (chown(ast_config_AST_RUN_DIR, pw->pw_uid, -1)) {
03476          ast_log(LOG_WARNING, "Unable to chown run directory to %d (%s)\n", (int) pw->pw_uid, runuser);
03477       }
03478 #ifdef HAVE_CAP
03479       if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0)) {
03480          ast_log(LOG_WARNING, "Unable to keep capabilities.\n");
03481          has_cap = 0;
03482       }
03483 #endif /* HAVE_CAP */
03484       if (!isroot && pw->pw_uid != geteuid()) {
03485          ast_log(LOG_ERROR, "Asterisk started as nonroot, but runuser '%s' requested.\n", runuser);
03486          exit(1);
03487       }
03488       if (!rungroup) {
03489          if (setgid(pw->pw_gid)) {
03490             ast_log(LOG_WARNING, "Unable to setgid to %d!\n", (int)pw->pw_gid);
03491             exit(1);
03492          }
03493          if (isroot && initgroups(pw->pw_name, pw->pw_gid)) {
03494             ast_log(LOG_WARNING, "Unable to init groups for '%s'\n", runuser);
03495             exit(1);
03496          }
03497       }
03498       if (setuid(pw->pw_uid)) {
03499          ast_log(LOG_WARNING, "Unable to setuid to %d (%s)\n", (int)pw->pw_uid, runuser);
03500          exit(1);
03501       }
03502       if (option_verbose)
03503          ast_verbose("Running as user '%s'\n", runuser);
03504 #ifdef HAVE_CAP
03505       if (has_cap) {
03506          cap_t cap;
03507 
03508          cap = cap_from_text("cap_net_admin=eip");
03509 
03510          if (cap_set_proc(cap))
03511             ast_log(LOG_WARNING, "Unable to install capabilities.\n");
03512 
03513          if (cap_free(cap))
03514             ast_log(LOG_WARNING, "Unable to drop capabilities.\n");
03515       }
03516 #endif /* HAVE_CAP */
03517    }
03518 
03519 #endif /* __CYGWIN__ */
03520 
03521 #ifdef linux
03522    if (geteuid() && ast_opt_dump_core) {
03523       if (prctl(PR_SET_DUMPABLE, 1, 0, 0, 0) < 0) {
03524          ast_log(LOG_WARNING, "Unable to set the process for core dumps after changing to a non-root user. %s\n", strerror(errno));
03525       }
03526    }
03527 #endif
03528 
03529    {
03530 #if defined(HAVE_EACCESS) || defined(HAVE_EUIDACCESS)
03531 #if defined(HAVE_EUIDACCESS) && !defined(HAVE_EACCESS)
03532 #define eaccess euidaccess
03533 #endif
03534       char dir[PATH_MAX];
03535       if (!getcwd(dir, sizeof(dir)) || eaccess(dir, R_OK | X_OK | F_OK)) {
03536          ast_log(LOG_ERROR, "Unable to access the running directory (%s).  Changing to '/' for compatibility.\n", strerror(errno));
03537          /* If we cannot access the CWD, then we couldn't dump core anyway,
03538           * so chdir("/") won't break anything. */
03539          if (chdir("/")) {
03540             /* chdir(/) should never fail, so this ends up being a no-op */
03541             ast_log(LOG_ERROR, "chdir(\"/\") failed?!! %s\n", strerror(errno));
03542          }
03543       } else
03544 #endif /* defined(HAVE_EACCESS) || defined(HAVE_EUIDACCESS) */
03545       if (!ast_opt_no_fork && !ast_opt_dump_core) {
03546          /* Backgrounding, but no cores, so chdir won't break anything. */
03547          if (chdir("/")) {
03548             ast_log(LOG_ERROR, "Unable to chdir(\"/\") ?!! %s\n", strerror(errno));
03549          }
03550       }
03551    }
03552 
03553    ast_term_init();
03554    printf("%s", term_end());
03555    fflush(stdout);
03556 
03557    if (ast_opt_console && !option_verbose) 
03558       ast_verbose("[ Initializing Custom Configuration Options ]\n");
03559    /* custom config setup */
03560    register_config_cli();
03561    read_config_maps();
03562    
03563    if (ast_opt_console) {
03564       if (el_hist == NULL || el == NULL)
03565          ast_el_initialize();
03566 
03567       if (!ast_strlen_zero(filename))
03568          ast_el_read_history(filename);
03569    }
03570 
03571    if (ast_tryconnect()) {
03572       /* One is already running */
03573       if (ast_opt_remote) {
03574          if (ast_opt_exec) {
03575             ast_remotecontrol(xarg);
03576             quit_handler(0, 0, 0, 0);
03577             exit(0);
03578          }
03579          printf("%s", term_quit());
03580          ast_remotecontrol(NULL);
03581          quit_handler(0, 0, 0, 0);
03582          exit(0);
03583       } else {
03584          ast_log(LOG_ERROR, "Asterisk already running on %s.  Use 'asterisk -r' to connect.\n", ast_config_AST_SOCKET);
03585          printf("%s", term_quit());
03586          exit(1);
03587       }
03588    } else if (ast_opt_remote || ast_opt_exec) {
03589       ast_log(LOG_ERROR, "Unable to connect to remote asterisk (does %s exist?)\n", ast_config_AST_SOCKET);
03590       printf("%s", term_quit());
03591       exit(1);
03592    }
03593    /* Blindly write pid file since we couldn't connect */
03594    unlink(ast_config_AST_PID);
03595    f = fopen(ast_config_AST_PID, "w");
03596    if (f) {
03597       fprintf(f, "%ld\n", (long)getpid());
03598       fclose(f);
03599    } else
03600       ast_log(LOG_WARNING, "Unable to open pid file '%s': %s\n", ast_config_AST_PID, strerror(errno));
03601 
03602 #if HAVE_WORKING_FORK
03603    if (ast_opt_always_fork || !ast_opt_no_fork) {
03604 #ifndef HAVE_SBIN_LAUNCHD
03605       if (daemon(1, 0) < 0) {
03606          ast_log(LOG_ERROR, "daemon() failed: %s\n", strerror(errno));
03607       }
03608       ast_mainpid = getpid();
03609       /* Blindly re-write pid file since we are forking */
03610       unlink(ast_config_AST_PID);
03611       f = fopen(ast_config_AST_PID, "w");
03612       if (f) {
03613          fprintf(f, "%ld\n", (long)ast_mainpid);
03614          fclose(f);
03615       } else
03616          ast_log(LOG_WARNING, "Unable to open pid file '%s': %s\n", ast_config_AST_PID, strerror(errno));
03617 #else
03618       ast_log(LOG_WARNING, "Mac OS X detected.  Use 'launchctl load /Library/LaunchDaemon/org.asterisk.asterisk.plist'.\n");
03619 #endif
03620    }
03621 #endif
03622 
03623    /* Spawning of astcanary must happen AFTER the call to daemon(3) */
03624    if (isroot && ast_opt_high_priority) {
03625       snprintf(canary_filename, sizeof(canary_filename), "%s/alt.asterisk.canary.tweet.tweet.tweet", ast_config_AST_RUN_DIR);
03626 
03627       /* Don't let the canary child kill Asterisk, if it dies immediately */
03628       sigaction(SIGPIPE, &ignore_sig_handler, NULL);
03629 
03630       canary_pid = fork();
03631       if (canary_pid == 0) {
03632          char canary_binary[128], *lastslash, ppid[12];
03633 
03634          /* Reset signal handler */
03635          signal(SIGCHLD, SIG_DFL);
03636          signal(SIGPIPE, SIG_DFL);
03637 
03638          ast_close_fds_above_n(0);
03639          ast_set_priority(0);
03640          snprintf(ppid, sizeof(ppid), "%d", (int) ast_mainpid);
03641 
03642          execlp("astcanary", "astcanary", canary_filename, ppid, (char *)NULL);
03643 
03644          /* If not found, try the same path as used to execute asterisk */
03645          ast_copy_string(canary_binary, argv[0], sizeof(canary_binary));
03646          if ((lastslash = strrchr(canary_binary, '/'))) {
03647             ast_copy_string(lastslash + 1, "astcanary", sizeof(canary_binary) + canary_binary - (lastslash + 1));
03648             execl(canary_binary, "astcanary", canary_filename, ppid, (char *)NULL);
03649          }
03650 
03651          /* Should never happen */
03652          _exit(1);
03653       } else if (canary_pid > 0) {
03654          pthread_t dont_care;
03655          ast_pthread_create_detached(&dont_care, NULL, canary_thread, NULL);
03656       }
03657 
03658       /* Kill the canary when we exit */
03659       ast_register_atexit(canary_exit);
03660    }
03661 
03662    if (ast_event_init()) {
03663       printf("%s", term_quit());
03664       exit(1);
03665    }
03666 
03667 #ifdef TEST_FRAMEWORK
03668    if (ast_test_init()) {
03669       printf("%s", term_quit());
03670       exit(1);
03671    }
03672 #endif
03673 
03674    ast_aoc_cli_init();
03675 
03676    ast_makesocket();
03677    sigemptyset(&sigs);
03678    sigaddset(&sigs, SIGHUP);
03679    sigaddset(&sigs, SIGTERM);
03680    sigaddset(&sigs, SIGINT);
03681    sigaddset(&sigs, SIGPIPE);
03682    sigaddset(&sigs, SIGWINCH);
03683    pthread_sigmask(SIG_BLOCK, &sigs, NULL);
03684    sigaction(SIGURG, &urg_handler, NULL);
03685    signal(SIGINT, __quit_handler);
03686    signal(SIGTERM, __quit_handler);
03687    sigaction(SIGHUP, &hup_handler, NULL);
03688    sigaction(SIGPIPE, &ignore_sig_handler, NULL);
03689 
03690    /* ensure that the random number generators are seeded with a different value every time
03691       Asterisk is started
03692    */
03693    srand((unsigned int) getpid() + (unsigned int) time(NULL));
03694    initstate((unsigned int) getpid() * 65536 + (unsigned int) time(NULL), randompool, sizeof(randompool));
03695 
03696    if (init_logger()) {    /* Start logging subsystem */
03697       printf("%s", term_quit());
03698       exit(1);
03699    }
03700 
03701    threadstorage_init();
03702 
03703    astobj2_init();
03704 
03705    ast_autoservice_init();
03706 
03707    if (ast_timing_init()) {
03708       printf("%s", term_quit());
03709       exit(1);
03710    }
03711 
03712    if (ast_ssl_init()) {
03713       printf("%s", term_quit());
03714       exit(1);
03715    }
03716 
03717 #ifdef AST_XML_DOCS
03718    /* Load XML documentation. */
03719    ast_xmldoc_load_documentation();
03720 #endif
03721 
03722    /* initialize the data retrieval API */
03723    if (ast_data_init()) {
03724       printf ("%s", term_quit());
03725       exit(1);
03726    }
03727 
03728    ast_channels_init();
03729 
03730    if ((moduleresult = load_modules(1))) {      /* Load modules, pre-load only */
03731       printf("%s", term_quit());
03732       exit(moduleresult == -2 ? 2 : 1);
03733    }
03734 
03735    if (dnsmgr_init()) {    /* Initialize the DNS manager */
03736       printf("%s", term_quit());
03737       exit(1);
03738    }
03739 
03740    ast_http_init();     /* Start the HTTP server, if needed */
03741 
03742    if (init_manager()) {
03743       printf("%s", term_quit());
03744       exit(1);
03745    }
03746 
03747    if (ast_cdr_engine_init()) {
03748       printf("%s", term_quit());
03749       exit(1);
03750    }
03751 
03752    if (ast_cel_engine_init()) {
03753       printf("%s", term_quit());
03754       exit(1);
03755    }
03756 
03757    if (ast_device_state_engine_init()) {
03758       printf("%s", term_quit());
03759       exit(1);
03760    }
03761 
03762    ast_dsp_init();
03763    ast_udptl_init();
03764 
03765    if (ast_image_init()) {
03766       printf("%s", term_quit());
03767       exit(1);
03768    }
03769 
03770    if (ast_file_init()) {
03771       printf("%s", term_quit());
03772       exit(1);
03773    }
03774 
03775    if (load_pbx()) {
03776       printf("%s", term_quit());
03777       exit(1);
03778    }
03779 
03780    if (ast_indications_init()) {
03781       printf("%s", term_quit());
03782       exit(1);
03783    }
03784 
03785    if (ast_features_init()) {
03786       printf("%s", term_quit());
03787       exit(1);
03788    }
03789 
03790    if (init_framer()) {
03791       printf("%s", term_quit());
03792       exit(1);
03793    }
03794 
03795    if (astdb_init()) {
03796       printf("%s", term_quit());
03797       exit(1);
03798    }
03799 
03800    if (ast_enum_init()) {
03801       printf("%s", term_quit());
03802       exit(1);
03803    }
03804 
03805    if (ast_cc_init()) {
03806       printf("%s", term_quit());
03807       exit(1);
03808    }
03809 
03810    if ((moduleresult = load_modules(0))) {      /* Load modules */
03811       printf("%s", term_quit());
03812       exit(moduleresult == -2 ? 2 : 1);
03813    }
03814 
03815    /* loads the cli_permissoins.conf file needed to implement cli restrictions. */
03816    ast_cli_perms_init(0);
03817 
03818    ast_stun_init();
03819 
03820    dnsmgr_start_refresh();
03821 
03822    /* We might have the option of showing a console, but for now just
03823       do nothing... */
03824    if (ast_opt_console && !option_verbose)
03825       ast_verbose(" ]\n");
03826    if (option_verbose || ast_opt_console)
03827       ast_verbose("%s", term_color(tmp, "Asterisk Ready.\n", COLOR_BRWHITE, COLOR_BLACK, sizeof(tmp)));
03828    if (ast_opt_no_fork)
03829       consolethread = pthread_self();
03830 
03831    if (pipe(sig_alert_pipe))
03832       sig_alert_pipe[0] = sig_alert_pipe[1] = -1;
03833 
03834    ast_set_flag(&ast_options, AST_OPT_FLAG_FULLY_BOOTED);
03835    manager_event(EVENT_FLAG_SYSTEM, "FullyBooted", "Status: Fully Booted\r\n");
03836 
03837    ast_process_pending_reloads();
03838 
03839    pthread_sigmask(SIG_UNBLOCK, &sigs, NULL);
03840 
03841 #ifdef __AST_DEBUG_MALLOC
03842    __ast_mm_init();
03843 #endif   
03844 
03845    ast_lastreloadtime = ast_startuptime = ast_tvnow();
03846    ast_cli_register_multiple(cli_asterisk, ARRAY_LEN(cli_asterisk));
03847 
03848    run_startup_commands();
03849 
03850    if (ast_opt_console) {
03851       /* Console stuff now... */
03852       /* Register our quit function */
03853       char title[256];
03854 
03855       ast_pthread_create_detached(&mon_sig_flags, NULL, monitor_sig_flags, NULL);
03856 
03857       set_icon("Asterisk");
03858       snprintf(title, sizeof(title), "Asterisk Console on '%s' (pid %ld)", hostname, (long)ast_mainpid);
03859       set_title(title);
03860 
03861       el_set(el, EL_GETCFN, ast_el_read_char);
03862 
03863       for (;;) {
03864          if (sig_flags.need_quit || sig_flags.need_quit_handler) {
03865             quit_handler(0, 0, 0, 0);
03866             break;
03867          }
03868          buf = (char *) el_gets(el, &num);
03869 
03870          if (!buf && write(1, "", 1) < 0)
03871             goto lostterm;
03872 
03873          if (buf) {
03874             if (buf[strlen(buf)-1] == '\n')
03875                buf[strlen(buf)-1] = '\0';
03876 
03877             consolehandler((char *)buf);
03878          } else if (ast_opt_remote && (write(STDOUT_FILENO, "\nUse EXIT or QUIT to exit the asterisk console\n",
03879                strlen("\nUse EXIT or QUIT to exit the asterisk console\n")) < 0)) {
03880             /* Whoa, stdout disappeared from under us... Make /dev/null's */
03881             int fd;
03882             fd = open("/dev/null", O_RDWR);
03883             if (fd > -1) {
03884                dup2(fd, STDOUT_FILENO);
03885                dup2(fd, STDIN_FILENO);
03886             } else
03887                ast_log(LOG_WARNING, "Failed to open /dev/null to recover from dead console. Bad things will happen!\n");
03888             break;
03889          }
03890       }
03891    }
03892 
03893    monitor_sig_flags(NULL);
03894 
03895 lostterm:
03896    return 0;
03897 }