Mon Sep 20 2010 00:20:16

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