Codename Pineapple

Home page | Mailing list | Docs

Last updated: Sat Feb 3 05:00:32 2007

Asterisk developer's documentation :: Codename Pineapple


asterisk.c

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

Asterisk is a trademark for Digium, inc.. | Edvina.net | Asterisk.org | This documentation was generated with Doxygen