asterisk.c

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

Generated on Thu Apr 16 06:27:14 2015 for Asterisk - The Open Source Telephony Project by  doxygen 1.5.6