Mon Mar 20 08:25:38 2006

Asterisk developer's documentation


Main Page | Modules | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals | Related Pages

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

Generated on Mon Mar 20 08:25:38 2006 for Asterisk - the Open Source PBX by  doxygen 1.3.9.1