Sat Jul 12 2014 17:18:26

Asterisk developer's documentation


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