Mon Mar 12 2012 21:19:10

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: 335716 $")
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    char buf[MAX_HISTORY_COMMAND_LENGTH];
02638    FILE *f;
02639    int ret = -1;
02640 
02641    if (el_hist == NULL || el == NULL)
02642       ast_el_initialize();
02643 
02644    if ((f = fopen(filename, "r")) == NULL)
02645       return ret;
02646 
02647    while (!feof(f)) {
02648       if (!fgets(buf, sizeof(buf), f))
02649          break;
02650       if (!strcmp(buf, "_HiStOrY_V2_\n"))
02651          continue;
02652       if (ast_all_zeros(buf))
02653          continue;
02654       if ((ret = ast_el_add_history(buf)) == -1)
02655          break;
02656    }
02657    fclose(f);
02658 
02659    return ret;
02660 }
02661 
02662 static void ast_remotecontrol(char *data)
02663 {
02664    char buf[80];
02665    int res;
02666    char filename[80] = "";
02667    char *hostname;
02668    char *cpid;
02669    char *version;
02670    int pid;
02671    char *stringp = NULL;
02672 
02673    char *ebuf;
02674    int num = 0;
02675 
02676    memset(&sig_flags, 0, sizeof(sig_flags));
02677    signal(SIGINT, __remote_quit_handler);
02678    signal(SIGTERM, __remote_quit_handler);
02679    signal(SIGHUP, __remote_quit_handler);
02680 
02681    if (read(ast_consock, buf, sizeof(buf)) < 0) {
02682       ast_log(LOG_ERROR, "read() failed: %s\n", strerror(errno));
02683       return;
02684    }
02685    if (data) {
02686       char prefix[] = "cli quit after ";
02687       char *tmp = alloca(strlen(data) + strlen(prefix) + 1);
02688       sprintf(tmp, "%s%s", prefix, data);
02689       if (write(ast_consock, tmp, strlen(tmp) + 1) < 0) {
02690          ast_log(LOG_ERROR, "write() failed: %s\n", strerror(errno));
02691          if (sig_flags.need_quit || sig_flags.need_quit_handler) {
02692             return;
02693          }
02694       }
02695    }
02696    stringp = buf;
02697    hostname = strsep(&stringp, "/");
02698    cpid = strsep(&stringp, "/");
02699    version = strsep(&stringp, "\n");
02700    if (!version)
02701       version = "<Version Unknown>";
02702    stringp = hostname;
02703    strsep(&stringp, ".");
02704    if (cpid)
02705       pid = atoi(cpid);
02706    else
02707       pid = -1;
02708    if (!data) {
02709       char tmp[80];
02710       snprintf(tmp, sizeof(tmp), "core set verbose atleast %d", option_verbose);
02711       fdsend(ast_consock, tmp);
02712       snprintf(tmp, sizeof(tmp), "core set debug atleast %d", option_debug);
02713       fdsend(ast_consock, tmp);
02714       if (!ast_opt_mute)
02715          fdsend(ast_consock, "logger mute silent");
02716       else 
02717          printf("log and verbose output currently muted ('logger mute' to unmute)\n");
02718    }
02719 
02720    if (ast_opt_exec && data) {  /* hack to print output then exit if asterisk -rx is used */
02721       struct pollfd fds;
02722       fds.fd = ast_consock;
02723       fds.events = POLLIN;
02724       fds.revents = 0;
02725       while (ast_poll(&fds, 1, 60000) > 0) {
02726          char buffer[512] = "", *curline = buffer, *nextline;
02727          int not_written = 1;
02728 
02729          if (sig_flags.need_quit || sig_flags.need_quit_handler) {
02730             break;
02731          }
02732 
02733          if (read(ast_consock, buffer, sizeof(buffer) - 1) <= 0) {
02734             break;
02735          }
02736 
02737          do {
02738             if ((nextline = strchr(curline, '\n'))) {
02739                nextline++;
02740             } else {
02741                nextline = strchr(curline, '\0');
02742             }
02743 
02744             /* Skip verbose lines */
02745             if (*curline != 127) {
02746                not_written = 0;
02747                if (write(STDOUT_FILENO, curline, nextline - curline) < 0) {
02748                   ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno));
02749                }
02750             }
02751             curline = nextline;
02752          } while (!ast_strlen_zero(curline));
02753 
02754          /* No non-verbose output in 60 seconds. */
02755          if (not_written) {
02756             break;
02757          }
02758       }
02759       return;
02760    }
02761 
02762    ast_verbose("Connected to Asterisk %s currently running on %s (pid = %d)\n", version, hostname, pid);
02763    remotehostname = hostname;
02764    if (getenv("HOME")) 
02765       snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
02766    if (el_hist == NULL || el == NULL)
02767       ast_el_initialize();
02768 
02769    el_set(el, EL_GETCFN, ast_el_read_char);
02770 
02771    if (!ast_strlen_zero(filename))
02772       ast_el_read_history(filename);
02773 
02774    for (;;) {
02775       ebuf = (char *)el_gets(el, &num);
02776 
02777       if (sig_flags.need_quit || sig_flags.need_quit_handler) {
02778          break;
02779       }
02780 
02781       if (!ebuf && write(1, "", 1) < 0)
02782          break;
02783 
02784       if (!ast_strlen_zero(ebuf)) {
02785          if (ebuf[strlen(ebuf)-1] == '\n')
02786             ebuf[strlen(ebuf)-1] = '\0';
02787          if (!remoteconsolehandler(ebuf)) {
02788             /* Strip preamble from output */
02789             char *temp;
02790             for (temp = ebuf; *temp; temp++) {
02791                if (*temp == 127) {
02792                   memmove(temp, temp + 1, strlen(temp));
02793                   temp--;
02794                }
02795             }
02796             res = write(ast_consock, ebuf, strlen(ebuf) + 1);
02797             if (res < 1) {
02798                ast_log(LOG_WARNING, "Unable to write: %s\n", strerror(errno));
02799                break;
02800             }
02801          }
02802       }
02803    }
02804    printf("\nDisconnected from Asterisk server\n");
02805 }
02806 
02807 static int show_version(void)
02808 {
02809    printf("Asterisk %s\n", ast_get_version());
02810    return 0;
02811 }
02812 
02813 static int show_cli_help(void) {
02814    printf("Asterisk %s, Copyright (C) 1999 - 2010, Digium, Inc. and others.\n", ast_get_version());
02815    printf("Usage: asterisk [OPTIONS]\n");
02816    printf("Valid Options:\n");
02817    printf("   -V              Display version number and exit\n");
02818    printf("   -C <configfile> Use an alternate configuration file\n");
02819    printf("   -G <group>      Run as a group other than the caller\n");
02820    printf("   -U <user>       Run as a user other than the caller\n");
02821    printf("   -c              Provide console CLI\n");
02822    printf("   -d              Enable extra debugging\n");
02823 #if HAVE_WORKING_FORK
02824    printf("   -f              Do not fork\n");
02825    printf("   -F              Always fork\n");
02826 #endif
02827    printf("   -g              Dump core in case of a crash\n");
02828    printf("   -h              This help screen\n");
02829    printf("   -i              Initialize crypto keys at startup\n");
02830    printf("   -I              Enable internal timing if DAHDI timer is available\n");
02831    printf("   -L <load>       Limit the maximum load average before rejecting new calls\n");
02832    printf("   -M <value>      Limit the maximum number of calls to the specified value\n");
02833    printf("   -m              Mute debugging and console output on the console\n");
02834    printf("   -n              Disable console colorization\n");
02835    printf("   -p              Run as pseudo-realtime thread\n");
02836    printf("   -q              Quiet mode (suppress output)\n");
02837    printf("   -r              Connect to Asterisk on this machine\n");
02838    printf("   -R              Same as -r, except attempt to reconnect if disconnected\n");
02839    printf("   -s <socket>     Connect to Asterisk via socket <socket> (only valid with -r)\n");
02840    printf("   -t              Record soundfiles in /var/tmp and move them where they\n");
02841    printf("                   belong after they are done\n");
02842    printf("   -T              Display the time in [Mmm dd hh:mm:ss] format for each line\n");
02843    printf("                   of output to the CLI\n");
02844    printf("   -v              Increase verbosity (multiple v's = more verbose)\n");
02845    printf("   -x <cmd>        Execute command <cmd> (only valid with -r)\n");
02846    printf("   -X              Execute includes by default (allows #exec in asterisk.conf)\n");
02847    printf("   -W              Adjust terminal colors to compensate for a light background\n");
02848    printf("\n");
02849    return 0;
02850 }
02851 
02852 static void ast_readconfig(void) 
02853 {
02854    struct ast_config *cfg;
02855    struct ast_variable *v;
02856    char *config = DEFAULT_CONFIG_FILE;
02857    char hostname[MAXHOSTNAMELEN] = "";
02858    struct ast_flags config_flags = { CONFIG_FLAG_NOREALTIME };
02859    struct {
02860       unsigned int dbdir:1;
02861       unsigned int keydir:1;
02862    } found = { 0, 0 };
02863 
02864    if (ast_opt_override_config) {
02865       cfg = ast_config_load2(ast_config_AST_CONFIG_FILE, "" /* core, can't reload */, config_flags);
02866       if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID)
02867          ast_log(LOG_WARNING, "Unable to open specified master config file '%s', using built-in defaults\n", ast_config_AST_CONFIG_FILE);
02868    } else 
02869       cfg = ast_config_load2(config, "" /* core, can't reload */, config_flags);
02870 
02871    /* init with buildtime config */
02872    ast_copy_string(cfg_paths.config_dir, DEFAULT_CONFIG_DIR, sizeof(cfg_paths.config_dir));
02873    ast_copy_string(cfg_paths.spool_dir, DEFAULT_SPOOL_DIR, sizeof(cfg_paths.spool_dir));
02874    ast_copy_string(cfg_paths.module_dir, DEFAULT_MODULE_DIR, sizeof(cfg_paths.module_dir));
02875    snprintf(cfg_paths.monitor_dir, sizeof(cfg_paths.monitor_dir), "%s/monitor", cfg_paths.spool_dir);
02876    ast_copy_string(cfg_paths.var_dir, DEFAULT_VAR_DIR, sizeof(cfg_paths.var_dir));
02877    ast_copy_string(cfg_paths.data_dir, DEFAULT_DATA_DIR, sizeof(cfg_paths.data_dir));
02878    ast_copy_string(cfg_paths.log_dir, DEFAULT_LOG_DIR, sizeof(cfg_paths.log_dir));
02879    ast_copy_string(cfg_paths.agi_dir, DEFAULT_AGI_DIR, sizeof(cfg_paths.agi_dir));
02880    ast_copy_string(cfg_paths.db_path, DEFAULT_DB, sizeof(cfg_paths.db_path));
02881    ast_copy_string(cfg_paths.key_dir, DEFAULT_KEY_DIR, sizeof(cfg_paths.key_dir));
02882    ast_copy_string(cfg_paths.pid_path, DEFAULT_PID, sizeof(cfg_paths.pid_path));
02883    ast_copy_string(cfg_paths.socket_path, DEFAULT_SOCKET, sizeof(cfg_paths.socket_path));
02884    ast_copy_string(cfg_paths.run_dir, DEFAULT_RUN_DIR, sizeof(cfg_paths.run_dir));
02885 
02886    ast_set_default_eid(&ast_eid_default);
02887 
02888    /* no asterisk.conf? no problem, use buildtime config! */
02889    if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) {
02890       return;
02891    }
02892 
02893    for (v = ast_variable_browse(cfg, "files"); v; v = v->next) {
02894       if (!strcasecmp(v->name, "astctlpermissions"))
02895          ast_copy_string(ast_config_AST_CTL_PERMISSIONS, v->value, sizeof(ast_config_AST_CTL_PERMISSIONS));
02896       else if (!strcasecmp(v->name, "astctlowner"))
02897          ast_copy_string(ast_config_AST_CTL_OWNER, v->value, sizeof(ast_config_AST_CTL_OWNER));
02898       else if (!strcasecmp(v->name, "astctlgroup"))
02899          ast_copy_string(ast_config_AST_CTL_GROUP, v->value, sizeof(ast_config_AST_CTL_GROUP));
02900       else if (!strcasecmp(v->name, "astctl"))
02901          ast_copy_string(ast_config_AST_CTL, v->value, sizeof(ast_config_AST_CTL));
02902    }
02903 
02904    for (v = ast_variable_browse(cfg, "directories"); v; v = v->next) {
02905       if (!strcasecmp(v->name, "astetcdir")) {
02906          ast_copy_string(cfg_paths.config_dir, v->value, sizeof(cfg_paths.config_dir));
02907       } else if (!strcasecmp(v->name, "astspooldir")) {
02908          ast_copy_string(cfg_paths.spool_dir, v->value, sizeof(cfg_paths.spool_dir));
02909          snprintf(cfg_paths.monitor_dir, sizeof(cfg_paths.monitor_dir), "%s/monitor", v->value);
02910       } else if (!strcasecmp(v->name, "astvarlibdir")) {
02911          ast_copy_string(cfg_paths.var_dir, v->value, sizeof(cfg_paths.var_dir));
02912          if (!found.dbdir)
02913             snprintf(cfg_paths.db_path, sizeof(cfg_paths.db_path), "%s/astdb", v->value);
02914       } else if (!strcasecmp(v->name, "astdbdir")) {
02915          snprintf(cfg_paths.db_path, sizeof(cfg_paths.db_path), "%s/astdb", v->value);
02916          found.dbdir = 1;
02917       } else if (!strcasecmp(v->name, "astdatadir")) {
02918          ast_copy_string(cfg_paths.data_dir, v->value, sizeof(cfg_paths.data_dir));
02919          if (!found.keydir)
02920             snprintf(cfg_paths.key_dir, sizeof(cfg_paths.key_dir), "%s/keys", v->value);
02921       } else if (!strcasecmp(v->name, "astkeydir")) {
02922          snprintf(cfg_paths.key_dir, sizeof(cfg_paths.key_dir), "%s/keys", v->value);
02923          found.keydir = 1;
02924       } else if (!strcasecmp(v->name, "astlogdir")) {
02925          ast_copy_string(cfg_paths.log_dir, v->value, sizeof(cfg_paths.log_dir));
02926       } else if (!strcasecmp(v->name, "astagidir")) {
02927          ast_copy_string(cfg_paths.agi_dir, v->value, sizeof(cfg_paths.agi_dir));
02928       } else if (!strcasecmp(v->name, "astrundir")) {
02929          snprintf(cfg_paths.pid_path, sizeof(cfg_paths.pid_path), "%s/%s", v->value, "asterisk.pid");
02930          snprintf(cfg_paths.socket_path, sizeof(cfg_paths.socket_path), "%s/%s", v->value, ast_config_AST_CTL);
02931          ast_copy_string(cfg_paths.run_dir, v->value, sizeof(cfg_paths.run_dir));
02932       } else if (!strcasecmp(v->name, "astmoddir")) {
02933          ast_copy_string(cfg_paths.module_dir, v->value, sizeof(cfg_paths.module_dir));
02934       }
02935    }
02936 
02937    for (v = ast_variable_browse(cfg, "options"); v; v = v->next) {
02938       /* verbose level (-v at startup) */
02939       if (!strcasecmp(v->name, "verbose")) {
02940          option_verbose = atoi(v->value);
02941       /* whether or not to force timestamping in CLI verbose output. (-T at startup) */
02942       } else if (!strcasecmp(v->name, "timestamp")) {
02943          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TIMESTAMP);
02944       /* whether or not to support #exec in config files */
02945       } else if (!strcasecmp(v->name, "execincludes")) {
02946          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_EXEC_INCLUDES);
02947       /* debug level (-d at startup) */
02948       } else if (!strcasecmp(v->name, "debug")) {
02949          option_debug = 0;
02950          if (sscanf(v->value, "%30d", &option_debug) != 1) {
02951             option_debug = ast_true(v->value);
02952          }
02953 #if HAVE_WORKING_FORK
02954       /* Disable forking (-f at startup) */
02955       } else if (!strcasecmp(v->name, "nofork")) {
02956          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_FORK);
02957       /* Always fork, even if verbose or debug are enabled (-F at startup) */
02958       } else if (!strcasecmp(v->name, "alwaysfork")) {
02959          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_ALWAYS_FORK);
02960 #endif
02961       /* Run quietly (-q at startup ) */
02962       } else if (!strcasecmp(v->name, "quiet")) {
02963          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_QUIET);
02964       /* Run as console (-c at startup, implies nofork) */
02965       } else if (!strcasecmp(v->name, "console")) {
02966          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_CONSOLE);
02967       /* Run with high priority if the O/S permits (-p at startup) */
02968       } else if (!strcasecmp(v->name, "highpriority")) {
02969          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_HIGH_PRIORITY);
02970       /* Initialize RSA auth keys (IAX2) (-i at startup) */
02971       } else if (!strcasecmp(v->name, "initcrypto")) {
02972          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_INIT_KEYS);
02973       /* Disable ANSI colors for console (-c at startup) */
02974       } else if (!strcasecmp(v->name, "nocolor")) {
02975          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_COLOR);
02976       /* Disable some usage warnings for picky people :p */
02977       } else if (!strcasecmp(v->name, "dontwarn")) {
02978          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_DONT_WARN);
02979       /* Dump core in case of crash (-g) */
02980       } else if (!strcasecmp(v->name, "dumpcore")) {
02981          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_DUMP_CORE);
02982       /* Cache recorded sound files to another directory during recording */
02983       } else if (!strcasecmp(v->name, "cache_record_files")) {
02984          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_CACHE_RECORD_FILES);
02985       /* Specify cache directory */
02986       }  else if (!strcasecmp(v->name, "record_cache_dir")) {
02987          ast_copy_string(record_cache_dir, v->value, AST_CACHE_DIR_LEN);
02988       /* Build transcode paths via SLINEAR, instead of directly */
02989       } else if (!strcasecmp(v->name, "transcode_via_sln")) {
02990          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TRANSCODE_VIA_SLIN);
02991       /* Transmit SLINEAR silence while a channel is being recorded or DTMF is being generated on a channel */
02992       } else if (!strcasecmp(v->name, "transmit_silence_during_record") || !strcasecmp(v->name, "transmit_silence")) {
02993          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TRANSMIT_SILENCE);
02994       /* Enable internal timing */
02995       } else if (!strcasecmp(v->name, "internal_timing")) {
02996          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_INTERNAL_TIMING);
02997       } else if (!strcasecmp(v->name, "maxcalls")) {
02998          if ((sscanf(v->value, "%30d", &option_maxcalls) != 1) || (option_maxcalls < 0)) {
02999             option_maxcalls = 0;
03000          }
03001       } else if (!strcasecmp(v->name, "maxload")) {
03002          double test[1];
03003 
03004          if (getloadavg(test, 1) == -1) {
03005             ast_log(LOG_ERROR, "Cannot obtain load average on this system. 'maxload' option disabled.\n");
03006             option_maxload = 0.0;
03007          } else if ((sscanf(v->value, "%30lf", &option_maxload) != 1) || (option_maxload < 0.0)) {
03008             option_maxload = 0.0;
03009          }
03010       /* Set the maximum amount of open files */
03011       } else if (!strcasecmp(v->name, "maxfiles")) {
03012          option_maxfiles = atoi(v->value);
03013          set_ulimit(option_maxfiles);
03014       /* What user to run as */
03015       } else if (!strcasecmp(v->name, "runuser")) {
03016          ast_copy_string(cfg_paths.run_user, v->value, sizeof(cfg_paths.run_user));
03017       /* What group to run as */
03018       } else if (!strcasecmp(v->name, "rungroup")) {
03019          ast_copy_string(cfg_paths.run_group, v->value, sizeof(cfg_paths.run_group));
03020       } else if (!strcasecmp(v->name, "systemname")) {
03021          ast_copy_string(cfg_paths.system_name, v->value, sizeof(cfg_paths.system_name));
03022       } else if (!strcasecmp(v->name, "autosystemname")) {
03023          if (ast_true(v->value)) {
03024             if (!gethostname(hostname, sizeof(hostname) - 1))
03025                ast_copy_string(cfg_paths.system_name, hostname, sizeof(cfg_paths.system_name));
03026             else {
03027                if (ast_strlen_zero(ast_config_AST_SYSTEM_NAME)){
03028                   ast_copy_string(cfg_paths.system_name, "localhost", sizeof(cfg_paths.system_name));
03029                }
03030                ast_log(LOG_ERROR, "Cannot obtain hostname for this system.  Using '%s' instead.\n", ast_config_AST_SYSTEM_NAME);
03031             }
03032          }
03033       } else if (!strcasecmp(v->name, "languageprefix")) {
03034          ast_language_is_prefix = ast_true(v->value);
03035       } else if (!strcasecmp(v->name, "defaultlanguage")) {
03036          ast_copy_string(defaultlanguage, v->value, MAX_LANGUAGE);
03037       } else if (!strcasecmp(v->name, "lockmode")) {
03038          if (!strcasecmp(v->value, "lockfile")) {
03039             ast_set_lock_type(AST_LOCK_TYPE_LOCKFILE);
03040          } else if (!strcasecmp(v->value, "flock")) {
03041             ast_set_lock_type(AST_LOCK_TYPE_FLOCK);
03042          } else {
03043             ast_log(LOG_WARNING, "'%s' is not a valid setting for the lockmode option, "
03044                "defaulting to 'lockfile'\n", v->value);
03045             ast_set_lock_type(AST_LOCK_TYPE_LOCKFILE);
03046          }
03047 #if defined(HAVE_SYSINFO)
03048       } else if (!strcasecmp(v->name, "minmemfree")) {
03049          /* specify the minimum amount of free memory to retain.  Asterisk should stop accepting new calls
03050           * if the amount of free memory falls below this watermark */
03051          if ((sscanf(v->value, "%30ld", &option_minmemfree) != 1) || (option_minmemfree < 0)) {
03052             option_minmemfree = 0;
03053          }
03054 #endif
03055       } else if (!strcasecmp(v->name, "entityid")) {
03056          struct ast_eid tmp_eid;
03057          if (!ast_str_to_eid(&tmp_eid, v->value)) {
03058             ast_verbose("Successfully set global EID to '%s'\n", v->value);
03059             ast_eid_default = tmp_eid;
03060          } else
03061             ast_verbose("Invalid Entity ID '%s' provided\n", v->value);
03062       } else if (!strcasecmp(v->name, "lightbackground")) {
03063          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_LIGHT_BACKGROUND);
03064       } else if (!strcasecmp(v->name, "forceblackbackground")) {
03065          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_FORCE_BLACK_BACKGROUND);
03066       } else if (!strcasecmp(v->name, "hideconnect")) {
03067          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_HIDE_CONSOLE_CONNECT);
03068       } else if (!strcasecmp(v->name, "lockconfdir")) {
03069          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_LOCK_CONFIG_DIR);
03070       }
03071    }
03072    for (v = ast_variable_browse(cfg, "compat"); v; v = v->next) {
03073       float version;
03074       if (sscanf(v->value, "%30f", &version) != 1) {
03075          ast_log(LOG_WARNING, "Compatibility version for option '%s' is not a number: '%s'\n", v->name, v->value);
03076          continue;
03077       }
03078       if (!strcasecmp(v->name, "app_set")) {
03079          ast_set2_flag(&ast_compat, version < 1.5 ? 1 : 0, AST_COMPAT_APP_SET);
03080       } else if (!strcasecmp(v->name, "res_agi")) {
03081          ast_set2_flag(&ast_compat, version < 1.5 ? 1 : 0, AST_COMPAT_DELIM_RES_AGI);
03082       } else if (!strcasecmp(v->name, "pbx_realtime")) {
03083          ast_set2_flag(&ast_compat, version < 1.5 ? 1 : 0, AST_COMPAT_DELIM_PBX_REALTIME);
03084       }
03085    }
03086    ast_config_destroy(cfg);
03087 }
03088 
03089 static void *monitor_sig_flags(void *unused)
03090 {
03091    for (;;) {
03092       struct pollfd p = { sig_alert_pipe[0], POLLIN, 0 };
03093       int a;
03094       ast_poll(&p, 1, -1);
03095       if (sig_flags.need_reload) {
03096          sig_flags.need_reload = 0;
03097          ast_module_reload(NULL);
03098       }
03099       if (sig_flags.need_quit) {
03100          sig_flags.need_quit = 0;
03101          if (consolethread != AST_PTHREADT_NULL) {
03102             sig_flags.need_quit_handler = 1;
03103             pthread_kill(consolethread, SIGURG);
03104          } else {
03105             quit_handler(0, 0, 1, 0);
03106          }
03107       }
03108       if (read(sig_alert_pipe[0], &a, sizeof(a)) != sizeof(a)) {
03109       }
03110    }
03111 
03112    return NULL;
03113 }
03114 
03115 static void *canary_thread(void *unused)
03116 {
03117    struct stat canary_stat;
03118    struct timeval now;
03119 
03120    /* Give the canary time to sing */
03121    sleep(120);
03122 
03123    for (;;) {
03124       stat(canary_filename, &canary_stat);
03125       now = ast_tvnow();
03126       if (now.tv_sec > canary_stat.st_mtime + 60) {
03127          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");
03128          ast_set_priority(0);
03129          pthread_exit(NULL);
03130       }
03131 
03132       /* Check the canary once a minute */
03133       sleep(60);
03134    }
03135 }
03136 
03137 /* Used by libc's atexit(3) function */
03138 static void canary_exit(void)
03139 {
03140    if (canary_pid > 0)
03141       kill(canary_pid, SIGKILL);
03142 }
03143 
03144 static void run_startup_commands(void)
03145 {
03146    int fd;
03147    struct ast_config *cfg;
03148    struct ast_flags cfg_flags = { 0 };
03149    struct ast_variable *v;
03150 
03151    if (!(cfg = ast_config_load2("cli.conf", "" /* core, can't reload */, cfg_flags)))
03152       return;
03153    if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) {
03154       return;
03155    }
03156 
03157    fd = open("/dev/null", O_RDWR);
03158    if (fd < 0) {
03159       ast_config_destroy(cfg);
03160       return;
03161    }
03162 
03163    for (v = ast_variable_browse(cfg, "startup_commands"); v; v = v->next) {
03164       if (ast_true(v->value))
03165          ast_cli_command(fd, v->name);
03166    }
03167 
03168    close(fd);
03169    ast_config_destroy(cfg);
03170 }
03171 
03172 static void env_init(void)
03173 {
03174    setenv("AST_SYSTEMNAME", ast_config_AST_SYSTEM_NAME, 1);
03175    setenv("AST_BUILD_HOST", ast_build_hostname, 1);
03176    setenv("AST_BUILD_DATE", ast_build_date, 1);
03177    setenv("AST_BUILD_KERNEL", ast_build_kernel, 1);
03178    setenv("AST_BUILD_MACHINE", ast_build_machine, 1);
03179    setenv("AST_BUILD_OS", ast_build_os, 1);
03180    setenv("AST_BUILD_USER", ast_build_user, 1);
03181    setenv("AST_VERSION", ast_get_version(), 1);
03182 }
03183 
03184 int main(int argc, char *argv[])
03185 {
03186    int c;
03187    char filename[80] = "";
03188    char hostname[MAXHOSTNAMELEN] = "";
03189    char tmp[80];
03190    char * xarg = NULL;
03191    int x;
03192    FILE *f;
03193    sigset_t sigs;
03194    int num;
03195    int isroot = 1, rundir_exists = 0;
03196    char *buf;
03197    const char *runuser = NULL, *rungroup = NULL;
03198    char *remotesock = NULL;
03199    int moduleresult;         /*!< Result from the module load subsystem */
03200    struct rlimit l;
03201 
03202    /* Remember original args for restart */
03203    if (argc > ARRAY_LEN(_argv) - 1) {
03204       fprintf(stderr, "Truncating argument size to %d\n", (int)ARRAY_LEN(_argv) - 1);
03205       argc = ARRAY_LEN(_argv) - 1;
03206    }
03207    for (x = 0; x < argc; x++)
03208       _argv[x] = argv[x];
03209    _argv[x] = NULL;
03210 
03211    if (geteuid() != 0)
03212       isroot = 0;
03213 
03214    /* if the progname is rasterisk consider it a remote console */
03215    if (argv[0] && (strstr(argv[0], "rasterisk")) != NULL) {
03216       ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE);
03217    }
03218    if (gethostname(hostname, sizeof(hostname)-1))
03219       ast_copy_string(hostname, "<Unknown>", sizeof(hostname));
03220    ast_mainpid = getpid();
03221    ast_ulaw_init();
03222    ast_alaw_init();
03223    callerid_init();
03224    ast_builtins_init();
03225    ast_utils_init();
03226    tdd_init();
03227    ast_tps_init();
03228    ast_fd_init();
03229    ast_pbx_init();
03230 
03231    if (getenv("HOME")) 
03232       snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
03233    /* Check for options */
03234    while ((c = getopt(argc, argv, "BC:cde:FfG:ghIiL:M:mnpqRrs:TtU:VvWXx:")) != -1) {
03235       /*!\note Please keep the ordering here to alphabetical, capital letters
03236        * first.  This will make it easier in the future to select unused
03237        * option flags for new features. */
03238       switch (c) {
03239       case 'B': /* Force black background */
03240          ast_set_flag(&ast_options, AST_OPT_FLAG_FORCE_BLACK_BACKGROUND);
03241          ast_clear_flag(&ast_options, AST_OPT_FLAG_LIGHT_BACKGROUND);
03242          break;
03243       case 'X':
03244          ast_set_flag(&ast_options, AST_OPT_FLAG_EXEC_INCLUDES);
03245          break;
03246       case 'C':
03247          ast_copy_string(cfg_paths.config_file, optarg, sizeof(cfg_paths.config_file));
03248          ast_set_flag(&ast_options, AST_OPT_FLAG_OVERRIDE_CONFIG);
03249          break;
03250       case 'c':
03251          ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_CONSOLE);
03252          break;
03253       case 'd':
03254          option_debug++;
03255          ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);
03256          break;
03257 #if defined(HAVE_SYSINFO)
03258       case 'e':
03259          if ((sscanf(&optarg[1], "%30ld", &option_minmemfree) != 1) || (option_minmemfree < 0)) {
03260             option_minmemfree = 0;
03261          }
03262          break;
03263 #endif
03264 #if HAVE_WORKING_FORK
03265       case 'F':
03266          ast_set_flag(&ast_options, AST_OPT_FLAG_ALWAYS_FORK);
03267          break;
03268       case 'f':
03269          ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);
03270          break;
03271 #endif
03272       case 'G':
03273          rungroup = ast_strdupa(optarg);
03274          break;
03275       case 'g':
03276          ast_set_flag(&ast_options, AST_OPT_FLAG_DUMP_CORE);
03277          break;
03278       case 'h':
03279          show_cli_help();
03280          exit(0);
03281       case 'I':
03282          ast_set_flag(&ast_options, AST_OPT_FLAG_INTERNAL_TIMING);
03283          break;
03284       case 'i':
03285          ast_set_flag(&ast_options, AST_OPT_FLAG_INIT_KEYS);
03286          break;
03287       case 'L':
03288          if ((sscanf(optarg, "%30lf", &option_maxload) != 1) || (option_maxload < 0.0)) {
03289             option_maxload = 0.0;
03290          }
03291          break;
03292       case 'M':
03293          if ((sscanf(optarg, "%30d", &option_maxcalls) != 1) || (option_maxcalls < 0)) {
03294             option_maxcalls = 0;
03295          }
03296          break;
03297       case 'm':
03298          ast_set_flag(&ast_options, AST_OPT_FLAG_MUTE);
03299          break;
03300       case 'n':
03301          ast_set_flag(&ast_options, AST_OPT_FLAG_NO_COLOR);
03302          break;
03303       case 'p':
03304          ast_set_flag(&ast_options, AST_OPT_FLAG_HIGH_PRIORITY);
03305          break;
03306       case 'q':
03307          ast_set_flag(&ast_options, AST_OPT_FLAG_QUIET);
03308          break;
03309       case 'R':
03310          ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE | AST_OPT_FLAG_RECONNECT);
03311          break;
03312       case 'r':
03313          ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE);
03314          break;
03315       case 's':
03316          remotesock = ast_strdupa(optarg);
03317          break;
03318       case 'T':
03319          ast_set_flag(&ast_options, AST_OPT_FLAG_TIMESTAMP);
03320          break;
03321       case 't':
03322          ast_set_flag(&ast_options, AST_OPT_FLAG_CACHE_RECORD_FILES);
03323          break;
03324       case 'U':
03325          runuser = ast_strdupa(optarg);
03326          break;
03327       case 'V':
03328          show_version();
03329          exit(0);
03330       case 'v':
03331          option_verbose++;
03332          ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);
03333          break;
03334       case 'W': /* White background */
03335          ast_set_flag(&ast_options, AST_OPT_FLAG_LIGHT_BACKGROUND);
03336          ast_clear_flag(&ast_options, AST_OPT_FLAG_FORCE_BLACK_BACKGROUND);
03337          break;
03338       case 'x':
03339          ast_set_flag(&ast_options, AST_OPT_FLAG_EXEC | AST_OPT_FLAG_NO_COLOR);
03340          xarg = ast_strdupa(optarg);
03341          break;
03342       case '?':
03343          exit(1);
03344       }
03345    }
03346 
03347    if (ast_opt_console || option_verbose || (ast_opt_remote && !ast_opt_exec)) {
03348       if (ast_register_verbose(console_verboser)) {
03349          ast_log(LOG_WARNING, "Unable to register console verboser?\n");
03350       }
03351       WELCOME_MESSAGE;
03352    }
03353 
03354    if (ast_opt_console && !option_verbose) 
03355       ast_verbose("[ Booting...\n");
03356 
03357    /* For remote connections, change the name of the remote connection.
03358     * We do this for the benefit of init scripts (which need to know if/when
03359     * the main asterisk process has died yet). */
03360    if (ast_opt_remote) {
03361       strcpy(argv[0], "rasterisk");
03362       for (x = 1; x < argc; x++) {
03363          argv[x] = argv[0] + 10;
03364       }
03365    }
03366 
03367    if (ast_opt_console && !option_verbose) {
03368       ast_verbose("[ Reading Master Configuration ]\n");
03369    }
03370 
03371    ast_readconfig();
03372    env_init();
03373 
03374    if (ast_opt_remote && remotesock != NULL)
03375       ast_copy_string((char *) cfg_paths.socket_path, remotesock, sizeof(cfg_paths.socket_path));
03376 
03377    if (!ast_language_is_prefix && !ast_opt_remote)
03378       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");
03379 
03380    if (ast_opt_always_fork && (ast_opt_remote || ast_opt_console)) {
03381       ast_log(LOG_WARNING, "'alwaysfork' is not compatible with console or remote console mode; ignored\n");
03382       ast_clear_flag(&ast_options, AST_OPT_FLAG_ALWAYS_FORK);
03383    }
03384 
03385    if (ast_opt_dump_core) {
03386       memset(&l, 0, sizeof(l));
03387       l.rlim_cur = RLIM_INFINITY;
03388       l.rlim_max = RLIM_INFINITY;
03389       if (setrlimit(RLIMIT_CORE, &l)) {
03390          ast_log(LOG_WARNING, "Unable to disable core size resource limit: %s\n", strerror(errno));
03391       }
03392    }
03393 
03394    if (getrlimit(RLIMIT_NOFILE, &l)) {
03395       ast_log(LOG_WARNING, "Unable to check file descriptor limit: %s\n", strerror(errno));
03396    }
03397 
03398 #if !defined(CONFIGURE_RAN_AS_ROOT)
03399    /* Check if select(2) will run with more file descriptors */
03400    do {
03401       int fd, fd2;
03402       ast_fdset readers;
03403       struct timeval tv = { 0, };
03404 
03405       if (l.rlim_cur <= FD_SETSIZE) {
03406          /* The limit of select()able FDs is irrelevant, because we'll never
03407           * open one that high. */
03408          break;
03409       }
03410 
03411       if (!(fd = open("/dev/null", O_RDONLY))) {
03412          ast_log(LOG_ERROR, "Cannot open a file descriptor at boot? %s\n", strerror(errno));
03413          break; /* XXX Should we exit() here? XXX */
03414       }
03415 
03416       fd2 = (l.rlim_cur > sizeof(readers) * 8 ? sizeof(readers) * 8 : l.rlim_cur) - 1;
03417       if (dup2(fd, fd2) < 0) {
03418          ast_log(LOG_WARNING, "Cannot open maximum file descriptor %d at boot? %s\n", fd2, strerror(errno));
03419          close(fd);
03420          break;
03421       }
03422 
03423       FD_ZERO(&readers);
03424       FD_SET(fd2, &readers);
03425       if (ast_select(fd2 + 1, &readers, NULL, NULL, &tv) < 0) {
03426          ast_log(LOG_WARNING, "Maximum select()able file descriptor is %d\n", FD_SETSIZE);
03427       }
03428       ast_FD_SETSIZE = l.rlim_cur > ast_FDMAX ? ast_FDMAX : l.rlim_cur;
03429       close(fd);
03430       close(fd2);
03431    } while (0);
03432 #elif defined(HAVE_VARIABLE_FDSET)
03433    ast_FD_SETSIZE = l.rlim_cur > ast_FDMAX ? ast_FDMAX : l.rlim_cur;
03434 #endif /* !defined(CONFIGURE_RAN_AS_ROOT) */
03435 
03436    if ((!rungroup) && !ast_strlen_zero(ast_config_AST_RUN_GROUP))
03437       rungroup = ast_config_AST_RUN_GROUP;
03438    if ((!runuser) && !ast_strlen_zero(ast_config_AST_RUN_USER))
03439       runuser = ast_config_AST_RUN_USER;
03440 
03441    /* Must install this signal handler up here to ensure that if the canary
03442     * fails to execute that it doesn't kill the Asterisk process.
03443     */
03444    sigaction(SIGCHLD, &child_handler, NULL);
03445 
03446    /* It's common on some platforms to clear /var/run at boot.  Create the
03447     * socket file directory before we drop privileges. */
03448    if (mkdir(ast_config_AST_RUN_DIR, 0755)) {
03449       if (errno == EEXIST) {
03450          rundir_exists = 1;
03451       } else {
03452          ast_log(LOG_WARNING, "Unable to create socket file directory.  Remote consoles will not be able to connect! (%s)\n", strerror(x));
03453       }
03454    }
03455 
03456 #ifndef __CYGWIN__
03457 
03458    if (isroot) {
03459       ast_set_priority(ast_opt_high_priority);
03460    }
03461 
03462    if (isroot && rungroup) {
03463       struct group *gr;
03464       gr = getgrnam(rungroup);
03465       if (!gr) {
03466          ast_log(LOG_WARNING, "No such group '%s'!\n", rungroup);
03467          exit(1);
03468       }
03469       if (!rundir_exists && chown(ast_config_AST_RUN_DIR, -1, gr->gr_gid)) {
03470          ast_log(LOG_WARNING, "Unable to chgrp run directory to %d (%s)\n", (int) gr->gr_gid, rungroup);
03471       }
03472       if (setgid(gr->gr_gid)) {
03473          ast_log(LOG_WARNING, "Unable to setgid to %d (%s)\n", (int)gr->gr_gid, rungroup);
03474          exit(1);
03475       }
03476       if (setgroups(0, NULL)) {
03477          ast_log(LOG_WARNING, "Unable to drop unneeded groups\n");
03478          exit(1);
03479       }
03480       if (option_verbose)
03481          ast_verbose("Running as group '%s'\n", rungroup);
03482    }
03483 
03484    if (runuser && !ast_test_flag(&ast_options, AST_OPT_FLAG_REMOTE)) {
03485 #ifdef HAVE_CAP
03486       int has_cap = 1;
03487 #endif /* HAVE_CAP */
03488       struct passwd *pw;
03489       pw = getpwnam(runuser);
03490       if (!pw) {
03491          ast_log(LOG_WARNING, "No such user '%s'!\n", runuser);
03492          exit(1);
03493       }
03494       if (chown(ast_config_AST_RUN_DIR, pw->pw_uid, -1)) {
03495          ast_log(LOG_WARNING, "Unable to chown run directory to %d (%s)\n", (int) pw->pw_uid, runuser);
03496       }
03497 #ifdef HAVE_CAP
03498       if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0)) {
03499          ast_log(LOG_WARNING, "Unable to keep capabilities.\n");
03500          has_cap = 0;
03501       }
03502 #endif /* HAVE_CAP */
03503       if (!isroot && pw->pw_uid != geteuid()) {
03504          ast_log(LOG_ERROR, "Asterisk started as nonroot, but runuser '%s' requested.\n", runuser);
03505          exit(1);
03506       }
03507       if (!rungroup) {
03508          if (setgid(pw->pw_gid)) {
03509             ast_log(LOG_WARNING, "Unable to setgid to %d!\n", (int)pw->pw_gid);
03510             exit(1);
03511          }
03512          if (isroot && initgroups(pw->pw_name, pw->pw_gid)) {
03513             ast_log(LOG_WARNING, "Unable to init groups for '%s'\n", runuser);
03514             exit(1);
03515          }
03516       }
03517       if (setuid(pw->pw_uid)) {
03518          ast_log(LOG_WARNING, "Unable to setuid to %d (%s)\n", (int)pw->pw_uid, runuser);
03519          exit(1);
03520       }
03521       if (option_verbose)
03522          ast_verbose("Running as user '%s'\n", runuser);
03523 #ifdef HAVE_CAP
03524       if (has_cap) {
03525          cap_t cap;
03526 
03527          cap = cap_from_text("cap_net_admin=eip");
03528 
03529          if (cap_set_proc(cap))
03530             ast_log(LOG_WARNING, "Unable to install capabilities.\n");
03531 
03532          if (cap_free(cap))
03533             ast_log(LOG_WARNING, "Unable to drop capabilities.\n");
03534       }
03535 #endif /* HAVE_CAP */
03536    }
03537 
03538 #endif /* __CYGWIN__ */
03539 
03540 #ifdef linux
03541    if (geteuid() && ast_opt_dump_core) {
03542       if (prctl(PR_SET_DUMPABLE, 1, 0, 0, 0) < 0) {
03543          ast_log(LOG_WARNING, "Unable to set the process for core dumps after changing to a non-root user. %s\n", strerror(errno));
03544       }
03545    }
03546 #endif
03547 
03548    {
03549 #if defined(HAVE_EACCESS) || defined(HAVE_EUIDACCESS)
03550 #if defined(HAVE_EUIDACCESS) && !defined(HAVE_EACCESS)
03551 #define eaccess euidaccess
03552 #endif
03553       char dir[PATH_MAX];
03554       if (!getcwd(dir, sizeof(dir)) || eaccess(dir, R_OK | X_OK | F_OK)) {
03555          ast_log(LOG_ERROR, "Unable to access the running directory (%s).  Changing to '/' for compatibility.\n", strerror(errno));
03556          /* If we cannot access the CWD, then we couldn't dump core anyway,
03557           * so chdir("/") won't break anything. */
03558          if (chdir("/")) {
03559             /* chdir(/) should never fail, so this ends up being a no-op */
03560             ast_log(LOG_ERROR, "chdir(\"/\") failed?!! %s\n", strerror(errno));
03561          }
03562       } else
03563 #endif /* defined(HAVE_EACCESS) || defined(HAVE_EUIDACCESS) */
03564       if (!ast_opt_no_fork && !ast_opt_dump_core) {
03565          /* Backgrounding, but no cores, so chdir won't break anything. */
03566          if (chdir("/")) {
03567             ast_log(LOG_ERROR, "Unable to chdir(\"/\") ?!! %s\n", strerror(errno));
03568          }
03569       }
03570    }
03571 
03572    ast_term_init();
03573    printf("%s", term_end());
03574    fflush(stdout);
03575 
03576    if (ast_opt_console && !option_verbose) 
03577       ast_verbose("[ Initializing Custom Configuration Options ]\n");
03578    /* custom config setup */
03579    register_config_cli();
03580    read_config_maps();
03581    
03582    if (ast_opt_console) {
03583       if (el_hist == NULL || el == NULL)
03584          ast_el_initialize();
03585 
03586       if (!ast_strlen_zero(filename))
03587          ast_el_read_history(filename);
03588    }
03589 
03590    if (ast_tryconnect()) {
03591       /* One is already running */
03592       if (ast_opt_remote) {
03593          if (ast_opt_exec) {
03594             ast_remotecontrol(xarg);
03595             quit_handler(0, 0, 0, 0);
03596             exit(0);
03597          }
03598          printf("%s", term_quit());
03599          ast_remotecontrol(NULL);
03600          quit_handler(0, 0, 0, 0);
03601          exit(0);
03602       } else {
03603          ast_log(LOG_ERROR, "Asterisk already running on %s.  Use 'asterisk -r' to connect.\n", ast_config_AST_SOCKET);
03604          printf("%s", term_quit());
03605          exit(1);
03606       }
03607    } else if (ast_opt_remote || ast_opt_exec) {
03608       ast_log(LOG_ERROR, "Unable to connect to remote asterisk (does %s exist?)\n", ast_config_AST_SOCKET);
03609       printf("%s", term_quit());
03610       exit(1);
03611    }
03612    /* Blindly write pid file since we couldn't connect */
03613    unlink(ast_config_AST_PID);
03614    f = fopen(ast_config_AST_PID, "w");
03615    if (f) {
03616       fprintf(f, "%ld\n", (long)getpid());
03617       fclose(f);
03618    } else
03619       ast_log(LOG_WARNING, "Unable to open pid file '%s': %s\n", ast_config_AST_PID, strerror(errno));
03620 
03621 #if HAVE_WORKING_FORK
03622    if (ast_opt_always_fork || !ast_opt_no_fork) {
03623 #ifndef HAVE_SBIN_LAUNCHD
03624       if (daemon(1, 0) < 0) {
03625          ast_log(LOG_ERROR, "daemon() failed: %s\n", strerror(errno));
03626       }
03627       ast_mainpid = getpid();
03628       /* Blindly re-write pid file since we are forking */
03629       unlink(ast_config_AST_PID);
03630       f = fopen(ast_config_AST_PID, "w");
03631       if (f) {
03632          fprintf(f, "%ld\n", (long)ast_mainpid);
03633          fclose(f);
03634       } else
03635          ast_log(LOG_WARNING, "Unable to open pid file '%s': %s\n", ast_config_AST_PID, strerror(errno));
03636 #else
03637       ast_log(LOG_WARNING, "Mac OS X detected.  Use 'launchctl load /Library/LaunchDaemon/org.asterisk.asterisk.plist'.\n");
03638 #endif
03639    }
03640 #endif
03641 
03642    /* Spawning of astcanary must happen AFTER the call to daemon(3) */
03643    if (isroot && ast_opt_high_priority) {
03644       snprintf(canary_filename, sizeof(canary_filename), "%s/alt.asterisk.canary.tweet.tweet.tweet", ast_config_AST_RUN_DIR);
03645 
03646       /* Don't let the canary child kill Asterisk, if it dies immediately */
03647       sigaction(SIGPIPE, &ignore_sig_handler, NULL);
03648 
03649       canary_pid = fork();
03650       if (canary_pid == 0) {
03651          char canary_binary[128], *lastslash, ppid[12];
03652 
03653          /* Reset signal handler */
03654          signal(SIGCHLD, SIG_DFL);
03655          signal(SIGPIPE, SIG_DFL);
03656 
03657          ast_close_fds_above_n(0);
03658          ast_set_priority(0);
03659          snprintf(ppid, sizeof(ppid), "%d", (int) ast_mainpid);
03660 
03661          execlp("astcanary", "astcanary", canary_filename, ppid, (char *)NULL);
03662 
03663          /* If not found, try the same path as used to execute asterisk */
03664          ast_copy_string(canary_binary, argv[0], sizeof(canary_binary));
03665          if ((lastslash = strrchr(canary_binary, '/'))) {
03666             ast_copy_string(lastslash + 1, "astcanary", sizeof(canary_binary) + canary_binary - (lastslash + 1));
03667             execl(canary_binary, "astcanary", canary_filename, ppid, (char *)NULL);
03668          }
03669 
03670          /* Should never happen */
03671          _exit(1);
03672       } else if (canary_pid > 0) {
03673          pthread_t dont_care;
03674          ast_pthread_create_detached(&dont_care, NULL, canary_thread, NULL);
03675       }
03676 
03677       /* Kill the canary when we exit */
03678       ast_register_atexit(canary_exit);
03679    }
03680 
03681    if (ast_event_init()) {
03682       printf("%s", term_quit());
03683       exit(1);
03684    }
03685 
03686 #ifdef TEST_FRAMEWORK
03687    if (ast_test_init()) {
03688       printf("%s", term_quit());
03689       exit(1);
03690    }
03691 #endif
03692 
03693    ast_aoc_cli_init();
03694 
03695    ast_makesocket();
03696    sigemptyset(&sigs);
03697    sigaddset(&sigs, SIGHUP);
03698    sigaddset(&sigs, SIGTERM);
03699    sigaddset(&sigs, SIGINT);
03700    sigaddset(&sigs, SIGPIPE);
03701    sigaddset(&sigs, SIGWINCH);
03702    pthread_sigmask(SIG_BLOCK, &sigs, NULL);
03703    sigaction(SIGURG, &urg_handler, NULL);
03704    signal(SIGINT, __quit_handler);
03705    signal(SIGTERM, __quit_handler);
03706    sigaction(SIGHUP, &hup_handler, NULL);
03707    sigaction(SIGPIPE, &ignore_sig_handler, NULL);
03708 
03709    /* ensure that the random number generators are seeded with a different value every time
03710       Asterisk is started
03711    */
03712    srand((unsigned int) getpid() + (unsigned int) time(NULL));
03713    initstate((unsigned int) getpid() * 65536 + (unsigned int) time(NULL), randompool, sizeof(randompool));
03714 
03715    if (init_logger()) {    /* Start logging subsystem */
03716       printf("%s", term_quit());
03717       exit(1);
03718    }
03719 
03720    threadstorage_init();
03721 
03722    astobj2_init();
03723 
03724    ast_autoservice_init();
03725 
03726    if (ast_timing_init()) {
03727       printf("%s", term_quit());
03728       exit(1);
03729    }
03730 
03731    if (ast_ssl_init()) {
03732       printf("%s", term_quit());
03733       exit(1);
03734    }
03735 
03736 #ifdef AST_XML_DOCS
03737    /* Load XML documentation. */
03738    ast_xmldoc_load_documentation();
03739 #endif
03740 
03741    /* initialize the data retrieval API */
03742    if (ast_data_init()) {
03743       printf ("%s", term_quit());
03744       exit(1);
03745    }
03746 
03747    ast_channels_init();
03748 
03749    if ((moduleresult = load_modules(1))) {      /* Load modules, pre-load only */
03750       printf("%s", term_quit());
03751       exit(moduleresult == -2 ? 2 : 1);
03752    }
03753 
03754    if (dnsmgr_init()) {    /* Initialize the DNS manager */
03755       printf("%s", term_quit());
03756       exit(1);
03757    }
03758 
03759    ast_http_init();     /* Start the HTTP server, if needed */
03760 
03761    if (init_manager()) {
03762       printf("%s", term_quit());
03763       exit(1);
03764    }
03765 
03766    if (ast_cdr_engine_init()) {
03767       printf("%s", term_quit());
03768       exit(1);
03769    }
03770 
03771    if (ast_cel_engine_init()) {
03772       printf("%s", term_quit());
03773       exit(1);
03774    }
03775 
03776    if (ast_device_state_engine_init()) {
03777       printf("%s", term_quit());
03778       exit(1);
03779    }
03780 
03781    ast_dsp_init();
03782    ast_udptl_init();
03783 
03784    if (ast_image_init()) {
03785       printf("%s", term_quit());
03786       exit(1);
03787    }
03788 
03789    if (ast_file_init()) {
03790       printf("%s", term_quit());
03791       exit(1);
03792    }
03793 
03794    if (load_pbx()) {
03795       printf("%s", term_quit());
03796       exit(1);
03797    }
03798 
03799    if (ast_indications_init()) {
03800       printf("%s", term_quit());
03801       exit(1);
03802    }
03803 
03804    if (ast_features_init()) {
03805       printf("%s", term_quit());
03806       exit(1);
03807    }
03808 
03809    if (init_framer()) {
03810       printf("%s", term_quit());
03811       exit(1);
03812    }
03813 
03814    if (astdb_init()) {
03815       printf("%s", term_quit());
03816       exit(1);
03817    }
03818 
03819    if (ast_enum_init()) {
03820       printf("%s", term_quit());
03821       exit(1);
03822    }
03823 
03824    if (ast_cc_init()) {
03825       printf("%s", term_quit());
03826       exit(1);
03827    }
03828 
03829    if ((moduleresult = load_modules(0))) {      /* Load modules */
03830       printf("%s", term_quit());
03831       exit(moduleresult == -2 ? 2 : 1);
03832    }
03833 
03834    /* loads the cli_permissoins.conf file needed to implement cli restrictions. */
03835    ast_cli_perms_init(0);
03836 
03837    ast_stun_init();
03838 
03839    dnsmgr_start_refresh();
03840 
03841    /* We might have the option of showing a console, but for now just
03842       do nothing... */
03843    if (ast_opt_console && !option_verbose)
03844       ast_verbose(" ]\n");
03845    if (option_verbose || ast_opt_console)
03846       ast_verbose("%s", term_color(tmp, "Asterisk Ready.\n", COLOR_BRWHITE, COLOR_BLACK, sizeof(tmp)));
03847    if (ast_opt_no_fork)
03848       consolethread = pthread_self();
03849 
03850    if (pipe(sig_alert_pipe))
03851       sig_alert_pipe[0] = sig_alert_pipe[1] = -1;
03852 
03853    ast_set_flag(&ast_options, AST_OPT_FLAG_FULLY_BOOTED);
03854    manager_event(EVENT_FLAG_SYSTEM, "FullyBooted", "Status: Fully Booted\r\n");
03855 
03856    ast_process_pending_reloads();
03857 
03858    pthread_sigmask(SIG_UNBLOCK, &sigs, NULL);
03859 
03860 #ifdef __AST_DEBUG_MALLOC
03861    __ast_mm_init();
03862 #endif   
03863 
03864    ast_lastreloadtime = ast_startuptime = ast_tvnow();
03865    ast_cli_register_multiple(cli_asterisk, ARRAY_LEN(cli_asterisk));
03866 
03867    run_startup_commands();
03868 
03869    if (ast_opt_console) {
03870       /* Console stuff now... */
03871       /* Register our quit function */
03872       char title[256];
03873 
03874       ast_pthread_create_detached(&mon_sig_flags, NULL, monitor_sig_flags, NULL);
03875 
03876       set_icon("Asterisk");
03877       snprintf(title, sizeof(title), "Asterisk Console on '%s' (pid %ld)", hostname, (long)ast_mainpid);
03878       set_title(title);
03879 
03880       el_set(el, EL_GETCFN, ast_el_read_char);
03881 
03882       for (;;) {
03883          if (sig_flags.need_quit || sig_flags.need_quit_handler) {
03884             quit_handler(0, 0, 0, 0);
03885             break;
03886          }
03887          buf = (char *) el_gets(el, &num);
03888 
03889          if (!buf && write(1, "", 1) < 0)
03890             goto lostterm;
03891 
03892          if (buf) {
03893             if (buf[strlen(buf)-1] == '\n')
03894                buf[strlen(buf)-1] = '\0';
03895 
03896             consolehandler((char *)buf);
03897          } else if (ast_opt_remote && (write(STDOUT_FILENO, "\nUse EXIT or QUIT to exit the asterisk console\n",
03898                strlen("\nUse EXIT or QUIT to exit the asterisk console\n")) < 0)) {
03899             /* Whoa, stdout disappeared from under us... Make /dev/null's */
03900             int fd;
03901             fd = open("/dev/null", O_RDWR);
03902             if (fd > -1) {
03903                dup2(fd, STDOUT_FILENO);
03904                dup2(fd, STDIN_FILENO);
03905             } else
03906                ast_log(LOG_WARNING, "Failed to open /dev/null to recover from dead console. Bad things will happen!\n");
03907             break;
03908          }
03909       }
03910    }
03911 
03912    monitor_sig_flags(NULL);
03913 
03914 lostterm:
03915    return 0;
03916 }