Tue Aug 24 2010 19:41:26

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