Main Page | Alphabetical List | Data Structures | File List | Data Fields | Globals

asterisk.c

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

Generated on Sun Apr 18 23:33:48 2004 for Asterisk by doxygen 1.3.6-20040222