Thu Mar 25 12:09:29 2010

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

Generated on Thu Mar 25 12:09:29 2010 for Asterisk - the Open Source PBX by  doxygen 1.4.7