Fri Apr 24 16:25:49 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 - 2009, Digium, Inc.
00035  * Asterisk is a trademark registered by Digium, Inc.
00036  *
00037  * \author Mark Spencer <markster@digium.com>
00038  * Also see \ref AstCREDITS
00039  *
00040  * See http://www.asterisk.org for more information about
00041  * the Asterisk project. Please do not directly contact
00042  * any of the maintainers of this project for assistance;
00043  * the project provides a web site, mailing lists and IRC
00044  * channels for your use.
00045  */
00046 
00047 /*! \file
00048   \brief Top level source file for Asterisk  - the Open Source PBX. Implementation
00049   of PBX core functions and CLI interface.
00050   
00051  */
00052 
00053 #include "asterisk.h"
00054 
00055 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 178508 $")
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_CAP
00925       cap_t cap = cap_from_text("cap_net_admin-eip");
00926 
00927       if (cap_set_proc(cap)) {
00928          /* Careful with order! Logging cannot happen after we close FDs */
00929          ast_log(LOG_WARNING, "Unable to remove capabilities.\n");
00930       }
00931       cap_free(cap);
00932 #endif
00933 #ifdef HAVE_WORKING_FORK
00934       if (ast_opt_high_priority)
00935          ast_set_priority(0);
00936       /* Close file descriptors and launch system command */
00937       for (x = STDERR_FILENO + 1; x < 4096; x++)
00938          close(x);
00939 #endif
00940       execl("/bin/sh", "/bin/sh", "-c", s, (char *) NULL);
00941       _exit(1);
00942    } else if (pid > 0) {
00943       for(;;) {
00944          res = wait4(pid, &status, 0, &rusage);
00945          if (res > -1) {
00946             res = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
00947             break;
00948          } else if (errno != EINTR) 
00949             break;
00950       }
00951    } else {
00952       ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno));
00953       res = -1;
00954    }
00955 
00956    ast_unreplace_sigchld();
00957 #else /* !defined(HAVE_WORKING_FORK) && !defined(HAVE_WORKING_VFORK) */
00958    res = -1;
00959 #endif
00960 
00961    return res;
00962 }
00963 
00964 /*!
00965  * \brief mute or unmute a console from logging
00966  */
00967 void ast_console_toggle_mute(int fd, int silent) {
00968    int x;
00969    for (x = 0;x < AST_MAX_CONNECTS; x++) {
00970       if (fd == consoles[x].fd) {
00971          if (consoles[x].mute) {
00972             consoles[x].mute = 0;
00973             if (!silent)
00974                ast_cli(fd, "Console is not muted anymore.\n");
00975          } else {
00976             consoles[x].mute = 1;
00977             if (!silent)
00978                ast_cli(fd, "Console is muted.\n");
00979          }
00980          return;
00981       }
00982    }
00983    ast_cli(fd, "Couldn't find remote console.\n");
00984 }
00985 
00986 /*!
00987  * \brief log the string to all attached console clients
00988  */
00989 static void ast_network_puts_mutable(const char *string)
00990 {
00991    int x;
00992    for (x = 0;x < AST_MAX_CONNECTS; x++) {
00993       if (consoles[x].mute)
00994          continue;
00995       if (consoles[x].fd > -1) 
00996          fdprint(consoles[x].p[1], string);
00997    }
00998 }
00999 
01000 /*!
01001  * \brief log the string to the console, and all attached
01002  * console clients
01003  */
01004 void ast_console_puts_mutable(const char *string)
01005 {
01006    fputs(string, stdout);
01007    fflush(stdout);
01008    ast_network_puts_mutable(string);
01009 }
01010 
01011 /*!
01012  * \brief write the string to all attached console clients
01013  */
01014 static void ast_network_puts(const char *string)
01015 {
01016    int x;
01017    for (x=0; x < AST_MAX_CONNECTS; x++) {
01018       if (consoles[x].fd > -1) 
01019          fdprint(consoles[x].p[1], string);
01020    }
01021 }
01022 
01023 /*!
01024  * write the string to the console, and all attached
01025  * console clients
01026  */
01027 void ast_console_puts(const char *string)
01028 {
01029    fputs(string, stdout);
01030    fflush(stdout);
01031    ast_network_puts(string);
01032 }
01033 
01034 static void network_verboser(const char *s)
01035 {
01036    ast_network_puts_mutable(s);
01037 }
01038 
01039 static pthread_t lthread;
01040 
01041 static void *netconsole(void *vconsole)
01042 {
01043    struct console *con = vconsole;
01044    char hostname[MAXHOSTNAMELEN] = "";
01045    char tmp[512];
01046    int res;
01047    struct pollfd fds[2];
01048    
01049    if (gethostname(hostname, sizeof(hostname)-1))
01050       ast_copy_string(hostname, "<Unknown>", sizeof(hostname));
01051    snprintf(tmp, sizeof(tmp), "%s/%ld/%s\n", hostname, (long)ast_mainpid, ASTERISK_VERSION);
01052    fdprint(con->fd, tmp);
01053    for(;;) {
01054       fds[0].fd = con->fd;
01055       fds[0].events = POLLIN;
01056       fds[0].revents = 0;
01057       fds[1].fd = con->p[0];
01058       fds[1].events = POLLIN;
01059       fds[1].revents = 0;
01060 
01061       res = poll(fds, 2, -1);
01062       if (res < 0) {
01063          if (errno != EINTR)
01064             ast_log(LOG_WARNING, "poll returned < 0: %s\n", strerror(errno));
01065          continue;
01066       }
01067       if (fds[0].revents) {
01068          res = read(con->fd, tmp, sizeof(tmp));
01069          if (res < 1) {
01070             break;
01071          }
01072          tmp[res] = 0;
01073          ast_cli_command_multiple(con->fd, res, tmp);
01074       }
01075       if (fds[1].revents) {
01076          res = read(con->p[0], tmp, sizeof(tmp));
01077          if (res < 1) {
01078             ast_log(LOG_ERROR, "read returned %d\n", res);
01079             break;
01080          }
01081          res = write(con->fd, tmp, res);
01082          if (res < 1)
01083             break;
01084       }
01085    }
01086    if (option_verbose > 2) 
01087       ast_verbose(VERBOSE_PREFIX_3 "Remote UNIX connection disconnected\n");
01088    close(con->fd);
01089    close(con->p[0]);
01090    close(con->p[1]);
01091    con->fd = -1;
01092    
01093    return NULL;
01094 }
01095 
01096 static void *listener(void *unused)
01097 {
01098    struct sockaddr_un sunaddr;
01099    int s;
01100    socklen_t len;
01101    int x;
01102    int flags;
01103    struct pollfd fds[1];
01104    pthread_attr_t attr;
01105    pthread_attr_init(&attr);
01106    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
01107    for (;;) {
01108       if (ast_socket < 0)
01109          return NULL;
01110       fds[0].fd = ast_socket;
01111       fds[0].events = POLLIN;
01112       s = poll(fds, 1, -1);
01113       pthread_testcancel();
01114       if (s < 0) {
01115          if (errno != EINTR)
01116             ast_log(LOG_WARNING, "poll returned error: %s\n", strerror(errno));
01117          continue;
01118       }
01119       len = sizeof(sunaddr);
01120       s = accept(ast_socket, (struct sockaddr *)&sunaddr, &len);
01121       if (s < 0) {
01122          if (errno != EINTR)
01123             ast_log(LOG_WARNING, "Accept returned %d: %s\n", s, strerror(errno));
01124       } else {
01125          for (x = 0; x < AST_MAX_CONNECTS; x++) {
01126             if (consoles[x].fd < 0) {
01127                if (socketpair(AF_LOCAL, SOCK_STREAM, 0, consoles[x].p)) {
01128                   ast_log(LOG_ERROR, "Unable to create pipe: %s\n", strerror(errno));
01129                   consoles[x].fd = -1;
01130                   fdprint(s, "Server failed to create pipe\n");
01131                   close(s);
01132                   break;
01133                }
01134                flags = fcntl(consoles[x].p[1], F_GETFL);
01135                fcntl(consoles[x].p[1], F_SETFL, flags | O_NONBLOCK);
01136                consoles[x].fd = s;
01137                consoles[x].mute = 1; /* Default is muted, we will un-mute if necessary */
01138                if (ast_pthread_create_background(&consoles[x].t, &attr, netconsole, &consoles[x])) {
01139                   ast_log(LOG_ERROR, "Unable to spawn thread to handle connection: %s\n", strerror(errno));
01140                   close(consoles[x].p[0]);
01141                   close(consoles[x].p[1]);
01142                   consoles[x].fd = -1;
01143                   fdprint(s, "Server failed to spawn thread\n");
01144                   close(s);
01145                }
01146                break;
01147             }
01148          }
01149          if (x >= AST_MAX_CONNECTS) {
01150             fdprint(s, "No more connections allowed\n");
01151             ast_log(LOG_WARNING, "No more connections allowed\n");
01152             close(s);
01153          } else if (consoles[x].fd > -1) {
01154             if (option_verbose > 2) 
01155                ast_verbose(VERBOSE_PREFIX_3 "Remote UNIX connection\n");
01156          }
01157       }
01158    }
01159    return NULL;
01160 }
01161 
01162 static int ast_makesocket(void)
01163 {
01164    struct sockaddr_un sunaddr;
01165    int res;
01166    int x;
01167    uid_t uid = -1;
01168    gid_t gid = -1;
01169 
01170    for (x = 0; x < AST_MAX_CONNECTS; x++) 
01171       consoles[x].fd = -1;
01172    unlink(ast_config_AST_SOCKET);
01173    ast_socket = socket(PF_LOCAL, SOCK_STREAM, 0);
01174    if (ast_socket < 0) {
01175       ast_log(LOG_WARNING, "Unable to create control socket: %s\n", strerror(errno));
01176       return -1;
01177    }     
01178    memset(&sunaddr, 0, sizeof(sunaddr));
01179    sunaddr.sun_family = AF_LOCAL;
01180    ast_copy_string(sunaddr.sun_path, ast_config_AST_SOCKET, sizeof(sunaddr.sun_path));
01181    res = bind(ast_socket, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
01182    if (res) {
01183       ast_log(LOG_WARNING, "Unable to bind socket to %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
01184       close(ast_socket);
01185       ast_socket = -1;
01186       return -1;
01187    }
01188    res = listen(ast_socket, 2);
01189    if (res < 0) {
01190       ast_log(LOG_WARNING, "Unable to listen on socket %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
01191       close(ast_socket);
01192       ast_socket = -1;
01193       return -1;
01194    }
01195    ast_register_verbose(network_verboser);
01196    ast_pthread_create_background(&lthread, NULL, listener, NULL);
01197 
01198    if (!ast_strlen_zero(ast_config_AST_CTL_OWNER)) {
01199       struct passwd *pw;
01200       if ((pw = getpwnam(ast_config_AST_CTL_OWNER)) == NULL) {
01201          ast_log(LOG_WARNING, "Unable to find uid of user %s\n", ast_config_AST_CTL_OWNER);
01202       } else {
01203          uid = pw->pw_uid;
01204       }
01205    }
01206       
01207    if (!ast_strlen_zero(ast_config_AST_CTL_GROUP)) {
01208       struct group *grp;
01209       if ((grp = getgrnam(ast_config_AST_CTL_GROUP)) == NULL) {
01210          ast_log(LOG_WARNING, "Unable to find gid of group %s\n", ast_config_AST_CTL_GROUP);
01211       } else {
01212          gid = grp->gr_gid;
01213       }
01214    }
01215 
01216    if (chown(ast_config_AST_SOCKET, uid, gid) < 0)
01217       ast_log(LOG_WARNING, "Unable to change ownership of %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
01218 
01219    if (!ast_strlen_zero(ast_config_AST_CTL_PERMISSIONS)) {
01220       int p1;
01221       mode_t p;
01222       sscanf(ast_config_AST_CTL_PERMISSIONS, "%o", &p1);
01223       p = p1;
01224       if ((chmod(ast_config_AST_SOCKET, p)) < 0)
01225          ast_log(LOG_WARNING, "Unable to change file permissions of %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
01226    }
01227 
01228    return 0;
01229 }
01230 
01231 static int ast_tryconnect(void)
01232 {
01233    struct sockaddr_un sunaddr;
01234    int res;
01235    ast_consock = socket(PF_LOCAL, SOCK_STREAM, 0);
01236    if (ast_consock < 0) {
01237       ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno));
01238       return 0;
01239    }
01240    memset(&sunaddr, 0, sizeof(sunaddr));
01241    sunaddr.sun_family = AF_LOCAL;
01242    ast_copy_string(sunaddr.sun_path, (char *)ast_config_AST_SOCKET, sizeof(sunaddr.sun_path));
01243    res = connect(ast_consock, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
01244    if (res) {
01245       close(ast_consock);
01246       ast_consock = -1;
01247       return 0;
01248    } else
01249       return 1;
01250 }
01251 
01252 /*! \brief Urgent handler
01253 
01254  Called by soft_hangup to interrupt the poll, read, or other
01255  system call.  We don't actually need to do anything though.  
01256  Remember: Cannot EVER ast_log from within a signal handler 
01257  */
01258 static void urg_handler(int num)
01259 {
01260    signal(num, urg_handler);
01261    return;
01262 }
01263 
01264 static void hup_handler(int num)
01265 {
01266    int a = 0;
01267    if (option_verbose > 1) 
01268       printf("Received HUP signal -- Reloading configs\n");
01269    if (restartnow)
01270       execvp(_argv[0], _argv);
01271    sig_flags.need_reload = 1;
01272    if (sig_alert_pipe[1] != -1) {
01273       if (write(sig_alert_pipe[1], &a, sizeof(a)) < 0) {
01274          fprintf(stderr, "hup_handler: write() failed: %s\n", strerror(errno));
01275       }
01276    }
01277    signal(num, hup_handler);
01278 }
01279 
01280 static void child_handler(int sig)
01281 {
01282    /* Must not ever ast_log or ast_verbose within signal handler */
01283    int n, status;
01284 
01285    /*
01286     * Reap all dead children -- not just one
01287     */
01288    for (n = 0; wait4(-1, &status, WNOHANG, NULL) > 0; n++)
01289       ;
01290    if (n == 0 && option_debug)   
01291       printf("Huh?  Child handler, but nobody there?\n");
01292    signal(sig, child_handler);
01293 }
01294 
01295 /*! \brief Set maximum open files */
01296 static void set_ulimit(int value)
01297 {
01298    struct rlimit l = {0, 0};
01299    
01300    if (value <= 0) {
01301       ast_log(LOG_WARNING, "Unable to change max files open to invalid value %i\n",value);
01302       return;
01303    }
01304    
01305    l.rlim_cur = value;
01306    l.rlim_max = value;
01307    
01308    if (setrlimit(RLIMIT_NOFILE, &l)) {
01309       ast_log(LOG_WARNING, "Unable to disable core size resource limit: %s\n",strerror(errno));
01310       return;
01311    }
01312    ast_log(LOG_NOTICE, "Setting max files open to %d\n",value);
01313    return;
01314 }
01315 
01316 /*! \brief Set an X-term or screen title */
01317 static void set_title(char *text)
01318 {
01319    if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
01320       fprintf(stdout, "\033]2;%s\007", text);
01321 }
01322 
01323 static void set_icon(char *text)
01324 {
01325    if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
01326       fprintf(stdout, "\033]1;%s\007", text);
01327 }
01328 
01329 /*! \brief We set ourselves to a high priority, that we might pre-empt everything
01330    else.  If your PBX has heavy activity on it, this is a good thing.  */
01331 int ast_set_priority(int pri)
01332 {
01333    struct sched_param sched;
01334    memset(&sched, 0, sizeof(sched));
01335 #ifdef __linux__
01336    if (pri) {  
01337       sched.sched_priority = 10;
01338       if (sched_setscheduler(0, SCHED_RR, &sched)) {
01339          ast_log(LOG_WARNING, "Unable to set high priority\n");
01340          return -1;
01341       } else
01342          if (option_verbose)
01343             ast_verbose("Set to realtime thread\n");
01344    } else {
01345       sched.sched_priority = 0;
01346       /* According to the manpage, these parameters can never fail. */
01347       sched_setscheduler(0, SCHED_OTHER, &sched);
01348    }
01349 #else
01350    if (pri) {
01351       if (setpriority(PRIO_PROCESS, 0, -10) == -1) {
01352          ast_log(LOG_WARNING, "Unable to set high priority\n");
01353          return -1;
01354       } else
01355          if (option_verbose)
01356             ast_verbose("Set to high priority\n");
01357    } else {
01358       /* According to the manpage, these parameters can never fail. */
01359       setpriority(PRIO_PROCESS, 0, 0);
01360    }
01361 #endif
01362    return 0;
01363 }
01364 
01365 static void ast_run_atexits(void)
01366 {
01367    struct ast_atexit *ae;
01368    AST_LIST_LOCK(&atexits);
01369    AST_LIST_TRAVERSE(&atexits, ae, list) {
01370       if (ae->func) 
01371          ae->func();
01372    }
01373    AST_LIST_UNLOCK(&atexits);
01374 }
01375 
01376 static void quit_handler(int num, int nice, int safeshutdown, int restart)
01377 {
01378    char filename[80] = "";
01379    time_t s,e;
01380    int x;
01381    /* Try to get as many CDRs as possible submitted to the backend engines (if in batch mode) */
01382    ast_cdr_engine_term();
01383    if (safeshutdown) {
01384       shuttingdown = 1;
01385       if (!nice) {
01386          /* Begin shutdown routine, hanging up active channels */
01387          ast_begin_shutdown(1);
01388          if (option_verbose && ast_opt_console)
01389             ast_verbose("Beginning asterisk %s....\n", restart ? "restart" : "shutdown");
01390          time(&s);
01391          for (;;) {
01392             time(&e);
01393             /* Wait up to 15 seconds for all channels to go away */
01394             if ((e - s) > 15)
01395                break;
01396             if (!ast_active_channels())
01397                break;
01398             if (!shuttingdown)
01399                break;
01400             /* Sleep 1/10 of a second */
01401             usleep(100000);
01402          }
01403       } else {
01404          if (nice < 2)
01405             ast_begin_shutdown(0);
01406          if (option_verbose && ast_opt_console)
01407             ast_verbose("Waiting for inactivity to perform %s...\n", restart ? "restart" : "halt");
01408          for (;;) {
01409             if (!ast_active_channels())
01410                break;
01411             if (!shuttingdown)
01412                break;
01413             sleep(1);
01414          }
01415       }
01416 
01417       if (!shuttingdown) {
01418          if (option_verbose && ast_opt_console)
01419             ast_verbose("Asterisk %s cancelled.\n", restart ? "restart" : "shutdown");
01420          return;
01421       }
01422 
01423       if (nice)
01424          ast_module_shutdown();
01425    }
01426    if (ast_opt_console || ast_opt_remote) {
01427       if (getenv("HOME")) 
01428          snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
01429       if (!ast_strlen_zero(filename))
01430          ast_el_write_history(filename);
01431       if (el != NULL)
01432          el_end(el);
01433       if (el_hist != NULL)
01434          history_end(el_hist);
01435    }
01436    if (option_verbose)
01437       ast_verbose("Executing last minute cleanups\n");
01438    ast_run_atexits();
01439    /* Called on exit */
01440    if (option_verbose && ast_opt_console)
01441       ast_verbose("Asterisk %s ending (%d).\n", ast_active_channels() ? "uncleanly" : "cleanly", num);
01442    if (option_debug)
01443       ast_log(LOG_DEBUG, "Asterisk ending (%d).\n", num);
01444    manager_event(EVENT_FLAG_SYSTEM, "Shutdown", "Shutdown: %s\r\nRestart: %s\r\n", ast_active_channels() ? "Uncleanly" : "Cleanly", restart ? "True" : "False");
01445    if (ast_socket > -1) {
01446       pthread_cancel(lthread);
01447       close(ast_socket);
01448       ast_socket = -1;
01449       unlink(ast_config_AST_SOCKET);
01450    }
01451    if (ast_consock > -1)
01452       close(ast_consock);
01453    if (!ast_opt_remote)
01454       unlink(ast_config_AST_PID);
01455    printf("%s", term_quit());
01456    if (restart) {
01457       if (option_verbose || ast_opt_console)
01458          ast_verbose("Preparing for Asterisk restart...\n");
01459       /* Mark all FD's for closing on exec */
01460       for (x=3; x < 32768; x++) {
01461          fcntl(x, F_SETFD, FD_CLOEXEC);
01462       }
01463       if (option_verbose || ast_opt_console)
01464          ast_verbose("Asterisk is now restarting...\n");
01465       restartnow = 1;
01466 
01467       /* close logger */
01468       close_logger();
01469 
01470       /* If there is a consolethread running send it a SIGHUP 
01471          so it can execvp, otherwise we can do it ourselves */
01472       if ((consolethread != AST_PTHREADT_NULL) && (consolethread != pthread_self())) {
01473          pthread_kill(consolethread, SIGHUP);
01474          /* Give the signal handler some time to complete */
01475          sleep(2);
01476       } else
01477          execvp(_argv[0], _argv);
01478    
01479    } else {
01480       /* close logger */
01481       close_logger();
01482    }
01483    exit(0);
01484 }
01485 
01486 static void __quit_handler(int num)
01487 {
01488    int a = 0;
01489    sig_flags.need_quit = 1;
01490    if (sig_alert_pipe[1] != -1) {
01491       if (write(sig_alert_pipe[1], &a, sizeof(a)) < 0) {
01492          fprintf(stderr, "hup_handler: write() failed: %s\n", strerror(errno));
01493       }
01494    }
01495    /* There is no need to restore the signal handler here, since the app
01496     * is going to exit */
01497 }
01498 
01499 static void __remote_quit_handler(int num)
01500 {
01501    sig_flags.need_quit = 1;
01502 }
01503 
01504 static const char *fix_header(char *outbuf, int maxout, const char *s, char *cmp)
01505 {
01506    const char *c;
01507 
01508    /* Check for verboser preamble */
01509    if (*s == 127) {
01510       s++;
01511    }
01512 
01513    if (!strncmp(s, cmp, strlen(cmp))) {
01514       c = s + strlen(cmp);
01515       term_color(outbuf, cmp, COLOR_GRAY, 0, maxout);
01516       return c;
01517    }
01518    return NULL;
01519 }
01520 
01521 static void console_verboser(const char *s)
01522 {
01523    char tmp[80];
01524    const char *c = NULL;
01525 
01526    if ((c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_4)) ||
01527        (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_3)) ||
01528        (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_2)) ||
01529        (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_1))) {
01530       fputs(tmp, stdout);
01531       fputs(c, stdout);
01532    } else {
01533       if (*s == 127) {
01534          s++;
01535       }
01536       fputs(s, stdout);
01537    }
01538 
01539    fflush(stdout);
01540    
01541    /* Wake up a poll()ing console */
01542    if (ast_opt_console && consolethread != AST_PTHREADT_NULL)
01543       pthread_kill(consolethread, SIGURG);
01544 }
01545 
01546 static int ast_all_zeros(char *s)
01547 {
01548    while (*s) {
01549       if (*s > 32)
01550          return 0;
01551       s++;  
01552    }
01553    return 1;
01554 }
01555 
01556 static void consolehandler(char *s)
01557 {
01558    printf("%s", term_end());
01559    fflush(stdout);
01560 
01561    /* Called when readline data is available */
01562    if (!ast_all_zeros(s))
01563       ast_el_add_history(s);
01564    /* The real handler for bang */
01565    if (s[0] == '!') {
01566       if (s[1])
01567          ast_safe_system(s+1);
01568       else
01569          ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
01570    } else 
01571       ast_cli_command(STDOUT_FILENO, s);
01572 }
01573 
01574 static int remoteconsolehandler(char *s)
01575 {
01576    int ret = 0;
01577 
01578    /* Called when readline data is available */
01579    if (!ast_all_zeros(s))
01580       ast_el_add_history(s);
01581    /* The real handler for bang */
01582    if (s[0] == '!') {
01583       if (s[1])
01584          ast_safe_system(s+1);
01585       else
01586          ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
01587       ret = 1;
01588    }
01589    if ((strncasecmp(s, "quit", 4) == 0 || strncasecmp(s, "exit", 4) == 0) &&
01590        (s[4] == '\0' || isspace(s[4]))) {
01591       quit_handler(0, 0, 0, 0);
01592       ret = 1;
01593    }
01594 
01595    return ret;
01596 }
01597 
01598 static char abort_halt_help[] = 
01599 "Usage: abort shutdown\n"
01600 "       Causes Asterisk to abort an executing shutdown or restart, and resume normal\n"
01601 "       call operations.\n";
01602 
01603 static char shutdown_now_help[] = 
01604 "Usage: stop now\n"
01605 "       Shuts down a running Asterisk immediately, hanging up all active calls .\n";
01606 
01607 static char shutdown_gracefully_help[] = 
01608 "Usage: stop gracefully\n"
01609 "       Causes Asterisk to not accept new calls, and exit when all\n"
01610 "       active calls have terminated normally.\n";
01611 
01612 static char shutdown_when_convenient_help[] = 
01613 "Usage: stop when convenient\n"
01614 "       Causes Asterisk to perform a shutdown when all active calls have ended.\n";
01615 
01616 static char restart_now_help[] = 
01617 "Usage: restart now\n"
01618 "       Causes Asterisk to hangup all calls and exec() itself performing a cold\n"
01619 "       restart.\n";
01620 
01621 static char restart_gracefully_help[] = 
01622 "Usage: restart gracefully\n"
01623 "       Causes Asterisk to stop accepting new calls and exec() itself performing a cold\n"
01624 "       restart when all active calls have ended.\n";
01625 
01626 static char restart_when_convenient_help[] = 
01627 "Usage: restart when convenient\n"
01628 "       Causes Asterisk to perform a cold restart when all active calls have ended.\n";
01629 
01630 static char bang_help[] =
01631 "Usage: !<command>\n"
01632 "       Executes a given shell command\n";
01633 
01634 static char show_warranty_help[] =
01635 "Usage: core show warranty\n"
01636 "  Shows the warranty (if any) for this copy of Asterisk.\n";
01637 
01638 static char show_license_help[] =
01639 "Usage: core show license\n"
01640 "  Shows the license(s) for this copy of Asterisk.\n";
01641 
01642 static char version_help[] =
01643 "Usage: core show version\n"
01644 "       Shows Asterisk version information.\n";
01645 
01646 static int handle_version_deprecated(int fd, int argc, char *argv[])
01647 {
01648    if (argc != 2)
01649       return RESULT_SHOWUSAGE;
01650    ast_cli(fd, "Asterisk %s built by %s @ %s on a %s running %s on %s\n",
01651       ASTERISK_VERSION, ast_build_user, ast_build_hostname,
01652       ast_build_machine, ast_build_os, ast_build_date);
01653    return RESULT_SUCCESS;
01654 }
01655 
01656 static int handle_version(int fd, int argc, char *argv[])
01657 {
01658    if (argc != 3)
01659       return RESULT_SHOWUSAGE;
01660    ast_cli(fd, "Asterisk %s built by %s @ %s on a %s running %s on %s\n",
01661       ASTERISK_VERSION, ast_build_user, ast_build_hostname,
01662       ast_build_machine, ast_build_os, ast_build_date);
01663    return RESULT_SUCCESS;
01664 }
01665 
01666 #if 0
01667 static int handle_quit(int fd, int argc, char *argv[])
01668 {
01669    if (argc != 1)
01670       return RESULT_SHOWUSAGE;
01671    quit_handler(0, 0, 1, 0);
01672    return RESULT_SUCCESS;
01673 }
01674 #endif
01675 
01676 static int handle_shutdown_now(int fd, int argc, char *argv[])
01677 {
01678    if (argc != 2)
01679       return RESULT_SHOWUSAGE;
01680    quit_handler(0, 0 /* Not nice */, 1 /* safely */, 0 /* not restart */);
01681    return RESULT_SUCCESS;
01682 }
01683 
01684 static int handle_shutdown_gracefully(int fd, int argc, char *argv[])
01685 {
01686    if (argc != 2)
01687       return RESULT_SHOWUSAGE;
01688    quit_handler(0, 1 /* nicely */, 1 /* safely */, 0 /* no restart */);
01689    return RESULT_SUCCESS;
01690 }
01691 
01692 static int handle_shutdown_when_convenient(int fd, int argc, char *argv[])
01693 {
01694    if (argc != 3)
01695       return RESULT_SHOWUSAGE;
01696    ast_cli(fd, "Waiting for inactivity to perform halt\n");
01697    quit_handler(0, 2 /* really nicely */, 1 /* safely */, 0 /* don't restart */);
01698    return RESULT_SUCCESS;
01699 }
01700 
01701 static int handle_restart_now(int fd, int argc, char *argv[])
01702 {
01703    if (argc != 2)
01704       return RESULT_SHOWUSAGE;
01705    quit_handler(0, 0 /* not nicely */, 1 /* safely */, 1 /* restart */);
01706    return RESULT_SUCCESS;
01707 }
01708 
01709 static int handle_restart_gracefully(int fd, int argc, char *argv[])
01710 {
01711    if (argc != 2)
01712       return RESULT_SHOWUSAGE;
01713    quit_handler(0, 1 /* nicely */, 1 /* safely */, 1 /* restart */);
01714    return RESULT_SUCCESS;
01715 }
01716 
01717 static int handle_restart_when_convenient(int fd, int argc, char *argv[])
01718 {
01719    if (argc != 3)
01720       return RESULT_SHOWUSAGE;
01721    ast_cli(fd, "Waiting for inactivity to perform restart\n");
01722    quit_handler(0, 2 /* really nicely */, 1 /* safely */, 1 /* restart */);
01723    return RESULT_SUCCESS;
01724 }
01725 
01726 static int handle_abort_halt(int fd, int argc, char *argv[])
01727 {
01728    if (argc != 2)
01729       return RESULT_SHOWUSAGE;
01730    ast_cancel_shutdown();
01731    shuttingdown = 0;
01732    return RESULT_SUCCESS;
01733 }
01734 
01735 static int handle_bang(int fd, int argc, char *argv[])
01736 {
01737    return RESULT_SUCCESS;
01738 }
01739 static const char *warranty_lines[] = {
01740    "\n",
01741    "            NO WARRANTY\n",
01742    "\n",
01743    "BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\n",
01744    "FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN\n",
01745    "OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\n",
01746    "PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\n",
01747    "OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n",
01748    "MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS\n",
01749    "TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE\n",
01750    "PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\n",
01751    "REPAIR OR CORRECTION.\n",
01752    "\n",
01753    "IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\n",
01754    "WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\n",
01755    "REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\n",
01756    "INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\n",
01757    "OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\n",
01758    "TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\n",
01759    "YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\n",
01760    "PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\n",
01761    "POSSIBILITY OF SUCH DAMAGES.\n",
01762 };
01763 
01764 static int show_warranty(int fd, int argc, char *argv[])
01765 {
01766    int x;
01767 
01768    for (x = 0; x < ARRAY_LEN(warranty_lines); x++)
01769       ast_cli(fd, "%s", (char *) warranty_lines[x]);
01770 
01771    return RESULT_SUCCESS;
01772 }
01773 
01774 static const char *license_lines[] = {
01775    "\n",
01776    "This program is free software; you can redistribute it and/or modify\n",
01777    "it under the terms of the GNU General Public License version 2 as\n",
01778    "published by the Free Software Foundation.\n",
01779    "\n",
01780    "This program also contains components licensed under other licenses.\n",
01781    "They include:\n",
01782    "\n",
01783    "This program is distributed in the hope that it will be useful,\n",
01784    "but WITHOUT ANY WARRANTY; without even the implied warranty of\n",
01785    "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n",
01786    "GNU General Public License for more details.\n",
01787    "\n",
01788    "You should have received a copy of the GNU General Public License\n",
01789    "along with this program; if not, write to the Free Software\n",
01790    "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\n",
01791 };
01792 
01793 static int show_license(int fd, int argc, char *argv[])
01794 {
01795    int x;
01796 
01797    for (x = 0; x < ARRAY_LEN(license_lines); x++)
01798       ast_cli(fd, "%s", (char *) license_lines[x]);
01799 
01800    return RESULT_SUCCESS;
01801 }
01802 
01803 #define ASTERISK_PROMPT "*CLI> "
01804 
01805 #define ASTERISK_PROMPT2 "%s*CLI> "
01806 
01807 static struct ast_cli_entry cli_show_version_deprecated = {
01808    { "show", "version", NULL },
01809    handle_version_deprecated, "Display version info",
01810    version_help };
01811 
01812 #if !defined(LOW_MEMORY)
01813 static struct ast_cli_entry cli_show_version_files_deprecated = {
01814    { "show", "version", "files", NULL },
01815    handle_show_version_files_deprecated, NULL,
01816    NULL, complete_show_version_files_deprecated };
01817 
01818 static struct ast_cli_entry cli_show_profile_deprecated = {
01819    { "show", "profile", NULL },
01820    handle_show_profile_deprecated, NULL,
01821    NULL };
01822 
01823 static struct ast_cli_entry cli_clear_profile_deprecated = {
01824    { "clear", "profile", NULL },
01825    handle_show_profile_deprecated, NULL,
01826    NULL };
01827 #endif /* ! LOW_MEMORY */
01828 
01829 static struct ast_cli_entry cli_asterisk[] = {
01830    { { "abort", "halt", NULL },
01831    handle_abort_halt, "Cancel a running halt",
01832    abort_halt_help },
01833 
01834    { { "stop", "now", NULL },
01835    handle_shutdown_now, "Shut down Asterisk immediately",
01836    shutdown_now_help },
01837 
01838    { { "stop", "gracefully", NULL },
01839    handle_shutdown_gracefully, "Gracefully shut down Asterisk",
01840    shutdown_gracefully_help },
01841 
01842    { { "stop", "when", "convenient", NULL },
01843    handle_shutdown_when_convenient, "Shut down Asterisk at empty call volume",
01844    shutdown_when_convenient_help },
01845 
01846    { { "restart", "now", NULL },
01847    handle_restart_now, "Restart Asterisk immediately",
01848    restart_now_help },
01849 
01850    { { "restart", "gracefully", NULL },
01851    handle_restart_gracefully, "Restart Asterisk gracefully",
01852    restart_gracefully_help },
01853 
01854    { { "restart", "when", "convenient", NULL },
01855    handle_restart_when_convenient, "Restart Asterisk at empty call volume",
01856    restart_when_convenient_help },
01857 
01858    { { "core", "show", "warranty", NULL },
01859    show_warranty, "Show the warranty (if any) for this copy of Asterisk",
01860    show_warranty_help },
01861 
01862    { { "core", "show", "license", NULL },
01863    show_license, "Show the license(s) for this copy of Asterisk",
01864    show_license_help },
01865 
01866    { { "core", "show", "version", NULL },
01867    handle_version, "Display version info",
01868    version_help, NULL, &cli_show_version_deprecated },
01869 
01870    { { "!", NULL },
01871    handle_bang, "Execute a shell command",
01872    bang_help },
01873 
01874 #if !defined(LOW_MEMORY)
01875    { { "core", "show", "file", "version", NULL },
01876    handle_show_version_files, "List versions of files used to build Asterisk",
01877    show_version_files_help, complete_show_version_files, &cli_show_version_files_deprecated },
01878 
01879    { { "core", "show", "settings", NULL },
01880    handle_show_settings, "Show some core settings",
01881    show_settings_help },
01882 
01883    { { "core", "show", "threads", NULL },
01884    handle_show_threads, "Show running threads",
01885    show_threads_help },
01886 
01887    { { "core", "show", "sysinfo", NULL },
01888    handle_show_sysinfo, "Show System Information",
01889    show_sysinfo_help },
01890 
01891    { { "core", "show", "profile", NULL },
01892    handle_show_profile, "Display profiling info",
01893    NULL, NULL, &cli_show_profile_deprecated },
01894 
01895    { { "core", "clear", "profile", NULL },
01896    handle_show_profile, "Clear profiling info",
01897    NULL, NULL, &cli_clear_profile_deprecated },
01898 #endif /* ! LOW_MEMORY */
01899 };
01900 
01901 static int ast_el_read_char(EditLine *el, char *cp)
01902 {
01903    int num_read = 0;
01904    int lastpos = 0;
01905    struct pollfd fds[2];
01906    int res;
01907    int max;
01908 #define EL_BUF_SIZE 512
01909    char buf[EL_BUF_SIZE];
01910 
01911    for (;;) {
01912       max = 1;
01913       fds[0].fd = ast_consock;
01914       fds[0].events = POLLIN;
01915       if (!ast_opt_exec) {
01916          fds[1].fd = STDIN_FILENO;
01917          fds[1].events = POLLIN;
01918          max++;
01919       }
01920       res = poll(fds, max, -1);
01921       if (res < 0) {
01922          if (sig_flags.need_quit)
01923             break;
01924          if (errno == EINTR)
01925             continue;
01926          ast_log(LOG_ERROR, "poll failed: %s\n", strerror(errno));
01927          break;
01928       }
01929 
01930       if (!ast_opt_exec && fds[1].revents) {
01931          num_read = read(STDIN_FILENO, cp, 1);
01932          if (num_read < 1) {
01933             break;
01934          } else 
01935             return (num_read);
01936       }
01937       if (fds[0].revents) {
01938          char *tmp;
01939          res = read(ast_consock, buf, sizeof(buf) - 1);
01940          /* if the remote side disappears exit */
01941          if (res < 1) {
01942             fprintf(stderr, "\nDisconnected from Asterisk server\n");
01943             if (!ast_opt_reconnect) {
01944                quit_handler(0, 0, 0, 0);
01945             } else {
01946                int tries;
01947                int reconnects_per_second = 20;
01948                fprintf(stderr, "Attempting to reconnect for 30 seconds\n");
01949                for (tries=0; tries < 30 * reconnects_per_second; tries++) {
01950                   if (ast_tryconnect()) {
01951                      fprintf(stderr, "Reconnect succeeded after %.3f seconds\n", 1.0 / reconnects_per_second * tries);
01952                      printf("%s", term_quit());
01953                      WELCOME_MESSAGE;
01954                      if (!ast_opt_mute)
01955                         fdsend(ast_consock, "logger mute silent");
01956                      else {
01957                         snprintf(tmp, sizeof(tmp), "log and verbose output currently muted ('logger unmute' to unmute)");
01958                         fdprint(ast_consock, tmp);
01959                      }
01960 
01961                      break;
01962                   } else {
01963                      usleep(1000000 / reconnects_per_second);
01964                   }
01965                }
01966                if (tries >= 30 * reconnects_per_second) {
01967                   fprintf(stderr, "Failed to reconnect for 30 seconds.  Quitting.\n");
01968                   quit_handler(0, 0, 0, 0);
01969                }
01970             }
01971          }
01972 
01973          buf[res] = '\0';
01974 
01975          /* Strip preamble from asynchronous events, too */
01976          for (tmp = buf; *tmp; tmp++) {
01977             if (*tmp == 127) {
01978                memmove(tmp, tmp + 1, strlen(tmp));
01979                tmp--;
01980                res--;
01981             }
01982          }
01983 
01984          /* Write over the CLI prompt */
01985          if (!ast_opt_exec && !lastpos) {
01986             if (write(STDOUT_FILENO, "\r", 1) < 0) {
01987             }
01988          }
01989          if (write(STDOUT_FILENO, buf, res) < 0) {
01990          }
01991          if ((res < EL_BUF_SIZE - 1) && ((buf[res-1] == '\n') || (buf[res-2] == '\n'))) {
01992             *cp = CC_REFRESH;
01993             return(1);
01994          } else {
01995             lastpos = 1;
01996          }
01997       }
01998    }
01999 
02000    *cp = '\0';
02001    return (0);
02002 }
02003 
02004 static char *cli_prompt(EditLine *el)
02005 {
02006    static char prompt[200];
02007    char *pfmt;
02008    int color_used = 0;
02009    char term_code[20];
02010 
02011    if ((pfmt = getenv("ASTERISK_PROMPT"))) {
02012       char *t = pfmt, *p = prompt;
02013       memset(prompt, 0, sizeof(prompt));
02014       while (*t != '\0' && *p < sizeof(prompt)) {
02015          if (*t == '%') {
02016             char hostname[MAXHOSTNAMELEN]="";
02017             int i;
02018             time_t ts;
02019             struct tm tm;
02020 #ifdef linux
02021             FILE *LOADAVG;
02022 #endif
02023             int fgcolor = COLOR_WHITE, bgcolor = COLOR_BLACK;
02024 
02025             t++;
02026             switch (*t) {
02027             case 'C': /* color */
02028                t++;
02029                if (sscanf(t, "%d;%d%n", &fgcolor, &bgcolor, &i) == 2) {
02030                   strncat(p, term_color_code(term_code, fgcolor, bgcolor, sizeof(term_code)),sizeof(prompt) - strlen(prompt) - 1);
02031                   t += i - 1;
02032                } else if (sscanf(t, "%d%n", &fgcolor, &i) == 1) {
02033                   strncat(p, term_color_code(term_code, fgcolor, 0, sizeof(term_code)),sizeof(prompt) - strlen(prompt) - 1);
02034                   t += i - 1;
02035                }
02036 
02037                /* If the color has been reset correctly, then there's no need to reset it later */
02038                if ((fgcolor == COLOR_WHITE) && (bgcolor == COLOR_BLACK)) {
02039                   color_used = 0;
02040                } else {
02041                   color_used = 1;
02042                }
02043                break;
02044             case 'd': /* date */
02045                memset(&tm, 0, sizeof(tm));
02046                time(&ts);
02047                if (ast_localtime(&ts, &tm, NULL)) {
02048                   strftime(p, sizeof(prompt) - strlen(prompt), "%Y-%m-%d", &tm);
02049                }
02050                break;
02051             case 'h': /* hostname */
02052                if (!gethostname(hostname, sizeof(hostname) - 1)) {
02053                   strncat(p, hostname, sizeof(prompt) - strlen(prompt) - 1);
02054                } else {
02055                   strncat(p, "localhost", sizeof(prompt) - strlen(prompt) - 1);
02056                }
02057                break;
02058             case 'H': /* short hostname */
02059                if (!gethostname(hostname, sizeof(hostname) - 1)) {
02060                   for (i = 0; i < sizeof(hostname); i++) {
02061                      if (hostname[i] == '.') {
02062                         hostname[i] = '\0';
02063                         break;
02064                      }
02065                   }
02066                   strncat(p, hostname, sizeof(prompt) - strlen(prompt) - 1);
02067                } else {
02068                   strncat(p, "localhost", sizeof(prompt) - strlen(prompt) - 1);
02069                }
02070                break;
02071 #ifdef linux
02072             case 'l': /* load avg */
02073                t++;
02074                if ((LOADAVG = fopen("/proc/loadavg", "r"))) {
02075                   float avg1, avg2, avg3;
02076                   int actproc, totproc, npid, which;
02077 
02078                   if (fscanf(LOADAVG, "%f %f %f %d/%d %d",
02079                         &avg1, &avg2, &avg3, &actproc, &totproc, &npid) != 6) {
02080                      ast_log(LOG_WARNING, "parsing /proc/loadavg failed\n");
02081                      fclose(LOADAVG);
02082                      break;
02083                   }
02084                   if (sscanf(t, "%d", &which) == 1) {
02085                      switch (which) {
02086                      case 1:
02087                         snprintf(p, sizeof(prompt) - strlen(prompt), "%.2f", avg1);
02088                         break;
02089                      case 2:
02090                         snprintf(p, sizeof(prompt) - strlen(prompt), "%.2f", avg2);
02091                         break;
02092                      case 3:
02093                         snprintf(p, sizeof(prompt) - strlen(prompt), "%.2f", avg3);
02094                         break;
02095                      case 4:
02096                         snprintf(p, sizeof(prompt) - strlen(prompt), "%d/%d", actproc, totproc);
02097                         break;
02098                      case 5:
02099                         snprintf(p, sizeof(prompt) - strlen(prompt), "%d", npid);
02100                         break;
02101                      }
02102                   }
02103                   fclose(LOADAVG);
02104                }
02105                break;
02106 #endif
02107             case 's': /* Asterisk system name (from asterisk.conf) */
02108                strncat(p, ast_config_AST_SYSTEM_NAME, sizeof(prompt) - strlen(prompt) - 1);
02109                break;
02110             case 't': /* time */
02111                memset(&tm, 0, sizeof(tm));
02112                time(&ts);
02113                if (ast_localtime(&ts, &tm, NULL)) {
02114                   strftime(p, sizeof(prompt) - strlen(prompt), "%H:%M:%S", &tm);
02115                }
02116                break;
02117             case '#': /* process console or remote? */
02118                if (!ast_opt_remote) {
02119                   strncat(p, "#", sizeof(prompt) - strlen(prompt) - 1);
02120                } else {
02121                   strncat(p, ">", sizeof(prompt) - strlen(prompt) - 1);
02122                }
02123                break;
02124             case '%': /* literal % */
02125                strncat(p, "%", sizeof(prompt) - strlen(prompt) - 1);
02126                break;
02127             case '\0': /* % is last character - prevent bug */
02128                t--;
02129                break;
02130             }
02131             while (*p != '\0') {
02132                p++;
02133             }
02134             t++;
02135          } else {
02136             *p = *t;
02137             p++;
02138             t++;
02139          }
02140       }
02141       if (color_used) {
02142          /* Force colors back to normal at end */
02143          term_color_code(term_code, COLOR_WHITE, COLOR_BLACK, sizeof(term_code));
02144          if (strlen(term_code) > sizeof(prompt) - strlen(prompt) - 1) {
02145             ast_copy_string(prompt + sizeof(prompt) - strlen(term_code) - 1, term_code, strlen(term_code) + 1);
02146          } else {
02147             /* This looks wrong, but we've already checked the length of term_code to ensure it's safe */
02148             strncat(p, term_code, sizeof(term_code));
02149          }
02150       }
02151    } else if (remotehostname)
02152       snprintf(prompt, sizeof(prompt), ASTERISK_PROMPT2, remotehostname);
02153    else
02154       ast_copy_string(prompt, ASTERISK_PROMPT, sizeof(prompt));
02155 
02156    return(prompt);   
02157 }
02158 
02159 static char **ast_el_strtoarr(char *buf)
02160 {
02161    char **match_list = NULL, *retstr;
02162    size_t match_list_len;
02163    int matches = 0;
02164 
02165    match_list_len = 1;
02166    while ( (retstr = strsep(&buf, " ")) != NULL) {
02167 
02168       if (!strcmp(retstr, AST_CLI_COMPLETE_EOF))
02169          break;
02170       if (matches + 1 >= match_list_len) {
02171          match_list_len <<= 1;
02172          if (!(match_list = ast_realloc(match_list, match_list_len * sizeof(char *)))) {
02173             /* TODO: Handle memory allocation failure */
02174          }
02175       }
02176 
02177       match_list[matches++] = ast_strdup(retstr);
02178    }
02179 
02180    if (!match_list)
02181       return (char **) NULL;
02182 
02183    if (matches >= match_list_len) {
02184       if (!(match_list = ast_realloc(match_list, (match_list_len + 1) * sizeof(char *)))) {
02185          /* TODO: Handle memory allocation failure */
02186       }
02187    }
02188 
02189    match_list[matches] = (char *) NULL;
02190 
02191    return match_list;
02192 }
02193 
02194 static int ast_el_sort_compare(const void *i1, const void *i2)
02195 {
02196    char *s1, *s2;
02197 
02198    s1 = ((char **)i1)[0];
02199    s2 = ((char **)i2)[0];
02200 
02201    return strcasecmp(s1, s2);
02202 }
02203 
02204 static int ast_cli_display_match_list(char **matches, int len, int max)
02205 {
02206    int i, idx, limit, count;
02207    int screenwidth = 0;
02208    int numoutput = 0, numoutputline = 0;
02209 
02210    screenwidth = ast_get_termcols(STDOUT_FILENO);
02211 
02212    /* find out how many entries can be put on one line, with two spaces between strings */
02213    limit = screenwidth / (max + 2);
02214    if (limit == 0)
02215       limit = 1;
02216 
02217    /* how many lines of output */
02218    count = len / limit;
02219    if (count * limit < len)
02220       count++;
02221 
02222    idx = 1;
02223 
02224    qsort(&matches[0], (size_t)(len), sizeof(char *), ast_el_sort_compare);
02225 
02226    for (; count > 0; count--) {
02227       numoutputline = 0;
02228       for (i=0; i < limit && matches[idx]; i++, idx++) {
02229 
02230          /* Don't print dupes */
02231          if ( (matches[idx+1] != NULL && strcmp(matches[idx], matches[idx+1]) == 0 ) ) {
02232             i--;
02233             ast_free(matches[idx]);
02234             matches[idx] = NULL;
02235             continue;
02236          }
02237 
02238          numoutput++;
02239          numoutputline++;
02240          fprintf(stdout, "%-*s  ", max, matches[idx]);
02241          ast_free(matches[idx]);
02242          matches[idx] = NULL;
02243       }
02244       if (numoutputline > 0)
02245          fprintf(stdout, "\n");
02246    }
02247 
02248    return numoutput;
02249 }
02250 
02251 
02252 static char *cli_complete(EditLine *el, int ch)
02253 {
02254    int len = 0;
02255    char *ptr;
02256    int nummatches = 0;
02257    char **matches;
02258    int retval = CC_ERROR;
02259    char buf[2048];
02260    int res;
02261 
02262    LineInfo *lf = (LineInfo *)el_line(el);
02263 
02264    *(char *)lf->cursor = '\0';
02265    ptr = (char *)lf->cursor;
02266    if (ptr) {
02267       while (ptr > lf->buffer) {
02268          if (isspace(*ptr)) {
02269             ptr++;
02270             break;
02271          }
02272          ptr--;
02273       }
02274    }
02275 
02276    len = lf->cursor - ptr;
02277 
02278    if (ast_opt_remote) {
02279       snprintf(buf, sizeof(buf),"_COMMAND NUMMATCHES \"%s\" \"%s\"", lf->buffer, ptr); 
02280       fdsend(ast_consock, buf);
02281       res = read(ast_consock, buf, sizeof(buf));
02282       buf[res] = '\0';
02283       nummatches = atoi(buf);
02284 
02285       if (nummatches > 0) {
02286          char *mbuf;
02287          int mlen = 0, maxmbuf = 2048;
02288          /* Start with a 2048 byte buffer */       
02289          if (!(mbuf = ast_malloc(maxmbuf)))
02290             return (char *)(CC_ERROR);
02291          snprintf(buf, sizeof(buf),"_COMMAND MATCHESARRAY \"%s\" \"%s\"", lf->buffer, ptr); 
02292          fdsend(ast_consock, buf);
02293          res = 0;
02294          mbuf[0] = '\0';
02295          while (!strstr(mbuf, AST_CLI_COMPLETE_EOF) && res != -1) {
02296             if (mlen + 1024 > maxmbuf) {
02297                /* Every step increment buffer 1024 bytes */
02298                maxmbuf += 1024;              
02299                if (!(mbuf = ast_realloc(mbuf, maxmbuf)))
02300                   return (char *)(CC_ERROR);
02301             }
02302             /* Only read 1024 bytes at a time */
02303             res = read(ast_consock, mbuf + mlen, 1024);
02304             if (res > 0)
02305                mlen += res;
02306          }
02307          mbuf[mlen] = '\0';
02308 
02309          matches = ast_el_strtoarr(mbuf);
02310          ast_free(mbuf);
02311       } else
02312          matches = (char **) NULL;
02313    } else {
02314       char **p, *oldbuf=NULL;
02315       nummatches = 0;
02316       matches = ast_cli_completion_matches((char *)lf->buffer,ptr);
02317       for (p = matches; p && *p; p++) {
02318          if (!oldbuf || strcmp(*p,oldbuf))
02319             nummatches++;
02320          oldbuf = *p;
02321       }
02322    }
02323 
02324    if (matches) {
02325       int i;
02326       int matches_num, maxlen, match_len;
02327 
02328       if (matches[0][0] != '\0') {
02329          el_deletestr(el, (int) len);
02330          el_insertstr(el, matches[0]);
02331          retval = CC_REFRESH;
02332       }
02333 
02334       if (nummatches == 1) {
02335          /* Found an exact match */
02336          el_insertstr(el, " ");
02337          retval = CC_REFRESH;
02338       } else {
02339          /* Must be more than one match */
02340          for (i=1, maxlen=0; matches[i]; i++) {
02341             match_len = strlen(matches[i]);
02342             if (match_len > maxlen)
02343                maxlen = match_len;
02344          }
02345          matches_num = i - 1;
02346          if (matches_num >1) {
02347             fprintf(stdout, "\n");
02348             ast_cli_display_match_list(matches, nummatches, maxlen);
02349             retval = CC_REDISPLAY;
02350          } else { 
02351             el_insertstr(el," ");
02352             retval = CC_REFRESH;
02353          }
02354       }
02355       for (i = 0; matches[i]; i++)
02356          ast_free(matches[i]);
02357       ast_free(matches);
02358    }
02359 
02360    return (char *)(long)retval;
02361 }
02362 
02363 static int ast_el_initialize(void)
02364 {
02365    HistEvent ev;
02366    char *editor = getenv("AST_EDITOR");
02367 
02368    if (el != NULL)
02369       el_end(el);
02370    if (el_hist != NULL)
02371       history_end(el_hist);
02372 
02373    el = el_init("asterisk", stdin, stdout, stderr);
02374    el_set(el, EL_PROMPT, cli_prompt);
02375 
02376    el_set(el, EL_EDITMODE, 1);      
02377    el_set(el, EL_EDITOR, editor ? editor : "emacs");     
02378    el_hist = history_init();
02379    if (!el || !el_hist)
02380       return -1;
02381 
02382    /* setup history with 100 entries */
02383    history(el_hist, &ev, H_SETSIZE, 100);
02384 
02385    el_set(el, EL_HIST, history, el_hist);
02386 
02387    el_set(el, EL_ADDFN, "ed-complete", "Complete argument", cli_complete);
02388    /* Bind <tab> to command completion */
02389    el_set(el, EL_BIND, "^I", "ed-complete", NULL);
02390    /* Bind ? to command completion */
02391    el_set(el, EL_BIND, "?", "ed-complete", NULL);
02392    /* Bind ^D to redisplay */
02393    el_set(el, EL_BIND, "^D", "ed-redisplay", NULL);
02394 
02395    return 0;
02396 }
02397 
02398 static int ast_el_add_history(char *buf)
02399 {
02400    HistEvent ev;
02401 
02402    if (el_hist == NULL || el == NULL)
02403       ast_el_initialize();
02404    if (strlen(buf) > 256)
02405       return 0;
02406    return (history(el_hist, &ev, H_ENTER, buf));
02407 }
02408 
02409 static int ast_el_write_history(char *filename)
02410 {
02411    HistEvent ev;
02412 
02413    if (el_hist == NULL || el == NULL)
02414       ast_el_initialize();
02415 
02416    return (history(el_hist, &ev, H_SAVE, filename));
02417 }
02418 
02419 static int ast_el_read_history(char *filename)
02420 {
02421    char buf[256];
02422    FILE *f;
02423    int ret = -1;
02424 
02425    if (el_hist == NULL || el == NULL)
02426       ast_el_initialize();
02427 
02428    if ((f = fopen(filename, "r")) == NULL)
02429       return ret;
02430 
02431    while (!feof(f)) {
02432       if (!fgets(buf, sizeof(buf), f)) {
02433          continue;
02434       }
02435       if (!strcmp(buf, "_HiStOrY_V2_\n"))
02436          continue;
02437       if (ast_all_zeros(buf))
02438          continue;
02439       if ((ret = ast_el_add_history(buf)) == -1)
02440          break;
02441    }
02442    fclose(f);
02443 
02444    return ret;
02445 }
02446 
02447 static void ast_remotecontrol(char *data)
02448 {
02449    char buf[80];
02450    int res;
02451    char filename[80] = "";
02452    char *hostname;
02453    char *cpid;
02454    char *version;
02455    int pid;
02456    char tmp[80];
02457    char *stringp = NULL;
02458 
02459    char *ebuf;
02460    int num = 0;
02461 
02462    memset(&sig_flags, 0, sizeof(sig_flags));
02463    signal(SIGINT, __remote_quit_handler);
02464    signal(SIGTERM, __remote_quit_handler);
02465    signal(SIGHUP, __remote_quit_handler);
02466 
02467    if (read(ast_consock, buf, sizeof(buf)) < 0) {
02468       ast_log(LOG_ERROR, "read() failed: %s\n", strerror(errno));
02469       return;
02470    }
02471    if (data) {
02472       if (write(ast_consock, data, strlen(data) + 1) < 0) {
02473          ast_log(LOG_ERROR, "write() failed: %s\n", strerror(errno));
02474          if (sig_flags.need_quit == 1) {
02475             return;
02476          }
02477       }
02478    }
02479    stringp = buf;
02480    hostname = strsep(&stringp, "/");
02481    cpid = strsep(&stringp, "/");
02482    version = strsep(&stringp, "\n");
02483    if (!version)
02484       version = "<Version Unknown>";
02485    stringp = hostname;
02486    strsep(&stringp, ".");
02487    if (cpid)
02488       pid = atoi(cpid);
02489    else
02490       pid = -1;
02491    if (!data) {
02492       snprintf(tmp, sizeof(tmp), "core set verbose atleast %d", option_verbose);
02493       fdsend(ast_consock, tmp);
02494       snprintf(tmp, sizeof(tmp), "core set debug atleast %d", option_debug);
02495       fdsend(ast_consock, tmp);
02496       if (!ast_opt_mute)
02497          fdsend(ast_consock, "logger mute silent");
02498       else 
02499          printf("log and verbose output currently muted ('logger mute' to unmute)\n");
02500    }
02501    ast_verbose("Connected to Asterisk %s currently running on %s (pid = %d)\n", version, hostname, pid);
02502    remotehostname = hostname;
02503    if (getenv("HOME")) 
02504       snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
02505    if (el_hist == NULL || el == NULL)
02506       ast_el_initialize();
02507 
02508    el_set(el, EL_GETCFN, ast_el_read_char);
02509 
02510    if (!ast_strlen_zero(filename))
02511       ast_el_read_history(filename);
02512 
02513    if (ast_opt_exec && data) {  /* hack to print output then exit if asterisk -rx is used */
02514       struct pollfd fds;
02515       fds.fd = ast_consock;
02516       fds.events = POLLIN;
02517       fds.revents = 0;
02518       while (poll(&fds, 1, 500) > 0) {
02519          char buf[512] = "", *curline = buf, *nextline;
02520          int not_written = 1;
02521 
02522          if (sig_flags.need_quit == 1) {
02523             break;
02524          }
02525 
02526          if (read(ast_consock, buf, sizeof(buf) - 1) <= 0) {
02527             break;
02528          }
02529 
02530          do {
02531             if ((nextline = strchr(curline, '\n'))) {
02532                nextline++;
02533             } else {
02534                nextline = strchr(curline, '\0');
02535             }
02536 
02537             /* Skip verbose lines */
02538             if (*curline != 127) {
02539                not_written = 0;
02540                if (write(STDOUT_FILENO, curline, nextline - curline) < 0) {
02541                   ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno));
02542                }
02543             }
02544             curline = nextline;
02545          } while (!ast_strlen_zero(curline));
02546 
02547          /* No non-verbose output in 500ms */
02548          if (not_written) {
02549             break;
02550          }
02551       }
02552       return;
02553    }
02554    for (;;) {
02555       ebuf = (char *)el_gets(el, &num);
02556 
02557       if (sig_flags.need_quit == 1) {
02558          break;
02559       }
02560 
02561       if (!ebuf && write(1, "", 1) < 0)
02562          break;
02563 
02564       if (!ast_strlen_zero(ebuf)) {
02565          if (ebuf[strlen(ebuf)-1] == '\n')
02566             ebuf[strlen(ebuf)-1] = '\0';
02567          if (!remoteconsolehandler(ebuf)) {
02568             /* Strip preamble from output */
02569             char *tmp;
02570             for (tmp = ebuf; *tmp; tmp++) {
02571                if (*tmp == 127) {
02572                   memmove(tmp, tmp + 1, strlen(tmp));
02573                   tmp--;
02574                }
02575             }
02576             res = write(ast_consock, ebuf, strlen(ebuf) + 1);
02577             if (res < 1) {
02578                ast_log(LOG_WARNING, "Unable to write: %s\n", strerror(errno));
02579                break;
02580             }
02581          }
02582       }
02583    }
02584    printf("\nDisconnected from Asterisk server\n");
02585 }
02586 
02587 static int show_version(void)
02588 {
02589    printf("Asterisk " ASTERISK_VERSION "\n");
02590    return 0;
02591 }
02592 
02593 static int show_cli_help(void) {
02594    printf("Asterisk " ASTERISK_VERSION ", Copyright (C) 1999 - 2008, Digium, Inc. and others.\n");
02595    printf("Usage: asterisk [OPTIONS]\n");
02596    printf("Valid Options:\n");
02597    printf("   -V              Display version number and exit\n");
02598    printf("   -C <configfile> Use an alternate configuration file\n");
02599    printf("   -G <group>      Run as a group other than the caller\n");
02600    printf("   -U <user>       Run as a user other than the caller\n");
02601    printf("   -c              Provide console CLI\n");
02602    printf("   -d              Enable extra debugging\n");
02603 #if HAVE_WORKING_FORK
02604    printf("   -f              Do not fork\n");
02605    printf("   -F              Always fork\n");
02606 #endif
02607    printf("   -g              Dump core in case of a crash\n");
02608    printf("   -h              This help screen\n");
02609    printf("   -i              Initialize crypto keys at startup\n");
02610    printf("   -I              Enable internal timing if %s timer is available\n", dahdi_chan_name);
02611    printf("   -L <load>       Limit the maximum load average before rejecting new calls\n");
02612    printf("   -M <value>      Limit the maximum number of calls to the specified value\n");
02613    printf("   -m              Mute debugging and console output on the console\n");
02614    printf("   -n              Disable console colorization\n");
02615    printf("   -p              Run as pseudo-realtime thread\n");
02616    printf("   -q              Quiet mode (suppress output)\n");
02617    printf("   -r              Connect to Asterisk on this machine\n");
02618    printf("   -R              Same as -r, except attempt to reconnect if disconnected\n");
02619    printf("   -t              Record soundfiles in /var/tmp and move them where they\n");
02620    printf("                   belong after they are done\n");
02621    printf("   -T              Display the time in [Mmm dd hh:mm:ss] format for each line\n");
02622    printf("                   of output to the CLI\n");
02623    printf("   -v              Increase verbosity (multiple v's = more verbose)\n");
02624    printf("   -x <cmd>        Execute command <cmd> (only valid with -r)\n");
02625    printf("\n");
02626    return 0;
02627 }
02628 
02629 static void ast_readconfig(void) 
02630 {
02631    struct ast_config *cfg;
02632    struct ast_variable *v;
02633    char *config = AST_CONFIG_FILE;
02634 
02635    if (ast_opt_override_config) {
02636       cfg = ast_config_load(ast_config_AST_CONFIG_FILE);
02637       if (!cfg)
02638          ast_log(LOG_WARNING, "Unable to open specified master config file '%s', using built-in defaults\n", ast_config_AST_CONFIG_FILE);
02639    } else {
02640       cfg = ast_config_load(config);
02641    }
02642 
02643    /* init with buildtime config */
02644    ast_copy_string(ast_config_AST_CONFIG_DIR, AST_CONFIG_DIR, sizeof(ast_config_AST_CONFIG_DIR));
02645    ast_copy_string(ast_config_AST_SPOOL_DIR, AST_SPOOL_DIR, sizeof(ast_config_AST_SPOOL_DIR));
02646    ast_copy_string(ast_config_AST_MODULE_DIR, AST_MODULE_DIR, sizeof(ast_config_AST_MODULE_DIR));
02647    snprintf(ast_config_AST_MONITOR_DIR, sizeof(ast_config_AST_MONITOR_DIR) - 1, "%s/monitor", ast_config_AST_SPOOL_DIR);
02648    ast_copy_string(ast_config_AST_VAR_DIR, AST_VAR_DIR, sizeof(ast_config_AST_VAR_DIR));
02649    ast_copy_string(ast_config_AST_DATA_DIR, AST_DATA_DIR, sizeof(ast_config_AST_DATA_DIR));
02650    ast_copy_string(ast_config_AST_LOG_DIR, AST_LOG_DIR, sizeof(ast_config_AST_LOG_DIR));
02651    ast_copy_string(ast_config_AST_AGI_DIR, AST_AGI_DIR, sizeof(ast_config_AST_AGI_DIR));
02652    ast_copy_string(ast_config_AST_DB, AST_DB, sizeof(ast_config_AST_DB));
02653    ast_copy_string(ast_config_AST_KEY_DIR, AST_KEY_DIR, sizeof(ast_config_AST_KEY_DIR));
02654    ast_copy_string(ast_config_AST_PID, AST_PID, sizeof(ast_config_AST_PID));
02655    ast_copy_string(ast_config_AST_SOCKET, AST_SOCKET, sizeof(ast_config_AST_SOCKET));
02656    ast_copy_string(ast_config_AST_RUN_DIR, AST_RUN_DIR, sizeof(ast_config_AST_RUN_DIR));
02657 
02658    /* no asterisk.conf? no problem, use buildtime config! */
02659    if (!cfg) {
02660       return;
02661    }
02662 
02663    for (v = ast_variable_browse(cfg, "files"); v; v = v->next) {
02664       if (!strcasecmp(v->name, "astctlpermissions")) {
02665          ast_copy_string(ast_config_AST_CTL_PERMISSIONS, v->value, sizeof(ast_config_AST_CTL_PERMISSIONS));
02666       } else if (!strcasecmp(v->name, "astctlowner")) {
02667          ast_copy_string(ast_config_AST_CTL_OWNER, v->value, sizeof(ast_config_AST_CTL_OWNER));
02668       } else if (!strcasecmp(v->name, "astctlgroup")) {
02669          ast_copy_string(ast_config_AST_CTL_GROUP, v->value, sizeof(ast_config_AST_CTL_GROUP));
02670       } else if (!strcasecmp(v->name, "astctl")) {
02671          ast_copy_string(ast_config_AST_CTL, v->value, sizeof(ast_config_AST_CTL));
02672       }
02673    }
02674 
02675    for (v = ast_variable_browse(cfg, "directories"); v; v = v->next) {
02676       if (!strcasecmp(v->name, "astetcdir")) {
02677          ast_copy_string(ast_config_AST_CONFIG_DIR, v->value, sizeof(ast_config_AST_CONFIG_DIR));
02678       } else if (!strcasecmp(v->name, "astspooldir")) {
02679          ast_copy_string(ast_config_AST_SPOOL_DIR, v->value, sizeof(ast_config_AST_SPOOL_DIR));
02680          snprintf(ast_config_AST_MONITOR_DIR, sizeof(ast_config_AST_MONITOR_DIR) - 1, "%s/monitor", v->value);
02681       } else if (!strcasecmp(v->name, "astvarlibdir")) {
02682          ast_copy_string(ast_config_AST_VAR_DIR, v->value, sizeof(ast_config_AST_VAR_DIR));
02683          snprintf(ast_config_AST_DB, sizeof(ast_config_AST_DB), "%s/astdb", v->value);
02684       } else if (!strcasecmp(v->name, "astdatadir")) {
02685          ast_copy_string(ast_config_AST_DATA_DIR, v->value, sizeof(ast_config_AST_DATA_DIR));
02686          snprintf(ast_config_AST_KEY_DIR, sizeof(ast_config_AST_KEY_DIR), "%s/keys", v->value);
02687       } else if (!strcasecmp(v->name, "astlogdir")) {
02688          ast_copy_string(ast_config_AST_LOG_DIR, v->value, sizeof(ast_config_AST_LOG_DIR));
02689       } else if (!strcasecmp(v->name, "astagidir")) {
02690          ast_copy_string(ast_config_AST_AGI_DIR, v->value, sizeof(ast_config_AST_AGI_DIR));
02691       } else if (!strcasecmp(v->name, "astrundir")) {
02692          snprintf(ast_config_AST_PID, sizeof(ast_config_AST_PID), "%s/%s", v->value, "asterisk.pid");
02693          snprintf(ast_config_AST_SOCKET, sizeof(ast_config_AST_SOCKET), "%s/%s", v->value, ast_config_AST_CTL);
02694          ast_copy_string(ast_config_AST_RUN_DIR, v->value, sizeof(ast_config_AST_RUN_DIR));
02695       } else if (!strcasecmp(v->name, "astmoddir")) {
02696          ast_copy_string(ast_config_AST_MODULE_DIR, v->value, sizeof(ast_config_AST_MODULE_DIR));
02697       }
02698    }
02699 
02700    for (v = ast_variable_browse(cfg, "options"); v; v = v->next) {
02701       /* verbose level (-v at startup) */
02702       if (!strcasecmp(v->name, "verbose")) {
02703          option_verbose = atoi(v->value);
02704       /* whether or not to force timestamping in CLI verbose output. (-T at startup) */
02705       } else if (!strcasecmp(v->name, "timestamp")) {
02706          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TIMESTAMP);
02707       /* whether or not to support #exec in config files */
02708       } else if (!strcasecmp(v->name, "execincludes")) {
02709          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_EXEC_INCLUDES);
02710       /* debug level (-d at startup) */
02711       } else if (!strcasecmp(v->name, "debug")) {
02712          option_debug = 0;
02713          if (sscanf(v->value, "%d", &option_debug) != 1) {
02714             option_debug = ast_true(v->value);
02715          }
02716 #if HAVE_WORKING_FORK
02717       /* Disable forking (-f at startup) */
02718       } else if (!strcasecmp(v->name, "nofork")) {
02719          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_FORK);
02720       /* Always fork, even if verbose or debug are enabled (-F at startup) */
02721       } else if (!strcasecmp(v->name, "alwaysfork")) {
02722          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_ALWAYS_FORK);
02723 #endif
02724       /* Run quietly (-q at startup ) */
02725       } else if (!strcasecmp(v->name, "quiet")) {
02726          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_QUIET);
02727       /* Run as console (-c at startup, implies nofork) */
02728       } else if (!strcasecmp(v->name, "console")) {
02729          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_CONSOLE);
02730       /* Run with high priority if the O/S permits (-p at startup) */
02731       } else if (!strcasecmp(v->name, "highpriority")) {
02732          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_HIGH_PRIORITY);
02733       /* Initialize RSA auth keys (IAX2) (-i at startup) */
02734       } else if (!strcasecmp(v->name, "initcrypto")) {
02735          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_INIT_KEYS);
02736       /* Disable ANSI colors for console (-c at startup) */
02737       } else if (!strcasecmp(v->name, "nocolor")) {
02738          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_COLOR);
02739       /* Disable some usage warnings for picky people :p */
02740       } else if (!strcasecmp(v->name, "dontwarn")) {
02741          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_DONT_WARN);
02742       /* Dump core in case of crash (-g) */
02743       } else if (!strcasecmp(v->name, "dumpcore")) {
02744          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_DUMP_CORE);
02745       /* Cache recorded sound files to another directory during recording */
02746       } else if (!strcasecmp(v->name, "cache_record_files")) {
02747          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_CACHE_RECORD_FILES);
02748       /* Specify cache directory */
02749       }  else if (!strcasecmp(v->name, "record_cache_dir")) {
02750          ast_copy_string(record_cache_dir, v->value, AST_CACHE_DIR_LEN);
02751       /* Build transcode paths via SLINEAR, instead of directly */
02752       } else if (!strcasecmp(v->name, "transcode_via_sln")) {
02753          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TRANSCODE_VIA_SLIN);
02754       /* Transmit SLINEAR silence while a channel is being recorded or DTMF is being generated on a channel */
02755       } else if (!strcasecmp(v->name, "transmit_silence_during_record") || !strcasecmp(v->name, "transmit_silence")) {
02756          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TRANSMIT_SILENCE);
02757       /* Enable internal timing */
02758       } else if (!strcasecmp(v->name, "internal_timing")) {
02759          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_INTERNAL_TIMING);
02760       } else if (!strcasecmp(v->name, "maxcalls")) {
02761          if ((sscanf(v->value, "%d", &option_maxcalls) != 1) || (option_maxcalls < 0)) {
02762             option_maxcalls = 0;
02763          }
02764       } else if (!strcasecmp(v->name, "maxload")) {
02765          double test[1];
02766          if (getloadavg(test, 1) == -1) {
02767             ast_log(LOG_ERROR, "Cannot obtain load average on this system. 'maxload' option disabled.\n");
02768             option_maxload = 0.0;
02769          } else if ((sscanf(v->value, "%lf", &option_maxload) != 1) || (option_maxload < 0.0)) {
02770             option_maxload = 0.0;
02771          }
02772       /* Set the maximum amount of open files */
02773       } else if (!strcasecmp(v->name, "maxfiles")) {
02774          option_maxfiles = atoi(v->value);
02775          set_ulimit(option_maxfiles);
02776       /* What user to run as */
02777       } else if (!strcasecmp(v->name, "runuser")) {
02778          ast_copy_string(ast_config_AST_RUN_USER, v->value, sizeof(ast_config_AST_RUN_USER));
02779       /* What group to run as */
02780       } else if (!strcasecmp(v->name, "rungroup")) {
02781          ast_copy_string(ast_config_AST_RUN_GROUP, v->value, sizeof(ast_config_AST_RUN_GROUP));
02782       } else if (!strcasecmp(v->name, "systemname")) {
02783          ast_copy_string(ast_config_AST_SYSTEM_NAME, v->value, sizeof(ast_config_AST_SYSTEM_NAME));
02784       } else if (!strcasecmp(v->name, "languageprefix")) {
02785          ast_language_is_prefix = ast_true(v->value);
02786       } else if (!strcasecmp(v->name, "dahdichanname")) {
02787 #ifdef HAVE_ZAPTEL
02788          if (ast_true(v->value)) {
02789             strcpy(_dahdi_chan_name, "DAHDI");
02790             _dahdi_chan_name_len = 5;
02791             _dahdi_chan_mode = CHAN_DAHDI_PLUS_ZAP_MODE;
02792          }
02793 #else
02794          if (ast_false(v->value)) {
02795             strcpy(_dahdi_chan_name, "Zap");
02796             _dahdi_chan_name_len = 3;
02797             _dahdi_chan_mode = CHAN_ZAP_MODE;
02798          }
02799 #endif
02800 #if defined(HAVE_SYSINFO)
02801       } else if (!strcasecmp(v->name, "minmemfree")) {
02802          /* specify the minimum amount of free memory to retain.  Asterisk should stop accepting new calls
02803           * if the amount of free memory falls below this watermark */
02804          if ((sscanf(v->value, "%ld", &option_minmemfree) != 1) || (option_minmemfree < 0)) {
02805             option_minmemfree = 0;
02806          }
02807  #endif
02808       }
02809    }
02810    ast_config_destroy(cfg);
02811 }
02812 
02813 static void *monitor_sig_flags(void *unused)
02814 {
02815    for (;;) {
02816       struct pollfd p = { sig_alert_pipe[0], POLLIN, 0 };
02817       int a;
02818       poll(&p, 1, -1);
02819       if (sig_flags.need_reload) {
02820          sig_flags.need_reload = 0;
02821          ast_module_reload(NULL);
02822       }
02823       if (sig_flags.need_quit) {
02824          sig_flags.need_quit = 0;
02825          quit_handler(0, 0, 1, 0);
02826       }
02827       if (read(sig_alert_pipe[0], &a, sizeof(a)) != sizeof(a)) {
02828       }
02829    }
02830 
02831    return NULL;
02832 }
02833 
02834 int main(int argc, char *argv[])
02835 {
02836    int c;
02837    char filename[80] = "";
02838    char hostname[MAXHOSTNAMELEN] = "";
02839    char tmp[80];
02840    char * xarg = NULL;
02841    int x;
02842    FILE *f;
02843    sigset_t sigs;
02844    int num;
02845    int isroot = 1;
02846    char *buf;
02847    char *runuser = NULL, *rungroup = NULL;
02848 
02849    /* Remember original args for restart */
02850    if (argc > sizeof(_argv) / sizeof(_argv[0]) - 1) {
02851       fprintf(stderr, "Truncating argument size to %d\n", (int)(sizeof(_argv) / sizeof(_argv[0])) - 1);
02852       argc = sizeof(_argv) / sizeof(_argv[0]) - 1;
02853    }
02854    for (x=0; x<argc; x++)
02855       _argv[x] = argv[x];
02856    _argv[x] = NULL;
02857 
02858    if (geteuid() != 0)
02859       isroot = 0;
02860 
02861    /* if the progname is rasterisk consider it a remote console */
02862    if (argv[0] && (strstr(argv[0], "rasterisk")) != NULL) {
02863       ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE);
02864    }
02865    if (gethostname(hostname, sizeof(hostname)-1))
02866       ast_copy_string(hostname, "<Unknown>", sizeof(hostname));
02867    ast_mainpid = getpid();
02868    ast_ulaw_init();
02869    ast_alaw_init();
02870    callerid_init();
02871    ast_builtins_init();
02872    ast_utils_init();
02873    tdd_init();
02874 
02875    if (getenv("HOME")) 
02876       snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
02877    /* Check for options */
02878    while ((c = getopt(argc, argv, "mtThfFdvVqprRgciInx:U:G:C:L:M:e:")) != -1) {
02879       switch (c) {
02880 #if defined(HAVE_SYSINFO)
02881       case 'e':
02882          if ((sscanf(&optarg[1], "%ld", &option_minmemfree) != 1) || (option_minmemfree < 0)) {
02883             option_minmemfree = 0;
02884          }
02885          break;
02886 #endif
02887 #if HAVE_WORKING_FORK
02888       case 'F':
02889          ast_set_flag(&ast_options, AST_OPT_FLAG_ALWAYS_FORK);
02890          break;
02891       case 'f':
02892          ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);
02893          break;
02894 #endif
02895       case 'd':
02896          option_debug++;
02897          ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);
02898          break;
02899       case 'c':
02900          ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_CONSOLE);
02901          break;
02902       case 'n':
02903          ast_set_flag(&ast_options, AST_OPT_FLAG_NO_COLOR);
02904          break;
02905       case 'r':
02906          ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE);
02907          break;
02908       case 'R':
02909          ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE | AST_OPT_FLAG_RECONNECT);
02910          break;
02911       case 'p':
02912          ast_set_flag(&ast_options, AST_OPT_FLAG_HIGH_PRIORITY);
02913          break;
02914       case 'v':
02915          option_verbose++;
02916          ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);
02917          break;
02918       case 'm':
02919          ast_set_flag(&ast_options, AST_OPT_FLAG_MUTE);
02920          break;
02921       case 'M':
02922          if ((sscanf(optarg, "%d", &option_maxcalls) != 1) || (option_maxcalls < 0))
02923             option_maxcalls = 0;
02924          break;
02925       case 'L':
02926          if ((sscanf(optarg, "%lf", &option_maxload) != 1) || (option_maxload < 0.0))
02927             option_maxload = 0.0;
02928          break;
02929       case 'q':
02930          ast_set_flag(&ast_options, AST_OPT_FLAG_QUIET);
02931          break;
02932       case 't':
02933          ast_set_flag(&ast_options, AST_OPT_FLAG_CACHE_RECORD_FILES);
02934          break;
02935       case 'T':
02936          ast_set_flag(&ast_options, AST_OPT_FLAG_TIMESTAMP);
02937          break;
02938       case 'x':
02939          ast_set_flag(&ast_options, AST_OPT_FLAG_EXEC);
02940          xarg = ast_strdupa(optarg);
02941          break;
02942       case 'C':
02943          ast_copy_string(ast_config_AST_CONFIG_FILE, optarg, sizeof(ast_config_AST_CONFIG_FILE));
02944          ast_set_flag(&ast_options, AST_OPT_FLAG_OVERRIDE_CONFIG);
02945          break;
02946       case 'I':
02947          ast_set_flag(&ast_options, AST_OPT_FLAG_INTERNAL_TIMING);
02948          break;
02949       case 'i':
02950          ast_set_flag(&ast_options, AST_OPT_FLAG_INIT_KEYS);
02951          break;
02952       case 'g':
02953          ast_set_flag(&ast_options, AST_OPT_FLAG_DUMP_CORE);
02954          break;
02955       case 'h':
02956          show_cli_help();
02957          exit(0);
02958       case 'V':
02959          show_version();
02960          exit(0);
02961       case 'U':
02962          runuser = ast_strdupa(optarg);
02963          break;
02964       case 'G':
02965          rungroup = ast_strdupa(optarg);
02966          break;
02967       case '?':
02968          exit(1);
02969       }
02970    }
02971 
02972    if (ast_opt_console || option_verbose || (ast_opt_remote && !ast_opt_exec)) {
02973       ast_register_verbose(console_verboser);
02974       WELCOME_MESSAGE;
02975    }
02976 
02977    if (ast_opt_console && !option_verbose) 
02978       ast_verbose("[ Booting...\n");
02979 
02980    /* For remote connections, change the name of the remote connection.
02981     * We do this for the benefit of init scripts (which need to know if/when
02982     * the main asterisk process has died yet). */
02983    if (ast_opt_remote) {
02984       strcpy(argv[0], "rasterisk");
02985       for (x = 1; x < argc; x++) {
02986          argv[x] = argv[0] + 10;
02987       }
02988    }
02989 
02990    if (ast_opt_console && !option_verbose) {
02991       ast_verbose("[ Reading Master Configuration ]\n");
02992    }
02993 
02994    ast_readconfig();
02995 
02996    if (ast_opt_always_fork && (ast_opt_remote || ast_opt_console)) {
02997       ast_log(LOG_WARNING, "'alwaysfork' is not compatible with console or remote console mode; ignored\n");
02998       ast_clear_flag(&ast_options, AST_OPT_FLAG_ALWAYS_FORK);
02999    }
03000 
03001    if (ast_opt_dump_core) {
03002       struct rlimit l;
03003       memset(&l, 0, sizeof(l));
03004       l.rlim_cur = RLIM_INFINITY;
03005       l.rlim_max = RLIM_INFINITY;
03006       if (setrlimit(RLIMIT_CORE, &l)) {
03007          ast_log(LOG_WARNING, "Unable to disable core size resource limit: %s\n", strerror(errno));
03008       }
03009    }
03010 
03011    if ((!rungroup) && !ast_strlen_zero(ast_config_AST_RUN_GROUP))
03012       rungroup = ast_config_AST_RUN_GROUP;
03013    if ((!runuser) && !ast_strlen_zero(ast_config_AST_RUN_USER))
03014       runuser = ast_config_AST_RUN_USER;
03015 
03016 #ifndef __CYGWIN__
03017 
03018    if (isroot) 
03019       ast_set_priority(ast_opt_high_priority);
03020 
03021    if (isroot && rungroup) {
03022       struct group *gr;
03023       gr = getgrnam(rungroup);
03024       if (!gr) {
03025          ast_log(LOG_WARNING, "No such group '%s'!\n", rungroup);
03026          exit(1);
03027       }
03028       if (setgid(gr->gr_gid)) {
03029          ast_log(LOG_WARNING, "Unable to setgid to %d (%s)\n", (int)gr->gr_gid, rungroup);
03030          exit(1);
03031       }
03032       if (setgroups(0, NULL)) {
03033          ast_log(LOG_WARNING, "Unable to drop unneeded groups\n");
03034          exit(1);
03035       }
03036       if (option_verbose)
03037          ast_verbose("Running as group '%s'\n", rungroup);
03038    }
03039 
03040    if (runuser && !ast_test_flag(&ast_options, AST_OPT_FLAG_REMOTE)) {
03041 #ifdef HAVE_CAP
03042       int has_cap = 1;
03043 #endif /* HAVE_CAP */
03044       struct passwd *pw;
03045       pw = getpwnam(runuser);
03046       if (!pw) {
03047          ast_log(LOG_WARNING, "No such user '%s'!\n", runuser);
03048          exit(1);
03049       }
03050 #ifdef HAVE_CAP
03051       if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0)) {
03052          ast_log(LOG_WARNING, "Unable to keep capabilities.\n");
03053          has_cap = 0;
03054       }
03055 #endif /* HAVE_CAP */
03056       if (!isroot && pw->pw_uid != geteuid()) {
03057          ast_log(LOG_ERROR, "Asterisk started as nonroot, but runuser '%s' requested.\n", runuser);
03058          exit(1);
03059       }
03060       if (!rungroup) {
03061          if (setgid(pw->pw_gid)) {
03062             ast_log(LOG_WARNING, "Unable to setgid to %d!\n", (int)pw->pw_gid);
03063             exit(1);
03064          }
03065          if (isroot && initgroups(pw->pw_name, pw->pw_gid)) {
03066             ast_log(LOG_WARNING, "Unable to init groups for '%s'\n", runuser);
03067             exit(1);
03068          }
03069       }
03070       if (setuid(pw->pw_uid)) {
03071          ast_log(LOG_WARNING, "Unable to setuid to %d (%s)\n", (int)pw->pw_uid, runuser);
03072          exit(1);
03073       }
03074       if (option_verbose)
03075          ast_verbose("Running as user '%s'\n", runuser);
03076 #ifdef HAVE_CAP
03077       if (has_cap) {
03078          cap_t cap = cap_from_text("cap_net_admin=eip");
03079 
03080          if (cap_set_proc(cap))
03081             ast_log(LOG_WARNING, "Unable to install capabilities.\n");
03082 
03083          if (cap_free(cap))
03084             ast_log(LOG_WARNING, "Unable to drop capabilities.\n");
03085       }
03086 #endif /* HAVE_CAP */
03087    }
03088 
03089 #endif /* __CYGWIN__ */
03090 
03091 #ifdef linux
03092    if (geteuid() && ast_opt_dump_core) {
03093       if (prctl(PR_SET_DUMPABLE, 1, 0, 0, 0) < 0) {
03094          ast_log(LOG_WARNING, "Unable to set the process for core dumps after changing to a non-root user. %s\n", strerror(errno));
03095       }  
03096    }
03097 #endif
03098 
03099    ast_term_init();
03100    printf("%s", term_end());
03101    fflush(stdout);
03102 
03103    if (ast_opt_console && !option_verbose) 
03104       ast_verbose("[ Initializing Custom Configuration Options ]\n");
03105    /* custom config setup */
03106    register_config_cli();
03107    read_config_maps();
03108    
03109    if (ast_opt_console) {
03110       if (el_hist == NULL || el == NULL)
03111          ast_el_initialize();
03112 
03113       if (!ast_strlen_zero(filename))
03114          ast_el_read_history(filename);
03115    }
03116 
03117    if (ast_tryconnect()) {
03118       /* One is already running */
03119       if (ast_opt_remote) {
03120          if (ast_opt_exec) {
03121             ast_remotecontrol(xarg);
03122             quit_handler(0, 0, 0, 0);
03123             exit(0);
03124          }
03125          printf("%s", term_quit());
03126          ast_remotecontrol(NULL);
03127          quit_handler(0, 0, 0, 0);
03128          exit(0);
03129       } else {
03130          ast_log(LOG_ERROR, "Asterisk already running on %s.  Use 'asterisk -r' to connect.\n", ast_config_AST_SOCKET);
03131          printf("%s", term_quit());
03132          exit(1);
03133       }
03134    } else if (ast_opt_remote || ast_opt_exec) {
03135       ast_log(LOG_ERROR, "Unable to connect to remote asterisk (does %s exist?)\n", ast_config_AST_SOCKET);
03136       printf("%s", term_quit());
03137       exit(1);
03138    }
03139    /* Blindly write pid file since we couldn't connect */
03140    unlink(ast_config_AST_PID);
03141    f = fopen(ast_config_AST_PID, "w");
03142    if (f) {
03143       fprintf(f, "%ld\n", (long)getpid());
03144       fclose(f);
03145    } else
03146       ast_log(LOG_WARNING, "Unable to open pid file '%s': %s\n", ast_config_AST_PID, strerror(errno));
03147 
03148 #if HAVE_WORKING_FORK
03149    if (ast_opt_always_fork || !ast_opt_no_fork) {
03150 #ifndef HAVE_SBIN_LAUNCHD
03151       if (daemon(1, 0) < 0) {
03152          ast_log(LOG_ERROR, "daemon() failed: %s\n", strerror(errno));
03153       }
03154       ast_mainpid = getpid();
03155       /* Blindly re-write pid file since we are forking */
03156       unlink(ast_config_AST_PID);
03157       f = fopen(ast_config_AST_PID, "w");
03158       if (f) {
03159          fprintf(f, "%ld\n", (long)ast_mainpid);
03160          fclose(f);
03161       } else
03162          ast_log(LOG_WARNING, "Unable to open pid file '%s': %s\n", ast_config_AST_PID, strerror(errno));
03163 #else
03164       ast_log(LOG_WARNING, "Mac OS X detected.  Use '/sbin/launchd -d' to launch with the nofork option.\n");
03165 #endif
03166    }
03167 #endif
03168 
03169    ast_makesocket();
03170    sigemptyset(&sigs);
03171    sigaddset(&sigs, SIGHUP);
03172    sigaddset(&sigs, SIGTERM);
03173    sigaddset(&sigs, SIGINT);
03174    sigaddset(&sigs, SIGPIPE);
03175    sigaddset(&sigs, SIGWINCH);
03176    pthread_sigmask(SIG_BLOCK, &sigs, NULL);
03177    signal(SIGURG, urg_handler);
03178    signal(SIGINT, __quit_handler);
03179    signal(SIGTERM, __quit_handler);
03180    signal(SIGHUP, hup_handler);
03181    signal(SIGCHLD, child_handler);
03182    signal(SIGPIPE, SIG_IGN);
03183 
03184    /* ensure that the random number generators are seeded with a different value every time
03185       Asterisk is started
03186    */
03187    srand((unsigned int) getpid() + (unsigned int) time(NULL));
03188    initstate((unsigned int) getpid() * 65536 + (unsigned int) time(NULL), randompool, sizeof(randompool));
03189 
03190    if (init_logger()) {    /* Start logging subsystem */
03191       printf("%s", term_quit());
03192       exit(1);
03193    }
03194 
03195    dahdi_chan_name = _dahdi_chan_name;
03196    dahdi_chan_name_len = &_dahdi_chan_name_len;
03197    dahdi_chan_mode = &_dahdi_chan_mode;
03198 
03199 #ifdef HAVE_DAHDI
03200    {
03201       int fd;
03202       int x = 160;
03203       fd = open(DAHDI_FILE_TIMER, O_RDWR);
03204       if (fd >= 0) {
03205          if (ioctl(fd, DAHDI_TIMERCONFIG, &x)) {
03206             ast_log(LOG_ERROR, "You have " DAHDI_NAME
03207                   " built and drivers loaded, but the "
03208                   DAHDI_NAME " timer test failed to set DAHDI_TIMERCONFIG to %d.\n", x);
03209             exit(1);
03210          }
03211          if ((x = ast_wait_for_input(fd, 300)) < 0) {
03212             ast_log(LOG_ERROR, "You have " DAHDI_NAME 
03213                   "built and drivers loaded, but the " 
03214                   DAHDI_NAME " timer could not be polled during the " 
03215                   DAHDI_NAME " timer test.\n");
03216             exit(1);
03217          }
03218          if (!x) {
03219             const char dahdi_timer_error[] = {
03220                "Asterisk has detected a problem with your " DAHDI_NAME 
03221                   " configuration and will shutdown for your protection.  You have options:"
03222                "\n\t1. You only have to compile " DAHDI_NAME 
03223                   " support into Asterisk if you need it.  One option is to recompile without " 
03224                   DAHDI_NAME " support."
03225                "\n\t2. You only have to load " DAHDI_NAME " drivers if you want to take advantage of " 
03226                   DAHDI_NAME " services.  One option is to unload " 
03227                   DAHDI_NAME " modules if you don't need them."
03228                "\n\t3. If you need Zaptel services, you must correctly configure " DAHDI_NAME "."
03229             };
03230             ast_log(LOG_ERROR, "%s\n", dahdi_timer_error);
03231             exit(1);
03232          }
03233          close(fd);
03234       }
03235    }
03236 #endif
03237    threadstorage_init();
03238 
03239    astobj2_init();
03240 
03241    ast_autoservice_init();
03242 
03243    if (load_modules(1)) {     /* Load modules, pre-load only */
03244       printf("%s", term_quit());
03245       exit(1);
03246    }
03247 
03248    if (dnsmgr_init()) {    /* Initialize the DNS manager */
03249       printf("%s", term_quit());
03250       exit(1);
03251    }
03252 
03253    ast_http_init();     /* Start the HTTP server, if needed */
03254 
03255    ast_channels_init();
03256 
03257    if (ast_cdr_engine_init()) {
03258       printf("%s", term_quit());
03259       exit(1);
03260    }
03261 
03262    if (ast_device_state_engine_init()) {
03263       printf("%s", term_quit());
03264       exit(1);
03265    }
03266 
03267    ast_rtp_init();
03268 
03269    ast_udptl_init();
03270 
03271    if (ast_image_init()) {
03272       printf("%s", term_quit());
03273       exit(1);
03274    }
03275 
03276    if (ast_file_init()) {
03277       printf("%s", term_quit());
03278       exit(1);
03279    }
03280 
03281    if (load_pbx()) {
03282       printf("%s", term_quit());
03283       exit(1);
03284    }
03285 
03286    if (init_framer()) {
03287       printf("%s", term_quit());
03288       exit(1);
03289    }
03290 
03291    if (astdb_init()) {
03292       printf("%s", term_quit());
03293       exit(1);
03294    }
03295 
03296    if (ast_enum_init()) {
03297       printf("%s", term_quit());
03298       exit(1);
03299    }
03300 
03301    if (load_modules(0)) {
03302       printf("%s", term_quit());
03303       exit(1);
03304    }
03305 
03306    /* AMI is initialized after loading modules because of a potential
03307     * conflict between issuing a module reload from manager and
03308     * registering manager actions.  This will cause reversed locking
03309     * order between the module list and manager actions list. */
03310    if (init_manager()) {
03311       printf("%s", term_quit());
03312       exit(1);
03313    }
03314 
03315    dnsmgr_start_refresh();
03316 
03317    /* We might have the option of showing a console, but for now just
03318       do nothing... */
03319    if (ast_opt_console && !option_verbose)
03320       ast_verbose(" ]\n");
03321    if (option_verbose || ast_opt_console)
03322       ast_verbose("%s", term_color(tmp, "Asterisk Ready.\n", COLOR_BRWHITE, COLOR_BLACK, sizeof(tmp)));
03323    if (ast_opt_no_fork)
03324       consolethread = pthread_self();
03325 
03326    if (pipe(sig_alert_pipe))
03327       sig_alert_pipe[0] = sig_alert_pipe[1] = -1;
03328 
03329    ast_set_flag(&ast_options, AST_OPT_FLAG_FULLY_BOOTED);
03330    pthread_sigmask(SIG_UNBLOCK, &sigs, NULL);
03331 
03332 #ifdef __AST_DEBUG_MALLOC
03333    __ast_mm_init();
03334 #endif   
03335 
03336    time(&ast_startuptime);
03337    ast_cli_register_multiple(cli_asterisk, sizeof(cli_asterisk) / sizeof(struct ast_cli_entry));
03338 
03339    if (ast_opt_console) {
03340       /* Console stuff now... */
03341       /* Register our quit function */
03342       char title[256];
03343       pthread_attr_t attr;
03344       pthread_t dont_care;
03345 
03346       pthread_attr_init(&attr);
03347       pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
03348       ast_pthread_create(&dont_care, &attr, monitor_sig_flags, NULL);
03349       pthread_attr_destroy(&attr);
03350 
03351       set_icon("Asterisk");
03352       snprintf(title, sizeof(title), "Asterisk Console on '%s' (pid %ld)", hostname, (long)ast_mainpid);
03353       set_title(title);
03354 
03355       for (;;) {
03356          buf = (char *)el_gets(el, &num);
03357 
03358          if (!buf && write(1, "", 1) < 0)
03359             goto lostterm;
03360 
03361          if (buf) {
03362             if (buf[strlen(buf)-1] == '\n')
03363                buf[strlen(buf)-1] = '\0';
03364 
03365             consolehandler((char *)buf);
03366          } else if (ast_opt_remote && (write(STDOUT_FILENO, "\nUse EXIT or QUIT to exit the asterisk console\n",
03367                strlen("\nUse EXIT or QUIT to exit the asterisk console\n")) < 0)) {
03368             /* Whoa, stdout disappeared from under us... Make /dev/null's */
03369             int fd;
03370             fd = open("/dev/null", O_RDWR);
03371             if (fd > -1) {
03372                dup2(fd, STDOUT_FILENO);
03373                dup2(fd, STDIN_FILENO);
03374             } else
03375                ast_log(LOG_WARNING, "Failed to open /dev/null to recover from dead console. Bad things will happen!\n");
03376             break;
03377          }
03378       }
03379    }
03380 
03381    monitor_sig_flags(NULL);
03382 
03383 lostterm:
03384    return 0;
03385 }

Generated on Fri Apr 24 16:25:49 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7