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

asterisk.c

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

Generated on Tue Aug 17 16:13:52 2004 for Asterisk by doxygen 1.3.8