Fri Jul 15 2011 11:57:18

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