Mon Mar 31 07:37:56 2008

Asterisk developer's documentation


asterisk.c

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

Generated on Mon Mar 31 07:37:57 2008 for Asterisk - the Open Source PBX by  doxygen 1.5.1