Main Page   Alphabetical List   Data Structures   File List   Data Fields   Globals  

asterisk.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- A telephony toolkit for Linux.
00003  *
00004  * Top level source file for asterisk
00005  * 
00006  * Copyright (C) 1999-2004, Digium, Inc.
00007  *
00008  * Mark Spencer <markster@digium.com>
00009  *
00010  * This program is free software, distributed under the terms of
00011  * the GNU General Public License
00012  */
00013 
00014 #include <unistd.h>
00015 #include <stdlib.h>
00016 #include <sys/poll.h>
00017 #include <asterisk/logger.h>
00018 #include <asterisk/options.h>
00019 #include <asterisk/cli.h>
00020 #include <asterisk/channel.h>
00021 #include <asterisk/ulaw.h>
00022 #include <asterisk/alaw.h>
00023 #include <asterisk/callerid.h>
00024 #include <asterisk/module.h>
00025 #include <asterisk/image.h>
00026 #include <asterisk/tdd.h>
00027 #include <asterisk/term.h>
00028 #include <asterisk/manager.h>
00029 #include <asterisk/pbx.h>
00030 #include <asterisk/enum.h>
00031 #include <asterisk/rtp.h>
00032 #include <asterisk/app.h>
00033 #include <asterisk/lock.h>
00034 #include <asterisk/utils.h>
00035 #include <asterisk/file.h>
00036 #include <sys/resource.h>
00037 #include <fcntl.h>
00038 #include <stdio.h>
00039 #include <signal.h>
00040 #include <sched.h>
00041 #include <asterisk/io.h>
00042 #include <asterisk/lock.h>
00043 #include <sys/socket.h>
00044 #include <sys/un.h>
00045 #include <sys/wait.h>
00046 #include <string.h>
00047 #include <errno.h>
00048 #include <ctype.h>
00049 #include "editline/histedit.h"
00050 #include "asterisk.h"
00051 #include <asterisk/config.h>
00052 #include <asterisk/config_pvt.h>
00053 #include <sys/resource.h>
00054 #include <grp.h>
00055 #include <pwd.h>
00056 
00057 #if  defined(__FreeBSD__) || defined( __NetBSD__ )
00058 #include <netdb.h>
00059 #endif
00060 
00061 #define AST_MAX_CONNECTS 128
00062 #define NUM_MSGS 64
00063 
00064 #define WELCOME_MESSAGE ast_verbose( "Asterisk " ASTERISK_VERSION ", Copyright (C) 1999-2004 Digium.\n"); \
00065       ast_verbose( "Written by Mark Spencer <markster@digium.com>\n"); \
00066       ast_verbose( "=========================================================================\n")
00067 
00068 int option_verbose=0;
00069 int option_debug=0;
00070 int option_nofork=0;
00071 int option_quiet=0;
00072 int option_console=0;
00073 int option_highpriority=0;
00074 int option_remote=0;
00075 int option_exec=0;
00076 int option_initcrypto=0;
00077 int option_nocolor;
00078 int option_dumpcore = 0;
00079 int option_cache_record_files = 0;
00080 int option_overrideconfig = 0;
00081 int option_reconnect = 0;
00082 int fully_booted = 0;
00083 char record_cache_dir[AST_CACHE_DIR_LEN] = AST_TMP_DIR;
00084 
00085 static int ast_socket = -1;      /* UNIX Socket for allowing remote control */
00086 static int ast_consock = -1;     /* UNIX Socket for controlling another asterisk */
00087 int ast_mainpid;
00088 struct console {
00089    int fd;              /* File descriptor */
00090    int p[2];            /* Pipe */
00091    pthread_t t;         /* Thread of handler */
00092 };
00093 
00094 static struct ast_atexit {
00095    void (*func)(void);
00096    struct ast_atexit *next;
00097 } *atexits = NULL;
00098 AST_MUTEX_DEFINE_STATIC(atexitslock);
00099 
00100 time_t ast_startuptime;
00101 time_t ast_lastreloadtime;
00102 
00103 static History *el_hist = NULL;
00104 static EditLine *el = NULL;
00105 static char *remotehostname;
00106 
00107 struct console consoles[AST_MAX_CONNECTS];
00108 
00109 char defaultlanguage[MAX_LANGUAGE] = DEFAULT_LANGUAGE;
00110 
00111 static int ast_el_add_history(char *);
00112 static int ast_el_read_history(char *);
00113 static int ast_el_write_history(char *);
00114 
00115 char ast_config_AST_CONFIG_DIR[AST_CONFIG_MAX_PATH];
00116 char ast_config_AST_CONFIG_FILE[AST_CONFIG_MAX_PATH];
00117 char ast_config_AST_MODULE_DIR[AST_CONFIG_MAX_PATH];
00118 char ast_config_AST_SPOOL_DIR[AST_CONFIG_MAX_PATH];
00119 char ast_config_AST_VAR_DIR[AST_CONFIG_MAX_PATH];
00120 char ast_config_AST_LOG_DIR[AST_CONFIG_MAX_PATH];
00121 char ast_config_AST_AGI_DIR[AST_CONFIG_MAX_PATH];
00122 char ast_config_AST_DB[AST_CONFIG_MAX_PATH];
00123 char ast_config_AST_KEY_DIR[AST_CONFIG_MAX_PATH];
00124 char ast_config_AST_PID[AST_CONFIG_MAX_PATH];
00125 char ast_config_AST_SOCKET[AST_CONFIG_MAX_PATH];
00126 char ast_config_AST_RUN_DIR[AST_CONFIG_MAX_PATH];
00127 char ast_config_AST_DATA_DIR[AST_CONFIG_MAX_PATH];
00128 
00129 static char *_argv[256];
00130 static int shuttingdown = 0;
00131 static int restartnow = 0;
00132 static pthread_t consolethread = AST_PTHREADT_NULL;
00133 
00134 int ast_register_atexit(void (*func)(void))
00135 {
00136    int res = -1;
00137    struct ast_atexit *ae;
00138    ast_unregister_atexit(func);
00139    ae = malloc(sizeof(struct ast_atexit));
00140    ast_mutex_lock(&atexitslock);
00141    if (ae) {
00142       memset(ae, 0, sizeof(struct ast_atexit));
00143       ae->next = atexits;
00144       ae->func = func;
00145       atexits = ae;
00146       res = 0;
00147    }
00148    ast_mutex_unlock(&atexitslock);
00149    return res;
00150 }
00151 
00152 void ast_unregister_atexit(void (*func)(void))
00153 {
00154    struct ast_atexit *ae, *prev = NULL;
00155    ast_mutex_lock(&atexitslock);
00156    ae = atexits;
00157    while(ae) {
00158       if (ae->func == func) {
00159          if (prev)
00160             prev->next = ae->next;
00161          else
00162             atexits = ae->next;
00163          break;
00164       }
00165       prev = ae;
00166       ae = ae->next;
00167    }
00168    ast_mutex_unlock(&atexitslock);
00169 }
00170 
00171 static int fdprint(int fd, const char *s)
00172 {
00173    return write(fd, s, strlen(s) + 1);
00174 }
00175 
00176 /* NULL handler so we can collect the child exit status */
00177 static void null_sig_handler(int signal)
00178 {
00179 
00180 }
00181 
00182 int ast_safe_system(const char *s)
00183 {
00184    /* XXX This function needs some optimization work XXX */
00185    pid_t pid;
00186    int x;
00187    int res;
00188    struct rusage rusage;
00189    int status;
00190    void (*prev_handler) = signal(SIGCHLD, null_sig_handler);
00191    pid = fork();
00192    if (pid == 0) {
00193       /* Close file descriptors and launch system command */
00194       for (x=STDERR_FILENO + 1; x<4096;x++) {
00195          close(x);
00196       }
00197       res = execl("/bin/sh", "/bin/sh", "-c", s, NULL);
00198       exit(1);
00199    } else if (pid > 0) {
00200       for(;;) {
00201          res = wait4(pid, &status, 0, &rusage);
00202          if (res > -1) {
00203             if (WIFEXITED(status))
00204                res = WEXITSTATUS(status);
00205             else
00206                res = -1;
00207             break;
00208          } else {
00209             if (errno != EINTR) 
00210                break;
00211          }
00212       }
00213    } else {
00214       ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno));
00215       res = -1;
00216    }
00217    signal(SIGCHLD, prev_handler);
00218    return res;
00219 }
00220 
00221 /*
00222  * write the string to all attached console clients
00223  */
00224 static void ast_network_puts(const char *string)
00225 {
00226    int x;
00227    for (x=0;x<AST_MAX_CONNECTS; x++) {
00228       if (consoles[x].fd > -1) 
00229          fdprint(consoles[x].p[1], string);
00230    }
00231 }
00232 
00233 /*
00234  * write the string to the console, and all attached
00235  * console clients
00236  */
00237 void ast_console_puts(const char *string)
00238 {
00239    fputs(string, stdout);
00240    fflush(stdout);
00241    ast_network_puts(string);
00242 }
00243 
00244 static void network_verboser(const char *s, int pos, int replace, int complete)
00245    /* ARGUSED */
00246 {
00247    if (replace) {
00248       char *t = alloca(strlen(s) + 2);
00249       if (t) {
00250          sprintf(t, "\r%s", s);
00251          ast_network_puts(t);
00252       } else {
00253          ast_log(LOG_ERROR, "Out of memory\n");
00254          ast_network_puts(s);
00255       }
00256    } else {
00257       ast_network_puts(s);
00258    }
00259 }
00260 
00261 static pthread_t lthread;
00262 
00263 static void *netconsole(void *vconsole)
00264 {
00265    struct console *con = vconsole;
00266    char hostname[256];
00267    char tmp[512];
00268    int res;
00269    struct pollfd fds[2];
00270    
00271    if (gethostname(hostname, sizeof(hostname)))
00272       strncpy(hostname, "<Unknown>", sizeof(hostname)-1);
00273    snprintf(tmp, sizeof(tmp), "%s/%d/%s\n", hostname, ast_mainpid, ASTERISK_VERSION);
00274    fdprint(con->fd, tmp);
00275    for(;;) {
00276       fds[0].fd = con->fd;
00277       fds[0].events = POLLIN;
00278       fds[1].fd = con->p[0];
00279       fds[1].events = POLLIN;
00280 
00281       res = poll(fds, 2, -1);
00282       if (res < 0) {
00283          if (errno != EINTR)
00284             ast_log(LOG_WARNING, "poll returned < 0: %s\n", strerror(errno));
00285          continue;
00286       }
00287       if (fds[0].revents) {
00288          res = read(con->fd, tmp, sizeof(tmp));
00289          if (res < 1) {
00290             break;
00291          }
00292          tmp[res] = 0;
00293          ast_cli_command(con->fd, tmp);
00294       }
00295       if (fds[1].revents) {
00296          res = read(con->p[0], tmp, sizeof(tmp));
00297          if (res < 1) {
00298             ast_log(LOG_ERROR, "read returned %d\n", res);
00299             break;
00300          }
00301          res = write(con->fd, tmp, res);
00302          if (res < 1)
00303             break;
00304       }
00305    }
00306    if (option_verbose > 2) 
00307       ast_verbose(VERBOSE_PREFIX_3 "Remote UNIX connection disconnected\n");
00308    close(con->fd);
00309    close(con->p[0]);
00310    close(con->p[1]);
00311    con->fd = -1;
00312    
00313    return NULL;
00314 }
00315 
00316 static void *listener(void *unused)
00317 {
00318    struct sockaddr_un sun;
00319    int s;
00320    int len;
00321    int x;
00322    int flags;
00323    struct pollfd fds[1];
00324    pthread_attr_t attr;
00325    pthread_attr_init(&attr);
00326    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
00327    for(;;) {
00328       if (ast_socket < 0)
00329          return NULL;
00330       fds[0].fd = ast_socket;
00331       fds[0].events= POLLIN;
00332       s = poll(fds, 1, -1);
00333       if (s < 0) {
00334          if (errno != EINTR)
00335             ast_log(LOG_WARNING, "poll returned error: %s\n", strerror(errno));
00336          continue;
00337       }
00338       len = sizeof(sun);
00339       s = accept(ast_socket, (struct sockaddr *)&sun, &len);
00340       if (s < 0) {
00341          if (errno != EINTR)
00342             ast_log(LOG_WARNING, "Accept returned %d: %s\n", s, strerror(errno));
00343       } else {
00344          for (x=0;x<AST_MAX_CONNECTS;x++) {
00345             if (consoles[x].fd < 0) {
00346                if (socketpair(AF_LOCAL, SOCK_STREAM, 0, consoles[x].p)) {
00347                   ast_log(LOG_ERROR, "Unable to create pipe: %s\n", strerror(errno));
00348                   consoles[x].fd = -1;
00349                   fdprint(s, "Server failed to create pipe\n");
00350                   close(s);
00351                   break;
00352                }
00353                flags = fcntl(consoles[x].p[1], F_GETFL);
00354                fcntl(consoles[x].p[1], F_SETFL, flags | O_NONBLOCK);
00355                consoles[x].fd = s;
00356                if (ast_pthread_create(&consoles[x].t, &attr, netconsole, &consoles[x])) {
00357                   ast_log(LOG_ERROR, "Unable to spawn thread to handle connection: %s\n", strerror(errno));
00358                   consoles[x].fd = -1;
00359                   fdprint(s, "Server failed to spawn thread\n");
00360                   close(s);
00361                }
00362                break;
00363             }
00364          }
00365          if (x >= AST_MAX_CONNECTS) {
00366             fdprint(s, "No more connections allowed\n");
00367             ast_log(LOG_WARNING, "No more connections allowed\n");
00368             close(s);
00369          } else if (consoles[x].fd > -1) {
00370             if (option_verbose > 2) 
00371                ast_verbose(VERBOSE_PREFIX_3 "Remote UNIX connection\n");
00372          }
00373       }
00374    }
00375    return NULL;
00376 }
00377 
00378 static int ast_makesocket(void)
00379 {
00380    struct sockaddr_un sun;
00381    int res;
00382    int x;
00383    for (x=0;x<AST_MAX_CONNECTS;x++) 
00384       consoles[x].fd = -1;
00385    unlink((char *)ast_config_AST_SOCKET);
00386    ast_socket = socket(PF_LOCAL, SOCK_STREAM, 0);
00387    if (ast_socket < 0) {
00388       ast_log(LOG_WARNING, "Unable to create control socket: %s\n", strerror(errno));
00389       return -1;
00390    }     
00391    memset(&sun, 0, sizeof(sun));
00392    sun.sun_family = AF_LOCAL;
00393    strncpy(sun.sun_path, (char *)ast_config_AST_SOCKET, sizeof(sun.sun_path)-1);
00394    res = bind(ast_socket, (struct sockaddr *)&sun, sizeof(sun));
00395    if (res) {
00396       ast_log(LOG_WARNING, "Unable to bind socket to %s: %s\n", (char *)ast_config_AST_SOCKET, strerror(errno));
00397       close(ast_socket);
00398       ast_socket = -1;
00399       return -1;
00400    }
00401    res = listen(ast_socket, 2);
00402    if (res < 0) {
00403       ast_log(LOG_WARNING, "Unable to listen on socket %s: %s\n", (char *)ast_config_AST_SOCKET, strerror(errno));
00404       close(ast_socket);
00405       ast_socket = -1;
00406       return -1;
00407    }
00408    ast_register_verbose(network_verboser);
00409    ast_pthread_create(&lthread, NULL, listener, NULL);
00410    return 0;
00411 }
00412 
00413 static int ast_tryconnect(void)
00414 {
00415    struct sockaddr_un sun;
00416    int res;
00417    ast_consock = socket(PF_LOCAL, SOCK_STREAM, 0);
00418    if (ast_consock < 0) {
00419       ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno));
00420       return 0;
00421    }
00422    memset(&sun, 0, sizeof(sun));
00423    sun.sun_family = AF_LOCAL;
00424    strncpy(sun.sun_path, (char *)ast_config_AST_SOCKET, sizeof(sun.sun_path)-1);
00425    res = connect(ast_consock, (struct sockaddr *)&sun, sizeof(sun));
00426    if (res) {
00427       close(ast_consock);
00428       ast_consock = -1;
00429       return 0;
00430    } else
00431       return 1;
00432 }
00433 
00434 static void urg_handler(int num)
00435 {
00436    /* Called by soft_hangup to interrupt the poll, read, or other
00437       system call.  We don't actually need to do anything though.  */
00438    /* Cannot EVER ast_log from within a signal handler */
00439    if (option_debug) 
00440       printf("Urgent handler\n");
00441    signal(num, urg_handler);
00442    return;
00443 }
00444 
00445 static void hup_handler(int num)
00446 {
00447    if (option_verbose > 1) 
00448       printf("Received HUP signal -- Reloading configs\n");
00449    if (restartnow)
00450       execvp(_argv[0], _argv);
00451    /* XXX This could deadlock XXX */
00452    ast_module_reload(NULL);
00453 }
00454 
00455 static void child_handler(int sig)
00456 {
00457    /* Must not ever ast_log or ast_verbose within signal handler */
00458    int n, status;
00459 
00460    /*
00461     * Reap all dead children -- not just one
00462     */
00463    for (n = 0; wait4(-1, &status, WNOHANG, NULL) > 0; n++)
00464       ;
00465    if (n == 0 && option_debug)   
00466       printf("Huh?  Child handler, but nobody there?\n");
00467 }
00468 
00469 static void set_title(char *text)
00470 {
00471    /* Set an X-term or screen title */
00472    if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
00473       fprintf(stdout, "\033]2;%s\007", text);
00474 }
00475 
00476 static void set_icon(char *text)
00477 {
00478    if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
00479       fprintf(stdout, "\033]1;%s\007", text);
00480 }
00481 
00482 static int set_priority(int pri)
00483 {
00484    struct sched_param sched;
00485    memset(&sched, 0, sizeof(sched));
00486    /* We set ourselves to a high priority, that we might pre-empt everything
00487       else.  If your PBX has heavy activity on it, this is a good thing.  */
00488 #ifdef __linux__
00489    if (pri) {  
00490       sched.sched_priority = 10;
00491       if (sched_setscheduler(0, SCHED_RR, &sched)) {
00492          ast_log(LOG_WARNING, "Unable to set high priority\n");
00493          return -1;
00494       } else
00495          if (option_verbose)
00496             ast_verbose("Set to realtime thread\n");
00497    } else {
00498       sched.sched_priority = 0;
00499       if (sched_setscheduler(0, SCHED_OTHER, &sched)) {
00500          ast_log(LOG_WARNING, "Unable to set normal priority\n");
00501          return -1;
00502       }
00503    }
00504 #else
00505    if (pri) {
00506       if (setpriority(PRIO_PROCESS, 0, -10) == -1) {
00507          ast_log(LOG_WARNING, "Unable to set high priority\n");
00508          return -1;
00509       } else
00510          if (option_verbose)
00511             ast_verbose("Set to high priority\n");
00512    } else {
00513       if (setpriority(PRIO_PROCESS, 0, 0) == -1) {
00514          ast_log(LOG_WARNING, "Unable to set normal priority\n");
00515          return -1;
00516       }
00517    }
00518 #endif
00519    return 0;
00520 }
00521 
00522 static void ast_run_atexits(void)
00523 {
00524    struct ast_atexit *ae;
00525    ast_mutex_lock(&atexitslock);
00526    ae = atexits;
00527    while(ae) {
00528       if (ae->func) 
00529          ae->func();
00530       ae = ae->next;
00531    }
00532    ast_mutex_unlock(&atexitslock);
00533 }
00534 
00535 static void quit_handler(int num, int nice, int safeshutdown, int restart)
00536 {
00537    char filename[80] = "";
00538    time_t s,e;
00539    int x;
00540    if (safeshutdown) {
00541       shuttingdown = 1;
00542       if (!nice) {
00543          /* Begin shutdown routine, hanging up active channels */
00544          ast_begin_shutdown(1);
00545          if (option_verbose && option_console)
00546             ast_verbose("Beginning asterisk %s....\n", restart ? "restart" : "shutdown");
00547          time(&s);
00548          for(;;) {
00549             time(&e);
00550             /* Wait up to 15 seconds for all channels to go away */
00551             if ((e - s) > 15)
00552                break;
00553             if (!ast_active_channels())
00554                break;
00555             if (!shuttingdown)
00556                break;
00557             /* Sleep 1/10 of a second */
00558             usleep(100000);
00559          }
00560       } else {
00561          if (nice < 2)
00562             ast_begin_shutdown(0);
00563          if (option_verbose && option_console)
00564             ast_verbose("Waiting for inactivity to perform %s...\n", restart ? "restart" : "halt");
00565          for(;;) {
00566             if (!ast_active_channels())
00567                break;
00568             if (!shuttingdown)
00569                break;
00570             sleep(1);
00571          }
00572       }
00573 
00574       if (!shuttingdown) {
00575          if (option_verbose && option_console)
00576             ast_verbose("Asterisk %s cancelled.\n", restart ? "restart" : "shutdown");
00577          return;
00578       }
00579    }
00580    if (option_console || option_remote) {
00581       if (getenv("HOME")) 
00582          snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
00583       if (!ast_strlen_zero(filename))
00584          ast_el_write_history(filename);
00585       if (el != NULL)
00586          el_end(el);
00587       if (el_hist != NULL)
00588          history_end(el_hist);
00589    }
00590    if (option_verbose)
00591       ast_verbose("Executing last minute cleanups\n");
00592    ast_run_atexits();
00593    /* Called on exit */
00594    if (option_verbose && option_console)
00595       ast_verbose("Asterisk %s ending (%d).\n", ast_active_channels() ? "uncleanly" : "cleanly", num);
00596    else if (option_debug)
00597       ast_log(LOG_DEBUG, "Asterisk ending (%d).\n", num);
00598    manager_event(EVENT_FLAG_SYSTEM, "Shutdown", "Shutdown: %s\r\nRestart: %s\r\n", ast_active_channels() ? "Uncleanly" : "Cleanly", restart ? "True" : "False");
00599    if (ast_socket > -1) {
00600       close(ast_socket);
00601       ast_socket = -1;
00602    }
00603    if (ast_consock > -1)
00604       close(ast_consock);
00605    if (ast_socket > -1)
00606       unlink((char *)ast_config_AST_SOCKET);
00607    if (!option_remote) unlink((char *)ast_config_AST_PID);
00608    printf(term_quit());
00609    if (restart) {
00610       if (option_verbose || option_console)
00611          ast_verbose("Preparing for Asterisk restart...\n");
00612       /* Mark all FD's for closing on exec */
00613       for (x=3;x<32768;x++) {
00614          fcntl(x, F_SETFD, FD_CLOEXEC);
00615       }
00616       if (option_verbose || option_console)
00617          ast_verbose("Restarting Asterisk NOW...\n");
00618       restartnow = 1;
00619 
00620       /* close logger */
00621       close_logger();
00622 
00623       /* If there is a consolethread running send it a SIGHUP 
00624          so it can execvp, otherwise we can do it ourselves */
00625       if (consolethread != AST_PTHREADT_NULL) {
00626          pthread_kill(consolethread, SIGHUP);
00627          /* Give the signal handler some time to complete */
00628          sleep(2);
00629       } else
00630          execvp(_argv[0], _argv);
00631    
00632    } else {
00633       /* close logger */
00634       close_logger();
00635    }
00636    exit(0);
00637 }
00638 
00639 static void __quit_handler(int num)
00640 {
00641    quit_handler(num, 0, 1, 0);
00642 }
00643 
00644 static const char *fix_header(char *outbuf, int maxout, const char *s, char *cmp)
00645 {
00646    const char *c;
00647    if (!strncmp(s, cmp, strlen(cmp))) {
00648       c = s + strlen(cmp);
00649       term_color(outbuf, cmp, COLOR_GRAY, 0, maxout);
00650       return c;
00651    }
00652    return NULL;
00653 }
00654 
00655 static void console_verboser(const char *s, int pos, int replace, int complete)
00656 {
00657    char tmp[80];
00658    const char *c=NULL;
00659    /* Return to the beginning of the line */
00660    if (!pos) {
00661       fprintf(stdout, "\r");
00662       if ((c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_4)) ||
00663          (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_3)) ||
00664          (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_2)) ||
00665          (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_1)))
00666          fputs(tmp, stdout);
00667    }
00668    if (c)
00669       fputs(c + pos,stdout);
00670    else
00671       fputs(s + pos,stdout);
00672    fflush(stdout);
00673    if (complete)
00674    /* Wake up a poll()ing console */
00675       if (option_console && consolethread != AST_PTHREADT_NULL)
00676          pthread_kill(consolethread, SIGURG);
00677 }
00678 
00679 static int ast_all_zeros(char *s)
00680 {
00681    while(*s) {
00682       if (*s > 32)
00683          return 0;
00684       s++;  
00685    }
00686    return 1;
00687 }
00688 
00689 static void consolehandler(char *s)
00690 {
00691    printf(term_end());
00692    fflush(stdout);
00693    /* Called when readline data is available */
00694    if (s && !ast_all_zeros(s))
00695       ast_el_add_history(s);
00696    /* Give the console access to the shell */
00697    if (s) {
00698       /* The real handler for bang */
00699       if (s[0] == '!') {
00700          if (s[1])
00701             ast_safe_system(s+1);
00702          else
00703             ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
00704       } else 
00705       ast_cli_command(STDOUT_FILENO, s);
00706    } else
00707       fprintf(stdout, "\nUse \"quit\" to exit\n");
00708 }
00709 
00710 static int remoteconsolehandler(char *s)
00711 {
00712    int ret = 0;
00713    /* Called when readline data is available */
00714    if (s && !ast_all_zeros(s))
00715       ast_el_add_history(s);
00716    /* Give the console access to the shell */
00717    if (s) {
00718       /* The real handler for bang */
00719       if (s[0] == '!') {
00720          if (s[1])
00721             ast_safe_system(s+1);
00722          else
00723             ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
00724          ret = 1;
00725       }
00726       if ((strncasecmp(s, "quit", 4) == 0 || strncasecmp(s, "exit", 4) == 0) &&
00727           (s[4] == '\0' || isspace(s[4]))) {
00728          quit_handler(0, 0, 0, 0);
00729          ret = 1;
00730       }
00731    } else
00732       fprintf(stdout, "\nUse \"quit\" to exit\n");
00733 
00734    return ret;
00735 }
00736 
00737 static char quit_help[] = 
00738 "Usage: quit\n"
00739 "       Exits Asterisk.\n";
00740 
00741 static char abort_halt_help[] = 
00742 "Usage: abort shutdown\n"
00743 "       Causes Asterisk to abort an executing shutdown or restart, and resume normal\n"
00744 "       call operations.\n";
00745 
00746 static char shutdown_now_help[] = 
00747 "Usage: stop now\n"
00748 "       Shuts down a running Asterisk immediately, hanging up all active calls .\n";
00749 
00750 static char shutdown_gracefully_help[] = 
00751 "Usage: stop gracefully\n"
00752 "       Causes Asterisk to not accept new calls, and exit when all\n"
00753 "       active calls have terminated normally.\n";
00754 
00755 static char shutdown_when_convenient_help[] = 
00756 "Usage: stop when convenient\n"
00757 "       Causes Asterisk to perform a shutdown when all active calls have ended.\n";
00758 
00759 static char restart_now_help[] = 
00760 "Usage: restart now\n"
00761 "       Causes Asterisk to hangup all calls and exec() itself performing a cold.\n"
00762 "       restart.\n";
00763 
00764 static char restart_gracefully_help[] = 
00765 "Usage: restart gracefully\n"
00766 "       Causes Asterisk to stop accepting new calls and exec() itself performing a cold.\n"
00767 "       restart when all active calls have ended.\n";
00768 
00769 static char restart_when_convenient_help[] = 
00770 "Usage: restart when convenient\n"
00771 "       Causes Asterisk to perform a cold restart when all active calls have ended.\n";
00772 
00773 static char bang_help[] =
00774 "Usage: !<command>\n"
00775 "       Executes a given shell command\n";
00776 
00777 #if 0
00778 static int handle_quit(int fd, int argc, char *argv[])
00779 {
00780    if (argc != 1)
00781       return RESULT_SHOWUSAGE;
00782    quit_handler(0, 0, 1, 0);
00783    return RESULT_SUCCESS;
00784 }
00785 #endif
00786 
00787 static int no_more_quit(int fd, int argc, char *argv[])
00788 {
00789    if (argc != 1)
00790       return RESULT_SHOWUSAGE;
00791    ast_cli(fd, "The QUIT and EXIT commands may no longer be used to shutdown the PBX.\n"
00792                "Please use STOP NOW instead, if you wish to shutdown the PBX.\n");
00793    return RESULT_SUCCESS;
00794 }
00795 
00796 static int handle_shutdown_now(int fd, int argc, char *argv[])
00797 {
00798    if (argc != 2)
00799       return RESULT_SHOWUSAGE;
00800    quit_handler(0, 0 /* Not nice */, 1 /* safely */, 0 /* not restart */);
00801    return RESULT_SUCCESS;
00802 }
00803 
00804 static int handle_shutdown_gracefully(int fd, int argc, char *argv[])
00805 {
00806    if (argc != 2)
00807       return RESULT_SHOWUSAGE;
00808    quit_handler(0, 1 /* nicely */, 1 /* safely */, 0 /* no restart */);
00809    return RESULT_SUCCESS;
00810 }
00811 
00812 static int handle_shutdown_when_convenient(int fd, int argc, char *argv[])
00813 {
00814    if (argc != 3)
00815       return RESULT_SHOWUSAGE;
00816    quit_handler(0, 2 /* really nicely */, 1 /* safely */, 0 /* don't restart */);
00817    return RESULT_SUCCESS;
00818 }
00819 
00820 static int handle_restart_now(int fd, int argc, char *argv[])
00821 {
00822    if (argc != 2)
00823       return RESULT_SHOWUSAGE;
00824    quit_handler(0, 0 /* not nicely */, 1 /* safely */, 1 /* restart */);
00825    return RESULT_SUCCESS;
00826 }
00827 
00828 static int handle_restart_gracefully(int fd, int argc, char *argv[])
00829 {
00830    if (argc != 2)
00831       return RESULT_SHOWUSAGE;
00832    quit_handler(0, 1 /* nicely */, 1 /* safely */, 1 /* restart */);
00833    return RESULT_SUCCESS;
00834 }
00835 
00836 static int handle_restart_when_convenient(int fd, int argc, char *argv[])
00837 {
00838    if (argc != 3)
00839       return RESULT_SHOWUSAGE;
00840    quit_handler(0, 2 /* really nicely */, 1 /* safely */, 1 /* restart */);
00841    return RESULT_SUCCESS;
00842 }
00843 
00844 static int handle_abort_halt(int fd, int argc, char *argv[])
00845 {
00846    if (argc != 2)
00847       return RESULT_SHOWUSAGE;
00848    ast_cancel_shutdown();
00849    shuttingdown = 0;
00850    return RESULT_SUCCESS;
00851 }
00852 
00853 static int handle_bang(int fd, int argc, char *argv[])
00854 {
00855    return RESULT_SUCCESS;
00856 }
00857 
00858 #define ASTERISK_PROMPT "*CLI> "
00859 
00860 #define ASTERISK_PROMPT2 "%s*CLI> "
00861 
00862 static struct ast_cli_entry aborthalt = { { "abort", "halt", NULL }, handle_abort_halt, "Cancel a running halt", abort_halt_help };
00863 
00864 static struct ast_cli_entry quit =  { { "quit", NULL }, no_more_quit, "Exit Asterisk", quit_help };
00865 static struct ast_cli_entry astexit =  { { "exit", NULL }, no_more_quit, "Exit Asterisk", quit_help };
00866 
00867 static struct ast_cli_entry astshutdownnow =    { { "stop", "now", NULL }, handle_shutdown_now, "Shut down Asterisk immediately", shutdown_now_help };
00868 static struct ast_cli_entry astshutdowngracefully =   { { "stop", "gracefully", NULL }, handle_shutdown_gracefully, "Gracefully shut down Asterisk", shutdown_gracefully_help };
00869 static struct ast_cli_entry astshutdownwhenconvenient =  { { "stop", "when","convenient", NULL }, handle_shutdown_when_convenient, "Shut down Asterisk at empty call volume", shutdown_when_convenient_help };
00870 static struct ast_cli_entry astrestartnow =  { { "restart", "now", NULL }, handle_restart_now, "Restart Asterisk immediately", restart_now_help };
00871 static struct ast_cli_entry astrestartgracefully =    { { "restart", "gracefully", NULL }, handle_restart_gracefully, "Restart Asterisk gracefully", restart_gracefully_help };
00872 static struct ast_cli_entry astrestartwhenconvenient=    { { "restart", "when", "convenient", NULL }, handle_restart_when_convenient, "Restart Asterisk at empty call volume", restart_when_convenient_help };
00873 static struct ast_cli_entry astbang = { { "!", NULL }, handle_bang, "Execute a shell command", bang_help };
00874 
00875 static int ast_el_read_char(EditLine *el, char *cp)
00876 {
00877    int num_read=0;
00878    int lastpos=0;
00879    struct pollfd fds[2];
00880    int res;
00881    int max;
00882    char buf[512];
00883 
00884    for (;;) {
00885       max = 1;
00886       fds[0].fd = ast_consock;
00887       fds[0].events = POLLIN;
00888       if (!option_exec) {
00889          fds[1].fd = STDIN_FILENO;
00890          fds[1].events = POLLIN;
00891          max++;
00892       }
00893       res = poll(fds, max, -1);
00894       if (res < 0) {
00895          if (errno == EINTR)
00896             continue;
00897          ast_log(LOG_ERROR, "poll failed: %s\n", strerror(errno));
00898          break;
00899       }
00900 
00901       if (!option_exec && fds[1].revents) {
00902          num_read = read(STDIN_FILENO, cp, 1);
00903          if (num_read < 1) {
00904             break;
00905          } else 
00906             return (num_read);
00907       }
00908       if (fds[0].revents) {
00909          res = read(ast_consock, buf, sizeof(buf) - 1);
00910          /* if the remote side disappears exit */
00911          if (res < 1) {
00912             fprintf(stderr, "\nDisconnected from Asterisk server\n");
00913             if (!option_reconnect) {
00914                quit_handler(0, 0, 0, 0);
00915             } else {
00916                int tries;
00917                int reconnects_per_second = 20;
00918                fprintf(stderr, "Attempting to reconnect for 30 seconds\n");
00919                for (tries=0;tries<30 * reconnects_per_second;tries++) {
00920                   if (ast_tryconnect()) {
00921                      fprintf(stderr, "Reconnect succeeded after %.3f seconds\n", 1.0 / reconnects_per_second * tries);
00922                      printf(term_quit());
00923                      WELCOME_MESSAGE;
00924                      break;
00925                   } else {
00926                      usleep(1000000 / reconnects_per_second);
00927                   }
00928                }
00929                if (tries >= 30) {
00930                   fprintf(stderr, "Failed to reconnect for 30 seconds.  Quitting.\n");
00931                   quit_handler(0, 0, 0, 0);
00932                }
00933             }
00934          }
00935 
00936          buf[res] = '\0';
00937 
00938          if (!option_exec && !lastpos)
00939             write(STDOUT_FILENO, "\r", 1);
00940          write(STDOUT_FILENO, buf, res);
00941          if ((buf[res-1] == '\n') || (buf[res-2] == '\n')) {
00942             *cp = CC_REFRESH;
00943             return(1);
00944          } else {
00945             lastpos = 1;
00946          }
00947       }
00948    }
00949 
00950    *cp = '\0';
00951    return (0);
00952 }
00953 
00954 static char *cli_prompt(EditLine *el)
00955 {
00956    static char prompt[200];
00957    char *pfmt;
00958    int color_used=0;
00959    char term_code[20];
00960 
00961    if ((pfmt = getenv("ASTERISK_PROMPT"))) {
00962       char *t = pfmt, *p = prompt;
00963       memset(prompt, 0, sizeof(prompt));
00964       while (*t != '\0' && *p < sizeof(prompt)) {
00965          if (*t == '%') {
00966             char hostname[256];
00967             int i;
00968             struct timeval tv;
00969             struct tm tm;
00970 #ifdef linux
00971             FILE *LOADAVG;
00972 #endif
00973             int fgcolor = COLOR_WHITE, bgcolor = COLOR_BLACK;
00974 
00975             t++;
00976             switch (*t) {
00977                case 'C': /* color */
00978                   t++;
00979                   if (sscanf(t, "%d;%d%n", &fgcolor, &bgcolor, &i) == 2) {
00980                      strncat(p, term_color_code(term_code, fgcolor, bgcolor, sizeof(term_code)),sizeof(prompt) - strlen(prompt) - 1);
00981                      t += i - 1;
00982                   } else if (sscanf(t, "%d%n", &fgcolor, &i) == 1) {
00983                      strncat(p, term_color_code(term_code, fgcolor, 0, sizeof(term_code)),sizeof(prompt) - strlen(prompt) - 1);
00984                      t += i - 1;
00985                   }
00986 
00987                   /* If the color has been reset correctly, then there's no need to reset it later */
00988                   if ((fgcolor == COLOR_WHITE) && (bgcolor == COLOR_BLACK)) {
00989                      color_used = 0;
00990                   } else {
00991                      color_used = 1;
00992                   }
00993                   break;
00994                case 'd': /* date */
00995                   memset(&tm, 0, sizeof(struct tm));
00996                   gettimeofday(&tv, NULL);
00997                   if (localtime_r(&(tv.tv_sec), &tm)) {
00998                      strftime(p, sizeof(prompt) - strlen(prompt), "%Y-%m-%d", &tm);
00999                   }
01000                   break;
01001                case 'h': /* hostname */
01002                   if (!gethostname(hostname, sizeof(hostname) - 1)) {
01003                      strncat(p, hostname, sizeof(prompt) - strlen(prompt) - 1);
01004                   } else {
01005                      strncat(p, "localhost", sizeof(prompt) - strlen(prompt) - 1);
01006                   }
01007                   break;
01008                case 'H': /* short hostname */
01009                   if (!gethostname(hostname, sizeof(hostname) - 1)) {
01010                      for (i=0;i<sizeof(hostname);i++) {
01011                         if (hostname[i] == '.') {
01012                            hostname[i] = '\0';
01013                            break;
01014                         }
01015                      }
01016                      strncat(p, hostname, sizeof(prompt) - strlen(prompt) - 1);
01017                   } else {
01018                      strncat(p, "localhost", sizeof(prompt) - strlen(prompt) - 1);
01019                   }
01020                   break;
01021 #ifdef linux
01022                case 'l': /* load avg */
01023                   t++;
01024                   if ((LOADAVG = fopen("/proc/loadavg", "r"))) {
01025                      float avg1, avg2, avg3;
01026                      int actproc, totproc, npid, which;
01027                      fscanf(LOADAVG, "%f %f %f %d/%d %d",
01028                         &avg1, &avg2, &avg3, &actproc, &totproc, &npid);
01029                      if (sscanf(t, "%d", &which) == 1) {
01030                         switch (which) {
01031                            case 1:
01032                               snprintf(p, sizeof(prompt) - strlen(prompt), "%.2f", avg1);
01033                               break;
01034                            case 2:
01035                               snprintf(p, sizeof(prompt) - strlen(prompt), "%.2f", avg2);
01036                               break;
01037                            case 3:
01038                               snprintf(p, sizeof(prompt) - strlen(prompt), "%.2f", avg3);
01039                               break;
01040                            case 4:
01041                               snprintf(p, sizeof(prompt) - strlen(prompt), "%d/%d", actproc, totproc);
01042                               break;
01043                            case 5:
01044                               snprintf(p, sizeof(prompt) - strlen(prompt), "%d", npid);
01045                               break;
01046                         }
01047                      }
01048                   }
01049                   break;
01050 #endif
01051                case 't': /* time */
01052                   memset(&tm, 0, sizeof(struct tm));
01053                   gettimeofday(&tv, NULL);
01054                   if (localtime_r(&(tv.tv_sec), &tm)) {
01055                      strftime(p, sizeof(prompt) - strlen(prompt), "%H:%M:%S", &tm);
01056                   }
01057                   break;
01058                case '#': /* process console or remote? */
01059                   if (! option_remote) {
01060                      strncat(p, "#", sizeof(prompt) - strlen(prompt) - 1);
01061                   } else {
01062                      strncat(p, ">", sizeof(prompt) - strlen(prompt) - 1);
01063                   }
01064                   break;
01065                case '%': /* literal % */
01066                   strncat(p, "%", sizeof(prompt) - strlen(prompt) - 1);
01067                   break;
01068                case '\0': /* % is last character - prevent bug */
01069                   t--;
01070                   break;
01071             }
01072             while (*p != '\0') {
01073                p++;
01074             }
01075             t++;
01076          } else {
01077             *p = *t;
01078             p++;
01079             t++;
01080          }
01081       }
01082       if (color_used) {
01083          /* Force colors back to normal at end */
01084          term_color_code(term_code, COLOR_WHITE, COLOR_BLACK, sizeof(term_code));
01085          if (strlen(term_code) > sizeof(prompt) - strlen(prompt)) {
01086             strncat(prompt + sizeof(prompt) - strlen(term_code) - 1, term_code, strlen(term_code));
01087          } else {
01088             strncat(p, term_code, sizeof(term_code));
01089          }
01090       }
01091    } else if (remotehostname)
01092       snprintf(prompt, sizeof(prompt), ASTERISK_PROMPT2, remotehostname);
01093    else
01094       snprintf(prompt, sizeof(prompt), ASTERISK_PROMPT);
01095 
01096    return(prompt);   
01097 }
01098 
01099 static char **ast_el_strtoarr(char *buf)
01100 {
01101    char **match_list = NULL, *retstr;
01102    size_t match_list_len;
01103    int matches = 0;
01104 
01105    match_list_len = 1;
01106    while ( (retstr = strsep(&buf, " ")) != NULL) {
01107 
01108       if (!strcmp(retstr, AST_CLI_COMPLETE_EOF))
01109          break;
01110       if (matches + 1 >= match_list_len) {
01111          match_list_len <<= 1;
01112          match_list = realloc(match_list, match_list_len * sizeof(char *));
01113       }
01114 
01115       match_list[matches++] = strdup(retstr);
01116    }
01117 
01118    if (!match_list)
01119       return (char **) NULL;
01120 
01121    if (matches>= match_list_len)
01122       match_list = realloc(match_list, (match_list_len + 1) * sizeof(char *));
01123 
01124    match_list[matches] = (char *) NULL;
01125 
01126    return match_list;
01127 }
01128 
01129 static int ast_el_sort_compare(const void *i1, const void *i2)
01130 {
01131    char *s1, *s2;
01132 
01133    s1 = ((char **)i1)[0];
01134    s2 = ((char **)i2)[0];
01135 
01136    return strcasecmp(s1, s2);
01137 }
01138 
01139 static int ast_cli_display_match_list(char **matches, int len, int max)
01140 {
01141    int i, idx, limit, count;
01142    int screenwidth = 0;
01143    int numoutput = 0, numoutputline = 0;
01144 
01145    screenwidth = ast_get_termcols(STDOUT_FILENO);
01146 
01147    /* find out how many entries can be put on one line, with two spaces between strings */
01148    limit = screenwidth / (max + 2);
01149    if (limit == 0)
01150       limit = 1;
01151 
01152    /* how many lines of output */
01153    count = len / limit;
01154    if (count * limit < len)
01155       count++;
01156 
01157    idx = 1;
01158 
01159    qsort(&matches[0], (size_t)(len + 1), sizeof(char *), ast_el_sort_compare);
01160 
01161    for (; count > 0; count--) {
01162       numoutputline = 0;
01163       for (i=0; i < limit && matches[idx]; i++, idx++) {
01164 
01165          /* Don't print dupes */
01166          if ( (matches[idx+1] != NULL && strcmp(matches[idx], matches[idx+1]) == 0 ) ) {
01167             i--;
01168             free(matches[idx]);
01169             matches[idx] = NULL;
01170             continue;
01171          }
01172 
01173          numoutput++;  numoutputline++;
01174          fprintf(stdout, "%-*s  ", max, matches[idx]);
01175          free(matches[idx]);
01176          matches[idx] = NULL;
01177       }
01178       if (numoutputline > 0)
01179          fprintf(stdout, "\n");
01180    }
01181 
01182    return numoutput;
01183 }
01184 
01185 
01186 static char *cli_complete(EditLine *el, int ch)
01187 {
01188    int len=0;
01189    char *ptr;
01190    int nummatches = 0;
01191    char **matches;
01192    int retval = CC_ERROR;
01193    char buf[2048];
01194    int res;
01195 
01196    LineInfo *lf = (LineInfo *)el_line(el);
01197 
01198    *(char *)lf->cursor = '\0';
01199    ptr = (char *)lf->cursor;
01200    if (ptr) {
01201       while (ptr > lf->buffer) {
01202          if (isspace(*ptr)) {
01203             ptr++;
01204             break;
01205          }
01206          ptr--;
01207       }
01208    }
01209 
01210    len = lf->cursor - ptr;
01211 
01212    if (option_remote) {
01213       snprintf(buf, sizeof(buf),"_COMMAND NUMMATCHES \"%s\" \"%s\"", lf->buffer, ptr); 
01214       fdprint(ast_consock, buf);
01215       res = read(ast_consock, buf, sizeof(buf));
01216       buf[res] = '\0';
01217       nummatches = atoi(buf);
01218 
01219       if (nummatches > 0) {
01220          char *mbuf;
01221          int mlen = 0, maxmbuf = 2048;
01222          /* Start with a 2048 byte buffer */
01223          mbuf = malloc(maxmbuf);
01224          if (!mbuf)
01225             return (char *)(CC_ERROR);
01226          snprintf(buf, sizeof(buf),"_COMMAND MATCHESARRAY \"%s\" \"%s\"", lf->buffer, ptr); 
01227          fdprint(ast_consock, buf);
01228          res = 0;
01229          mbuf[0] = '\0';
01230          while (!strstr(mbuf, AST_CLI_COMPLETE_EOF) && res != -1) {
01231             if (mlen + 1024 > maxmbuf) {
01232                /* Every step increment buffer 1024 bytes */
01233                maxmbuf += 1024;
01234                mbuf = realloc(mbuf, maxmbuf);
01235                if (!mbuf)
01236                   return (char *)(CC_ERROR);
01237             }
01238             /* Only read 1024 bytes at a time */
01239             res = read(ast_consock, mbuf + mlen, 1024);
01240             if (res > 0)
01241                mlen += res;
01242          }
01243          mbuf[mlen] = '\0';
01244 
01245          matches = ast_el_strtoarr(mbuf);
01246          free(mbuf);
01247       } else
01248          matches = (char **) NULL;
01249 
01250 
01251    }  else {
01252 
01253       nummatches = ast_cli_generatornummatches((char *)lf->buffer,ptr);
01254       matches = ast_cli_completion_matches((char *)lf->buffer,ptr);
01255    }
01256 
01257    if (matches) {
01258       int i;
01259       int matches_num, maxlen, match_len;
01260 
01261       if (matches[0][0] != '\0') {
01262          el_deletestr(el, (int) len);
01263          el_insertstr(el, matches[0]);
01264          retval = CC_REFRESH;
01265       }
01266 
01267       if (nummatches == 1) {
01268          /* Found an exact match */
01269          el_insertstr(el, " ");
01270          retval = CC_REFRESH;
01271       } else {
01272          /* Must be more than one match */
01273          for (i=1, maxlen=0; matches[i]; i++) {
01274             match_len = strlen(matches[i]);
01275             if (match_len > maxlen)
01276                maxlen = match_len;
01277          }
01278          matches_num = i - 1;
01279          if (matches_num >1) {
01280             fprintf(stdout, "\n");
01281             ast_cli_display_match_list(matches, nummatches, maxlen);
01282             retval = CC_REDISPLAY;
01283          } else { 
01284             el_insertstr(el," ");
01285             retval = CC_REFRESH;
01286          }
01287       }
01288    free(matches);
01289    }
01290 
01291    return (char *)(long)retval;
01292 }
01293 
01294 static int ast_el_initialize(void)
01295 {
01296    HistEvent ev;
01297    char *editor = getenv("AST_EDITOR");
01298 
01299    if (el != NULL)
01300       el_end(el);
01301    if (el_hist != NULL)
01302       history_end(el_hist);
01303 
01304    el = el_init("asterisk", stdin, stdout, stderr);
01305    el_set(el, EL_PROMPT, cli_prompt);
01306 
01307    el_set(el, EL_EDITMODE, 1);      
01308    el_set(el, EL_EDITOR, editor ? editor : "emacs");     
01309    el_hist = history_init();
01310    if (!el || !el_hist)
01311       return -1;
01312 
01313    /* setup history with 100 entries */
01314    history(el_hist, &ev, H_SETSIZE, 100);
01315 
01316    el_set(el, EL_HIST, history, el_hist);
01317 
01318    el_set(el, EL_ADDFN, "ed-complete", "Complete argument", cli_complete);
01319    /* Bind <tab> to command completion */
01320    el_set(el, EL_BIND, "^I", "ed-complete", NULL);
01321    /* Bind ? to command completion */
01322    el_set(el, EL_BIND, "?", "ed-complete", NULL);
01323    /* Bind ^D to redisplay */
01324    el_set(el, EL_BIND, "^D", "ed-redisplay", NULL);
01325 
01326    return 0;
01327 }
01328 
01329 static int ast_el_add_history(char *buf)
01330 {
01331    HistEvent ev;
01332 
01333    if (el_hist == NULL || el == NULL)
01334       ast_el_initialize();
01335    if (strlen(buf) > 256)
01336       return 0;
01337    return (history(el_hist, &ev, H_ENTER, buf));
01338 }
01339 
01340 static int ast_el_write_history(char *filename)
01341 {
01342    HistEvent ev;
01343 
01344    if (el_hist == NULL || el == NULL)
01345       ast_el_initialize();
01346 
01347    return (history(el_hist, &ev, H_SAVE, filename));
01348 }
01349 
01350 static int ast_el_read_history(char *filename)
01351 {
01352    char buf[256];
01353    FILE *f;
01354    int ret = -1;
01355 
01356    if (el_hist == NULL || el == NULL)
01357       ast_el_initialize();
01358 
01359    if ((f = fopen(filename, "r")) == NULL)
01360       return ret;
01361 
01362    while (!feof(f)) {
01363       fgets(buf, sizeof(buf), f);
01364       if (!strcmp(buf, "_HiStOrY_V2_\n"))
01365          continue;
01366       if (ast_all_zeros(buf))
01367          continue;
01368       if ((ret = ast_el_add_history(buf)) == -1)
01369          break;
01370    }
01371    fclose(f);
01372 
01373    return ret;
01374 }
01375 
01376 static void ast_remotecontrol(char * data)
01377 {
01378    char buf[80];
01379    int res;
01380    char filename[80] = "";
01381    char *hostname;
01382    char *cpid;
01383    char *version;
01384    int pid;
01385    char tmp[80];
01386    char *stringp=NULL;
01387 
01388    char *ebuf;
01389    int num = 0;
01390 
01391    read(ast_consock, buf, sizeof(buf));
01392    if (data)
01393       write(ast_consock, data, strlen(data) + 1);
01394    stringp=buf;
01395    hostname = strsep(&stringp, "/");
01396    cpid = strsep(&stringp, "/");
01397    version = strsep(&stringp, "\n");
01398    if (!version)
01399       version = "<Version Unknown>";
01400    stringp=hostname;
01401    strsep(&stringp, ".");
01402    if (cpid)
01403       pid = atoi(cpid);
01404    else
01405       pid = -1;
01406    snprintf(tmp, sizeof(tmp), "set verbose atleast %d", option_verbose);
01407    fdprint(ast_consock, tmp);
01408    snprintf(tmp, sizeof(tmp), "set debug atleast %d", option_debug);
01409    fdprint(ast_consock, tmp);
01410    ast_verbose("Connected to Asterisk %s currently running on %s (pid = %d)\n", version, hostname, pid);
01411    remotehostname = hostname;
01412    if (getenv("HOME")) 
01413       snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
01414    if (el_hist == NULL || el == NULL)
01415       ast_el_initialize();
01416 
01417    el_set(el, EL_GETCFN, ast_el_read_char);
01418 
01419    if (!ast_strlen_zero(filename))
01420       ast_el_read_history(filename);
01421 
01422    ast_cli_register(&quit);
01423    ast_cli_register(&astexit);
01424 #if 0
01425    ast_cli_register(&astshutdown);
01426 #endif   
01427    if (option_exec && data) {  /* hack to print output then exit if asterisk -rx is used */
01428       char tempchar;
01429       struct pollfd fds[0];
01430       fds[0].fd = ast_consock;
01431       fds[0].events = POLLIN;
01432       fds[0].revents = 0;
01433       while(poll(fds, 1, 100) > 0) {
01434          ast_el_read_char(el, &tempchar);
01435       }
01436       return;
01437    }
01438    for(;;) {
01439       ebuf = (char *)el_gets(el, &num);
01440 
01441       if (ebuf && !ast_strlen_zero(ebuf)) {
01442          if (ebuf[strlen(ebuf)-1] == '\n')
01443             ebuf[strlen(ebuf)-1] = '\0';
01444          if (!remoteconsolehandler(ebuf)) {
01445             res = write(ast_consock, ebuf, strlen(ebuf) + 1);
01446             if (res < 1) {
01447                ast_log(LOG_WARNING, "Unable to write: %s\n", strerror(errno));
01448                break;
01449             }
01450          }
01451       }
01452    }
01453    printf("\nDisconnected from Asterisk server\n");
01454 }
01455 
01456 static int show_version(void)
01457 {
01458    printf("Asterisk " ASTERISK_VERSION "\n");
01459    return 0;
01460 }
01461 
01462 static int show_cli_help(void) {
01463    printf("Asterisk " ASTERISK_VERSION ", Copyright (C) 2000-2004, Digium.\n");
01464    printf("Usage: asterisk [OPTIONS]\n");
01465    printf("Valid Options:\n");
01466    printf("   -V              Display version number and exit\n");
01467    printf("   -C <configfile> Use an alternate configuration file\n");
01468    printf("   -G <group>      Run as a group other than the caller\n");
01469    printf("   -U <user>       Run as a user other than the caller\n");
01470    printf("   -c              Provide console CLI\n");
01471    printf("   -d              Enable extra debugging\n");
01472    printf("   -f              Do not fork\n");
01473    printf("   -g              Dump core in case of a crash\n");
01474    printf("   -h              This help screen\n");
01475    printf("   -i              Initializie crypto keys at startup\n");
01476    printf("   -n              Disable console colorization\n");
01477    printf("   -p              Run as pseudo-realtime thread\n");
01478    printf("   -q              Quiet mode (supress output)\n");
01479    printf("   -r              Connect to Asterisk on this machine\n");
01480    printf("   -R              Connect to Asterisk, and attempt to reconnect if disconnected\n");
01481    printf("   -t              Record soundfiles in /tmp and move them where they belong after they are done.\n");
01482    printf("   -v              Increase verbosity (multiple v's = more verbose)\n");
01483    printf("   -x <cmd>        Execute command <cmd> (only valid with -r)\n");
01484    printf("\n");
01485    return 0;
01486 }
01487 
01488 static void ast_readconfig(void) {
01489    struct ast_config *cfg;
01490    struct ast_variable *v;
01491    char *config = ASTCONFPATH;
01492 
01493    if (option_overrideconfig == 1) {
01494       cfg = ast_load((char *)ast_config_AST_CONFIG_FILE);
01495       if (!cfg)
01496          ast_log(LOG_WARNING, "Unable to open specified master config file '%s', using builtin defaults\n", ast_config_AST_CONFIG_FILE);
01497    } else {
01498       cfg = ast_load(config);
01499    }
01500 
01501    /* init with buildtime config */
01502    strncpy((char *)ast_config_AST_CONFIG_DIR,AST_CONFIG_DIR,sizeof(ast_config_AST_CONFIG_DIR)-1);
01503    strncpy((char *)ast_config_AST_SPOOL_DIR,AST_SPOOL_DIR,sizeof(ast_config_AST_SPOOL_DIR)-1);
01504    strncpy((char *)ast_config_AST_MODULE_DIR,AST_MODULE_DIR,sizeof(ast_config_AST_VAR_DIR)-1);
01505    strncpy((char *)ast_config_AST_VAR_DIR,AST_VAR_DIR,sizeof(ast_config_AST_VAR_DIR)-1);
01506    strncpy((char *)ast_config_AST_LOG_DIR,AST_LOG_DIR,sizeof(ast_config_AST_LOG_DIR)-1);
01507    strncpy((char *)ast_config_AST_AGI_DIR,AST_AGI_DIR,sizeof(ast_config_AST_AGI_DIR)-1);
01508    strncpy((char *)ast_config_AST_DB,AST_DB,sizeof(ast_config_AST_DB)-1);
01509    strncpy((char *)ast_config_AST_KEY_DIR,AST_KEY_DIR,sizeof(ast_config_AST_KEY_DIR)-1);
01510    strncpy((char *)ast_config_AST_PID,AST_PID,sizeof(ast_config_AST_PID)-1);
01511    strncpy((char *)ast_config_AST_SOCKET,AST_SOCKET,sizeof(ast_config_AST_SOCKET)-1);
01512    strncpy((char *)ast_config_AST_RUN_DIR,AST_RUN_DIR,sizeof(ast_config_AST_RUN_DIR)-1);
01513    strncpy((char *)ast_config_AST_DATA_DIR,AST_DATA_DIR,sizeof(ast_config_AST_DATA_DIR)-1);
01514    
01515    /* no asterisk.conf? no problem, use buildtime config! */
01516    if (!cfg) {
01517       return;
01518    }
01519    v = ast_variable_browse(cfg, "directories");
01520    while(v) {
01521       if (!strcasecmp(v->name, "astetcdir")) {
01522          strncpy((char *)ast_config_AST_CONFIG_DIR,v->value,sizeof(ast_config_AST_CONFIG_DIR)-1);
01523       } else if (!strcasecmp(v->name, "astspooldir")) {
01524          strncpy((char *)ast_config_AST_SPOOL_DIR,v->value,sizeof(ast_config_AST_SPOOL_DIR)-1);
01525       } else if (!strcasecmp(v->name, "astvarlibdir")) {
01526          strncpy((char *)ast_config_AST_VAR_DIR,v->value,sizeof(ast_config_AST_VAR_DIR)-1);
01527          snprintf((char *)ast_config_AST_DB,sizeof(ast_config_AST_DB),"%s/%s",v->value,"astdb");    
01528       } else if (!strcasecmp(v->name, "astlogdir")) {
01529          strncpy((char *)ast_config_AST_LOG_DIR,v->value,sizeof(ast_config_AST_LOG_DIR)-1);
01530       } else if (!strcasecmp(v->name, "astagidir")) {
01531          strncpy((char *)ast_config_AST_AGI_DIR,v->value,sizeof(ast_config_AST_AGI_DIR)-1);
01532       } else if (!strcasecmp(v->name, "astrundir")) {
01533          snprintf((char *)ast_config_AST_PID,sizeof(ast_config_AST_PID),"%s/%s",v->value,"asterisk.pid");    
01534          snprintf((char *)ast_config_AST_SOCKET,sizeof(ast_config_AST_SOCKET),"%s/%s",v->value,"asterisk.ctl");    
01535          strncpy((char *)ast_config_AST_RUN_DIR,v->value,sizeof(ast_config_AST_RUN_DIR)-1);
01536       } else if (!strcasecmp(v->name, "astmoddir")) {
01537          strncpy((char *)ast_config_AST_MODULE_DIR,v->value,sizeof(ast_config_AST_MODULE_DIR)-1);
01538       }
01539       v = v->next;
01540    }
01541    v = ast_variable_browse(cfg, "options");
01542    while(v) {
01543       if(!strcasecmp(v->name, "verbose")) {
01544          option_verbose= atoi(v->value);
01545       } else if (!strcasecmp(v->name, "debug")) {
01546          option_debug= ast_true(v->value);
01547       } else if (!strcasecmp(v->name, "nofork")) {
01548          option_nofork = ast_true(v->value);
01549       } else if (!strcasecmp(v->name, "quiet")) {
01550          option_quiet = ast_true(v->value);
01551       } else if (!strcasecmp(v->name, "console")) {
01552          option_console = ast_true(v->value);
01553       } else if (!strcasecmp(v->name, "highpriority")) {
01554          option_highpriority = ast_true(v->value);
01555       } else if (!strcasecmp(v->name, "initcrypto")) {
01556          option_initcrypto = ast_true(v->value);
01557       } else if (!strcasecmp(v->name, "nocolor")) {
01558          option_nocolor = ast_true(v->value);
01559       } else if (!strcasecmp(v->name, "dumpcore")) {
01560          option_dumpcore = ast_true(v->value);
01561       } else if (!strcasecmp(v->name, "cache_record_files")) {
01562          option_cache_record_files = ast_true(v->value);
01563       }  else if (!strcasecmp(v->name, "record_cache_dir")) {
01564          strncpy(record_cache_dir,v->value,AST_CACHE_DIR_LEN);
01565       }
01566       v = v->next;
01567    }
01568    ast_destroy(cfg);
01569 }
01570 
01571 int main(int argc, char *argv[])
01572 {
01573    int c;
01574    char filename[80] = "";
01575    char hostname[256];
01576    char tmp[80];
01577    char * xarg = NULL;
01578    int x;
01579    FILE *f;
01580    sigset_t sigs;
01581    int num;
01582    char *buf;
01583    char *runuser=NULL, *rungroup=NULL;
01584 
01585    /* Remember original args for restart */
01586    if (argc > sizeof(_argv) / sizeof(_argv[0]) - 1) {
01587       fprintf(stderr, "Truncating argument size to %d\n", (int)(sizeof(_argv) / sizeof(_argv[0])) - 1);
01588       argc = sizeof(_argv) / sizeof(_argv[0]) - 1;
01589    }
01590    for (x=0;x<argc;x++)
01591       _argv[x] = argv[x];
01592    _argv[x] = NULL;
01593 
01594    /* if the progname is rasterisk consider it a remote console */
01595    if ( argv[0] && (strstr(argv[0], "rasterisk")) != NULL)  {
01596       option_remote++;
01597       option_nofork++;
01598    }
01599    if (gethostname(hostname, sizeof(hostname)))
01600       strncpy(hostname, "<Unknown>", sizeof(hostname)-1);
01601    ast_mainpid = getpid();
01602    ast_ulaw_init();
01603    ast_alaw_init();
01604    callerid_init();
01605    ast_utils_init();
01606    tdd_init();
01607    if (getenv("HOME")) 
01608       snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
01609    /* Check for options */
01610    while((c=getopt(argc, argv, "thfdvVqprRgcinx:U:G:C:")) != -1) {
01611       switch(c) {
01612       case 'd':
01613          option_debug++;
01614          option_nofork++;
01615          break;
01616       case 'c':
01617          option_console++;
01618          option_nofork++;
01619          break;
01620       case 'f':
01621          option_nofork++;
01622          break;
01623       case 'n':
01624          option_nocolor++;
01625          break;
01626       case 'r':
01627          option_remote++;
01628          option_nofork++;
01629          break;
01630       case 'R':
01631          option_remote++;
01632          option_nofork++;
01633          option_reconnect++;
01634          break;
01635       case 'p':
01636          option_highpriority++;
01637          break;
01638       case 'v':
01639          option_verbose++;
01640          option_nofork++;
01641          break;
01642       case 'q':
01643          option_quiet++;
01644          break;
01645       case 't':
01646          option_cache_record_files++;
01647          break;
01648       case 'x':
01649          option_exec++;
01650          xarg = optarg;
01651          break;
01652       case 'C':
01653          strncpy((char *)ast_config_AST_CONFIG_FILE,optarg,sizeof(ast_config_AST_CONFIG_FILE) - 1);
01654          option_overrideconfig++;
01655          break;
01656       case 'i':
01657          option_initcrypto++;
01658          break;
01659       case'g':
01660          option_dumpcore++;
01661          break;
01662       case 'h':
01663          show_cli_help();
01664          exit(0);
01665       case 'V':
01666          show_version();
01667          exit(0);
01668       case 'U':
01669          runuser = optarg;
01670          break;
01671       case 'G':
01672          rungroup = optarg;
01673          break;
01674       case '?':
01675          exit(1);
01676       }
01677    }
01678 
01679    if (option_dumpcore) {
01680       struct rlimit l;
01681       memset(&l, 0, sizeof(l));
01682       l.rlim_cur = RLIM_INFINITY;
01683       l.rlim_max = RLIM_INFINITY;
01684       if (setrlimit(RLIMIT_CORE, &l)) {
01685          ast_log(LOG_WARNING, "Unable to disable core size resource limit: %s\n", strerror(errno));
01686       }
01687    }
01688 
01689    if (rungroup) {
01690       struct group *gr;
01691       gr = getgrnam(rungroup);
01692       if (!gr) {
01693          ast_log(LOG_WARNING, "No such group '%s'!\n", rungroup);
01694          exit(1);
01695       }
01696       if (setgid(gr->gr_gid)) {
01697          ast_log(LOG_WARNING, "Unable to setgid to %d (%s)\n", gr->gr_gid, rungroup);
01698          exit(1);
01699       }
01700       if (option_verbose)
01701          ast_verbose("Running as group '%s'\n", rungroup);
01702    }
01703 
01704    if (set_priority(option_highpriority)) {
01705       exit(1);
01706    }
01707    if (runuser) {
01708       struct passwd *pw;
01709       pw = getpwnam(runuser);
01710       if (!pw) {
01711          ast_log(LOG_WARNING, "No such user '%s'!\n", runuser);
01712          exit(1);
01713       }
01714       if (setuid(pw->pw_uid)) {
01715          ast_log(LOG_WARNING, "Unable to setuid to %d (%s)\n", pw->pw_uid, runuser);
01716          exit(1);
01717       }
01718       if (option_verbose)
01719          ast_verbose("Running as user '%s'\n", runuser);
01720    }
01721 
01722    term_init();
01723    printf(term_end());
01724    fflush(stdout);
01725 
01726    if (option_console && !option_verbose) 
01727       ast_verbose("[ Reading Master Configuration ]");
01728    ast_readconfig();
01729 
01730    if (option_console && !option_verbose) 
01731       ast_verbose("[ Initializing Custom Configuration Options]");
01732    /* custom config setup */
01733    register_config_cli();
01734    read_ast_cust_config();
01735    
01736 
01737    if (option_console) {
01738       if (el_hist == NULL || el == NULL)
01739          ast_el_initialize();
01740 
01741       if (!ast_strlen_zero(filename))
01742          ast_el_read_history(filename);
01743    }
01744 
01745    if (ast_tryconnect()) {
01746       /* One is already running */
01747       if (option_remote) {
01748          if (option_exec) {
01749             ast_remotecontrol(xarg);
01750             quit_handler(0, 0, 0, 0);
01751             exit(0);
01752          }
01753          printf(term_quit());
01754          ast_register_verbose(console_verboser);
01755          WELCOME_MESSAGE;
01756          ast_remotecontrol(NULL);
01757          quit_handler(0, 0, 0, 0);
01758          exit(0);
01759       } else {
01760          ast_log(LOG_ERROR, "Asterisk already running on %s.  Use 'asterisk -r' to connect.\n", (char *)ast_config_AST_SOCKET);
01761          printf(term_quit());
01762          exit(1);
01763       }
01764    } else if (option_remote || option_exec) {
01765       ast_log(LOG_ERROR, "Unable to connect to remote asterisk\n");
01766       printf(term_quit());
01767       exit(1);
01768    }
01769    /* Blindly write pid file since we couldn't connect */
01770    unlink((char *)ast_config_AST_PID);
01771    f = fopen((char *)ast_config_AST_PID, "w");
01772    if (f) {
01773       fprintf(f, "%d\n", getpid());
01774       fclose(f);
01775    } else
01776       ast_log(LOG_WARNING, "Unable to open pid file '%s': %s\n", (char *)ast_config_AST_PID, strerror(errno));
01777 
01778    if (!option_verbose && !option_debug && !option_nofork && !option_console) {
01779       daemon(0,0);
01780       /* Blindly re-write pid file since we are forking */
01781       unlink((char *)ast_config_AST_PID);
01782       f = fopen((char *)ast_config_AST_PID, "w");
01783       if (f) {
01784          fprintf(f, "%d\n", getpid());
01785          fclose(f);
01786       } else
01787          ast_log(LOG_WARNING, "Unable to open pid file '%s': %s\n", (char *)ast_config_AST_PID, strerror(errno));
01788    }
01789 
01790    /* Test recursive mutex locking. */
01791    if (test_for_thread_safety())
01792       ast_verbose("Warning! Asterisk is not thread safe.\n");
01793 
01794    ast_makesocket();
01795    sigemptyset(&sigs);
01796    sigaddset(&sigs, SIGHUP);
01797    sigaddset(&sigs, SIGTERM);
01798    sigaddset(&sigs, SIGINT);
01799    sigaddset(&sigs, SIGPIPE);
01800    sigaddset(&sigs, SIGWINCH);
01801    pthread_sigmask(SIG_BLOCK, &sigs, NULL);
01802    if (option_console || option_verbose || option_remote)
01803       ast_register_verbose(console_verboser);
01804    /* Print a welcome message if desired */
01805    if (option_verbose || option_console) {
01806       WELCOME_MESSAGE;
01807    }
01808    if (option_console && !option_verbose) 
01809       ast_verbose("[ Booting...");
01810 
01811    signal(SIGURG, urg_handler);
01812    signal(SIGINT, __quit_handler);
01813    signal(SIGTERM, __quit_handler);
01814    signal(SIGHUP, hup_handler);
01815    signal(SIGCHLD, child_handler);
01816    signal(SIGPIPE, SIG_IGN);
01817 
01818    if (init_logger()) {
01819       printf(term_quit());
01820       exit(1);
01821    }
01822    if (init_manager()) {
01823       printf(term_quit());
01824       exit(1);
01825    }
01826    ast_rtp_init();
01827    if (ast_image_init()) {
01828       printf(term_quit());
01829       exit(1);
01830    }
01831    if (ast_file_init()) {
01832       printf(term_quit());
01833       exit(1);
01834    }
01835    if (load_pbx()) {
01836       printf(term_quit());
01837       exit(1);
01838    }
01839    if (load_modules()) {
01840       printf(term_quit());
01841       exit(1);
01842    }
01843    if (init_framer()) {
01844       printf(term_quit());
01845       exit(1);
01846    }
01847    if (astdb_init()) {
01848       printf(term_quit());
01849       exit(1);
01850    }
01851    if (ast_enum_init()) {
01852       printf(term_quit());
01853       exit(1);
01854    }
01855    /* sync cust config and reload some internals in case a custom config handler binded to them */
01856    read_ast_cust_config();
01857    reload_logger(0);
01858    reload_manager();
01859    ast_enum_reload();
01860    ast_rtp_reload();
01861 
01862 
01863    /* We might have the option of showing a console, but for now just
01864       do nothing... */
01865    if (option_console && !option_verbose)
01866       ast_verbose(" ]\n");
01867    if (option_verbose || option_console)
01868       ast_verbose(term_color(tmp, "Asterisk Ready.\n", COLOR_BRWHITE, COLOR_BLACK, sizeof(tmp)));
01869    if (option_nofork)
01870       consolethread = pthread_self();
01871    fully_booted = 1;
01872    pthread_sigmask(SIG_UNBLOCK, &sigs, NULL);
01873 #ifdef __AST_DEBUG_MALLOC
01874    __ast_mm_init();
01875 #endif   
01876    time(&ast_startuptime);
01877    ast_cli_register(&astshutdownnow);
01878    ast_cli_register(&astshutdowngracefully);
01879    ast_cli_register(&astrestartnow);
01880    ast_cli_register(&astrestartgracefully);
01881    ast_cli_register(&astrestartwhenconvenient);
01882    ast_cli_register(&astshutdownwhenconvenient);
01883    ast_cli_register(&aborthalt);
01884    ast_cli_register(&astbang);
01885    if (option_console) {
01886       /* Console stuff now... */
01887       /* Register our quit function */
01888       char title[256];
01889       set_icon("Asterisk");
01890       snprintf(title, sizeof(title), "Asterisk Console on '%s' (pid %d)", hostname, ast_mainpid);
01891       set_title(title);
01892        ast_cli_register(&quit);
01893        ast_cli_register(&astexit);
01894 
01895       for (;;) {
01896          buf = (char *)el_gets(el, &num);
01897          if (buf) {
01898             if (buf[strlen(buf)-1] == '\n')
01899                buf[strlen(buf)-1] = '\0';
01900 
01901             consolehandler((char *)buf);
01902          } else {
01903             if (option_remote)
01904                ast_cli(STDOUT_FILENO, "\nUse EXIT or QUIT to exit the asterisk console\n");
01905          }
01906       }
01907 
01908    } else {
01909       /* Do nothing */
01910       for(;;) 
01911          poll(NULL,0, -1);
01912    }
01913    return 0;
01914 }

Generated on Thu Oct 28 11:32:52 2004 for Asterisk by doxygen1.2.15