Sat Sep 16 05:47:41 2006

Asterisk developer's documentation


asterisk.c

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

Generated on Sat Sep 16 05:47:41 2006 for Asterisk - the Open Source PBX by  doxygen 1.4.7