Sat Apr 26 2014 22:01:29

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