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

Generated on Tue Nov 4 13:20:14 2008 for Asterisk - the Open Source PBX by  doxygen 1.4.7