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