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