Thu Oct 8 21:55:55 2009

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

Generated on Thu Oct 8 21:55:55 2009 for Asterisk - the Open Source PBX by  doxygen 1.5.6