Wed Aug 15 01:24:15 2007

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

Generated on Wed Aug 15 01:24:16 2007 for Asterisk - the Open Source PBX by  doxygen 1.5.3