![]() |
Home page |
Mailing list |
Docs
Asterisk developer's documentation :: Codename Pineapple
asterisk.c
Go to the documentation of this file.
00001 /* 00002 * Asterisk -- An open source telephony toolkit. 00003 * 00004 * Copyright (C) 1999 - 2006, Digium, Inc. 00005 * 00006 * Mark Spencer <markster@digium.com> 00007 * 00008 * See http://www.asterisk.org for more information about 00009 * the Asterisk project. Please do not directly contact 00010 * any of the maintainers of this project for assistance; 00011 * the project provides a web site, mailing lists and IRC 00012 * channels for your use. 00013 * 00014 * This program is free software, distributed under the terms of 00015 * the GNU General Public License Version 2. See the LICENSE file 00016 * at the top of the source tree. 00017 */ 00018 00019 00020 /* Doxygenified Copyright Header */ 00021 /*! 00022 * \mainpage Asterisk -- An Open Source Telephony Toolkit 00023 * 00024 * \par Developer Documentation for Asterisk 00025 * This is the main developer documentation for Asterisk. It is 00026 * generated by running "make progdocs". 00027 * \par Additional documentation 00028 * \arg \ref DevDoc 00029 * \arg \ref ConfigFiles 00030 * 00031 * \section copyright Copyright and author 00032 * 00033 * Copyright (C) 1999 - 2006, Digium, Inc. 00034 * Asterisk is a trade mark registered by Digium, Inc. 00035 * 00036 * \author Mark Spencer <markster@digium.com> 00037 * Also see \ref AstCREDITS 00038 * 00039 * \section license License 00040 * See http://www.asterisk.org for more information about 00041 * the Asterisk project. Please do not directly contact 00042 * any of the maintainers of this project for assistance; 00043 * the project provides a web site, mailing lists and IRC 00044 * channels for your use. 00045 * 00046 * This program is free software, distributed under the terms of 00047 * the GNU General Public License Version 2. See the LICENSE file 00048 * at the top of the source tree. 00049 * 00050 * \verbinclude LICENSE 00051 * 00052 */ 00053 00054 /*! \file 00055 \brief Top level source file for Asterisk - the Open Source PBX. Implementation 00056 of PBX core functions and CLI interface. 00057 00058 */ 00059 00060 #include "asterisk.h" 00061 00062 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 53128 $") 00063 00064 #include <unistd.h> 00065 #include <stdlib.h> 00066 #include <sys/time.h> 00067 #include <fcntl.h> 00068 #include <stdio.h> 00069 #include <signal.h> 00070 #include <sched.h> 00071 #include <sys/socket.h> 00072 #include <sys/un.h> 00073 #include <sys/wait.h> 00074 #include <string.h> 00075 #include <errno.h> 00076 #include <ctype.h> 00077 #include <sys/resource.h> 00078 #include <grp.h> 00079 #include <pwd.h> 00080 #include <sys/stat.h> 00081 #ifdef linux 00082 #include <sys/prctl.h> 00083 #ifdef HAVE_CAP 00084 #include <sys/capability.h> 00085 #endif /* HAVE_CAP */ 00086 #endif /* linux */ 00087 #include <regex.h> 00088 00089 #if defined(__FreeBSD__) || defined( __NetBSD__ ) || defined(SOLARIS) 00090 #include <netdb.h> 00091 #if defined(SOLARIS) 00092 int daemon(int, int); /* defined in libresolv of all places */ 00093 #endif 00094 #endif 00095 00096 #include "asterisk/logger.h" 00097 #include "asterisk/options.h" 00098 #include "asterisk/cli.h" 00099 #include "asterisk/channel.h" 00100 #include "asterisk/ulaw.h" 00101 #include "asterisk/alaw.h" 00102 #include "asterisk/callerid.h" 00103 #include "asterisk/image.h" 00104 #include "asterisk/tdd.h" 00105 #include "asterisk/term.h" 00106 #include "asterisk/manager.h" 00107 #include "asterisk/cdr.h" 00108 #include "asterisk/pbx.h" 00109 #include "asterisk/enum.h" 00110 #include "asterisk/rtp.h" 00111 #include "asterisk/http.h" 00112 #include "asterisk/udptl.h" 00113 #include "asterisk/app.h" 00114 #include "asterisk/lock.h" 00115 #include "asterisk/utils.h" 00116 #include "asterisk/file.h" 00117 #include "asterisk/io.h" 00118 #include "asterisk/lock.h" 00119 #include "editline/histedit.h" 00120 #include "asterisk/config.h" 00121 #include "asterisk/version.h" 00122 #include "asterisk/linkedlists.h" 00123 #include "asterisk/devicestate.h" 00124 00125 #include "asterisk/doxyref.h" /* Doxygen documentation */ 00126 00127 #include "../defaults.h" 00128 00129 #ifndef AF_LOCAL 00130 #define AF_LOCAL AF_UNIX 00131 #define PF_LOCAL PF_UNIX 00132 #endif 00133 00134 #define AST_MAX_CONNECTS 128 00135 #define NUM_MSGS 64 00136 00137 /*! \brief Welcome message when starting a CLI interface */ 00138 #define WELCOME_MESSAGE \ 00139 ast_verbose("Asterisk " ASTERISK_VERSION ", Copyright (C) 1999 - 2006 Digium, Inc. and others.\n"); \ 00140 ast_verbose("Created by Mark Spencer <markster@digium.com>\n"); \ 00141 ast_verbose("Asterisk comes with ABSOLUTELY NO WARRANTY; type 'core show warranty' for details.\n"); \ 00142 ast_verbose("This is free software, with components licensed under the GNU General Public\n"); \ 00143 ast_verbose("License version 2 and other licenses; you are welcome to redistribute it under\n"); \ 00144 ast_verbose("certain conditions. Type 'core show license' for details.\n"); \ 00145 ast_verbose("=========================================================================\n"); \ 00146 ast_verbose("NOTE: This is a development version of Asterisk, and should not be used in\n"); \ 00147 ast_verbose("production installations.\n"); 00148 00149 /*! \defgroup main_options Main Configuration Options 00150 \brief Main configuration options from \ref Config_ast "asterisk.conf" or 00151 the operating system command line when starting Asterisk 00152 Some of them can be changed in the CLI 00153 */ 00154 /*! @{ */ 00155 00156 struct ast_flags ast_options = { AST_DEFAULT_OPTIONS }; 00157 00158 int option_verbose; /*!< Verbosity level */ 00159 int option_debug; /*!< Debug level */ 00160 00161 double option_maxload; /*!< Max load avg on system */ 00162 int option_maxcalls; /*!< Max number of active calls */ 00163 00164 /*! @} */ 00165 00166 char record_cache_dir[AST_CACHE_DIR_LEN] = AST_TMP_DIR; 00167 char debug_filename[AST_FILENAME_MAX] = ""; 00168 00169 static int ast_socket = -1; /*!< UNIX Socket for allowing remote control */ 00170 static int ast_consock = -1; /*!< UNIX Socket for controlling another asterisk */ 00171 pid_t ast_mainpid; 00172 struct console { 00173 int fd; /*!< File descriptor */ 00174 int p[2]; /*!< Pipe */ 00175 pthread_t t; /*!< Thread of handler */ 00176 int mute; /*!< Is the console muted for logs */ 00177 }; 00178 00179 struct ast_atexit { 00180 void (*func)(void); 00181 AST_LIST_ENTRY(ast_atexit) list; 00182 }; 00183 00184 static AST_LIST_HEAD_STATIC(atexits, ast_atexit); 00185 00186 time_t ast_startuptime; 00187 time_t ast_lastreloadtime; 00188 00189 static History *el_hist; 00190 static EditLine *el; 00191 static char *remotehostname; 00192 00193 struct console consoles[AST_MAX_CONNECTS]; 00194 00195 char defaultlanguage[MAX_LANGUAGE] = DEFAULT_LANGUAGE; 00196 00197 static int ast_el_add_history(char *); 00198 static int ast_el_read_history(char *); 00199 static int ast_el_write_history(char *); 00200 00201 char ast_config_AST_CONFIG_DIR[PATH_MAX]; 00202 char ast_config_AST_CONFIG_FILE[PATH_MAX]; 00203 char ast_config_AST_MODULE_DIR[PATH_MAX]; 00204 char ast_config_AST_SPOOL_DIR[PATH_MAX]; 00205 char ast_config_AST_MONITOR_DIR[PATH_MAX]; 00206 char ast_config_AST_VAR_DIR[PATH_MAX]; 00207 char ast_config_AST_DATA_DIR[PATH_MAX]; 00208 char ast_config_AST_LOG_DIR[PATH_MAX]; 00209 char ast_config_AST_AGI_DIR[PATH_MAX]; 00210 char ast_config_AST_DB[PATH_MAX]; 00211 char ast_config_AST_KEY_DIR[PATH_MAX]; 00212 char ast_config_AST_PID[PATH_MAX]; 00213 char ast_config_AST_SOCKET[PATH_MAX]; 00214 char ast_config_AST_RUN_DIR[PATH_MAX]; 00215 char ast_config_AST_RUN_USER[PATH_MAX]; 00216 char ast_config_AST_RUN_GROUP[PATH_MAX]; 00217 char ast_config_AST_CTL_PERMISSIONS[PATH_MAX]; 00218 char ast_config_AST_CTL_OWNER[PATH_MAX] = "\0"; 00219 char ast_config_AST_CTL_GROUP[PATH_MAX] = "\0"; 00220 char ast_config_AST_CTL[PATH_MAX] = "asterisk.ctl"; 00221 char ast_config_AST_SYSTEM_NAME[20] = ""; 00222 00223 extern const char *ast_build_hostname; 00224 extern const char *ast_build_kernel; 00225 extern const char *ast_build_machine; 00226 extern const char *ast_build_os; 00227 extern const char *ast_build_date; 00228 extern const char *ast_build_user; 00229 00230 static char *_argv[256]; 00231 static int shuttingdown; 00232 static int restartnow; 00233 static pthread_t consolethread = AST_PTHREADT_NULL; 00234 00235 static char randompool[256]; 00236 00237 static unsigned int need_reload; 00238 00239 #if !defined(LOW_MEMORY) 00240 struct file_version { 00241 AST_LIST_ENTRY(file_version) list; 00242 const char *file; 00243 char *version; 00244 }; 00245 00246 static AST_LIST_HEAD_STATIC(file_versions, file_version); 00247 00248 void ast_register_file_version(const char *file, const char *version) 00249 { 00250 struct file_version *new; 00251 char *work; 00252 size_t version_length; 00253 00254 work = ast_strdupa(version); 00255 work = ast_strip(ast_strip_quoted(work, "$", "$")); 00256 version_length = strlen(work) + 1; 00257 00258 if (!(new = ast_calloc(1, sizeof(*new) + version_length))) 00259 return; 00260 00261 new->file = file; 00262 new->version = (char *) new + sizeof(*new); 00263 memcpy(new->version, work, version_length); 00264 AST_LIST_LOCK(&file_versions); 00265 AST_LIST_INSERT_HEAD(&file_versions, new, list); 00266 AST_LIST_UNLOCK(&file_versions); 00267 } 00268 00269 void ast_unregister_file_version(const char *file) 00270 { 00271 struct file_version *find; 00272 00273 AST_LIST_LOCK(&file_versions); 00274 AST_LIST_TRAVERSE_SAFE_BEGIN(&file_versions, find, list) { 00275 if (!strcasecmp(find->file, file)) { 00276 AST_LIST_REMOVE_CURRENT(&file_versions, list); 00277 break; 00278 } 00279 } 00280 AST_LIST_TRAVERSE_SAFE_END; 00281 AST_LIST_UNLOCK(&file_versions); 00282 if (find) 00283 free(find); 00284 } 00285 00286 struct thread_list_t { 00287 AST_LIST_ENTRY(thread_list_t) list; 00288 char *name; 00289 pthread_t id; 00290 }; 00291 00292 static AST_LIST_HEAD_STATIC(thread_list, thread_list_t); 00293 00294 static const char show_threads_help[] = 00295 "Usage: core show threads\n" 00296 " List threads currently active in the system.\n"; 00297 00298 void ast_register_thread(char *name) 00299 { 00300 struct thread_list_t *new = ast_calloc(1, sizeof(*new)); 00301 00302 if (!new) 00303 return; 00304 new->id = pthread_self(); 00305 new->name = name; /* steal the allocated memory for the thread name */ 00306 AST_LIST_LOCK(&thread_list); 00307 AST_LIST_INSERT_HEAD(&thread_list, new, list); 00308 AST_LIST_UNLOCK(&thread_list); 00309 } 00310 00311 void ast_unregister_thread(void *id) 00312 { 00313 struct thread_list_t *x; 00314 00315 AST_LIST_LOCK(&thread_list); 00316 AST_LIST_TRAVERSE_SAFE_BEGIN(&thread_list, x, list) { 00317 if ((void *) x->id == id) { 00318 AST_LIST_REMOVE_CURRENT(&thread_list, list); 00319 break; 00320 } 00321 } 00322 AST_LIST_TRAVERSE_SAFE_END; 00323 AST_LIST_UNLOCK(&thread_list); 00324 if (x) { 00325 free(x->name); 00326 free(x); 00327 } 00328 } 00329 00330 static int handle_show_threads(int fd, int argc, char *argv[]) 00331 { 00332 int count = 0; 00333 struct thread_list_t *cur; 00334 00335 AST_LIST_LOCK(&thread_list); 00336 AST_LIST_TRAVERSE(&thread_list, cur, list) { 00337 ast_cli(fd, "%p %s\n", (void *)cur->id, cur->name); 00338 count++; 00339 } 00340 AST_LIST_UNLOCK(&thread_list); 00341 ast_cli(fd, "%d threads listed.\n", count); 00342 return 0; 00343 } 00344 00345 struct profile_entry { 00346 const char *name; 00347 uint64_t scale; /* if non-zero, values are scaled by this */ 00348 int64_t mark; 00349 int64_t value; 00350 int64_t events; 00351 }; 00352 00353 struct profile_data { 00354 int entries; 00355 int max_size; 00356 struct profile_entry e[0]; 00357 }; 00358 00359 static struct profile_data *prof_data; 00360 00361 /*! \brief allocates a counter with a given name and scale. 00362 * \return Returns the identifier of the counter. 00363 */ 00364 int ast_add_profile(const char *name, uint64_t scale) 00365 { 00366 int l = sizeof(struct profile_data); 00367 int n = 10; /* default entries */ 00368 00369 if (prof_data == NULL) { 00370 prof_data = ast_calloc(1, l + n*sizeof(struct profile_entry)); 00371 if (prof_data == NULL) 00372 return -1; 00373 prof_data->entries = 0; 00374 prof_data->max_size = n; 00375 } 00376 if (prof_data->entries >= prof_data->max_size) { 00377 void *p; 00378 n = prof_data->max_size + 20; 00379 p = ast_realloc(prof_data, l + n*sizeof(struct profile_entry)); 00380 if (p == NULL) 00381 return -1; 00382 prof_data = p; 00383 prof_data->max_size = n; 00384 } 00385 n = prof_data->entries++; 00386 prof_data->e[n].name = ast_strdup(name); 00387 prof_data->e[n].value = 0; 00388 prof_data->e[n].events = 0; 00389 prof_data->e[n].mark = 0; 00390 prof_data->e[n].scale = scale; 00391 return n; 00392 } 00393 00394 int64_t ast_profile(int i, int64_t delta) 00395 { 00396 if (!prof_data || i < 0 || i > prof_data->entries) /* invalid index */ 00397 return 0; 00398 if (prof_data->e[i].scale > 1) 00399 delta /= prof_data->e[i].scale; 00400 prof_data->e[i].value += delta; 00401 prof_data->e[i].events++; 00402 return prof_data->e[i].value; 00403 } 00404 00405 #if defined ( __i386__) && (defined(__FreeBSD__) || defined(linux)) 00406 #if defined(__FreeBSD__) 00407 #include <machine/cpufunc.h> 00408 #elif defined(linux) 00409 static __inline uint64_t 00410 rdtsc(void) 00411 { 00412 uint64_t rv; 00413 00414 __asm __volatile(".byte 0x0f, 0x31" : "=A" (rv)); 00415 return (rv); 00416 } 00417 #endif 00418 #else /* supply a dummy function on other platforms */ 00419 static __inline uint64_t 00420 rdtsc(void) 00421 { 00422 return 0; 00423 } 00424 #endif 00425 00426 int64_t ast_mark(int i, int startstop) 00427 { 00428 if (!prof_data || i < 0 || i > prof_data->entries) /* invalid index */ 00429 return 0; 00430 if (startstop == 1) 00431 prof_data->e[i].mark = rdtsc(); 00432 else { 00433 prof_data->e[i].mark = (rdtsc() - prof_data->e[i].mark); 00434 if (prof_data->e[i].scale > 1) 00435 prof_data->e[i].mark /= prof_data->e[i].scale; 00436 prof_data->e[i].value += prof_data->e[i].mark; 00437 prof_data->e[i].events++; 00438 } 00439 return prof_data->e[i].mark; 00440 } 00441 00442 static int handle_show_profile(int fd, int argc, char *argv[]) 00443 { 00444 int i, min, max; 00445 char *search = NULL; 00446 00447 if (prof_data == NULL) 00448 return 0; 00449 00450 min = 0; 00451 max = prof_data->entries; 00452 if (argc > 3) { /* specific entries */ 00453 if (isdigit(argv[3][0])) { 00454 min = atoi(argv[3]); 00455 if (argc == 5 && strcmp(argv[4], "-")) 00456 max = atoi(argv[4]); 00457 } else 00458 search = argv[3]; 00459 } 00460 if (max > prof_data->entries) 00461 max = prof_data->entries; 00462 if (!strcmp(argv[1], "clear")) { 00463 for (i= min; i < max; i++) { 00464 if (!search || strstr(prof_data->e[i].name, search)) { 00465 prof_data->e[i].value = 0; 00466 prof_data->e[i].events = 0; 00467 } 00468 } 00469 return 0; 00470 } 00471 ast_cli(fd, "profile values (%d, allocated %d)\n-------------------\n", 00472 prof_data->entries, prof_data->max_size); 00473 ast_cli(fd, "%6s %8s %10s %12s %12s %s\n", "ID", "Scale", "Events", 00474 "Value", "Average", "Name"); 00475 for (i = min; i < max; i++) { 00476 struct profile_entry *e = &prof_data->e[i]; 00477 if (!search || strstr(prof_data->e[i].name, search)) 00478 ast_cli(fd, "%6d: [%8ld] %10ld %12lld %12lld %s\n", 00479 i, 00480 (long)e->scale, 00481 (long)e->events, (long long)e->value, 00482 (long long)(e->events ? e->value / e->events : e->value), 00483 e->name); 00484 } 00485 return 0; 00486 } 00487 00488 static const char show_version_files_help[] = 00489 "Usage: core show file version [like <pattern>]\n" 00490 " Lists the revision numbers of the files used to build this copy of Asterisk.\n" 00491 " Optional regular expression pattern is used to filter the file list.\n"; 00492 00493 /*! \brief CLI command to list module versions */ 00494 static int handle_show_version_files(int fd, int argc, char *argv[]) 00495 { 00496 #define FORMAT "%-25.25s %-40.40s\n" 00497 struct file_version *iterator; 00498 regex_t regexbuf; 00499 int havepattern = 0; 00500 int havename = 0; 00501 int count_files = 0; 00502 00503 switch (argc) { 00504 case 5: 00505 if (!strcasecmp(argv[3], "like")) { 00506 if (regcomp(®exbuf, argv[4], REG_EXTENDED | REG_NOSUB)) 00507 return RESULT_SHOWUSAGE; 00508 havepattern = 1; 00509 } else 00510 return RESULT_SHOWUSAGE; 00511 break; 00512 case 4: 00513 havename = 1; 00514 break; 00515 case 3: 00516 break; 00517 default: 00518 return RESULT_SHOWUSAGE; 00519 } 00520 00521 ast_cli(fd, FORMAT, "File", "Revision"); 00522 ast_cli(fd, FORMAT, "----", "--------"); 00523 AST_LIST_LOCK(&file_versions); 00524 AST_LIST_TRAVERSE(&file_versions, iterator, list) { 00525 if (havename && strcasecmp(iterator->file, argv[3])) 00526 continue; 00527 00528 if (havepattern && regexec(®exbuf, iterator->file, 0, NULL, 0)) 00529 continue; 00530 00531 ast_cli(fd, FORMAT, iterator->file, iterator->version); 00532 count_files++; 00533 if (havename) 00534 break; 00535 } 00536 AST_LIST_UNLOCK(&file_versions); 00537 if (!havename) { 00538 ast_cli(fd, "%d files listed.\n", count_files); 00539 } 00540 00541 if (havepattern) 00542 regfree(®exbuf); 00543 00544 return RESULT_SUCCESS; 00545 #undef FORMAT 00546 } 00547 00548 static char *complete_show_version_files(const char *line, const char *word, int pos, int state) 00549 { 00550 struct file_version *find; 00551 int which = 0; 00552 char *ret = NULL; 00553 int matchlen = strlen(word); 00554 00555 if (pos != 3) 00556 return NULL; 00557 00558 AST_LIST_LOCK(&file_versions); 00559 AST_LIST_TRAVERSE(&file_versions, find, list) { 00560 if (!strncasecmp(word, find->file, matchlen) && ++which > state) { 00561 ret = ast_strdup(find->file); 00562 break; 00563 } 00564 } 00565 AST_LIST_UNLOCK(&file_versions); 00566 00567 return ret; 00568 } 00569 #endif /* ! LOW_MEMORY */ 00570 00571 int ast_register_atexit(void (*func)(void)) 00572 { 00573 int res = -1; 00574 struct ast_atexit *ae; 00575 ast_unregister_atexit(func); 00576 AST_LIST_LOCK(&atexits); 00577 if ((ae = ast_calloc(1, sizeof(*ae)))) { 00578 AST_LIST_INSERT_HEAD(&atexits, ae, list); 00579 ae->func = func; 00580 res = 0; 00581 } 00582 AST_LIST_UNLOCK(&atexits); 00583 return res; 00584 } 00585 00586 void ast_unregister_atexit(void (*func)(void)) 00587 { 00588 struct ast_atexit *ae; 00589 AST_LIST_LOCK(&atexits); 00590 AST_LIST_TRAVERSE_SAFE_BEGIN(&atexits, ae, list) { 00591 if (ae->func == func) { 00592 AST_LIST_REMOVE_CURRENT(&atexits, list); 00593 break; 00594 } 00595 } 00596 AST_LIST_TRAVERSE_SAFE_END 00597 AST_LIST_UNLOCK(&atexits); 00598 } 00599 00600 static int fdprint(int fd, const char *s) 00601 { 00602 return write(fd, s, strlen(s) + 1); 00603 } 00604 00605 /*! \brief NULL handler so we can collect the child exit status */ 00606 static void null_sig_handler(int signal) 00607 { 00608 00609 } 00610 00611 AST_MUTEX_DEFINE_STATIC(safe_system_lock); 00612 /*! \brief Keep track of how many threads are currently trying to wait*() on 00613 * a child process */ 00614 static unsigned int safe_system_level = 0; 00615 static void *safe_system_prev_handler; 00616 00617 void ast_replace_sigchld(void) 00618 { 00619 unsigned int level; 00620 00621 ast_mutex_lock(&safe_system_lock); 00622 level = safe_system_level++; 00623 00624 /* only replace the handler if it has not already been done */ 00625 if (level == 0) 00626 safe_system_prev_handler = signal(SIGCHLD, null_sig_handler); 00627 00628 ast_mutex_unlock(&safe_system_lock); 00629 } 00630 00631 void ast_unreplace_sigchld(void) 00632 { 00633 unsigned int level; 00634 00635 ast_mutex_lock(&safe_system_lock); 00636 level = --safe_system_level; 00637 00638 /* only restore the handler if we are the last one */ 00639 if (level == 0) 00640 signal(SIGCHLD, safe_system_prev_handler); 00641 00642 ast_mutex_unlock(&safe_system_lock); 00643 } 00644 00645 int ast_safe_system(const char *s) 00646 { 00647 pid_t pid; 00648 #ifdef HAVE_WORKING_FORK 00649 int x; 00650 #endif 00651 int res; 00652 struct rusage rusage; 00653 int status; 00654 00655 #if defined(HAVE_WORKING_FORK) || defined(HAVE_WORKING_VFORK) 00656 ast_replace_sigchld(); 00657 00658 #ifdef HAVE_WORKING_FORK 00659 pid = fork(); 00660 #else 00661 pid = vfork(); 00662 #endif 00663 00664 if (pid == 0) { 00665 #ifdef HAVE_WORKING_FORK 00666 if (ast_opt_high_priority) 00667 ast_set_priority(0); 00668 /* Close file descriptors and launch system command */ 00669 for (x = STDERR_FILENO + 1; x < 4096; x++) 00670 close(x); 00671 #endif 00672 execl("/bin/sh", "/bin/sh", "-c", s, (char *) NULL); 00673 _exit(1); 00674 } else if (pid > 0) { 00675 for (;;) { 00676 res = wait4(pid, &status, 0, &rusage); 00677 if (res > -1) { 00678 res = WIFEXITED(status) ? WEXITSTATUS(status) : -1; 00679 break; 00680 } else if (errno != EINTR) 00681 break; 00682 } 00683 } else { 00684 ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno)); 00685 res = -1; 00686 } 00687 00688 ast_unreplace_sigchld(); 00689 #else 00690 res = -1; 00691 #endif 00692 00693 return res; 00694 } 00695 00696 /*! 00697 * \brief mute or unmute a console from logging 00698 */ 00699 void ast_console_toggle_mute(int fd) { 00700 int x; 00701 for (x = 0;x < AST_MAX_CONNECTS; x++) { 00702 if (fd == consoles[x].fd) { 00703 if (consoles[x].mute) { 00704 consoles[x].mute = 0; 00705 ast_cli(fd, "Console is not muted anymore.\n"); 00706 } else { 00707 consoles[x].mute = 1; 00708 ast_cli(fd, "Console is muted.\n"); 00709 } 00710 return; 00711 } 00712 } 00713 ast_cli(fd, "Couldn't find remote console.\n"); 00714 } 00715 00716 /*! 00717 * \brief log the string to all attached console clients 00718 */ 00719 static void ast_network_puts_mutable(const char *string) 00720 { 00721 int x; 00722 for (x = 0;x < AST_MAX_CONNECTS; x++) { 00723 if (consoles[x].mute) 00724 continue; 00725 if (consoles[x].fd > -1) 00726 fdprint(consoles[x].p[1], string); 00727 } 00728 } 00729 00730 /*! 00731 * \brief log the string to the console, and all attached 00732 * console clients 00733 */ 00734 void ast_console_puts_mutable(const char *string) 00735 { 00736 fputs(string, stdout); 00737 fflush(stdout); 00738 ast_network_puts_mutable(string); 00739 } 00740 00741 /*! 00742 * \brief write the string to all attached console clients 00743 */ 00744 static void ast_network_puts(const char *string) 00745 { 00746 int x; 00747 for (x=0; x < AST_MAX_CONNECTS; x++) { 00748 if (consoles[x].fd > -1) 00749 fdprint(consoles[x].p[1], string); 00750 } 00751 } 00752 00753 /*! 00754 * write the string to the console, and all attached 00755 * console clients 00756 */ 00757 void ast_console_puts(const char *string) 00758 { 00759 fputs(string, stdout); 00760 fflush(stdout); 00761 ast_network_puts(string); 00762 } 00763 00764 static void network_verboser(const char *s) 00765 { 00766 ast_network_puts_mutable(s); 00767 } 00768 00769 static pthread_t lthread; 00770 00771 static void *netconsole(void *vconsole) 00772 { 00773 struct console *con = vconsole; 00774 char hostname[MAXHOSTNAMELEN] = ""; 00775 char tmp[512]; 00776 int res; 00777 struct pollfd fds[2]; 00778 00779 if (gethostname(hostname, sizeof(hostname)-1)) 00780 ast_copy_string(hostname, "<Unknown>", sizeof(hostname)); 00781 snprintf(tmp, sizeof(tmp), "%s/%ld/%s\n", hostname, (long)ast_mainpid, ASTERISK_VERSION); 00782 fdprint(con->fd, tmp); 00783 for (;;) { 00784 fds[0].fd = con->fd; 00785 fds[0].events = POLLIN; 00786 fds[0].revents = 0; 00787 fds[1].fd = con->p[0]; 00788 fds[1].events = POLLIN; 00789 fds[1].revents = 0; 00790 00791 res = poll(fds, 2, -1); 00792 if (res < 0) { 00793 if (errno != EINTR) 00794 ast_log(LOG_WARNING, "poll returned < 0: %s\n", strerror(errno)); 00795 continue; 00796 } 00797 if (fds[0].revents) { 00798 res = read(con->fd, tmp, sizeof(tmp)); 00799 if (res < 1) { 00800 break; 00801 } 00802 tmp[res] = 0; 00803 ast_cli_command(con->fd, tmp); 00804 } 00805 if (fds[1].revents) { 00806 res = read(con->p[0], tmp, sizeof(tmp)); 00807 if (res < 1) { 00808 ast_log(LOG_ERROR, "read returned %d\n", res); 00809 break; 00810 } 00811 res = write(con->fd, tmp, res); 00812 if (res < 1) 00813 break; 00814 } 00815 } 00816 if (option_verbose > 2) 00817 ast_verbose(VERBOSE_PREFIX_3 "Remote UNIX connection disconnected\n"); 00818 close(con->fd); 00819 close(con->p[0]); 00820 close(con->p[1]); 00821 con->fd = -1; 00822 00823 return NULL; 00824 } 00825 00826 static void *listener(void *unused) 00827 { 00828 struct sockaddr_un sunaddr; 00829 int s; 00830 socklen_t len; 00831 int x; 00832 int flags; 00833 struct pollfd fds[1]; 00834 pthread_attr_t attr; 00835 pthread_attr_init(&attr); 00836 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 00837 for (;;) { 00838 if (ast_socket < 0) 00839 return NULL; 00840 fds[0].fd = ast_socket; 00841 fds[0].events = POLLIN; 00842 s = poll(fds, 1, -1); 00843 pthread_testcancel(); 00844 if (s < 0) { 00845 if (errno != EINTR) 00846 ast_log(LOG_WARNING, "poll returned error: %s\n", strerror(errno)); 00847 continue; 00848 } 00849 len = sizeof(sunaddr); 00850 s = accept(ast_socket, (struct sockaddr *)&sunaddr, &len); 00851 if (s < 0) { 00852 if (errno != EINTR) 00853 ast_log(LOG_WARNING, "Accept returned %d: %s\n", s, strerror(errno)); 00854 } else { 00855 for (x = 0; x < AST_MAX_CONNECTS; x++) { 00856 if (consoles[x].fd < 0) { 00857 if (socketpair(AF_LOCAL, SOCK_STREAM, 0, consoles[x].p)) { 00858 ast_log(LOG_ERROR, "Unable to create pipe: %s\n", strerror(errno)); 00859 consoles[x].fd = -1; 00860 fdprint(s, "Server failed to create pipe\n"); 00861 close(s); 00862 break; 00863 } 00864 flags = fcntl(consoles[x].p[1], F_GETFL); 00865 fcntl(consoles[x].p[1], F_SETFL, flags | O_NONBLOCK); 00866 consoles[x].fd = s; 00867 consoles[x].mute = ast_opt_mute; 00868 if (ast_pthread_create_background(&consoles[x].t, &attr, netconsole, &consoles[x])) { 00869 ast_log(LOG_ERROR, "Unable to spawn thread to handle connection: %s\n", strerror(errno)); 00870 close(consoles[x].p[0]); 00871 close(consoles[x].p[1]); 00872 consoles[x].fd = -1; 00873 fdprint(s, "Server failed to spawn thread\n"); 00874 close(s); 00875 } 00876 break; 00877 } 00878 } 00879 if (x >= AST_MAX_CONNECTS) { 00880 fdprint(s, "No more connections allowed\n"); 00881 ast_log(LOG_WARNING, "No more connections allowed\n"); 00882 close(s); 00883 } else if (consoles[x].fd > -1) { 00884 if (option_verbose > 2) 00885 ast_verbose(VERBOSE_PREFIX_3 "Remote UNIX connection\n"); 00886 } 00887 } 00888 } 00889 return NULL; 00890 } 00891 00892 static int ast_makesocket(void) 00893 { 00894 struct sockaddr_un sunaddr; 00895 int res; 00896 int x; 00897 uid_t uid = -1; 00898 gid_t gid = -1; 00899 00900 for (x = 0; x < AST_MAX_CONNECTS; x++) 00901 consoles[x].fd = -1; 00902 unlink(ast_config_AST_SOCKET); 00903 ast_socket = socket(PF_LOCAL, SOCK_STREAM, 0); 00904 if (ast_socket < 0) { 00905 ast_log(LOG_WARNING, "Unable to create control socket: %s\n", strerror(errno)); 00906 return -1; 00907 } 00908 memset(&sunaddr, 0, sizeof(sunaddr)); 00909 sunaddr.sun_family = AF_LOCAL; 00910 ast_copy_string(sunaddr.sun_path, ast_config_AST_SOCKET, sizeof(sunaddr.sun_path)); 00911 res = bind(ast_socket, (struct sockaddr *)&sunaddr, sizeof(sunaddr)); 00912 if (res) { 00913 ast_log(LOG_WARNING, "Unable to bind socket to %s: %s\n", ast_config_AST_SOCKET, strerror(errno)); 00914 close(ast_socket); 00915 ast_socket = -1; 00916 return -1; 00917 } 00918 res = listen(ast_socket, 2); 00919 if (res < 0) { 00920 ast_log(LOG_WARNING, "Unable to listen on socket %s: %s\n", ast_config_AST_SOCKET, strerror(errno)); 00921 close(ast_socket); 00922 ast_socket = -1; 00923 return -1; 00924 } 00925 ast_register_verbose(network_verboser); 00926 ast_pthread_create_background(<hread, NULL, listener, NULL); 00927 00928 if (!ast_strlen_zero(ast_config_AST_CTL_OWNER)) { 00929 struct passwd *pw; 00930 if ((pw = getpwnam(ast_config_AST_CTL_OWNER)) == NULL) 00931 ast_log(LOG_WARNING, "Unable to find uid of user %s\n", ast_config_AST_CTL_OWNER); 00932 else 00933 uid = pw->pw_uid; 00934 } 00935 00936 if (!ast_strlen_zero(ast_config_AST_CTL_GROUP)) { 00937 struct group *grp; 00938 if ((grp = getgrnam(ast_config_AST_CTL_GROUP)) == NULL) 00939 ast_log(LOG_WARNING, "Unable to find gid of group %s\n", ast_config_AST_CTL_GROUP); 00940 else 00941 gid = grp->gr_gid; 00942 } 00943 00944 if (chown(ast_config_AST_SOCKET, uid, gid) < 0) 00945 ast_log(LOG_WARNING, "Unable to change ownership of %s: %s\n", ast_config_AST_SOCKET, strerror(errno)); 00946 00947 if (!ast_strlen_zero(ast_config_AST_CTL_PERMISSIONS)) { 00948 int p1; 00949 mode_t p; 00950 sscanf(ast_config_AST_CTL_PERMISSIONS, "%o", &p1); 00951 p = p1; 00952 if ((chmod(ast_config_AST_SOCKET, p)) < 0) 00953 ast_log(LOG_WARNING, "Unable to change file permissions of %s: %s\n", ast_config_AST_SOCKET, strerror(errno)); 00954 } 00955 00956 return 0; 00957 } 00958 00959 static int ast_tryconnect(void) 00960 { 00961 struct sockaddr_un sunaddr; 00962 int res; 00963 ast_consock = socket(PF_LOCAL, SOCK_STREAM, 0); 00964 if (ast_consock < 0) { 00965 ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno)); 00966 return 0; 00967 } 00968 memset(&sunaddr, 0, sizeof(sunaddr)); 00969 sunaddr.sun_family = AF_LOCAL; 00970 ast_copy_string(sunaddr.sun_path, (char *)ast_config_AST_SOCKET, sizeof(sunaddr.sun_path)); 00971 res = connect(ast_consock, (struct sockaddr *)&sunaddr, sizeof(sunaddr)); 00972 if (res) { 00973 close(ast_consock); 00974 ast_consock = -1; 00975 return 0; 00976 } else 00977 return 1; 00978 } 00979 00980 /*! \brief Urgent handler 00981 00982 Called by soft_hangup to interrupt the poll, read, or other 00983 system call. We don't actually need to do anything though. 00984 Remember: Cannot EVER ast_log from within a signal handler 00985 */ 00986 static void urg_handler(int num) 00987 { 00988 signal(num, urg_handler); 00989 return; 00990 } 00991 00992 static void hup_handler(int num) 00993 { 00994 if (option_verbose > 1) 00995 printf("Received HUP signal -- Reloading configs\n"); 00996 if (restartnow) 00997 execvp(_argv[0], _argv); 00998 need_reload = 1; 00999 signal(num, hup_handler); 01000 } 01001 01002 static void child_handler(int sig) 01003 { 01004 /* Must not ever ast_log or ast_verbose within signal handler */ 01005 int n, status; 01006 01007 /* 01008 * Reap all dead children -- not just one 01009 */ 01010 for (n = 0; wait4(-1, &status, WNOHANG, NULL) > 0; n++) 01011 ; 01012 if (n == 0 && option_debug) 01013 printf("Huh? Child handler, but nobody there?\n"); 01014 signal(sig, child_handler); 01015 } 01016 01017 /*! \brief Set maximum open files */ 01018 static void set_ulimit(int value) 01019 { 01020 struct rlimit l = {0, 0}; 01021 01022 if (value <= 0) { 01023 ast_log(LOG_WARNING, "Unable to change max files open to invalid value %i\n",value); 01024 return; 01025 } 01026 01027 l.rlim_cur = value; 01028 l.rlim_max = value; 01029 01030 if (setrlimit(RLIMIT_NOFILE, &l)) { 01031 ast_log(LOG_WARNING, "Unable to disable core size resource limit: %s\n",strerror(errno)); 01032 return; 01033 } 01034 01035 ast_log(LOG_NOTICE, "Setting max files open to %d\n",value); 01036 01037 return; 01038 } 01039 01040 /*! \brief Set an X-term or screen title */ 01041 static void set_title(char *text) 01042 { 01043 if (getenv("TERM") && strstr(getenv("TERM"), "xterm")) 01044 fprintf(stdout, "\033]2;%s\007", text); 01045 } 01046 01047 static void set_icon(char *text) 01048 { 01049 if (getenv("TERM") && strstr(getenv("TERM"), "xterm")) 01050 fprintf(stdout, "\033]1;%s\007", text); 01051 } 01052 01053 /*! \brief We set ourselves to a high priority, that we might pre-empt everything 01054 else. If your PBX has heavy activity on it, this is a good thing. */ 01055 int ast_set_priority(int pri) 01056 { 01057 struct sched_param sched; 01058 memset(&sched, 0, sizeof(sched)); 01059 #ifdef __linux__ 01060 if (pri) { 01061 sched.sched_priority = 10; 01062 if (sched_setscheduler(0, SCHED_RR, &sched)) { 01063 ast_log(LOG_WARNING, "Unable to set high priority\n"); 01064 return -1; 01065 } else 01066 if (option_verbose) 01067 ast_verbose("Set to realtime thread\n"); 01068 } else { 01069 sched.sched_priority = 0; 01070 if (sched_setscheduler(0, SCHED_OTHER, &sched)) { 01071 ast_log(LOG_WARNING, "Unable to set normal priority\n"); 01072 return -1; 01073 } 01074 } 01075 #else 01076 if (pri) { 01077 if (setpriority(PRIO_PROCESS, 0, -10) == -1) { 01078 ast_log(LOG_WARNING, "Unable to set high priority\n"); 01079 return -1; 01080 } else 01081 if (option_verbose) 01082 ast_verbose("Set to high priority\n"); 01083 } else { 01084 if (setpriority(PRIO_PROCESS, 0, 0) == -1) { 01085 ast_log(LOG_WARNING, "Unable to set normal priority\n"); 01086 return -1; 01087 } 01088 } 01089 #endif 01090 return 0; 01091 } 01092 01093 static void ast_run_atexits(void) 01094 { 01095 struct ast_atexit *ae; 01096 AST_LIST_LOCK(&atexits); 01097 AST_LIST_TRAVERSE(&atexits, ae, list) { 01098 if (ae->func) 01099 ae->func(); 01100 } 01101 AST_LIST_UNLOCK(&atexits); 01102 } 01103 01104 static void quit_handler(int num, int nice, int safeshutdown, int restart) 01105 { 01106 char filename[80] = ""; 01107 time_t s,e; 01108 int x; 01109 /* Try to get as many CDRs as possible submitted to the backend engines (if in batch mode) */ 01110 ast_cdr_engine_term(); 01111 if (safeshutdown) { 01112 shuttingdown = 1; 01113 if (!nice) { 01114 /* Begin shutdown routine, hanging up active channels */ 01115 ast_begin_shutdown(1); 01116 if (option_verbose && ast_opt_console) 01117 ast_verbose("Beginning asterisk %s....\n", restart ? "restart" : "shutdown"); 01118 time(&s); 01119 for (;;) { 01120 time(&e); 01121 /* Wait up to 15 seconds for all channels to go away */ 01122 if ((e - s) > 15) 01123 break; 01124 if (!ast_active_channels()) 01125 break; 01126 if (!shuttingdown) 01127 break; 01128 /* Sleep 1/10 of a second */ 01129 usleep(100000); 01130 } 01131 } else { 01132 if (nice < 2) 01133 ast_begin_shutdown(0); 01134 if (option_verbose && ast_opt_console) 01135 ast_verbose("Waiting for inactivity to perform %s...\n", restart ? "restart" : "halt"); 01136 for (;;) { 01137 if (!ast_active_channels()) 01138 break; 01139 if (!shuttingdown) 01140 break; 01141 sleep(1); 01142 } 01143 } 01144 01145 if (!shuttingdown) { 01146 if (option_verbose && ast_opt_console) 01147 ast_verbose("Asterisk %s cancelled.\n", restart ? "restart" : "shutdown"); 01148 return; 01149 } 01150 } 01151 if (ast_opt_console || ast_opt_remote) { 01152 if (getenv("HOME")) 01153 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME")); 01154 if (!ast_strlen_zero(filename)) 01155 ast_el_write_history(filename); 01156 if (el != NULL) 01157 el_end(el); 01158 if (el_hist != NULL) 01159 history_end(el_hist); 01160 } 01161 if (option_verbose) 01162 ast_verbose("Executing last minute cleanups\n"); 01163 ast_run_atexits(); 01164 /* Called on exit */ 01165 if (option_verbose && ast_opt_console) 01166 ast_verbose("Asterisk %s ending (%d).\n", ast_active_channels() ? "uncleanly" : "cleanly", num); 01167 if (option_debug) 01168 ast_log(LOG_DEBUG, "Asterisk ending (%d).\n", num); 01169 manager_event(EVENT_FLAG_SYSTEM, "Shutdown", "Shutdown: %s\r\nRestart: %s\r\n", ast_active_channels() ? "Uncleanly" : "Cleanly", restart ? "True" : "False"); 01170 if (ast_socket > -1) { 01171 pthread_cancel(lthread); 01172 close(ast_socket); 01173 ast_socket = -1; 01174 unlink(ast_config_AST_SOCKET); 01175 } 01176 if (ast_consock > -1) 01177 close(ast_consock); 01178 if (!ast_opt_remote) 01179 unlink(ast_config_AST_PID); 01180 printf(term_quit()); 01181 if (restart) { 01182 if (option_verbose || ast_opt_console) 01183 ast_verbose("Preparing for Asterisk restart...\n"); 01184 /* Mark all FD's for closing on exec */ 01185 for (x=3; x < 32768; x++) { 01186 fcntl(x, F_SETFD, FD_CLOEXEC); 01187 } 01188 if (option_verbose || ast_opt_console) 01189 ast_verbose("Restarting Asterisk NOW...\n"); 01190 restartnow = 1; 01191 01192 /* close logger */ 01193 close_logger(); 01194 01195 /* If there is a consolethread running send it a SIGHUP 01196 so it can execvp, otherwise we can do it ourselves */ 01197 if ((consolethread != AST_PTHREADT_NULL) && (consolethread != pthread_self())) { 01198 pthread_kill(consolethread, SIGHUP); 01199 /* Give the signal handler some time to complete */ 01200 sleep(2); 01201 } else 01202 execvp(_argv[0], _argv); 01203 01204 } else { 01205 /* close logger */ 01206 close_logger(); 01207 } 01208 exit(0); 01209 } 01210 01211 static void __quit_handler(int num) 01212 { 01213 quit_handler(num, 0, 1, 0); 01214 } 01215 01216 static const char *fix_header(char *outbuf, int maxout, const char *s, char *cmp) 01217 { 01218 const char *c; 01219 if (!strncmp(s, cmp, strlen(cmp))) { 01220 c = s + strlen(cmp); 01221 term_color(outbuf, cmp, COLOR_GRAY, 0, maxout); 01222 return c; 01223 } 01224 return NULL; 01225 } 01226 01227 static void console_verboser(const char *s) 01228 { 01229 char tmp[80]; 01230 const char *c = NULL; 01231 01232 if ((c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_4)) || 01233 (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_3)) || 01234 (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_2)) || 01235 (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_1))) { 01236 fputs(tmp, stdout); 01237 fputs(c, stdout); 01238 } else 01239 fputs(s, stdout); 01240 01241 fflush(stdout); 01242 01243 /* Wake up a poll()ing console */ 01244 if (ast_opt_console && consolethread != AST_PTHREADT_NULL) 01245 pthread_kill(consolethread, SIGURG); 01246 } 01247 01248 static int ast_all_zeros(char *s) 01249 { 01250 while (*s) { 01251 if (*s > 32) 01252 return 0; 01253 s++; 01254 } 01255 return 1; 01256 } 01257 01258 static void consolehandler(char *s) 01259 { 01260 printf(term_end()); 01261 fflush(stdout); 01262 01263 /* Called when readline data is available */ 01264 if (!ast_all_zeros(s)) 01265 ast_el_add_history(s); 01266 /* The real handler for bang */ 01267 if (s[0] == '!') { 01268 if (s[1]) 01269 ast_safe_system(s+1); 01270 else 01271 ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh"); 01272 } else 01273 ast_cli_command(STDOUT_FILENO, s); 01274 } 01275 01276 static int remoteconsolehandler(char *s) 01277 { 01278 int ret = 0; 01279 01280 /* Called when readline data is available */ 01281 if (!ast_all_zeros(s)) 01282 ast_el_add_history(s); 01283 /* The real handler for bang */ 01284 if (s[0] == '!') { 01285 if (s[1]) 01286 ast_safe_system(s+1); 01287 else 01288 ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh"); 01289 ret = 1; 01290 } 01291 if ((strncasecmp(s, "quit", 4) == 0 || strncasecmp(s, "exit", 4) == 0) && 01292 (s[4] == '\0' || isspace(s[4]))) { 01293 quit_handler(0, 0, 0, 0); 01294 ret = 1; 01295 } 01296 01297 return ret; 01298 } 01299 01300 static const char abort_halt_help[] = 01301 "Usage: abort shutdown\n" 01302 " Causes Asterisk to abort an executing shutdown or restart, and resume normal\n" 01303 " call operations.\n"; 01304 01305 static const char shutdown_now_help[] = 01306 "Usage: stop now\n" 01307 " Shuts down a running Asterisk immediately, hanging up all active calls .\n"; 01308 01309 static const char shutdown_gracefully_help[] = 01310 "Usage: stop gracefully\n" 01311 " Causes Asterisk to not accept new calls, and exit when all\n" 01312 " active calls have terminated normally.\n"; 01313 01314 static const char shutdown_when_convenient_help[] = 01315 "Usage: stop when convenient\n" 01316 " Causes Asterisk to perform a shutdown when all active calls have ended.\n"; 01317 01318 static const char restart_now_help[] = 01319 "Usage: restart now\n" 01320 " Causes Asterisk to hangup all calls and exec() itself performing a cold\n" 01321 " restart.\n"; 01322 01323 static const char restart_gracefully_help[] = 01324 "Usage: restart gracefully\n" 01325 " Causes Asterisk to stop accepting new calls and exec() itself performing a cold\n" 01326 " restart when all active calls have ended.\n"; 01327 01328 static const char restart_when_convenient_help[] = 01329 "Usage: restart when convenient\n" 01330 " Causes Asterisk to perform a cold restart when all active calls have ended.\n"; 01331 01332 static const char bang_help[] = 01333 "Usage: !<command>\n" 01334 " Executes a given shell command\n"; 01335 01336 static const char show_warranty_help[] = 01337 "Usage: core show warranty\n" 01338 " Shows the warranty (if any) for this copy of Asterisk.\n"; 01339 01340 static const char show_license_help[] = 01341 "Usage: core show license\n" 01342 " Shows the license(s) for this copy of Asterisk.\n"; 01343 01344 static const char version_help[] = 01345 "Usage: core show version\n" 01346 " Shows Asterisk version information.\n"; 01347 01348 static int handle_version(int fd, int argc, char *argv[]) 01349 { 01350 if (argc != 3) 01351 return RESULT_SHOWUSAGE; 01352 ast_cli(fd, "Asterisk %s built by %s @ %s on a %s running %s on %s\n", 01353 ASTERISK_VERSION, ast_build_user, ast_build_hostname, 01354 ast_build_machine, ast_build_os, ast_build_date); 01355 return RESULT_SUCCESS; 01356 } 01357 01358 #if 0 01359 static int handle_quit(int fd, int argc, char *argv[]) 01360 { 01361 if (argc != 1) 01362 return RESULT_SHOWUSAGE; 01363 quit_handler(0, 0, 1, 0); 01364 return RESULT_SUCCESS; 01365 } 01366 #endif 01367 01368 static int handle_shutdown_now(int fd, int argc, char *argv[]) 01369 { 01370 if (argc != 2) 01371 return RESULT_SHOWUSAGE; 01372 quit_handler(0, 0 /* Not nice */, 1 /* safely */, 0 /* not restart */); 01373 return RESULT_SUCCESS; 01374 } 01375 01376 static int handle_shutdown_gracefully(int fd, int argc, char *argv[]) 01377 { 01378 if (argc != 2) 01379 return RESULT_SHOWUSAGE; 01380 quit_handler(0, 1 /* nicely */, 1 /* safely */, 0 /* no restart */); 01381 return RESULT_SUCCESS; 01382 } 01383 01384 static int handle_shutdown_when_convenient(int fd, int argc, char *argv[]) 01385 { 01386 if (argc != 3) 01387 return RESULT_SHOWUSAGE; 01388 ast_cli(fd, "Waiting for inactivity to perform halt\n"); 01389 quit_handler(0, 2 /* really nicely */, 1 /* safely */, 0 /* don't restart */); 01390 return RESULT_SUCCESS; 01391 } 01392 01393 static int handle_restart_now(int fd, int argc, char *argv[]) 01394 { 01395 if (argc != 2) 01396 return RESULT_SHOWUSAGE; 01397 quit_handler(0, 0 /* not nicely */, 1 /* safely */, 1 /* restart */); 01398 return RESULT_SUCCESS; 01399 } 01400 01401 static int handle_restart_gracefully(int fd, int argc, char *argv[]) 01402 { 01403 if (argc != 2) 01404 return RESULT_SHOWUSAGE; 01405 quit_handler(0, 1 /* nicely */, 1 /* safely */, 1 /* restart */); 01406 return RESULT_SUCCESS; 01407 } 01408 01409 static int handle_restart_when_convenient(int fd, int argc, char *argv[]) 01410 { 01411 if (argc != 3) 01412 return RESULT_SHOWUSAGE; 01413 ast_cli(fd, "Waiting for inactivity to perform restart\n"); 01414 quit_handler(0, 2 /* really nicely */, 1 /* safely */, 1 /* restart */); 01415 return RESULT_SUCCESS; 01416 } 01417 01418 static int handle_abort_halt(int fd, int argc, char *argv[]) 01419 { 01420 if (argc != 2) 01421 return RESULT_SHOWUSAGE; 01422 ast_cancel_shutdown(); 01423 shuttingdown = 0; 01424 return RESULT_SUCCESS; 01425 } 01426 01427 static int handle_bang(int fd, int argc, char *argv[]) 01428 { 01429 return RESULT_SUCCESS; 01430 } 01431 static const char *warranty_lines[] = { 01432 "\n", 01433 " NO WARRANTY\n", 01434 "\n", 01435 "BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\n", 01436 "FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN\n", 01437 "OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\n", 01438 "PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\n", 01439 "OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n", 01440 "MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS\n", 01441 "TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE\n", 01442 "PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\n", 01443 "REPAIR OR CORRECTION.\n", 01444 "\n", 01445 "IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\n", 01446 "WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\n", 01447 "REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\n", 01448 "INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\n", 01449 "OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\n", 01450 "TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\n", 01451 "YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\n", 01452 "PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\n", 01453 "POSSIBILITY OF SUCH DAMAGES.\n", 01454 }; 01455 01456 static int show_warranty(int fd, int argc, char *argv[]) 01457 { 01458 int x; 01459 01460 for (x = 0; x < sizeof(warranty_lines) / sizeof(warranty_lines[0]); x++) 01461 ast_cli(fd, (char *) warranty_lines[x]); 01462 01463 return RESULT_SUCCESS; 01464 } 01465 01466 static const char *license_lines[] = { 01467 "\n", 01468 "This program is free software; you can redistribute it and/or modify\n", 01469 "it under the terms of the GNU General Public License version 2 as\n", 01470 "published by the Free Software Foundation.\n", 01471 "\n", 01472 "This program also contains components licensed under other licenses.\n", 01473 "They include:\n", 01474 "\n", 01475 "This program is distributed in the hope that it will be useful,\n", 01476 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n", 01477 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n", 01478 "GNU General Public License for more details.\n", 01479 "\n", 01480 "You should have received a copy of the GNU General Public License\n", 01481 "along with this program; if not, write to the Free Software\n", 01482 "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n", 01483 }; 01484 01485 static int show_license(int fd, int argc, char *argv[]) 01486 { 01487 int x; 01488 01489 for (x = 0; x < sizeof(license_lines) / sizeof(license_lines[0]); x++) 01490 ast_cli(fd, (char *) license_lines[x]); 01491 01492 return RESULT_SUCCESS; 01493 } 01494 01495 #define ASTERISK_PROMPT "*CLI> " 01496 01497 #define ASTERISK_PROMPT2 "%s*CLI> " 01498 01499 static struct ast_cli_entry cli_asterisk[] = { 01500 { { "abort", "halt", NULL }, 01501 handle_abort_halt, "Cancel a running halt", 01502 abort_halt_help }, 01503 01504 { { "stop", "now", NULL }, 01505 handle_shutdown_now, "Shut down Asterisk immediately", 01506 shutdown_now_help }, 01507 01508 { { "stop", "gracefully", NULL }, 01509 handle_shutdown_gracefully, "Gracefully shut down Asterisk", 01510 shutdown_gracefully_help }, 01511 01512 { { "stop", "when", "convenient", NULL }, 01513 handle_shutdown_when_convenient, "Shut down Asterisk at empty call volume", 01514 shutdown_when_convenient_help }, 01515 01516 { { "restart", "now", NULL }, 01517 handle_restart_now, "Restart Asterisk immediately", restart_now_help }, 01518 01519 { { "restart", "gracefully", NULL }, 01520 handle_restart_gracefully, "Restart Asterisk gracefully", 01521 restart_gracefully_help }, 01522 01523 { { "restart", "when", "convenient", NULL }, 01524 handle_restart_when_convenient, "Restart Asterisk at empty call volume", 01525 restart_when_convenient_help }, 01526 01527 { { "core", "show", "warranty", NULL }, 01528 show_warranty, "Show the warranty (if any) for this copy of Asterisk", 01529 show_warranty_help }, 01530 01531 { { "core", "show", "license", NULL }, 01532 show_license, "Show the license(s) for this copy of Asterisk", 01533 show_license_help }, 01534 01535 { { "core", "show", "version", NULL }, 01536 handle_version, "Display version info", 01537 version_help }, 01538 01539 { { "!", NULL }, 01540 handle_bang, "Execute a shell command", 01541 bang_help }, 01542 01543 #if !defined(LOW_MEMORY) 01544 { { "core", "show", "file", "version", NULL }, 01545 handle_show_version_files, "List versions of files used to build Asterisk", 01546 show_version_files_help, complete_show_version_files }, 01547 01548 { { "core", "show", "threads", NULL }, 01549 handle_show_threads, "Show running threads", 01550 show_threads_help }, 01551 01552 { { "core", "show", "profile", NULL }, 01553 handle_show_profile, "Display profiling info", 01554 NULL }, 01555 01556 { { "core", "clear", "profile", NULL }, 01557 handle_show_profile, "Clear profiling info", 01558 NULL }, 01559 #endif /* ! LOW_MEMORY */ 01560 }; 01561 01562 static int ast_el_read_char(EditLine *el, char *cp) 01563 { 01564 int num_read = 0; 01565 int lastpos = 0; 01566 struct pollfd fds[2]; 01567 int res; 01568 int max; 01569 char buf[512]; 01570 01571 for (;;) { 01572 max = 1; 01573 fds[0].fd = ast_consock; 01574 fds[0].events = POLLIN; 01575 if (!ast_opt_exec) { 01576 fds[1].fd = STDIN_FILENO; 01577 fds[1].events = POLLIN; 01578 max++; 01579 } 01580 res = poll(fds, max, -1); 01581 if (res < 0) { 01582 if (errno == EINTR) 01583 continue; 01584 ast_log(LOG_ERROR, "poll failed: %s\n", strerror(errno)); 01585 break; 01586 } 01587 01588 if (!ast_opt_exec && fds[1].revents) { 01589 num_read = read(STDIN_FILENO, cp, 1); 01590 if (num_read < 1) { 01591 break; 01592 } else 01593 return (num_read); 01594 } 01595 if (fds[0].revents) { 01596 res = read(ast_consock, buf, sizeof(buf) - 1); 01597 /* if the remote side disappears exit */ 01598 if (res < 1) { 01599 fprintf(stderr, "\nDisconnected from Asterisk server\n"); 01600 if (!ast_opt_reconnect) { 01601 quit_handler(0, 0, 0, 0); 01602 } else { 01603 int tries; 01604 int reconnects_per_second = 20; 01605 fprintf(stderr, "Attempting to reconnect for 30 seconds\n"); 01606 for (tries=0; tries < 30 * reconnects_per_second; tries++) { 01607 if (ast_tryconnect()) { 01608 fprintf(stderr, "Reconnect succeeded after %.3f seconds\n", 1.0 / reconnects_per_second * tries); 01609 printf(term_quit()); 01610 WELCOME_MESSAGE; 01611 break; 01612 } else 01613 usleep(1000000 / reconnects_per_second); 01614 } 01615 if (tries >= 30 * reconnects_per_second) { 01616 fprintf(stderr, "Failed to reconnect for 30 seconds. Quitting.\n"); 01617 quit_handler(0, 0, 0, 0); 01618 } 01619 } 01620 } 01621 01622 buf[res] = '\0'; 01623 01624 if (!ast_opt_exec && !lastpos) 01625 write(STDOUT_FILENO, "\r", 1); 01626 write(STDOUT_FILENO, buf, res); 01627 if ((buf[res-1] == '\n') || (buf[res-2] == '\n')) { 01628 *cp = CC_REFRESH; 01629 return(1); 01630 } else 01631 lastpos = 1; 01632 } 01633 } 01634 01635 *cp = '\0'; 01636 return (0); 01637 } 01638 01639 static char *cli_prompt(EditLine *el) 01640 { 01641 static char prompt[200]; 01642 char *pfmt; 01643 int color_used = 0; 01644 char term_code[20]; 01645 01646 if ((pfmt = getenv("ASTERISK_PROMPT"))) { 01647 char *t = pfmt, *p = prompt; 01648 memset(prompt, 0, sizeof(prompt)); 01649 while (*t != '\0' && *p < sizeof(prompt)) { 01650 if (*t == '%') { 01651 char hostname[MAXHOSTNAMELEN]=""; 01652 int i; 01653 time_t ts; 01654 struct tm tm; 01655 #ifdef linux 01656 FILE *LOADAVG; 01657 #endif 01658 int fgcolor = COLOR_WHITE, bgcolor = COLOR_BLACK; 01659 01660 t++; 01661 switch (*t) { 01662 case 'C': /* color */ 01663 t++; 01664 if (sscanf(t, "%d;%d%n", &fgcolor, &bgcolor, &i) == 2) { 01665 strncat(p, term_color_code(term_code, fgcolor, bgcolor, sizeof(term_code)),sizeof(prompt) - strlen(prompt) - 1); 01666 t += i - 1; 01667 } else if (sscanf(t, "%d%n", &fgcolor, &i) == 1) { 01668 strncat(p, term_color_code(term_code, fgcolor, 0, sizeof(term_code)),sizeof(prompt) - strlen(prompt) - 1); 01669 t += i - 1; 01670 } 01671 01672 /* If the color has been reset correctly, then there's no need to reset it later */ 01673 color_used = ((fgcolor == COLOR_WHITE) && (bgcolor == COLOR_BLACK)) ? 0 : 1; 01674 break; 01675 case 'd': /* date */ 01676 memset(&tm, 0, sizeof(tm)); 01677 time(&ts); 01678 if (localtime_r(&ts, &tm)) 01679 strftime(p, sizeof(prompt) - strlen(prompt), "%Y-%m-%d", &tm); 01680 break; 01681 case 'h': /* hostname */ 01682 if (!gethostname(hostname, sizeof(hostname) - 1)) 01683 strncat(p, hostname, sizeof(prompt) - strlen(prompt) - 1); 01684 else 01685 strncat(p, "localhost", sizeof(prompt) - strlen(prompt) - 1); 01686 break; 01687 case 'H': /* short hostname */ 01688 if (!gethostname(hostname, sizeof(hostname) - 1)) { 01689 for (i = 0; i < sizeof(hostname); i++) { 01690 if (hostname[i] == '.') { 01691 hostname[i] = '\0'; 01692 break; 01693 } 01694 } 01695 strncat(p, hostname, sizeof(prompt) - strlen(prompt) - 1); 01696 } else 01697 strncat(p, "localhost", sizeof(prompt) - strlen(prompt) - 1); 01698 break; 01699 #ifdef linux 01700 case 'l': /* load avg */ 01701 t++; 01702 if ((LOADAVG = fopen("/proc/loadavg", "r"))) { 01703 float avg1, avg2, avg3; 01704 int actproc, totproc, npid, which; 01705 fscanf(LOADAVG, "%f %f %f %d/%d %d", 01706 &avg1, &avg2, &avg3, &actproc, &totproc, &npid); 01707 if (sscanf(t, "%d", &which) == 1) { 01708 switch (which) { 01709 case 1: 01710 snprintf(p, sizeof(prompt) - strlen(prompt), "%.2f", avg1); 01711 break; 01712 case 2: 01713 snprintf(p, sizeof(prompt) - strlen(prompt), "%.2f", avg2); 01714 break; 01715 case 3: 01716 snprintf(p, sizeof(prompt) - strlen(prompt), "%.2f", avg3); 01717 break; 01718 case 4: 01719 snprintf(p, sizeof(prompt) - strlen(prompt), "%d/%d", actproc, totproc); 01720 break; 01721 case 5: 01722 snprintf(p, sizeof(prompt) - strlen(prompt), "%d", npid); 01723 break; 01724 } 01725 } 01726 } 01727 break; 01728 #endif 01729 case 's': /* Asterisk system name (from asterisk.conf) */ 01730 strncat(p, ast_config_AST_SYSTEM_NAME, sizeof(prompt) - strlen(prompt) - 1); 01731 break; 01732 case 't': /* time */ 01733 memset(&tm, 0, sizeof(tm)); 01734 time(&ts); 01735 if (localtime_r(&ts, &tm)) 01736 strftime(p, sizeof(prompt) - strlen(prompt), "%H:%M:%S", &tm); 01737 break; 01738 case '#': /* process console or remote? */ 01739 if (!ast_opt_remote) 01740 strncat(p, "#", sizeof(prompt) - strlen(prompt) - 1); 01741 else 01742 strncat(p, ">", sizeof(prompt) - strlen(prompt) - 1); 01743 break; 01744 case '%': /* literal % */ 01745 strncat(p, "%", sizeof(prompt) - strlen(prompt) - 1); 01746 break; 01747 case '\0': /* % is last character - prevent bug */ 01748 t--; 01749 break; 01750 } 01751 while (*p != '\0') 01752 p++; 01753 t++; 01754 } else { 01755 *p = *t; 01756 p++; 01757 t++; 01758 } 01759 } 01760 if (color_used) { 01761 /* Force colors back to normal at end */ 01762 term_color_code(term_code, COLOR_WHITE, COLOR_BLACK, sizeof(term_code)); 01763 if (strlen(term_code) > sizeof(prompt) - strlen(prompt)) 01764 strncat(prompt + sizeof(prompt) - strlen(term_code) - 1, term_code, strlen(term_code)); 01765 else 01766 strncat(p, term_code, sizeof(term_code)); 01767 } 01768 } else if (remotehostname) 01769 snprintf(prompt, sizeof(prompt), ASTERISK_PROMPT2, remotehostname); 01770 else 01771 snprintf(prompt, sizeof(prompt), ASTERISK_PROMPT); 01772 01773 return(prompt); 01774 } 01775 01776 static char **ast_el_strtoarr(char *buf) 01777 { 01778 char **match_list = NULL, *retstr; 01779 size_t match_list_len; 01780 int matches = 0; 01781 01782 match_list_len = 1; 01783 while ( (retstr = strsep(&buf, " ")) != NULL) { 01784 01785 if (!strcmp(retstr, AST_CLI_COMPLETE_EOF)) 01786 break; 01787 if (matches + 1 >= match_list_len) { 01788 match_list_len <<= 1; 01789 if (!(match_list = ast_realloc(match_list, match_list_len * sizeof(char *)))) { 01790 /* TODO: Handle memory allocation failure */ 01791 } 01792 } 01793 01794 match_list[matches++] = strdup(retstr); 01795 } 01796 01797 if (!match_list) 01798 return (char **) NULL; 01799 01800 if (matches >= match_list_len) { 01801 if (!(match_list = ast_realloc(match_list, (match_list_len + 1) * sizeof(char *)))) { 01802 /* TODO: Handle memory allocation failure */ 01803 } 01804 } 01805 01806 match_list[matches] = (char *) NULL; 01807 01808 return match_list; 01809 } 01810 01811 static int ast_el_sort_compare(const void *i1, const void *i2) 01812 { 01813 char *s1, *s2; 01814 01815 s1 = ((char **)i1)[0]; 01816 s2 = ((char **)i2)[0]; 01817 01818 return strcasecmp(s1, s2); 01819 } 01820 01821 static int ast_cli_display_match_list(char **matches, int len, int max) 01822 { 01823 int i, idx, limit, count; 01824 int screenwidth = 0; 01825 int numoutput = 0, numoutputline = 0; 01826 01827 screenwidth = ast_get_termcols(STDOUT_FILENO); 01828 01829 /* find out how many entries can be put on one line, with two spaces between strings */ 01830 limit = screenwidth / (max + 2); 01831 if (limit == 0) 01832 limit = 1; 01833 01834 /* how many lines of output */ 01835 count = len / limit; 01836 if (count * limit < len) 01837 count++; 01838 01839 idx = 1; 01840 01841 qsort(&matches[0], (size_t)(len), sizeof(char *), ast_el_sort_compare); 01842 01843 for (; count > 0; count--) { 01844 numoutputline = 0; 01845 for (i=0; i < limit && matches[idx]; i++, idx++) { 01846 01847 /* Don't print dupes */ 01848 if ( (matches[idx+1] != NULL && strcmp(matches[idx], matches[idx+1]) == 0 ) ) { 01849 i--; 01850 free(matches[idx]); 01851 matches[idx] = NULL; 01852 continue; 01853 } 01854 01855 numoutput++; 01856 numoutputline++; 01857 fprintf(stdout, "%-*s ", max, matches[idx]); 01858 free(matches[idx]); 01859 matches[idx] = NULL; 01860 } 01861 if (numoutputline > 0) 01862 fprintf(stdout, "\n"); 01863 } 01864 01865 return numoutput; 01866 } 01867 01868 01869 static char *cli_complete(EditLine *el, int ch) 01870 { 01871 int len = 0; 01872 char *ptr; 01873 int nummatches = 0; 01874 char **matches; 01875 int retval = CC_ERROR; 01876 char buf[2048]; 01877 int res; 01878 01879 LineInfo *lf = (LineInfo *)el_line(el); 01880 01881 *(char *)lf->cursor = '\0'; 01882 ptr = (char *)lf->cursor; 01883 if (ptr) { 01884 while (ptr > lf->buffer) { 01885 if (isspace(*ptr)) { 01886 ptr++; 01887 break; 01888 } 01889 ptr--; 01890 } 01891 } 01892 01893 len = lf->cursor - ptr; 01894 01895 if (ast_opt_remote) { 01896 snprintf(buf, sizeof(buf),"_COMMAND NUMMATCHES \"%s\" \"%s\"", lf->buffer, ptr); 01897 fdprint(ast_consock, buf); 01898 res = read(ast_consock, buf, sizeof(buf)); 01899 buf[res] = '\0'; 01900 nummatches = atoi(buf); 01901 01902 if (nummatches > 0) { 01903 char *mbuf; 01904 int mlen = 0, maxmbuf = 2048; 01905 /* Start with a 2048 byte buffer */ 01906 if (!(mbuf = ast_malloc(maxmbuf))) 01907 return (char *)(CC_ERROR); 01908 snprintf(buf, sizeof(buf),"_COMMAND MATCHESARRAY \"%s\" \"%s\"", lf->buffer, ptr); 01909 fdprint(ast_consock, buf); 01910 res = 0; 01911 mbuf[0] = '\0'; 01912 while (!strstr(mbuf, AST_CLI_COMPLETE_EOF) && res != -1) { 01913 if (mlen + 1024 > maxmbuf) { 01914 /* Every step increment buffer 1024 bytes */ 01915 maxmbuf += 1024; 01916 if (!(mbuf = ast_realloc(mbuf, maxmbuf))) 01917 return (char *)(CC_ERROR); 01918 } 01919 /* Only read 1024 bytes at a time */ 01920 res = read(ast_consock, mbuf + mlen, 1024); 01921 if (res > 0) 01922 mlen += res; 01923 } 01924 mbuf[mlen] = '\0'; 01925 01926 matches = ast_el_strtoarr(mbuf); 01927 free(mbuf); 01928 } else 01929 matches = (char **) NULL; 01930 } else { 01931 char **p, *oldbuf=NULL; 01932 nummatches = 0; 01933 matches = ast_cli_completion_matches((char *)lf->buffer,ptr); 01934 for (p = matches; p && *p; p++) { 01935 if (!oldbuf || strcmp(*p,oldbuf)) 01936 nummatches++; 01937 oldbuf = *p; 01938 } 01939 } 01940 01941 if (matches) { 01942 int i; 01943 int matches_num, maxlen, match_len; 01944 01945 if (matches[0][0] != '\0') { 01946 el_deletestr(el, (int) len); 01947 el_insertstr(el, matches[0]); 01948 retval = CC_REFRESH; 01949 } 01950 01951 if (nummatches == 1) { 01952 /* Found an exact match */ 01953 el_insertstr(el, " "); 01954 retval = CC_REFRESH; 01955 } else { 01956 /* Must be more than one match */ 01957 for (i=1, maxlen=0; matches[i]; i++) { 01958 match_len = strlen(matches[i]); 01959 if (match_len > maxlen) 01960 maxlen = match_len; 01961 } 01962 matches_num = i - 1; 01963 if (matches_num >1) { 01964 fprintf(stdout, "\n"); 01965 ast_cli_display_match_list(matches, nummatches, maxlen); 01966 retval = CC_REDISPLAY; 01967 } else { 01968 el_insertstr(el," "); 01969 retval = CC_REFRESH; 01970 } 01971 } 01972 for (i = 0; matches[i]; i++) 01973 free(matches[i]); 01974 free(matches); 01975 } 01976 01977 return (char *)(long)retval; 01978 } 01979 01980 static int ast_el_initialize(void) 01981 { 01982 HistEvent ev; 01983 char *editor = getenv("AST_EDITOR"); 01984 01985 if (el != NULL) 01986 el_end(el); 01987 if (el_hist != NULL) 01988 history_end(el_hist); 01989 01990 el = el_init("asterisk", stdin, stdout, stderr); 01991 el_set(el, EL_PROMPT, cli_prompt); 01992 01993 el_set(el, EL_EDITMODE, 1); 01994 el_set(el, EL_EDITOR, editor ? editor : "emacs"); 01995 el_hist = history_init(); 01996 if (!el || !el_hist) 01997 return -1; 01998 01999 /* setup history with 100 entries */ 02000 history(el_hist, &ev, H_SETSIZE, 100); 02001 02002 el_set(el, EL_HIST, history, el_hist); 02003 02004 el_set(el, EL_ADDFN, "ed-complete", "Complete argument", cli_complete); 02005 /* Bind <tab> to command completion */ 02006 el_set(el, EL_BIND, "^I", "ed-complete", NULL); 02007 /* Bind ? to command completion */ 02008 el_set(el, EL_BIND, "?", "ed-complete", NULL); 02009 /* Bind ^D to redisplay */ 02010 el_set(el, EL_BIND, "^D", "ed-redisplay", NULL); 02011 02012 return 0; 02013 } 02014 02015 static int ast_el_add_history(char *buf) 02016 { 02017 HistEvent ev; 02018 02019 if (el_hist == NULL || el == NULL) 02020 ast_el_initialize(); 02021 if (strlen(buf) > 256) 02022 return 0; 02023 return (history(el_hist, &ev, H_ENTER, buf)); 02024 } 02025 02026 static int ast_el_write_history(char *filename) 02027 { 02028 HistEvent ev; 02029 02030 if (el_hist == NULL || el == NULL) 02031 ast_el_initialize(); 02032 02033 return (history(el_hist, &ev, H_SAVE, filename)); 02034 } 02035 02036 static int ast_el_read_history(char *filename) 02037 { 02038 char buf[256]; 02039 FILE *f; 02040 int ret = -1; 02041 02042 if (el_hist == NULL || el == NULL) 02043 ast_el_initialize(); 02044 02045 if ((f = fopen(filename, "r")) == NULL) 02046 return ret; 02047 02048 while (!feof(f)) { 02049 fgets(buf, sizeof(buf), f); 02050 if (!strcmp(buf, "_HiStOrY_V2_\n")) 02051 continue; 02052 if (ast_all_zeros(buf)) 02053 continue; 02054 if ((ret = ast_el_add_history(buf)) == -1) 02055 break; 02056 } 02057 fclose(f); 02058 02059 return ret; 02060 } 02061 02062 static void ast_remotecontrol(char * data) 02063 { 02064 char buf[80]; 02065 int res; 02066 char filename[80] = ""; 02067 char *hostname; 02068 char *cpid; 02069 char *version; 02070 int pid; 02071 char tmp[80]; 02072 char *stringp = NULL; 02073 02074 char *ebuf; 02075 int num = 0; 02076 02077 read(ast_consock, buf, sizeof(buf)); 02078 if (data) 02079 write(ast_consock, data, strlen(data) + 1); 02080 stringp = buf; 02081 hostname = strsep(&stringp, "/"); 02082 cpid = strsep(&stringp, "/"); 02083 version = strsep(&stringp, "\n"); 02084 if (!version) 02085 version = "<Version Unknown>"; 02086 stringp = hostname; 02087 strsep(&stringp, "."); 02088 if (cpid) 02089 pid = atoi(cpid); 02090 else 02091 pid = -1; 02092 snprintf(tmp, sizeof(tmp), "core set verbose atleast %d", option_verbose); 02093 fdprint(ast_consock, tmp); 02094 snprintf(tmp, sizeof(tmp), "core set debug atleast %d", option_debug); 02095 fdprint(ast_consock, tmp); 02096 if (ast_opt_mute) { 02097 snprintf(tmp, sizeof(tmp), "log and verbose output currently muted ('logger unmute' to unmute)"); 02098 fdprint(ast_consock, tmp); 02099 } 02100 ast_verbose("Connected to Asterisk %s currently running on %s (pid = %d)\n", version, hostname, pid); 02101 remotehostname = hostname; 02102 if (getenv("HOME")) 02103 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME")); 02104 if (el_hist == NULL || el == NULL) 02105 ast_el_initialize(); 02106 02107 el_set(el, EL_GETCFN, ast_el_read_char); 02108 02109 if (!ast_strlen_zero(filename)) 02110 ast_el_read_history(filename); 02111 02112 if (ast_opt_exec && data) { /* hack to print output then exit if asterisk -rx is used */ 02113 char tempchar; 02114 struct pollfd fds; 02115 fds.fd = ast_consock; 02116 fds.events = POLLIN; 02117 fds.revents = 0; 02118 while (poll(&fds, 1, 100) > 0) 02119 ast_el_read_char(el, &tempchar); 02120 return; 02121 } 02122 for (;;) { 02123 ebuf = (char *)el_gets(el, &num); 02124 02125 if (!ast_strlen_zero(ebuf)) { 02126 if (ebuf[strlen(ebuf)-1] == '\n') 02127 ebuf[strlen(ebuf)-1] = '\0'; 02128 if (!remoteconsolehandler(ebuf)) { 02129 res = write(ast_consock, ebuf, strlen(ebuf) + 1); 02130 if (res < 1) { 02131 ast_log(LOG_WARNING, "Unable to write: %s\n", strerror(errno)); 02132 break; 02133 } 02134 } 02135 } 02136 02137 if (need_reload) { 02138 need_reload = 0; 02139 ast_module_reload(NULL); 02140 } 02141 } 02142 printf("\nDisconnected from Asterisk server\n"); 02143 } 02144 02145 static int show_version(void) 02146 { 02147 printf("Asterisk " ASTERISK_VERSION "\n"); 02148 return 0; 02149 } 02150 02151 static int show_cli_help(void) { 02152 printf("Asterisk " ASTERISK_VERSION ", Copyright (C) 1999 - 2006, Digium, Inc. and others.\n"); 02153 printf("Usage: asterisk [OPTIONS]\n"); 02154 printf("Valid Options:\n"); 02155 printf(" -V Display version number and exit\n"); 02156 printf(" -C <configfile> Use an alternate configuration file\n"); 02157 printf(" -G <group> Run as a group other than the caller\n"); 02158 printf(" -U <user> Run as a user other than the caller\n"); 02159 printf(" -c Provide console CLI\n"); 02160 printf(" -d Enable extra debugging\n"); 02161 #if HAVE_WORKING_FORK 02162 printf(" -f Do not fork\n"); 02163 printf(" -F Always fork\n"); 02164 #endif 02165 printf(" -g Dump core in case of a crash\n"); 02166 printf(" -h This help screen\n"); 02167 printf(" -i Initialize crypto keys at startup\n"); 02168 printf(" -I Enable internal timing if Zaptel timer is available\n"); 02169 printf(" -L <load> Limit the maximum load average before rejecting new calls\n"); 02170 printf(" -M <value> Limit the maximum number of calls to the specified value\n"); 02171 printf(" -m Mute the console from debugging and verbose output\n"); 02172 printf(" -n Disable console colorization\n"); 02173 printf(" -p Run as pseudo-realtime thread\n"); 02174 printf(" -q Quiet mode (suppress output)\n"); 02175 printf(" -r Connect to Asterisk on this machine\n"); 02176 printf(" -R Connect to Asterisk, and attempt to reconnect if disconnected\n"); 02177 printf(" -t Record soundfiles in /var/tmp and move them where they belong after they are done.\n"); 02178 printf(" -T Display the time in [Mmm dd hh:mm:ss] format for each line of output to the CLI.\n"); 02179 printf(" -v Increase verbosity (multiple v's = more verbose)\n"); 02180 printf(" -x <cmd> Execute command <cmd> (only valid with -r)\n"); 02181 printf("\n"); 02182 return 0; 02183 } 02184 02185 static void ast_readconfig(void) 02186 { 02187 struct ast_config *cfg; 02188 struct ast_variable *v; 02189 char *config = AST_CONFIG_FILE; 02190 02191 if (ast_opt_override_config) { 02192 cfg = ast_config_load(ast_config_AST_CONFIG_FILE); 02193 if (!cfg) 02194 ast_log(LOG_WARNING, "Unable to open specified master config file '%s', using built-in defaults\n", ast_config_AST_CONFIG_FILE); 02195 } else 02196 cfg = ast_config_load(config); 02197 02198 /* init with buildtime config */ 02199 ast_copy_string(ast_config_AST_CONFIG_DIR, AST_CONFIG_DIR, sizeof(ast_config_AST_CONFIG_DIR)); 02200 ast_copy_string(ast_config_AST_SPOOL_DIR, AST_SPOOL_DIR, sizeof(ast_config_AST_SPOOL_DIR)); 02201 ast_copy_string(ast_config_AST_MODULE_DIR, AST_MODULE_DIR, sizeof(ast_config_AST_MODULE_DIR)); 02202 snprintf(ast_config_AST_MONITOR_DIR, sizeof(ast_config_AST_MONITOR_DIR) - 1, "%s/monitor", ast_config_AST_SPOOL_DIR); 02203 ast_copy_string(ast_config_AST_VAR_DIR, AST_VAR_DIR, sizeof(ast_config_AST_VAR_DIR)); 02204 ast_copy_string(ast_config_AST_DATA_DIR, AST_DATA_DIR, sizeof(ast_config_AST_DATA_DIR)); 02205 ast_copy_string(ast_config_AST_LOG_DIR, AST_LOG_DIR, sizeof(ast_config_AST_LOG_DIR)); 02206 ast_copy_string(ast_config_AST_AGI_DIR, AST_AGI_DIR, sizeof(ast_config_AST_AGI_DIR)); 02207 ast_copy_string(ast_config_AST_DB, AST_DB, sizeof(ast_config_AST_DB)); 02208 ast_copy_string(ast_config_AST_KEY_DIR, AST_KEY_DIR, sizeof(ast_config_AST_KEY_DIR)); 02209 ast_copy_string(ast_config_AST_PID, AST_PID, sizeof(ast_config_AST_PID)); 02210 ast_copy_string(ast_config_AST_SOCKET, AST_SOCKET, sizeof(ast_config_AST_SOCKET)); 02211 ast_copy_string(ast_config_AST_RUN_DIR, AST_RUN_DIR, sizeof(ast_config_AST_RUN_DIR)); 02212 02213 /* no asterisk.conf? no problem, use buildtime config! */ 02214 if (!cfg) { 02215 return; 02216 } 02217 02218 for (v = ast_variable_browse(cfg, "files"); v; v = v->next) { 02219 if (!strcasecmp(v->name, "astctlpermissions")) 02220 ast_copy_string(ast_config_AST_CTL_PERMISSIONS, v->value, sizeof(ast_config_AST_CTL_PERMISSIONS)); 02221 else if (!strcasecmp(v->name, "astctlowner")) 02222 ast_copy_string(ast_config_AST_CTL_OWNER, v->value, sizeof(ast_config_AST_CTL_OWNER)); 02223 else if (!strcasecmp(v->name, "astctlgroup")) 02224 ast_copy_string(ast_config_AST_CTL_GROUP, v->value, sizeof(ast_config_AST_CTL_GROUP)); 02225 else if (!strcasecmp(v->name, "astctl")) 02226 ast_copy_string(ast_config_AST_CTL, v->value, sizeof(ast_config_AST_CTL)); 02227 } 02228 02229 for (v = ast_variable_browse(cfg, "directories"); v; v = v->next) { 02230 if (!strcasecmp(v->name, "astetcdir")) { 02231 ast_copy_string(ast_config_AST_CONFIG_DIR, v->value, sizeof(ast_config_AST_CONFIG_DIR)); 02232 } else if (!strcasecmp(v->name, "astspooldir")) { 02233 ast_copy_string(ast_config_AST_SPOOL_DIR, v->value, sizeof(ast_config_AST_SPOOL_DIR)); 02234 snprintf(ast_config_AST_MONITOR_DIR, sizeof(ast_config_AST_MONITOR_DIR) - 1, "%s/monitor", v->value); 02235 } else if (!strcasecmp(v->name, "astvarlibdir")) { 02236 ast_copy_string(ast_config_AST_VAR_DIR, v->value, sizeof(ast_config_AST_VAR_DIR)); 02237 snprintf(ast_config_AST_DB, sizeof(ast_config_AST_DB), "%s/astdb", v->value); 02238 } else if (!strcasecmp(v->name, "astdatadir")) { 02239 ast_copy_string(ast_config_AST_DATA_DIR, v->value, sizeof(ast_config_AST_DATA_DIR)); 02240 snprintf(ast_config_AST_KEY_DIR, sizeof(ast_config_AST_KEY_DIR), "%s/keys", v->value); 02241 } else if (!strcasecmp(v->name, "astlogdir")) { 02242 ast_copy_string(ast_config_AST_LOG_DIR, v->value, sizeof(ast_config_AST_LOG_DIR)); 02243 } else if (!strcasecmp(v->name, "astagidir")) { 02244 ast_copy_string(ast_config_AST_AGI_DIR, v->value, sizeof(ast_config_AST_AGI_DIR)); 02245 } else if (!strcasecmp(v->name, "astrundir")) { 02246 snprintf(ast_config_AST_PID, sizeof(ast_config_AST_PID), "%s/%s", v->value, "asterisk.pid"); 02247 snprintf(ast_config_AST_SOCKET, sizeof(ast_config_AST_SOCKET), "%s/%s", v->value, ast_config_AST_CTL); 02248 ast_copy_string(ast_config_AST_RUN_DIR, v->value, sizeof(ast_config_AST_RUN_DIR)); 02249 } else if (!strcasecmp(v->name, "astmoddir")) { 02250 ast_copy_string(ast_config_AST_MODULE_DIR, v->value, sizeof(ast_config_AST_MODULE_DIR)); 02251 } 02252 } 02253 02254 for (v = ast_variable_browse(cfg, "options"); v; v = v->next) { 02255 /* verbose level (-v at startup) */ 02256 if (!strcasecmp(v->name, "verbose")) { 02257 option_verbose = atoi(v->value); 02258 /* whether or not to force timestamping in CLI verbose output. (-T at startup) */ 02259 } else if (!strcasecmp(v->name, "timestamp")) { 02260 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TIMESTAMP); 02261 /* whether or not to support #exec in config files */ 02262 } else if (!strcasecmp(v->name, "execincludes")) { 02263 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_EXEC_INCLUDES); 02264 /* debug level (-d at startup) */ 02265 } else if (!strcasecmp(v->name, "debug")) { 02266 option_debug = 0; 02267 if (sscanf(v->value, "%d", &option_debug) != 1) { 02268 option_debug = ast_true(v->value); 02269 } 02270 #if HAVE_WORKING_FORK 02271 /* Disable forking (-f at startup) */ 02272 } else if (!strcasecmp(v->name, "nofork")) { 02273 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_FORK); 02274 /* Always fork, even if verbose or debug are enabled (-F at startup) */ 02275 } else if (!strcasecmp(v->name, "alwaysfork")) { 02276 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_ALWAYS_FORK); 02277 #endif 02278 /* Run quietly (-q at startup ) */ 02279 } else if (!strcasecmp(v->name, "quiet")) { 02280 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_QUIET); 02281 /* Run as console (-c at startup, implies nofork) */ 02282 } else if (!strcasecmp(v->name, "console")) { 02283 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_CONSOLE); 02284 /* Run with high priority if the O/S permits (-p at startup) */ 02285 } else if (!strcasecmp(v->name, "highpriority")) { 02286 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_HIGH_PRIORITY); 02287 /* Initialize RSA auth keys (IAX2) (-i at startup) */ 02288 } else if (!strcasecmp(v->name, "initcrypto")) { 02289 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_INIT_KEYS); 02290 /* Disable ANSI colors for console (-c at startup) */ 02291 } else if (!strcasecmp(v->name, "nocolor")) { 02292 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_COLOR); 02293 /* Disable some usage warnings for picky people :p */ 02294 } else if (!strcasecmp(v->name, "dontwarn")) { 02295 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_DONT_WARN); 02296 /* Dump core in case of crash (-g) */ 02297 } else if (!strcasecmp(v->name, "dumpcore")) { 02298 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_DUMP_CORE); 02299 /* Cache recorded sound files to another directory during recording */ 02300 } else if (!strcasecmp(v->name, "cache_record_files")) { 02301 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_CACHE_RECORD_FILES); 02302 /* Specify cache directory */ 02303 } else if (!strcasecmp(v->name, "record_cache_dir")) { 02304 ast_copy_string(record_cache_dir, v->value, AST_CACHE_DIR_LEN); 02305 /* Build transcode paths via SLINEAR, instead of directly */ 02306 } else if (!strcasecmp(v->name, "transcode_via_sln")) { 02307 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TRANSCODE_VIA_SLIN); 02308 /* Transmit SLINEAR silence while a channel is being recorded */ 02309 } else if (!strcasecmp(v->name, "transmit_silence_during_record")) { 02310 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TRANSMIT_SILENCE); 02311 /* Enable internal timing */ 02312 } else if (!strcasecmp(v->name, "internal_timing")) { 02313 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_INTERNAL_TIMING); 02314 } else if (!strcasecmp(v->name, "maxcalls")) { 02315 if ((sscanf(v->value, "%d", &option_maxcalls) != 1) || (option_maxcalls < 0)) { 02316 option_maxcalls = 0; 02317 } 02318 } else if (!strcasecmp(v->name, "maxload")) { 02319 double test[1]; 02320 02321 if (getloadavg(test, 1) == -1) { 02322 ast_log(LOG_ERROR, "Cannot obtain load average on this system. 'maxload' option disabled.\n"); 02323 option_maxload = 0.0; 02324 } else if ((sscanf(v->value, "%lf", &option_maxload) != 1) || (option_maxload < 0.0)) { 02325 option_maxload = 0.0; 02326 } 02327 /* Set the maximum amount of open files */ 02328 } else if (!strcasecmp(v->name, "maxfiles")) { 02329 set_ulimit(atoi(v->value)); 02330 /* What user to run as */ 02331 } else if (!strcasecmp(v->name, "runuser")) { 02332 ast_copy_string(ast_config_AST_RUN_USER, v->value, sizeof(ast_config_AST_RUN_USER)); 02333 /* What group to run as */ 02334 } else if (!strcasecmp(v->name, "rungroup")) { 02335 ast_copy_string(ast_config_AST_RUN_GROUP, v->value, sizeof(ast_config_AST_RUN_GROUP)); 02336 } else if (!strcasecmp(v->name, "systemname")) { 02337 ast_copy_string(ast_config_AST_SYSTEM_NAME, v->value, sizeof(ast_config_AST_SYSTEM_NAME)); 02338 } else if (!strcasecmp(v->name, "languageprefix")) { 02339 ast_language_is_prefix = ast_true(v->value); 02340 } 02341 } 02342 ast_config_destroy(cfg); 02343 } 02344 02345 int main(int argc, char *argv[]) 02346 { 02347 int c; 02348 char filename[80] = ""; 02349 char hostname[MAXHOSTNAMELEN] = ""; 02350 char tmp[80]; 02351 char * xarg = NULL; 02352 int x; 02353 FILE *f; 02354 sigset_t sigs; 02355 int num; 02356 int is_child_of_nonroot = 0; 02357 char *buf; 02358 char *runuser = NULL, *rungroup = NULL; 02359 02360 /* Remember original args for restart */ 02361 if (argc > sizeof(_argv) / sizeof(_argv[0]) - 1) { 02362 fprintf(stderr, "Truncating argument size to %d\n", (int)(sizeof(_argv) / sizeof(_argv[0])) - 1); 02363 argc = sizeof(_argv) / sizeof(_argv[0]) - 1; 02364 } 02365 for (x=0; x<argc; x++) 02366 _argv[x] = argv[x]; 02367 _argv[x] = NULL; 02368 02369 /* if the progname is rasterisk consider it a remote console */ 02370 if (argv[0] && (strstr(argv[0], "rasterisk")) != NULL) { 02371 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE); 02372 } 02373 if (gethostname(hostname, sizeof(hostname)-1)) 02374 ast_copy_string(hostname, "<Unknown>", sizeof(hostname)); 02375 ast_mainpid = getpid(); 02376 ast_ulaw_init(); 02377 ast_alaw_init(); 02378 callerid_init(); 02379 ast_builtins_init(); 02380 ast_utils_init(); 02381 tdd_init(); 02382 /* When Asterisk restarts after it has dropped the root privileges, 02383 * it can't issue setuid(), setgid(), setgroups() or set_priority() 02384 */ 02385 if (getenv("ASTERISK_ALREADY_NONROOT")) 02386 is_child_of_nonroot=1; 02387 if (getenv("HOME")) 02388 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME")); 02389 /* Check for options */ 02390 while ((c = getopt(argc, argv, "mtThfFdvVqprRgciInx:U:G:C:L:M:")) != -1) { 02391 switch (c) { 02392 #if HAVE_WORKING_FORK 02393 case 'F': 02394 ast_set_flag(&ast_options, AST_OPT_FLAG_ALWAYS_FORK); 02395 break; 02396 case 'f': 02397 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK); 02398 break; 02399 #endif 02400 case 'd': 02401 option_debug++; 02402 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK); 02403 break; 02404 case 'c': 02405 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_CONSOLE); 02406 break; 02407 case 'n': 02408 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_COLOR); 02409 break; 02410 case 'r': 02411 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE); 02412 break; 02413 case 'R': 02414 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE | AST_OPT_FLAG_RECONNECT); 02415 break; 02416 case 'p': 02417 ast_set_flag(&ast_options, AST_OPT_FLAG_HIGH_PRIORITY); 02418 break; 02419 case 'v': 02420 option_verbose++; 02421 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK); 02422 break; 02423 case 'm': 02424 ast_set_flag(&ast_options, AST_OPT_FLAG_MUTE); 02425 break; 02426 case 'M': 02427 if ((sscanf(optarg, "%d", &option_maxcalls) != 1) || (option_maxcalls < 0)) 02428 option_maxcalls = 0; 02429 break; 02430 case 'L': 02431 if ((sscanf(optarg, "%lf", &option_maxload) != 1) || (option_maxload < 0.0)) 02432 option_maxload = 0.0; 02433 break; 02434 case 'q': 02435 ast_set_flag(&ast_options, AST_OPT_FLAG_QUIET); 02436 break; 02437 case 't': 02438 ast_set_flag(&ast_options, AST_OPT_FLAG_CACHE_RECORD_FILES); 02439 break; 02440 case 'T': 02441 ast_set_flag(&ast_options, AST_OPT_FLAG_TIMESTAMP); 02442 break; 02443 case 'x': 02444 ast_set_flag(&ast_options, AST_OPT_FLAG_EXEC); 02445 xarg = optarg; 02446 break; 02447 case 'C': 02448 ast_copy_string(ast_config_AST_CONFIG_FILE, optarg, sizeof(ast_config_AST_CONFIG_FILE)); 02449 ast_set_flag(&ast_options, AST_OPT_FLAG_OVERRIDE_CONFIG); 02450 break; 02451 case 'I': 02452 ast_set_flag(&ast_options, AST_OPT_FLAG_INTERNAL_TIMING); 02453 break; 02454 case 'i': 02455 ast_set_flag(&ast_options, AST_OPT_FLAG_INIT_KEYS); 02456 break; 02457 case 'g': 02458 ast_set_flag(&ast_options, AST_OPT_FLAG_DUMP_CORE); 02459 break; 02460 case 'h': 02461 show_cli_help(); 02462 exit(0); 02463 case 'V': 02464 show_version(); 02465 exit(0); 02466 case 'U': 02467 runuser = optarg; 02468 break; 02469 case 'G': 02470 rungroup = optarg; 02471 break; 02472 case '?': 02473 exit(1); 02474 } 02475 } 02476 02477 if (ast_opt_console || option_verbose || (ast_opt_remote && !ast_opt_exec)) { 02478 ast_register_verbose(console_verboser); 02479 WELCOME_MESSAGE; 02480 } 02481 02482 if (ast_opt_console && !option_verbose) 02483 ast_verbose("[ Booting...\n"); 02484 02485 if (ast_opt_always_fork && (ast_opt_remote || ast_opt_console)) { 02486 ast_log(LOG_WARNING, "'alwaysfork' is not compatible with console or remote console mode; ignored\n"); 02487 ast_clear_flag(&ast_options, AST_OPT_FLAG_ALWAYS_FORK); 02488 } 02489 02490 /* For remote connections, change the name of the remote connection. 02491 * We do this for the benefit of init scripts (which need to know if/when 02492 * the main asterisk process has died yet). */ 02493 if (ast_opt_remote) { 02494 strcpy(argv[0], "rasterisk"); 02495 for (x = 1; x < argc; x++) { 02496 argv[x] = argv[0] + 10; 02497 } 02498 } 02499 02500 if (ast_opt_console && !option_verbose) 02501 ast_verbose("[ Reading Master Configuration ]\n"); 02502 ast_readconfig(); 02503 02504 if (!ast_language_is_prefix && !ast_opt_remote) 02505 ast_log(LOG_WARNING, "The 'languageprefix' option in asterisk.conf is deprecated; in a future release it will be removed, and your sound files will need to be organized in the 'new style' language layout.\n"); 02506 02507 if (ast_opt_dump_core) { 02508 struct rlimit l; 02509 memset(&l, 0, sizeof(l)); 02510 l.rlim_cur = RLIM_INFINITY; 02511 l.rlim_max = RLIM_INFINITY; 02512 if (setrlimit(RLIMIT_CORE, &l)) { 02513 ast_log(LOG_WARNING, "Unable to disable core size resource limit: %s\n", strerror(errno)); 02514 } 02515 } 02516 02517 if ((!rungroup) && !ast_strlen_zero(ast_config_AST_RUN_GROUP)) 02518 rungroup = ast_config_AST_RUN_GROUP; 02519 if ((!runuser) && !ast_strlen_zero(ast_config_AST_RUN_USER)) 02520 runuser = ast_config_AST_RUN_USER; 02521 02522 #ifndef __CYGWIN__ 02523 02524 if (!is_child_of_nonroot) 02525 ast_set_priority(ast_opt_high_priority); 02526 02527 if (!is_child_of_nonroot && rungroup) { 02528 struct group *gr; 02529 gr = getgrnam(rungroup); 02530 if (!gr) { 02531 ast_log(LOG_WARNING, "No such group '%s'!\n", rungroup); 02532 exit(1); 02533 } 02534 if (setgid(gr->gr_gid)) { 02535 ast_log(LOG_WARNING, "Unable to setgid to %d (%s)\n", (int)gr->gr_gid, rungroup); 02536 exit(1); 02537 } 02538 if (setgroups(0, NULL)) { 02539 ast_log(LOG_WARNING, "Unable to drop unneeded groups\n"); 02540 exit(1); 02541 } 02542 if (option_verbose) 02543 ast_verbose("Running as group '%s'\n", rungroup); 02544 } 02545 02546 if (!is_child_of_nonroot && runuser) { 02547 #ifdef HAVE_CAP 02548 int has_cap = 1; 02549 #endif /* HAVE_CAP */ 02550 struct passwd *pw; 02551 pw = getpwnam(runuser); 02552 if (!pw) { 02553 ast_log(LOG_WARNING, "No such user '%s'!\n", runuser); 02554 exit(1); 02555 } 02556 #ifdef HAVE_CAP 02557 if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0)) { 02558 ast_log(LOG_WARNING, "Unable to keep capabilities.\n"); 02559 has_cap = 0; 02560 } 02561 #endif /* HAVE_CAP */ 02562 if (!rungroup) { 02563 if (setgid(pw->pw_gid)) { 02564 ast_log(LOG_WARNING, "Unable to setgid to %d!\n", (int)pw->pw_gid); 02565 exit(1); 02566 } 02567 if (initgroups(pw->pw_name, pw->pw_gid)) { 02568 ast_log(LOG_WARNING, "Unable to init groups for '%s'\n", runuser); 02569 exit(1); 02570 } 02571 } 02572 if (setuid(pw->pw_uid)) { 02573 ast_log(LOG_WARNING, "Unable to setuid to %d (%s)\n", (int)pw->pw_uid, runuser); 02574 exit(1); 02575 } 02576 setenv("ASTERISK_ALREADY_NONROOT", "yes", 1); 02577 if (option_verbose) 02578 ast_verbose("Running as user '%s'\n", runuser); 02579 #ifdef HAVE_CAP 02580 if (has_cap) { 02581 cap_t cap; 02582 02583 cap = cap_from_text("cap_net_admin=ep"); 02584 02585 if (cap_set_proc(cap)) 02586 ast_log(LOG_WARNING, "Unable to install capabilities.\n"); 02587 02588 if (cap_free(cap)) 02589 ast_log(LOG_WARNING, "Unable to drop capabilities.\n"); 02590 } 02591 #endif /* HAVE_CAP */ 02592 } 02593 02594 #endif /* __CYGWIN__ */ 02595 02596 #ifdef linux 02597 if (geteuid() && ast_opt_dump_core) { 02598 if (prctl(PR_SET_DUMPABLE, 1, 0, 0, 0) < 0) { 02599 ast_log(LOG_WARNING, "Unable to set the process for core dumps after changing to a non-root user. %s\n", strerror(errno)); 02600 } 02601 } 02602 #endif 02603 02604 ast_term_init(); 02605 printf(term_end()); 02606 fflush(stdout); 02607 02608 if (ast_opt_console && !option_verbose) 02609 ast_verbose("[ Initializing Custom Configuration Options ]\n"); 02610 /* custom config setup */ 02611 register_config_cli(); 02612 read_config_maps(); 02613 02614 if (ast_opt_console) { 02615 if (el_hist == NULL || el == NULL) 02616 ast_el_initialize(); 02617 02618 if (!ast_strlen_zero(filename)) 02619 ast_el_read_history(filename); 02620 } 02621 02622 if (ast_tryconnect()) { 02623 /* One is already running */ 02624 if (ast_opt_remote) { 02625 if (ast_opt_exec) { 02626 ast_remotecontrol(xarg); 02627 quit_handler(0, 0, 0, 0); 02628 exit(0); 02629 } 02630 printf(term_quit()); 02631 ast_remotecontrol(NULL); 02632 quit_handler(0, 0, 0, 0); 02633 exit(0); 02634 } else { 02635 ast_log(LOG_ERROR, "Asterisk already running on %s. Use 'asterisk -r' to connect.\n", ast_config_AST_SOCKET); 02636 printf(term_quit()); 02637 exit(1); 02638 } 02639 } else if (ast_opt_remote || ast_opt_exec) { 02640 ast_log(LOG_ERROR, "Unable to connect to remote asterisk (does %s exist?)\n", ast_config_AST_SOCKET); 02641 printf(term_quit()); 02642 exit(1); 02643 } 02644 /* Blindly write pid file since we couldn't connect */ 02645 unlink(ast_config_AST_PID); 02646 f = fopen(ast_config_AST_PID, "w"); 02647 if (f) { 02648 fprintf(f, "%ld\n", (long)getpid()); 02649 fclose(f); 02650 } else 02651 ast_log(LOG_WARNING, "Unable to open pid file '%s': %s\n", ast_config_AST_PID, strerror(errno)); 02652 02653 #if HAVE_WORKING_FORK 02654 if (ast_opt_always_fork || !ast_opt_no_fork) { 02655 daemon(0, 0); 02656 ast_mainpid = getpid(); 02657 /* Blindly re-write pid file since we are forking */ 02658 unlink(ast_config_AST_PID); 02659 f = fopen(ast_config_AST_PID, "w"); 02660 if (f) { 02661 fprintf(f, "%ld\n", (long)ast_mainpid); 02662 fclose(f); 02663 } else 02664 ast_log(LOG_WARNING, "Unable to open pid file '%s': %s\n", ast_config_AST_PID, strerror(errno)); 02665 } 02666 #endif 02667 02668 /* Test recursive mutex locking. */ 02669 if (test_for_thread_safety()) 02670 ast_verbose("Warning! Asterisk is not thread safe.\n"); 02671 02672 ast_makesocket(); 02673 sigemptyset(&sigs); 02674 sigaddset(&sigs, SIGHUP); 02675 sigaddset(&sigs, SIGTERM); 02676 sigaddset(&sigs, SIGINT); 02677 sigaddset(&sigs, SIGPIPE); 02678 sigaddset(&sigs, SIGWINCH); 02679 pthread_sigmask(SIG_BLOCK, &sigs, NULL); 02680 signal(SIGURG, urg_handler); 02681 signal(SIGINT, __quit_handler); 02682 signal(SIGTERM, __quit_handler); 02683 signal(SIGHUP, hup_handler); 02684 signal(SIGCHLD, child_handler); 02685 signal(SIGPIPE, SIG_IGN); 02686 02687 /* ensure that the random number generators are seeded with a different value every time 02688 Asterisk is started 02689 */ 02690 srand((unsigned int) getpid() + (unsigned int) time(NULL)); 02691 initstate((unsigned int) getpid() * 65536 + (unsigned int) time(NULL), randompool, sizeof(randompool)); 02692 02693 if (init_logger()) { /* Start logging subsystem */ 02694 printf(term_quit()); 02695 exit(1); 02696 } 02697 02698 threadstorage_init(); 02699 02700 if (load_modules(1)) { /* Load modules */ 02701 printf(term_quit()); 02702 exit(1); 02703 } 02704 02705 if (dnsmgr_init()) { /* Initialize the DNS manager */ 02706 printf(term_quit()); 02707 exit(1); 02708 } 02709 02710 ast_http_init(); /* Start the HTTP server, if needed */ 02711 02712 ast_channels_init(); 02713 02714 if (init_manager()) { 02715 printf(term_quit()); 02716 exit(1); 02717 } 02718 02719 if (ast_cdr_engine_init()) { 02720 printf(term_quit()); 02721 exit(1); 02722 } 02723 02724 if (ast_device_state_engine_init()) { 02725 printf(term_quit()); 02726 exit(1); 02727 } 02728 02729 ast_rtp_init(); 02730 02731 ast_udptl_init(); 02732 02733 if (ast_image_init()) { 02734 printf(term_quit()); 02735 exit(1); 02736 } 02737 02738 if (ast_file_init()) { 02739 printf(term_quit()); 02740 exit(1); 02741 } 02742 02743 if (load_pbx()) { 02744 printf(term_quit()); 02745 exit(1); 02746 } 02747 02748 if (init_framer()) { 02749 printf(term_quit()); 02750 exit(1); 02751 } 02752 02753 if (astdb_init()) { 02754 printf(term_quit()); 02755 exit(1); 02756 } 02757 02758 if (ast_enum_init()) { 02759 printf(term_quit()); 02760 exit(1); 02761 } 02762 02763 if (load_modules(0)) { 02764 printf(term_quit()); 02765 exit(1); 02766 } 02767 02768 dnsmgr_start_refresh(); 02769 02770 /* We might have the option of showing a console, but for now just 02771 do nothing... */ 02772 if (ast_opt_console && !option_verbose) 02773 ast_verbose(" ]\n"); 02774 if (option_verbose || ast_opt_console) 02775 ast_verbose(term_color(tmp, "Asterisk Ready.\n", COLOR_BRWHITE, COLOR_BLACK, sizeof(tmp))); 02776 if (ast_opt_no_fork) 02777 consolethread = pthread_self(); 02778 02779 ast_set_flag(&ast_options, AST_OPT_FLAG_FULLY_BOOTED); 02780 pthread_sigmask(SIG_UNBLOCK, &sigs, NULL); 02781 02782 #ifdef __AST_DEBUG_MALLOC 02783 __ast_mm_init(); 02784 #endif 02785 02786 time(&ast_startuptime); 02787 ast_cli_register_multiple(cli_asterisk, sizeof(cli_asterisk) / sizeof(struct ast_cli_entry)); 02788 02789 if (ast_opt_console) { 02790 /* Console stuff now... */ 02791 /* Register our quit function */ 02792 char title[256]; 02793 set_icon("Asterisk"); 02794 snprintf(title, sizeof(title), "Asterisk Console on '%s' (pid %ld)", hostname, (long)ast_mainpid); 02795 set_title(title); 02796 02797 for (;;) { 02798 buf = (char *)el_gets(el, &num); 02799 if (buf) { 02800 if (buf[strlen(buf)-1] == '\n') 02801 buf[strlen(buf)-1] = '\0'; 02802 02803 consolehandler((char *)buf); 02804 } else if (ast_opt_remote && (write(STDOUT_FILENO, "\nUse EXIT or QUIT to exit the asterisk console\n", 02805 strlen("\nUse EXIT or QUIT to exit the asterisk console\n")) < 0)) { 02806 /* Whoa, stdout disappeared from under us... Make /dev/null's */ 02807 int fd; 02808 fd = open("/dev/null", O_RDWR); 02809 if (fd > -1) { 02810 dup2(fd, STDOUT_FILENO); 02811 dup2(fd, STDIN_FILENO); 02812 } else 02813 ast_log(LOG_WARNING, "Failed to open /dev/null to recover from dead console. Bad things will happen!\n"); 02814 break; 02815 } 02816 if (need_reload) { 02817 need_reload = 0; 02818 ast_module_reload(NULL); 02819 } 02820 } 02821 } 02822 /* Do nothing */ 02823 for (;;) { /* apparently needed for Mac OS X */ 02824 struct pollfd p = { -1 /* no descriptor */, 0, 0 }; 02825 poll(&p, 0, -1); 02826 /* SIGHUP will cause this to break out of poll() */ 02827 if (need_reload) { 02828 need_reload = 0; 02829 ast_module_reload(NULL); 02830 } 02831 } 02832 02833 return 0; 02834 }