Sat Apr 12 07:12:18 2008

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

Generated on Sat Apr 12 07:12:18 2008 for Asterisk - the Open Source PBX by  doxygen 1.5.5