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

Generated on Wed Mar 16 20:08:34 2005 for Asterisk by  doxygen 1.4.0