Thu Sep 7 01:02:53 2017

Asterisk developer's documentation


asterisk.c

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

Generated on 7 Sep 2017 for Asterisk - The Open Source Telephony Project by  doxygen 1.6.1