Sat Nov 1 06:28:23 2008

Asterisk developer's documentation


asterisk.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 1999 - 2008, Digium, Inc.
00005  *
00006  * Mark Spencer <markster@digium.com>
00007  *
00008  * See http://www.asterisk.org for more information about
00009  * the Asterisk project. Please do not directly contact
00010  * any of the maintainers of this project for assistance;
00011  * the project provides a web site, mailing lists and IRC
00012  * channels for your use.
00013  *
00014  * This program is free software, distributed under the terms of
00015  * the GNU General Public License Version 2. See the LICENSE file
00016  * at the top of the source tree.
00017  */
00018 
00019 
00020 /* Doxygenified Copyright Header */
00021 /*!
00022  * \mainpage Asterisk -- An Open Source Telephony Toolkit
00023  *
00024  * \par Developer Documentation for Asterisk
00025  * This is the main developer documentation for Asterisk. It is 
00026  * generated by running "make progdocs".
00027  * \par Additional documentation
00028  * \arg \ref Licensing
00029  * \arg \ref DevDoc 
00030  * \arg \ref ConfigFiles
00031  *
00032  * \section copyright Copyright and author
00033  *
00034  * Copyright (C) 1999 - 2008, Digium, Inc.
00035  * Asterisk is a trademark registered by Digium, Inc.
00036  *
00037  * \author Mark Spencer <markster@digium.com>
00038  * Also see \ref AstCREDITS
00039  *
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 
00047 /*! \file
00048   \brief Top level source file for Asterisk  - the Open Source PBX. Implementation
00049   of PBX core functions and CLI interface.
00050   
00051  */
00052 
00053 #include "asterisk.h"
00054 
00055 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 151905 $")
00056 
00057 #undef sched_setscheduler
00058 #undef setpriority
00059 #include <unistd.h>
00060 #include <stdlib.h>
00061 #include <sys/time.h>
00062 #include <fcntl.h>
00063 #include <stdio.h>
00064 #include <signal.h>
00065 #include <sched.h>
00066 #include <sys/socket.h>
00067 #include <sys/un.h>
00068 #include <sys/wait.h>
00069 #include <string.h>
00070 #include <errno.h>
00071 #include <ctype.h>
00072 #include <sys/resource.h>
00073 #include <grp.h>
00074 #include <pwd.h>
00075 #include <sys/stat.h>
00076 
00077 #if defined(HAVE_ZAPTEL) || defined (HAVE_DAHDI)
00078 #include <sys/ioctl.h>
00079 #include "asterisk/dahdi_compat.h"
00080 #endif
00081 
00082 #ifdef linux
00083 #include <sys/prctl.h>
00084 #ifdef HAVE_CAP
00085 #include <sys/capability.h>
00086 #endif /* HAVE_CAP */
00087 #endif /* linux */
00088 #include <regex.h>
00089 
00090 #if  defined(__FreeBSD__) || defined( __NetBSD__ ) || defined(SOLARIS)
00091 #include <netdb.h>
00092 #if defined(SOLARIS)
00093 int daemon(int, int);  /* defined in libresolv of all places */
00094 #endif
00095 #endif
00096 
00097 #include "asterisk/logger.h"
00098 #include "asterisk/options.h"
00099 #include "asterisk/cli.h"
00100 #include "asterisk/channel.h"
00101 #include "asterisk/ulaw.h"
00102 #include "asterisk/alaw.h"
00103 #include "asterisk/callerid.h"
00104 #include "asterisk/image.h"
00105 #include "asterisk/tdd.h"
00106 #include "asterisk/term.h"
00107 #include "asterisk/manager.h"
00108 #include "asterisk/cdr.h"
00109 #include "asterisk/pbx.h"
00110 #include "asterisk/enum.h"
00111 #include "asterisk/rtp.h"
00112 #include "asterisk/http.h"
00113 #include "asterisk/udptl.h"
00114 #include "asterisk/app.h"
00115 #include "asterisk/lock.h"
00116 #include "asterisk/utils.h"
00117 #include "asterisk/file.h"
00118 #include "asterisk/io.h"
00119 #include "asterisk/lock.h"
00120 #include "editline/histedit.h"
00121 #include "asterisk/config.h"
00122 #include "asterisk/version.h"
00123 #include "asterisk/linkedlists.h"
00124 #include "asterisk/devicestate.h"
00125 #include "asterisk/module.h"
00126 
00127 #include "asterisk/doxyref.h"    /* Doxygen documentation */
00128 
00129 #include "../defaults.h"
00130 
00131 #ifndef AF_LOCAL
00132 #define AF_LOCAL AF_UNIX
00133 #define PF_LOCAL PF_UNIX
00134 #endif
00135 
00136 #define AST_MAX_CONNECTS 128
00137 #define NUM_MSGS 64
00138 
00139 /*! \brief Welcome message when starting a CLI interface */
00140 #define WELCOME_MESSAGE \
00141    ast_verbose("Asterisk " ASTERISK_VERSION ", Copyright (C) 1999 - 2008 Digium, Inc. and others.\n"); \
00142    ast_verbose("Created by Mark Spencer <markster@digium.com>\n"); \
00143    ast_verbose("Asterisk comes with ABSOLUTELY NO WARRANTY; type 'core show warranty' for details.\n"); \
00144    ast_verbose("This is free software, with components licensed under the GNU General Public\n"); \
00145    ast_verbose("License version 2 and other licenses; you are welcome to redistribute it under\n"); \
00146    ast_verbose("certain conditions. Type 'core show license' for details.\n"); \
00147    ast_verbose("=========================================================================\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 #ifdef HAVE_ZAPTEL
00169 static char _dahdi_chan_name[AST_CHANNEL_NAME] = "Zap";
00170 static size_t _dahdi_chan_name_len = 3;
00171 static enum dahdi_chan_modes _dahdi_chan_mode = CHAN_ZAP_MODE;
00172 #else
00173 static char _dahdi_chan_name[AST_CHANNEL_NAME] = "DAHDI";
00174 static size_t _dahdi_chan_name_len = 5;
00175 static enum dahdi_chan_modes _dahdi_chan_mode = CHAN_DAHDI_PLUS_ZAP_MODE;
00176 #endif
00177 const char *dahdi_chan_name;
00178 const size_t *dahdi_chan_name_len;
00179 const enum dahdi_chan_modes *dahdi_chan_mode;
00180 
00181 static int ast_socket = -1;      /*!< UNIX Socket for allowing remote control */
00182 static int ast_consock = -1;     /*!< UNIX Socket for controlling another asterisk */
00183 pid_t ast_mainpid;
00184 struct console {
00185    int fd;           /*!< File descriptor */
00186    int p[2];         /*!< Pipe */
00187    pthread_t t;         /*!< Thread of handler */
00188    int mute;         /*!< Is the console muted for logs */
00189 };
00190 
00191 struct ast_atexit {
00192    void (*func)(void);
00193    AST_LIST_ENTRY(ast_atexit) list;
00194 };
00195 
00196 static AST_LIST_HEAD_STATIC(atexits, ast_atexit);
00197 
00198 time_t ast_startuptime;
00199 time_t ast_lastreloadtime;
00200 
00201 static History *el_hist;
00202 static EditLine *el;
00203 static char *remotehostname;
00204 
00205 struct console consoles[AST_MAX_CONNECTS];
00206 
00207 char defaultlanguage[MAX_LANGUAGE] = DEFAULT_LANGUAGE;
00208 
00209 static int ast_el_add_history(char *);
00210 static int ast_el_read_history(char *);
00211 static int ast_el_write_history(char *);
00212 
00213 char ast_config_AST_CONFIG_DIR[PATH_MAX];
00214 char ast_config_AST_CONFIG_FILE[PATH_MAX];
00215 char ast_config_AST_MODULE_DIR[PATH_MAX];
00216 char ast_config_AST_SPOOL_DIR[PATH_MAX];
00217 char ast_config_AST_MONITOR_DIR[PATH_MAX];
00218 char ast_config_AST_VAR_DIR[PATH_MAX];
00219 char ast_config_AST_DATA_DIR[PATH_MAX];
00220 char ast_config_AST_LOG_DIR[PATH_MAX];
00221 char ast_config_AST_AGI_DIR[PATH_MAX];
00222 char ast_config_AST_DB[PATH_MAX];
00223 char ast_config_AST_KEY_DIR[PATH_MAX];
00224 char ast_config_AST_PID[PATH_MAX];
00225 char ast_config_AST_SOCKET[PATH_MAX];
00226 char ast_config_AST_RUN_DIR[PATH_MAX];
00227 char ast_config_AST_RUN_USER[PATH_MAX];
00228 char ast_config_AST_RUN_GROUP[PATH_MAX];
00229 char ast_config_AST_CTL_PERMISSIONS[PATH_MAX];
00230 char ast_config_AST_CTL_OWNER[PATH_MAX] = "\0";
00231 char ast_config_AST_CTL_GROUP[PATH_MAX] = "\0";
00232 char ast_config_AST_CTL[PATH_MAX] = "asterisk.ctl";
00233 char ast_config_AST_SYSTEM_NAME[20] = "";
00234 
00235 extern const char *ast_build_hostname;
00236 extern const char *ast_build_kernel;
00237 extern const char *ast_build_machine;
00238 extern const char *ast_build_os;
00239 extern const char *ast_build_date;
00240 extern const char *ast_build_user;
00241 
00242 static char *_argv[256];
00243 static int shuttingdown;
00244 static int restartnow;
00245 static pthread_t consolethread = AST_PTHREADT_NULL;
00246 
00247 static char randompool[256];
00248 
00249 static int sig_alert_pipe[2] = { -1, -1 };
00250 static struct {
00251     unsigned int need_reload:1;
00252     unsigned int need_quit:1;
00253 } sig_flags;
00254 
00255 #if !defined(LOW_MEMORY)
00256 struct file_version {
00257    AST_LIST_ENTRY(file_version) list;
00258    const char *file;
00259    char *version;
00260 };
00261 
00262 static AST_LIST_HEAD_STATIC(file_versions, file_version);
00263 
00264 void ast_register_file_version(const char *file, const char *version)
00265 {
00266    struct file_version *new;
00267    char *work;
00268    size_t version_length;
00269 
00270    work = ast_strdupa(version);
00271    work = ast_strip(ast_strip_quoted(work, "$", "$"));
00272    version_length = strlen(work) + 1;
00273    
00274    if (!(new = ast_calloc(1, sizeof(*new) + version_length)))
00275       return;
00276 
00277    new->file = file;
00278    new->version = (char *) new + sizeof(*new);
00279    memcpy(new->version, work, version_length);
00280    AST_LIST_LOCK(&file_versions);
00281    AST_LIST_INSERT_HEAD(&file_versions, new, list);
00282    AST_LIST_UNLOCK(&file_versions);
00283 }
00284 
00285 void ast_unregister_file_version(const char *file)
00286 {
00287    struct file_version *find;
00288 
00289    AST_LIST_LOCK(&file_versions);
00290    AST_LIST_TRAVERSE_SAFE_BEGIN(&file_versions, find, list) {
00291       if (!strcasecmp(find->file, file)) {
00292          AST_LIST_REMOVE_CURRENT(&file_versions, list);
00293          break;
00294       }
00295    }
00296    AST_LIST_TRAVERSE_SAFE_END;
00297    AST_LIST_UNLOCK(&file_versions);
00298    if (find)
00299       free(find);
00300 }
00301 
00302 struct thread_list_t {
00303    AST_LIST_ENTRY(thread_list_t) list;
00304    char *name;
00305    pthread_t id;
00306 };
00307 
00308 static AST_LIST_HEAD_STATIC(thread_list, thread_list_t);
00309 
00310 static char show_threads_help[] =
00311 "Usage: core show threads\n"
00312 "       List threads currently active in the system.\n";
00313 
00314 void ast_register_thread(char *name)
00315 { 
00316    struct thread_list_t *new = ast_calloc(1, sizeof(*new));
00317 
00318    if (!new)
00319       return;
00320    new->id = pthread_self();
00321    new->name = name; /* steal the allocated memory for the thread name */
00322    AST_LIST_LOCK(&thread_list);
00323    AST_LIST_INSERT_HEAD(&thread_list, new, list);
00324    AST_LIST_UNLOCK(&thread_list);
00325 }
00326 
00327 void ast_unregister_thread(void *id)
00328 {
00329    struct thread_list_t *x;
00330 
00331    AST_LIST_LOCK(&thread_list);
00332    AST_LIST_TRAVERSE_SAFE_BEGIN(&thread_list, x, list) {
00333       if ((void *) x->id == id) {
00334          AST_LIST_REMOVE_CURRENT(&thread_list, list);
00335          break;
00336       }
00337    }
00338    AST_LIST_TRAVERSE_SAFE_END;
00339    AST_LIST_UNLOCK(&thread_list);
00340    if (x) {
00341       free(x->name);
00342       free(x);
00343    }
00344 }
00345 
00346 static int handle_show_threads(int fd, int argc, char *argv[])
00347 {
00348    int count = 0;
00349    struct thread_list_t *cur;
00350 
00351    AST_LIST_LOCK(&thread_list);
00352    AST_LIST_TRAVERSE(&thread_list, cur, list) {
00353       ast_cli(fd, "%p %s\n", (void *)cur->id, cur->name);
00354       count++;
00355    }
00356         AST_LIST_UNLOCK(&thread_list);
00357    ast_cli(fd, "%d threads listed.\n", count);
00358    return 0;
00359 }
00360 
00361 struct profile_entry {
00362    const char *name;
00363    uint64_t scale;   /* if non-zero, values are scaled by this */
00364    int64_t  mark;
00365    int64_t  value;
00366    int64_t  events;
00367 };
00368 
00369 struct profile_data {
00370    int entries;
00371    int max_size;
00372    struct profile_entry e[0];
00373 };
00374 
00375 static struct profile_data *prof_data;
00376 
00377 /*! \brief allocates a counter with a given name and scale.
00378  * \return Returns the identifier of the counter.
00379  */
00380 int ast_add_profile(const char *name, uint64_t scale)
00381 {
00382    int l = sizeof(struct profile_data);
00383    int n = 10; /* default entries */
00384 
00385    if (prof_data == NULL) {
00386       prof_data = ast_calloc(1, l + n*sizeof(struct profile_entry));
00387       if (prof_data == NULL)
00388          return -1;
00389       prof_data->entries = 0;
00390       prof_data->max_size = n;
00391    }
00392    if (prof_data->entries >= prof_data->max_size) {
00393       void *p;
00394       n = prof_data->max_size + 20;
00395       p = ast_realloc(prof_data, l + n*sizeof(struct profile_entry));
00396       if (p == NULL)
00397          return -1;
00398       prof_data = p;
00399       prof_data->max_size = n;
00400    }
00401    n = prof_data->entries++;
00402    prof_data->e[n].name = ast_strdup(name);
00403    prof_data->e[n].value = 0;
00404    prof_data->e[n].events = 0;
00405    prof_data->e[n].mark = 0;
00406    prof_data->e[n].scale = scale;
00407    return n;
00408 }
00409 
00410 int64_t ast_profile(int i, int64_t delta)
00411 {
00412    if (!prof_data || i < 0 || i > prof_data->entries) /* invalid index */
00413       return 0;
00414    if (prof_data->e[i].scale > 1)
00415       delta /= prof_data->e[i].scale;
00416    prof_data->e[i].value += delta;
00417    prof_data->e[i].events++;
00418    return prof_data->e[i].value;
00419 }
00420 
00421 /* The RDTSC instruction was introduced on the Pentium processor and is not
00422  * implemented on certain clones, like the Cyrix 586. Hence, the previous
00423  * expectation of __i386__ was in error. */
00424 #if defined ( __i686__) && (defined(__FreeBSD__) || defined(linux))
00425 #if defined(__FreeBSD__)
00426 #include <machine/cpufunc.h>
00427 #elif defined(linux)
00428 static __inline uint64_t
00429 rdtsc(void)
00430 { 
00431    uint64_t rv;
00432 
00433    __asm __volatile(".byte 0x0f, 0x31" : "=A" (rv));
00434    return (rv);
00435 }
00436 #endif
00437 #else /* supply a dummy function on other platforms */
00438 static __inline uint64_t
00439 rdtsc(void)
00440 {
00441    return 0;
00442 }
00443 #endif
00444 
00445 int64_t ast_mark(int i, int startstop)
00446 {
00447    if (!prof_data || i < 0 || i > prof_data->entries) /* invalid index */
00448       return 0;
00449    if (startstop == 1)
00450       prof_data->e[i].mark = rdtsc();
00451    else {
00452       prof_data->e[i].mark = (rdtsc() - prof_data->e[i].mark);
00453       if (prof_data->e[i].scale > 1)
00454          prof_data->e[i].mark /= prof_data->e[i].scale;
00455       prof_data->e[i].value += prof_data->e[i].mark;
00456       prof_data->e[i].events++;
00457    }
00458    return prof_data->e[i].mark;
00459 }
00460 
00461 static int handle_show_profile_deprecated(int fd, int argc, char *argv[])
00462 {
00463    int i, min, max;
00464    char *search = NULL;
00465 
00466    if (prof_data == NULL)
00467       return 0;
00468 
00469    min = 0;
00470    max = prof_data->entries;
00471    if  (argc >= 3) { /* specific entries */
00472       if (isdigit(argv[2][0])) {
00473          min = atoi(argv[2]);
00474          if (argc == 4 && strcmp(argv[3], "-"))
00475             max = atoi(argv[3]);
00476       } else
00477          search = argv[2];
00478    }
00479    if (max > prof_data->entries)
00480       max = prof_data->entries;
00481    if (!strcmp(argv[0], "clear")) {
00482       for (i= min; i < max; i++) {
00483          if (!search || strstr(prof_data->e[i].name, search)) {
00484             prof_data->e[i].value = 0;
00485             prof_data->e[i].events = 0;
00486          }
00487       }
00488       return 0;
00489    }
00490    ast_cli(fd, "profile values (%d, allocated %d)\n-------------------\n",
00491       prof_data->entries, prof_data->max_size);
00492    ast_cli(fd, "%6s   %8s  %10s %12s %12s  %s\n", "ID", "Scale", "Events",
00493          "Value", "Average", "Name");
00494    for (i = min; i < max; i++) {
00495       struct profile_entry *e = &prof_data->e[i];
00496       if (!search || strstr(prof_data->e[i].name, search))
00497           ast_cli(fd, "%6d: [%8ld] %10ld %12lld %12lld  %s\n",
00498          i,
00499          (long)e->scale,
00500          (long)e->events, (long long)e->value,
00501          (long long)(e->events ? e->value / e->events : e->value),
00502          e->name);
00503    }
00504    return 0;
00505 }
00506 
00507 static int handle_show_profile(int fd, int argc, char *argv[])
00508 {
00509    int i, min, max;
00510    char *search = NULL;
00511 
00512    if (prof_data == NULL)
00513       return 0;
00514 
00515    min = 0;
00516    max = prof_data->entries;
00517    if  (argc > 3) { /* specific entries */
00518       if (isdigit(argv[3][0])) {
00519          min = atoi(argv[3]);
00520          if (argc == 5 && strcmp(argv[4], "-"))
00521             max = atoi(argv[4]);
00522       } else
00523          search = argv[3];
00524    }
00525    if (max > prof_data->entries)
00526       max = prof_data->entries;
00527    if (!strcmp(argv[1], "clear")) {
00528       for (i= min; i < max; i++) {
00529          if (!search || strstr(prof_data->e[i].name, search)) {
00530             prof_data->e[i].value = 0;
00531             prof_data->e[i].events = 0;
00532          }
00533       }
00534       return 0;
00535    }
00536    ast_cli(fd, "profile values (%d, allocated %d)\n-------------------\n",
00537       prof_data->entries, prof_data->max_size);
00538    ast_cli(fd, "%6s   %8s  %10s %12s %12s  %s\n", "ID", "Scale", "Events",
00539          "Value", "Average", "Name");
00540    for (i = min; i < max; i++) {
00541       struct profile_entry *e = &prof_data->e[i];
00542       if (!search || strstr(prof_data->e[i].name, search))
00543           ast_cli(fd, "%6d: [%8ld] %10ld %12lld %12lld  %s\n",
00544          i,
00545          (long)e->scale,
00546          (long)e->events, (long long)e->value,
00547          (long long)(e->events ? e->value / e->events : e->value),
00548          e->name);
00549    }
00550    return 0;
00551 }
00552 
00553 static char show_version_files_help[] = 
00554 "Usage: core show file version [like <pattern>]\n"
00555 "       Lists the revision numbers of the files used to build this copy of Asterisk.\n"
00556 "       Optional regular expression pattern is used to filter the file list.\n";
00557 
00558 /*! \brief CLI command to list module versions */
00559 static int handle_show_version_files_deprecated(int fd, int argc, char *argv[])
00560 {
00561 #define FORMAT "%-25.25s %-40.40s\n"
00562    struct file_version *iterator;
00563    regex_t regexbuf;
00564    int havepattern = 0;
00565    int havename = 0;
00566    int count_files = 0;
00567 
00568    switch (argc) {
00569    case 5:
00570       if (!strcasecmp(argv[3], "like")) {
00571          if (regcomp(&regexbuf, argv[4], REG_EXTENDED | REG_NOSUB))
00572             return RESULT_SHOWUSAGE;
00573          havepattern = 1;
00574       } else
00575          return RESULT_SHOWUSAGE;
00576       break;
00577    case 4:
00578       havename = 1;
00579       break;
00580    case 3:
00581       break;
00582    default:
00583       return RESULT_SHOWUSAGE;
00584    }
00585 
00586    ast_cli(fd, FORMAT, "File", "Revision");
00587    ast_cli(fd, FORMAT, "----", "--------");
00588    AST_LIST_LOCK(&file_versions);
00589    AST_LIST_TRAVERSE(&file_versions, iterator, list) {
00590       if (havename && strcasecmp(iterator->file, argv[3]))
00591          continue;
00592 
00593       if (havepattern && regexec(&regexbuf, iterator->file, 0, NULL, 0))
00594          continue;
00595 
00596       ast_cli(fd, FORMAT, iterator->file, iterator->version);
00597       count_files++;
00598       if (havename)
00599          break;
00600    }
00601    AST_LIST_UNLOCK(&file_versions);
00602    if (!havename) {
00603       ast_cli(fd, "%d files listed.\n", count_files);
00604    }
00605 
00606    if (havepattern)
00607       regfree(&regexbuf);
00608 
00609    return RESULT_SUCCESS;
00610 #undef FORMAT
00611 }
00612 
00613 static int handle_show_version_files(int fd, int argc, char *argv[])
00614 {
00615 #define FORMAT "%-25.25s %-40.40s\n"
00616    struct file_version *iterator;
00617    regex_t regexbuf;
00618    int havepattern = 0;
00619    int havename = 0;
00620    int count_files = 0;
00621 
00622    switch (argc) {
00623    case 6:
00624       if (!strcasecmp(argv[4], "like")) {
00625          if (regcomp(&regexbuf, argv[5], REG_EXTENDED | REG_NOSUB))
00626             return RESULT_SHOWUSAGE;
00627          havepattern = 1;
00628       } else
00629          return RESULT_SHOWUSAGE;
00630       break;
00631    case 5:
00632       havename = 1;
00633       break;
00634    case 4:
00635       break;
00636    default:
00637       return RESULT_SHOWUSAGE;
00638    }
00639 
00640    ast_cli(fd, FORMAT, "File", "Revision");
00641    ast_cli(fd, FORMAT, "----", "--------");
00642    AST_LIST_LOCK(&file_versions);
00643    AST_LIST_TRAVERSE(&file_versions, iterator, list) {
00644       if (havename && strcasecmp(iterator->file, argv[4]))
00645          continue;
00646       
00647       if (havepattern && regexec(&regexbuf, iterator->file, 0, NULL, 0))
00648          continue;
00649 
00650       ast_cli(fd, FORMAT, iterator->file, iterator->version);
00651       count_files++;
00652       if (havename)
00653          break;
00654    }
00655    AST_LIST_UNLOCK(&file_versions);
00656    if (!havename) {
00657       ast_cli(fd, "%d files listed.\n", count_files);
00658    }
00659 
00660    if (havepattern)
00661       regfree(&regexbuf);
00662 
00663    return RESULT_SUCCESS;
00664 #undef FORMAT
00665 }
00666 
00667 static char *complete_show_version_files_deprecated(const char *line, const char *word, int pos, int state)
00668 {
00669    struct file_version *find;
00670    int which = 0;
00671    char *ret = NULL;
00672    int matchlen = strlen(word);
00673 
00674    if (pos != 3)
00675       return NULL;
00676 
00677    AST_LIST_LOCK(&file_versions);
00678    AST_LIST_TRAVERSE(&file_versions, find, list) {
00679       if (!strncasecmp(word, find->file, matchlen) && ++which > state) {
00680          ret = ast_strdup(find->file);
00681          break;
00682       }
00683    }
00684    AST_LIST_UNLOCK(&file_versions);
00685 
00686    return ret;
00687 }
00688 
00689 static char *complete_show_version_files(const char *line, const char *word, int pos, int state)
00690 {
00691    struct file_version *find;
00692    int which = 0;
00693    char *ret = NULL;
00694    int matchlen = strlen(word);
00695    
00696    if (pos != 4)
00697       return NULL;
00698 
00699    AST_LIST_LOCK(&file_versions);
00700    AST_LIST_TRAVERSE(&file_versions, find, list) {
00701       if (!strncasecmp(word, find->file, matchlen) && ++which > state) {
00702          ret = ast_strdup(find->file);
00703          break;
00704       }
00705    }
00706    AST_LIST_UNLOCK(&file_versions);
00707 
00708    return ret;
00709 }
00710 
00711 #endif /* ! LOW_MEMORY */
00712 
00713 int ast_register_atexit(void (*func)(void))
00714 {
00715    struct ast_atexit *ae;
00716 
00717    if (!(ae = ast_calloc(1, sizeof(*ae))))
00718       return -1;
00719 
00720    ae->func = func;
00721 
00722    ast_unregister_atexit(func);  
00723 
00724    AST_LIST_LOCK(&atexits);
00725    AST_LIST_INSERT_HEAD(&atexits, ae, list);
00726    AST_LIST_UNLOCK(&atexits);
00727 
00728    return 0;
00729 }
00730 
00731 void ast_unregister_atexit(void (*func)(void))
00732 {
00733    struct ast_atexit *ae = NULL;
00734 
00735    AST_LIST_LOCK(&atexits);
00736    AST_LIST_TRAVERSE_SAFE_BEGIN(&atexits, ae, list) {
00737       if (ae->func == func) {
00738          AST_LIST_REMOVE_CURRENT(&atexits, list);
00739          break;
00740       }
00741    }
00742    AST_LIST_TRAVERSE_SAFE_END
00743    AST_LIST_UNLOCK(&atexits);
00744 
00745    if (ae)
00746       free(ae);
00747 }
00748 
00749 /* Sending commands from consoles back to the daemon requires a terminating NULL */
00750 static int fdsend(int fd, const char *s)
00751 {
00752    return write(fd, s, strlen(s) + 1);
00753 }
00754 
00755 /* Sending messages from the daemon back to the display requires _excluding_ the terminating NULL */
00756 static int fdprint(int fd, const char *s)
00757 {
00758    return write(fd, s, strlen(s));
00759 }
00760 
00761 /*! \brief NULL handler so we can collect the child exit status */
00762 static void null_sig_handler(int signal)
00763 {
00764 
00765 }
00766 
00767 AST_MUTEX_DEFINE_STATIC(safe_system_lock);
00768 /*! \brief Keep track of how many threads are currently trying to wait*() on
00769  *  a child process */
00770 static unsigned int safe_system_level = 0;
00771 static void *safe_system_prev_handler;
00772 
00773 void ast_replace_sigchld(void)
00774 {
00775    unsigned int level;
00776 
00777    ast_mutex_lock(&safe_system_lock);
00778    level = safe_system_level++;
00779 
00780    /* only replace the handler if it has not already been done */
00781    if (level == 0)
00782       safe_system_prev_handler = signal(SIGCHLD, null_sig_handler);
00783 
00784    ast_mutex_unlock(&safe_system_lock);
00785 }
00786 
00787 void ast_unreplace_sigchld(void)
00788 {
00789    unsigned int level;
00790 
00791    ast_mutex_lock(&safe_system_lock);
00792    level = --safe_system_level;
00793 
00794    /* only restore the handler if we are the last one */
00795    if (level == 0)
00796       signal(SIGCHLD, safe_system_prev_handler);
00797 
00798    ast_mutex_unlock(&safe_system_lock);
00799 }
00800 
00801 int ast_safe_system(const char *s)
00802 {
00803    pid_t pid;
00804 #ifdef HAVE_WORKING_FORK
00805    int x;
00806 #endif
00807    int res;
00808    struct rusage rusage;
00809    int status;
00810 
00811 #if defined(HAVE_WORKING_FORK) || defined(HAVE_WORKING_VFORK)
00812    ast_replace_sigchld();
00813 
00814 #ifdef HAVE_WORKING_FORK
00815    pid = fork();
00816 #else
00817    pid = vfork();
00818 #endif   
00819 
00820    if (pid == 0) {
00821 #ifdef HAVE_WORKING_FORK
00822       if (ast_opt_high_priority)
00823          ast_set_priority(0);
00824       /* Close file descriptors and launch system command */
00825       for (x = STDERR_FILENO + 1; x < 4096; x++)
00826          close(x);
00827 #endif
00828       execl("/bin/sh", "/bin/sh", "-c", s, (char *) NULL);
00829       _exit(1);
00830    } else if (pid > 0) {
00831       for(;;) {
00832          res = wait4(pid, &status, 0, &rusage);
00833          if (res > -1) {
00834             res = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
00835             break;
00836          } else if (errno != EINTR) 
00837             break;
00838       }
00839    } else {
00840       ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno));
00841       res = -1;
00842    }
00843 
00844    ast_unreplace_sigchld();
00845 #else
00846    res = -1;
00847 #endif
00848 
00849    return res;
00850 }
00851 
00852 /*!
00853  * \brief mute or unmute a console from logging
00854  */
00855 void ast_console_toggle_mute(int fd, int silent) {
00856    int x;
00857    for (x = 0;x < AST_MAX_CONNECTS; x++) {
00858       if (fd == consoles[x].fd) {
00859          if (consoles[x].mute) {
00860             consoles[x].mute = 0;
00861             if (!silent)
00862                ast_cli(fd, "Console is not muted anymore.\n");
00863          } else {
00864             consoles[x].mute = 1;
00865             if (!silent)
00866                ast_cli(fd, "Console is muted.\n");
00867          }
00868          return;
00869       }
00870    }
00871    ast_cli(fd, "Couldn't find remote console.\n");
00872 }
00873 
00874 /*!
00875  * \brief log the string to all attached console clients
00876  */
00877 static void ast_network_puts_mutable(const char *string)
00878 {
00879    int x;
00880    for (x = 0;x < AST_MAX_CONNECTS; x++) {
00881       if (consoles[x].mute)
00882          continue;
00883       if (consoles[x].fd > -1) 
00884          fdprint(consoles[x].p[1], string);
00885    }
00886 }
00887 
00888 /*!
00889  * \brief log the string to the console, and all attached
00890  * console clients
00891  */
00892 void ast_console_puts_mutable(const char *string)
00893 {
00894    fputs(string, stdout);
00895    fflush(stdout);
00896    ast_network_puts_mutable(string);
00897 }
00898 
00899 /*!
00900  * \brief write the string to all attached console clients
00901  */
00902 static void ast_network_puts(const char *string)
00903 {
00904    int x;
00905    for (x=0; x < AST_MAX_CONNECTS; x++) {
00906       if (consoles[x].fd > -1) 
00907          fdprint(consoles[x].p[1], string);
00908    }
00909 }
00910 
00911 /*!
00912  * write the string to the console, and all attached
00913  * console clients
00914  */
00915 void ast_console_puts(const char *string)
00916 {
00917    fputs(string, stdout);
00918    fflush(stdout);
00919    ast_network_puts(string);
00920 }
00921 
00922 static void network_verboser(const char *s)
00923 {
00924    ast_network_puts_mutable(s);
00925 }
00926 
00927 static pthread_t lthread;
00928 
00929 static void *netconsole(void *vconsole)
00930 {
00931    struct console *con = vconsole;
00932    char hostname[MAXHOSTNAMELEN] = "";
00933    char tmp[512];
00934    int res;
00935    struct pollfd fds[2];
00936    
00937    if (gethostname(hostname, sizeof(hostname)-1))
00938       ast_copy_string(hostname, "<Unknown>", sizeof(hostname));
00939    snprintf(tmp, sizeof(tmp), "%s/%ld/%s\n", hostname, (long)ast_mainpid, ASTERISK_VERSION);
00940    fdprint(con->fd, tmp);
00941    for(;;) {
00942       fds[0].fd = con->fd;
00943       fds[0].events = POLLIN;
00944       fds[0].revents = 0;
00945       fds[1].fd = con->p[0];
00946       fds[1].events = POLLIN;
00947       fds[1].revents = 0;
00948 
00949       res = poll(fds, 2, -1);
00950       if (res < 0) {
00951          if (errno != EINTR)
00952             ast_log(LOG_WARNING, "poll returned < 0: %s\n", strerror(errno));
00953          continue;
00954       }
00955       if (fds[0].revents) {
00956          res = read(con->fd, tmp, sizeof(tmp));
00957          if (res < 1) {
00958             break;
00959          }
00960          tmp[res] = 0;
00961          ast_cli_command_multiple(con->fd, res, tmp);
00962       }
00963       if (fds[1].revents) {
00964          res = read(con->p[0], tmp, sizeof(tmp));
00965          if (res < 1) {
00966             ast_log(LOG_ERROR, "read returned %d\n", res);
00967             break;
00968          }
00969          res = write(con->fd, tmp, res);
00970          if (res < 1)
00971             break;
00972       }
00973    }
00974    if (option_verbose > 2) 
00975       ast_verbose(VERBOSE_PREFIX_3 "Remote UNIX connection disconnected\n");
00976    close(con->fd);
00977    close(con->p[0]);
00978    close(con->p[1]);
00979    con->fd = -1;
00980    
00981    return NULL;
00982 }
00983 
00984 static void *listener(void *unused)
00985 {
00986    struct sockaddr_un sunaddr;
00987    int s;
00988    socklen_t len;
00989    int x;
00990    int flags;
00991    struct pollfd fds[1];