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

Generated on Wed Aug 10 11:36:31 2005 for Asterisk by  doxygen 1.4.4