Thu Apr 28 2011 16:56:41

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: 307535 $")
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    HistEvent ev;
02617 
02618    if (el_hist == NULL || el == NULL)
02619       ast_el_initialize();
02620 
02621    return (history(el_hist, &ev, H_LOAD, filename));
02622 }
02623 
02624 static void ast_remotecontrol(char *data)
02625 {
02626    char buf[80];
02627    int res;
02628    char filename[80] = "";
02629    char *hostname;
02630    char *cpid;
02631    char *version;
02632    int pid;
02633    char *stringp = NULL;
02634 
02635    char *ebuf;
02636    int num = 0;
02637 
02638    memset(&sig_flags, 0, sizeof(sig_flags));
02639    signal(SIGINT, __remote_quit_handler);
02640    signal(SIGTERM, __remote_quit_handler);
02641    signal(SIGHUP, __remote_quit_handler);
02642 
02643    if (read(ast_consock, buf, sizeof(buf)) < 0) {
02644       ast_log(LOG_ERROR, "read() failed: %s\n", strerror(errno));
02645       return;
02646    }
02647    if (data) {
02648       char prefix[] = "cli quit after ";
02649       char *tmp = alloca(strlen(data) + strlen(prefix) + 1);
02650       sprintf(tmp, "%s%s", prefix, data);
02651       if (write(ast_consock, tmp, strlen(tmp) + 1) < 0) {
02652          ast_log(LOG_ERROR, "write() failed: %s\n", strerror(errno));
02653          if (sig_flags.need_quit == 1) {
02654             return;
02655          }
02656       }
02657    }
02658    stringp = buf;
02659    hostname = strsep(&stringp, "/");
02660    cpid = strsep(&stringp, "/");
02661    version = strsep(&stringp, "\n");
02662    if (!version)
02663       version = "<Version Unknown>";
02664    stringp = hostname;
02665    strsep(&stringp, ".");
02666    if (cpid)
02667       pid = atoi(cpid);
02668    else
02669       pid = -1;
02670    if (!data) {
02671       char tmp[80];
02672       snprintf(tmp, sizeof(tmp), "core set verbose atleast %d", option_verbose);
02673       fdsend(ast_consock, tmp);
02674       snprintf(tmp, sizeof(tmp), "core set debug atleast %d", option_debug);
02675       fdsend(ast_consock, tmp);
02676       if (!ast_opt_mute)
02677          fdsend(ast_consock, "logger mute silent");
02678       else 
02679          printf("log and verbose output currently muted ('logger mute' to unmute)\n");
02680    }
02681 
02682    if (ast_opt_exec && data) {  /* hack to print output then exit if asterisk -rx is used */
02683       struct pollfd fds;
02684       fds.fd = ast_consock;
02685       fds.events = POLLIN;
02686       fds.revents = 0;
02687       while (ast_poll(&fds, 1, 60000) > 0) {
02688          char buffer[512] = "", *curline = buffer, *nextline;
02689          int not_written = 1;
02690 
02691          if (sig_flags.need_quit == 1) {
02692             break;
02693          }
02694 
02695          if (read(ast_consock, buffer, sizeof(buffer) - 1) <= 0) {
02696             break;
02697          }
02698 
02699          do {
02700             if ((nextline = strchr(curline, '\n'))) {
02701                nextline++;
02702             } else {
02703                nextline = strchr(curline, '\0');
02704             }
02705 
02706             /* Skip verbose lines */
02707             if (*curline != 127) {
02708                not_written = 0;
02709                if (write(STDOUT_FILENO, curline, nextline - curline) < 0) {
02710                   ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno));
02711                }
02712             }
02713             curline = nextline;
02714          } while (!ast_strlen_zero(curline));
02715 
02716          /* No non-verbose output in 60s */
02717          if (not_written) {
02718             break;
02719          }
02720       }
02721       return;
02722    }
02723 
02724    ast_verbose("Connected to Asterisk %s currently running on %s (pid = %d)\n", version, hostname, pid);
02725    remotehostname = hostname;
02726    if (getenv("HOME")) 
02727       snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
02728    if (el_hist == NULL || el == NULL)
02729       ast_el_initialize();
02730 
02731    el_set(el, EL_GETCFN, ast_el_read_char);
02732 
02733    if (!ast_strlen_zero(filename))
02734       ast_el_read_history(filename);
02735 
02736    for (;;) {
02737       ebuf = (char *)el_gets(el, &num);
02738 
02739       if (sig_flags.need_quit == 1) {
02740          break;
02741       }
02742 
02743       if (!ebuf && write(1, "", 1) < 0)
02744          break;
02745 
02746       if (!ast_strlen_zero(ebuf)) {
02747          if (ebuf[strlen(ebuf)-1] == '\n')
02748             ebuf[strlen(ebuf)-1] = '\0';
02749          if (!remoteconsolehandler(ebuf)) {
02750             /* Strip preamble from output */
02751             char *temp;
02752             for (temp = ebuf; *temp; temp++) {
02753                if (*temp == 127) {
02754                   memmove(temp, temp + 1, strlen(temp));
02755                   temp--;
02756                }
02757             }
02758             res = write(ast_consock, ebuf, strlen(ebuf) + 1);
02759             if (res < 1) {
02760                ast_log(LOG_WARNING, "Unable to write: %s\n", strerror(errno));
02761                break;
02762             }
02763          }
02764       }
02765    }
02766    printf("\nDisconnected from Asterisk server\n");
02767 }
02768 
02769 static int show_version(void)
02770 {
02771    printf("Asterisk %s\n", ast_get_version());
02772    return 0;
02773 }
02774 
02775 static int show_cli_help(void) {
02776    printf("Asterisk %s, Copyright (C) 1999 - 2010, Digium, Inc. and others.\n", ast_get_version());
02777    printf("Usage: asterisk [OPTIONS]\n");
02778    printf("Valid Options:\n");
02779    printf("   -V              Display version number and exit\n");
02780    printf("   -C <configfile> Use an alternate configuration file\n");
02781    printf("   -G <group>      Run as a group other than the caller\n");
02782    printf("   -U <user>       Run as a user other than the caller\n");
02783    printf("   -c              Provide console CLI\n");
02784    printf("   -d              Enable extra debugging\n");
02785 #if HAVE_WORKING_FORK
02786    printf("   -f              Do not fork\n");
02787    printf("   -F              Always fork\n");
02788 #endif
02789    printf("   -g              Dump core in case of a crash\n");
02790    printf("   -h              This help screen\n");
02791    printf("   -i              Initialize crypto keys at startup\n");
02792    printf("   -I              Enable internal timing if DAHDI timer is available\n");
02793    printf("   -L <load>       Limit the maximum load average before rejecting new calls\n");
02794    printf("   -M <value>      Limit the maximum number of calls to the specified value\n");
02795    printf("   -m              Mute debugging and console output on the console\n");
02796    printf("   -n              Disable console colorization\n");
02797    printf("   -p              Run as pseudo-realtime thread\n");
02798    printf("   -q              Quiet mode (suppress output)\n");
02799    printf("   -r              Connect to Asterisk on this machine\n");
02800    printf("   -R              Same as -r, except attempt to reconnect if disconnected\n");
02801    printf("   -s <socket>     Connect to Asterisk via socket <socket> (only valid with -r)\n");
02802    printf("   -t              Record soundfiles in /var/tmp and move them where they\n");
02803    printf("                   belong after they are done\n");
02804    printf("   -T              Display the time in [Mmm dd hh:mm:ss] format for each line\n");
02805    printf("                   of output to the CLI\n");
02806    printf("   -v              Increase verbosity (multiple v's = more verbose)\n");
02807    printf("   -x <cmd>        Execute command <cmd> (only valid with -r)\n");
02808    printf("   -W              Adjust terminal colors to compensate for a light background\n");
02809    printf("\n");
02810    return 0;
02811 }
02812 
02813 static void ast_readconfig(void) 
02814 {
02815    struct ast_config *cfg;
02816    struct ast_variable *v;
02817    char *config = DEFAULT_CONFIG_FILE;
02818    char hostname[MAXHOSTNAMELEN] = "";
02819    struct ast_flags config_flags = { 0 };
02820    struct {
02821       unsigned int dbdir:1;
02822       unsigned int keydir:1;
02823    } found = { 0, 0 };
02824 
02825    if (ast_opt_override_config) {
02826       cfg = ast_config_load2(ast_config_AST_CONFIG_FILE, "" /* core, can't reload */, config_flags);
02827       if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID)
02828          ast_log(LOG_WARNING, "Unable to open specified master config file '%s', using built-in defaults\n", ast_config_AST_CONFIG_FILE);
02829    } else 
02830       cfg = ast_config_load2(config, "" /* core, can't reload */, config_flags);
02831 
02832    /* init with buildtime config */
02833    ast_copy_string(cfg_paths.config_dir, DEFAULT_CONFIG_DIR, sizeof(cfg_paths.config_dir));
02834    ast_copy_string(cfg_paths.spool_dir, DEFAULT_SPOOL_DIR, sizeof(cfg_paths.spool_dir));
02835    ast_copy_string(cfg_paths.module_dir, DEFAULT_MODULE_DIR, sizeof(cfg_paths.module_dir));
02836    snprintf(cfg_paths.monitor_dir, sizeof(cfg_paths.monitor_dir), "%s/monitor", cfg_paths.spool_dir);
02837    ast_copy_string(cfg_paths.var_dir, DEFAULT_VAR_DIR, sizeof(cfg_paths.var_dir));
02838    ast_copy_string(cfg_paths.data_dir, DEFAULT_DATA_DIR, sizeof(cfg_paths.data_dir));
02839    ast_copy_string(cfg_paths.log_dir, DEFAULT_LOG_DIR, sizeof(cfg_paths.log_dir));
02840    ast_copy_string(cfg_paths.agi_dir, DEFAULT_AGI_DIR, sizeof(cfg_paths.agi_dir));
02841    ast_copy_string(cfg_paths.db_path, DEFAULT_DB, sizeof(cfg_paths.db_path));
02842    ast_copy_string(cfg_paths.key_dir, DEFAULT_KEY_DIR, sizeof(cfg_paths.key_dir));
02843    ast_copy_string(cfg_paths.pid_path, DEFAULT_PID, sizeof(cfg_paths.pid_path));
02844    ast_copy_string(cfg_paths.socket_path, DEFAULT_SOCKET, sizeof(cfg_paths.socket_path));
02845    ast_copy_string(cfg_paths.run_dir, DEFAULT_RUN_DIR, sizeof(cfg_paths.run_dir));
02846 
02847    ast_set_default_eid(&ast_eid_default);
02848 
02849    /* no asterisk.conf? no problem, use buildtime config! */
02850    if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) {
02851       return;
02852    }
02853 
02854    for (v = ast_variable_browse(cfg, "files"); v; v = v->next) {
02855       if (!strcasecmp(v->name, "astctlpermissions"))
02856          ast_copy_string(ast_config_AST_CTL_PERMISSIONS, v->value, sizeof(ast_config_AST_CTL_PERMISSIONS));
02857       else if (!strcasecmp(v->name, "astctlowner"))
02858          ast_copy_string(ast_config_AST_CTL_OWNER, v->value, sizeof(ast_config_AST_CTL_OWNER));
02859       else if (!strcasecmp(v->name, "astctlgroup"))
02860          ast_copy_string(ast_config_AST_CTL_GROUP, v->value, sizeof(ast_config_AST_CTL_GROUP));
02861       else if (!strcasecmp(v->name, "astctl"))
02862          ast_copy_string(ast_config_AST_CTL, v->value, sizeof(ast_config_AST_CTL));
02863    }
02864 
02865    for (v = ast_variable_browse(cfg, "directories"); v; v = v->next) {
02866       if (!strcasecmp(v->name, "astetcdir")) {
02867          ast_copy_string(cfg_paths.config_dir, v->value, sizeof(cfg_paths.config_dir));
02868       } else if (!strcasecmp(v->name, "astspooldir")) {
02869          ast_copy_string(cfg_paths.spool_dir, v->value, sizeof(cfg_paths.spool_dir));
02870          snprintf(cfg_paths.monitor_dir, sizeof(cfg_paths.monitor_dir), "%s/monitor", v->value);
02871       } else if (!strcasecmp(v->name, "astvarlibdir")) {
02872          ast_copy_string(cfg_paths.var_dir, v->value, sizeof(cfg_paths.var_dir));
02873          if (!found.dbdir)
02874             snprintf(cfg_paths.db_path, sizeof(cfg_paths.db_path), "%s/astdb", v->value);
02875       } else if (!strcasecmp(v->name, "astdbdir")) {
02876          snprintf(cfg_paths.db_path, sizeof(cfg_paths.db_path), "%s/astdb", v->value);
02877          found.dbdir = 1;
02878       } else if (!strcasecmp(v->name, "astdatadir")) {
02879          ast_copy_string(cfg_paths.data_dir, v->value, sizeof(cfg_paths.data_dir));
02880          if (!found.keydir)
02881             snprintf(cfg_paths.key_dir, sizeof(cfg_paths.key_dir), "%s/keys", v->value);
02882       } else if (!strcasecmp(v->name, "astkeydir")) {
02883          snprintf(cfg_paths.key_dir, sizeof(cfg_paths.key_dir), "%s/keys", v->value);
02884          found.keydir = 1;
02885       } else if (!strcasecmp(v->name, "astlogdir")) {
02886          ast_copy_string(cfg_paths.log_dir, v->value, sizeof(cfg_paths.log_dir));
02887       } else if (!strcasecmp(v->name, "astagidir")) {
02888          ast_copy_string(cfg_paths.agi_dir, v->value, sizeof(cfg_paths.agi_dir));
02889       } else if (!strcasecmp(v->name, "astrundir")) {
02890          snprintf(cfg_paths.pid_path, sizeof(cfg_paths.pid_path), "%s/%s", v->value, "asterisk.pid");
02891          snprintf(cfg_paths.socket_path, sizeof(cfg_paths.socket_path), "%s/%s", v->value, ast_config_AST_CTL);
02892          ast_copy_string(cfg_paths.run_dir, v->value, sizeof(cfg_paths.run_dir));
02893       } else if (!strcasecmp(v->name, "astmoddir")) {
02894          ast_copy_string(cfg_paths.module_dir, v->value, sizeof(cfg_paths.module_dir));
02895       }
02896    }
02897 
02898    for (v = ast_variable_browse(cfg, "options"); v; v = v->next) {
02899       /* verbose level (-v at startup) */
02900       if (!strcasecmp(v->name, "verbose")) {
02901          option_verbose = atoi(v->value);
02902       /* whether or not to force timestamping in CLI verbose output. (-T at startup) */
02903       } else if (!strcasecmp(v->name, "timestamp")) {
02904          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TIMESTAMP);
02905       /* whether or not to support #exec in config files */
02906       } else if (!strcasecmp(v->name, "execincludes")) {
02907          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_EXEC_INCLUDES);
02908       /* debug level (-d at startup) */
02909       } else if (!strcasecmp(v->name, "debug")) {
02910          option_debug = 0;
02911          if (sscanf(v->value, "%30d", &option_debug) != 1) {
02912             option_debug = ast_true(v->value);
02913          }
02914 #if HAVE_WORKING_FORK
02915       /* Disable forking (-f at startup) */
02916       } else if (!strcasecmp(v->name, "nofork")) {
02917          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_FORK);
02918       /* Always fork, even if verbose or debug are enabled (-F at startup) */
02919       } else if (!strcasecmp(v->name, "alwaysfork")) {
02920          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_ALWAYS_FORK);
02921 #endif
02922       /* Run quietly (-q at startup ) */
02923       } else if (!strcasecmp(v->name, "quiet")) {
02924          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_QUIET);
02925       /* Run as console (-c at startup, implies nofork) */
02926       } else if (!strcasecmp(v->name, "console")) {
02927          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_CONSOLE);
02928       /* Run with high priority if the O/S permits (-p at startup) */
02929       } else if (!strcasecmp(v->name, "highpriority")) {
02930          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_HIGH_PRIORITY);
02931       /* Initialize RSA auth keys (IAX2) (-i at startup) */
02932       } else if (!strcasecmp(v->name, "initcrypto")) {
02933          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_INIT_KEYS);
02934       /* Disable ANSI colors for console (-c at startup) */
02935       } else if (!strcasecmp(v->name, "nocolor")) {
02936          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_COLOR);
02937       /* Disable some usage warnings for picky people :p */
02938       } else if (!strcasecmp(v->name, "dontwarn")) {
02939          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_DONT_WARN);
02940       /* Dump core in case of crash (-g) */
02941       } else if (!strcasecmp(v->name, "dumpcore")) {
02942          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_DUMP_CORE);
02943       /* Cache recorded sound files to another directory during recording */
02944       } else if (!strcasecmp(v->name, "cache_record_files")) {
02945          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_CACHE_RECORD_FILES);
02946       /* Specify cache directory */
02947       }  else if (!strcasecmp(v->name, "record_cache_dir")) {
02948          ast_copy_string(record_cache_dir, v->value, AST_CACHE_DIR_LEN);
02949       /* Build transcode paths via SLINEAR, instead of directly */
02950       } else if (!strcasecmp(v->name, "transcode_via_sln")) {
02951          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TRANSCODE_VIA_SLIN);
02952       /* Transmit SLINEAR silence while a channel is being recorded or DTMF is being generated on a channel */
02953       } else if (!strcasecmp(v->name, "transmit_silence_during_record") || !strcasecmp(v->name, "transmit_silence")) {
02954          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TRANSMIT_SILENCE);
02955       /* Enable internal timing */
02956       } else if (!strcasecmp(v->name, "internal_timing")) {
02957          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_INTERNAL_TIMING);
02958       } else if (!strcasecmp(v->name, "maxcalls")) {
02959          if ((sscanf(v->value, "%30d", &option_maxcalls) != 1) || (option_maxcalls < 0)) {
02960             option_maxcalls = 0;
02961          }
02962       } else if (!strcasecmp(v->name, "maxload")) {
02963          double test[1];
02964 
02965          if (getloadavg(test, 1) == -1) {
02966             ast_log(LOG_ERROR, "Cannot obtain load average on this system. 'maxload' option disabled.\n");
02967             option_maxload = 0.0;
02968          } else if ((sscanf(v->value, "%30lf", &option_maxload) != 1) || (option_maxload < 0.0)) {
02969             option_maxload = 0.0;
02970          }
02971       /* Set the maximum amount of open files */
02972       } else if (!strcasecmp(v->name, "maxfiles")) {
02973          option_maxfiles = atoi(v->value);
02974          set_ulimit(option_maxfiles);
02975       /* What user to run as */
02976       } else if (!strcasecmp(v->name, "runuser")) {
02977          ast_copy_string(cfg_paths.run_user, v->value, sizeof(cfg_paths.run_user));
02978       /* What group to run as */
02979       } else if (!strcasecmp(v->name, "rungroup")) {
02980          ast_copy_string(cfg_paths.run_group, v->value, sizeof(cfg_paths.run_group));
02981       } else if (!strcasecmp(v->name, "systemname")) {
02982          ast_copy_string(cfg_paths.system_name, v->value, sizeof(cfg_paths.system_name));
02983       } else if (!strcasecmp(v->name, "autosystemname")) {
02984          if (ast_true(v->value)) {
02985             if (!gethostname(hostname, sizeof(hostname) - 1))
02986                ast_copy_string(cfg_paths.system_name, hostname, sizeof(cfg_paths.system_name));
02987             else {
02988                if (ast_strlen_zero(ast_config_AST_SYSTEM_NAME)){
02989                   ast_copy_string(cfg_paths.system_name, "localhost", sizeof(cfg_paths.system_name));
02990                }
02991                ast_log(LOG_ERROR, "Cannot obtain hostname for this system.  Using '%s' instead.\n", ast_config_AST_SYSTEM_NAME);
02992             }
02993          }
02994       } else if (!strcasecmp(v->name, "languageprefix")) {
02995          ast_language_is_prefix = ast_true(v->value);
02996       } else if (!strcasecmp(v->name, "lockmode")) {
02997          if (!strcasecmp(v->value, "lockfile")) {
02998             ast_set_lock_type(AST_LOCK_TYPE_LOCKFILE);
02999          } else if (!strcasecmp(v->value, "flock")) {
03000             ast_set_lock_type(AST_LOCK_TYPE_FLOCK);
03001          } else {
03002             ast_log(LOG_WARNING, "'%s' is not a valid setting for the lockmode option, "
03003                "defaulting to 'lockfile'\n", v->value);
03004             ast_set_lock_type(AST_LOCK_TYPE_LOCKFILE);
03005          }
03006 #if defined(HAVE_SYSINFO)
03007       } else if (!strcasecmp(v->name, "minmemfree")) {
03008          /* specify the minimum amount of free memory to retain.  Asterisk should stop accepting new calls
03009           * if the amount of free memory falls below this watermark */
03010          if ((sscanf(v->value, "%30ld", &option_minmemfree) != 1) || (option_minmemfree < 0)) {
03011             option_minmemfree = 0;
03012          }
03013 #endif
03014       } else if (!strcasecmp(v->name, "entityid")) {
03015          struct ast_eid tmp_eid;
03016          if (!ast_str_to_eid(&tmp_eid, v->value)) {
03017             ast_verbose("Successfully set global EID to '%s'\n", v->value);
03018             ast_eid_default = tmp_eid;
03019          } else
03020             ast_verbose("Invalid Entity ID '%s' provided\n", v->value);
03021       } else if (!strcasecmp(v->name, "lightbackground")) {
03022          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_LIGHT_BACKGROUND);
03023       } else if (!strcasecmp(v->name, "forceblackbackground")) {
03024          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_FORCE_BLACK_BACKGROUND);
03025       } else if (!strcasecmp(v->name, "hideconnect")) {
03026          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_HIDE_CONSOLE_CONNECT);
03027       } else if (!strcasecmp(v->name, "sendfullybooted")) {
03028          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_SEND_FULLYBOOTED);
03029       }
03030    }
03031    for (v = ast_variable_browse(cfg, "compat"); v; v = v->next) {
03032       float version;
03033       if (sscanf(v->value, "%30f", &version) != 1) {
03034          ast_log(LOG_WARNING, "Compatibility version for option '%s' is not a number: '%s'\n", v->name, v->value);
03035          continue;
03036       }
03037       if (!strcasecmp(v->name, "app_set")) {
03038          ast_set2_flag(&ast_compat, version < 1.5 ? 1 : 0, AST_COMPAT_APP_SET);
03039       } else if (!strcasecmp(v->name, "res_agi")) {
03040          ast_set2_flag(&ast_compat, version < 1.5 ? 1 : 0, AST_COMPAT_DELIM_RES_AGI);
03041       } else if (!strcasecmp(v->name, "pbx_realtime")) {
03042          ast_set2_flag(&ast_compat, version < 1.5 ? 1 : 0, AST_COMPAT_DELIM_PBX_REALTIME);
03043       }
03044    }
03045    ast_config_destroy(cfg);
03046 }
03047 
03048 static void *monitor_sig_flags(void *unused)
03049 {
03050    for (;;) {
03051       struct pollfd p = { sig_alert_pipe[0], POLLIN, 0 };
03052       int a;
03053       ast_poll(&p, 1, -1);
03054       if (sig_flags.need_reload) {
03055          sig_flags.need_reload = 0;
03056          ast_module_reload(NULL);
03057       }
03058       if (sig_flags.need_quit) {
03059          sig_flags.need_quit = 0;
03060          quit_handler(0, 0, 1, 0);
03061       }
03062       if (read(sig_alert_pipe[0], &a, sizeof(a)) != sizeof(a)) {
03063       }
03064    }
03065 
03066    return NULL;
03067 }
03068 
03069 static void *canary_thread(void *unused)
03070 {
03071    struct stat canary_stat;
03072    struct timeval now;
03073 
03074    /* Give the canary time to sing */
03075    sleep(120);
03076 
03077    for (;;) {
03078       stat(canary_filename, &canary_stat);
03079       now = ast_tvnow();
03080       if (now.tv_sec > canary_stat.st_mtime + 60) {
03081          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");
03082          ast_set_priority(0);
03083          pthread_exit(NULL);
03084       }
03085 
03086       /* Check the canary once a minute */
03087       sleep(60);
03088    }
03089 }
03090 
03091 /* Used by libc's atexit(3) function */
03092 static void canary_exit(void)
03093 {
03094    if (canary_pid > 0)
03095       kill(canary_pid, SIGKILL);
03096 }
03097 
03098 static void run_startup_commands(void)
03099 {
03100    int fd;
03101    struct ast_config *cfg;
03102    struct ast_flags cfg_flags = { 0 };
03103    struct ast_variable *v;
03104 
03105    if (!(cfg = ast_config_load2("cli.conf", "" /* core, can't reload */, cfg_flags)))
03106       return;
03107    if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) {
03108       return;
03109    }
03110 
03111    fd = open("/dev/null", O_RDWR);
03112    if (fd < 0) {
03113       ast_config_destroy(cfg);
03114       return;
03115    }
03116 
03117    for (v = ast_variable_browse(cfg, "startup_commands"); v; v = v->next) {
03118       if (ast_true(v->value))
03119          ast_cli_command(fd, v->name);
03120    }
03121 
03122    close(fd);
03123    ast_config_destroy(cfg);
03124 }
03125 
03126 int main(int argc, char *argv[])
03127 {
03128    int c;
03129    char filename[80] = "";
03130    char hostname[MAXHOSTNAMELEN] = "";
03131    char tmp[80];
03132    char * xarg = NULL;
03133    int x;
03134    FILE *f;
03135    sigset_t sigs;
03136    int num;
03137    int isroot = 1, rundir_exists = 0;
03138    char *buf;
03139    const char *runuser = NULL, *rungroup = NULL;
03140    char *remotesock = NULL;
03141    struct rlimit l;
03142 
03143    /* Remember original args for restart */
03144    if (argc > ARRAY_LEN(_argv) - 1) {
03145       fprintf(stderr, "Truncating argument size to %d\n", (int)ARRAY_LEN(_argv) - 1);
03146       argc = ARRAY_LEN(_argv) - 1;
03147    }
03148    for (x = 0; x < argc; x++)
03149       _argv[x] = argv[x];
03150    _argv[x] = NULL;
03151 
03152    if (geteuid() != 0)
03153       isroot = 0;
03154 
03155    /* if the progname is rasterisk consider it a remote console */
03156    if (argv[0] && (strstr(argv[0], "rasterisk")) != NULL) {
03157       ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE);
03158    }
03159    if (gethostname(hostname, sizeof(hostname)-1))
03160       ast_copy_string(hostname, "<Unknown>", sizeof(hostname));
03161    ast_mainpid = getpid();
03162    ast_ulaw_init();
03163    ast_alaw_init();
03164    callerid_init();
03165    ast_builtins_init();
03166    ast_utils_init();
03167    tdd_init();
03168    ast_tps_init();
03169    ast_fd_init();
03170    ast_pbx_init();
03171 
03172    if (getenv("HOME")) 
03173       snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
03174    /* Check for options */
03175    while ((c = getopt(argc, argv, "mtThfFdvVqprRgciInx:U:G:C:L:M:e:s:WB")) != -1) {
03176       switch (c) {
03177 #if defined(HAVE_SYSINFO)
03178       case 'e':
03179          if ((sscanf(&optarg[1], "%30ld", &option_minmemfree) != 1) || (option_minmemfree < 0)) {
03180             option_minmemfree = 0;
03181          }
03182          break;
03183 #endif
03184 #if HAVE_WORKING_FORK
03185       case 'F':
03186          ast_set_flag(&ast_options, AST_OPT_FLAG_ALWAYS_FORK);
03187          break;
03188       case 'f':
03189          ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);
03190          break;
03191 #endif
03192       case 'd':
03193          option_debug++;
03194          ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);
03195          break;
03196       case 'c':
03197          ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_CONSOLE);
03198          break;
03199       case 'n':
03200          ast_set_flag(&ast_options, AST_OPT_FLAG_NO_COLOR);
03201          break;
03202       case 'r':
03203          ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE);
03204          break;
03205       case 'R':
03206          ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE | AST_OPT_FLAG_RECONNECT);
03207          break;
03208       case 'p':
03209          ast_set_flag(&ast_options, AST_OPT_FLAG_HIGH_PRIORITY);
03210          break;
03211       case 'v':
03212          option_verbose++;
03213          ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);
03214          break;
03215       case 'm':
03216          ast_set_flag(&ast_options, AST_OPT_FLAG_MUTE);
03217          break;
03218       case 'M':
03219          if ((sscanf(optarg, "%30d", &option_maxcalls) != 1) || (option_maxcalls < 0))
03220             option_maxcalls = 0;
03221          break;
03222       case 'L':
03223          if ((sscanf(optarg, "%30lf", &option_maxload) != 1) || (option_maxload < 0.0))
03224             option_maxload = 0.0;
03225          break;
03226       case 'q':
03227          ast_set_flag(&ast_options, AST_OPT_FLAG_QUIET);
03228          break;
03229       case 't':
03230          ast_set_flag(&ast_options, AST_OPT_FLAG_CACHE_RECORD_FILES);
03231          break;
03232       case 'T':
03233          ast_set_flag(&ast_options, AST_OPT_FLAG_TIMESTAMP);
03234          break;
03235       case 'x':
03236          ast_set_flag(&ast_options, AST_OPT_FLAG_EXEC | AST_OPT_FLAG_NO_COLOR);
03237          xarg = ast_strdupa(optarg);
03238          break;
03239       case 'C':
03240          ast_copy_string(cfg_paths.config_file, optarg, sizeof(cfg_paths.config_file));
03241          ast_set_flag(&ast_options, AST_OPT_FLAG_OVERRIDE_CONFIG);
03242          break;
03243       case 'I':
03244          ast_set_flag(&ast_options, AST_OPT_FLAG_INTERNAL_TIMING);
03245          break;
03246       case 'i':
03247          ast_set_flag(&ast_options, AST_OPT_FLAG_INIT_KEYS);
03248          break;
03249       case 'g':
03250          ast_set_flag(&ast_options, AST_OPT_FLAG_DUMP_CORE);
03251          break;
03252       case 'h':
03253          show_cli_help();
03254          exit(0);
03255       case 'V':
03256          show_version();
03257          exit(0);
03258       case 'U':
03259          runuser = ast_strdupa(optarg);
03260          break;
03261       case 'G':
03262          rungroup = ast_strdupa(optarg);
03263          break;
03264       case 's':
03265          remotesock = ast_strdupa(optarg);
03266          break;
03267       case 'W': /* White background */
03268          ast_set_flag(&ast_options, AST_OPT_FLAG_LIGHT_BACKGROUND);
03269          ast_clear_flag(&ast_options, AST_OPT_FLAG_FORCE_BLACK_BACKGROUND);
03270          break;
03271       case 'B': /* Force black background */
03272          ast_set_flag(&ast_options, AST_OPT_FLAG_FORCE_BLACK_BACKGROUND);
03273          ast_clear_flag(&ast_options, AST_OPT_FLAG_LIGHT_BACKGROUND);
03274          break;
03275       case '?':
03276          exit(1);
03277       }
03278    }
03279 
03280    if (ast_opt_console || option_verbose || (ast_opt_remote && !ast_opt_exec)) {
03281       if (ast_register_verbose(console_verboser)) {
03282          ast_log(LOG_WARNING, "Unable to register console verboser?\n");
03283       }
03284       WELCOME_MESSAGE;
03285    }
03286 
03287    if (ast_opt_console && !option_verbose) 
03288       ast_verbose("[ Booting...\n");
03289 
03290    /* For remote connections, change the name of the remote connection.
03291     * We do this for the benefit of init scripts (which need to know if/when
03292     * the main asterisk process has died yet). */
03293    if (ast_opt_remote) {
03294       strcpy(argv[0], "rasterisk");
03295       for (x = 1; x < argc; x++) {
03296          argv[x] = argv[0] + 10;
03297       }
03298    }
03299 
03300    if (ast_opt_console && !option_verbose) {
03301       ast_verbose("[ Reading Master Configuration ]\n");
03302    }
03303 
03304    ast_readconfig();
03305 
03306    if (ast_opt_remote && remotesock != NULL)
03307       ast_copy_string((char *) cfg_paths.socket_path, remotesock, sizeof(cfg_paths.socket_path));
03308 
03309    if (!ast_language_is_prefix && !ast_opt_remote)
03310       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");
03311 
03312    if (ast_opt_always_fork && (ast_opt_remote || ast_opt_console)) {
03313       ast_log(LOG_WARNING, "'alwaysfork' is not compatible with console or remote console mode; ignored\n");
03314       ast_clear_flag(&ast_options, AST_OPT_FLAG_ALWAYS_FORK);
03315    }
03316 
03317    if (ast_opt_dump_core) {
03318       memset(&l, 0, sizeof(l));
03319       l.rlim_cur = RLIM_INFINITY;
03320       l.rlim_max = RLIM_INFINITY;
03321       if (setrlimit(RLIMIT_CORE, &l)) {
03322          ast_log(LOG_WARNING, "Unable to disable core size resource limit: %s\n", strerror(errno));
03323       }
03324    }
03325 
03326    if (getrlimit(RLIMIT_NOFILE, &l)) {
03327       ast_log(LOG_WARNING, "Unable to check file descriptor limit: %s\n", strerror(errno));
03328    }
03329 
03330 #if !defined(CONFIGURE_RAN_AS_ROOT)
03331    /* Check if select(2) will run with more file descriptors */
03332    do {
03333       int fd, fd2;
03334       ast_fdset readers;
03335       struct timeval tv = { 0, };
03336 
03337       if (l.rlim_cur <= FD_SETSIZE) {
03338          /* The limit of select()able FDs is irrelevant, because we'll never
03339           * open one that high. */
03340          break;
03341       }
03342 
03343       if (!(fd = open("/dev/null", O_RDONLY))) {
03344          ast_log(LOG_ERROR, "Cannot open a file descriptor at boot? %s\n", strerror(errno));
03345          break; /* XXX Should we exit() here? XXX */
03346       }
03347 
03348       fd2 = (l.rlim_cur > sizeof(readers) * 8 ? sizeof(readers) * 8 : l.rlim_cur) - 1;
03349       if (dup2(fd, fd2) < 0) {
03350          ast_log(LOG_WARNING, "Cannot open maximum file descriptor %d at boot? %s\n", fd2, strerror(errno));
03351          break;
03352       }
03353 
03354       FD_ZERO(&readers);
03355       FD_SET(fd2, &readers);
03356       if (ast_select(fd2 + 1, &readers, NULL, NULL, &tv) < 0) {
03357          ast_log(LOG_WARNING, "Maximum select()able file descriptor is %d\n", FD_SETSIZE);
03358       }
03359    } while (0);
03360 #elif defined(HAVE_VARIABLE_FDSET)
03361    ast_FD_SETSIZE = l.rlim_cur;
03362 #endif /* !defined(CONFIGURE_RAN_AS_ROOT) */
03363 
03364    if ((!rungroup) && !ast_strlen_zero(ast_config_AST_RUN_GROUP))
03365       rungroup = ast_config_AST_RUN_GROUP;
03366    if ((!runuser) && !ast_strlen_zero(ast_config_AST_RUN_USER))
03367       runuser = ast_config_AST_RUN_USER;
03368 
03369    /* Must install this signal handler up here to ensure that if the canary
03370     * fails to execute that it doesn't kill the Asterisk process.
03371     */
03372    sigaction(SIGCHLD, &child_handler, NULL);
03373 
03374    /* It's common on some platforms to clear /var/run at boot.  Create the
03375     * socket file directory before we drop privileges. */
03376    if (mkdir(ast_config_AST_RUN_DIR, 0755)) {
03377       if (errno == EEXIST) {
03378          rundir_exists = 1;
03379       } else {
03380          ast_log(LOG_WARNING, "Unable to create socket file directory.  Remote consoles will not be able to connect! (%s)\n", strerror(x));
03381       }
03382    }
03383 
03384 #ifndef __CYGWIN__
03385 
03386    if (isroot) {
03387       ast_set_priority(ast_opt_high_priority);
03388    }
03389 
03390    if (isroot && rungroup) {
03391       struct group *gr;
03392       gr = getgrnam(rungroup);
03393       if (!gr) {
03394          ast_log(LOG_WARNING, "No such group '%s'!\n", rungroup);
03395          exit(1);
03396       }
03397       if (!rundir_exists && chown(ast_config_AST_RUN_DIR, -1, gr->gr_gid)) {
03398          ast_log(LOG_WARNING, "Unable to chgrp run directory to %d (%s)\n", (int) gr->gr_gid, rungroup);
03399       }
03400       if (setgid(gr->gr_gid)) {
03401          ast_log(LOG_WARNING, "Unable to setgid to %d (%s)\n", (int)gr->gr_gid, rungroup);
03402          exit(1);
03403       }
03404       if (setgroups(0, NULL)) {
03405          ast_log(LOG_WARNING, "Unable to drop unneeded groups\n");
03406          exit(1);
03407       }
03408       if (option_verbose)
03409          ast_verbose("Running as group '%s'\n", rungroup);
03410    }
03411 
03412    if (runuser && !ast_test_flag(&ast_options, AST_OPT_FLAG_REMOTE)) {
03413 #ifdef HAVE_CAP
03414       int has_cap = 1;
03415 #endif /* HAVE_CAP */
03416       struct passwd *pw;
03417       pw = getpwnam(runuser);
03418       if (!pw) {
03419          ast_log(LOG_WARNING, "No such user '%s'!\n", runuser);
03420          exit(1);
03421       }
03422       if (chown(ast_config_AST_RUN_DIR, pw->pw_uid, -1)) {
03423          ast_log(LOG_WARNING, "Unable to chown run directory to %d (%s)\n", (int) pw->pw_uid, runuser);
03424       }
03425 #ifdef HAVE_CAP
03426       if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0)) {
03427          ast_log(LOG_WARNING, "Unable to keep capabilities.\n");
03428          has_cap = 0;
03429       }
03430 #endif /* HAVE_CAP */
03431       if (!isroot && pw->pw_uid != geteuid()) {
03432          ast_log(LOG_ERROR, "Asterisk started as nonroot, but runuser '%s' requested.\n", runuser);
03433          exit(1);
03434       }
03435       if (!rungroup) {
03436          if (setgid(pw->pw_gid)) {
03437             ast_log(LOG_WARNING, "Unable to setgid to %d!\n", (int)pw->pw_gid);
03438             exit(1);
03439          }
03440          if (isroot && initgroups(pw->pw_name, pw->pw_gid)) {
03441             ast_log(LOG_WARNING, "Unable to init groups for '%s'\n", runuser);
03442             exit(1);
03443          }
03444       }
03445       if (setuid(pw->pw_uid)) {
03446          ast_log(LOG_WARNING, "Unable to setuid to %d (%s)\n", (int)pw->pw_uid, runuser);
03447          exit(1);
03448       }
03449       if (option_verbose)
03450          ast_verbose("Running as user '%s'\n", runuser);
03451 #ifdef HAVE_CAP
03452       if (has_cap) {
03453          cap_t cap;
03454 
03455          cap = cap_from_text("cap_net_admin=eip");
03456 
03457          if (cap_set_proc(cap))
03458             ast_log(LOG_WARNING, "Unable to install capabilities.\n");
03459 
03460          if (cap_free(cap))
03461             ast_log(LOG_WARNING, "Unable to drop capabilities.\n");
03462       }
03463 #endif /* HAVE_CAP */
03464    }
03465 
03466 #endif /* __CYGWIN__ */
03467 
03468 #ifdef linux
03469    if (geteuid() && ast_opt_dump_core) {
03470       if (prctl(PR_SET_DUMPABLE, 1, 0, 0, 0) < 0) {
03471          ast_log(LOG_WARNING, "Unable to set the process for core dumps after changing to a non-root user. %s\n", strerror(errno));
03472       }
03473    }
03474 #endif
03475 
03476    {
03477 #if defined(HAVE_EACCESS) || defined(HAVE_EUIDACCESS)
03478 #if defined(HAVE_EUIDACCESS) && !defined(HAVE_EACCESS)
03479 #define eaccess euidaccess
03480 #endif
03481       char dir[PATH_MAX];
03482       if (!getcwd(dir, sizeof(dir)) || eaccess(dir, R_OK | X_OK | F_OK)) {
03483          ast_log(LOG_ERROR, "Unable to access the running directory (%s).  Changing to '/' for compatibility.\n", strerror(errno));
03484          /* If we cannot access the CWD, then we couldn't dump core anyway,
03485           * so chdir("/") won't break anything. */
03486          if (chdir("/")) {
03487             /* chdir(/) should never fail, so this ends up being a no-op */
03488             ast_log(LOG_ERROR, "chdir(\"/\") failed?!! %s\n", strerror(errno));
03489          }
03490       } else
03491 #endif /* defined(HAVE_EACCESS) || defined(HAVE_EUIDACCESS) */
03492       if (!ast_opt_no_fork && !ast_opt_dump_core) {
03493          /* Backgrounding, but no cores, so chdir won't break anything. */
03494          if (chdir("/")) {
03495             ast_log(LOG_ERROR, "Unable to chdir(\"/\") ?!! %s\n", strerror(errno));
03496          }
03497       }
03498    }
03499 
03500    ast_term_init();
03501    printf("%s", term_end());
03502    fflush(stdout);
03503 
03504    if (ast_opt_console && !option_verbose) 
03505       ast_verbose("[ Initializing Custom Configuration Options ]\n");
03506    /* custom config setup */
03507    register_config_cli();
03508    read_config_maps();
03509    
03510    if (ast_opt_console) {
03511       if (el_hist == NULL || el == NULL)
03512          ast_el_initialize();
03513 
03514       if (!ast_strlen_zero(filename))
03515          ast_el_read_history(filename);
03516    }
03517 
03518    if (ast_tryconnect()) {
03519       /* One is already running */
03520       if (ast_opt_remote) {
03521          if (ast_opt_exec) {
03522             ast_remotecontrol(xarg);
03523             quit_handler(0, 0, 0, 0);
03524             exit(0);
03525          }
03526          printf("%s", term_quit());
03527          ast_remotecontrol(NULL);
03528          quit_handler(0, 0, 0, 0);
03529          exit(0);
03530       } else {
03531          ast_log(LOG_ERROR, "Asterisk already running on %s.  Use 'asterisk -r' to connect.\n", ast_config_AST_SOCKET);
03532          printf("%s", term_quit());
03533          exit(1);
03534       }
03535    } else if (ast_opt_remote || ast_opt_exec) {
03536       ast_log(LOG_ERROR, "Unable to connect to remote asterisk (does %s exist?)\n", ast_config_AST_SOCKET);
03537       printf("%s", term_quit());
03538       exit(1);
03539    }
03540    /* Blindly write pid file since we couldn't connect */
03541    unlink(ast_config_AST_PID);
03542    f = fopen(ast_config_AST_PID, "w");
03543    if (f) {
03544       fprintf(f, "%ld\n", (long)getpid());
03545       fclose(f);
03546    } else
03547       ast_log(LOG_WARNING, "Unable to open pid file '%s': %s\n", ast_config_AST_PID, strerror(errno));
03548 
03549 #if HAVE_WORKING_FORK
03550    if (ast_opt_always_fork || !ast_opt_no_fork) {
03551 #ifndef HAVE_SBIN_LAUNCHD
03552       if (daemon(1, 0) < 0) {
03553          ast_log(LOG_ERROR, "daemon() failed: %s\n", strerror(errno));
03554       }
03555       ast_mainpid = getpid();
03556       /* Blindly re-write pid file since we are forking */
03557       unlink(ast_config_AST_PID);
03558       f = fopen(ast_config_AST_PID, "w");
03559       if (f) {
03560          fprintf(f, "%ld\n", (long)ast_mainpid);
03561          fclose(f);
03562       } else
03563          ast_log(LOG_WARNING, "Unable to open pid file '%s': %s\n", ast_config_AST_PID, strerror(errno));
03564 #else
03565       ast_log(LOG_WARNING, "Mac OS X detected.  Use 'launchctl load /Library/LaunchDaemon/org.asterisk.asterisk.plist'.\n");
03566 #endif
03567    }
03568 #endif
03569 
03570    /* Spawning of astcanary must happen AFTER the call to daemon(3) */
03571    if (isroot && ast_opt_high_priority) {
03572       snprintf(canary_filename, sizeof(canary_filename), "%s/alt.asterisk.canary.tweet.tweet.tweet", ast_config_AST_RUN_DIR);
03573 
03574       /* Don't let the canary child kill Asterisk, if it dies immediately */
03575       sigaction(SIGPIPE, &ignore_sig_handler, NULL);
03576 
03577       canary_pid = fork();
03578       if (canary_pid == 0) {
03579          char canary_binary[128], *lastslash, ppid[12];
03580 
03581          /* Reset signal handler */
03582          signal(SIGCHLD, SIG_DFL);
03583          signal(SIGPIPE, SIG_DFL);
03584 
03585          ast_close_fds_above_n(0);
03586          ast_set_priority(0);
03587          snprintf(ppid, sizeof(ppid), "%d", (int) ast_mainpid);
03588 
03589          execlp("astcanary", "astcanary", canary_filename, ppid, (char *)NULL);
03590 
03591          /* If not found, try the same path as used to execute asterisk */
03592          ast_copy_string(canary_binary, argv[0], sizeof(canary_binary));
03593          if ((lastslash = strrchr(canary_binary, '/'))) {
03594             ast_copy_string(lastslash + 1, "astcanary", sizeof(canary_binary) + canary_binary - (lastslash + 1));
03595             execl(canary_binary, "astcanary", canary_filename, (char *)NULL);
03596          }
03597 
03598          /* Should never happen */
03599          _exit(1);
03600       } else if (canary_pid > 0) {
03601          pthread_t dont_care;
03602          ast_pthread_create_detached(&dont_care, NULL, canary_thread, NULL);
03603       }
03604 
03605       /* Kill the canary when we exit */
03606       ast_register_atexit(canary_exit);
03607    }
03608 
03609    if (ast_event_init()) {
03610       printf("%s", term_quit());
03611       exit(1);
03612    }
03613 
03614 #ifdef TEST_FRAMEWORK
03615    if (ast_test_init()) {
03616       printf("%s", term_quit());
03617       exit(1);
03618    }
03619 #endif
03620 
03621    ast_makesocket();
03622    sigemptyset(&sigs);
03623    sigaddset(&sigs, SIGHUP);
03624    sigaddset(&sigs, SIGTERM);
03625    sigaddset(&sigs, SIGINT);
03626    sigaddset(&sigs, SIGPIPE);
03627    sigaddset(&sigs, SIGWINCH);
03628    pthread_sigmask(SIG_BLOCK, &sigs, NULL);
03629    sigaction(SIGURG, &urg_handler, NULL);
03630    signal(SIGINT, __quit_handler);
03631    signal(SIGTERM, __quit_handler);
03632    sigaction(SIGHUP, &hup_handler, NULL);
03633    sigaction(SIGPIPE, &ignore_sig_handler, NULL);
03634 
03635    /* ensure that the random number generators are seeded with a different value every time
03636       Asterisk is started
03637    */
03638    srand((unsigned int) getpid() + (unsigned int) time(NULL));
03639    initstate((unsigned int) getpid() * 65536 + (unsigned int) time(NULL), randompool, sizeof(randompool));
03640 
03641    if (init_logger()) {    /* Start logging subsystem */
03642       printf("%s", term_quit());
03643       exit(1);
03644    }
03645 
03646    threadstorage_init();
03647 
03648    astobj2_init();
03649 
03650    ast_autoservice_init();
03651 
03652    if (ast_timing_init()) {
03653       printf("%s", term_quit());
03654       exit(1);
03655    }
03656 
03657    if (ast_ssl_init()) {
03658       printf("%s", term_quit());
03659       exit(1);
03660    }
03661 
03662 #ifdef AST_XML_DOCS
03663    /* Load XML documentation. */
03664    ast_xmldoc_load_documentation();
03665 #endif
03666 
03667    if (load_modules(1)) {     /* Load modules, pre-load only */
03668       printf("%s", term_quit());
03669       exit(1);
03670    }
03671 
03672    if (dnsmgr_init()) {    /* Initialize the DNS manager */
03673       printf("%s", term_quit());
03674       exit(1);
03675    }
03676 
03677    ast_http_init();     /* Start the HTTP server, if needed */
03678 
03679    ast_channels_init();
03680 
03681    if (init_manager()) {
03682       printf("%s", term_quit());
03683       exit(1);
03684    }
03685 
03686    if (ast_cdr_engine_init()) {
03687       printf("%s", term_quit());
03688       exit(1);
03689    }
03690 
03691    if (ast_device_state_engine_init()) {
03692       printf("%s", term_quit());
03693       exit(1);
03694    }
03695 
03696    ast_rtp_init();
03697    ast_dsp_init();
03698    ast_udptl_init();
03699 
03700    if (ast_image_init()) {
03701       printf("%s", term_quit());
03702       exit(1);
03703    }
03704 
03705    if (ast_file_init()) {
03706       printf("%s", term_quit());
03707       exit(1);
03708    }
03709 
03710    if (load_pbx()) {
03711       printf("%s", term_quit());
03712       exit(1);
03713    }
03714 
03715    if (ast_indications_init()) {
03716       printf("%s", term_quit());
03717       exit(1);
03718    }
03719 
03720    ast_features_init();
03721 
03722    if (init_framer()) {
03723       printf("%s", term_quit());
03724       exit(1);
03725    }
03726 
03727    if (astdb_init()) {
03728       printf("%s", term_quit());
03729       exit(1);
03730    }
03731 
03732    if (ast_enum_init()) {
03733       printf("%s", term_quit());
03734       exit(1);
03735    }
03736 
03737    if (load_modules(0)) {
03738       printf("%s", term_quit());
03739       exit(1);
03740    }
03741 
03742    /* loads the cli_permissoins.conf file needed to implement cli restrictions. */
03743    ast_cli_perms_init(0);
03744 
03745    dnsmgr_start_refresh();
03746 
03747    /* We might have the option of showing a console, but for now just
03748       do nothing... */
03749    if (ast_opt_console && !option_verbose)
03750       ast_verbose(" ]\n");
03751    if (option_verbose || ast_opt_console)
03752       ast_verbose("%s", term_color(tmp, "Asterisk Ready.\n", COLOR_BRWHITE, COLOR_BLACK, sizeof(tmp)));
03753    if (ast_opt_no_fork)
03754       consolethread = pthread_self();
03755 
03756    if (pipe(sig_alert_pipe))
03757       sig_alert_pipe[0] = sig_alert_pipe[1] = -1;
03758 
03759    ast_set_flag(&ast_options, AST_OPT_FLAG_FULLY_BOOTED);
03760    if (ast_opt_send_fullybooted) {
03761       manager_event(EVENT_FLAG_SYSTEM, "FullyBooted", "Status: Fully Booted\r\n");
03762    }
03763 
03764    ast_process_pending_reloads();
03765 
03766    pthread_sigmask(SIG_UNBLOCK, &sigs, NULL);
03767 
03768 #ifdef __AST_DEBUG_MALLOC
03769    __ast_mm_init();
03770 #endif   
03771 
03772    ast_lastreloadtime = ast_startuptime = ast_tvnow();
03773    ast_cli_register_multiple(cli_asterisk, ARRAY_LEN(cli_asterisk));
03774 
03775    run_startup_commands();
03776 
03777    if (ast_opt_console) {
03778       /* Console stuff now... */
03779       /* Register our quit function */
03780       char title[256];
03781 
03782       ast_pthread_create_detached(&mon_sig_flags, NULL, monitor_sig_flags, NULL);
03783 
03784       set_icon("Asterisk");
03785       snprintf(title, sizeof(title), "Asterisk Console on '%s' (pid %ld)", hostname, (long)ast_mainpid);
03786       set_title(title);
03787 
03788       for (;;) {
03789          buf = (char *) el_gets(el, &num);
03790 
03791          if (!buf && write(1, "", 1) < 0)
03792             goto lostterm;
03793 
03794          if (buf) {
03795             if (buf[strlen(buf)-1] == '\n')
03796                buf[strlen(buf)-1] = '\0';
03797 
03798             consolehandler((char *)buf);
03799          } else if (ast_opt_remote && (write(STDOUT_FILENO, "\nUse EXIT or QUIT to exit the asterisk console\n",
03800                strlen("\nUse EXIT or QUIT to exit the asterisk console\n")) < 0)) {
03801             /* Whoa, stdout disappeared from under us... Make /dev/null's */
03802             int fd;
03803             fd = open("/dev/null", O_RDWR);
03804             if (fd > -1) {
03805                dup2(fd, STDOUT_FILENO);
03806                dup2(fd, STDIN_FILENO);
03807             } else
03808                ast_log(LOG_WARNING, "Failed to open /dev/null to recover from dead console. Bad things will happen!\n");
03809             break;
03810          }
03811       }
03812    }
03813 
03814    monitor_sig_flags(NULL);
03815 
03816 lostterm:
03817    return 0;
03818 }