Asterisk.org: Developer Documentation (28 Oct 2009)

Wed Oct 28 15:47:49 2009

## Asterisk developer's documentation

- Main Page
- Related Pages
- Modules
- Data Structures
- Files
- Directories

# 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: 211526 $")
    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 - 2007 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_highpriority=0;    /*!< Run in realtime Linux priority */
    00159 int option_remote=0;       /*!< Remote CLI */
    00160 int option_exec=0;         /*!< */
    00161 int option_initcrypto=0;      /*!< Initialize crypto keys for RSA auth */
    00162 int option_nocolor;        /*!< Don't use termcap colors */
    00163 int option_dumpcore = 0;         /*!< Dump core when failing */
    00164 int option_cache_record_files = 0;     /*!< Cache sound files */
    00165 int option_timestamp = 0;        /*!< Timestamp in logging */
    00166 int option_overrideconfig = 0;         /*!< */
    00167 int option_reconnect = 0;        /*!< */
    00168 int option_transcode_slin = 1;         /*!< */
    00169 int option_maxcalls = 0;         /*!< */
    00170 double option_maxload = 0.0;        /*!< Max load avg on system */
    00171 int option_dontwarn = 0;         /*!< */
    00172 int option_priority_jumping = 1;    /*!< Enable priority jumping as result value for apps */
    00173 int option_transmit_silence_during_record = 0;  /*!< Transmit silence during record() app */
    00174
    00175 /*! @} */
    00176
    00177 int fully_booted = 0;
    00178 char record_cache_dir[AST_CACHE_DIR_LEN] = AST_TMP_DIR;
    00179 char debug_filename[AST_FILENAME_MAX] = "";
    00180
    00181 static int ast_socket = -1;      /*!< UNIX Socket for allowing remote control */
    00182 static int ast_consock = -1;     /*!< UNIX Socket for controlling another asterisk */
    00183 int ast_mainpid;
    00184 struct console {
    00185    int fd;           /*!< File descriptor */
    00186    int p[2];         /*!< Pipe */
    00187    pthread_t t;         /*!< Thread of handler */
    00188 };
    00189
    00190 static struct ast_atexit {
    00191    void (*func)(void);
    00192    struct ast_atexit *next;
    00193 } *atexits = NULL;
    00194
    00195 AST_MUTEX_DEFINE_STATIC(atexitslock);
    00196
    00197 time_t ast_startuptime;
    00198 time_t ast_lastreloadtime;
    00199
    00200 static History *el_hist = NULL;
    00201 static EditLine *el = NULL;
    00202 static char *remotehostname;
    00203
    00204 struct console consoles[AST_MAX_CONNECTS];
    00205
    00206 char defaultlanguage[MAX_LANGUAGE] = DEFAULT_LANGUAGE;
    00207
    00208 static int ast_el_add_history(char *);
    00209 static int ast_el_read_history(char *);
    00210 static int ast_el_write_history(char *);
    00211
    00212 char ast_config_AST_CONFIG_DIR[AST_CONFIG_MAX_PATH];
    00213 char ast_config_AST_CONFIG_FILE[AST_CONFIG_MAX_PATH];
    00214 char ast_config_AST_MODULE_DIR[AST_CONFIG_MAX_PATH];
    00215 char ast_config_AST_SPOOL_DIR[AST_CONFIG_MAX_PATH];
    00216 char ast_config_AST_MONITOR_DIR[AST_CONFIG_MAX_PATH];
    00217 char ast_config_AST_VAR_DIR[AST_CONFIG_MAX_PATH];
    00218 char ast_config_AST_LOG_DIR[AST_CONFIG_MAX_PATH];
    00219 char ast_config_AST_AGI_DIR[AST_CONFIG_MAX_PATH];
    00220 char ast_config_AST_DB[AST_CONFIG_MAX_PATH];
    00221 char ast_config_AST_KEY_DIR[AST_CONFIG_MAX_PATH];
    00222 char ast_config_AST_PID[AST_CONFIG_MAX_PATH];
    00223 char ast_config_AST_SOCKET[AST_CONFIG_MAX_PATH];
    00224 char ast_config_AST_RUN_DIR[AST_CONFIG_MAX_PATH];
    00225 char ast_config_AST_RUN_USER[AST_CONFIG_MAX_PATH];
    00226 char ast_config_AST_RUN_GROUP[AST_CONFIG_MAX_PATH];
    00227 char ast_config_AST_CTL_PERMISSIONS[AST_CONFIG_MAX_PATH];
    00228 char ast_config_AST_CTL_OWNER[AST_CONFIG_MAX_PATH] = "\0";
    00229 char ast_config_AST_CTL_GROUP[AST_CONFIG_MAX_PATH] = "\0";
    00230 char ast_config_AST_CTL[AST_CONFIG_MAX_PATH] = "asterisk.ctl";
    00231
    00232 static char *_argv[256];
    00233 static int shuttingdown = 0;
    00234 static int restartnow = 0;
    00235 static pthread_t consolethread = AST_PTHREADT_NULL;
    00236
    00237 static int sig_alert_pipe[2] = { -1, -1 };
    00238 static struct {
    00239     unsigned int need_reload:1;
    00240     unsigned int need_quit:1;
    00241 } sig_flags;
    00242
    00243 #if !defined(LOW_MEMORY)
    00244 struct file_version {
    00245    AST_LIST_ENTRY(file_version) list;
    00246    const char *file;
    00247    char *version;
    00248 };
    00249
    00250 static AST_LIST_HEAD_STATIC(file_versions, file_version);
    00251
    00252 void ast_register_file_version(const char *file, const char *version)
    00253 {
    00254    struct file_version *new;
    00255    char *work;
    00256    size_t version_length;
    00257
    00258    work = ast_strdupa(version);
    00259    work = ast_strip(ast_strip_quoted(work, "$", "$"));
    00260    version_length = strlen(work) + 1;
    00261
    00262    new = calloc(1, sizeof(*new) + version_length);
    00263    if (!new)
    00264       return;
    00265
    00266    new->file = file;
    00267    new->version = (char *) new + sizeof(*new);
    00268    memcpy(new->version, work, version_length);
    00269    AST_LIST_LOCK(&file_versions);
    00270    AST_LIST_INSERT_HEAD(&file_versions, new, list);
    00271    AST_LIST_UNLOCK(&file_versions);
    00272 }
    00273
    00274 void ast_unregister_file_version(const char *file)
    00275 {
    00276    struct file_version *find;
    00277
    00278    AST_LIST_LOCK(&file_versions);
    00279    AST_LIST_TRAVERSE_SAFE_BEGIN(&file_versions, find, list) {
    00280       if (!strcasecmp(find->file, file)) {
    00281          AST_LIST_REMOVE_CURRENT(&file_versions, list);
    00282          break;
    00283       }
    00284    }
    00285    AST_LIST_TRAVERSE_SAFE_END;
    00286    AST_LIST_UNLOCK(&file_versions);
    00287    if (find)
    00288       free(find);
    00289 }
    00290
    00291 static char show_version_files_help[] =
    00292 "Usage: show version files [like <pattern>]\n"
    00293 "       Shows the revision numbers of the files used to build this copy of Asterisk.\n"
    00294 "       Optional regular expression pattern is used to filter the file list.\n";
    00295
    00296 /*! CLI command to list module versions */
    00297 static int handle_show_version_files(int fd, int argc, char *argv[])
    00298 {
    00299 #define FORMAT "%-25.25s %-40.40s\n"
    00300    struct file_version *iterator;
    00301    regex_t regexbuf;
    00302    int havepattern = 0;
    00303    int havename = 0;
    00304    int count_files = 0;
    00305
    00306    switch (argc) {
    00307    case 5:
    00308       if (!strcasecmp(argv[3], "like")) {
    00309          if (regcomp(&regexbuf, argv[4], REG_EXTENDED | REG_NOSUB))
    00310             return RESULT_SHOWUSAGE;
    00311          havepattern = 1;
    00312       } else
    00313          return RESULT_SHOWUSAGE;
    00314       break;
    00315    case 4:
    00316       havename = 1;
    00317       break;
    00318    case 3:
    00319       break;
    00320    default:
    00321       return RESULT_SHOWUSAGE;
    00322    }
    00323
    00324    ast_cli(fd, FORMAT, "File", "Revision");
    00325    ast_cli(fd, FORMAT, "----", "--------");
    00326    AST_LIST_LOCK(&file_versions);
    00327    AST_LIST_TRAVERSE(&file_versions, iterator, list) {
    00328       if (havename && strcasecmp(iterator->file, argv[3]))
    00329          continue;
    00330
    00331       if (havepattern && regexec(&regexbuf, iterator->file, 0, NULL, 0))
    00332          continue;
    00333
    00334       ast_cli(fd, FORMAT, iterator->file, iterator->version);
    00335       count_files++;
    00336       if (havename)
    00337          break;
    00338    }
    00339    AST_LIST_UNLOCK(&file_versions);
    00340    if (!havename) {
    00341       ast_cli(fd, "%d files listed.\n", count_files);
    00342    }
    00343
    00344    if (havepattern)
    00345       regfree(&regexbuf);
    00346
    00347    return RESULT_SUCCESS;
    00348 #undef FORMAT
    00349 }
    00350
    00351 static char *complete_show_version_files(char *line, char *word, int pos, int state)
    00352 {
    00353    struct file_version *find;
    00354    int which = 0;
    00355    char *ret = NULL;
    00356    int matchlen = strlen(word);
    00357
    00358    if (pos != 3)
    00359       return NULL;
    00360
    00361    AST_LIST_LOCK(&file_versions);
    00362    AST_LIST_TRAVERSE(&file_versions, find, list) {
    00363       if (!strncasecmp(word, find->file, matchlen)) {
    00364          if (++which > state) {
    00365             ret = strdup(find->file);
    00366             break;
    00367          }
    00368       }
    00369    }
    00370    AST_LIST_UNLOCK(&file_versions);
    00371
    00372    return ret;
    00373 }
    00374 #endif /* ! LOW_MEMORY */
    00375
    00376 int ast_register_atexit(void (*func)(void))
    00377 {
    00378    int res = -1;
    00379    struct ast_atexit *ae;
    00380    ast_unregister_atexit(func);
    00381    ae = malloc(sizeof(struct ast_atexit));
    00382    ast_mutex_lock(&atexitslock);
    00383    if (ae) {
    00384       memset(ae, 0, sizeof(struct ast_atexit));
    00385       ae->next = atexits;
    00386       ae->func = func;
    00387       atexits = ae;
    00388       res = 0;
    00389    }
    00390    ast_mutex_unlock(&atexitslock);
    00391    return res;
    00392 }
    00393
    00394 void ast_unregister_atexit(void (*func)(void))
    00395 {
    00396    struct ast_atexit *ae, *prev = NULL;
    00397    ast_mutex_lock(&atexitslock);
    00398    ae = atexits;
    00399    while(ae) {
    00400       if (ae->func == func) {
    00401          if (prev)
    00402             prev->next = ae->next;
    00403          else
    00404             atexits = ae->next;
    00405          break;
    00406       }
    00407       prev = ae;
    00408       ae = ae->next;
    00409    }
    00410    ast_mutex_unlock(&atexitslock);
    00411 }
    00412
    00413 static int fdprint(int fd, const char *s)
    00414 {
    00415    return write(fd, s, strlen(s) + 1);
    00416 }
    00417
    00418 /*! NULL handler so we can collect the child exit status */
    00419 static void null_sig_handler(int signal)
    00420 {
    00421
    00422 }
    00423
    00424 AST_MUTEX_DEFINE_STATIC(safe_system_lock);
    00425 static unsigned int safe_system_level = 0;
    00426 static void *safe_system_prev_handler;
    00427
    00428 int ast_safe_system(const char *s)
    00429 {
    00430    pid_t pid;
    00431    int x;
    00432    int res;
    00433    struct rusage rusage;
    00434    int status;
    00435    unsigned int level;
    00436
    00437    /* keep track of how many ast_safe_system() functions
    00438       are running at this moment
    00439    */
    00440    ast_mutex_lock(&safe_system_lock);
    00441    level = safe_system_level++;
    00442
    00443    /* only replace the handler if it has not already been done */
    00444    if (level == 0)
    00445       safe_system_prev_handler = signal(SIGCHLD, null_sig_handler);
    00446
    00447    ast_mutex_unlock(&safe_system_lock);
    00448
    00449    pid = fork();
    00450
    00451    if (pid == 0) {
    00452       if (option_highpriority)
    00453          ast_set_priority(0);
    00454       /* Close file descriptors and launch system command */
    00455       for (x = STDERR_FILENO + 1; x < 4096; x++)
    00456          close(x);
    00457       execl("/bin/sh", "/bin/sh", "-c", s, NULL);
    00458       _exit(1);
    00459    } else if (pid > 0) {
    00460       for(;;) {
    00461          res = wait4(pid, &status, 0, &rusage);
    00462          if (res > -1) {
    00463             res = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
    00464             break;
    00465          } else if (errno != EINTR)
    00466             break;
    00467       }
    00468    } else {
    00469       ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno));
    00470       res = -1;
    00471    }
    00472
    00473    ast_mutex_lock(&safe_system_lock);
    00474    level = --safe_system_level;
    00475
    00476    /* only restore the handler if we are the last one */
    00477    if (level == 0)
    00478       signal(SIGCHLD, safe_system_prev_handler);
    00479
    00480    ast_mutex_unlock(&safe_system_lock);
    00481
    00482    return res;
    00483 }
    00484
    00485 /*!
    00486  * write the string to all attached console clients
    00487  */
    00488 static void ast_network_puts(const char *string)
    00489 {
    00490    int x;
    00491    for (x=0;x<AST_MAX_CONNECTS; x++) {
    00492       if (consoles[x].fd > -1)
    00493          fdprint(consoles[x].p[1], string);
    00494    }
    00495 }
    00496
    00497 /*!
    00498  * write the string to the console, and all attached
    00499  * console clients
    00500  */
    00501 void ast_console_puts(const char *string)
    00502 {
    00503    fputs(string, stdout);
    00504    fflush(stdout);
    00505    ast_network_puts(string);
    00506 }
    00507
    00508 static void network_verboser(const char *s, int pos, int replace, int complete)
    00509    /* ARGUSED */
    00510 {
    00511    if (replace) {
    00512       char *t = alloca(strlen(s) + 2);
    00513       if (t) {
    00514          sprintf(t, "\r%s", s);
    00515          if (complete)
    00516             ast_network_puts(t);
    00517       } else {
    00518          ast_log(LOG_ERROR, "Out of memory\n");
    00519          ast_network_puts(s);
    00520       }
    00521    } else {
    00522       if (complete)
    00523          ast_network_puts(s);
    00524    }
    00525 }
    00526
    00527 static pthread_t lthread;
    00528
    00529 static void *netconsole(void *vconsole)
    00530 {
    00531    struct console *con = vconsole;
    00532    char hostname[MAXHOSTNAMELEN]="";
    00533    char tmp[512];
    00534    int res;
    00535    struct pollfd fds[2];
    00536
    00537    if (gethostname(hostname, sizeof(hostname)-1))
    00538       ast_copy_string(hostname, "<Unknown>", sizeof(hostname));
    00539    snprintf(tmp, sizeof(tmp), "%s/%d/%s\n", hostname, ast_mainpid, ASTERISK_VERSION);
    00540    fdprint(con->fd, tmp);
    00541    for(;;) {
    00542       fds[0].fd = con->fd;
    00543       fds[0].events = POLLIN;
    00544       fds[0].revents = 0;
    00545       fds[1].fd = con->p[0];
    00546       fds[1].events = POLLIN;
    00547       fds[1].revents = 0;
    00548
    00549       res = poll(fds, 2, -1);
    00550       if (res < 0) {
    00551          if (errno != EINTR)
    00552             ast_log(LOG_WARNING, "poll returned < 0: %s\n", strerror(errno));
    00553          continue;
    00554       }
    00555       if (fds[0].revents) {
    00556          res = read(con->fd, tmp, sizeof(tmp));
    00557          if (res < 1) {
    00558             break;
    00559          }
    00560          tmp[res] = 0;
    00561          ast_cli_command(con->fd, tmp);
    00562       }
    00563       if (fds[1].revents) {
    00564          res = read(con->p[0], tmp, sizeof(tmp));
    00565          if (res < 1) {
    00566             ast_log(LOG_ERROR, "read returned %d\n", res);
    00567             break;
    00568          }
    00569          res = write(con->fd, tmp, res);
    00570          if (res < 1)
    00571             break;
    00572       }
    00573    }
    00574    if (option_verbose > 2)
    00575       ast_verbose(VERBOSE_PREFIX_3 "Remote UNIX connection disconnected\n");
    00576    close(con->fd);
    00577    close(con->p[0]);
    00578    close(con->p[1]);
    00579    con->fd = -1;
    00580
    00581    return NULL;
    00582 }
    00583
    00584 static void *listener(void *unused)
    00585 {
    00586    struct sockaddr_un sunaddr;
    00587    int s;
    00588    socklen_t len;
    00589    int x;
    00590    int flags;
    00591    struct pollfd fds[1];
    00592    pthread_attr_t attr;
    00593    pthread_attr_init(&attr);
    00594    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
    00595    for(;;) {
    00596       if (ast_socket < 0)
    00597          return NULL;
    00598       fds[0].fd = ast_socket;
    00599       fds[0].events= POLLIN;
    00600       s = poll(fds, 1, -1);
    00601       pthread_testcancel();
    00602       if (s < 0) {
    00603          if (errno != EINTR)
    00604             ast_log(LOG_WARNING, "poll returned error: %s\n", strerror(errno));
    00605          continue;
    00606       }
    00607       len = sizeof(sunaddr);
    00608       s = accept(ast_socket, (struct sockaddr *)&sunaddr, &len);
    00609       if (s < 0) {
    00610          if (errno != EINTR)
    00611             ast_log(LOG_WARNING, "Accept returned %d: %s\n", s, strerror(errno));
    00612       } else {
    00613          for (x=0;x<AST_MAX_CONNECTS;x++) {
    00614             if (consoles[x].fd < 0) {
    00615                if (socketpair(AF_LOCAL, SOCK_STREAM, 0, consoles[x].p)) {
    00616                   ast_log(LOG_ERROR, "Unable to create pipe: %s\n", strerror(errno));
    00617                   consoles[x].fd = -1;
    00618                   fdprint(s, "Server failed to create pipe\n");
    00619                   close(s);
    00620                   break;
    00621                }
    00622                flags = fcntl(consoles[x].p[1], F_GETFL);
    00623                fcntl(consoles[x].p[1], F_SETFL, flags | O_NONBLOCK);
    00624                consoles[x].fd = s;
    00625                if (ast_pthread_create(&consoles[x].t, &attr, netconsole, &consoles[x])) {
    00626                   ast_log(LOG_ERROR, "Unable to spawn thread to handle connection: %s\n", strerror(errno));
    00627                   close(consoles[x].p[0]);
    00628                   close(consoles[x].p[1]);
    00629                   consoles[x].fd = -1;
    00630                   fdprint(s, "Server failed to spawn thread\n");
    00631                   close(s);
    00632                }
    00633                break;
    00634             }
    00635          }
    00636          if (x >= AST_MAX_CONNECTS) {
    00637             fdprint(s, "No more connections allowed\n");
    00638             ast_log(LOG_WARNING, "No more connections allowed\n");
    00639             close(s);
    00640          } else if (consoles[x].fd > -1) {
    00641             if (option_verbose > 2)
    00642                ast_verbose(VERBOSE_PREFIX_3 "Remote UNIX connection\n");
    00643          }
    00644       }
    00645    }
    00646    return NULL;
    00647 }
    00648
    00649 static int ast_makesocket(void)
    00650 {
    00651    struct sockaddr_un sunaddr;
    00652    int res;
    00653    int x;
    00654    uid_t uid = -1;
    00655    gid_t gid = -1;
    00656
    00657    for (x = 0; x < AST_MAX_CONNECTS; x++)
    00658       consoles[x].fd = -1;
    00659    unlink(ast_config_AST_SOCKET);
    00660    ast_socket = socket(PF_LOCAL, SOCK_STREAM, 0);
    00661    if (ast_socket < 0) {
    00662       ast_log(LOG_WARNING, "Unable to create control socket: %s\n", strerror(errno));
    00663       return -1;
    00664    }
    00665    memset(&sunaddr, 0, sizeof(sunaddr));
    00666    sunaddr.sun_family = AF_LOCAL;
    00667    ast_copy_string(sunaddr.sun_path, ast_config_AST_SOCKET, sizeof(sunaddr.sun_path));
    00668    res = bind(ast_socket, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
    00669    if (res) {
    00670       ast_log(LOG_WARNING, "Unable to bind socket to %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
    00671       close(ast_socket);
    00672       ast_socket = -1;
    00673       return -1;
    00674    }
    00675    res = listen(ast_socket, 2);
    00676    if (res < 0) {
    00677       ast_log(LOG_WARNING, "Unable to listen on socket %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
    00678       close(ast_socket);
    00679       ast_socket = -1;
    00680       return -1;
    00681    }
    00682    ast_register_verbose(network_verboser);
    00683    ast_pthread_create(&lthread, NULL, listener, NULL);
    00684
    00685    if (!ast_strlen_zero(ast_config_AST_CTL_OWNER)) {
    00686       struct passwd *pw;
    00687       if ((pw = getpwnam(ast_config_AST_CTL_OWNER)) == NULL) {
    00688          ast_log(LOG_WARNING, "Unable to find uid of user %s\n", ast_config_AST_CTL_OWNER);
    00689       } else {
    00690          uid = pw->pw_uid;
    00691       }
    00692    }
    00693
    00694    if (!ast_strlen_zero(ast_config_AST_CTL_GROUP)) {
    00695       struct group *grp;
    00696       if ((grp = getgrnam(ast_config_AST_CTL_GROUP)) == NULL) {
    00697          ast_log(LOG_WARNING, "Unable to find gid of group %s\n", ast_config_AST_CTL_GROUP);
    00698       } else {
    00699          gid = grp->gr_gid;
    00700       }
    00701    }
    00702
    00703    if (chown(ast_config_AST_SOCKET, uid, gid) < 0)
    00704       ast_log(LOG_WARNING, "Unable to change ownership of %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
    00705
    00706    if (!ast_strlen_zero(ast_config_AST_CTL_PERMISSIONS)) {
    00707       int p1;
    00708       mode_t p;
    00709       sscanf(ast_config_AST_CTL_PERMISSIONS, "%30o", &p1);
    00710       p = p1;
    00711       if ((chmod(ast_config_AST_SOCKET, p)) < 0)
    00712          ast_log(LOG_WARNING, "Unable to change file permissions of %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
    00713    }
    00714
    00715    return 0;
    00716 }
    00717
    00718 static int ast_tryconnect(void)
    00719 {
    00720    struct sockaddr_un sunaddr;
    00721    int res;
    00722    ast_consock = socket(PF_LOCAL, SOCK_STREAM, 0);
    00723    if (ast_consock < 0) {
    00724       ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno));
    00725       return 0;
    00726    }
    00727    memset(&sunaddr, 0, sizeof(sunaddr));
    00728    sunaddr.sun_family = AF_LOCAL;
    00729    ast_copy_string(sunaddr.sun_path, (char *)ast_config_AST_SOCKET, sizeof(sunaddr.sun_path));
    00730    res = connect(ast_consock, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
    00731    if (res) {
    00732       close(ast_consock);
    00733       ast_consock = -1;
    00734       return 0;
    00735    } else
    00736       return 1;
    00737 }
    00738
    00739 /*! Urgent handler
    00740  Called by soft_hangup to interrupt the poll, read, or other
    00741  system call.  We don't actually need to do anything though.
    00742  Remember: Cannot EVER ast_log from within a signal handler
    00743  */
    00744 static void urg_handler(int num)
    00745 {
    00746    signal(num, urg_handler);
    00747    return;
    00748 }
    00749
    00750 static void hup_handler(int num)
    00751 {
    00752    int a = 0;
    00753    if (option_verbose > 1)
    00754       printf("Received HUP signal -- Reloading configs\n");
    00755    if (restartnow)
    00756       execvp(_argv[0], _argv);
    00757    sig_flags.need_reload = 1;
    00758    if (sig_alert_pipe[1] != -1)
    00759       write(sig_alert_pipe[1], &a, sizeof(a));
    00760    signal(num, hup_handler);
    00761 }
    00762
    00763 static void child_handler(int sig)
    00764 {
    00765    /* Must not ever ast_log or ast_verbose within signal handler */
    00766    int n, status;
    00767
    00768    /*
    00769     * Reap all dead children -- not just one
    00770     */
    00771    for (n = 0; wait4(-1, &status, WNOHANG, NULL) > 0; n++)
    00772       ;
    00773    if (n == 0 && option_debug)
    00774       printf("Huh?  Child handler, but nobody there?\n");
    00775    signal(sig, child_handler);
    00776 }
    00777
    00778 /*! Set an X-term or screen title */
    00779 static void set_title(char *text)
    00780 {
    00781    if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
    00782       fprintf(stdout, "\033]2;%s\007", text);
    00783 }
    00784
    00785 static void set_icon(char *text)
    00786 {
    00787    if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
    00788       fprintf(stdout, "\033]1;%s\007", text);
    00789 }
    00790
    00791 /*! We set ourselves to a high priority, that we might pre-empt everything
    00792    else.  If your PBX has heavy activity on it, this is a good thing.  */
    00793 int ast_set_priority(int pri)
    00794 {
    00795    struct sched_param sched;
    00796    memset(&sched, 0, sizeof(sched));
    00797 #ifdef __linux__
    00798 #undef sched_setscheduler
    00799    if (pri) {
    00800       sched.sched_priority = 10;
    00801       if (sched_setscheduler(0, SCHED_RR, &sched)) {
    00802          ast_log(LOG_WARNING, "Unable to set high priority\n");
    00803          return -1;
    00804       } else
    00805          if (option_verbose)
    00806             ast_verbose("Set to realtime thread\n");
    00807    } else {
    00808       sched.sched_priority = 0;
    00809       /* According to the manpage, this can never fail, with these parameters. */
    00810       sched_setscheduler(0, SCHED_OTHER, &sched);
    00811    }
    00812 #else
    00813 #undef setpriority
    00814    if (pri) {
    00815       if (setpriority(PRIO_PROCESS, 0, -10) == -1) {
    00816          ast_log(LOG_WARNING, "Unable to set high priority\n");
    00817          return -1;
    00818       } else
    00819          if (option_verbose)
    00820             ast_verbose("Set to high priority\n");
    00821    } else {
    00822       /* According to the manpage, this can never fail, with these parameters. */
    00823       setpriority(PRIO_PROCESS, 0, 0);
    00824    }
    00825 #endif
    00826    return 0;
    00827 }
    00828
    00829 static void ast_run_atexits(void)
    00830 {
    00831    struct ast_atexit *ae;
    00832    ast_mutex_lock(&atexitslock);
    00833    ae = atexits;
    00834    while(ae) {
    00835       if (ae->func)
    00836          ae->func();
    00837       ae = ae->next;
    00838    }
    00839    ast_mutex_unlock(&atexitslock);
    00840 }
    00841
    00842 static void quit_handler(int num, int nice, int safeshutdown, int restart)
    00843 {
    00844    char filename[80] = "";
    00845    time_t s,e;
    00846    int x;
    00847    /* Try to get as many CDRs as possible submitted to the backend engines (if in batch mode) */
    00848    ast_cdr_engine_term();
    00849    if (safeshutdown) {
    00850       shuttingdown = 1;
    00851       if (!nice) {
    00852          /* Begin shutdown routine, hanging up active channels */
    00853          ast_begin_shutdown(1);
    00854          if (option_verbose && option_console)
    00855             ast_verbose("Beginning asterisk %s....\n", restart ? "restart" : "shutdown");
    00856          time(&s);
    00857          for(;;) {
    00858             time(&e);
    00859             /* Wait up to 15 seconds for all channels to go away */
    00860             if ((e - s) > 15)
    00861                break;
    00862             if (!ast_active_channels())
    00863                break;
    00864             if (!shuttingdown)
    00865                break;
    00866             /* Sleep 1/10 of a second */
    00867             usleep(100000);
    00868          }
    00869       } else {
    00870          if (nice < 2)
    00871             ast_begin_shutdown(0);
    00872          if (option_verbose && option_console)
    00873             ast_verbose("Waiting for inactivity to perform %s...\n", restart ? "restart" : "halt");
    00874          for(;;) {
    00875             if (!ast_active_channels())
    00876                break;
    00877             if (!shuttingdown)
    00878                break;
    00879             sleep(1);
    00880          }
    00881       }
    00882
    00883       if (!shuttingdown) {
    00884          if (option_verbose && option_console)
    00885             ast_verbose("Asterisk %s cancelled.\n", restart ? "restart" : "shutdown");
    00886          return;
    00887       }
    00888    }
    00889    if (option_console || option_remote) {
    00890       if (getenv("HOME"))
    00891          snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
    00892       if (!ast_strlen_zero(filename))
    00893          ast_el_write_history(filename);
    00894       if (el != NULL)
    00895          el_end(el);
    00896       if (el_hist != NULL)
    00897          history_end(el_hist);
    00898    }
    00899    if (option_verbose)
    00900       ast_verbose("Executing last minute cleanups\n");
    00901    ast_run_atexits();
    00902    /* Called on exit */
    00903    if (option_verbose && option_console)
    00904       ast_verbose("Asterisk %s ending (%d).\n", ast_active_channels() ? "uncleanly" : "cleanly", num);
    00905    if (option_debug)
    00906       ast_log(LOG_DEBUG, "Asterisk ending (%d).\n", num);
    00907    manager_event(EVENT_FLAG_SYSTEM, "Shutdown", "Shutdown: %s\r\nRestart: %s\r\n", ast_active_channels() ? "Uncleanly" : "Cleanly", restart ? "True" : "False");
    00908    if (ast_socket > -1) {
    00909       pthread_cancel(lthread);
    00910       close(ast_socket);
    00911       ast_socket = -1;
    00912       unlink(ast_config_AST_SOCKET);
    00913    }
    00914    if (ast_consock > -1)
    00915       close(ast_consock);
    00916    if (!option_remote) unlink((char *)ast_config_AST_PID);
    00917    printf(term_quit());
    00918    if (restart) {
    00919       if (option_verbose || option_console)
    00920          ast_verbose("Preparing for Asterisk restart...\n");
    00921       /* Mark all FD's for closing on exec */
    00922       for (x=3;x<32768;x++) {
    00923          fcntl(x, F_SETFD, FD_CLOEXEC);
    00924       }
    00925       if (option_verbose || option_console)
    00926          ast_verbose("Restarting Asterisk NOW...\n");
    00927       restartnow = 1;
    00928
    00929       /* close logger */
    00930       close_logger();
    00931
    00932       /* If there is a consolethread running send it a SIGHUP
    00933          so it can execvp, otherwise we can do it ourselves */
    00934       if ((consolethread != AST_PTHREADT_NULL) && (consolethread != pthread_self())) {
    00935          pthread_kill(consolethread, SIGHUP);
    00936          /* Give the signal handler some time to complete */
    00937          sleep(2);
    00938       } else
    00939          execvp(_argv[0], _argv);
    00940
    00941    } else {
    00942       /* close logger */
    00943       close_logger();
    00944    }
    00945    exit(0);
    00946 }
    00947
    00948 static void __quit_handler(int num)
    00949 {
    00950    int a = 0;
    00951    sig_flags.need_quit = 1;
    00952    if (sig_alert_pipe[1] != -1)
    00953       write(sig_alert_pipe[1], &a, sizeof(a));
    00954    /* There is no need to restore the signal handler here, since the app
    00955     * is going to exit */
    00956 }
    00957
    00958 static const char *fix_header(char *outbuf, int maxout, const char *s, char *cmp)
    00959 {
    00960    const char *c;
    00961    if (!strncmp(s, cmp, strlen(cmp))) {
    00962       c = s + strlen(cmp);
    00963       term_color(outbuf, cmp, COLOR_GRAY, 0, maxout);
    00964       return c;
    00965    }
    00966    return NULL;
    00967 }
    00968
    00969 static void console_verboser(const char *s, int pos, int replace, int complete)
    00970 {
    00971    char tmp[80];
    00972    const char *c=NULL;
    00973    /* Return to the beginning of the line */
    00974    if (!pos) {
    00975       fprintf(stdout, "\r");
    00976       if ((c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_4)) ||
    00977          (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_3)) ||
    00978          (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_2)) ||
    00979          (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_1)))
    00980          fputs(tmp, stdout);
    00981    }
    00982    if (c)
    00983       fputs(c + pos,stdout);
    00984    else
    00985       fputs(s + pos,stdout);
    00986    fflush(stdout);
    00987    if (complete) {
    00988       /* Wake up a poll()ing console */
    00989       if (option_console && consolethread != AST_PTHREADT_NULL)
    00990          pthread_kill(consolethread, SIGURG);
    00991    }
    00992 }
    00993
    00994 static int ast_all_zeros(char *s)
    00995 {
    00996    while(*s) {
    00997       if (*s > 32)
    00998          return 0;
    00999       s++;
    01000    }
    01001    return 1;
    01002 }
    01003
    01004 static void consolehandler(char *s)
    01005 {
    01006    printf(term_end());
    01007    fflush(stdout);
    01008
    01009    /* Called when readline data is available */
    01010    if (!ast_all_zeros(s))
    01011       ast_el_add_history(s);
    01012    /* The real handler for bang */
    01013    if (s[0] == '!') {
    01014       if (s[1])
    01015          ast_safe_system(s+1);
    01016       else
    01017          ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
    01018    } else
    01019       ast_cli_command(STDOUT_FILENO, s);
    01020 }
    01021
    01022 static int remoteconsolehandler(char *s)
    01023 {
    01024    int ret = 0;
    01025
    01026    /* Called when readline data is available */
    01027    if (!ast_all_zeros(s))
    01028       ast_el_add_history(s);
    01029    /* The real handler for bang */
    01030    if (s[0] == '!') {
    01031       if (s[1])
    01032          ast_safe_system(s+1);
    01033       else
    01034          ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
    01035       ret = 1;
    01036    }
    01037    if ((strncasecmp(s, "quit", 4) == 0 || strncasecmp(s, "exit", 4) == 0) &&
    01038        (s[4] == '\0' || isspace(s[4]))) {
    01039       quit_handler(0, 0, 0, 0);
    01040       ret = 1;
    01041    }
    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, "%30d;%30d%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, "%30d%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, "%30f %30f %30f %30d/%30d %30d",
    01409                         &avg1, &avg2, &avg3, &actproc, &totproc, &npid);
    01410                      if (sscanf(t, "%30d", &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       for (i=0; matches[i]; i++)
    01671          free(matches[i]);
    01672       free(matches);
    01673    }
    01674
    01675    return (char *)(long)retval;
    01676 }
    01677
    01678 static int ast_el_initialize(void)
    01679 {
    01680    HistEvent ev;
    01681    char *editor = getenv("AST_EDITOR");
    01682
    01683    if (el != NULL)
    01684       el_end(el);
    01685    if (el_hist != NULL)
    01686       history_end(el_hist);
    01687
    01688    el = el_init("asterisk", stdin, stdout, stderr);
    01689    el_set(el, EL_PROMPT, cli_prompt);
    01690
    01691    el_set(el, EL_EDITMODE, 1);
    01692    el_set(el, EL_EDITOR, editor ? editor : "emacs");
    01693    el_hist = history_init();
    01694    if (!el || !el_hist)
    01695       return -1;
    01696
    01697    /* setup history with 100 entries */
    01698    history(el_hist, &ev, H_SETSIZE, 100);
    01699
    01700    el_set(el, EL_HIST, history, el_hist);
    01701
    01702    el_set(el, EL_ADDFN, "ed-complete", "Complete argument", cli_complete);
    01703    /* Bind <tab> to command completion */
    01704    el_set(el, EL_BIND, "^I", "ed-complete", NULL);
    01705    /* Bind ? to command completion */
    01706    el_set(el, EL_BIND, "?", "ed-complete", NULL);
    01707    /* Bind ^D to redisplay */
    01708    el_set(el, EL_BIND, "^D", "ed-redisplay", NULL);
    01709
    01710    return 0;
    01711 }
    01712
    01713 static int ast_el_add_history(char *buf)
    01714 {
    01715    HistEvent ev;
    01716
    01717    if (el_hist == NULL || el == NULL)
    01718       ast_el_initialize();
    01719    if (strlen(buf) > 256)
    01720       return 0;
    01721    return (history(el_hist, &ev, H_ENTER, buf));
    01722 }
    01723
    01724 static int ast_el_write_history(char *filename)
    01725 {
    01726    HistEvent ev;
    01727
    01728    if (el_hist == NULL || el == NULL)
    01729       ast_el_initialize();
    01730
    01731    return (history(el_hist, &ev, H_SAVE, filename));
    01732 }
    01733
    01734 static int ast_el_read_history(char *filename)
    01735 {
    01736    char buf[256];
    01737    FILE *f;
    01738    int ret = -1;
    01739
    01740    if (el_hist == NULL || el == NULL)
    01741       ast_el_initialize();
    01742
    01743    if ((f = fopen(filename, "r")) == NULL)
    01744       return ret;
    01745
    01746    while (!feof(f)) {
    01747       fgets(buf, sizeof(buf), f);
    01748       if (!strcmp(buf, "_HiStOrY_V2_\n"))
    01749          continue;
    01750       if (ast_all_zeros(buf))
    01751          continue;
    01752       if ((ret = ast_el_add_history(buf)) == -1)
    01753          break;
    01754    }
    01755    fclose(f);
    01756
    01757    return ret;
    01758 }
    01759
    01760 static void ast_remotecontrol(char * data)
    01761 {
    01762    char buf[80];
    01763    int res;
    01764    char filename[80] = "";
    01765    char *hostname;
    01766    char *cpid;
    01767    char *version;
    01768    int pid;
    01769    char tmp[80];
    01770    char *stringp=NULL;
    01771
    01772    char *ebuf;
    01773    int num = 0;
    01774
    01775    read(ast_consock, buf, sizeof(buf));
    01776    if (data)
    01777       write(ast_consock, data, strlen(data) + 1);
    01778    stringp=buf;
    01779    hostname = strsep(&stringp, "/");
    01780    cpid = strsep(&stringp, "/");
    01781    version = strsep(&stringp, "\n");
    01782    if (!version)
    01783       version = "<Version Unknown>";
    01784    stringp=hostname;
    01785    strsep(&stringp, ".");
    01786    if (cpid)
    01787       pid = atoi(cpid);
    01788    else
    01789       pid = -1;
    01790    snprintf(tmp, sizeof(tmp), "set verbose atleast %d", option_verbose);
    01791    fdprint(ast_consock, tmp);
    01792    snprintf(tmp, sizeof(tmp), "set debug atleast %d", option_debug);
    01793    fdprint(ast_consock, tmp);
    01794    ast_verbose("Connected to Asterisk %s currently running on %s (pid = %d)\n", version, hostname, pid);
    01795    remotehostname = hostname;
    01796    if (getenv("HOME"))
    01797       snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
    01798    if (el_hist == NULL || el == NULL)
    01799       ast_el_initialize();
    01800
    01801    el_set(el, EL_GETCFN, ast_el_read_char);
    01802
    01803    if (!ast_strlen_zero(filename))
    01804       ast_el_read_history(filename);
    01805
    01806    if (option_exec && data) {  /* hack to print output then exit if asterisk -rx is used */
    01807       char tempchar;
    01808       struct pollfd fds;
    01809       fds.fd = ast_consock;
    01810       fds.events = POLLIN;
    01811       fds.revents = 0;
    01812       while (poll(&fds, 1, 100) > 0)
    01813          ast_el_read_char(el, &tempchar);
    01814       return;
    01815    }
    01816    for(;;) {
    01817       ebuf = (char *)el_gets(el, &num);
    01818
    01819       if (!ebuf && write(1, "", 1) < 0)
    01820          break;
    01821
    01822       if (!ast_strlen_zero(ebuf)) {
    01823          if (ebuf[strlen(ebuf)-1] == '\n')
    01824             ebuf[strlen(ebuf)-1] = '\0';
    01825          if (!remoteconsolehandler(ebuf)) {
    01826             res = write(ast_consock, ebuf, strlen(ebuf) + 1);
    01827             if (res < 1) {
    01828                ast_log(LOG_WARNING, "Unable to write: %s\n", strerror(errno));
    01829                break;
    01830             }
    01831          }
    01832       }
    01833    }
    01834    printf("\nDisconnected from Asterisk server\n");
    01835 }
    01836
    01837 static int show_version(void)
    01838 {
    01839    printf("Asterisk " ASTERISK_VERSION "\n");
    01840    return 0;
    01841 }
    01842
    01843 static int show_cli_help(void) {
    01844    printf("Asterisk " ASTERISK_VERSION ", Copyright (C) 1999 - 2005, Digium, Inc. and others.\n");
    01845    printf("Usage: asterisk [OPTIONS]\n");
    01846    printf("Valid Options:\n");
    01847    printf("   -V              Display version number and exit\n");
    01848    printf("   -C <configfile> Use an alternate configuration file\n");
    01849    printf("   -G <group>      Run as a group other than the caller\n");
    01850    printf("   -U <user>       Run as a user other than the caller\n");
    01851    printf("   -c              Provide console CLI\n");
    01852    printf("   -d              Enable extra debugging\n");
    01853    printf("   -f              Do not fork\n");
    01854    printf("   -g              Dump core in case of a crash\n");
    01855    printf("   -h              This help screen\n");
    01856    printf("   -i              Initialize crypto keys at startup\n");
    01857    printf("   -n              Disable console colorization\n");
    01858    printf("   -p              Run as pseudo-realtime thread\n");
    01859    printf("   -q              Quiet mode (suppress output)\n");
    01860    printf("   -r              Connect to Asterisk on this machine\n");
    01861    printf("   -R              Connect to Asterisk, and attempt to reconnect if disconnected\n");
    01862    printf("   -t              Record soundfiles in /var/tmp and move them where they belong after they are done.\n");
    01863    printf("   -T              Display the time in [Mmm dd hh:mm:ss] format for each line of output to the CLI.\n");
    01864    printf("   -v              Increase verbosity (multiple v's = more verbose)\n");
    01865    printf("   -x <cmd>        Execute command <cmd> (only valid with -r)\n");
    01866    printf("\n");
    01867    return 0;
    01868 }
    01869
    01870 static void ast_readconfig(void) {
    01871    struct ast_config *cfg;
    01872    struct ast_variable *v;
    01873    char *config = AST_CONFIG_FILE;
    01874
    01875    if (option_overrideconfig == 1) {
    01876       cfg = ast_config_load(ast_config_AST_CONFIG_FILE);
    01877       if (!cfg)
    01878          ast_log(LOG_WARNING, "Unable to open specified master config file '%s', using built-in defaults\n", ast_config_AST_CONFIG_FILE);
    01879    } else {
    01880       cfg = ast_config_load(config);
    01881    }
    01882
    01883    /* init with buildtime config */
    01884    ast_copy_string(ast_config_AST_CONFIG_DIR, AST_CONFIG_DIR, sizeof(ast_config_AST_CONFIG_DIR));
    01885    ast_copy_string(ast_config_AST_SPOOL_DIR, AST_SPOOL_DIR, sizeof(ast_config_AST_SPOOL_DIR));
    01886    ast_copy_string(ast_config_AST_MODULE_DIR, AST_MODULE_DIR, sizeof(ast_config_AST_MODULE_DIR));
    01887    snprintf(ast_config_AST_MONITOR_DIR, sizeof(ast_config_AST_MONITOR_DIR) - 1, "%s/monitor", ast_config_AST_SPOOL_DIR);
    01888    ast_copy_string(ast_config_AST_VAR_DIR, AST_VAR_DIR, sizeof(ast_config_AST_VAR_DIR));
    01889    ast_copy_string(ast_config_AST_LOG_DIR, AST_LOG_DIR, sizeof(ast_config_AST_LOG_DIR));
    01890    ast_copy_string(ast_config_AST_AGI_DIR, AST_AGI_DIR, sizeof(ast_config_AST_AGI_DIR));
    01891    ast_copy_string(ast_config_AST_DB, AST_DB, sizeof(ast_config_AST_DB));
    01892    ast_copy_string(ast_config_AST_KEY_DIR, AST_KEY_DIR, sizeof(ast_config_AST_KEY_DIR));
    01893    ast_copy_string(ast_config_AST_PID, AST_PID, sizeof(ast_config_AST_PID));
    01894    ast_copy_string(ast_config_AST_SOCKET, AST_SOCKET, sizeof(ast_config_AST_SOCKET));
    01895    ast_copy_string(ast_config_AST_RUN_DIR, AST_RUN_DIR, sizeof(ast_config_AST_RUN_DIR));
    01896
    01897    /* no asterisk.conf? no problem, use buildtime config! */
    01898    if (!cfg) {
    01899       return;
    01900    }
    01901    v = ast_variable_browse(cfg, "files");
    01902    while (v) {
    01903       if (!strcasecmp(v->name, "astctlpermissions")) {
    01904          ast_copy_string(ast_config_AST_CTL_PERMISSIONS, v->value, sizeof(ast_config_AST_CTL_PERMISSIONS));
    01905       } else if (!strcasecmp(v->name, "astctlowner")) {
    01906          ast_copy_string(ast_config_AST_CTL_OWNER, v->value, sizeof(ast_config_AST_CTL_OWNER));
    01907       } else if (!strcasecmp(v->name, "astctlgroup")) {
    01908          ast_copy_string(ast_config_AST_CTL_GROUP, v->value, sizeof(ast_config_AST_CTL_GROUP));
    01909       } else if (!strcasecmp(v->name, "astctl")) {
    01910          ast_copy_string(ast_config_AST_CTL, v->value, sizeof(ast_config_AST_CTL));
    01911       }
    01912       v = v->next;
    01913    }
    01914    v = ast_variable_browse(cfg, "directories");
    01915    while(v) {
    01916       if (!strcasecmp(v->name, "astetcdir")) {
    01917          ast_copy_string(ast_config_AST_CONFIG_DIR, v->value, sizeof(ast_config_AST_CONFIG_DIR));
    01918       } else if (!strcasecmp(v->name, "astspooldir")) {
    01919          ast_copy_string(ast_config_AST_SPOOL_DIR, v->value, sizeof(ast_config_AST_SPOOL_DIR));
    01920          snprintf(ast_config_AST_MONITOR_DIR, sizeof(ast_config_AST_MONITOR_DIR) - 1, "%s/monitor", v->value);
    01921       } else if (!strcasecmp(v->name, "astvarlibdir")) {
    01922          ast_copy_string(ast_config_AST_VAR_DIR, v->value, sizeof(ast_config_AST_VAR_DIR));
    01923          snprintf(ast_config_AST_DB, sizeof(ast_config_AST_DB), "%s/astdb", v->value);
    01924          snprintf(ast_config_AST_KEY_DIR, sizeof(ast_config_AST_KEY_DIR), "%s/keys", v->value);
    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, "%30d", &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, "%30d", &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, "%30lf", &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 static void *monitor_sig_flags(void *unused)
    02017 {
    02018    for (;;) {
    02019       struct pollfd p = { sig_alert_pipe[0], POLLIN, 0 };
    02020       int a;
    02021       poll(&p, 1, -1);
    02022       if (sig_flags.need_reload) {
    02023          sig_flags.need_reload = 0;
    02024          ast_module_reload(NULL);
    02025       }
    02026       if (sig_flags.need_quit) {
    02027          sig_flags.need_quit = 0;
    02028          quit_handler(0, 0, 1, 0);
    02029       }
    02030       read(sig_alert_pipe[0], &a, sizeof(a));
    02031    }
    02032
    02033    return NULL;
    02034 }
    02035
    02036 int main(int argc, char *argv[])
    02037 {
    02038    int c;
    02039    char filename[80] = "";
    02040    char hostname[MAXHOSTNAMELEN]="";
    02041    char tmp[80];
    02042    char * xarg = NULL;
    02043    int x;
    02044    FILE *f;
    02045    sigset_t sigs;
    02046    int num;
    02047    int is_child_of_nonroot=0;
    02048    char *buf;
    02049    char *runuser=NULL, *rungroup=NULL;
    02050
    02051    /* Remember original args for restart */
    02052    if (argc > sizeof(_argv) / sizeof(_argv[0]) - 1) {
    02053       fprintf(stderr, "Truncating argument size to %d\n", (int)(sizeof(_argv) / sizeof(_argv[0])) - 1);
    02054       argc = sizeof(_argv) / sizeof(_argv[0]) - 1;
    02055    }
    02056    for (x=0;x<argc;x++)
    02057       _argv[x] = argv[x];
    02058    _argv[x] = NULL;
    02059
    02060    /* if the progname is rasterisk consider it a remote console */
    02061    if (argv[0] && (strstr(argv[0], "rasterisk")) != NULL) {
    02062       option_remote++;
    02063       option_nofork++;
    02064    }
    02065    if (gethostname(hostname, sizeof(hostname)-1))
    02066       ast_copy_string(hostname, "<Unknown>", sizeof(hostname));
    02067    ast_mainpid = getpid();
    02068    ast_ulaw_init();
    02069    ast_alaw_init();
    02070    callerid_init();
    02071    ast_utils_init();
    02072    tdd_init();
    02073    /* When Asterisk restarts after it has dropped the root privileges,
    02074     * it can't issue setuid(), setgid(), setgroups() or set_priority()
    02075     * */
    02076    if (getenv("ASTERISK_ALREADY_NONROOT"))
    02077       is_child_of_nonroot=1;
    02078    if (getenv("HOME"))
    02079       snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
    02080    /* Check if we're root */
    02081    /*
    02082    if (geteuid()) {
    02083       ast_log(LOG_ERROR, "Must be run as root\n");
    02084       exit(1);
    02085    }
    02086    */
    02087    /* Check for options */
    02088    while((c=getopt(argc, argv, "tThfdvVqprRgcinx:U:G:C:L:M:")) != -1) {
    02089       switch(c) {
    02090       case 'd':
    02091          option_debug++;
    02092          option_nofork++;
    02093          break;
    02094       case 'c':
    02095          option_console++;
    02096          option_nofork++;
    02097          break;
    02098       case 'f':
    02099          option_nofork++;
    02100          break;
    02101       case 'n':
    02102          option_nocolor++;
    02103          break;
    02104       case 'r':
    02105          option_remote++;
    02106          option_nofork++;
    02107          break;
    02108       case 'R':
    02109          option_remote++;
    02110          option_nofork++;
    02111          option_reconnect++;
    02112          break;
    02113       case 'p':
    02114          option_highpriority++;
    02115          break;
    02116       case 'v':
    02117          option_verbose++;
    02118          option_nofork++;
    02119          break;
    02120       case 'M':
    02121          if ((sscanf(optarg, "%30d", &option_maxcalls) != 1) || (option_maxcalls < 0))
    02122             option_maxcalls = 0;
    02123          break;
    02124       case 'L':
    02125          if ((sscanf(optarg, "%30lf", &option_maxload) != 1) || (option_maxload < 0.0))
    02126             option_maxload = 0.0;
    02127          break;
    02128       case 'q':
    02129          option_quiet++;
    02130          break;
    02131       case 't':
    02132          option_cache_record_files++;
    02133          break;
    02134       case 'T':
    02135          option_timestamp++;
    02136          break;
    02137       case 'x':
    02138          option_exec++;
    02139          xarg = optarg;
    02140          break;
    02141       case 'C':
    02142          ast_copy_string((char *)ast_config_AST_CONFIG_FILE,optarg,sizeof(ast_config_AST_CONFIG_FILE));
    02143          option_overrideconfig++;
    02144          break;
    02145       case 'i':
    02146          option_initcrypto++;
    02147          break;
    02148       case'g':
    02149          option_dumpcore++;
    02150          break;
    02151       case 'h':
    02152          show_cli_help();
    02153          exit(0);
    02154       case 'V':
    02155          show_version();
    02156          exit(0);
    02157       case 'U':
    02158          runuser = optarg;
    02159          break;
    02160       case 'G':
    02161          rungroup = optarg;
    02162          break;
    02163       case '?':
    02164          exit(1);
    02165       }
    02166    }
    02167
    02168    /* For remote connections, change the name of the remote connection.
    02169     * We do this for the benefit of init scripts (which need to know if/when
    02170     * the main asterisk process has died yet). */
    02171    if (option_remote) {
    02172       strcpy(argv[0], "rasterisk");
    02173       for (x = 1; x < argc; x++) {
    02174          argv[x] = argv[0] + 10;
    02175       }
    02176    }
    02177
    02178    if (option_console && !option_verbose)
    02179       ast_verbose("[ Reading Master Configuration ]");
    02180    ast_readconfig();
    02181
    02182    if (option_dumpcore) {
    02183       struct rlimit l;
    02184       memset(&l, 0, sizeof(l));
    02185       l.rlim_cur = RLIM_INFINITY;
    02186       l.rlim_max = RLIM_INFINITY;
    02187       if (setrlimit(RLIMIT_CORE, &l)) {
    02188          ast_log(LOG_WARNING, "Unable to disable core size resource limit: %s\n", strerror(errno));
    02189       }
    02190    }
    02191
    02192    if ((!rungroup) && !ast_strlen_zero(ast_config_AST_RUN_GROUP))
    02193       rungroup = ast_config_AST_RUN_GROUP;
    02194    if ((!runuser) && !ast_strlen_zero(ast_config_AST_RUN_USER))
    02195       runuser = ast_config_AST_RUN_USER;
    02196 #ifndef __CYGWIN__
    02197
    02198    if (!is_child_of_nonroot)
    02199       ast_set_priority(option_highpriority);
    02200
    02201    if (!is_child_of_nonroot && rungroup) {
    02202       struct group *gr;
    02203       gr = getgrnam(rungroup);
    02204       if (!gr) {
    02205          ast_log(LOG_WARNING, "No such group '%s'!\n", rungroup);
    02206          exit(1);
    02207       }
    02208       if (setgid(gr->gr_gid)) {
    02209          ast_log(LOG_WARNING, "Unable to setgid to %d (%s)\n", (int)gr->gr_gid, rungroup);
    02210          exit(1);
    02211       }
    02212       if (setgroups(0, NULL)) {
    02213          ast_log(LOG_WARNING, "Unable to drop unneeded groups\n");
    02214          exit(1);
    02215       }
    02216       if (option_verbose)
    02217          ast_verbose("Running as group '%s'\n", rungroup);
    02218    }
    02219
    02220    if (!is_child_of_nonroot && runuser) {
    02221       struct passwd *pw;
    02222       pw = getpwnam(runuser);
    02223       if (!pw) {
    02224          ast_log(LOG_WARNING, "No such user '%s'!\n", runuser);
    02225          exit(1);
    02226       }
    02227       if (!rungroup) {
    02228          if (setgid(pw->pw_gid)) {
    02229             ast_log(LOG_WARNING, "Unable to setgid to %d!\n", (int)pw->pw_gid);
    02230             exit(1);
    02231          }
    02232          if (initgroups(pw->pw_name, pw->pw_gid)) {
    02233             ast_log(LOG_WARNING, "Unable to init groups for '%s'\n", runuser);
    02234             exit(1);
    02235          }
    02236       }
    02237       if (setuid(pw->pw_uid)) {
    02238          ast_log(LOG_WARNING, "Unable to setuid to %d (%s)\n", (int)pw->pw_uid, runuser);
    02239          exit(1);
    02240       }
    02241       setenv("ASTERISK_ALREADY_NONROOT","yes",1);
    02242       if (option_verbose)
    02243          ast_verbose("Running as user '%s'\n", runuser);
    02244    }
    02245
    02246 #endif /* __CYGWIN__ */
    02247
    02248 #ifdef linux
    02249
    02250    if (geteuid() && option_dumpcore) {
    02251       if (prctl(PR_SET_DUMPABLE, 1, 0, 0, 0) < 0) {
    02252          ast_log(LOG_WARNING, "Unable to set the process for core dumps after changing to a non-root user. %s\n", strerror(errno));
    02253       }
    02254    }
    02255
    02256 #endif
    02257
    02258    term_init();
    02259    printf(term_end());
    02260    fflush(stdout);
    02261
    02262    if (option_console && !option_verbose)
    02263       ast_verbose("[ Initializing Custom Configuration Options ]");
    02264    /* custom config setup */
    02265    register_config_cli();
    02266    read_config_maps();
    02267
    02268
    02269    if (option_console) {
    02270       if (el_hist == NULL || el == NULL)
    02271          ast_el_initialize();
    02272
    02273       if (!ast_strlen_zero(filename))
    02274          ast_el_read_history(filename);
    02275    }
    02276
    02277    if (ast_tryconnect()) {
    02278       /* One is already running */
    02279       if (option_remote) {
    02280          if (option_exec) {
    02281             ast_remotecontrol(xarg);
    02282             quit_handler(0, 0, 0, 0);
    02283             exit(0);
    02284          }
    02285          printf(term_quit());
    02286          ast_register_verbose(console_verboser);
    02287          WELCOME_MESSAGE;
    02288          ast_remotecontrol(NULL);
    02289          quit_handler(0, 0, 0, 0);
    02290          exit(0);
    02291       } else {
    02292          ast_log(LOG_ERROR, "Asterisk already running on %s.  Use 'asterisk -r' to connect.\n", (char *)ast_config_AST_SOCKET);
    02293          printf(term_quit());
    02294          exit(1);
    02295       }
    02296    } else if (option_remote || option_exec) {
    02297       ast_log(LOG_ERROR, "Unable to connect to remote asterisk (does %s exist?)\n",ast_config_AST_SOCKET);
    02298       printf(term_quit());
    02299       exit(1);
    02300    }
    02301    /* Blindly write pid file since we couldn't connect */
    02302    unlink((char *)ast_config_AST_PID);
    02303    f = fopen((char *)ast_config_AST_PID, "w");
    02304    if (f) {
    02305       fprintf(f, "%d\n", (int)getpid());
    02306       fclose(f);
    02307    } else
    02308       ast_log(LOG_WARNING, "Unable to open pid file '%s': %s\n", (char *)ast_config_AST_PID, strerror(errno));
    02309
    02310    if (!option_verbose && !option_debug && !option_nofork && !option_console) {
    02311       daemon(0,0);
    02312       /* Blindly re-write pid file since we are forking */
    02313       unlink((char *)ast_config_AST_PID);
    02314       f = fopen((char *)ast_config_AST_PID, "w");
    02315       if (f) {
    02316          fprintf(f, "%d\n", (int)getpid());
    02317          fclose(f);
    02318       } else
    02319          ast_log(LOG_WARNING, "Unable to open pid file '%s': %s\n", (char *)ast_config_AST_PID, strerror(errno));
    02320       ast_mainpid = getpid();
    02321    }
    02322
    02323    /* Test recursive mutex locking. */
    02324    if (test_for_thread_safety())
    02325       ast_verbose("Warning! Asterisk is not thread safe.\n");
    02326
    02327    ast_makesocket();
    02328    sigemptyset(&sigs);
    02329    sigaddset(&sigs, SIGHUP);
    02330    sigaddset(&sigs, SIGTERM);
    02331    sigaddset(&sigs, SIGINT);
    02332    sigaddset(&sigs, SIGPIPE);
    02333    sigaddset(&sigs, SIGWINCH);
    02334    pthread_sigmask(SIG_BLOCK, &sigs, NULL);
    02335    if (option_console || option_verbose || option_remote)
    02336       ast_register_verbose(console_verboser);
    02337    /* Print a welcome message if desired */
    02338    if (option_verbose || option_console) {
    02339       WELCOME_MESSAGE;
    02340    }
    02341    if (option_console && !option_verbose)
    02342       ast_verbose("[ Booting...");
    02343
    02344    signal(SIGURG, urg_handler);
    02345    signal(SIGINT, __quit_handler);
    02346    signal(SIGTERM, __quit_handler);
    02347    signal(SIGHUP, hup_handler);
    02348    signal(SIGCHLD, child_handler);
    02349    signal(SIGPIPE, SIG_IGN);
    02350
    02351    /* ensure that the random number generators are seeded with a different value every time
    02352       Asterisk is started
    02353    */
    02354    srand((unsigned int) getpid() + (unsigned int) time(NULL));
    02355    srandom((unsigned int) getpid() + (unsigned int) time(NULL));
    02356
    02357    if (init_logger()) {
    02358       printf(term_quit());
    02359       exit(1);
    02360    }
    02361    if (dnsmgr_init()) {
    02362       printf(term_quit());
    02363       exit(1);
    02364    }
    02365    /* load 'preload' modules, required for access to Realtime-mapped configuration files */
    02366    if (load_modules(1)) {
    02367       printf(term_quit());
    02368       exit(1);
    02369    }
    02370    ast_channels_init();
    02371    if (init_manager()) {
    02372       printf(term_quit());
    02373       exit(1);
    02374    }
    02375    if (ast_cdr_engine_init()) {
    02376       printf(term_quit());
    02377       exit(1);
    02378    }
    02379    if (ast_device_state_engine_init()) {
    02380       printf(term_quit());
    02381       exit(1);
    02382    }
    02383    ast_rtp_init();
    02384    if (ast_image_init()) {
    02385       printf(term_quit());
    02386       exit(1);
    02387    }
    02388    if (ast_file_init()) {
    02389       printf(term_quit());
    02390       exit(1);
    02391    }
    02392    if (load_pbx()) {
    02393       printf(term_quit());
    02394       exit(1);
    02395    }
    02396    if (init_framer()) {
    02397       printf(term_quit());
    02398       exit(1);
    02399    }
    02400    if (astdb_init()) {
    02401       printf(term_quit());
    02402       exit(1);
    02403    }
    02404    if (ast_enum_init()) {
    02405       printf(term_quit());
    02406       exit(1);
    02407    }
    02408    if (load_modules(0)) {
    02409       printf(term_quit());
    02410       exit(1);
    02411    }
    02412
    02413    dnsmgr_start_refresh();
    02414
    02415 #if 0
    02416    /* This should no longer be necessary */
    02417    /* sync cust config and reload some internals in case a custom config handler binded to them */
    02418    read_ast_cust_config();
    02419    reload_logger(0);
    02420    reload_manager();
    02421    ast_enum_reload();
    02422    ast_rtp_reload();
    02423 #endif
    02424
    02425
    02426    /* We might have the option of showing a console, but for now just
    02427       do nothing... */
    02428    if (option_console && !option_verbose)
    02429       ast_verbose(" ]\n");
    02430    if (option_verbose || option_console)
    02431       ast_verbose(term_color(tmp, "Asterisk Ready.\n", COLOR_BRWHITE, COLOR_BLACK, sizeof(tmp)));
    02432    if (option_nofork)
    02433       consolethread = pthread_self();
    02434
    02435    if (pipe(sig_alert_pipe))
    02436       sig_alert_pipe[0] = sig_alert_pipe[1] = -1;
    02437
    02438    fully_booted = 1;
    02439    pthread_sigmask(SIG_UNBLOCK, &sigs, NULL);
    02440 #ifdef __AST_DEBUG_MALLOC
    02441    __ast_mm_init();
    02442 #endif
    02443    time(&ast_startuptime);
    02444    ast_cli_register_multiple(core_cli, sizeof(core_cli) / sizeof(core_cli[0]));
    02445    if (option_console) {
    02446       /* Console stuff now... */
    02447       /* Register our quit function */
    02448       char title[256];
    02449       pthread_attr_t attr;
    02450       pthread_t dont_care;
    02451
    02452       pthread_attr_init(&attr);
    02453       pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
    02454       ast_pthread_create(&dont_care, &attr, monitor_sig_flags, NULL);
    02455       pthread_attr_destroy(&attr);
    02456
    02457       set_icon("Asterisk");
    02458       snprintf(title, sizeof(title), "Asterisk Console on '%s' (pid %d)", hostname, ast_mainpid);
    02459       set_title(title);
    02460
    02461       for (;;) {
    02462          buf = (char *)el_gets(el, &num);
    02463
    02464          if (!buf && write(1, "", 1) < 0)
    02465             goto lostterm;
    02466
    02467          if (buf) {
    02468             if (buf[strlen(buf)-1] == '\n')
    02469                buf[strlen(buf)-1] = '\0';
    02470
    02471             consolehandler((char *)buf);
    02472          } else if (option_remote) {
    02473             if (write(STDOUT_FILENO, "\nUse EXIT or QUIT to exit the asterisk console\n",
    02474                  strlen("\nUse EXIT or QUIT to exit the asterisk console\n")) < 0) {
    02475                /* Whoa, stdout disappeared from under us... Make /dev/null's */
    02476                int fd;
    02477                fd = open("/dev/null", O_RDWR);
    02478                if (fd > -1) {
    02479                   dup2(fd, STDOUT_FILENO);
    02480                   dup2(fd, STDIN_FILENO);
    02481                } else
    02482                   ast_log(LOG_WARNING, "Failed to open /dev/null to recover from dead console.  Bad things will happen!\n");
    02483                break;
    02484             }
    02485          }
    02486       }
    02487    }
    02488
    02489    monitor_sig_flags(NULL);
    02490
    02491 lostterm:
    02492    return 0;
    02493 }