Sat Mar 10 01:54:04 2012

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

Generated on Sat Mar 10 01:54:04 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7