Wed Oct 28 11:45:28 2009

Asterisk developer's documentation


asterisk.c

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

Generated on Wed Oct 28 11:45:28 2009 for Asterisk - the Open Source PBX by  doxygen 1.5.6