Mon Nov 24 15:34:07 2008

Asterisk developer's documentation


asterisk.c

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

Generated on Mon Nov 24 15:34:08 2008 for Asterisk - the Open Source PBX by  doxygen 1.4.7