Fri May 26 01:45:29 2006

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

Generated on Fri May 26 01:45:29 2006 for Asterisk - the Open Source PBX by  doxygen 1.4.6