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