Mon Jun 18 2012 03:55:22

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