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

Generated on Sat Jun 12 16:40:57 2004 for Asterisk by doxygen 1.3.7