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

Generated on Fri Sep 24 21:03:45 2004 for Asterisk by doxygen 1.3.8