![]() |
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 ==