Wed Mar 4 19:58:01 2009

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

Generated on Wed Mar 4 19:58:01 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7