Wed Aug 18 22:33:44 2010

Asterisk developer's documentation


asterisk.c

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

Generated on Wed Aug 18 22:33:44 2010 for Asterisk - the Open Source PBX by  doxygen 1.4.7