Fri Aug 24 02:22:12 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$")
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 maximum open files */
01152 static void set_ulimit(int value)
01153 {
01154    struct rlimit l = {0, 0};
01155    
01156    if (value <= 0) {
01157       ast_log(LOG_WARNING, "Unable to change max files open to invalid value %i\n",value);
01158       return;
01159    }
01160    
01161    l.rlim_cur = value;
01162    l.rlim_max = value;
01163    
01164    if (setrlimit(RLIMIT_NOFILE, &l)) {
01165       ast_log(LOG_WARNING, "Unable to disable core size resource limit: %s\n",strerror(errno));
01166       return;
01167    }
01168    
01169    ast_log(LOG_NOTICE, "Setting max files open to %d\n",value);
01170    
01171    return;
01172 }
01173 
01174 /*! \brief Set an X-term or screen title */
01175 static void set_title(char *text)
01176 {
01177    if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
01178       fprintf(stdout, "\033]2;%s\007", text);
01179 }
01180 
01181 static void set_icon(char *text)
01182 {
01183    if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
01184       fprintf(stdout, "\033]1;%s\007", text);
01185 }
01186 
01187 /*! \brief We set ourselves to a high priority, that we might pre-empt everything
01188    else.  If your PBX has heavy activity on it, this is a good thing.  */
01189 int ast_set_priority(int pri)
01190 {
01191    struct sched_param sched;
01192    memset(&sched, 0, sizeof(sched));
01193 #ifdef __linux__
01194    if (pri) {  
01195       sched.sched_priority = 10;
01196       if (sched_setscheduler(0, SCHED_RR, &sched)) {
01197          ast_log(LOG_WARNING, "Unable to set high priority\n");
01198          return -1;
01199       } else
01200          if (option_verbose)
01201             ast_verbose("Set to realtime thread\n");
01202    } else {
01203       sched.sched_priority = 0;
01204       /* According to the manpage, these parameters can never fail. */
01205       sched_setscheduler(0, SCHED_OTHER, &sched);
01206    }
01207 #else
01208    if (pri) {
01209       if (setpriority(PRIO_PROCESS, 0, -10) == -1) {
01210          ast_log(LOG_WARNING, "Unable to set high priority\n");
01211          return -1;
01212       } else
01213          if (option_verbose)
01214             ast_verbose("Set to high priority\n");
01215    } else {
01216       /* According to the manpage, these parameters can never fail. */
01217       setpriority(PRIO_PROCESS, 0, 0);
01218    }
01219 #endif
01220    return 0;
01221 }
01222 
01223 static void ast_run_atexits(void)
01224 {
01225    struct ast_atexit *ae;
01226    AST_LIST_LOCK(&atexits);
01227    AST_LIST_TRAVERSE(&atexits, ae, list) {
01228       if (ae->func) 
01229          ae->func();
01230    }
01231    AST_LIST_UNLOCK(&atexits);
01232 }
01233 
01234 static void quit_handler(int num, int nice, int safeshutdown, int restart)
01235 {
01236    char filename[80] = "";
01237    time_t s,e;
01238    int x;
01239    /* Try to get as many CDRs as possible submitted to the backend engines (if in batch mode) */
01240    ast_cdr_engine_term();
01241    if (safeshutdown) {
01242       shuttingdown = 1;
01243       if (!nice) {
01244          /* Begin shutdown routine, hanging up active channels */
01245          ast_begin_shutdown(1);
01246          if (option_verbose && ast_opt_console)
01247             ast_verbose("Beginning asterisk %s....\n", restart ? "restart" : "shutdown");
01248          time(&s);
01249          for (;;) {
01250             time(&e);
01251             /* Wait up to 15 seconds for all channels to go away */
01252             if ((e - s) > 15)
01253                break;
01254             if (!ast_active_channels())
01255                break;
01256             if (!shuttingdown)
01257                break;
01258             /* Sleep 1/10 of a second */
01259             usleep(100000);
01260          }
01261       } else {
01262          if (nice < 2)
01263             ast_begin_shutdown(0);
01264          if (option_verbose && ast_opt_console)
01265             ast_verbose("Waiting for inactivity to perform %s...\n", restart ? "restart" : "halt");
01266          for (;;) {
01267             if (!ast_active_channels())
01268                break;
01269             if (!shuttingdown)
01270                break;
01271             sleep(1);
01272          }
01273       }
01274 
01275       if (!shuttingdown) {
01276          if (option_verbose && ast_opt_console)
01277             ast_verbose("Asterisk %s cancelled.\n", restart ? "restart" : "shutdown");
01278          return;
01279       }
01280 
01281       if (nice)
01282          ast_module_shutdown();
01283    }
01284    if (ast_opt_console || ast_opt_remote) {
01285       if (getenv("HOME")) 
01286          snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
01287       if (!ast_strlen_zero(filename))
01288          ast_el_write_history(filename);
01289       if (el != NULL)
01290          el_end(el);
01291       if (el_hist != NULL)
01292          history_end(el_hist);
01293    }
01294    if (option_verbose)
01295       ast_verbose("Executing last minute cleanups\n");
01296    ast_run_atexits();
01297    /* Called on exit */
01298    if (option_verbose && ast_opt_console)
01299       ast_verbose("Asterisk %s ending (%d).\n", ast_active_channels() ? "uncleanly" : "cleanly", num);
01300    if (option_debug)
01301       ast_log(LOG_DEBUG, "Asterisk ending (%d).\n", num);
01302    manager_event(EVENT_FLAG_SYSTEM, "Shutdown", "Shutdown: %s\r\nRestart: %s\r\n", ast_active_channels() ? "Uncleanly" : "Cleanly", restart ? "True" : "False");
01303    if (ast_socket > -1) {
01304       pthread_cancel(lthread);
01305       close(ast_socket);
01306       ast_socket = -1;
01307       unlink(ast_config_AST_SOCKET);
01308    }
01309    if (ast_consock > -1)
01310       close(ast_consock);
01311    if (!ast_opt_remote)
01312       unlink(ast_config_AST_PID);
01313    printf(term_quit());
01314    if (restart) {
01315       if (option_verbose || ast_opt_console)
01316          ast_verbose("Preparing for Asterisk restart...\n");
01317       /* Mark all FD's for closing on exec */
01318       for (x=3; x < 32768; x++) {
01319          fcntl(x, F_SETFD, FD_CLOEXEC);
01320       }
01321       if (option_verbose || ast_opt_console)
01322          ast_verbose("Asterisk is now restarting...\n");
01323       restartnow = 1;
01324 
01325       /* close logger */
01326       close_logger();
01327 
01328       /* If there is a consolethread running send it a SIGHUP 
01329          so it can execvp, otherwise we can do it ourselves */
01330       if ((consolethread != AST_PTHREADT_NULL) && (consolethread != pthread_self())) {
01331          pthread_kill(consolethread, SIGHUP);
01332          /* Give the signal handler some time to complete */
01333          sleep(2);
01334       } else
01335          execvp(_argv[0], _argv);
01336    
01337    } else {
01338       /* close logger */
01339       close_logger();
01340    }
01341    exit(0);
01342 }
01343 
01344 static void __quit_handler(int num)
01345 {
01346    int a = 0;
01347    sig_flags.need_quit = 1;
01348    if (sig_alert_pipe[1] != -1)
01349       write(sig_alert_pipe[1], &a, sizeof(a));
01350    /* There is no need to restore the signal handler here, since the app
01351     * is going to exit */
01352 }
01353 
01354 static const char *fix_header(char *outbuf, int maxout, const char *s, char *cmp)
01355 {
01356    const char *c;
01357    if (!strncmp(s, cmp, strlen(cmp))) {
01358       c = s + strlen(cmp);
01359       term_color(outbuf, cmp, COLOR_GRAY, 0, maxout);
01360       return c;
01361    }
01362    return NULL;
01363 }
01364 
01365 static void console_verboser(const char *s)
01366 {
01367    char tmp[80];
01368    const char *c = NULL;
01369 
01370    if ((c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_4)) ||
01371        (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_3)) ||
01372        (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_2)) ||
01373        (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_1))) {
01374       fputs(tmp, stdout);
01375       fputs(c, stdout);
01376    } else
01377       fputs(s, stdout);
01378 
01379    fflush(stdout);
01380    
01381    /* Wake up a poll()ing console */
01382    if (ast_opt_console && consolethread != AST_PTHREADT_NULL)
01383       pthread_kill(consolethread, SIGURG);
01384 }
01385 
01386 static int ast_all_zeros(char *s)
01387 {
01388    while (*s) {
01389       if (*s > 32)
01390          return 0;
01391       s++;  
01392    }
01393    return 1;
01394 }
01395 
01396 static void consolehandler(char *s)
01397 {
01398    printf(term_end());
01399    fflush(stdout);
01400 
01401    /* Called when readline data is available */
01402    if (!ast_all_zeros(s))
01403       ast_el_add_history(s);
01404    /* The real handler for bang */
01405    if (s[0] == '!') {
01406       if (s[1])
01407          ast_safe_system(s+1);
01408       else
01409          ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
01410    } else 
01411       ast_cli_command(STDOUT_FILENO, s);
01412 }
01413 
01414 static int remoteconsolehandler(char *s)
01415 {
01416    int ret = 0;
01417 
01418    /* Called when readline data is available */
01419    if (!ast_all_zeros(s))
01420       ast_el_add_history(s);
01421    /* The real handler for bang */
01422    if (s[0] == '!') {
01423       if (s[1])
01424          ast_safe_system(s+1);
01425       else
01426          ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
01427       ret = 1;
01428    }
01429    if ((strncasecmp(s, "quit", 4) == 0 || strncasecmp(s, "exit", 4) == 0) &&
01430        (s[4] == '\0' || isspace(s[4]))) {
01431       quit_handler(0, 0, 0, 0);
01432       ret = 1;
01433    }
01434 
01435    return ret;
01436 }
01437 
01438 static char abort_halt_help[] = 
01439 "Usage: abort shutdown\n"
01440 "       Causes Asterisk to abort an executing shutdown or restart, and resume normal\n"
01441 "       call operations.\n";
01442 
01443 static char shutdown_now_help[] = 
01444 "Usage: stop now\n"
01445 "       Shuts down a running Asterisk immediately, hanging up all active calls .\n";
01446 
01447 static char shutdown_gracefully_help[] = 
01448 "Usage: stop gracefully\n"
01449 "       Causes Asterisk to not accept new calls, and exit when all\n"
01450 "       active calls have terminated normally.\n";
01451 
01452 static char shutdown_when_convenient_help[] = 
01453 "Usage: stop when convenient\n"
01454 "       Causes Asterisk to perform a shutdown when all active calls have ended.\n";
01455 
01456 static char restart_now_help[] = 
01457 "Usage: restart now\n"
01458 "       Causes Asterisk to hangup all calls and exec() itself performing a cold\n"
01459 "       restart.\n";
01460 
01461 static char restart_gracefully_help[] = 
01462 "Usage: restart gracefully\n"
01463 "       Causes Asterisk to stop accepting new calls and exec() itself performing a cold\n"
01464 "       restart when all active calls have ended.\n";
01465 
01466 static char restart_when_convenient_help[] = 
01467 "Usage: restart when convenient\n"
01468 "       Causes Asterisk to perform a cold restart when all active calls have ended.\n";
01469 
01470 static char bang_help[] =
01471 "Usage: !<command>\n"
01472 "       Executes a given shell command\n";
01473 
01474 static char show_warranty_help[] =
01475 "Usage: core show warranty\n"
01476 "  Shows the warranty (if any) for this copy of Asterisk.\n";
01477 
01478 static char show_license_help[] =
01479 "Usage: core show license\n"
01480 "  Shows the license(s) for this copy of Asterisk.\n";
01481 
01482 static char version_help[] =
01483 "Usage: core show version\n"
01484 "       Shows Asterisk version information.\n";
01485 
01486 static int handle_version_deprecated(int fd, int argc, char *argv[])
01487 {
01488    if (argc != 2)
01489       return RESULT_SHOWUSAGE;
01490    ast_cli(fd, "Asterisk %s built by %s @ %s on a %s running %s on %s\n",
01491       ASTERISK_VERSION, ast_build_user, ast_build_hostname,
01492       ast_build_machine, ast_build_os, ast_build_date);
01493    return RESULT_SUCCESS;
01494 }
01495 
01496 static int handle_version(int fd, int argc, char *argv[])
01497 {
01498    if (argc != 3)
01499       return RESULT_SHOWUSAGE;
01500    ast_cli(fd, "Asterisk %s built by %s @ %s on a %s running %s on %s\n",
01501       ASTERISK_VERSION, ast_build_user, ast_build_hostname,
01502       ast_build_machine, ast_build_os, ast_build_date);
01503    return RESULT_SUCCESS;
01504 }
01505 
01506 #if 0
01507 static int handle_quit(int fd, int argc, char *argv[])
01508 {
01509    if (argc != 1)
01510       return RESULT_SHOWUSAGE;
01511    quit_handler(0, 0, 1, 0);
01512    return RESULT_SUCCESS;
01513 }
01514 #endif
01515 
01516 static int handle_shutdown_now(int fd, int argc, char *argv[])
01517 {
01518    if (argc != 2)
01519       return RESULT_SHOWUSAGE;
01520    quit_handler(0, 0 /* Not nice */, 1 /* safely */, 0 /* not restart */);
01521    return RESULT_SUCCESS;
01522 }
01523 
01524 static int handle_shutdown_gracefully(int fd, int argc, char *argv[])
01525 {
01526    if (argc != 2)
01527       return RESULT_SHOWUSAGE;
01528    quit_handler(0, 1 /* nicely */, 1 /* safely */, 0 /* no restart */);
01529    return RESULT_SUCCESS;
01530 }
01531 
01532 static int handle_shutdown_when_convenient(int fd, int argc, char *argv[])
01533 {
01534    if (argc != 3)
01535       return RESULT_SHOWUSAGE;
01536    ast_cli(fd, "Waiting for inactivity to perform halt\n");
01537    quit_handler(0, 2 /* really nicely */, 1 /* safely */, 0 /* don't restart */);
01538    return RESULT_SUCCESS;
01539 }
01540 
01541 static int handle_restart_now(int fd, int argc, char *argv[])
01542 {
01543    if (argc != 2)
01544       return RESULT_SHOWUSAGE;
01545    quit_handler(0, 0 /* not nicely */, 1 /* safely */, 1 /* restart */);
01546    return RESULT_SUCCESS;
01547 }
01548 
01549 static int handle_restart_gracefully(int fd, int argc, char *argv[])
01550 {
01551    if (argc != 2)
01552       return RESULT_SHOWUSAGE;
01553    quit_handler(0, 1 /* nicely */, 1 /* safely */, 1 /* restart */);
01554    return RESULT_SUCCESS;
01555 }
01556 
01557 static int handle_restart_when_convenient(int fd, int argc, char *argv[])
01558 {
01559    if (argc != 3)
01560       return RESULT_SHOWUSAGE;
01561    ast_cli(fd, "Waiting for inactivity to perform restart\n");
01562    quit_handler(0, 2 /* really nicely */, 1 /* safely */, 1 /* restart */);
01563    return RESULT_SUCCESS;
01564 }
01565 
01566 static int handle_abort_halt(int fd, int argc, char *argv[])
01567 {
01568    if (argc != 2)
01569       return RESULT_SHOWUSAGE;
01570    ast_cancel_shutdown();
01571    shuttingdown = 0;
01572    return RESULT_SUCCESS;
01573 }
01574 
01575 static int handle_bang(int fd, int argc, char *argv[])
01576 {
01577    return RESULT_SUCCESS;
01578 }
01579 static const char *warranty_lines[] = {
01580    "\n",
01581    "            NO WARRANTY\n",
01582    "\n",
01583    "BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\n",
01584    "FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN\n",
01585    "OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\n",
01586    "PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\n",
01587    "OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n",
01588    "MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS\n",
01589    "TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE\n",
01590    "PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\n",
01591    "REPAIR OR CORRECTION.\n",
01592    "\n",
01593    "IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\n",
01594    "WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\n",
01595    "REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\n",
01596    "INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\n",
01597    "OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\n",
01598    "TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\n",
01599    "YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\n",
01600    "PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\n",
01601    "POSSIBILITY OF SUCH DAMAGES.\n",
01602 };
01603 
01604 static int show_warranty(int fd, int argc, char *argv[])
01605 {
01606    int x;
01607 
01608    for (x = 0; x < sizeof(warranty_lines) / sizeof(warranty_lines[0]); x++)
01609       ast_cli(fd, (char *) warranty_lines[x]);
01610 
01611    return RESULT_SUCCESS;
01612 }
01613 
01614 static const char *license_lines[] = {
01615    "\n",
01616    "This program is free software; you can redistribute it and/or modify\n",
01617    "it under the terms of the GNU General Public License version 2 as\n",
01618    "published by the Free Software Foundation.\n",
01619    "\n",
01620    "This program also contains components licensed under other licenses.\n",
01621    "They include:\n",
01622    "\n",
01623    "This program is distributed in the hope that it will be useful,\n",
01624    "but WITHOUT ANY WARRANTY; without even the implied warranty of\n",
01625    "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n",
01626    "GNU General Public License for more details.\n",
01627    "\n",
01628    "You should have received a copy of the GNU General Public License\n",
01629    "along with this program; if not, write to the Free Software\n",
01630    "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\n",
01631 };
01632 
01633 static int show_license(int fd, int argc, char *argv[])
01634 {
01635    int x;
01636 
01637    for (x = 0; x < sizeof(license_lines) / sizeof(license_lines[0]); x++)
01638       ast_cli(fd, (char *) license_lines[x]);
01639 
01640    return RESULT_SUCCESS;
01641 }
01642 
01643 #define ASTERISK_PROMPT "*CLI> "
01644 
01645 #define ASTERISK_PROMPT2 "%s*CLI> "
01646 
01647 static struct ast_cli_entry cli_show_version_deprecated = {
01648    { "show", "version", NULL },
01649    handle_version_deprecated, "Display version info",
01650    version_help };
01651 
01652 #if !defined(LOW_MEMORY)
01653 static struct ast_cli_entry cli_show_version_files_deprecated = {
01654    { "show", "version", "files", NULL },
01655    handle_show_version_files_deprecated, NULL,
01656    NULL, complete_show_version_files_deprecated };
01657 
01658 static struct ast_cli_entry cli_show_profile_deprecated = {
01659    { "show", "profile", NULL },
01660    handle_show_profile_deprecated, NULL,
01661    NULL };
01662 
01663 static struct ast_cli_entry cli_clear_profile_deprecated = {
01664    { "clear", "profile", NULL },
01665    handle_show_profile_deprecated, NULL,
01666    NULL };
01667 #endif /* ! LOW_MEMORY */
01668 
01669 static struct ast_cli_entry cli_asterisk[] = {
01670    { { "abort", "halt", NULL },
01671    handle_abort_halt, "Cancel a running halt",
01672    abort_halt_help },
01673 
01674    { { "stop", "now", NULL },
01675    handle_shutdown_now, "Shut down Asterisk immediately",
01676    shutdown_now_help },
01677 
01678    { { "stop", "gracefully", NULL },
01679    handle_shutdown_gracefully, "Gracefully shut down Asterisk",
01680    shutdown_gracefully_help },
01681 
01682    { { "stop", "when", "convenient", NULL },
01683    handle_shutdown_when_convenient, "Shut down Asterisk at empty call volume",
01684    shutdown_when_convenient_help },
01685 
01686    { { "restart", "now", NULL },
01687    handle_restart_now, "Restart Asterisk immediately", restart_now_help },
01688 
01689    { { "restart", "gracefully", NULL },
01690    handle_restart_gracefully, "Restart Asterisk gracefully",
01691    restart_gracefully_help },
01692 
01693    { { "restart", "when", "convenient", NULL },
01694    handle_restart_when_convenient, "Restart Asterisk at empty call volume",
01695    restart_when_convenient_help },
01696 
01697    { { "core", "show", "warranty", NULL },
01698    show_warranty, "Show the warranty (if any) for this copy of Asterisk",
01699    show_warranty_help },
01700 
01701    { { "core", "show", "license", NULL },
01702    show_license, "Show the license(s) for this copy of Asterisk",
01703    show_license_help },
01704 
01705    { { "core", "show", "version", NULL },
01706    handle_version, "Display version info",
01707    version_help, NULL, &cli_show_version_deprecated },
01708 
01709    { { "!", NULL },
01710    handle_bang, "Execute a shell command",
01711    bang_help },
01712 
01713 #if !defined(LOW_MEMORY)
01714    { { "core", "show", "file", "version", NULL },
01715    handle_show_version_files, "List versions of files used to build Asterisk",
01716    show_version_files_help, complete_show_version_files, &cli_show_version_files_deprecated },
01717 
01718    { { "core", "show", "threads", NULL },
01719    handle_show_threads, "Show running threads",
01720    show_threads_help },
01721 
01722    { { "core", "show", "profile", NULL },
01723    handle_show_profile, "Display profiling info",
01724    NULL, NULL, &cli_show_profile_deprecated },
01725 
01726    { { "core", "clear", "profile", NULL },
01727    handle_show_profile, "Clear profiling info",
01728    NULL, NULL, &cli_clear_profile_deprecated },
01729 #endif /* ! LOW_MEMORY */
01730 };
01731 
01732 static int ast_el_read_char(EditLine *el, char *cp)
01733 {
01734    int num_read = 0;
01735    int lastpos = 0;
01736    struct pollfd fds[2];
01737    int res;
01738    int max;
01739    char buf[512];
01740 
01741    for (;;) {
01742       max = 1;
01743       fds[0].fd = ast_consock;
01744       fds[0].events = POLLIN;
01745       if (!ast_opt_exec) {
01746          fds[1].fd = STDIN_FILENO;
01747          fds[1].events = POLLIN;
01748          max++;
01749       }
01750       res = poll(fds, max, -1);
01751       if (res < 0) {
01752          if (errno == EINTR)
01753             continue;
01754          ast_log(LOG_ERROR, "poll failed: %s\n", strerror(errno));
01755          break;
01756       }
01757 
01758       if (!ast_opt_exec && fds[1].revents) {
01759          num_read = read(STDIN_FILENO, cp, 1);
01760          if (num_read < 1) {
01761             break;
01762          } else 
01763             return (num_read);
01764       }
01765       if (fds[0].revents) {
01766          res = read(ast_consock, buf, sizeof(buf) - 1);
01767          /* if the remote side disappears exit */
01768          if (res < 1) {
01769             fprintf(stderr, "\nDisconnected from Asterisk server\n");
01770             if (!ast_opt_reconnect) {
01771                quit_handler(0, 0, 0, 0);
01772             } else {
01773                int tries;
01774                int reconnects_per_second = 20;
01775                fprintf(stderr, "Attempting to reconnect for 30 seconds\n");
01776                for (tries=0; tries < 30 * reconnects_per_second; tries++) {
01777                   if (ast_tryconnect()) {
01778                      fprintf(stderr, "Reconnect succeeded after %.3f seconds\n", 1.0 / reconnects_per_second * tries);
01779                      printf(term_quit());
01780                      WELCOME_MESSAGE;
01781                      break;
01782                   } else {
01783                      usleep(1000000 / reconnects_per_second);
01784                   }
01785                }
01786                if (tries >= 30 * reconnects_per_second) {
01787                   fprintf(stderr, "Failed to reconnect for 30 seconds.  Quitting.\n");
01788                   quit_handler(0, 0, 0, 0);
01789                }
01790             }
01791          }
01792 
01793          buf[res] = '\0';
01794 
01795          if (!ast_opt_exec && !lastpos)
01796             write(STDOUT_FILENO, "\r", 1);
01797          write(STDOUT_FILENO, buf, res);
01798          if ((buf[res-1] == '\n') || (buf[res-2] == '\n')) {
01799             *cp = CC_REFRESH;
01800             return(1);
01801          } else {
01802             lastpos = 1;
01803          }
01804       }
01805    }
01806 
01807    *cp = '\0';
01808    return (0);
01809 }
01810 
01811 static char *cli_prompt(EditLine *el)
01812 {
01813    static char prompt[200];
01814    char *pfmt;
01815    int color_used = 0;
01816    char term_code[20];
01817 
01818    if ((pfmt = getenv("ASTERISK_PROMPT"))) {
01819       char *t = pfmt, *p = prompt;
01820       memset(prompt, 0, sizeof(prompt));
01821       while (*t != '\0' && *p < sizeof(prompt)) {
01822          if (*t == '%') {
01823             char hostname[MAXHOSTNAMELEN]="";
01824             int i;
01825             time_t ts;
01826             struct tm tm;
01827 #ifdef linux
01828             FILE *LOADAVG;
01829 #endif
01830             int fgcolor = COLOR_WHITE, bgcolor = COLOR_BLACK;
01831 
01832             t++;
01833             switch (*t) {
01834             case 'C': /* color */
01835                t++;
01836                if (sscanf(t, "%d;%d%n", &fgcolor, &bgcolor, &i) == 2) {
01837                   strncat(p, term_color_code(term_code, fgcolor, bgcolor, sizeof(term_code)),sizeof(prompt) - strlen(prompt) - 1);
01838                   t += i - 1;
01839                } else if (sscanf(t, "%d%n", &fgcolor, &i) == 1) {
01840                   strncat(p, term_color_code(term_code, fgcolor, 0, sizeof(term_code)),sizeof(prompt) - strlen(prompt) - 1);
01841                   t += i - 1;
01842                }
01843 
01844                /* If the color has been reset correctly, then there's no need to reset it later */
01845                if ((fgcolor == COLOR_WHITE) && (bgcolor == COLOR_BLACK)) {
01846                   color_used = 0;
01847                } else {
01848                   color_used = 1;
01849                }
01850                break;
01851             case 'd': /* date */
01852                memset(&tm, 0, sizeof(tm));
01853                time(&ts);
01854                if (ast_localtime(&ts, &tm, NULL)) {
01855                   strftime(p, sizeof(prompt) - strlen(prompt), "%Y-%m-%d", &tm);
01856                }
01857                break;
01858             case 'h': /* hostname */
01859                if (!gethostname(hostname, sizeof(hostname) - 1)) {
01860                   strncat(p, hostname, sizeof(prompt) - strlen(prompt) - 1);
01861                } else {
01862                   strncat(p, "localhost", sizeof(prompt) - strlen(prompt) - 1);
01863                }
01864                break;
01865             case 'H': /* short hostname */
01866                if (!gethostname(hostname, sizeof(hostname) - 1)) {
01867                   for (i = 0; i < sizeof(hostname); i++) {
01868                      if (hostname[i] == '.') {
01869                         hostname[i] = '\0';
01870                         break;
01871                      }
01872                   }
01873                   strncat(p, hostname, sizeof(prompt) - strlen(prompt) - 1);
01874                } else {
01875                   strncat(p, "localhost", sizeof(prompt) - strlen(prompt) - 1);
01876                }
01877                break;
01878 #ifdef linux
01879             case 'l': /* load avg */
01880                t++;
01881                if ((LOADAVG = fopen("/proc/loadavg", "r"))) {
01882                   float avg1, avg2, avg3;
01883                   int actproc, totproc, npid, which;
01884                   fscanf(LOADAVG, "%f %f %f %d/%d %d",
01885                      &avg1, &avg2, &avg3, &actproc, &totproc, &npid);
01886                   if (sscanf(t, "%d", &which) == 1) {
01887                      switch (which) {
01888                      case 1:
01889                         snprintf(p, sizeof(prompt) - strlen(prompt), "%.2f", avg1);
01890                         break;
01891                      case 2:
01892                         snprintf(p, sizeof(prompt) - strlen(prompt), "%.2f", avg2);
01893                         break;
01894                      case 3:
01895                         snprintf(p, sizeof(prompt) - strlen(prompt), "%.2f", avg3);
01896                         break;
01897                      case 4:
01898                         snprintf(p, sizeof(prompt) - strlen(prompt), "%d/%d", actproc, totproc);
01899                         break;
01900                      case 5:
01901                         snprintf(p, sizeof(prompt) - strlen(prompt), "%d", npid);
01902                         break;
01903                      }
01904                   }
01905                }
01906                break;
01907 #endif
01908             case 's': /* Asterisk system name (from asterisk.conf) */
01909                strncat(p, ast_config_AST_SYSTEM_NAME, sizeof(prompt) - strlen(prompt) - 1);
01910                break;
01911             case 't': /* time */
01912                memset(&tm, 0, sizeof(tm));
01913                time(&ts);
01914                if (ast_localtime(&ts, &tm, NULL)) {
01915                   strftime(p, sizeof(prompt) - strlen(prompt), "%H:%M:%S", &tm);
01916                }
01917                break;
01918             case '#': /* process console or remote? */
01919                if (!ast_opt_remote) {
01920                   strncat(p, "#", sizeof(prompt) - strlen(prompt) - 1);
01921                } else {
01922                   strncat(p, ">", sizeof(prompt) - strlen(prompt) - 1);
01923                }
01924                break;
01925             case '%': /* literal % */
01926                strncat(p, "%", sizeof(prompt) - strlen(prompt) - 1);
01927                break;
01928             case '\0': /* % is last character - prevent bug */
01929                t--;
01930                break;
01931             }
01932             while (*p != '\0') {
01933                p++;
01934             }
01935             t++;
01936          } else {
01937             *p = *t;
01938             p++;
01939             t++;
01940          }
01941       }
01942       if (color_used) {
01943          /* Force colors back to normal at end */
01944          term_color_code(term_code, COLOR_WHITE, COLOR_BLACK, sizeof(term_code));
01945          if (strlen(term_code) > sizeof(prompt) - strlen(prompt)) {
01946             strncat(prompt + sizeof(prompt) - strlen(term_code) - 1, term_code, strlen(term_code));
01947          } else {
01948             strncat(p, term_code, sizeof(term_code));
01949          }
01950       }
01951    } else if (remotehostname)
01952       snprintf(prompt, sizeof(prompt), ASTERISK_PROMPT2, remotehostname);
01953    else
01954       snprintf(prompt, sizeof(prompt), ASTERISK_PROMPT);
01955 
01956    return(prompt);   
01957 }
01958 
01959 static char **ast_el_strtoarr(char *buf)
01960 {
01961    char **match_list = NULL, *retstr;
01962    size_t match_list_len;
01963    int matches = 0;
01964 
01965    match_list_len = 1;
01966    while ( (retstr = strsep(&buf, " ")) != NULL) {
01967 
01968       if (!strcmp(retstr, AST_CLI_COMPLETE_EOF))
01969          break;
01970       if (matches + 1 >= match_list_len) {
01971          match_list_len <<= 1;
01972          if (!(match_list = ast_realloc(match_list, match_list_len * sizeof(char *)))) {
01973             /* TODO: Handle memory allocation failure */
01974          }
01975       }
01976 
01977       match_list[matches++] = strdup(retstr);
01978    }
01979 
01980    if (!match_list)
01981       return (char **) NULL;
01982 
01983    if (matches >= match_list_len) {
01984       if (!(match_list = ast_realloc(match_list, (match_list_len + 1) * sizeof(char *)))) {
01985          /* TODO: Handle memory allocation failure */
01986       }
01987    }
01988 
01989    match_list[matches] = (char *) NULL;
01990 
01991    return match_list;
01992 }
01993 
01994 static int ast_el_sort_compare(const void *i1, const void *i2)
01995 {
01996    char *s1, *s2;
01997 
01998    s1 = ((char **)i1)[0];
01999    s2 = ((char **)i2)[0];
02000 
02001    return strcasecmp(s1, s2);
02002 }
02003 
02004 static int ast_cli_display_match_list(char **matches, int len, int max)
02005 {
02006    int i, idx, limit, count;
02007    int screenwidth = 0;
02008    int numoutput = 0, numoutputline = 0;
02009 
02010    screenwidth = ast_get_termcols(STDOUT_FILENO);
02011 
02012    /* find out how many entries can be put on one line, with two spaces between strings */
02013    limit = screenwidth / (max + 2);
02014    if (limit == 0)
02015       limit = 1;
02016 
02017    /* how many lines of output */
02018    count = len / limit;
02019    if (count * limit < len)
02020       count++;
02021 
02022    idx = 1;
02023 
02024    qsort(&matches[0], (size_t)(len), sizeof(char *), ast_el_sort_compare);
02025 
02026    for (; count > 0; count--) {
02027       numoutputline = 0;
02028       for (i=0; i < limit && matches[idx]; i++, idx++) {
02029 
02030          /* Don't print dupes */
02031          if ( (matches[idx+1] != NULL && strcmp(matches[idx], matches[idx+1]) == 0 ) ) {
02032             i--;
02033             free(matches[idx]);
02034             matches[idx] = NULL;
02035             continue;
02036          }
02037 
02038          numoutput++;
02039          numoutputline++;
02040          fprintf(stdout, "%-*s  ", max, matches[idx]);
02041          free(matches[idx]);
02042          matches[idx] = NULL;
02043       }
02044       if (numoutputline > 0)
02045          fprintf(stdout, "\n");
02046    }
02047 
02048    return numoutput;
02049 }
02050 
02051 
02052 static char *cli_complete(EditLine *el, int ch)
02053 {
02054    int len = 0;
02055    char *ptr;
02056    int nummatches = 0;
02057    char **matches;
02058    int retval = CC_ERROR;
02059    char buf[2048];
02060    int res;
02061 
02062    LineInfo *lf = (LineInfo *)el_line(el);
02063 
02064    *(char *)lf->cursor = '\0';
02065    ptr = (char *)lf->cursor;
02066    if (ptr) {
02067       while (ptr > lf->buffer) {
02068          if (isspace(*ptr)) {
02069             ptr++;
02070             break;
02071          }
02072          ptr--;
02073       }
02074    }
02075 
02076    len = lf->cursor - ptr;
02077 
02078    if (ast_opt_remote) {
02079       snprintf(buf, sizeof(buf),"_COMMAND NUMMATCHES \"%s\" \"%s\"", lf->buffer, ptr); 
02080       fdprint(ast_consock, buf);
02081       res = read(ast_consock, buf, sizeof(buf));
02082       buf[res] = '\0';
02083       nummatches = atoi(buf);
02084 
02085       if (nummatches > 0) {
02086          char *mbuf;
02087          int mlen = 0, maxmbuf = 2048;
02088          /* Start with a 2048 byte buffer */       
02089          if (!(mbuf = ast_malloc(maxmbuf)))
02090             return (char *)(CC_ERROR);
02091          snprintf(buf, sizeof(buf),"_COMMAND MATCHESARRAY \"%s\" \"%s\"", lf->buffer, ptr); 
02092          fdprint(ast_consock, buf);
02093          res = 0;
02094          mbuf[0] = '\0';
02095          while (!strstr(mbuf, AST_CLI_COMPLETE_EOF) && res != -1) {
02096             if (mlen + 1024 > maxmbuf) {
02097                /* Every step increment buffer 1024 bytes */
02098                maxmbuf += 1024;              
02099                if (!(mbuf = ast_realloc(mbuf, maxmbuf)))
02100                   return (char *)(CC_ERROR);
02101             }
02102             /* Only read 1024 bytes at a time */
02103             res = read(ast_consock, mbuf + mlen, 1024);
02104             if (res > 0)
02105                mlen += res;
02106          }
02107          mbuf[mlen] = '\0';
02108 
02109          matches = ast_el_strtoarr(mbuf);
02110          free(mbuf);
02111       } else
02112          matches = (char **) NULL;
02113    } else {
02114       char **p, *oldbuf=NULL;
02115       nummatches = 0;
02116       matches = ast_cli_completion_matches((char *)lf->buffer,ptr);
02117       for (p = matches; p && *p; p++) {
02118          if (!oldbuf || strcmp(*p,oldbuf))
02119             nummatches++;
02120          oldbuf = *p;
02121       }
02122    }
02123 
02124    if (matches) {
02125       int i;
02126       int matches_num, maxlen, match_len;
02127 
02128       if (matches[0][0] != '\0') {
02129          el_deletestr(el, (int) len);
02130          el_insertstr(el, matches[0]);
02131          retval = CC_REFRESH;
02132       }
02133 
02134       if (nummatches == 1) {
02135          /* Found an exact match */
02136          el_insertstr(el, " ");
02137          retval = CC_REFRESH;
02138       } else {
02139          /* Must be more than one match */
02140          for (i=1, maxlen=0; matches[i]; i++) {
02141             match_len = strlen(matches[i]);
02142             if (match_len > maxlen)
02143                maxlen = match_len;
02144          }
02145          matches_num = i - 1;
02146          if (matches_num >1) {
02147             fprintf(stdout, "\n");
02148             ast_cli_display_match_list(matches, nummatches, maxlen);
02149             retval = CC_REDISPLAY;
02150          } else { 
02151             el_insertstr(el," ");
02152             retval = CC_REFRESH;
02153          }
02154       }
02155       for (i = 0; matches[i]; i++)
02156          free(matches[i]);
02157       free(matches);
02158    }
02159 
02160    return (char *)(long)retval;
02161 }
02162 
02163 static int ast_el_initialize(void)
02164 {
02165    HistEvent ev;
02166    char *editor = getenv("AST_EDITOR");
02167 
02168    if (el != NULL)
02169       el_end(el);
02170    if (el_hist != NULL)
02171       history_end(el_hist);
02172 
02173    el = el_init("asterisk", stdin, stdout, stderr);
02174    el_set(el, EL_PROMPT, cli_prompt);
02175 
02176    el_set(el, EL_EDITMODE, 1);      
02177    el_set(el, EL_EDITOR, editor ? editor : "emacs");     
02178    el_hist = history_init();
02179    if (!el || !el_hist)
02180       return -1;
02181 
02182    /* setup history with 100 entries */
02183    history(el_hist, &ev, H_SETSIZE, 100);
02184 
02185    el_set(el, EL_HIST, history, el_hist);
02186 
02187    el_set(el, EL_ADDFN, "ed-complete", "Complete argument", cli_complete);
02188    /* Bind <tab> to command completion */
02189    el_set(el, EL_BIND, "^I", "ed-complete", NULL);
02190    /* Bind ? to command completion */
02191    el_set(el, EL_BIND, "?", "ed-complete", NULL);
02192    /* Bind ^D to redisplay */
02193    el_set(el, EL_BIND, "^D", "ed-redisplay", NULL);
02194 
02195    return 0;
02196 }
02197 
02198 static int ast_el_add_history(char *buf)
02199 {
02200    HistEvent ev;
02201 
02202    if (el_hist == NULL || el == NULL)
02203       ast_el_initialize();
02204    if (strlen(buf) > 256)
02205       return 0;
02206    return (history(el_hist, &ev, H_ENTER, buf));
02207 }
02208 
02209 static int ast_el_write_history(char *filename)
02210 {
02211    HistEvent ev;
02212 
02213    if (el_hist == NULL || el == NULL)
02214       ast_el_initialize();
02215 
02216    return (history(el_hist, &ev, H_SAVE, filename));
02217 }
02218 
02219 static int ast_el_read_history(char *filename)
02220 {
02221    char buf[256];
02222    FILE *f;
02223    int ret = -1;
02224 
02225    if (el_hist == NULL || el == NULL)
02226       ast_el_initialize();
02227 
02228    if ((f = fopen(filename, "r")) == NULL)
02229       return ret;
02230 
02231    while (!feof(f)) {
02232       fgets(buf, sizeof(buf), f);
02233       if (!strcmp(buf, "_HiStOrY_V2_\n"))
02234          continue;
02235       if (ast_all_zeros(buf))
02236          continue;
02237       if ((ret = ast_el_add_history(buf)) == -1)
02238          break;
02239    }
02240    fclose(f);
02241 
02242    return ret;
02243 }
02244 
02245 static void ast_remotecontrol(char * data)
02246 {
02247    char buf[80];
02248    int res;
02249    char filename[80] = "";
02250    char *hostname;
02251    char *cpid;
02252    char *version;
02253    int pid;
02254    char tmp[80];
02255    char *stringp = NULL;
02256 
02257    char *ebuf;
02258    int num = 0;
02259 
02260    read(ast_consock, buf, sizeof(buf));
02261    if (data)
02262       write(ast_consock, data, strlen(data) + 1);
02263    stringp = buf;
02264    hostname = strsep(&stringp, "/");
02265    cpid = strsep(&stringp, "/");
02266    version = strsep(&stringp, "\n");
02267    if (!version)
02268       version = "<Version Unknown>";
02269    stringp = hostname;
02270    strsep(&stringp, ".");
02271    if (cpid)
02272       pid = atoi(cpid);
02273    else
02274       pid = -1;
02275    snprintf(tmp, sizeof(tmp), "core set verbose atleast %d", option_verbose);
02276    fdprint(ast_consock, tmp);
02277    snprintf(tmp, sizeof(tmp), "core set debug atleast %d", option_debug);
02278    fdprint(ast_consock, tmp);
02279    if (ast_opt_mute) {
02280       snprintf(tmp, sizeof(tmp), "log and verbose output currently muted ('logger unmute' to unmute)");
02281       fdprint(ast_consock, tmp);
02282    }
02283    ast_verbose("Connected to Asterisk %s currently running on %s (pid = %d)\n", version, hostname, pid);
02284    remotehostname = hostname;
02285    if (getenv("HOME")) 
02286       snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
02287    if (el_hist == NULL || el == NULL)
02288       ast_el_initialize();
02289 
02290    el_set(el, EL_GETCFN, ast_el_read_char);
02291 
02292    if (!ast_strlen_zero(filename))
02293       ast_el_read_history(filename);
02294 
02295    if (ast_opt_exec && data) {  /* hack to print output then exit if asterisk -rx is used */
02296       char tempchar;
02297       struct pollfd fds;
02298       fds.fd = ast_consock;
02299       fds.events = POLLIN;
02300       fds.revents = 0;
02301       while (poll(&fds, 1, 100) > 0)
02302          ast_el_read_char(el, &tempchar);
02303       return;
02304    }
02305    for (;;) {
02306       ebuf = (char *)el_gets(el, &num);
02307 
02308       if (!ebuf && write(1, "", 1) < 0)
02309          break;
02310 
02311       if (!ast_strlen_zero(ebuf)) {
02312          if (ebuf[strlen(ebuf)-1] == '\n')
02313             ebuf[strlen(ebuf)-1] = '\0';
02314          if (!remoteconsolehandler(ebuf)) {
02315             res = write(ast_consock, ebuf, strlen(ebuf) + 1);
02316             if (res < 1) {
02317                ast_log(LOG_WARNING, "Unable to write: %s\n", strerror(errno));
02318                break;
02319             }
02320          }
02321       }
02322    }
02323    printf("\nDisconnected from Asterisk server\n");
02324 }
02325 
02326 static int show_version(void)
02327 {
02328    printf("Asterisk " ASTERISK_VERSION "\n");
02329    return 0;
02330 }
02331 
02332 static int show_cli_help(void) {
02333    printf("Asterisk " ASTERISK_VERSION ", Copyright (C) 1999 - 2007, Digium, Inc. and others.\n");
02334    printf("Usage: asterisk [OPTIONS]\n");
02335    printf("Valid Options:\n");
02336    printf("   -V              Display version number and exit\n");
02337    printf("   -C <configfile> Use an alternate configuration file\n");
02338    printf("   -G <group>      Run as a group other than the caller\n");
02339    printf("   -U <user>       Run as a user other than the caller\n");
02340    printf("   -c              Provide console CLI\n");
02341    printf("   -d              Enable extra debugging\n");
02342 #if HAVE_WORKING_FORK
02343    printf("   -f              Do not fork\n");
02344    printf("   -F              Always fork\n");
02345 #endif
02346    printf("   -g              Dump core in case of a crash\n");
02347    printf("   -h              This help screen\n");
02348    printf("   -i              Initialize crypto keys at startup\n");
02349    printf("   -I              Enable internal timing if Zaptel timer is available\n");
02350    printf("   -L <load>       Limit the maximum load average before rejecting new calls\n");
02351    printf("   -M <value>      Limit the maximum number of calls to the specified value\n");
02352    printf("   -m              Mute the console from debugging and verbose output\n");
02353    printf("   -n              Disable console colorization\n");
02354    printf("   -p              Run as pseudo-realtime thread\n");
02355    printf("   -q              Quiet mode (suppress output)\n");
02356    printf("   -r              Connect to Asterisk on this machine\n");
02357    printf("   -R              Connect to Asterisk, and attempt to reconnect if disconnected\n");
02358    printf("   -t              Record soundfiles in /var/tmp and move them where they belong after they are done.\n");
02359    printf("   -T              Display the time in [Mmm dd hh:mm:ss] format for each line of output to the CLI.\n");
02360    printf("   -v              Increase verbosity (multiple v's = more verbose)\n");
02361    printf("   -x <cmd>        Execute command <cmd> (only valid with -r)\n");
02362    printf("\n");
02363    return 0;
02364 }
02365 
02366 static void ast_readconfig(void) 
02367 {
02368    struct ast_config *cfg;
02369    struct ast_variable *v;
02370    char *config = AST_CONFIG_FILE;
02371 
02372    if (ast_opt_override_config) {
02373       cfg = ast_config_load(ast_config_AST_CONFIG_FILE);
02374       if (!cfg)
02375          ast_log(LOG_WARNING, "Unable to open specified master config file '%s', using built-in defaults\n", ast_config_AST_CONFIG_FILE);
02376    } else {
02377       cfg = ast_config_load(config);
02378    }
02379 
02380    /* init with buildtime config */
02381    ast_copy_string(ast_config_AST_CONFIG_DIR, AST_CONFIG_DIR, sizeof(ast_config_AST_CONFIG_DIR));
02382    ast_copy_string(ast_config_AST_SPOOL_DIR, AST_SPOOL_DIR, sizeof(ast_config_AST_SPOOL_DIR));
02383    ast_copy_string(ast_config_AST_MODULE_DIR, AST_MODULE_DIR, sizeof(ast_config_AST_MODULE_DIR));
02384    snprintf(ast_config_AST_MONITOR_DIR, sizeof(ast_config_AST_MONITOR_DIR) - 1, "%s/monitor", ast_config_AST_SPOOL_DIR);
02385    ast_copy_string(ast_config_AST_VAR_DIR, AST_VAR_DIR, sizeof(ast_config_AST_VAR_DIR));
02386    ast_copy_string(ast_config_AST_DATA_DIR, AST_DATA_DIR, sizeof(ast_config_AST_DATA_DIR));
02387    ast_copy_string(ast_config_AST_LOG_DIR, AST_LOG_DIR, sizeof(ast_config_AST_LOG_DIR));
02388    ast_copy_string(ast_config_AST_AGI_DIR, AST_AGI_DIR, sizeof(ast_config_AST_AGI_DIR));
02389    ast_copy_string(ast_config_AST_DB, AST_DB, sizeof(ast_config_AST_DB));
02390    ast_copy_string(ast_config_AST_KEY_DIR, AST_KEY_DIR, sizeof(ast_config_AST_KEY_DIR));
02391    ast_copy_string(ast_config_AST_PID, AST_PID, sizeof(ast_config_AST_PID));
02392    ast_copy_string(ast_config_AST_SOCKET, AST_SOCKET, sizeof(ast_config_AST_SOCKET));
02393    ast_copy_string(ast_config_AST_RUN_DIR, AST_RUN_DIR, sizeof(ast_config_AST_RUN_DIR));
02394 
02395    /* no asterisk.conf? no problem, use buildtime config! */
02396    if (!cfg) {
02397       return;
02398    }
02399 
02400    for (v = ast_variable_browse(cfg, "files"); v; v = v->next) {
02401       if (!strcasecmp(v->name, "astctlpermissions")) {
02402          ast_copy_string(ast_config_AST_CTL_PERMISSIONS, v->value, sizeof(ast_config_AST_CTL_PERMISSIONS));
02403       } else if (!strcasecmp(v->name, "astctlowner")) {
02404          ast_copy_string(ast_config_AST_CTL_OWNER, v->value, sizeof(ast_config_AST_CTL_OWNER));
02405       } else if (!strcasecmp(v->name, "astctlgroup")) {
02406          ast_copy_string(ast_config_AST_CTL_GROUP, v->value, sizeof(ast_config_AST_CTL_GROUP));
02407       } else if (!strcasecmp(v->name, "astctl")) {
02408          ast_copy_string(ast_config_AST_CTL, v->value, sizeof(ast_config_AST_CTL));
02409       }
02410    }
02411 
02412    for (v = ast_variable_browse(cfg, "directories"); v; v = v->next) {
02413       if (!strcasecmp(v->name, "astetcdir")) {
02414          ast_copy_string(ast_config_AST_CONFIG_DIR, v->value, sizeof(ast_config_AST_CONFIG_DIR));
02415       } else if (!strcasecmp(v->name, "astspooldir")) {
02416          ast_copy_string(ast_config_AST_SPOOL_DIR, v->value, sizeof(ast_config_AST_SPOOL_DIR));
02417          snprintf(ast_config_AST_MONITOR_DIR, sizeof(ast_config_AST_MONITOR_DIR) - 1, "%s/monitor", v->value);
02418       } else if (!strcasecmp(v->name, "astvarlibdir")) {
02419          ast_copy_string(ast_config_AST_VAR_DIR, v->value, sizeof(ast_config_AST_VAR_DIR));
02420          snprintf(ast_config_AST_DB, sizeof(ast_config_AST_DB), "%s/astdb", v->value);
02421       } else if (!strcasecmp(v->name, "astdatadir")) {
02422          ast_copy_string(ast_config_AST_DATA_DIR, v->value, sizeof(ast_config_AST_DATA_DIR));
02423          snprintf(ast_config_AST_KEY_DIR, sizeof(ast_config_AST_KEY_DIR), "%s/keys", v->value);
02424       } else if (!strcasecmp(v->name, "astlogdir")) {
02425          ast_copy_string(ast_config_AST_LOG_DIR, v->value, sizeof(ast_config_AST_LOG_DIR));
02426       } else if (!strcasecmp(v->name, "astagidir")) {
02427          ast_copy_string(ast_config_AST_AGI_DIR, v->value, sizeof(ast_config_AST_AGI_DIR));
02428       } else if (!strcasecmp(v->name, "astrundir")) {
02429          snprintf(ast_config_AST_PID, sizeof(ast_config_AST_PID), "%s/%s", v->value, "asterisk.pid");
02430          snprintf(ast_config_AST_SOCKET, sizeof(ast_config_AST_SOCKET), "%s/%s", v->value, ast_config_AST_CTL);
02431          ast_copy_string(ast_config_AST_RUN_DIR, v->value, sizeof(ast_config_AST_RUN_DIR));
02432       } else if (!strcasecmp(v->name, "astmoddir")) {
02433          ast_copy_string(ast_config_AST_MODULE_DIR, v->value, sizeof(ast_config_AST_MODULE_DIR));
02434       }
02435    }
02436 
02437    for (v = ast_variable_browse(cfg, "options"); v; v = v->next) {
02438       /* verbose level (-v at startup) */
02439       if (!strcasecmp(v->name, "verbose")) {
02440          option_verbose = atoi(v->value);
02441       /* whether or not to force timestamping in CLI verbose output. (-T at startup) */
02442       } else if (!strcasecmp(v->name, "timestamp")) {
02443          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TIMESTAMP);
02444       /* whether or not to support #exec in config files */
02445       } else if (!strcasecmp(v->name, "execincludes")) {
02446          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_EXEC_INCLUDES);
02447       /* debug level (-d at startup) */
02448       } else if (!strcasecmp(v->name, "debug")) {
02449          option_debug = 0;
02450          if (sscanf(v->value, "%d", &option_debug) != 1) {
02451             option_debug = ast_true(v->value);
02452          }
02453 #if HAVE_WORKING_FORK
02454       /* Disable forking (-f at startup) */
02455       } else if (!strcasecmp(v->name, "nofork")) {
02456          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_FORK);
02457       /* Always fork, even if verbose or debug are enabled (-F at startup) */
02458       } else if (!strcasecmp(v->name, "alwaysfork")) {
02459          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_ALWAYS_FORK);
02460 #endif
02461       /* Run quietly (-q at startup ) */
02462       } else if (!strcasecmp(v->name, "quiet")) {
02463          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_QUIET);
02464       /* Run as console (-c at startup, implies nofork) */
02465       } else if (!strcasecmp(v->name, "console")) {
02466          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_CONSOLE);
02467       /* Run with high priority if the O/S permits (-p at startup) */
02468       } else if (!strcasecmp(v->name, "highpriority")) {
02469          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_HIGH_PRIORITY);
02470       /* Initialize RSA auth keys (IAX2) (-i at startup) */
02471       } else if (!strcasecmp(v->name, "initcrypto")) {
02472          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_INIT_KEYS);
02473       /* Disable ANSI colors for console (-c at startup) */
02474       } else if (!strcasecmp(v->name, "nocolor")) {
02475          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_COLOR);
02476       /* Disable some usage warnings for picky people :p */
02477       } else if (!strcasecmp(v->name, "dontwarn")) {
02478          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_DONT_WARN);
02479       /* Dump core in case of crash (-g) */
02480       } else if (!strcasecmp(v->name, "dumpcore")) {
02481          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_DUMP_CORE);
02482       /* Cache recorded sound files to another directory during recording */
02483       } else if (!strcasecmp(v->name, "cache_record_files")) {
02484          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_CACHE_RECORD_FILES);
02485       /* Specify cache directory */
02486       }  else if (!strcasecmp(v->name, "record_cache_dir")) {
02487          ast_copy_string(record_cache_dir, v->value, AST_CACHE_DIR_LEN);
02488       /* Build transcode paths via SLINEAR, instead of directly */
02489       } else if (!strcasecmp(v->name, "transcode_via_sln")) {
02490          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TRANSCODE_VIA_SLIN);
02491       /* Transmit SLINEAR silence while a channel is being recorded */
02492       } else if (!strcasecmp(v->name, "transmit_silence_during_record")) {
02493          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TRANSMIT_SILENCE);
02494       /* Enable internal timing */
02495       } else if (!strcasecmp(v->name, "internal_timing")) {
02496          ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_INTERNAL_TIMING);
02497       } else if (!strcasecmp(v->name, "maxcalls")) {
02498          if ((sscanf(v->value, "%d", &option_maxcalls) != 1) || (option_maxcalls < 0)) {
02499             option_maxcalls = 0;
02500          }
02501       } else if (!strcasecmp(v->name, "maxload")) {
02502          double test[1];
02503 
02504          if (getloadavg(test, 1) == -1) {
02505             ast_log(LOG_ERROR, "Cannot obtain load average on this system. 'maxload' option disabled.\n");
02506             option_maxload = 0.0;
02507          } else if ((sscanf(v->value, "%lf", &option_maxload) != 1) || (option_maxload < 0.0)) {
02508             option_maxload = 0.0;
02509          }
02510       /* Set the maximum amount of open files */
02511       } else if (!strcasecmp(v->name, "maxfiles")) {
02512          set_ulimit(atoi(v->value));
02513       /* What user to run as */
02514       } else if (!strcasecmp(v->name, "runuser")) {
02515          ast_copy_string(ast_config_AST_RUN_USER, v->value, sizeof(ast_config_AST_RUN_USER));
02516       /* What group to run as */
02517       } else if (!strcasecmp(v->name, "rungroup")) {
02518          ast_copy_string(ast_config_AST_RUN_GROUP, v->value, sizeof(ast_config_AST_RUN_GROUP));
02519       } else if (!strcasecmp(v->name, "systemname")) {
02520          ast_copy_string(ast_config_AST_SYSTEM_NAME, v->value, sizeof(ast_config_AST_SYSTEM_NAME));
02521       } else if (!strcasecmp(v->name, "languageprefix")) {
02522          ast_language_is_prefix = ast_true(v->value);
02523       }
02524    }
02525    ast_config_destroy(cfg);
02526 }
02527 
02528 static void *monitor_sig_flags(void *unused)
02529 {
02530    for (;;) {
02531       struct pollfd p = { sig_alert_pipe[0], POLLIN, 0 };
02532       int a;
02533       poll(&p, 1, -1);
02534       if (sig_flags.need_reload) {
02535          sig_flags.need_reload = 0;
02536          ast_module_reload(NULL);
02537       }
02538       if (sig_flags.need_quit) {
02539          sig_flags.need_quit = 0;
02540          quit_handler(0, 0, 1, 0);
02541       }
02542       read(sig_alert_pipe[0], &a, sizeof(a));
02543    }
02544 
02545    return NULL;
02546 }
02547 
02548 int main(int argc, char *argv[])
02549 {
02550    int c;
02551    char filename[80] = "";
02552    char hostname[MAXHOSTNAMELEN] = "";
02553    char tmp[80];
02554    char * xarg = NULL;
02555    int x;
02556    FILE *f;
02557    sigset_t sigs;
02558    int num;
02559    int is_child_of_nonroot = 0;
02560    char *buf;
02561    char *runuser = NULL, *rungroup = NULL;
02562 
02563    /* Remember original args for restart */
02564    if (argc > sizeof(_argv) / sizeof(_argv[0]) - 1) {
02565       fprintf(stderr, "Truncating argument size to %d\n", (int)(sizeof(_argv) / sizeof(_argv[0])) - 1);
02566       argc = sizeof(_argv) / sizeof(_argv[0]) - 1;
02567    }
02568    for (x=0; x<argc; x++)
02569       _argv[x] = argv[x];
02570    _argv[x] = NULL;
02571 
02572    /* if the progname is rasterisk consider it a remote console */
02573    if (argv[0] && (strstr(argv[0], "rasterisk")) != NULL) {
02574       ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE);
02575    }
02576    if (gethostname(hostname, sizeof(hostname)-1))
02577       ast_copy_string(hostname, "<Unknown>", sizeof(hostname));
02578    ast_mainpid = getpid();
02579    ast_ulaw_init();
02580    ast_alaw_init();
02581    callerid_init();
02582    ast_builtins_init();
02583    ast_utils_init();
02584    tdd_init();
02585    /* When Asterisk restarts after it has dropped the root privileges,
02586     * it can't issue setuid(), setgid(), setgroups() or set_priority() 
02587     */
02588    if (getenv("ASTERISK_ALREADY_NONROOT"))
02589       is_child_of_nonroot=1;
02590    if (getenv("HOME")) 
02591       snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
02592    /* Check for options */
02593    while ((c = getopt(argc, argv, "mtThfFdvVqprRgciInx:U:G:C:L:M:")) != -1) {
02594       switch (c) {
02595 #if HAVE_WORKING_FORK
02596       case 'F':
02597          ast_set_flag(&ast_options, AST_OPT_FLAG_ALWAYS_FORK);
02598          break;
02599       case 'f':
02600          ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);
02601          break;
02602 #endif
02603       case 'd':
02604          option_debug++;
02605          ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);
02606          break;
02607       case 'c':
02608          ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_CONSOLE);
02609          break;
02610       case 'n':
02611          ast_set_flag(&ast_options, AST_OPT_FLAG_NO_COLOR);
02612          break;
02613       case 'r':
02614          ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE);
02615          break;
02616       case 'R':
02617          ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE | AST_OPT_FLAG_RECONNECT);
02618          break;
02619       case 'p':
02620          ast_set_flag(&ast_options, AST_OPT_FLAG_HIGH_PRIORITY);
02621          break;
02622       case 'v':
02623          option_verbose++;
02624          ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);
02625          break;
02626       case 'm':
02627          ast_set_flag(&ast_options, AST_OPT_FLAG_MUTE);
02628          break;
02629       case 'M':
02630          if ((sscanf(optarg, "%d", &option_maxcalls) != 1) || (option_maxcalls < 0))
02631             option_maxcalls = 0;
02632          break;
02633       case 'L':
02634          if ((sscanf(optarg, "%lf", &option_maxload) != 1) || (option_maxload < 0.0))
02635             option_maxload = 0.0;
02636          break;
02637       case 'q':
02638          ast_set_flag(&ast_options, AST_OPT_FLAG_QUIET);
02639          break;
02640       case 't':
02641          ast_set_flag(&ast_options, AST_OPT_FLAG_CACHE_RECORD_FILES);
02642          break;
02643       case 'T':
02644          ast_set_flag(&ast_options, AST_OPT_FLAG_TIMESTAMP);
02645          break;
02646       case 'x':
02647          ast_set_flag(&ast_options, AST_OPT_FLAG_EXEC);
02648          xarg = optarg;
02649          break;
02650       case 'C':
02651          ast_copy_string(ast_config_AST_CONFIG_FILE, optarg, sizeof(ast_config_AST_CONFIG_FILE));
02652          ast_set_flag(&ast_options, AST_OPT_FLAG_OVERRIDE_CONFIG);
02653          break;
02654       case 'I':
02655          ast_set_flag(&ast_options, AST_OPT_FLAG_INTERNAL_TIMING);
02656          break;
02657       case 'i':
02658          ast_set_flag(&ast_options, AST_OPT_FLAG_INIT_KEYS);
02659          break;
02660       case 'g':
02661          ast_set_flag(&ast_options, AST_OPT_FLAG_DUMP_CORE);
02662          break;
02663       case 'h':
02664          show_cli_help();
02665          exit(0);
02666       case 'V':
02667          show_version();
02668          exit(0);
02669       case 'U':
02670          runuser = optarg;
02671          break;
02672       case 'G':
02673          rungroup = optarg;
02674          break;
02675       case '?':
02676          exit(1);
02677       }
02678    }
02679 
02680    if (ast_opt_console || option_verbose || (ast_opt_remote && !ast_opt_exec)) {
02681       ast_register_verbose(console_verboser);
02682       WELCOME_MESSAGE;
02683    }
02684 
02685    if (ast_opt_console && !option_verbose) 
02686       ast_verbose("[ Booting...\n");
02687 
02688    if (ast_opt_always_fork && (ast_opt_remote || ast_opt_console)) {
02689       ast_log(LOG_WARNING, "'alwaysfork' is not compatible with console or remote console mode; ignored\n");
02690       ast_clear_flag(&ast_options, AST_OPT_FLAG_ALWAYS_FORK);
02691    }
02692 
02693    /* For remote connections, change the name of the remote connection.
02694     * We do this for the benefit of init scripts (which need to know if/when
02695     * the main asterisk process has died yet). */
02696    if (ast_opt_remote) {
02697       strcpy(argv[0], "rasterisk");
02698       for (x = 1; x < argc; x++) {
02699          argv[x] = argv[0] + 10;
02700       }
02701    }
02702 
02703    if (ast_opt_console && !option_verbose) 
02704       ast_verbose("[ Reading Master Configuration ]\n");
02705    ast_readconfig();
02706 
02707    if (ast_opt_dump_core) {
02708       struct rlimit l;
02709       memset(&l, 0, sizeof(l));
02710       l.rlim_cur = RLIM_INFINITY;
02711       l.rlim_max = RLIM_INFINITY;
02712       if (setrlimit(RLIMIT_CORE, &l)) {
02713          ast_log(LOG_WARNING, "Unable to disable core size resource limit: %s\n", strerror(errno));
02714       }
02715    }
02716 
02717    if ((!rungroup) && !ast_strlen_zero(ast_config_AST_RUN_GROUP))
02718       rungroup = ast_config_AST_RUN_GROUP;
02719    if ((!runuser) && !ast_strlen_zero(ast_config_AST_RUN_USER))
02720       runuser = ast_config_AST_RUN_USER;
02721 
02722 #ifndef __CYGWIN__
02723 
02724    if (!is_child_of_nonroot) 
02725       ast_set_priority(ast_opt_high_priority);
02726 
02727    if (!is_child_of_nonroot && rungroup) {
02728       struct group *gr;
02729       gr = getgrnam(rungroup);
02730       if (!gr) {
02731          ast_log(LOG_WARNING, "No such group '%s'!\n", rungroup);
02732          exit(1);
02733       }
02734       if (setgid(gr->gr_gid)) {
02735          ast_log(LOG_WARNING, "Unable to setgid to %d (%s)\n", (int)gr->gr_gid, rungroup);
02736          exit(1);
02737       }
02738       if (setgroups(0, NULL)) {
02739          ast_log(LOG_WARNING, "Unable to drop unneeded groups\n");
02740          exit(1);
02741       }
02742       if (option_verbose)
02743          ast_verbose("Running as group '%s'\n", rungroup);
02744    }
02745 
02746    if (!is_child_of_nonroot && runuser) {
02747       struct passwd *pw;
02748       pw = getpwnam(runuser);
02749       if (!pw) {
02750          ast_log(LOG_WARNING, "No such user '%s'!\n", runuser);
02751          exit(1);
02752       }
02753       if (!rungroup) {
02754          if (setgid(pw->pw_gid)) {
02755             ast_log(LOG_WARNING, "Unable to setgid to %d!\n", (int)pw->pw_gid);
02756             exit(1);
02757          }
02758          if (initgroups(pw->pw_name, pw->pw_gid)) {
02759             ast_log(LOG_WARNING, "Unable to init groups for '%s'\n", runuser);
02760             exit(1);
02761          }
02762       }
02763       if (setuid(pw->pw_uid)) {
02764          ast_log(LOG_WARNING, "Unable to setuid to %d (%s)\n", (int)pw->pw_uid, runuser);
02765          exit(1);
02766       }
02767       setenv("ASTERISK_ALREADY_NONROOT", "yes", 1);
02768       if (option_verbose)
02769          ast_verbose("Running as user '%s'\n", runuser);
02770    }
02771 
02772 #endif /* __CYGWIN__ */
02773 
02774 #ifdef linux
02775    if (geteuid() && ast_opt_dump_core) {
02776       if (prctl(PR_SET_DUMPABLE, 1, 0, 0, 0) < 0) {
02777          ast_log(LOG_WARNING, "Unable to set the process for core dumps after changing to a non-root user. %s\n", strerror(errno));
02778       }  
02779    }
02780 #endif
02781 
02782    ast_term_init();
02783    printf(term_end());
02784    fflush(stdout);
02785 
02786    if (ast_opt_console && !option_verbose) 
02787       ast_verbose("[ Initializing Custom Configuration Options ]\n");
02788    /* custom config setup */
02789    register_config_cli();
02790    read_config_maps();
02791    
02792    if (ast_opt_console) {
02793       if (el_hist == NULL || el == NULL)
02794          ast_el_initialize();
02795 
02796       if (!ast_strlen_zero(filename))
02797          ast_el_read_history(filename);
02798    }
02799 
02800    if (ast_tryconnect()) {
02801       /* One is already running */
02802       if (ast_opt_remote) {
02803          if (ast_opt_exec) {
02804             ast_remotecontrol(xarg);
02805             quit_handler(0, 0, 0, 0);
02806             exit(0);
02807          }
02808          printf(term_quit());
02809          ast_remotecontrol(NULL);
02810          quit_handler(0, 0, 0, 0);
02811          exit(0);
02812       } else {
02813          ast_log(LOG_ERROR, "Asterisk already running on %s.  Use 'asterisk -r' to connect.\n", ast_config_AST_SOCKET);
02814          printf(term_quit());
02815          exit(1);
02816       }
02817    } else if (ast_opt_remote || ast_opt_exec) {
02818       ast_log(LOG_ERROR, "Unable to connect to remote asterisk (does %s exist?)\n", ast_config_AST_SOCKET);
02819       printf(term_quit());
02820       exit(1);
02821    }
02822    /* Blindly write pid file since we couldn't connect */
02823    unlink(ast_config_AST_PID);
02824    f = fopen(ast_config_AST_PID, "w");
02825    if (f) {
02826       fprintf(f, "%ld\n", (long)getpid());
02827       fclose(f);
02828    } else
02829       ast_log(LOG_WARNING, "Unable to open pid file '%s': %s\n", ast_config_AST_PID, strerror(errno));
02830 
02831 #if HAVE_WORKING_FORK
02832    if (ast_opt_always_fork || !ast_opt_no_fork) {
02833       daemon(0, 0);
02834       ast_mainpid = getpid();
02835       /* Blindly re-write pid file since we are forking */
02836       unlink(ast_config_AST_PID);
02837       f = fopen(ast_config_AST_PID, "w");
02838       if (f) {
02839          fprintf(f, "%ld\n", (long)ast_mainpid);
02840          fclose(f);
02841       } else
02842          ast_log(LOG_WARNING, "Unable to open pid file '%s': %s\n", ast_config_AST_PID, strerror(errno));
02843    }
02844 #endif
02845 
02846    /* Test recursive mutex locking. */
02847    if (test_for_thread_safety())
02848       ast_verbose("Warning! Asterisk is not thread safe.\n");
02849 
02850    ast_makesocket();
02851    sigemptyset(&sigs);
02852    sigaddset(&sigs, SIGHUP);
02853    sigaddset(&sigs, SIGTERM);
02854    sigaddset(&sigs, SIGINT);
02855    sigaddset(&sigs, SIGPIPE);
02856    sigaddset(&sigs, SIGWINCH);
02857    pthread_sigmask(SIG_BLOCK, &sigs, NULL);
02858    signal(SIGURG, urg_handler);
02859    signal(SIGINT, __quit_handler);
02860    signal(SIGTERM, __quit_handler);
02861    signal(SIGHUP, hup_handler);
02862    signal(SIGCHLD, child_handler);
02863    signal(SIGPIPE, SIG_IGN);
02864 
02865    /* ensure that the random number generators are seeded with a different value every time
02866       Asterisk is started
02867    */
02868    srand((unsigned int) getpid() + (unsigned int) time(NULL));
02869    initstate((unsigned int) getpid() * 65536 + (unsigned int) time(NULL), randompool, sizeof(randompool));
02870 
02871    if (init_logger()) {
02872       printf(term_quit());
02873       exit(1);
02874    }
02875 
02876    threadstorage_init();
02877 
02878    if (load_modules(1)) {
02879       printf(term_quit());
02880       exit(1);
02881    }
02882 
02883    if (dnsmgr_init()) {
02884       printf(term_quit());
02885       exit(1);
02886    }
02887 
02888    ast_http_init();
02889 
02890    ast_channels_init();
02891 
02892    if (init_manager()) {
02893       printf(term_quit());
02894       exit(1);
02895    }
02896 
02897    if (ast_cdr_engine_init()) {
02898       printf(term_quit());
02899       exit(1);
02900    }
02901 
02902    if (ast_device_state_engine_init()) {
02903       printf(term_quit());
02904       exit(1);
02905    }
02906 
02907    ast_rtp_init();
02908 
02909    ast_udptl_init();
02910 
02911    if (ast_image_init()) {
02912       printf(term_quit());
02913       exit(1);
02914    }
02915 
02916    if (ast_file_init()) {
02917       printf(term_quit());
02918       exit(1);
02919    }
02920 
02921    if (load_pbx()) {
02922       printf(term_quit());
02923       exit(1);
02924    }
02925 
02926    if (init_framer()) {
02927       printf(term_quit());
02928       exit(1);
02929    }
02930 
02931    if (astdb_init()) {
02932       printf(term_quit());
02933       exit(1);
02934    }
02935 
02936    if (ast_enum_init()) {
02937       printf(term_quit());
02938       exit(1);
02939    }
02940 
02941    if (load_modules(0)) {
02942       printf(term_quit());
02943       exit(1);
02944    }
02945 
02946    dnsmgr_start_refresh();
02947 
02948    /* We might have the option of showing a console, but for now just
02949       do nothing... */
02950    if (ast_opt_console && !option_verbose)
02951       ast_verbose(" ]\n");
02952    if (option_verbose || ast_opt_console)
02953       ast_verbose(term_color(tmp, "Asterisk Ready.\n", COLOR_BRWHITE, COLOR_BLACK, sizeof(tmp)));
02954    if (ast_opt_no_fork)
02955       consolethread = pthread_self();
02956 
02957    if (pipe(sig_alert_pipe))
02958       sig_alert_pipe[0] = sig_alert_pipe[1] = -1;
02959 
02960    ast_set_flag(&ast_options, AST_OPT_FLAG_FULLY_BOOTED);
02961    pthread_sigmask(SIG_UNBLOCK, &sigs, NULL);
02962 
02963 #ifdef __AST_DEBUG_MALLOC
02964    __ast_mm_init();
02965 #endif   
02966 
02967    time(&ast_startuptime);
02968    ast_cli_register_multiple(cli_asterisk, sizeof(cli_asterisk) / sizeof(struct ast_cli_entry));
02969 
02970    if (ast_opt_console) {
02971       /* Console stuff now... */
02972       /* Register our quit function */
02973       char title[256];
02974       pthread_attr_t attr;
02975       pthread_t dont_care;
02976 
02977       pthread_attr_init(&attr);
02978       pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
02979       ast_pthread_create(&dont_care, &attr, monitor_sig_flags, NULL);
02980       pthread_attr_destroy(&attr);
02981 
02982       set_icon("Asterisk");
02983       snprintf(title, sizeof(title), "Asterisk Console on '%s' (pid %ld)", hostname, (long)ast_mainpid);
02984       set_title(title);
02985 
02986       for (;;) {
02987          buf = (char *)el_gets(el, &num);
02988 
02989          if (!buf && write(1, "", 1) < 0)
02990             goto lostterm;
02991 
02992          if (buf) {
02993             if (buf[strlen(buf)-1] == '\n')
02994                buf[strlen(buf)-1] = '\0';
02995 
02996             consolehandler((char *)buf);
02997          } else if (ast_opt_remote && (write(STDOUT_FILENO, "\nUse EXIT or QUIT to exit the asterisk console\n",
02998                strlen("\nUse EXIT or QUIT to exit the asterisk console\n")) < 0)) {
02999             /* Whoa, stdout disappeared from under us... Make /dev/null's */
03000             int fd;
03001             fd = open("/dev/null", O_RDWR);
03002             if (fd > -1) {
03003                dup2(fd, STDOUT_FILENO);
03004                dup2(fd, STDIN_FILENO);
03005             } else
03006                ast_log(LOG_WARNING, "Failed to open /dev/null to recover from dead console. Bad things will happen!\n");
03007             break;
03008          }
03009       }
03010    }
03011 
03012    monitor_sig_flags(NULL);
03013 
03014 lostterm:
03015    return 0;
03016 }

Generated on Fri Aug 24 02:22:12 2007 for Asterisk - the Open Source PBX by  doxygen 1.5.1