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 ==