Mon Apr 28 2014 10:05:36

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