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

Generated on Mon May 14 04:42:54 2007 for Asterisk - the Open Source PBX by  doxygen 1.5.1