Sat Aug 6 00:39:22 2011

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 - 2010, 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 -- An Open Source Telephony Toolkit
00023  *
00024  * \par Developer Documentation for Asterisk
00025  * This is the main developer documentation for Asterisk. It is 
00026  * generated by running "make progdocs".
00027  * \par Additional documentation
00028  * \arg \ref Licensing
00029  * \arg \ref DevDoc 
00030  * \arg \ref ConfigFiles
00031  *
00032  * \section copyright Copyright and author
00033  *
00034  * Copyright (C) 1999 - 2009, Digium, Inc.
00035  * Asterisk is a trademark registered by Digium, Inc.
00036  *
00037  * \author Mark Spencer <markster@digium.com>
00038  * Also see \ref AstCREDITS
00039  *
00040  * See http://www.asterisk.org for more information about
00041  * the Asterisk project. Please do not directly contact
00042  * any of the maintainers of this project for assistance;
00043  * the project provides a web site, mailing lists and IRC
00044  * channels for your use.
00045  */
00046 
00047 /*! \file
00048   \brief Top level source file for Asterisk  - the Open Source PBX. Implementation
00049   of PBX core functions and CLI interface.
00050   
00051  */
00052 
00053 #include "asterisk.h"
00054 
00055 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 312285 $")
00056 
00057 #undef sched_setscheduler
00058 #undef setpriority
00059 #include <unistd.h>
00060 #include <stdlib.h>
00061 #include <sys/time.h>
00062 #include <fcntl.h>
00063 #include <stdio.h>
00064 #include <signal.h>
00065 #include <sched.h>
00066 #include <sys/socket.h>
00067 #include <sys/un.h>
00068 #include <sys/wait.h>
00069 #include <string.h>
00070 #include <errno.h>
00071 #include <ctype.h>
00072 #include <sys/resource.h>
00073 #include <grp.h>
00074 #include <pwd.h>
00075 #include <sys/stat.h>
00076 
00077 #if defined(HAVE_ZAPTEL) || defined (HAVE_DAHDI)
00078 #include <sys/ioctl.h>
00079 #include "asterisk/dahdi_compat.h"
00080 #endif
00081 
00082 #if defined(HAVE_SYSINFO)
00083 #include <sys/sysinfo.h>
00084 #endif /* HAVE_SYSINFO */
00085 
00086 #ifdef linux
00087 #include <sys/prctl.h>
00088 #ifdef HAVE_CAP
00089 #include <sys/capability.h>
00090 #endif /* HAVE_CAP */
00091 #endif /* linux */
00092 #include <regex.h>
00093 
00094 #if  defined(__FreeBSD__) || defined( __NetBSD__ ) || defined(SOLARIS)
00095 #include <netdb.h>
00096 #if defined(SOLARIS)
00097 int daemon(int, int);  /* defined in libresolv of all places */
00098 #endif
00099 #endif
00100 
00101 #include "asterisk/logger.h"
00102 #include "asterisk/options.h"
00103 #include "asterisk/cli.h"
00104 #include "asterisk/channel.h"
00105 #include "asterisk/ulaw.h"
00106 #include "asterisk/alaw.h"
00107 #include "asterisk/callerid.h"
00108 #include "asterisk/image.h"
00109 #include "asterisk/tdd.h"
00110 #include "asterisk/term.h"
00111 #include "asterisk/manager.h"
00112 #include "asterisk/cdr.h"
00113 #include "asterisk/pbx.h"
00114 #include "asterisk/enum.h"
00115 #include "asterisk/rtp.h"
00116 #include "asterisk/http.h"
00117 #include "asterisk/udptl.h"
00118 #include "asterisk/app.h"
00119 #include "asterisk/lock.h"
00120 #include "asterisk/utils.h"
00121 #include "asterisk/file.h"
00122 #include "asterisk/io.h"
00123 #include "asterisk/lock.h"
00124 #include "editline/histedit.h"
00125 #include "asterisk/config.h"
00126 #include "asterisk/version.h"
00127 #include "asterisk/linkedlists.h"
00128 #include "asterisk/devicestate.h"
00129 #include "asterisk/module.h"
00130 #include "asterisk/poll-compat.h"
00131 
00132 #include "asterisk/doxyref.h"    /* Doxygen documentation */
00133 
00134 #include "../defaults.h"
00135 
00136 #ifndef AF_LOCAL
00137 #define AF_LOCAL AF_UNIX
00138 #define PF_LOCAL PF_UNIX
00139 #endif
00140 
00141 #define AST_MAX_CONNECTS 128
00142 #define NUM_MSGS 64
00143 
00144 /*! \brief Welcome message when starting a CLI interface */
00145 #define WELCOME_MESSAGE \
00146    ast_verbose("Asterisk " ASTERISK_VERSION ", Copyright (C) 1999 - 2010 Digium, Inc. and others.\n"); \
00147    ast_verbose("Created by Mark Spencer <markster@digium.com>\n"); \
00148    ast_verbose("Asterisk comes with ABSOLUTELY NO WARRANTY; type 'core show warranty' for details.\n"); \
00149    ast_verbose("This is free software, with components licensed under the GNU General Public\n"); \
00150    ast_verbose("License version 2 and other licenses; you are welcome to redistribute it under\n"); \
00151    ast_verbose("certain conditions. Type 'core show license' for details.\n"); \
00152    ast_verbose("=========================================================================\n")
00153 
00154 /*! \defgroup main_options Main Configuration Options
00155  \brief Main configuration options from \ref Config_ast "asterisk.conf" or 
00156   the operating system command line when starting Asterisk 
00157   Some of them can be changed in the CLI 
00158  */
00159 /*! @{ */
00160 
00161 struct ast_flags ast_options = { AST_DEFAULT_OPTIONS };
00162 
00163 int option_verbose;           /*!< Verbosity level */
00164 int option_debug;          /*!< Debug level */
00165 
00166 double option_maxload;           /*!< Max load avg on system */
00167 int option_maxcalls;          /*!< Max number of active calls */
00168 int option_maxfiles = 0;    /*!< Max number of open file handles (files, sockets) */
00169 #if defined(HAVE_SYSINFO)
00170 long option_minmemfree = 0;         /*!< Minimum amount of free system memory - stop accepting calls if free memory falls below this watermark */
00171 #endif
00172 /*! @} */
00173 
00174 char record_cache_dir[AST_CACHE_DIR_LEN] = AST_TMP_DIR;
00175 char debug_filename[AST_FILENAME_MAX] = "";
00176 #ifdef HAVE_ZAPTEL
00177 static char _dahdi_chan_name[AST_CHANNEL_NAME] = "Zap";
00178 static size_t _dahdi_chan_name_len = 3;
00179 static enum dahdi_chan_modes _dahdi_chan_mode = CHAN_ZAP_MODE;
00180 #else
00181 static char _dahdi_chan_name[AST_CHANNEL_NAME] = "DAHDI";
00182 static size_t _dahdi_chan_name_len = 5;
00183 static enum dahdi_chan_modes _dahdi_chan_mode = CHAN_DAHDI_PLUS_ZAP_MODE;
00184 #endif
00185 const char *dahdi_chan_name;
00186 const size_t *dahdi_chan_name_len;
00187 const enum dahdi_chan_modes *dahdi_chan_mode;
00188 
00189 static int ast_socket = -1;      /*!< UNIX Socket for allowing remote control */
00190 static int ast_consock = -1;     /*!< UNIX Socket for controlling another asterisk */
00191 pid_t ast_mainpid;
00192 struct console {
00193    int fd;           /*!< File descriptor */
00194    int p[2];         /*!< Pipe */
00195    pthread_t t;         /*!< Thread of handler */
00196    int mute;         /*!< Is the console muted for logs */
00197 };
00198 
00199 struct ast_atexit {
00200    void (*func)(void);
00201    AST_LIST_ENTRY(ast_atexit) list;
00202 };
00203 
00204 static AST_LIST_HEAD_STATIC(atexits, ast_atexit);
00205 
00206 time_t ast_startuptime;
00207 time_t ast_lastreloadtime;
00208 
00209 static History *el_hist;
00210 static EditLine *el;
00211 static char *remotehostname;
00212 
00213 struct console consoles[AST_MAX_CONNECTS];
00214 
00215 char defaultlanguage[MAX_LANGUAGE] = DEFAULT_LANGUAGE;
00216 
00217 static int ast_el_add_history(char *);
00218 static int ast_el_read_history(char *);
00219 static int ast_el_write_history(char *);
00220 
00221 char ast_config_AST_CONFIG_DIR[PATH_MAX];
00222 char ast_config_AST_CONFIG_FILE[PATH_MAX];
00223 char ast_config_AST_MODULE_DIR[PATH_MAX];
00224 char ast_config_AST_SPOOL_DIR[PATH_MAX];
00225 char ast_config_AST_MONITOR_DIR[PATH_MAX];
00226 char ast_config_AST_VAR_DIR[PATH_MAX];
00227 char ast_config_AST_DATA_DIR[PATH_MAX];
00228 char ast_config_AST_LOG_DIR[PATH_MAX];
00229 char ast_config_AST_AGI_DIR[PATH_MAX];
00230 char ast_config_AST_DB[PATH_MAX];
00231 char ast_config_AST_KEY_DIR[PATH_MAX];
00232 char ast_config_AST_PID[PATH_MAX];
00233 char ast_config_AST_SOCKET[PATH_MAX];
00234 char ast_config_AST_RUN_DIR[PATH_MAX];
00235 char ast_config_AST_RUN_USER[PATH_MAX];
00236 char ast_config_AST_RUN_GROUP[PATH_MAX];
00237 char ast_config_AST_CTL_PERMISSIONS[PATH_MAX];
00238 char ast_config_AST_CTL_OWNER[PATH_MAX] = "\0";
00239 char ast_config_AST_CTL_GROUP[PATH_MAX] = "\0";
00240 char ast_config_AST_CTL[PATH_MAX] = "asterisk.ctl";
00241 char ast_config_AST_SYSTEM_NAME[20] = "";
00242 
00243 extern const char *ast_build_hostname;
00244 extern const char *ast_build_kernel;
00245 extern const char *ast_build_machine;
00246 extern const char *ast_build_os;
00247 extern const char *ast_build_date;
00248 extern const char *ast_build_user;
00249 
00250 unsigned int ast_FD_SETSIZE = FD_SETSIZE;
00251 
00252 static char *_argv[256];
00253 static int shuttingdown;
00254 static int restartnow;
00255 static pthread_t consolethread = AST_PTHREADT_NULL;
00256 static pthread_t mon_sig_flags;
00257 
00258 static char randompool[256];
00259 
00260 static int sig_alert_pipe[2] = { -1, -1 };
00261 static struct {
00262     unsigned int need_reload:1;
00263     unsigned int need_quit:1;
00264 } sig_flags;
00265 
00266 #if !defined(LOW_MEMORY)
00267 struct file_version {
00268    AST_LIST_ENTRY(file_version) list;
00269    const char *file;
00270    char *version;
00271 };
00272 
00273 #ifndef AST_MUTEX_INIT_W_CONSTRUCTORS
00274 static AST_LIST_HEAD_STATIC(file_versions, file_version);
00275 #else
00276 static AST_LIST_HEAD(file_versions, file_version) file_versions;
00277 static pthread_once_t file_versions_once = PTHREAD_ONCE_INIT;
00278 static void file_versions_init(void)
00279 {
00280    AST_LIST_HEAD_INIT(&file_versions);
00281 }
00282 #endif
00283 
00284 void ast_register_file_version(const char *file, const char *version)
00285 {
00286    struct file_version *new;
00287    char *work;
00288    size_t version_length;
00289 
00290    work = ast_strdupa(version);
00291    work = ast_strip(ast_strip_quoted(work, "$", "$"));
00292    version_length = strlen(work) + 1;
00293    
00294    if (!(new = ast_calloc(1, sizeof(*new) + version_length)))
00295       return;
00296 
00297    new->file = file;
00298    new->version = (char *) new + sizeof(*new);
00299    memcpy(new->version, work, version_length);
00300 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
00301    pthread_once(&file_versions_once, file_versions_init);
00302 #endif
00303    AST_LIST_LOCK(&file_versions);
00304    AST_LIST_INSERT_HEAD(&file_versions, new, list);
00305    AST_LIST_UNLOCK(&file_versions);
00306 }
00307 
00308 void ast_unregister_file_version(const char *file)
00309 {
00310    struct file_version *find;
00311 
00312    AST_LIST_LOCK(&file_versions);
00313    AST_LIST_TRAVERSE_SAFE_BEGIN(&file_versions, find, list) {
00314       if (!strcasecmp(find->file, file)) {
00315          AST_LIST_REMOVE_CURRENT(&file_versions, list);
00316          break;
00317       }
00318    }
00319    AST_LIST_TRAVERSE_SAFE_END;
00320    AST_LIST_UNLOCK(&file_versions);
00321    if (find)
00322       ast_free(find);
00323 }
00324 
00325 struct thread_list_t {
00326    AST_LIST_ENTRY(thread_list_t) list;
00327    char *name;
00328    pthread_t id;
00329 };
00330 
00331 static AST_LIST_HEAD_STATIC(thread_list, thread_list_t);
00332 
00333 static char show_threads_help[] =
00334 "Usage: core show threads\n"
00335 "       List threads currently active in the system.\n";
00336 
00337 static char show_settings_help[] =
00338 "Usage: core show settings\n"
00339 "       Show core misc settings.\n";
00340 
00341 static char show_sysinfo_help[] =
00342 "Usage: core show sysinfo\n"
00343 "       List current system information.\n";
00344 
00345 void ast_register_thread(char *name)
00346 { 
00347    struct thread_list_t *new = ast_calloc(1, sizeof(*new));
00348 
00349    if (!new)
00350       return;
00351    new->id = pthread_self();
00352    new->name = name; /* steal the allocated memory for the thread name */
00353    AST_LIST_LOCK(&thread_list);
00354    AST_LIST_INSERT_HEAD(&thread_list, new, list);
00355    AST_LIST_UNLOCK(&thread_list);
00356 }
00357 
00358 void ast_unregister_thread(void *id)
00359 {
00360    struct thread_list_t *x;
00361 
00362    AST_LIST_LOCK(&thread_list);
00363    AST_LIST_TRAVERSE_SAFE_BEGIN(&thread_list, x, list) {
00364       if ((void *) x->id == id) {
00365          AST_LIST_REMOVE_CURRENT(&thread_list, list);
00366          break;
00367       }
00368    }
00369    AST_LIST_TRAVERSE_SAFE_END;
00370    AST_LIST_UNLOCK(&thread_list);
00371    if (x) {
00372       ast_free(x->name);
00373       ast_free(x);
00374    }
00375 }
00376 
00377 /*! \brief Give an overview of core settings */
00378 static int handle_show_settings(int fd, int argc, char *argv[])
00379 {
00380    char buf[BUFSIZ];
00381    struct tm tm;
00382 
00383    ast_cli(fd, "\nPBX Core settings\n");
00384    ast_cli(fd, "-----------------\n");
00385    ast_cli(fd, "  Version:                     %s\n", "" ASTERISK_VERSION "" );
00386    if (option_maxcalls)
00387       ast_cli(fd, "  Max. calls:                  %d (Current %d)\n", option_maxcalls, ast_active_channels());
00388    else
00389       ast_cli(fd, "  Max. calls:                  Not set\n");
00390    if (option_maxfiles)
00391       ast_cli(fd, "  Max. open file handles:      %d\n", option_maxfiles); 
00392    else
00393       ast_cli(fd, "  Max. open file handles:      Not set\n");
00394    ast_cli(fd, "  Verbosity:                   %d\n", option_verbose);
00395    ast_cli(fd, "  Debug level:                 %d\n", option_debug);
00396    ast_cli(fd, "  Max load avg:                %lf\n", option_maxload);
00397 #if defined(HAVE_SYSINFO)
00398    ast_cli(fd, "  Min Free Memory:             %ld MB\n", option_minmemfree);
00399 #endif
00400    if (ast_localtime(&ast_startuptime, &tm, NULL)) {
00401       strftime(buf, sizeof(buf), "%H:%M:%S", &tm);
00402       ast_cli(fd, "  Startup time:                %s\n", buf);
00403    }
00404    if (ast_localtime(&ast_lastreloadtime, &tm, NULL)) {
00405       strftime(buf, sizeof(buf), "%H:%M:%S", &tm);
00406       ast_cli(fd, "  Last reload time:            %s\n", buf);
00407    }
00408    ast_cli(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);
00409    ast_cli(fd, "  System name:                 %s\n", ast_config_AST_SYSTEM_NAME);
00410    ast_cli(fd, "  Default language:            %s\n", defaultlanguage);
00411    ast_cli(fd, "  Language prefix:             %s\n", ast_language_is_prefix ? "Enabled" : "Disabled");
00412    ast_cli(fd, "  User name and group:         %s/%s\n", ast_config_AST_RUN_USER, ast_config_AST_RUN_GROUP);
00413    ast_cli(fd, "  Executable includes:         %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_EXEC_INCLUDES) ? "Enabled" : "Disabled");
00414    ast_cli(fd, "  Transcode via SLIN:          %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_TRANSCODE_VIA_SLIN) ? "Enabled" : "Disabled");
00415    ast_cli(fd, "  Internal timing:             %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_INTERNAL_TIMING) ? "Enabled" : "Disabled");
00416    ast_cli(fd, "  Transmit silence during rec: %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_INTERNAL_TIMING) ? "Enabled" : "Disabled");
00417 
00418    struct rlimit rlim;
00419    if (!getrlimit(RLIMIT_NOFILE, &rlim))
00420      ast_cli(fd, "  Current fd limits:           current: %i max: %i\n", rlim.rlim_cur, rlim.rlim_max);
00421    ast_cli(fd, "\n* Subsystems\n");
00422    ast_cli(fd, "  -------------\n");
00423    ast_cli(fd, "  Manager (AMI):               %s\n", check_manager_enabled() ? "Enabled" : "Disabled");
00424    ast_cli(fd, "  Web Manager (AMI/HTTP):      %s\n", check_webmanager_enabled() ? "Enabled" : "Disabled");
00425    ast_cli(fd, "  Call data records:           %s\n", check_cdr_enabled() ? "Enabled" : "Disabled");
00426    ast_cli(fd, "  Realtime Architecture (ARA): %s\n", ast_realtime_enabled() ? "Enabled" : "Disabled");
00427 
00428    /*! \todo we could check musiconhold, voicemail, smdi, adsi, queues  */
00429 
00430    ast_cli(fd, "\n* Directories\n");
00431    ast_cli(fd, "  -------------\n");
00432    ast_cli(fd, "  Configuration file:          %s\n", ast_config_AST_CONFIG_FILE);
00433    ast_cli(fd, "  Configuration directory:     %s\n", ast_config_AST_CONFIG_DIR);
00434    ast_cli(fd, "  Module directory:            %s\n", ast_config_AST_MODULE_DIR);
00435    ast_cli(fd, "  Spool directory:             %s\n", ast_config_AST_SPOOL_DIR);
00436    ast_cli(fd, "  Log directory:               %s\n", ast_config_AST_LOG_DIR);
00437    ast_cli(fd, "\n\n");
00438    return RESULT_SUCCESS;
00439 }
00440  
00441 static int handle_show_threads(int fd, int argc, char *argv[])
00442 {
00443    int count = 0;
00444    struct thread_list_t *cur;
00445 
00446    AST_LIST_LOCK(&thread_list);
00447    AST_LIST_TRAVERSE(&thread_list, cur, list) {
00448       ast_cli(fd, "%p %s\n", (void *)cur->id, cur->name);
00449       count++;
00450    }
00451         AST_LIST_UNLOCK(&thread_list);
00452    ast_cli(fd, "%d threads listed.\n", count);
00453    return RESULT_SUCCESS;
00454 }
00455 
00456 #if defined(HAVE_SYSINFO)
00457 /*! \brief Give an overview of system statistics */
00458 static int handle_show_sysinfo(int fd, int argc, char *argv[])
00459 {
00460    struct sysinfo sys_info;
00461 
00462    if (sysinfo(&sys_info)) {
00463       ast_cli(fd, "FAILED to retrieve system information\n\n");
00464       return RESULT_FAILURE;
00465    }
00466    ast_cli(fd, "\nSystem Statistics\n");
00467    ast_cli(fd, "-----------------\n");
00468    ast_cli(fd, "  System Uptime:             %ld hours\n", sys_info.uptime/3600);
00469    ast_cli(fd, "  Total RAM:                 %ld KiB\n", (sys_info.totalram / sys_info.mem_unit)/1024);
00470    ast_cli(fd, "  Free RAM:                  %ld KiB\n", (sys_info.freeram / sys_info.mem_unit)/1024);
00471    ast_cli(fd, "  Buffer RAM:                %ld KiB\n", (sys_info.bufferram / sys_info.mem_unit)/1024);
00472    ast_cli(fd, "  Total Swap Space:          %ld KiB\n", (sys_info.totalswap / sys_info.mem_unit)/1024);
00473    ast_cli(fd, "  Free Swap Space:           %ld KiB\n\n", (sys_info.freeswap / sys_info.mem_unit)/1024);
00474    ast_cli(fd, "  Number of Processes:       %d \n\n", sys_info.procs);
00475    return RESULT_SUCCESS;
00476 }
00477 #endif
00478 
00479 struct profile_entry {
00480    const char *name;
00481    uint64_t scale;   /* if non-zero, values are scaled by this */
00482    int64_t  mark;
00483    int64_t  value;
00484    int64_t  events;
00485 };
00486 
00487 struct profile_data {
00488    int entries;
00489    int max_size;
00490    struct profile_entry e[0];
00491 };
00492 
00493 static struct profile_data *prof_data;
00494 
00495 /*! \brief allocates a counter with a given name and scale.
00496  * \return Returns the identifier of the counter.
00497  */
00498 int ast_add_profile(const char *name, uint64_t scale)
00499 {
00500    int l = sizeof(struct profile_data);
00501    int n = 10; /* default entries */
00502 
00503    if (prof_data == NULL) {
00504       prof_data = ast_calloc(1, l + n*sizeof(struct profile_entry));
00505       if (prof_data == NULL)
00506          return -1;
00507       prof_data->entries = 0;
00508       prof_data->max_size = n;
00509    }
00510    if (prof_data->entries >= prof_data->max_size) {
00511       void *p;
00512       n = prof_data->max_size + 20;
00513       p = ast_realloc(prof_data, l + n*sizeof(struct profile_entry));
00514       if (p == NULL)
00515          return -1;
00516       prof_data = p;
00517       prof_data->max_size = n;
00518    }
00519    n = prof_data->entries++;
00520    prof_data->e[n].name = ast_strdup(name);
00521    prof_data->e[n].value = 0;
00522    prof_data->e[n].events = 0;
00523    prof_data->e[n].mark = 0;
00524    prof_data->e[n].scale = scale;
00525    return n;
00526 }
00527 
00528 int64_t ast_profile(int i, int64_t delta)
00529 {
00530    if (!prof_data || i < 0 || i > prof_data->entries) /* invalid index */
00531       return 0;
00532    if (prof_data->e[i].scale > 1)
00533       delta /= prof_data->e[i].scale;
00534    prof_data->e[i].value += delta;
00535    prof_data->e[i].events++;
00536    return prof_data->e[i].value;
00537 }
00538 
00539 /* The RDTSC instruction was introduced on the Pentium processor and is not
00540  * implemented on certain clones, like the Cyrix 586. Hence, the previous
00541  * expectation of __i386__ was in error. */
00542 #if defined ( __i686__) && (defined(__FreeBSD__) || defined(linux))
00543 #if defined(__FreeBSD__)
00544 #include <machine/cpufunc.h>
00545 #elif defined(linux)
00546 static __inline uint64_t
00547 rdtsc(void)
00548 { 
00549    uint64_t rv;
00550 
00551    __asm __volatile(".byte 0x0f, 0x31" : "=A" (rv));
00552    return (rv);
00553 }
00554 #endif
00555 #else /* supply a dummy function on other platforms */
00556 static __inline uint64_t
00557 rdtsc(void)
00558 {
00559    return 0;
00560 }
00561 #endif
00562 
00563 int64_t ast_mark(int i, int startstop)
00564 {
00565    if (!prof_data || i < 0 || i > prof_data->entries) /* invalid index */
00566       return 0;
00567    if (startstop == 1)
00568       prof_data->e[i].mark = rdtsc();
00569    else {
00570       prof_data->e[i].mark = (rdtsc() - prof_data->e[i].mark);
00571       if (prof_data->e[i].scale > 1)
00572          prof_data->e[i].mark /= prof_data->e[i].scale;
00573       prof_data->e[i].value += prof_data->e[i].mark;
00574       prof_data->e[i].events++;
00575    }
00576    return prof_data->e[i].mark;
00577 }
00578 
00579 static int handle_show_profile_deprecated(int fd, int argc, char *argv[])
00580 {
00581    int i, min, max;
00582    char *search = NULL;
00583 
00584    if (prof_data == NULL)
00585       return 0;
00586 
00587    min = 0;
00588    max = prof_data->entries;
00589    if  (argc >= 3) { /* specific entries */
00590       if (isdigit(argv[2][0])) {
00591          min = atoi(argv[2]);
00592          if (argc == 4 && strcmp(argv[3], "-"))
00593             max = atoi(argv[3]);
00594       } else
00595          search = argv[2];
00596    }
00597    if (max > prof_data->entries)
00598       max = prof_data->entries;
00599    if (!strcmp(argv[0], "clear")) {
00600       for (i= min; i < max; i++) {
00601          if (!search || strstr(prof_data->e[i].name, search)) {
00602             prof_data->e[i].value = 0;
00603             prof_data->e[i].events = 0;
00604          }
00605       }
00606       return 0;
00607    }
00608    ast_cli(fd, "profile values (%d, allocated %d)\n-------------------\n",
00609       prof_data->entries, prof_data->max_size);
00610    ast_cli(fd, "%6s   %8s  %10s %12s %12s  %s\n", "ID", "Scale", "Events",
00611          "Value", "Average", "Name");
00612    for (i = min; i < max; i++) {
00613       struct profile_entry *e = &prof_data->e[i];
00614       if (!search || strstr(prof_data->e[i].name, search))
00615           ast_cli(fd, "%6d: [%8ld] %10ld %12lld %12lld  %s\n",
00616          i,
00617          (long)e->scale,
00618          (long)e->events, (long long)e->value,
00619          (long long)(e->events ? e->value / e->events : e->value),
00620          e->name);
00621    }
00622    return 0;
00623 }
00624 
00625 static int handle_show_profile(int fd, int argc, char *argv[])
00626 {
00627    int i, min, max;
00628    char *search = NULL;
00629 
00630    if (prof_data == NULL)
00631       return 0;
00632 
00633    min = 0;
00634    max = prof_data->entries;
00635    if  (argc > 3) { /* specific entries */
00636       if (isdigit(argv[3][0])) {
00637          min = atoi(argv[3]);
00638          if (argc == 5 && strcmp(argv[4], "-"))
00639             max = atoi(argv[4]);
00640       } else
00641          search = argv[3];
00642    }
00643    if (max > prof_data->entries)
00644       max = prof_data->entries;
00645    if (!strcmp(argv[1], "clear")) {
00646       for (i= min; i < max; i++) {
00647          if (!search || strstr(prof_data->e[i].name, search)) {
00648             prof_data->e[i].value = 0;
00649             prof_data->e[i].events = 0;
00650          }
00651       }
00652       return 0;
00653    }
00654    ast_cli(fd, "profile values (%d, allocated %d)\n-------------------\n",
00655       prof_data->entries, prof_data->max_size);
00656    ast_cli(fd, "%6s   %8s  %10s %12s %12s  %s\n", "ID", "Scale", "Events",
00657          "Value", "Average", "Name");
00658    for (i = min; i < max; i++) {
00659       struct profile_entry *e = &prof_data->e[i];
00660       if (!search || strstr(prof_data->e[i].name, search))
00661           ast_cli(fd, "%6d: [%8ld] %10ld %12lld %12lld  %s\n",
00662          i,
00663          (long)e->scale,
00664          (long)e->events, (long long)e->value,
00665          (long long)(e->events ? e->value / e->events : e->value),
00666          e->name);
00667    }
00668    return 0;
00669 }
00670 
00671 static char show_version_files_help[] = 
00672 "Usage: core show file version [like <pattern>]\n"
00673 "       Lists the revision numbers of the files used to build this copy of Asterisk.\n"
00674 "       Optional regular expression pattern is used to filter the file list.\n";
00675 
00676 /*! \brief CLI command to list module versions */
00677 static int handle_show_version_files_deprecated(int fd, int argc, char *argv[])
00678 {
00679 #define FORMAT "%-25.25s %-40.40s\n"
00680    struct file_version *iterator;
00681    regex_t regexbuf;
00682    int havepattern = 0;
00683    int havename = 0;
00684    int count_files = 0;
00685 
00686    switch (argc) {
00687    case 5:
00688       if (!strcasecmp(argv[3], "like")) {
00689          if (regcomp(&regexbuf, argv[4], REG_EXTENDED | REG_NOSUB))
00690             return RESULT_SHOWUSAGE;
00691          havepattern = 1;
00692       } else
00693          return RESULT_SHOWUSAGE;
00694       break;
00695    case 4:
00696       havename = 1;
00697       break;
00698    case 3:
00699       break;
00700    default:
00701       return RESULT_SHOWUSAGE;
00702    }
00703 
00704    ast_cli(fd, FORMAT, "File", "Revision");
00705    ast_cli(fd, FORMAT, "----", "--------");
00706    AST_LIST_LOCK(&file_versions);
00707    AST_LIST_TRAVERSE(&file_versions, iterator, list) {
00708       if (havename && strcasecmp(iterator->file, argv[3]))
00709          continue;
00710 
00711       if (havepattern && regexec(&regexbuf, iterator->file, 0, NULL, 0))
00712          continue;
00713 
00714       ast_cli(fd, FORMAT, iterator->file, iterator->version);
00715       count_files++;
00716       if (havename)
00717          break;
00718    }
00719    AST_LIST_UNLOCK(&file_versions);
00720    if (!havename) {
00721       ast_cli(fd, "%d files listed.\n", count_files);
00722    }
00723 
00724    if (havepattern)
00725       regfree(&regexbuf);
00726 
00727    return RESULT_SUCCESS;
00728 #undef FORMAT
00729 }
00730 
00731 static int handle_show_version_files(int fd, int argc, char *argv[])
00732 {
00733 #define FORMAT "%-25.25s %-40.40s\n"
00734    struct file_version *iterator;
00735    regex_t regexbuf;
00736    int havepattern = 0;
00737    int havename = 0;
00738    int count_files = 0;
00739 
00740    switch (argc) {
00741    case 6:
00742       if (!strcasecmp(argv[4], "like")) {
00743          if (regcomp(&regexbuf, argv[5], REG_EXTENDED | REG_NOSUB))
00744             return RESULT_SHOWUSAGE;
00745          havepattern = 1;
00746       } else
00747          return RESULT_SHOWUSAGE;
00748       break;
00749    case 5:
00750       havename = 1;
00751       break;
00752    case 4:
00753       break;
00754    default:
00755       return RESULT_SHOWUSAGE;
00756    }
00757 
00758    ast_cli(fd, FORMAT, "File", "Revision");
00759    ast_cli(fd, FORMAT, "----", "--------");
00760    AST_LIST_LOCK(&file_versions);
00761    AST_LIST_TRAVERSE(&file_versions, iterator, list) {
00762       if (havename && strcasecmp(iterator->file, argv[4]))
00763          continue;
00764       
00765       if (havepattern && regexec(&regexbuf, iterator->file, 0, NULL, 0))
00766          continue;
00767 
00768       ast_cli(fd, FORMAT, iterator->file, iterator->version);
00769       count_files++;
00770       if (havename)
00771          break;
00772    }
00773    AST_LIST_UNLOCK(&file_versions);
00774    if (!havename) {
00775       ast_cli(fd, "%d files listed.\n", count_files);
00776    }
00777 
00778    if (havepattern)
00779       regfree(&regexbuf);
00780 
00781    return RESULT_SUCCESS;
00782 #undef FORMAT
00783 }
00784 
00785 static char *complete_show_version_files_deprecated(const char *line, const char *word, int pos, int state)
00786 {
00787    struct file_version *find;
00788    int which = 0;
00789    char *ret = NULL;
00790    int matchlen = strlen(word);
00791 
00792    if (pos != 3)
00793       return NULL;
00794 
00795    AST_LIST_LOCK(&file_versions);
00796    AST_LIST_TRAVERSE(&file_versions, find, list) {
00797       if (!strncasecmp(word, find->file, matchlen) && ++which > state) {
00798          ret = ast_strdup(find->file);
00799          break;
00800       }
00801    }
00802    AST_LIST_UNLOCK(&file_versions);
00803 
00804    return ret;
00805 }
00806 
00807 static char *complete_show_version_files(const char *line, const char *word, int pos, int state)
00808 {
00809    struct file_version *find;
00810    int which = 0;
00811    char *ret = NULL;
00812    int matchlen = strlen(word);
00813    
00814    if (pos != 4)
00815       return NULL;
00816 
00817    AST_LIST_LOCK(&file_versions);
00818    AST_LIST_TRAVERSE(&file_versions, find, list) {
00819       if (!strncasecmp(word, find->file, matchlen) && ++which > state) {
00820          ret = ast_strdup(find->file);
00821          break;
00822       }
00823    }
00824    AST_LIST_UNLOCK(&file_versions);
00825 
00826    return ret;
00827 }
00828 
00829 #endif /* ! LOW_MEMORY */
00830 
00831 int ast_register_atexit(void (*func)(void))
00832 {
00833    struct ast_atexit *ae;
00834 
00835    if (!(ae = ast_calloc(1, sizeof(*ae))))
00836       return -1;
00837 
00838    ae->func = func;
00839 
00840    ast_unregister_atexit(func);  
00841 
00842    AST_LIST_LOCK(&atexits);
00843    AST_LIST_INSERT_HEAD(&atexits, ae, list);
00844    AST_LIST_UNLOCK(&atexits);
00845 
00846    return 0;
00847 }
00848 
00849 void ast_unregister_atexit(void (*func)(void))
00850 {
00851    struct ast_atexit *ae = NULL;
00852 
00853    AST_LIST_LOCK(&atexits);
00854    AST_LIST_TRAVERSE_SAFE_BEGIN(&atexits, ae, list) {
00855       if (ae->func == func) {
00856          AST_LIST_REMOVE_CURRENT(&atexits, list);
00857          break;
00858       }
00859    }
00860    AST_LIST_TRAVERSE_SAFE_END
00861    AST_LIST_UNLOCK(&atexits);
00862 
00863    if (ae)
00864       free(ae);
00865 }
00866 
00867 /* Sending commands from consoles back to the daemon requires a terminating NULL */
00868 static int fdsend(int fd, const char *s)
00869 {
00870    return write(fd, s, strlen(s) + 1);
00871 }
00872 
00873 /* Sending messages from the daemon back to the display requires _excluding_ the terminating NULL */
00874 static int fdprint(int fd, const char *s)
00875 {
00876    return write(fd, s, strlen(s));
00877 }
00878 
00879 /*! \brief NULL handler so we can collect the child exit status */
00880 static void _null_sig_handler(int signal)
00881 {
00882 
00883 }
00884 
00885 static struct sigaction null_sig_handler = {
00886    .sa_handler = _null_sig_handler,
00887    .sa_flags = SA_RESTART,
00888 };
00889 
00890 AST_MUTEX_DEFINE_STATIC(safe_system_lock);
00891 /*! \brief Keep track of how many threads are currently trying to wait*() on
00892  *  a child process */
00893 static unsigned int safe_system_level = 0;
00894 static struct sigaction safe_system_prev_handler;
00895 
00896 void ast_replace_sigchld(void)
00897 {
00898    unsigned int level;
00899 
00900    ast_mutex_lock(&safe_system_lock);
00901    level = safe_system_level++;
00902 
00903    /* only replace the handler if it has not already been done */
00904    if (level == 0) {
00905       sigaction(SIGCHLD, &null_sig_handler, &safe_system_prev_handler);
00906    }
00907 
00908    ast_mutex_unlock(&safe_system_lock);
00909 }
00910 
00911 void ast_unreplace_sigchld(void)
00912 {
00913    unsigned int level;
00914 
00915    ast_mutex_lock(&safe_system_lock);
00916    level = --safe_system_level;
00917 
00918    /* only restore the handler if we are the last one */
00919    if (level == 0) {
00920       sigaction(SIGCHLD, &safe_system_prev_handler, NULL);
00921    }
00922 
00923    ast_mutex_unlock(&safe_system_lock);
00924 }
00925 
00926 int ast_safe_system(const char *s)
00927 {
00928    pid_t pid;
00929 #ifdef HAVE_WORKING_FORK
00930    int x;
00931 #endif
00932    int res;
00933    struct rusage rusage;
00934    int status;
00935 
00936 #if defined(HAVE_WORKING_FORK) || defined(HAVE_WORKING_VFORK)
00937    ast_replace_sigchld();
00938 
00939 #ifdef HAVE_WORKING_FORK
00940    pid = fork();
00941 #else
00942    pid = vfork();
00943 #endif   
00944 
00945    if (pid == 0) {
00946 #ifdef HAVE_CAP
00947       cap_t cap = cap_from_text("cap_net_admin-eip");
00948 
00949       if (cap_set_proc(cap)) {
00950          /* Careful with order! Logging cannot happen after we close FDs */
00951          ast_log(LOG_WARNING, "Unable to remove capabilities.\n");
00952       }
00953       cap_free(cap);
00954 #endif
00955 #ifdef HAVE_WORKING_FORK
00956       if (ast_opt_high_priority)
00957          ast_set_priority(0);
00958       /* Close file descriptors and launch system command */
00959       for (x = STDERR_FILENO + 1; x < 4096; x++)
00960          close(x);
00961 #endif
00962       execl("/bin/sh", "/bin/sh", "-c", s, (char *) NULL);
00963       _exit(1);
00964    } else if (pid > 0) {
00965       for(;;) {
00966          res = wait4(pid, &status, 0, &rusage);
00967          if (res > -1) {
00968             res = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
00969             break;
00970          } else if (errno != EINTR) 
00971             break;
00972       }
00973    } else {
00974       ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno));
00975       res = -1;
00976    }
00977 
00978    ast_unreplace_sigchld();
00979 #else /* !defined(HAVE_WORKING_FORK) && !defined(HAVE_WORKING_VFORK) */
00980    res = -1;
00981 #endif
00982 
00983    return res;
00984 }
00985 
00986 /*!
00987  * \brief mute or unmute a console from logging
00988  */
00989 void ast_console_toggle_mute(int fd, int silent) {
00990    int x;
00991    for (x = 0;x < AST_MAX_CONNECTS; x++) {
00992       if (fd == consoles[x].fd) {
00993          if (consoles[x].mute) {
00994             consoles[x].mute = 0;
00995             if (!silent)
00996                ast_cli(fd, "Console is not muted anymore.\n");
00997          } else {
00998             consoles[x].mute = 1;
00999             if (!silent)
01000                ast_cli(fd, "Console is muted.\n");
01001          }
01002          return;
01003       }
01004    }
01005    ast_cli(fd, "Couldn't find remote console.\n");
01006 }
01007 
01008 /*!
01009  * \brief log the string to all attached console clients
01010  */
01011 static void ast_network_puts_mutable(const char *string)
01012 {
01013    int x;
01014    for (x = 0;x < AST_MAX_CONNECTS; x++) {
01015       if (consoles[x].mute)
01016          continue;
01017       if (consoles[x].fd > -1) 
01018          fdprint(consoles[x].p[1], string);
01019    }
01020 }
01021 
01022 /*!
01023  * \brief log the string to the console, and all attached
01024  * console clients
01025  */
01026 void ast_console_puts_mutable(const char *string)
01027 {
01028    fputs(string, stdout);
01029    fflush(stdout);
01030    ast_network_puts_mutable(string);
01031 }
01032 
01033 /*!
01034  * \brief write the string to all attached console clients
01035  */
01036 static void ast_network_puts(const char *string)
01037 {
01038    int x;
01039    for (x=0; x < AST_MAX_CONNECTS; x++) {
01040       if (consoles[x].fd > -1) 
01041          fdprint(consoles[x].p[1], string);
01042    }
01043 }
01044 
01045 /*!
01046  * write the string to the console, and all attached
01047  * console clients
01048  */
01049 void ast_console_puts(const char *string)
01050 {
01051    fputs(string, stdout);
01052    fflush(stdout);
01053    ast_network_puts(string);
01054 }
01055 
01056 static void network_verboser(const char *s)
01057 {
01058    ast_network_puts_mutable(s);
01059 }
01060 
01061 static pthread_t lthread;
01062 
01063 static void *netconsole(void *vconsole)
01064 {
01065    struct console *con = vconsole;
01066    char hostname[MAXHOSTNAMELEN] = "";
01067    char tmp[512];
01068    int res;
01069    struct pollfd fds[2];
01070    
01071    if (gethostname(hostname, sizeof(hostname)-1))
01072       ast_copy_string(hostname, "<Unknown>", sizeof(hostname));
01073    snprintf(tmp, sizeof(tmp), "%s/%ld/%s\n", hostname, (long)ast_mainpid, ASTERISK_VERSION);
01074    fdprint(con->fd, tmp);
01075    for(;;) {
01076       fds[0].fd = con->fd;
01077       fds[0].events = POLLIN;
01078       fds[0].revents = 0;
01079       fds[1].fd = con->p[0];
01080       fds[1].events = POLLIN;
01081       fds[1].revents = 0;
01082 
01083       res = ast_poll(fds, 2, -1);
01084       if (res < 0) {
01085          if (errno != EINTR)
01086             ast_log(LOG_WARNING, "poll returned < 0: %s\n", strerror(errno));
01087          continue;
01088       }
01089       if (fds[0].revents) {
01090          res = read(con->fd, tmp, sizeof(tmp) - 1);
01091          if (res < 1) {
01092             break;
01093          }
01094          tmp[res] = 0;
01095          ast_cli_command_multiple(con->fd, res, tmp);
01096       }
01097       if (fds[1].revents) {
01098          res = read(con->p[0], tmp, sizeof(tmp));
01099          if (res < 1) {
01100             ast_log(LOG_ERROR, "read returned %d\n", res);
01101             break;
01102          }
01103          res = write(con->fd, tmp, res);
01104          if (res < 1)
01105             break;
01106       }
01107    }
01108    if (option_verbose > 2) 
01109       ast_verbose(VERBOSE_PREFIX_3 "Remote UNIX connection disconnected\n");
01110    close(con->fd);
01111    close(con->p[0]);
01112    close(con->p[1]);
01113    con->fd = -1;
01114    
01115    return NULL;
01116 }
01117 
01118 static void *listener(void *unused)
01119 {
01120    struct sockaddr_un sunaddr;
01121    int s;
01122    socklen_t len;
01123    int x;
01124    int flags;
01125    struct pollfd fds[1];
01126    pthread_attr_t attr;
01127    pthread_attr_init(&attr);
01128    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
01129    for (;;) {
01130       if (ast_socket < 0)
01131          return NULL;
01132       fds[0].fd = ast_socket;
01133       fds[0].events = POLLIN;
01134       s = ast_poll(fds, 1, -1);
01135       pthread_testcancel();
01136       if (s < 0) {
01137          if (errno != EINTR)
01138             ast_log(LOG_WARNING, "poll returned error: %s\n", strerror(errno));
01139          continue;
01140       }
01141       len = sizeof(sunaddr);
01142       s = accept(ast_socket, (struct sockaddr *)&sunaddr, &len);
01143       if (s < 0) {
01144          if (errno != EINTR)
01145             ast_log(LOG_WARNING, "Accept returned %d: %s\n", s, strerror(errno));
01146       } else {
01147          for (x = 0; x < AST_MAX_CONNECTS; x++) {
01148             if (consoles[x].fd < 0) {
01149                if (socketpair(AF_LOCAL, SOCK_STREAM, 0, consoles[x].p)) {
01150                   ast_log(LOG_ERROR, "Unable to create pipe: %s\n", strerror(errno));
01151                   consoles[x].fd = -1;
01152                   fdprint(s, "Server failed to create pipe\n");
01153                   close(s);
01154                   break;
01155                }
01156                flags = fcntl(consoles[x].p[1], F_GETFL);
01157                fcntl(consoles[x].p[1], F_SETFL, flags | O_NONBLOCK);
01158                consoles[x].fd = s;
01159                consoles[x].mute = 1; /* Default is muted, we will un-mute if necessary */
01160                if (ast_pthread_create_background(&consoles[x].t, &attr, netconsole, &consoles[x])) {
01161                   ast_log(LOG_ERROR, "Unable to spawn thread to handle connection: %s\n", strerror(errno));
01162                   close(consoles[x].p[0]);
01163                   close(consoles[x].p[1]);
01164                   consoles[x].fd = -1;
01165                   fdprint(s, "Server failed to spawn thread\n");
01166                   close(s);
01167                }
01168                break;
01169             }
01170          }
01171          if (x >= AST_MAX_CONNECTS) {
01172             fdprint(s, "No more connections allowed\n");
01173             ast_log(LOG_WARNING, "No more connections allowed\n");
01174             close(s);
01175          } else if (consoles[x].fd > -1) {
01176             if (option_verbose > 2) 
01177                ast_verbose(VERBOSE_PREFIX_3 "Remote UNIX connection\n");
01178          }
01179       }
01180    }
01181    return NULL;
01182 }
01183 
01184 static int ast_makesocket(void)
01185 {
01186    struct sockaddr_un sunaddr;
01187    int res;
01188    int x;
01189    uid_t uid = -1;
01190    gid_t gid = -1;
01191 
01192    for (x = 0; x < AST_MAX_CONNECTS; x++) 
01193       consoles[x].fd = -1;
01194    unlink(ast_config_AST_SOCKET);
01195    ast_socket = socket(PF_LOCAL, SOCK_STREAM, 0);
01196    if (ast_socket < 0) {
01197       ast_log(LOG_WARNING, "Unable to create control socket: %s\n", strerror(errno));
01198       return -1;
01199    }     
01200    memset(&sunaddr, 0, sizeof(sunaddr));
01201    sunaddr.sun_family = AF_LOCAL;
01202    ast_copy_string(sunaddr.sun_path, ast_config_AST_SOCKET, sizeof(sunaddr.sun_path));
01203    res = bind(ast_socket, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
01204    if (res) {
01205       ast_log(LOG_WARNING, "Unable to bind socket to %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
01206       close(ast_socket);
01207       ast_socket = -1;
01208       return -1;
01209    }
01210    res = listen(ast_socket, 2);
01211    if (res < 0) {
01212       ast_log(LOG_WARNING, "Unable to listen on socket %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
01213       close(ast_socket);
01214       ast_socket = -1;
01215       return -1;
01216    }
01217    ast_register_verbose(network_verboser);
01218    ast_pthread_create_background(&lthread, NULL, listener, NULL);
01219 
01220    if (!ast_strlen_zero(ast_config_AST_CTL_OWNER)) {
01221       struct passwd *pw;
01222       if ((pw = getpwnam(ast_config_AST_CTL_OWNER)) == NULL) {
01223          ast_log(LOG_WARNING, "Unable to find uid of user %s\n", ast_config_AST_CTL_OWNER);
01224       } else {
01225          uid = pw->pw_uid;
01226       }
01227    }
01228       
01229    if (!ast_strlen_zero(ast_config_AST_CTL_GROUP)) {
01230       struct group *grp;
01231       if ((grp = getgrnam(ast_config_AST_CTL_GROUP)) == NULL) {
01232          ast_log(LOG_WARNING, "Unable to find gid of group %s\n", ast_config_AST_CTL_GROUP);
01233       } else {
01234          gid = grp->gr_gid;
01235       }
01236    }
01237 
01238    if (chown(ast_config_AST_SOCKET, uid, gid) < 0)
01239       ast_log(LOG_WARNING, "Unable to change ownership of %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
01240 
01241    if (!ast_strlen_zero(ast_config_AST_CTL_PERMISSIONS)) {
01242       int p1;
01243       mode_t p;
01244       sscanf(ast_config_AST_CTL_PERMISSIONS, "%30o", &p1);
01245       p = p1;
01246       if ((chmod(ast_config_AST_SOCKET, p)) < 0)
01247          ast_log(LOG_WARNING, "Unable to change file permissions of %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
01248    }
01249 
01250    return 0;
01251 }
01252 
01253 static int ast_tryconnect(void)
01254 {
01255    struct sockaddr_un sunaddr;
01256    int res;
01257    ast_consock = socket(PF_LOCAL, SOCK_STREAM, 0);
01258    if (ast_consock < 0) {
01259       ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno));
01260       return 0;
01261    }
01262    memset(&sunaddr, 0, sizeof(sunaddr));
01263    sunaddr.sun_family = AF_LOCAL;
01264    ast_copy_string(sunaddr.sun_path, (char *)ast_config_AST_SOCKET, sizeof(sunaddr.sun_path));
01265    res = connect(ast_consock, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
01266    if (res) {
01267       close(ast_consock);
01268       ast_consock = -1;
01269       return 0;
01270    } else
01271       return 1;
01272 }
01273 
01274 /*! \brief Urgent handler
01275 
01276  Called by soft_hangup to interrupt the poll, read, or other
01277  system call.  We don't actually need to do anything though.  
01278  Remember: Cannot EVER ast_log from within a signal handler 
01279  */
01280 static void _urg_handler(int num)
01281 {
01282    return;
01283 }
01284 
01285 static struct sigaction urg_handler = {
01286    .sa_handler = _urg_handler,
01287    .sa_flags = SA_RESTART,
01288 };
01289 
01290 static void _hup_handler(int num)
01291 {
01292    int a = 0;
01293    if (option_verbose > 1) 
01294       printf("Received HUP signal -- Reloading configs\n");
01295    if (restartnow)
01296       execvp(_argv[0], _argv);
01297    sig_flags.need_reload = 1;
01298    if (sig_alert_pipe[1] != -1) {
01299       if (write(sig_alert_pipe[1], &a, sizeof(a)) < 0) {
01300          fprintf(stderr, "hup_handler: write() failed: %s\n", strerror(errno));
01301       }
01302    }
01303 }
01304 
01305 static struct sigaction hup_handler = {
01306    .sa_handler = _hup_handler,
01307    .sa_flags = SA_RESTART,
01308 };
01309 
01310 static void _child_handler(int sig)
01311 {
01312    /* Must not ever ast_log or ast_verbose within signal handler */
01313    int n, status;
01314 
01315    /*
01316     * Reap all dead children -- not just one
01317     */
01318    for (n = 0; wait4(-1, &status, WNOHANG, NULL) > 0; n++)
01319       ;
01320    if (n == 0 && option_debug)   
01321       printf("Huh?  Child handler, but nobody there?\n");
01322 }
01323 
01324 static struct sigaction child_handler = {
01325    .sa_handler = _child_handler,
01326    .sa_flags = SA_RESTART,
01327 };
01328 
01329 /*! \brief Set maximum open files */
01330 static void set_ulimit(int value)
01331 {
01332    struct rlimit l = {0, 0};
01333    
01334    if (value <= 0) {
01335       ast_log(LOG_WARNING, "Unable to change max files open to invalid value %i\n",value);
01336       return;
01337    }
01338    
01339    l.rlim_cur = value;
01340    l.rlim_max = value;
01341    
01342    if (setrlimit(RLIMIT_NOFILE, &l)) {
01343       ast_log(LOG_WARNING, "Unable to disable core size resource limit: %s\n",strerror(errno));
01344       return;
01345    }
01346    ast_log(LOG_NOTICE, "Setting max files open to %d\n",value);
01347    return;
01348 }
01349 
01350 /*! \brief Set an X-term or screen title */
01351 static void set_title(char *text)
01352 {
01353    if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
01354       fprintf(stdout, "\033]2;%s\007", text);
01355 }
01356 
01357 static void set_icon(char *text)
01358 {
01359    if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
01360       fprintf(stdout, "\033]1;%s\007", text);
01361 }
01362 
01363 /*! \brief We set ourselves to a high priority, that we might pre-empt everything
01364    else.  If your PBX has heavy activity on it, this is a good thing.  */
01365 int ast_set_priority(int pri)
01366 {
01367    struct sched_param sched;
01368    memset(&sched, 0, sizeof(sched));
01369 #ifdef __linux__
01370    if (pri) {  
01371       sched.sched_priority = 10;
01372       if (sched_setscheduler(0, SCHED_RR, &sched)) {
01373          ast_log(LOG_WARNING, "Unable to set high priority\n");
01374          return -1;
01375       } else
01376          if (option_verbose)
01377             ast_verbose("Set to realtime thread\n");
01378    } else {
01379       sched.sched_priority = 0;
01380       /* According to the manpage, these parameters can never fail. */
01381       sched_setscheduler(0, SCHED_OTHER, &sched);
01382    }
01383 #else
01384    if (pri) {
01385       if (setpriority(PRIO_PROCESS, 0, -10) == -1) {
01386          ast_log(LOG_WARNING, "Unable to set high priority\n");
01387          return -1;
01388       } else
01389          if (option_verbose)
01390             ast_verbose("Set to high priority\n");
01391    } else {
01392       /* According to the manpage, these parameters can never fail. */
01393       setpriority(PRIO_PROCESS, 0, 0);
01394    }
01395 #endif
01396    return 0;
01397 }
01398 
01399 static void ast_run_atexits(void)
01400 {
01401    struct ast_atexit *ae;
01402    AST_LIST_LOCK(&atexits);
01403    AST_LIST_TRAVERSE(&atexits, ae, list) {
01404       if (ae->func) 
01405          ae->func();
01406    }
01407    AST_LIST_UNLOCK(&atexits);
01408 }
01409 
01410 static void quit_handler(int num, int nice, int safeshutdown, int restart)
01411 {
01412    char filename[80] = "";
01413    time_t s,e;
01414    int x;
01415    /* Try to get as many CDRs as possible submitted to the backend engines (if in batch mode) */
01416    ast_cdr_engine_term();
01417    if (safeshutdown) {
01418       shuttingdown = 1;
01419       if (!nice) {
01420          /* Begin shutdown routine, hanging up active channels */
01421          ast_begin_shutdown(1);
01422          if (option_verbose && ast_opt_console)
01423             ast_verbose("Beginning asterisk %s....\n", restart ? "restart" : "shutdown");
01424          time(&s);
01425          for (;;) {
01426             time(&e);
01427             /* Wait up to 15 seconds for all channels to go away */
01428             if ((e - s) > 15)
01429                break;
01430             if (!ast_active_channels())
01431                break;
01432             if (!shuttingdown)
01433                break;
01434             /* Sleep 1/10 of a second */
01435             usleep(100000);
01436          }
01437       } else {
01438          if (nice < 2)
01439             ast_begin_shutdown(0);
01440          if (option_verbose && ast_opt_console)
01441             ast_verbose("Waiting for inactivity to perform %s...\n", restart ? "restart" : "halt");
01442          for (;;) {
01443             if (!ast_active_channels())
01444                break;
01445             if (!shuttingdown)
01446                break;
01447             sleep(1);
01448          }
01449       }
01450 
01451       if (!shuttingdown) {
01452          if (option_verbose && ast_opt_console)
01453             ast_verbose("Asterisk %s cancelled.\n", restart ? "restart" : "shutdown");
01454          return;
01455       }
01456 
01457       if (nice)
01458          ast_module_shutdown();
01459    }
01460    if (ast_opt_console || ast_opt_remote) {
01461       pthread_t thisthread = pthread_self();
01462       if (getenv("HOME")) {
01463          snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
01464       }
01465       if (!ast_strlen_zero(filename)) {
01466          ast_el_write_history(filename);
01467       }
01468       if (consolethread == AST_PTHREADT_NULL || consolethread == thisthread || mon_sig_flags == thisthread) {
01469          /* Only end if we are the consolethread or signal handler, otherwise there's a race with that thread. */
01470          if (el != NULL) {
01471             el_end(el);
01472          }
01473          if (el_hist != NULL) {
01474             history_end(el_hist);
01475          }
01476       }
01477    }
01478    if (option_verbose)
01479       ast_verbose("Executing last minute cleanups\n");
01480    ast_run_atexits();
01481    /* Called on exit */
01482    if (option_verbose && ast_opt_console)
01483       ast_verbose("Asterisk %s ending (%d).\n", ast_active_channels() ? "uncleanly" : "cleanly", num);
01484    if (option_debug)
01485       ast_log(LOG_DEBUG, "Asterisk ending (%d).\n", num);
01486    manager_event(EVENT_FLAG_SYSTEM, "Shutdown", "Shutdown: %s\r\nRestart: %s\r\n", ast_active_channels() ? "Uncleanly" : "Cleanly", restart ? "True" : "False");
01487    if (ast_socket > -1) {
01488       pthread_cancel(lthread);
01489       close(ast_socket);
01490       ast_socket = -1;
01491       unlink(ast_config_AST_SOCKET);
01492    }
01493    if (ast_consock > -1)
01494       close(ast_consock);
01495    if (!ast_opt_remote)
01496       unlink(ast_config_AST_PID);
01497    printf("%s", term_quit());
01498    if (restart) {
01499       if (option_verbose || ast_opt_console)
01500          ast_verbose("Preparing for Asterisk restart...\n");
01501       /* Mark all FD's for closing on exec */
01502       for (x=3; x < 32768; x++) {
01503          fcntl(x, F_SETFD, FD_CLOEXEC);
01504       }
01505       if (option_verbose || ast_opt_console)
01506          ast_verbose("Asterisk is now restarting...\n");
01507       restartnow = 1;
01508 
01509       /* close logger */
01510       close_logger();
01511 
01512       /* If there is a consolethread running send it a SIGHUP 
01513          so it can execvp, otherwise we can do it ourselves */
01514       if ((consolethread != AST_PTHREADT_NULL) && (consolethread != pthread_self())) {
01515          pthread_kill(consolethread, SIGHUP);
01516          /* Give the signal handler some time to complete */
01517          sleep(2);
01518       } else
01519          execvp(_argv[0], _argv);
01520    
01521    } else {
01522       /* close logger */
01523       close_logger();
01524    }
01525    exit(0);
01526 }
01527 
01528 static void __quit_handler(int num)
01529 {
01530    int a = 0;
01531    sig_flags.need_quit = 1;
01532    if (sig_alert_pipe[1] != -1) {
01533       if (write(sig_alert_pipe[1], &a, sizeof(a)) < 0) {
01534          fprintf(stderr, "quit_handler: write() failed: %s\n", strerror(errno));
01535       }
01536    }
01537    /* There is no need to restore the signal handler here, since the app
01538     * is going to exit */
01539 }
01540 
01541 static void __remote_quit_handler(int num)
01542 {
01543    sig_flags.need_quit = 1;
01544 }
01545 
01546 static const char *fix_header(char *outbuf, int maxout, const char *s, char *cmp)
01547 {
01548    const char *c;
01549 
01550    /* Check for verboser preamble */
01551    if (*s == 127) {
01552       s++;
01553    }
01554 
01555    if (!strncmp(s, cmp, strlen(cmp))) {
01556       c = s + strlen(cmp);
01557       term_color(outbuf, cmp, COLOR_GRAY, 0, maxout);
01558       return c;
01559    }
01560    return NULL;
01561 }
01562 
01563 static void console_verboser(const char *s)
01564 {
01565    char tmp[80];
01566    const char *c = NULL;
01567 
01568    if ((c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_4)) ||
01569        (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_3)) ||
01570        (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_2)) ||
01571        (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_1))) {
01572       fputs(tmp, stdout);
01573       fputs(c, stdout);
01574    } else {
01575       if (*s == 127) {
01576          s++;
01577       }
01578       fputs(s, stdout);
01579    }
01580 
01581    fflush(stdout);
01582    
01583    /* Wake up a poll()ing console */
01584    if (ast_opt_console && consolethread != AST_PTHREADT_NULL)
01585       pthread_kill(consolethread, SIGURG);
01586 }
01587 
01588 static int ast_all_zeros(char *s)
01589 {
01590    while (*s) {
01591       if (*s > 32)
01592          return 0;
01593       s++;  
01594    }
01595    return 1;
01596 }
01597 
01598 static void consolehandler(char *s)
01599 {
01600    printf("%s", term_end());
01601    fflush(stdout);
01602 
01603    /* Called when readline data is available */
01604    if (!ast_all_zeros(s))
01605       ast_el_add_history(s);
01606    /* The real handler for bang */
01607    if (s[0] == '!') {
01608       if (s[1])
01609          ast_safe_system(s+1);
01610       else
01611          ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
01612    } else 
01613       ast_cli_command(STDOUT_FILENO, s);
01614 }
01615 
01616 static int remoteconsolehandler(char *s)
01617 {
01618    int ret = 0;
01619 
01620    /* Called when readline data is available */
01621    if (!ast_all_zeros(s))
01622       ast_el_add_history(s);
01623    /* The real handler for bang */
01624    if (s[0] == '!') {
01625       if (s[1])
01626          ast_safe_system(s+1);
01627       else
01628          ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
01629       ret = 1;
01630    }
01631    if ((strncasecmp(s, "quit", 4) == 0 || strncasecmp(s, "exit", 4) == 0) &&
01632        (s[4] == '\0' || isspace(s[4]))) {
01633       quit_handler(0, 0, 0, 0);
01634       ret = 1;
01635    }
01636 
01637    return ret;
01638 }
01639 
01640 static char abort_halt_help[] = 
01641 "Usage: abort shutdown\n"
01642 "       Causes Asterisk to abort an executing shutdown or restart, and resume normal\n"
01643 "       call operations.\n";
01644 
01645 static char shutdown_now_help[] = 
01646 "Usage: stop now\n"
01647 "       Shuts down a running Asterisk immediately, hanging up all active calls .\n";
01648 
01649 static char shutdown_gracefully_help[] = 
01650 "Usage: stop gracefully\n"
01651 "       Causes Asterisk to not accept new calls, and exit when all\n"
01652 "       active calls have terminated normally.\n";
01653 
01654 static char shutdown_when_convenient_help[] = 
01655 "Usage: stop when convenient\n"
01656 "       Causes Asterisk to perform a shutdown when all active calls have ended.\n";
01657 
01658 static char restart_now_help[] = 
01659 "Usage: restart now\n"
01660 "       Causes Asterisk to hangup all calls and exec() itself performing a cold\n"
01661 "       restart.\n";
01662 
01663 static char restart_gracefully_help[] = 
01664 "Usage: restart gracefully\n"
01665 "       Causes Asterisk to stop accepting new calls and exec() itself performing a cold\n"
01666 "       restart when all active calls have ended.\n";
01667 
01668 static char restart_when_convenient_help[] = 
01669 "Usage: restart when convenient\n"
01670 "       Causes Asterisk to perform a cold restart when all active calls have ended.\n";
01671 
01672 static char bang_help[] =
01673 "Usage: !<command>\n"
01674 "       Executes a given shell command\n";
01675 
01676 static char show_warranty_help[] =
01677 "Usage: core show warranty\n"
01678 "  Shows the warranty (if any) for this copy of Asterisk.\n";
01679 
01680 static char show_license_help[] =
01681 "Usage: core show license\n"
01682 "  Shows the license(s) for this copy of Asterisk.\n";
01683 
01684 static char version_help[] =
01685 "Usage: core show version\n"
01686 "       Shows Asterisk version information.\n";
01687 
01688 static int handle_version_deprecated(int fd, int argc, char *argv[])
01689 {
01690    if (argc != 2)
01691       return RESULT_SHOWUSAGE;
01692    ast_cli(fd, "Asterisk %s built by %s @ %s on a %s running %s on %s\n",
01693       ASTERISK_VERSION, ast_build_user, ast_build_hostname,
01694       ast_build_machine, ast_build_os, ast_build_date);
01695    return RESULT_SUCCESS;
01696 }
01697 
01698 static int handle_version(int fd, int argc, char *argv[])
01699 {
01700    if (argc != 3)
01701       return RESULT_SHOWUSAGE;
01702    ast_cli(fd, "Asterisk %s built by %s @ %s on a %s running %s on %s\n",
01703       ASTERISK_VERSION, ast_build_user, ast_build_hostname,
01704       ast_build_machine, ast_build_os, ast_build_date);
01705    return RESULT_SUCCESS;
01706 }
01707 
01708 #if 0
01709 static int handle_quit(int fd, int argc, char *argv[])
01710 {
01711    if (argc != 1)
01712       return RESULT_SHOWUSAGE;
01713    quit_handler(0, 0, 1, 0);
01714    return RESULT_SUCCESS;
01715 }
01716 #endif
01717 
01718 static int handle_shutdown_now(int fd, int argc, char *argv[])
01719 {
01720    if (argc != 2)
01721       return RESULT_SHOWUSAGE;
01722    quit_handler(0, 0 /* Not nice */, 1 /* safely */, 0 /* not restart */);
01723    return RESULT_SUCCESS;
01724 }
01725 
01726 static int handle_shutdown_gracefully(int fd, int argc, char *argv[])
01727 {
01728    if (argc != 2)
01729       return RESULT_SHOWUSAGE;
01730    quit_handler(0, 1 /* nicely */, 1 /* safely */, 0 /* no restart */);
01731    return RESULT_SUCCESS;
01732 }
01733 
01734 static int handle_shutdown_when_convenient(int fd, int argc, char *argv[])
01735 {
01736    if (argc != 3)
01737       return RESULT_SHOWUSAGE;
01738    ast_cli(fd, "Waiting for inactivity to perform halt\n");
01739    quit_handler(0, 2 /* really nicely */, 1 /* safely */, 0 /* don't restart */);
01740    return RESULT_SUCCESS;
01741 }
01742 
01743 static int handle_restart_now(int fd, int argc, char *argv[])
01744 {
01745    if (argc != 2)
01746       return RESULT_SHOWUSAGE;
01747    quit_handler(0, 0 /* not nicely */, 1 /* safely */, 1 /* restart */);
01748    return RESULT_SUCCESS;
01749 }
01750 
01751 static int handle_restart_gracefully(int fd, int argc, char *argv[])
01752 {
01753    if (argc != 2)
01754       return RESULT_SHOWUSAGE;
01755    quit_handler(0, 1 /* nicely */, 1 /* safely */, 1 /* restart */);
01756    return RESULT_SUCCESS;
01757 }
01758 
01759 static int handle_restart_when_convenient(int fd, int argc, char *argv[])
01760 {
01761    if (argc != 3)
01762       return RESULT_SHOWUSAGE;
01763    ast_cli(fd, "Waiting for inactivity to perform restart\n");
01764    quit_handler(0, 2 /* really nicely */, 1 /* safely */, 1 /* restart */);
01765    return RESULT_SUCCESS;
01766 }
01767 
01768 static int handle_abort_halt(int fd, int argc, char *argv[])
01769 {
01770    if (argc != 2)
01771       return RESULT_SHOWUSAGE;
01772    ast_cancel_shutdown();
01773    shuttingdown = 0;
01774    return RESULT_SUCCESS;
01775 }
01776 
01777 static int handle_bang(int fd, int argc, char *argv[])
01778 {
01779    return RESULT_SUCCESS;
01780 }
01781 static const char *warranty_lines[] = {
01782    "\n",
01783    "            NO WARRANTY\n",
01784    "\n",
01785    "BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\n",
01786    "FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN\n",
01787    "OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\n",
01788    "PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\n",
01789    "OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n",
01790    "MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS\n",
01791    "TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE\n",
01792    "PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\n",
01793    "REPAIR OR CORRECTION.\n",
01794    "\n",
01795    "IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\n",
01796    "WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\n",
01797    "REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\n",
01798    "INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\n",
01799    "OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\n",
01800    "TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\n",
01801    "YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\n",
01802    "PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\n",
01803    "POSSIBILITY OF SUCH DAMAGES.\n",
01804 };
01805 
01806 static int show_warranty(int fd, int argc, char *argv[])
01807 {
01808    int x;
01809 
01810    for (x = 0; x < ARRAY_LEN(warranty_lines); x++)
01811       ast_cli(fd, "%s", (char *) warranty_lines[x]);
01812 
01813    return RESULT_SUCCESS;
01814 }
01815 
01816 static const char *license_lines[] = {
01817    "\n",
01818    "This program is free software; you can redistribute it and/or modify\n",
01819    "it under the terms of the GNU General Public License version 2 as\n",
01820    "published by the Free Software Foundation.\n",
01821    "\n",
01822    "This program also contains components licensed under other licenses.\n",
01823    "They include:\n",
01824    "\n",
01825    "This program is distributed in the hope that it will be useful,\n",
01826    "but WITHOUT ANY WARRANTY; without even the implied warranty of\n",
01827    "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n",
01828    "GNU General Public License for more details.\n",
01829    "\n",
01830    "You should have received a copy of the GNU General Public License\n",
01831    "along with this program; if not, write to the Free Software\n",
01832    "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\n",
01833 };
01834 
01835 static int show_license(int fd, int argc, char *argv[])
01836 {
01837    int x;
01838 
01839    for (x = 0; x < ARRAY_LEN(license_lines); x++)
01840       ast_cli(fd, "%s", (char *) license_lines[x]);
01841 
01842    return RESULT_SUCCESS;
01843 }
01844 
01845 #define ASTERISK_PROMPT "*CLI> "
01846 
01847 #define ASTERISK_PROMPT2 "%s*CLI> "
01848 
01849 static struct ast_cli_entry cli_show_version_deprecated = {
01850    { "show", "version", NULL },
01851    handle_version_deprecated, "Display version info",
01852    version_help };
01853 
01854 #if !defined(LOW_MEMORY)
01855 static struct ast_cli_entry cli_show_version_files_deprecated = {
01856    { "show", "version", "files", NULL },
01857    handle_show_version_files_deprecated, NULL,
01858    NULL, complete_show_version_files_deprecated };
01859 
01860 static struct ast_cli_entry cli_show_profile_deprecated = {
01861    { "show", "profile", NULL },
01862    handle_show_profile_deprecated, NULL,
01863    NULL };
01864 
01865 static struct ast_cli_entry cli_clear_profile_deprecated = {
01866    { "clear", "profile", NULL },
01867    handle_show_profile_deprecated, NULL,
01868    NULL };
01869 #endif /* ! LOW_MEMORY */
01870 
01871 static struct ast_cli_entry cli_asterisk[] = {
01872    { { "abort", "halt", NULL },
01873    handle_abort_halt, "Cancel a running halt",
01874    abort_halt_help },
01875 
01876    { { "stop", "now", NULL },
01877    handle_shutdown_now, "Shut down Asterisk immediately",
01878    shutdown_now_help },
01879 
01880    { { "stop", "gracefully", NULL },
01881    handle_shutdown_gracefully, "Gracefully shut down Asterisk",
01882    shutdown_gracefully_help },
01883 
01884    { { "stop", "when", "convenient", NULL },
01885    handle_shutdown_when_convenient, "Shut down Asterisk at empty call volume",
01886    shutdown_when_convenient_help },
01887 
01888    { { "restart", "now", NULL },
01889    handle_restart_now, "Restart Asterisk immediately",
01890    restart_now_help },
01891 
01892    { { "restart", "gracefully", NULL },
01893    handle_restart_gracefully, "Restart Asterisk gracefully",
01894    restart_gracefully_help },
01895 
01896    { { "restart", "when", "convenient", NULL },
01897    handle_restart_when_convenient, "Restart Asterisk at empty call volume",
01898    restart_when_convenient_help },
01899 
01900    { { "core", "show", "warranty", NULL },
01901    show_warranty, "Show the warranty (if any) for this copy of Asterisk",
01902    show_warranty_help },
01903 
01904    { { "core", "show", "license", NULL },
01905    show_license, "Show the license(s) for this copy of Asterisk",
01906    show_license_help },
01907 
01908    { { "core", "show", "version", NULL },
01909    handle_version, "Display version info",
01910    version_help, NULL, &cli_show_version_deprecated },
01911 
01912    { { "!", NULL },
01913    handle_bang, "Execute a shell command",
01914    bang_help },
01915 
01916 #if !defined(LOW_MEMORY)
01917    { { "core", "show", "file", "version", NULL },
01918    handle_show_version_files, "List versions of files used to build Asterisk",
01919    show_version_files_help, complete_show_version_files, &cli_show_version_files_deprecated },
01920 
01921    { { "core", "show", "settings", NULL },
01922    handle_show_settings, "Show some core settings",
01923    show_settings_help },
01924 
01925    { { "core", "show", "threads", NULL },
01926    handle_show_threads, "Show running threads",
01927    show_threads_help },
01928 
01929    { { "core", "show", "sysinfo", NULL },
01930    handle_show_sysinfo, "Show System Information",
01931    show_sysinfo_help },
01932 
01933    { { "core", "show", "profile", NULL },
01934    handle_show_profile, "Display profiling info",
01935    NULL, NULL, &cli_show_profile_deprecated },
01936 
01937    { { "core", "clear", "profile", NULL },
01938    handle_show_profile, "Clear profiling info",
01939    NULL, NULL, &cli_clear_profile_deprecated },
01940 #endif /* ! LOW_MEMORY */
01941 };
01942 
01943 static int ast_el_read_char(EditLine *el, char *cp)
01944 {
01945    int num_read = 0;
01946    int lastpos = 0;
01947    struct pollfd fds[2];
01948    int res;
01949    int max;
01950 #define EL_BUF_SIZE 512
01951    char buf[EL_BUF_SIZE];
01952 
01953    for (;;) {
01954       max = 1;
01955       fds[0].fd = ast_consock;
01956       fds[0].events = POLLIN;
01957       if (!ast_opt_exec) {
01958          fds[1].fd = STDIN_FILENO;
01959          fds[1].events = POLLIN;
01960          max++;
01961       }
01962       res = ast_poll(fds, max, -1);
01963       if (res < 0) {
01964          if (sig_flags.need_quit)
01965             break;
01966          if (errno == EINTR)
01967             continue;
01968          ast_log(LOG_ERROR, "poll failed: %s\n", strerror(errno));
01969          break;
01970       }
01971 
01972       if (!ast_opt_exec && fds[1].revents) {
01973          num_read = read(STDIN_FILENO, cp, 1);
01974          if (num_read < 1) {
01975             break;
01976          } else 
01977             return (num_read);
01978       }
01979       if (fds[0].revents) {
01980          char *tmp;
01981          res = read(ast_consock, buf, sizeof(buf) - 1);
01982          /* if the remote side disappears exit */
01983          if (res < 1) {
01984             fprintf(stderr, "\nDisconnected from Asterisk server\n");
01985             if (!ast_opt_reconnect) {
01986                quit_handler(0, 0, 0, 0);
01987             } else {
01988                int tries;
01989                int reconnects_per_second = 20;
01990                fprintf(stderr, "Attempting to reconnect for 30 seconds\n");
01991                for (tries=0; tries < 30 * reconnects_per_second; tries++) {
01992                   if (ast_tryconnect()) {
01993                      fprintf(stderr, "Reconnect succeeded after %.3f seconds\n", 1.0 / reconnects_per_second * tries);
01994                      printf("%s", term_quit());
01995                      WELCOME_MESSAGE;
01996                      if (!ast_opt_mute)
01997                         fdsend(ast_consock, "logger mute silent");
01998                      else {
01999                         snprintf(tmp, sizeof(tmp), "log and verbose output currently muted ('logger unmute' to unmute)");
02000                         fdprint(ast_consock, tmp);
02001                      }
02002 
02003                      break;
02004                   } else {
02005                      usleep(1000000 / reconnects_per_second);
02006                   }
02007                }
02008                if (tries >= 30 * reconnects_per_second) {
02009                   fprintf(stderr, "Failed to reconnect for 30 seconds.  Quitting.\n");
02010                   quit_handler(0, 0, 0, 0);
02011                }
02012             }
02013          }
02014 
02015          buf[res] = '\0';
02016 
02017          /* Strip preamble from asynchronous events, too */
02018          for (tmp = buf; *tmp; tmp++) {
02019             if (*tmp == 127) {
02020                memmove(tmp, tmp + 1, strlen(tmp));
02021                tmp--;
02022                res--;
02023             }
02024          }
02025 
02026          /* Write over the CLI prompt */
02027          if (!ast_opt_exec && !lastpos) {
02028             if (write(STDOUT_FILENO, "\r", 5) < 0) {
02029             }
02030          }
02031          if (write(STDOUT_FILENO, buf, res) < 0) {
02032          }
02033          if ((res < EL_BUF_SIZE - 1) && ((buf[res-1] == '\n') || (buf[res-2] == '\n'))) {
02034             *cp = CC_REFRESH;
02035             return(1);
02036          } else {
02037             lastpos = 1;
02038          }
02039       }
02040    }
02041 
02042    *cp = '\0';
02043    return (0);
02044 }
02045 
02046 static char *cli_prompt(EditLine *el)
02047 {
02048    static char prompt[200];
02049    char *pfmt;
02050    int color_used = 0;
02051    char term_code[20];
02052 
02053    if ((pfmt = getenv("ASTERISK_PROMPT"))) {
02054       char *t = pfmt, *p = prompt;
02055       memset(prompt, 0, sizeof(prompt));
02056       while (*t != '\0' && *p < sizeof(prompt)) {
02057          if (*t == '%') {
02058             char hostname[MAXHOSTNAMELEN]="";
02059             int i;
02060             time_t ts;
02061             struct tm tm;
02062 #ifdef linux
02063             FILE *LOADAVG;
02064 #endif
02065             int fgcolor = COLOR_WHITE, bgcolor = COLOR_BLACK;
02066 
02067             t++;
02068             switch (*t) {
02069             case 'C': /* color */
02070                t++;
02071                if (sscanf(t, "%30d;%30d%n", &fgcolor, &bgcolor, &i) == 2) {
02072                   strncat(p, term_color_code(term_code, fgcolor, bgcolor, sizeof(term_code)),sizeof(prompt) - strlen(prompt) - 1);
02073                   t += i - 1;
02074                } else if (sscanf(t, "%30d%n", &fgcolor, &i) == 1) {
02075                   strncat(p, term_color_code(term_code, fgcolor, 0, sizeof(term_code)),sizeof(prompt) - strlen(prompt) - 1);
02076                   t += i - 1;
02077                }
02078 
02079                /* If the color has been reset correctly, then there's no need to reset it later */
02080                if ((fgcolor == COLOR_WHITE) && (bgcolor == COLOR_BLACK)) {
02081                   color_used = 0;
02082                } else {
02083                   color_used = 1;
02084                }
02085                break;
02086             case 'd': /* date */
02087                memset(&tm, 0, sizeof(tm));
02088                time(&ts);
02089                if (ast_localtime(&ts, &tm, NULL)) {
02090                   strftime(p, sizeof(prompt) - strlen(prompt), "%Y-%m-%d", &tm);
02091                }
02092                break;
02093             case 'h': /* hostname */
02094                if (!gethostname(hostname, sizeof(hostname) - 1)) {
02095                   strncat(p, hostname, sizeof(prompt) - strlen(prompt) - 1);
02096                } else {
02097                   strncat(p, "localhost", sizeof(prompt) - strlen(prompt) - 1);
02098                }
02099                break;
02100             case 'H': /* short hostname */
02101                if (!gethostname(hostname, sizeof(hostname) - 1)) {
02102                   for (i = 0; i < sizeof(hostname); i++) {
02103                      if (hostname[i] == '.') {
02104                         hostname[i] = '\0';
02105                         break;
02106                      }
02107                   }
02108                   strncat(p, hostname, sizeof(prompt) - strlen(prompt) - 1);
02109                } else {
02110                   strncat(p, "localhost", sizeof(prompt) - strlen(prompt) - 1);
02111                }
02112                break;
02113 #ifdef linux
02114             case 'l': /* load avg */
02115                t++;
02116                if ((LOADAVG = fopen("/proc/loadavg", "r"))) {
02117                   float avg1, avg2, avg3;
02118                   int actproc, totproc, npid, which;
02119 
02120                   if (fscanf(LOADAVG, "%30f %30f %30f %30d/%30d %30d",
02121                         &avg1, &avg2, &avg3, &actproc, &totproc, &npid) != 6) {
02122                      ast_log(LOG_WARNING, "parsing /proc/loadavg failed\n");
02123                      fclose(LOADAVG);
02124                      break;
02125                   }
02126                   if (sscanf(t, "%30d", &which) == 1) {
02127                      switch (which) {
02128                      case 1:
02129                         snprintf(p, sizeof(prompt) - strlen(prompt), "%.2f", avg1);
02130                         break;
02131                      case 2:
02132                         snprintf(p, sizeof(prompt) - strlen(prompt), "%.2f", avg2);
02133                         break;
02134                      case 3:
02135                         snprintf(p, sizeof(prompt) - strlen(prompt), "%.2f", avg3);
02136                         break;
02137                      case 4:
02138                         snprintf(p, sizeof(prompt) - strlen(prompt), "%d/%d", actproc, totproc);
02139                         break;
02140                      case 5:
02141                         snprintf(p, sizeof(prompt) - strlen(prompt), "%d", npid);
02142                         break;
02143                      }
02144                   }
02145                   fclose(LOADAVG);
02146                }
02147                break;
02148 #endif
02149             case 's': /* Asterisk system name (from asterisk.conf) */
02150                strncat(p, ast_config_AST_SYSTEM_NAME, sizeof(prompt) - strlen(prompt) - 1);
02151                break;
02152             case 't': /* time */
02153                memset(&tm, 0, sizeof(tm));
02154                time(&ts);
02155                if (ast_localtime(&ts, &tm, NULL)) {
02156                   strftime(p, sizeof(prompt) - strlen(prompt), "%H:%M:%S", &tm);
02157                }
02158                break;
02159             case '#': /* process console or remote? */
02160                if (!ast_opt_remote) {
02161                   strncat(p, "#", sizeof(prompt) - strlen(prompt) - 1);
02162                } else {
02163                   strncat(p, ">", sizeof(prompt) - strlen(prompt) - 1);
02164                }
02165                break;
02166             case '%': /* literal % */
02167                strncat(p, "%", sizeof(prompt) - strlen(prompt) - 1);
02168                break;
02169             case '\0': /* % is last character - prevent bug */
02170                t--;
02171                break;
02172             }
02173             while (*p != '\0') {
02174                p++;
02175             }
02176             t++;
02177          } else {
02178             *p = *t;
02179             p++;
02180             t++;
02181          }
02182       }
02183       if (color_used) {
02184          /* Force colors back to normal at end */
02185          term_color_code(term_code, COLOR_WHITE, COLOR_BLACK, sizeof(term_code));
02186          if (strlen(term_code) > sizeof(prompt) - strlen(prompt) - 1) {
02187             ast_copy_string(prompt + sizeof(prompt) - strlen(term_code) - 1, term_code, strlen(term_code) + 1);
02188          } else {
02189             /* This looks wrong, but we've already checked the length of term_code to ensure it's safe */
02190             strncat(p, term_code, sizeof(term_code));
02191          }
02192       }
02193    } else if (remotehostname)
02194       snprintf(prompt, sizeof(prompt), ASTERISK_PROMPT2, remotehostname);
02195    else
02196       ast_copy_string(prompt, ASTERISK_PROMPT, sizeof(prompt));
02197 
02198    return(prompt);   
02199 }
02200 
02201 static char **ast_el_strtoarr(char *buf)
02202 {
02203    char **match_list = NULL, *retstr;
02204    size_t match_list_len;
02205    int matches = 0;
02206 
02207    match_list_len = 1;
02208    while ( (retstr = strsep(&buf, " ")) != NULL) {
02209 
02210       if (!strcmp(retstr, AST_CLI_COMPLETE_EOF))
02211          break;
02212       if (matches + 1 >= match_list_len) {
02213          match_list_len <<= 1;
02214          if (!(match_list = ast_realloc(match_list, match_list_len * sizeof(char *)))) {
02215             /* TODO: Handle memory allocation failure */
02216          }
02217       }
02218 
02219       match_list[matches++] = ast_strdup(retstr);
02220    }
02221 
02222    if (!match_list)
02223       return (char **) NULL;
02224 
02225    if (matches >= match_list_len) {
02226       if (!(match_list = ast_realloc(match_list, (match_list_len + 1) * sizeof(char *)))) {
02227          /* TODO: Handle memory allocation failure */
02228       }
02229    }
02230 
02231    match_list[matches] = (char *) NULL;
02232 
02233    return match_list;
02234 }
02235 
02236 static int ast_el_sort_compare(const void *i1, const void *i2)
02237 {
02238    char *s1, *s2;
02239 
02240    s1 = ((char **)i1)[0];
02241    s2 = ((char **)i2)[0];
02242 
02243    return strcasecmp(s1, s2);
02244 }
02245 
02246 static int ast_cli_display_match_list(char **matches, int len, int max)
02247 {
02248    int i, idx, limit, count;
02249    int screenwidth = 0;
02250    int numoutput = 0, numoutputline = 0;
02251 
02252    screenwidth = ast_get_termcols(STDOUT_FILENO);
02253 
02254    /* find out how many entries can be put on one line, with two spaces between strings */
02255    limit = screenwidth / (max + 2);
02256    if (limit == 0)
02257       limit = 1;
02258 
02259    /* how many lines of output */
02260    count = len / limit;
02261    if (count * limit < len)
02262       count++;
02263 
02264    idx = 1;
02265 
02266    qsort(&matches[0], (size_t)(len), sizeof(char *), ast_el_sort_compare);
02267 
02268    for (; count > 0; count--) {
02269       numoutputline = 0;
02270       for (i=0; i < limit && matches[idx]; i++, idx++) {
02271 
02272          /* Don't print dupes */
02273          if ( (matches[idx+1] != NULL && strcmp(matches[idx], matches[idx+1]) == 0 ) ) {
02274             i--;
02275             ast_free(matches[idx]);
02276             matches[idx] = NULL;
02277             continue;
02278          }
02279 
02280          numoutput++;
02281          numoutputline++;
02282          fprintf(stdout, "%-*s  ", max, matches[idx]);
02283          ast_free(matches[idx]);
02284          matches[idx] = NULL;
02285       }
02286       if (numoutputline > 0)
02287          fprintf(stdout, "\n");
02288    }
02289 
02290    return numoutput;
02291 }
02292 
02293 
02294 static char *cli_complete(EditLine *el, int ch)
02295 {
02296    int len = 0;
02297    char *ptr;
02298    int nummatches = 0;
02299    char **matches;
02300    int retval = CC_ERROR;
02301    char buf[2048], savechr;
02302    int res;
02303 
02304    LineInfo *lf = (LineInfo *)el_line(el);
02305 
02306    savechr = *(char *)lf->cursor;
02307    *(char *)lf->cursor = '\0';
02308    ptr = (char *)lf->cursor;
02309    if (ptr) {
02310       while (ptr > lf->buffer) {
02311          if (isspace(*ptr)) {
02312             ptr++;
02313             break;
02314          }
02315          ptr--;
02316       }
02317    }
02318 
02319    len = lf->cursor - ptr;
02320 
02321    if (ast_opt_remote) {
02322       snprintf(buf, sizeof(buf),"_COMMAND NUMMATCHES \"%s\" \"%s\"", lf->buffer, ptr); 
02323       fdsend(ast_consock, buf);
02324       res = read(ast_consock, buf, sizeof(buf) - 1);
02325       buf[res] = '\0';
02326       nummatches = atoi(buf);
02327 
02328       if (nummatches > 0) {
02329          char *mbuf;
02330          int mlen = 0, maxmbuf = 2048;
02331          /* Start with a 2048 byte buffer */       
02332          if (!(mbuf = ast_malloc(maxmbuf))) {
02333             lf->cursor[0] = savechr;
02334             return (char *)(CC_ERROR);
02335          }
02336          snprintf(buf, sizeof(buf),"_COMMAND MATCHESARRAY \"%s\" \"%s\"", lf->buffer, ptr); 
02337          fdsend(ast_consock, buf);
02338          res = 0;
02339          mbuf[0] = '\0';
02340          while (!strstr(mbuf, AST_CLI_COMPLETE_EOF) && res != -1) {
02341             if (mlen + 1024 > maxmbuf) {
02342                /* Every step increment buffer 1024 bytes */
02343                maxmbuf += 1024;              
02344                if (!(mbuf = ast_realloc(mbuf, maxmbuf))) {
02345                   lf->cursor[0] = savechr;
02346                   return (char *)(CC_ERROR);
02347                }
02348             }
02349             /* Only read 1024 bytes at a time */
02350             res = read(ast_consock, mbuf + mlen, 1024);
02351             if (res > 0)
02352                mlen += res;
02353          }
02354          mbuf[mlen] = '\0';
02355 
02356          matches = ast_el_strtoarr(mbuf);
02357          ast_free(mbuf);
02358       } else
02359          matches = (char **) NULL;
02360    } else {
02361       char **p, *oldbuf=NULL;
02362       nummatches = 0;
02363       matches = ast_cli_completion_matches((char *)lf->buffer,ptr);
02364       for (p = matches; p && *p; p++) {
02365          if (!oldbuf || strcmp(*p,oldbuf))
02366             nummatches++;
02367          oldbuf = *p;
02368       }
02369    }
02370 
02371    if (matches) {
02372       int i;
02373       int matches_num, maxlen, match_len;
02374 
02375       if (matches[0][0] != '\0') {
02376          el_deletestr(el, (int) len);
02377          el_insertstr(el, matches[0]);
02378          retval = CC_REFRESH;
02379       }
02380 
02381       if (nummatches == 1) {
02382          /* Found an exact match */
02383          el_insertstr(el, " ");
02384          retval = CC_REFRESH;
02385       } else {
02386          /* Must be more than one match */
02387          for (i=1, maxlen=0; matches[i]; i++) {
02388             match_len = strlen(matches[i]);
02389             if (match_len > maxlen)
02390                maxlen = match_len;
02391          }
02392          matches_num = i - 1;
02393          if (matches_num >1) {
02394             fprintf(stdout, "\n");
02395             ast_cli_display_match_list(matches, nummatches, maxlen);
02396             retval = CC_REDISPLAY;
02397          } else { 
02398             el_insertstr(el," ");
02399             retval = CC_REFRESH;
02400          }
02401       }
02402       for (i = 0; matches[i]; i++)
02403          ast_free(matches[i]);
02404       ast_free(matches);
02405    }
02406 
02407    lf->cursor[0] = savechr;
02408 
02409    return (char *)(long)retval;
02410 }
02411 
02412 static int ast_el_initialize(void)
02413 {
02414    HistEvent ev;
02415    char *editor = getenv("AST_EDITOR");
02416 
02417    if (el != NULL)
02418       el_end(el);
02419    if (el_hist != NULL)
02420       history_end(el_hist);
02421 
02422    el = el_init("asterisk", stdin, stdout, stderr);
02423    el_set(el, EL_PROMPT, cli_prompt);
02424 
02425    el_set(el, EL_EDITMODE, 1);      
02426    el_set(el, EL_EDITOR, editor ? editor : "emacs");     
02427    el_hist = history_init();
02428    if (!el || !el_hist)
02429       return -1;
02430 
02431    /* setup history with 100 entries */
02432    history(el_hist, &ev, H_SETSIZE, 100);
02433 
02434    el_set(el, EL_HIST, history, el_hist);
02435 
02436    el_set(el, EL_ADDFN, "ed-complete", "Complete argument", cli_complete);
02437    /* Bind <tab> to command completion */
02438    el_set(el, EL_BIND, "^I", "ed-complete", NULL);
02439    /* Bind ? to command completion */
02440    el_set(el, EL_BIND, "?", "ed-complete", NULL);
02441    /* Bind ^D to redisplay */
02442    el_set(el, EL_BIND, "^D", "ed-redisplay", NULL);
02443 
02444    return 0;
02445 }
02446 
02447 static int ast_el_add_history(char *buf)
02448 {
02449    HistEvent ev;
02450 
02451    if (el_hist == NULL || el == NULL)
02452       ast_el_initialize();
02453    if (strlen(buf) > 256)
02454       return 0;
02455    return (history(el_hist, &ev, H_ENTER, buf));
02456 }
02457 
02458 static int ast_el_write_history(char *filename)
02459 {
02460    HistEvent ev;
02461 
02462    if (el_hist == NULL || el == NULL)
02463       ast_el_initialize();
02464 
02465    return (history(el_hist, &ev, H_SAVE, filename));
02466 }
02467 
02468 static int ast_el_read_history(char *filename)
02469 {
02470    char buf[256];
02471    FILE *f;
02472    int ret = -1;
02473 
02474    if (el_hist == NULL || el == NULL)
02475       ast_el_initialize();
02476 
02477    if ((f = fopen(filename, "r")) == NULL)
02478       return ret;
02479 
02480    while (!feof(f)) {
02481       if (!fgets(buf, sizeof(buf), f)) {
02482          continue;
02483       }
02484       if (!strcmp(buf, "_HiStOrY_V2_\n"))
02485          continue;
02486       if (ast_all_zeros(buf))
02487          continue;
02488       if ((ret = ast_el_add_history(buf)) == -1)
02489          break;
02490    }
02491    fclose(f);
02492 
02493    return ret;
02494 }
02495 
02496 static void ast_remotecontrol(char *data)
02497 {
02498    char buf[80];
02499    int res;
02500    char filename[80] = "";
02501    char *hostname;
02502    char *cpid;
02503    char *version;
02504    int pid;
02505    char tmp[80];
02506    char *stringp = NULL;
02507 
02508    char *ebuf;
02509    int num = 0;
02510 
02511    memset(&sig_flags, 0, sizeof(sig_flags));
02512    signal(SIGINT, __remote_quit_handler);
02513    signal(SIGTERM, __remote_quit_handler);
02514    signal(SIGHUP, __remote_quit_handler);
02515 
02516    if (read(ast_consock, buf, sizeof(buf)) < 0) {
02517       ast_log(LOG_ERROR, "read() failed: %s\n", strerror(errno));
02518       return;
02519    }
02520    if (data) {
02521       if (write(ast_consock, data, strlen(data) + 1) < 0) {
02522          ast_log(LOG_ERROR, "write() failed: %s\n", strerror(errno));
02523          if (sig_flags.need_quit == 1) {
02524             return;
02525          }
02526       }
02527    }
02528    stringp = buf;
02529    hostname = strsep(&stringp, "/");
02530    cpid = strsep(&stringp, "/");
02531    version = strsep(&stringp, "\n");
02532    if (!version)
02533       version = "<Version Unknown>";
02534    stringp = hostname;
02535    strsep(&stringp, ".");
02536    if (cpid)
02537       pid = atoi(cpid);
02538    else
02539       pid = -1;
02540    if (!data) {
02541       snprintf(tmp, sizeof(tmp), "core set verbose atleast %d", option_verbose);
02542       fdsend(ast_consock, tmp);
02543       snprintf(tmp, sizeof(tmp), "core set debug atleast %d", option_debug);
02544       fdsend(ast_consock, tmp);
02545       if (!ast_opt_mute)
02546          fdsend(ast_consock, "logger mute silent");
02547       else 
02548          printf("log and verbose output currently muted ('logger mute' to unmute)\n");
02549    }
02550    ast_verbose("Connected to Asterisk %s currently running on %s (pid = %d)\n", version, hostname, pid);
02551    remotehostname = hostname;
02552    if (getenv("HOME")) 
02553       snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
02554    if (el_hist == NULL || el == NULL)
02555       ast_el_initialize();
02556 
02557    el_set(el, EL_GETCFN, ast_el_read_char);
02558 
02559    if (!ast_strlen_zero(filename))
02560       ast_el_read_history(filename);
02561 
02562    if (ast_opt_exec && data) {  /* hack to print output then exit if asterisk -rx is used */
02563       struct pollfd fds;
02564       fds.fd = ast_consock;
02565       fds.events = POLLIN;
02566       fds.revents = 0;
02567       while (ast_poll(&fds, 1, 500) > 0) {
02568          char buf[512] = "", *curline = buf, *nextline;
02569          int not_written = 1;
02570 
02571          if (sig_flags.need_quit == 1) {
02572             break;
02573          }
02574 
02575          if (read(ast_consock, buf, sizeof(buf) - 1) <= 0) {
02576             break;
02577          }
02578 
02579          do {
02580             if ((nextline = strchr(curline, '\n'))) {
02581                nextline++;
02582             } else {
02583                nextline = strchr(curline, '\0');
02584             }
02585 
02586             /* Skip verbose lines */
02587             if (*curline != 127) {
02588                not_written = 0;
02589                if (write(STDOUT_FILENO, curline, nextline - curline) < 0) {
02590                   ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno));
02591                }
02592             }
02593             curline = nextline;
02594          } while (!ast_strlen_zero(curline));
02595 
02596          /* No non-verbose output in 500ms */
02597          if (not_written) {
02598             break;
02599          }
02600       }
02601       return;
02602    }
02603    for (;;) {
02604       ebuf = (char *)el_gets(el, &num);
02605 
02606       if (sig_flags.need_quit == 1) {
02607          break;
02608       }
02609 
02610       if (!ebuf && write(1, "", 1) < 0)
02611          break;
02612 
02613       if (!ast_strlen_zero(ebuf)) {
02614          if (ebuf[strlen(ebuf)-1] == '\n')
02615             ebuf[strlen(ebuf)-1] = '\0';
02616          if (!remoteconsolehandler(ebuf)) {
02617             /* Strip preamble from output */
02618             char *tmp;
02619             for (tmp = ebuf; *tmp; tmp++) {
02620                if (*tmp == 127) {
02621                   memmove(tmp, tmp + 1, strlen(tmp));
02622                   tmp--;
02623                }
02624             }
02625             res = write(ast_consock, ebuf, strlen(ebuf) + 1);
02626             if (res < 1) {
02627                ast_log(LOG_WARNING, "Unable to write: %s\n", strerror(errno));
02628                break;
02629             }
02630          }
02631       }
02632    }
02633    printf("\nDisconnected from Asterisk server\n");
02634 }
02635 
02636 static int show_version(void)
02637 {
02638    printf("Asterisk " ASTERISK_VERSION "\n");
02639    return 0;
02640 }
02641 
02642 static int show_cli_help(void) {
02643    printf("Asterisk " ASTERISK_VERSION ", Copyright (C) 1999 - 2010, Digium, Inc. and others.\n");
02644    printf("Usage: asterisk [OPTIONS]\n");
02645    printf("Valid Options:\n");
02646    printf("   -V              Display version number and exit\n");
02647    printf("   -C <configfile> Use an alternate configuration file\n");
02648    printf("   -G <group>      Run as a group other than the caller\n");
02649    printf("   -U <user>       Run as a user other than the caller\n");
02650    printf("   -c              Provide console CLI\n");
02651    printf("   -d              Enable extra debugging\n");
02652 #if HAVE_WORKING_FORK
02653    printf("   -f              Do not fork\n");
02654    printf("   -F              Always fork\n");
02655 #endif
02656    printf("   -g              Dump core in case of a crash\n");
02657    printf("   -h              This help screen\n");
02658    printf("   -i              Initialize crypto keys at startup\n");
02659    printf("   -I              Enable internal timing if %s timer is available\n", dahdi_chan_name);
02660    printf("   -L <load>       Limit the maximum load average before rejecting new calls\n");
02661    printf("   -M <value>      Limit the maximum number of calls to the specified value\n");
02662    printf("   -m              Mute debugging and console output on the console\n");
02663    printf("   -n              Disable console colorization\n");
02664    printf("   -p              Run as pseudo-realtime thread\n");
02665    printf("   -q              Quiet mode (suppress output)\n");
02666    printf("   -r              Connect to Asterisk on this machine\n");
02667    printf("   -R              Same as -r, except attempt to reconnect if disconnected\n");
02668    printf("   -t              Record soundfiles in /var/tmp and move them where they\n");
02669    printf("                   belong after they are done\n");
02670    printf("   -T              Display the time in [Mmm dd hh:mm:ss] format for each line\n");
02671    printf("                   of output to the CLI\n");
02672    printf("   -v              Increase verbosity (multiple v's = more verbose)\n");
02673    printf("   -x <cmd>        Execute command <cmd> (only valid with -r)\n");
02674    printf("\n");
02675    return 0;
02676 }
02677 
02678 static void ast_readconfig(void) 
02679 {
02680    struct ast_config *cfg;
02681    struct ast_variable *v;
02682    char *config = AST_CONFIG_FILE;
02683 
02684    if (ast_opt_override_config) {
02685       cfg = ast_config_load(ast_config_AST_CONFIG_FILE);
02686       if (!cfg)
02687          ast_log(LOG_WARNING, "Unable to open specified master config file '%s', using built-in defaults\n", ast_config_AST_CONFIG_FILE);
02688    } else {
02689       cfg = ast_config_load(config);
02690    }
02691 
02692    /* init with buildtime config */
02693    ast_copy_string(ast_config_AST_CONFIG_DIR, AST_CONFIG_DIR, sizeof(ast_config_AST_CONFIG_DIR));
02694    ast_copy_string(ast_config_AST_SPOOL_DIR, AST_SPOOL_DIR, sizeof(ast_config_AST_SPOOL_DIR));
02695    ast_copy_string(ast_config_AST_MODULE_DIR, AST_MODULE_DIR, sizeof(ast_config_AST_MODULE_DIR));
02696    snprintf(ast_config_AST_MONITOR_DIR, sizeof(ast_config_AST_MONITOR_DIR) - 1, "%s/monitor", ast_config_AST_SPOOL_DIR);
02697    ast_copy_string(ast_config_AST_VAR_DIR, AST_VAR_DIR, sizeof(ast_config_AST_VAR_DIR));
02698    ast_copy_string(ast_config_AST_DATA_DIR, AST_DATA_DIR, sizeof(ast_config_AST_DATA_DIR));
02699    ast_copy_string(ast_config_AST_LOG_DIR, AST_LOG_DIR, sizeof(ast_config_AST_LOG_DIR));
02700    ast_copy_string(ast_config_AST_AGI_DIR, AST_AGI_DIR, sizeof(ast_config_AST_AGI_DIR));
02701    ast_copy_string(ast_config_AST_DB, AST_DB, sizeof(ast_config_AST_DB));
02702    ast_copy_string(ast_config_AST_KEY_DIR, AST_KEY_DIR, sizeof(ast_config_AST_KEY_DIR));
02703    ast_copy_string(ast_config_AST_PID, AST_PID, sizeof(ast_config_AST_PID));
02704    ast_copy_string(ast_config_AST_SOCKET, AST_SOCKET, sizeof(ast_config_AST_SOCKET));
02705    ast_copy_string(ast_config_AST_RUN_DIR, AST_RUN_DIR, sizeof(ast_config_AST_RUN_DIR));
02706 
02707    /* no asterisk.conf? no problem, use buildtime config! */
02708    if (!cfg) {
02709       return;
02710    }
02711 
02712    for (v = ast_variable_browse(cfg, "files"); v; v = v->next) {
02713       if (!strcasecmp(v->name, "astctlpermissions")) {
02714          ast_copy_string(ast_config_AST_CTL_PERMISSIONS, v->value, sizeof(ast_config_AST_CTL_PERMISSIONS));
02715       } else if (!strcasecmp(v->name, "astctlowner")) {
02716          ast_copy_string(ast_config_AST_CTL_OWNER, v->value, sizeof(ast_config_AST_CTL_OWNER));
02717       } else if (!strcasecmp(v->name, "astctlgroup")) {
02718          ast_copy_string(ast_config_AST_CTL_GROUP, v->value, sizeof(ast_config_AST_CTL_GROUP));
02719       } else if (!strcasecmp(v->name, "astctl")) {
02720          ast_copy_string(ast_config_AST_CTL, v->value, sizeof(ast_config_AST_CTL));
02721       }
02722    }
02723 
02724    for (v = ast_variable_browse(cfg, "directories"); v; v = v->next) {
02725       if (!strcasecmp(v->name, "astetcdir")) {
02726          ast_copy_string(ast_config_AST_CONFIG_DIR, v->value, sizeof(ast_config_AST_CONFIG_DIR));
02727       } else if (!strcasecmp(v->name, "astspooldir")) {
02728          ast_copy_string(ast_config_AST_SPOOL_DIR, v->value, sizeof(ast_config_AST_SPOOL_DIR));
02729          snprintf(ast_config_AST_MONITOR_DIR, sizeof(ast_config_AST_MONITOR_DIR) - 1, "%s/monitor", v->value);
02730       } else if (!strcasecmp(v->name, "astvarlibdir")) {
02731          ast_copy_string(ast_config_AST_VAR_DIR, v->value, sizeof(ast_config_AST_VAR_DIR));
02732          snprintf(ast_config_AST_DB, sizeof(ast_config_AST_DB), "%s/astdb", v->value);
02733       } else if (!strcasecmp(v->name, "astdatadir")) {
02734          ast_copy_string(ast_config_AST_DATA_DIR, v->value, sizeof(ast_config_AST_DATA_DIR));
02735          snprintf(ast_config_AST_KEY_DIR, sizeof(ast_config_AST_KEY_DIR), "%s/keys", v->value);
02736       } else if (!strcasecmp(v->name, "astlogdir")) {
02737          ast_copy_string(ast_config_AST_LOG_DIR, v->value, sizeof(ast_config_AST_LOG_DIR));
02738       } else if (!strcasecmp(v->name, "astagidir")) {
02739          ast_copy_string(ast_config_AST_AGI_DIR, v->value, sizeof(ast_config_AST_AGI_DIR));
02740       } else if (!strcasecmp(v->name, "astrundir")) {
02741          snprintf(ast_config_AST_PID, sizeof(ast_config_AST_PID), "%s/%s", v->value, "asterisk.pid");
02742          snprintf(ast_config_AST_SOCKET, sizeof(ast_config_AST_SOCKET), "%s/%s", v->value, ast_config_AST_CTL);
02743          ast_copy_string(ast_config_AST_RUN_DIR, v->value, sizeof(ast_config_AST_RUN_DIR));
02744       } else if (!strcasecmp(v->name, "astmoddir")) {
02745          ast_copy_string(ast_config_AST_MODULE_DIR, v->value, sizeof(ast_config_AST_MODULE_DIR));
02746       }
02747    }
02748 
02749    for (v = ast_variable_browse(cfg, "options"); v; v = v->next) {
02750       /* verbose level (-v at startup) */
02751       if (!strcasecmp(v->name, "verbose")) {
02752          option_verbose = atoi(v->value);
02753       /* whether or not to force timestamping in CLI verbose output. (-T at startup) */
02754       } else if (!strcasecmp(v->name, "timestamp")) {
02755          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TIMESTAMP);
02756       /* whether or not to support #exec in config files */
02757       } else if (!strcasecmp(v->name, "execincludes")) {
02758          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_EXEC_INCLUDES);
02759       /* debug level (-d at startup) */
02760       } else if (!strcasecmp(v->name, "debug")) {
02761          option_debug = 0;
02762          if (sscanf(v->value, "%30d", &option_debug) != 1) {
02763             option_debug = ast_true(v->value);
02764          }
02765 #if HAVE_WORKING_FORK
02766       /* Disable forking (-f at startup) */
02767       } else if (!strcasecmp(v->name, "nofork")) {
02768          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_FORK);
02769       /* Always fork, even if verbose or debug are enabled (-F at startup) */
02770       } else if (!strcasecmp(v->name, "alwaysfork")) {
02771          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_ALWAYS_FORK);
02772 #endif
02773       /* Run quietly (-q at startup ) */
02774       } else if (!strcasecmp(v->name, "quiet")) {
02775          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_QUIET);
02776       /* Run as console (-c at startup, implies nofork) */
02777       } else if (!strcasecmp(v->name, "console")) {
02778          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_CONSOLE);
02779       /* Run with high priority if the O/S permits (-p at startup) */
02780       } else if (!strcasecmp(v->name, "highpriority")) {
02781          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_HIGH_PRIORITY);
02782       /* Initialize RSA auth keys (IAX2) (-i at startup) */
02783       } else if (!strcasecmp(v->name, "initcrypto")) {
02784          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_INIT_KEYS);
02785       /* Disable ANSI colors for console (-c at startup) */
02786       } else if (!strcasecmp(v->name, "nocolor")) {
02787          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_COLOR);
02788       /* Disable some usage warnings for picky people :p */
02789       } else if (!strcasecmp(v->name, "dontwarn")) {
02790          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_DONT_WARN);
02791       /* Dump core in case of crash (-g) */
02792       } else if (!strcasecmp(v->name, "dumpcore")) {
02793          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_DUMP_CORE);
02794       /* Cache recorded sound files to another directory during recording */
02795       } else if (!strcasecmp(v->name, "cache_record_files")) {
02796          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_CACHE_RECORD_FILES);
02797       /* Specify cache directory */
02798       }  else if (!strcasecmp(v->name, "record_cache_dir")) {
02799          ast_copy_string(record_cache_dir, v->value, AST_CACHE_DIR_LEN);
02800       /* Build transcode paths via SLINEAR, instead of directly */
02801       } else if (!strcasecmp(v->name, "transcode_via_sln")) {
02802          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TRANSCODE_VIA_SLIN);
02803       /* Transmit SLINEAR silence while a channel is being recorded or DTMF is being generated on a channel */
02804       } else if (!strcasecmp(v->name, "transmit_silence_during_record") || !strcasecmp(v->name, "transmit_silence")) {
02805          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TRANSMIT_SILENCE);
02806       /* Enable internal timing */
02807       } else if (!strcasecmp(v->name, "internal_timing")) {
02808          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_INTERNAL_TIMING);
02809       } else if (!strcasecmp(v->name, "maxcalls")) {
02810          if ((sscanf(v->value, "%30d", &option_maxcalls) != 1) || (option_maxcalls < 0)) {
02811             option_maxcalls = 0;
02812          }
02813       } else if (!strcasecmp(v->name, "maxload")) {
02814          double test[1];
02815          if (getloadavg(test, 1) == -1) {
02816             ast_log(LOG_ERROR, "Cannot obtain load average on this system. 'maxload' option disabled.\n");
02817             option_maxload = 0.0;
02818          } else if ((sscanf(v->value, "%30lf", &option_maxload) != 1) || (option_maxload < 0.0)) {
02819             option_maxload = 0.0;
02820          }
02821       /* Set the maximum amount of open files */
02822       } else if (!strcasecmp(v->name, "maxfiles")) {
02823          option_maxfiles = atoi(v->value);
02824          set_ulimit(option_maxfiles);
02825       /* What user to run as */
02826       } else if (!strcasecmp(v->name, "runuser")) {
02827          ast_copy_string(ast_config_AST_RUN_USER, v->value, sizeof(ast_config_AST_RUN_USER));
02828       /* What group to run as */
02829       } else if (!strcasecmp(v->name, "rungroup")) {
02830          ast_copy_string(ast_config_AST_RUN_GROUP, v->value, sizeof(ast_config_AST_RUN_GROUP));
02831       } else if (!strcasecmp(v->name, "systemname")) {
02832          ast_copy_string(ast_config_AST_SYSTEM_NAME, v->value, sizeof(ast_config_AST_SYSTEM_NAME));
02833       } else if (!strcasecmp(v->name, "languageprefix")) {
02834          ast_language_is_prefix = ast_true(v->value);
02835       } else if (!strcasecmp(v->name, "dahdichanname")) {
02836 #ifdef HAVE_ZAPTEL
02837          if (ast_true(v->value)) {
02838             strcpy(_dahdi_chan_name, "DAHDI");
02839             _dahdi_chan_name_len = 5;
02840             _dahdi_chan_mode = CHAN_DAHDI_PLUS_ZAP_MODE;
02841          }
02842 #else
02843          if (ast_false(v->value)) {
02844             strcpy(_dahdi_chan_name, "Zap");
02845             _dahdi_chan_name_len = 3;
02846             _dahdi_chan_mode = CHAN_ZAP_MODE;
02847          }
02848 #endif
02849 #if defined(HAVE_SYSINFO)
02850       } else if (!strcasecmp(v->name, "minmemfree")) {
02851          /* specify the minimum amount of free memory to retain.  Asterisk should stop accepting new calls
02852           * if the amount of free memory falls below this watermark */
02853          if ((sscanf(v->value, "%ld", &option_minmemfree) != 1) || (option_minmemfree < 0)) {
02854             option_minmemfree = 0;
02855          }
02856 #endif
02857       } else if (!strcasecmp(v->name, "sendfullybooted")) {
02858          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_SEND_FULLYBOOTED);
02859       }
02860    }
02861    ast_config_destroy(cfg);
02862 }
02863 
02864 static void *monitor_sig_flags(void *unused)
02865 {
02866    for (;;) {
02867       struct pollfd p = { sig_alert_pipe[0], POLLIN, 0 };
02868       int a;
02869       ast_poll(&p, 1, -1);
02870       if (sig_flags.need_reload) {
02871          sig_flags.need_reload = 0;
02872          ast_module_reload(NULL);
02873       }
02874       if (sig_flags.need_quit) {
02875          sig_flags.need_quit = 0;
02876          quit_handler(0, 0, 1, 0);
02877       }
02878       if (read(sig_alert_pipe[0], &a, sizeof(a)) != sizeof(a)) {
02879       }
02880    }
02881 
02882    return NULL;
02883 }
02884 
02885 int main(int argc, char *argv[])
02886 {
02887    int c;
02888    char filename[80] = "";
02889    char hostname[MAXHOSTNAMELEN] = "";
02890    char tmp[80];
02891    char * xarg = NULL;
02892    int x;
02893    FILE *f;
02894    sigset_t sigs;
02895    int num;
02896    int isroot = 1, rundir_exists = 0;
02897    char *buf;
02898    char *runuser = NULL, *rungroup = NULL;
02899    struct rlimit l;
02900 
02901    /* Remember original args for restart */
02902    if (argc > sizeof(_argv) / sizeof(_argv[0]) - 1) {
02903       fprintf(stderr, "Truncating argument size to %d\n", (int)(sizeof(_argv) / sizeof(_argv[0])) - 1);
02904       argc = sizeof(_argv) / sizeof(_argv[0]) - 1;
02905    }
02906    for (x=0; x<argc; x++)
02907       _argv[x] = argv[x];
02908    _argv[x] = NULL;
02909 
02910    if (geteuid() != 0)
02911       isroot = 0;
02912 
02913    /* if the progname is rasterisk consider it a remote console */
02914    if (argv[0] && (strstr(argv[0], "rasterisk")) != NULL) {
02915       ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE);
02916    }
02917    if (gethostname(hostname, sizeof(hostname)-1))
02918       ast_copy_string(hostname, "<Unknown>", sizeof(hostname));
02919    ast_mainpid = getpid();
02920    ast_ulaw_init();
02921    ast_alaw_init();
02922    callerid_init();
02923    ast_builtins_init();
02924    ast_utils_init();
02925    tdd_init();
02926    ast_fd_init();
02927    ast_pbx_init();
02928 
02929    if (getenv("HOME")) 
02930       snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
02931    /* Check for options */
02932    while ((c = getopt(argc, argv, "mtThfFdvVqprRgciInx:U:G:C:L:M:e:")) != -1) {
02933       switch (c) {
02934 #if defined(HAVE_SYSINFO)
02935       case 'e':
02936          if ((sscanf(&optarg[1], "%ld", &option_minmemfree) != 1) || (option_minmemfree < 0)) {
02937             option_minmemfree = 0;
02938          }
02939          break;
02940 #endif
02941 #if HAVE_WORKING_FORK
02942       case 'F':
02943          ast_set_flag(&ast_options, AST_OPT_FLAG_ALWAYS_FORK);
02944          break;
02945       case 'f':
02946          ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);
02947          break;
02948 #endif
02949       case 'd':
02950          option_debug++;
02951          ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);
02952          break;
02953       case 'c':
02954          ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_CONSOLE);
02955          break;
02956       case 'n':
02957          ast_set_flag(&ast_options, AST_OPT_FLAG_NO_COLOR);
02958          break;
02959       case 'r':
02960          ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE);
02961          break;
02962       case 'R':
02963          ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE | AST_OPT_FLAG_RECONNECT);
02964          break;
02965       case 'p':
02966          ast_set_flag(&ast_options, AST_OPT_FLAG_HIGH_PRIORITY);
02967          break;
02968       case 'v':
02969          option_verbose++;
02970          ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);
02971          break;
02972       case 'm':
02973          ast_set_flag(&ast_options, AST_OPT_FLAG_MUTE);
02974          break;
02975       case 'M':
02976          if ((sscanf(optarg, "%30d", &option_maxcalls) != 1) || (option_maxcalls < 0))
02977             option_maxcalls = 0;
02978          break;
02979       case 'L':
02980          if ((sscanf(optarg, "%30lf", &option_maxload) != 1) || (option_maxload < 0.0))
02981             option_maxload = 0.0;
02982          break;
02983       case 'q':
02984          ast_set_flag(&ast_options, AST_OPT_FLAG_QUIET);
02985          break;
02986       case 't':
02987          ast_set_flag(&ast_options, AST_OPT_FLAG_CACHE_RECORD_FILES);
02988          break;
02989       case 'T':
02990          ast_set_flag(&ast_options, AST_OPT_FLAG_TIMESTAMP);
02991          break;
02992       case 'x':
02993          ast_set_flag(&ast_options, AST_OPT_FLAG_EXEC | AST_OPT_FLAG_NO_COLOR);
02994          xarg = ast_strdupa(optarg);
02995          break;
02996       case 'C':
02997          ast_copy_string(ast_config_AST_CONFIG_FILE, optarg, sizeof(ast_config_AST_CONFIG_FILE));
02998          ast_set_flag(&ast_options, AST_OPT_FLAG_OVERRIDE_CONFIG);
02999          break;
03000       case 'I':
03001          ast_set_flag(&ast_options, AST_OPT_FLAG_INTERNAL_TIMING);
03002          break;
03003       case 'i':
03004          ast_set_flag(&ast_options, AST_OPT_FLAG_INIT_KEYS);
03005          break;
03006       case 'g':
03007          ast_set_flag(&ast_options, AST_OPT_FLAG_DUMP_CORE);
03008          break;
03009       case 'h':
03010          show_cli_help();
03011          exit(0);
03012       case 'V':
03013          show_version();
03014          exit(0);
03015       case 'U':
03016          runuser = ast_strdupa(optarg);
03017          break;
03018       case 'G':
03019          rungroup = ast_strdupa(optarg);
03020          break;
03021       case '?':
03022          exit(1);
03023       }
03024    }
03025 
03026    if (ast_opt_console || option_verbose || (ast_opt_remote && !ast_opt_exec)) {
03027       ast_register_verbose(console_verboser);
03028       WELCOME_MESSAGE;
03029    }
03030 
03031    if (ast_opt_console && !option_verbose) 
03032       ast_verbose("[ Booting...\n");
03033 
03034    /* For remote connections, change the name of the remote connection.
03035     * We do this for the benefit of init scripts (which need to know if/when
03036     * the main asterisk process has died yet). */
03037    if (ast_opt_remote) {
03038       strcpy(argv[0], "rasterisk");
03039       for (x = 1; x < argc; x++) {
03040          argv[x] = argv[0] + 10;
03041       }
03042    }
03043 
03044    if (ast_opt_console && !option_verbose) {
03045       ast_verbose("[ Reading Master Configuration ]\n");
03046    }
03047 
03048    ast_readconfig();
03049 
03050    if (ast_opt_always_fork && (ast_opt_remote || ast_opt_console)) {
03051       ast_log(LOG_WARNING, "'alwaysfork' is not compatible with console or remote console mode; ignored\n");
03052       ast_clear_flag(&ast_options, AST_OPT_FLAG_ALWAYS_FORK);
03053    }
03054 
03055    if (ast_opt_dump_core) {
03056       memset(&l, 0, sizeof(l));
03057       l.rlim_cur = RLIM_INFINITY;
03058       l.rlim_max = RLIM_INFINITY;
03059       if (setrlimit(RLIMIT_CORE, &l)) {
03060          ast_log(LOG_WARNING, "Unable to disable core size resource limit: %s\n", strerror(errno));
03061       }
03062    }
03063 
03064    if (getrlimit(RLIMIT_NOFILE, &l)) {
03065       ast_log(LOG_WARNING, "Unable to check file descriptor limit: %s\n", strerror(errno));
03066    }
03067 
03068 #if !defined(CONFIGURE_RAN_AS_ROOT)
03069    /* Check if select(2) will run with more file descriptors */
03070    do {
03071       int fd, fd2;
03072       ast_fdset readers;
03073       struct timeval tv = { 0, };
03074 
03075       if (l.rlim_cur <= FD_SETSIZE) {
03076          /* The limit of select()able FDs is irrelevant, because we'll never
03077           * open one that high. */
03078          break;
03079       }
03080 
03081       if (!(fd = open("/dev/null", O_RDONLY))) {
03082          ast_log(LOG_ERROR, "Cannot open a file descriptor at boot? %s\n", strerror(errno));
03083          break; /* XXX Should we exit() here? XXX */
03084       }
03085 
03086       fd2 = (l.rlim_cur > sizeof(readers) * 8 ? sizeof(readers) * 8 : l.rlim_cur) - 1;
03087       if (dup2(fd, fd2) < 0) {
03088          ast_log(LOG_WARNING, "Cannot open maximum file descriptor %d at boot? %s\n", fd2, strerror(errno));
03089          close(fd);
03090          break;
03091       }
03092 
03093       FD_ZERO(&readers);
03094       FD_SET(fd2, &readers);
03095       if (ast_select(fd2 + 1, &readers, NULL, NULL, &tv) < 0) {
03096          ast_log(LOG_WARNING, "Maximum select()able file descriptor is %d\n", FD_SETSIZE);
03097       }
03098       ast_FD_SETSIZE = l.rlim_cur > ast_FDMAX ? ast_FDMAX : l.rlim_cur;
03099       close(fd);
03100       close(fd2);
03101    } while (0);
03102 #elif defined(HAVE_VARIABLE_FDSET)
03103    ast_FD_SETSIZE = l.rlim_cur > ast_FDMAX ? ast_FDMAX : l.rlim_cur;
03104 #endif /* !defined(CONFIGURE_RAN_AS_ROOT) */
03105 
03106    if ((!rungroup) && !ast_strlen_zero(ast_config_AST_RUN_GROUP))
03107       rungroup = ast_config_AST_RUN_GROUP;
03108    if ((!runuser) && !ast_strlen_zero(ast_config_AST_RUN_USER))
03109       runuser = ast_config_AST_RUN_USER;
03110 
03111    /* It's common on some platforms to clear /var/run at boot.  Create the
03112     * socket file directory before we drop privileges. */
03113    if (mkdir(ast_config_AST_RUN_DIR, 0755)) {
03114       if (errno == EEXIST) {
03115          rundir_exists = 1;
03116       } else {
03117          ast_log(LOG_WARNING, "Unable to create socket file directory.  Remote consoles will not be able to connect! (%s)\n", strerror(x));
03118       }
03119    }
03120 
03121 #ifndef __CYGWIN__
03122 
03123    if (isroot) 
03124       ast_set_priority(ast_opt_high_priority);
03125 
03126    if (isroot && rungroup) {
03127       struct group *gr;
03128       gr = getgrnam(rungroup);
03129       if (!gr) {
03130          ast_log(LOG_WARNING, "No such group '%s'!\n", rungroup);
03131          exit(1);
03132       }
03133       if (!rundir_exists && chown(ast_config_AST_RUN_DIR, -1, gr->gr_gid)) {
03134          ast_log(LOG_WARNING, "Unable to chgrp run directory to %d (%s)\n", (int) gr->gr_gid, rungroup);
03135       }
03136       if (setgid(gr->gr_gid)) {
03137          ast_log(LOG_WARNING, "Unable to setgid to %d (%s)\n", (int)gr->gr_gid, rungroup);
03138          exit(1);
03139       }
03140       if (setgroups(0, NULL)) {
03141          ast_log(LOG_WARNING, "Unable to drop unneeded groups\n");
03142          exit(1);
03143       }
03144       if (option_verbose)
03145          ast_verbose("Running as group '%s'\n", rungroup);
03146    }
03147 
03148    if (runuser && !ast_test_flag(&ast_options, AST_OPT_FLAG_REMOTE)) {
03149 #ifdef HAVE_CAP
03150       int has_cap = 1;
03151 #endif /* HAVE_CAP */
03152       struct passwd *pw;
03153       pw = getpwnam(runuser);
03154       if (!pw) {
03155          ast_log(LOG_WARNING, "No such user '%s'!\n", runuser);
03156          exit(1);
03157       }
03158       if (chown(ast_config_AST_RUN_DIR, pw->pw_uid, -1)) {
03159          ast_log(LOG_WARNING, "Unable to chown run directory to %d (%s)\n", (int) pw->pw_uid, runuser);
03160       }
03161 #ifdef HAVE_CAP
03162       if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0)) {
03163          ast_log(LOG_WARNING, "Unable to keep capabilities.\n");
03164          has_cap = 0;
03165       }
03166 #endif /* HAVE_CAP */
03167       if (!isroot && pw->pw_uid != geteuid()) {
03168          ast_log(LOG_ERROR, "Asterisk started as nonroot, but runuser '%s' requested.\n", runuser);
03169          exit(1);
03170       }
03171       if (!rungroup) {
03172          if (setgid(pw->pw_gid)) {
03173             ast_log(LOG_WARNING, "Unable to setgid to %d!\n", (int)pw->pw_gid);
03174             exit(1);
03175          }
03176          if (isroot && initgroups(pw->pw_name, pw->pw_gid)) {
03177             ast_log(LOG_WARNING, "Unable to init groups for '%s'\n", runuser);
03178             exit(1);
03179          }
03180       }
03181       if (setuid(pw->pw_uid)) {
03182          ast_log(LOG_WARNING, "Unable to setuid to %d (%s)\n", (int)pw->pw_uid, runuser);
03183          exit(1);
03184       }
03185       if (option_verbose)
03186          ast_verbose("Running as user '%s'\n", runuser);
03187 #ifdef HAVE_CAP
03188       if (has_cap) {
03189          cap_t cap = cap_from_text("cap_net_admin=eip");
03190 
03191          if (cap_set_proc(cap))
03192             ast_log(LOG_WARNING, "Unable to install capabilities.\n");
03193 
03194          if (cap_free(cap))
03195             ast_log(LOG_WARNING, "Unable to drop capabilities.\n");
03196       }
03197 #endif /* HAVE_CAP */
03198    }
03199 
03200 #endif /* __CYGWIN__ */
03201 
03202 #ifdef linux
03203    if (geteuid() && ast_opt_dump_core) {
03204       if (prctl(PR_SET_DUMPABLE, 1, 0, 0, 0) < 0) {
03205          ast_log(LOG_WARNING, "Unable to set the process for core dumps after changing to a non-root user. %s\n", strerror(errno));
03206       }  
03207    }
03208 #endif
03209 
03210    ast_term_init();
03211    printf("%s", term_end());
03212    fflush(stdout);
03213 
03214    if (ast_opt_console && !option_verbose) 
03215       ast_verbose("[ Initializing Custom Configuration Options ]\n");
03216    /* custom config setup */
03217    register_config_cli();
03218    read_config_maps();
03219    
03220    if (ast_opt_console) {
03221       if (el_hist == NULL || el == NULL)
03222          ast_el_initialize();
03223 
03224       if (!ast_strlen_zero(filename))
03225          ast_el_read_history(filename);
03226    }
03227 
03228    if (ast_tryconnect()) {
03229       /* One is already running */
03230       if (ast_opt_remote) {
03231          if (ast_opt_exec) {
03232             ast_remotecontrol(xarg);
03233             quit_handler(0, 0, 0, 0);
03234             exit(0);
03235          }
03236          printf("%s", term_quit());
03237          ast_remotecontrol(NULL);
03238          quit_handler(0, 0, 0, 0);
03239          exit(0);
03240       } else {
03241          ast_log(LOG_ERROR, "Asterisk already running on %s.  Use 'asterisk -r' to connect.\n", ast_config_AST_SOCKET);
03242          printf("%s", term_quit());
03243          exit(1);
03244       }
03245    } else if (ast_opt_remote || ast_opt_exec) {
03246       ast_log(LOG_ERROR, "Unable to connect to remote asterisk (does %s exist?)\n", ast_config_AST_SOCKET);
03247       printf("%s", term_quit());
03248       exit(1);
03249    }
03250    /* Blindly write pid file since we couldn't connect */
03251    unlink(ast_config_AST_PID);
03252    f = fopen(ast_config_AST_PID, "w");
03253    if (f) {
03254       fprintf(f, "%ld\n", (long)getpid());
03255       fclose(f);
03256    } else
03257       ast_log(LOG_WARNING, "Unable to open pid file '%s': %s\n", ast_config_AST_PID, strerror(errno));
03258 
03259 #if HAVE_WORKING_FORK
03260    if (ast_opt_always_fork || !ast_opt_no_fork) {
03261 #ifndef HAVE_SBIN_LAUNCHD
03262       if (daemon(1, 0) < 0) {
03263          ast_log(LOG_ERROR, "daemon() failed: %s\n", strerror(errno));
03264       }
03265       ast_mainpid = getpid();
03266       /* Blindly re-write pid file since we are forking */
03267       unlink(ast_config_AST_PID);
03268       f = fopen(ast_config_AST_PID, "w");
03269       if (f) {
03270          fprintf(f, "%ld\n", (long)ast_mainpid);
03271          fclose(f);
03272       } else
03273          ast_log(LOG_WARNING, "Unable to open pid file '%s': %s\n", ast_config_AST_PID, strerror(errno));
03274 #else
03275       ast_log(LOG_WARNING, "Mac OS X detected.  Use 'launchctl load /Library/LaunchDaemon/org.asterisk.asterisk.plist'.\n");
03276 #endif
03277    }
03278 #endif
03279 
03280 #ifdef TEST_FRAMEWORK
03281    if (ast_test_init()) {
03282       printf("%s", term_quit());
03283       exit(1);
03284    }
03285 #endif
03286 
03287    ast_makesocket();
03288    sigemptyset(&sigs);
03289    sigaddset(&sigs, SIGHUP);
03290    sigaddset(&sigs, SIGTERM);
03291    sigaddset(&sigs, SIGINT);
03292    sigaddset(&sigs, SIGPIPE);
03293    sigaddset(&sigs, SIGWINCH);
03294    pthread_sigmask(SIG_BLOCK, &sigs, NULL);
03295    sigaction(SIGURG, &urg_handler, NULL);
03296    signal(SIGINT, __quit_handler);
03297    signal(SIGTERM, __quit_handler);
03298    sigaction(SIGHUP, &hup_handler, NULL);
03299    sigaction(SIGCHLD, &child_handler, NULL);
03300    signal(SIGPIPE, SIG_IGN);
03301 
03302    /* ensure that the random number generators are seeded with a different value every time
03303       Asterisk is started
03304    */
03305    srand((unsigned int) getpid() + (unsigned int) time(NULL));
03306    initstate((unsigned int) getpid() * 65536 + (unsigned int) time(NULL), randompool, sizeof(randompool));
03307 
03308    if (init_logger()) {    /* Start logging subsystem */
03309       printf("%s", term_quit());
03310       exit(1);
03311    }
03312 
03313    dahdi_chan_name = _dahdi_chan_name;
03314    dahdi_chan_name_len = &_dahdi_chan_name_len;
03315    dahdi_chan_mode = &_dahdi_chan_mode;
03316 
03317 #ifdef HAVE_DAHDI
03318    {
03319       int fd;
03320       int x = 160;
03321       fd = open(DAHDI_FILE_TIMER, O_RDWR);
03322       if (fd >= 0) {
03323          if (ioctl(fd, DAHDI_TIMERCONFIG, &x)) {
03324             ast_log(LOG_ERROR, "You have " DAHDI_NAME
03325                   " built and drivers loaded, but the "
03326                   DAHDI_NAME " timer test failed to set DAHDI_TIMERCONFIG to %d.\n", x);
03327             exit(1);
03328          }
03329          if ((x = ast_wait_for_input(fd, 300)) < 0) {
03330             ast_log(LOG_ERROR, "You have " DAHDI_NAME 
03331                   "built and drivers loaded, but the " 
03332                   DAHDI_NAME " timer could not be polled during the " 
03333                   DAHDI_NAME " timer test.\n");
03334             exit(1);
03335          }
03336          if (!x) {
03337             const char dahdi_timer_error[] = {
03338                "Asterisk has detected a problem with your " DAHDI_NAME 
03339                   " configuration and will shutdown for your protection.  You have options:"
03340                "\n\t1. You only have to compile " DAHDI_NAME 
03341                   " support into Asterisk if you need it.  One option is to recompile without " 
03342                   DAHDI_NAME " support."
03343                "\n\t2. You only have to load " DAHDI_NAME " drivers if you want to take advantage of " 
03344                   DAHDI_NAME " services.  One option is to unload " 
03345                   DAHDI_NAME " modules if you don't need them."
03346                "\n\t3. If you need Zaptel services, you must correctly configure " DAHDI_NAME "."
03347             };
03348             ast_log(LOG_ERROR, "%s\n", dahdi_timer_error);
03349             exit(1);
03350          }
03351          close(fd);
03352       }
03353    }
03354 #endif
03355    threadstorage_init();
03356 
03357    astobj2_init();
03358 
03359    ast_autoservice_init();
03360 
03361    if (load_modules(1)) {     /* Load modules, pre-load only */
03362       printf("%s", term_quit());
03363       exit(1);
03364    }
03365 
03366    if (dnsmgr_init()) {    /* Initialize the DNS manager */
03367       printf("%s", term_quit());
03368       exit(1);
03369    }
03370 
03371    ast_http_init();     /* Start the HTTP server, if needed */
03372 
03373    ast_channels_init();
03374 
03375    if (init_manager()) {
03376       printf("%s", term_quit());
03377       exit(1);
03378    }
03379 
03380    if (ast_cdr_engine_init()) {
03381       printf("%s", term_quit());
03382       exit(1);
03383    }
03384 
03385    if (ast_device_state_engine_init()) {
03386       printf("%s", term_quit());
03387       exit(1);
03388    }
03389 
03390    ast_rtp_init();
03391 
03392    ast_udptl_init();
03393 
03394    if (ast_image_init()) {
03395       printf("%s", term_quit());
03396       exit(1);
03397    }
03398 
03399    if (ast_file_init()) {
03400       printf("%s", term_quit());
03401       exit(1);
03402    }
03403 
03404    if (load_pbx()) {
03405       printf("%s", term_quit());
03406       exit(1);
03407    }
03408 
03409    if (init_framer()) {
03410       printf("%s", term_quit());
03411       exit(1);
03412    }
03413 
03414    if (astdb_init()) {
03415       printf("%s", term_quit());
03416       exit(1);
03417    }
03418 
03419    if (ast_enum_init()) {
03420       printf("%s", term_quit());
03421       exit(1);
03422    }
03423 
03424    if (load_modules(0)) {
03425       printf("%s", term_quit());
03426       exit(1);
03427    }
03428 
03429    dnsmgr_start_refresh();
03430 
03431    /* We might have the option of showing a console, but for now just
03432       do nothing... */
03433    if (ast_opt_console && !option_verbose)
03434       ast_verbose(" ]\n");
03435    if (option_verbose || ast_opt_console)
03436       ast_verbose("%s", term_color(tmp, "Asterisk Ready.\n", COLOR_BRWHITE, COLOR_BLACK, sizeof(tmp)));
03437    if (ast_opt_no_fork)
03438       consolethread = pthread_self();
03439 
03440    if (pipe(sig_alert_pipe))
03441       sig_alert_pipe[0] = sig_alert_pipe[1] = -1;
03442 
03443    ast_set_flag(&ast_options, AST_OPT_FLAG_FULLY_BOOTED);
03444    if (ast_opt_send_fullybooted) {
03445       manager_event(EVENT_FLAG_SYSTEM, "FullyBooted", "Status: Fully Booted\r\n");
03446    }
03447 
03448    ast_process_pending_reloads();
03449 
03450    pthread_sigmask(SIG_UNBLOCK, &sigs, NULL);
03451 
03452 #ifdef __AST_DEBUG_MALLOC
03453    __ast_mm_init();
03454 #endif   
03455 
03456    time(&ast_startuptime);
03457    ast_cli_register_multiple(cli_asterisk, sizeof(cli_asterisk) / sizeof(struct ast_cli_entry));
03458 
03459    if (ast_opt_console) {
03460       /* Console stuff now... */
03461       /* Register our quit function */
03462       char title[256];
03463       pthread_attr_t attr;
03464 
03465       pthread_attr_init(&attr);
03466       pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
03467       ast_pthread_create(&mon_sig_flags, &attr, monitor_sig_flags, NULL);
03468       pthread_attr_destroy(&attr);
03469 
03470       set_icon("Asterisk");
03471       snprintf(title, sizeof(title), "Asterisk Console on '%s' (pid %ld)", hostname, (long)ast_mainpid);
03472       set_title(title);
03473 
03474       for (;;) {
03475          buf = (char *)el_gets(el, &num);
03476 
03477          if (!buf && write(1, "", 1) < 0)
03478             goto lostterm;
03479 
03480          if (buf) {
03481             if (buf[strlen(buf)-1] == '\n')
03482                buf[strlen(buf)-1] = '\0';
03483 
03484             consolehandler((char *)buf);
03485          } else if (ast_opt_remote && (write(STDOUT_FILENO, "\nUse EXIT or QUIT to exit the asterisk console\n",
03486                strlen("\nUse EXIT or QUIT to exit the asterisk console\n")) < 0)) {
03487             /* Whoa, stdout disappeared from under us... Make /dev/null's */
03488             int fd;
03489             fd = open("/dev/null", O_RDWR);
03490             if (fd > -1) {
03491                dup2(fd, STDOUT_FILENO);
03492                dup2(fd, STDIN_FILENO);
03493             } else
03494                ast_log(LOG_WARNING, "Failed to open /dev/null to recover from dead console. Bad things will happen!\n");
03495             break;
03496          }
03497       }
03498    }
03499 
03500    monitor_sig_flags(NULL);
03501 
03502 lostterm:
03503    return 0;
03504 }

Generated on Sat Aug 6 00:39:22 2011 for Asterisk - the Open Source PBX by  doxygen 1.4.7