00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053 #include "asterisk.h"
00054
00055 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 151905 $")
00056
00057 #undef sched_setscheduler
00058 #undef setpriority
00059 #include <unistd.h>
00060 #include <stdlib.h>
00061 #include <sys/time.h>
00062 #include <fcntl.h>
00063 #include <stdio.h>
00064 #include <signal.h>
00065 #include <sched.h>
00066 #include <sys/socket.h>
00067 #include <sys/un.h>
00068 #include <sys/wait.h>
00069 #include <string.h>
00070 #include <errno.h>
00071 #include <ctype.h>
00072 #include <sys/resource.h>
00073 #include <grp.h>
00074 #include <pwd.h>
00075 #include <sys/stat.h>
00076
00077 #if defined(HAVE_ZAPTEL) || defined (HAVE_DAHDI)
00078 #include <sys/ioctl.h>
00079 #include "asterisk/dahdi_compat.h"
00080 #endif
00081
00082 #ifdef linux
00083 #include <sys/prctl.h>
00084 #ifdef HAVE_CAP
00085 #include <sys/capability.h>
00086 #endif
00087 #endif
00088 #include <regex.h>
00089
00090 #if defined(__FreeBSD__) || defined( __NetBSD__ ) || defined(SOLARIS)
00091 #include <netdb.h>
00092 #if defined(SOLARIS)
00093 int daemon(int, int);
00094 #endif
00095 #endif
00096
00097 #include "asterisk/logger.h"
00098 #include "asterisk/options.h"
00099 #include "asterisk/cli.h"
00100 #include "asterisk/channel.h"
00101 #include "asterisk/ulaw.h"
00102 #include "asterisk/alaw.h"
00103 #include "asterisk/callerid.h"
00104 #include "asterisk/image.h"
00105 #include "asterisk/tdd.h"
00106 #include "asterisk/term.h"
00107 #include "asterisk/manager.h"
00108 #include "asterisk/cdr.h"
00109 #include "asterisk/pbx.h"
00110 #include "asterisk/enum.h"
00111 #include "asterisk/rtp.h"
00112 #include "asterisk/http.h"
00113 #include "asterisk/udptl.h"
00114 #include "asterisk/app.h"
00115 #include "asterisk/lock.h"
00116 #include "asterisk/utils.h"
00117 #include "asterisk/file.h"
00118 #include "asterisk/io.h"
00119 #include "asterisk/lock.h"
00120 #include "editline/histedit.h"
00121 #include "asterisk/config.h"
00122 #include "asterisk/version.h"
00123 #include "asterisk/linkedlists.h"
00124 #include "asterisk/devicestate.h"
00125 #include "asterisk/module.h"
00126
00127 #include "asterisk/doxyref.h"
00128
00129 #include "../defaults.h"
00130
00131 #ifndef AF_LOCAL
00132 #define AF_LOCAL AF_UNIX
00133 #define PF_LOCAL PF_UNIX
00134 #endif
00135
00136 #define AST_MAX_CONNECTS 128
00137 #define NUM_MSGS 64
00138
00139
00140 #define WELCOME_MESSAGE \
00141 ast_verbose("Asterisk " ASTERISK_VERSION ", Copyright (C) 1999 - 2008 Digium, Inc. and others.\n"); \
00142 ast_verbose("Created by Mark Spencer <markster@digium.com>\n"); \
00143 ast_verbose("Asterisk comes with ABSOLUTELY NO WARRANTY; type 'core show warranty' for details.\n"); \
00144 ast_verbose("This is free software, with components licensed under the GNU General Public\n"); \
00145 ast_verbose("License version 2 and other licenses; you are welcome to redistribute it under\n"); \
00146 ast_verbose("certain conditions. Type 'core show license' for details.\n"); \
00147 ast_verbose("=========================================================================\n")
00148
00149
00150
00151
00152
00153
00154
00155
00156 struct ast_flags ast_options = { AST_DEFAULT_OPTIONS };
00157
00158 int option_verbose;
00159 int option_debug;
00160
00161 double option_maxload;
00162 int option_maxcalls;
00163
00164
00165
00166 char record_cache_dir[AST_CACHE_DIR_LEN] = AST_TMP_DIR;
00167 char debug_filename[AST_FILENAME_MAX] = "";
00168 #ifdef HAVE_ZAPTEL
00169 static char _dahdi_chan_name[AST_CHANNEL_NAME] = "Zap";
00170 static size_t _dahdi_chan_name_len = 3;
00171 static enum dahdi_chan_modes _dahdi_chan_mode = CHAN_ZAP_MODE;
00172 #else
00173 static char _dahdi_chan_name[AST_CHANNEL_NAME] = "DAHDI";
00174 static size_t _dahdi_chan_name_len = 5;
00175 static enum dahdi_chan_modes _dahdi_chan_mode = CHAN_DAHDI_PLUS_ZAP_MODE;
00176 #endif
00177 const char *dahdi_chan_name;
00178 const size_t *dahdi_chan_name_len;
00179 const enum dahdi_chan_modes *dahdi_chan_mode;
00180
00181 static int ast_socket = -1;
00182 static int ast_consock = -1;
00183 pid_t ast_mainpid;
00184 struct console {
00185 int fd;
00186 int p[2];
00187 pthread_t t;
00188 int mute;
00189 };
00190
00191 struct ast_atexit {
00192 void (*func)(void);
00193 AST_LIST_ENTRY(ast_atexit) list;
00194 };
00195
00196 static AST_LIST_HEAD_STATIC(atexits, ast_atexit);
00197
00198 time_t ast_startuptime;
00199 time_t ast_lastreloadtime;
00200
00201 static History *el_hist;
00202 static EditLine *el;
00203 static char *remotehostname;
00204
00205 struct console consoles[AST_MAX_CONNECTS];
00206
00207 char defaultlanguage[MAX_LANGUAGE] = DEFAULT_LANGUAGE;
00208
00209 static int ast_el_add_history(char *);
00210 static int ast_el_read_history(char *);
00211 static int ast_el_write_history(char *);
00212
00213 char ast_config_AST_CONFIG_DIR[PATH_MAX];
00214 char ast_config_AST_CONFIG_FILE[PATH_MAX];
00215 char ast_config_AST_MODULE_DIR[PATH_MAX];
00216 char ast_config_AST_SPOOL_DIR[PATH_MAX];
00217 char ast_config_AST_MONITOR_DIR[PATH_MAX];
00218 char ast_config_AST_VAR_DIR[PATH_MAX];
00219 char ast_config_AST_DATA_DIR[PATH_MAX];
00220 char ast_config_AST_LOG_DIR[PATH_MAX];
00221 char ast_config_AST_AGI_DIR[PATH_MAX];
00222 char ast_config_AST_DB[PATH_MAX];
00223 char ast_config_AST_KEY_DIR[PATH_MAX];
00224 char ast_config_AST_PID[PATH_MAX];
00225 char ast_config_AST_SOCKET[PATH_MAX];
00226 char ast_config_AST_RUN_DIR[PATH_MAX];
00227 char ast_config_AST_RUN_USER[PATH_MAX];
00228 char ast_config_AST_RUN_GROUP[PATH_MAX];
00229 char ast_config_AST_CTL_PERMISSIONS[PATH_MAX];
00230 char ast_config_AST_CTL_OWNER[PATH_MAX] = "\0";
00231 char ast_config_AST_CTL_GROUP[PATH_MAX] = "\0";
00232 char ast_config_AST_CTL[PATH_MAX] = "asterisk.ctl";
00233 char ast_config_AST_SYSTEM_NAME[20] = "";
00234
00235 extern const char *ast_build_hostname;
00236 extern const char *ast_build_kernel;
00237 extern const char *ast_build_machine;
00238 extern const char *ast_build_os;
00239 extern const char *ast_build_date;
00240 extern const char *ast_build_user;
00241
00242 static char *_argv[256];
00243 static int shuttingdown;
00244 static int restartnow;
00245 static pthread_t consolethread = AST_PTHREADT_NULL;
00246
00247 static char randompool[256];
00248
00249 static int sig_alert_pipe[2] = { -1, -1 };
00250 static struct {
00251 unsigned int need_reload:1;
00252 unsigned int need_quit:1;
00253 } sig_flags;
00254
00255 #if !defined(LOW_MEMORY)
00256 struct file_version {
00257 AST_LIST_ENTRY(file_version) list;
00258 const char *file;
00259 char *version;
00260 };
00261
00262 static AST_LIST_HEAD_STATIC(file_versions, file_version);
00263
00264 void ast_register_file_version(const char *file, const char *version)
00265 {
00266 struct file_version *new;
00267 char *work;
00268 size_t version_length;
00269
00270 work = ast_strdupa(version);
00271 work = ast_strip(ast_strip_quoted(work, "$", "$"));
00272 version_length = strlen(work) + 1;
00273
00274 if (!(new = ast_calloc(1, sizeof(*new) + version_length)))
00275 return;
00276
00277 new->file = file;
00278 new->version = (char *) new + sizeof(*new);
00279 memcpy(new->version, work, version_length);
00280 AST_LIST_LOCK(&file_versions);
00281 AST_LIST_INSERT_HEAD(&file_versions, new, list);
00282 AST_LIST_UNLOCK(&file_versions);
00283 }
00284
00285 void ast_unregister_file_version(const char *file)
00286 {
00287 struct file_version *find;
00288
00289 AST_LIST_LOCK(&file_versions);
00290 AST_LIST_TRAVERSE_SAFE_BEGIN(&file_versions, find, list) {
00291 if (!strcasecmp(find->file, file)) {
00292 AST_LIST_REMOVE_CURRENT(&file_versions, list);
00293 break;
00294 }
00295 }
00296 AST_LIST_TRAVERSE_SAFE_END;
00297 AST_LIST_UNLOCK(&file_versions);
00298 if (find)
00299 free(find);
00300 }
00301
00302 struct thread_list_t {
00303 AST_LIST_ENTRY(thread_list_t) list;
00304 char *name;
00305 pthread_t id;
00306 };
00307
00308 static AST_LIST_HEAD_STATIC(thread_list, thread_list_t);
00309
00310 static char show_threads_help[] =
00311 "Usage: core show threads\n"
00312 " List threads currently active in the system.\n";
00313
00314 void ast_register_thread(char *name)
00315 {
00316 struct thread_list_t *new = ast_calloc(1, sizeof(*new));
00317
00318 if (!new)
00319 return;
00320 new->id = pthread_self();
00321 new->name = name;
00322 AST_LIST_LOCK(&thread_list);
00323 AST_LIST_INSERT_HEAD(&thread_list, new, list);
00324 AST_LIST_UNLOCK(&thread_list);
00325 }
00326
00327 void ast_unregister_thread(void *id)
00328 {
00329 struct thread_list_t *x;
00330
00331 AST_LIST_LOCK(&thread_list);
00332 AST_LIST_TRAVERSE_SAFE_BEGIN(&thread_list, x, list) {
00333 if ((void *) x->id == id) {
00334 AST_LIST_REMOVE_CURRENT(&thread_list, list);
00335 break;
00336 }
00337 }
00338 AST_LIST_TRAVERSE_SAFE_END;
00339 AST_LIST_UNLOCK(&thread_list);
00340 if (x) {
00341 free(x->name);
00342 free(x);
00343 }
00344 }
00345
00346 static int handle_show_threads(int fd, int argc, char *argv[])
00347 {
00348 int count = 0;
00349 struct thread_list_t *cur;
00350
00351 AST_LIST_LOCK(&thread_list);
00352 AST_LIST_TRAVERSE(&thread_list, cur, list) {
00353 ast_cli(fd, "%p %s\n", (void *)cur->id, cur->name);
00354 count++;
00355 }
00356 AST_LIST_UNLOCK(&thread_list);
00357 ast_cli(fd, "%d threads listed.\n", count);
00358 return 0;
00359 }
00360
00361 struct profile_entry {
00362 const char *name;
00363 uint64_t scale;
00364 int64_t mark;
00365 int64_t value;
00366 int64_t events;
00367 };
00368
00369 struct profile_data {
00370 int entries;
00371 int max_size;
00372 struct profile_entry e[0];
00373 };
00374
00375 static struct profile_data *prof_data;
00376
00377
00378
00379
00380 int ast_add_profile(const char *name, uint64_t scale)
00381 {
00382 int l = sizeof(struct profile_data);
00383 int n = 10;
00384
00385 if (prof_data == NULL) {
00386 prof_data = ast_calloc(1, l + n*sizeof(struct profile_entry));
00387 if (prof_data == NULL)
00388 return -1;
00389 prof_data->entries = 0;
00390 prof_data->max_size = n;
00391 }
00392 if (prof_data->entries >= prof_data->max_size) {
00393 void *p;
00394 n = prof_data->max_size + 20;
00395 p = ast_realloc(prof_data, l + n*sizeof(struct profile_entry));
00396 if (p == NULL)
00397 return -1;
00398 prof_data = p;
00399 prof_data->max_size = n;
00400 }
00401 n = prof_data->entries++;
00402 prof_data->e[n].name = ast_strdup(name);
00403 prof_data->e[n].value = 0;
00404 prof_data->e[n].events = 0;
00405 prof_data->e[n].mark = 0;
00406 prof_data->e[n].scale = scale;
00407 return n;
00408 }
00409
00410 int64_t ast_profile(int i, int64_t delta)
00411 {
00412 if (!prof_data || i < 0 || i > prof_data->entries)
00413 return 0;
00414 if (prof_data->e[i].scale > 1)
00415 delta /= prof_data->e[i].scale;
00416 prof_data->e[i].value += delta;
00417 prof_data->e[i].events++;
00418 return prof_data->e[i].value;
00419 }
00420
00421
00422
00423
00424 #if defined ( __i686__) && (defined(__FreeBSD__) || defined(linux))
00425 #if defined(__FreeBSD__)
00426 #include <machine/cpufunc.h>
00427 #elif defined(linux)
00428 static __inline uint64_t
00429 rdtsc(void)
00430 {
00431 uint64_t rv;
00432
00433 __asm __volatile(".byte 0x0f, 0x31" : "=A" (rv));
00434 return (rv);
00435 }
00436 #endif
00437 #else
00438 static __inline uint64_t
00439 rdtsc(void)
00440 {
00441 return 0;
00442 }
00443 #endif
00444
00445 int64_t ast_mark(int i, int startstop)
00446 {
00447 if (!prof_data || i < 0 || i > prof_data->entries)
00448 return 0;
00449 if (startstop == 1)
00450 prof_data->e[i].mark = rdtsc();
00451 else {
00452 prof_data->e[i].mark = (rdtsc() - prof_data->e[i].mark);
00453 if (prof_data->e[i].scale > 1)
00454 prof_data->e[i].mark /= prof_data->e[i].scale;
00455 prof_data->e[i].value += prof_data->e[i].mark;
00456 prof_data->e[i].events++;
00457 }
00458 return prof_data->e[i].mark;
00459 }
00460
00461 static int handle_show_profile_deprecated(int fd, int argc, char *argv[])
00462 {
00463 int i, min, max;
00464 char *search = NULL;
00465
00466 if (prof_data == NULL)
00467 return 0;
00468
00469 min = 0;
00470 max = prof_data->entries;
00471 if (argc >= 3) {
00472 if (isdigit(argv[2][0])) {
00473 min = atoi(argv[2]);
00474 if (argc == 4 && strcmp(argv[3], "-"))
00475 max = atoi(argv[3]);
00476 } else
00477 search = argv[2];
00478 }
00479 if (max > prof_data->entries)
00480 max = prof_data->entries;
00481 if (!strcmp(argv[0], "clear")) {
00482 for (i= min; i < max; i++) {
00483 if (!search || strstr(prof_data->e[i].name, search)) {
00484 prof_data->e[i].value = 0;
00485 prof_data->e[i].events = 0;
00486 }
00487 }
00488 return 0;
00489 }
00490 ast_cli(fd, "profile values (%d, allocated %d)\n-------------------\n",
00491 prof_data->entries, prof_data->max_size);
00492 ast_cli(fd, "%6s %8s %10s %12s %12s %s\n", "ID", "Scale", "Events",
00493 "Value", "Average", "Name");
00494 for (i = min; i < max; i++) {
00495 struct profile_entry *e = &prof_data->e[i];
00496 if (!search || strstr(prof_data->e[i].name, search))
00497 ast_cli(fd, "%6d: [%8ld] %10ld %12lld %12lld %s\n",
00498 i,
00499 (long)e->scale,
00500 (long)e->events, (long long)e->value,
00501 (long long)(e->events ? e->value / e->events : e->value),
00502 e->name);
00503 }
00504 return 0;
00505 }
00506
00507 static int handle_show_profile(int fd, int argc, char *argv[])
00508 {
00509 int i, min, max;
00510 char *search = NULL;
00511
00512 if (prof_data == NULL)
00513 return 0;
00514
00515 min = 0;
00516 max = prof_data->entries;
00517 if (argc > 3) {
00518 if (isdigit(argv[3][0])) {
00519 min = atoi(argv[3]);
00520 if (argc == 5 && strcmp(argv[4], "-"))
00521 max = atoi(argv[4]);
00522 } else
00523 search = argv[3];
00524 }
00525 if (max > prof_data->entries)
00526 max = prof_data->entries;
00527 if (!strcmp(argv[1], "clear")) {
00528 for (i= min; i < max; i++) {
00529 if (!search || strstr(prof_data->e[i].name, search)) {
00530 prof_data->e[i].value = 0;
00531 prof_data->e[i].events = 0;
00532 }
00533 }
00534 return 0;
00535 }
00536 ast_cli(fd, "profile values (%d, allocated %d)\n-------------------\n",
00537 prof_data->entries, prof_data->max_size);
00538 ast_cli(fd, "%6s %8s %10s %12s %12s %s\n", "ID", "Scale", "Events",
00539 "Value", "Average", "Name");
00540 for (i = min; i < max; i++) {
00541 struct profile_entry *e = &prof_data->e[i];
00542 if (!search || strstr(prof_data->e[i].name, search))
00543 ast_cli(fd, "%6d: [%8ld] %10ld %12lld %12lld %s\n",
00544 i,
00545 (long)e->scale,
00546 (long)e->events, (long long)e->value,
00547 (long long)(e->events ? e->value / e->events : e->value),
00548 e->name);
00549 }
00550 return 0;
00551 }
00552
00553 static char show_version_files_help[] =
00554 "Usage: core show file version [like <pattern>]\n"
00555 " Lists the revision numbers of the files used to build this copy of Asterisk.\n"
00556 " Optional regular expression pattern is used to filter the file list.\n";
00557
00558
00559 static int handle_show_version_files_deprecated(int fd, int argc, char *argv[])
00560 {
00561 #define FORMAT "%-25.25s %-40.40s\n"
00562 struct file_version *iterator;
00563 regex_t regexbuf;
00564 int havepattern = 0;
00565 int havename = 0;
00566 int count_files = 0;
00567
00568 switch (argc) {
00569 case 5:
00570 if (!strcasecmp(argv[3], "like")) {
00571 if (regcomp(®exbuf, argv[4], REG_EXTENDED | REG_NOSUB))
00572 return RESULT_SHOWUSAGE;
00573 havepattern = 1;
00574 } else
00575 return RESULT_SHOWUSAGE;
00576 break;
00577 case 4:
00578 havename = 1;
00579 break;
00580 case 3:
00581 break;
00582 default:
00583 return RESULT_SHOWUSAGE;
00584 }
00585
00586 ast_cli(fd, FORMAT, "File", "Revision");
00587 ast_cli(fd, FORMAT, "----", "--------");
00588 AST_LIST_LOCK(&file_versions);
00589 AST_LIST_TRAVERSE(&file_versions, iterator, list) {
00590 if (havename && strcasecmp(iterator->file, argv[3]))
00591 continue;
00592
00593 if (havepattern && regexec(®exbuf, iterator->file, 0, NULL, 0))
00594 continue;
00595
00596 ast_cli(fd, FORMAT, iterator->file, iterator->version);
00597 count_files++;
00598 if (havename)
00599 break;
00600 }
00601 AST_LIST_UNLOCK(&file_versions);
00602 if (!havename) {
00603 ast_cli(fd, "%d files listed.\n", count_files);
00604 }
00605
00606 if (havepattern)
00607 regfree(®exbuf);
00608
00609 return RESULT_SUCCESS;
00610 #undef FORMAT
00611 }
00612
00613 static int handle_show_version_files(int fd, int argc, char *argv[])
00614 {
00615 #define FORMAT "%-25.25s %-40.40s\n"
00616 struct file_version *iterator;
00617 regex_t regexbuf;
00618 int havepattern = 0;
00619 int havename = 0;
00620 int count_files = 0;
00621
00622 switch (argc) {
00623 case 6:
00624 if (!strcasecmp(argv[4], "like")) {
00625 if (regcomp(®exbuf, argv[5], REG_EXTENDED | REG_NOSUB))
00626 return RESULT_SHOWUSAGE;
00627 havepattern = 1;
00628 } else
00629 return RESULT_SHOWUSAGE;
00630 break;
00631 case 5:
00632 havename = 1;
00633 break;
00634 case 4:
00635 break;
00636 default:
00637 return RESULT_SHOWUSAGE;
00638 }
00639
00640 ast_cli(fd, FORMAT, "File", "Revision");
00641 ast_cli(fd, FORMAT, "----", "--------");
00642 AST_LIST_LOCK(&file_versions);
00643 AST_LIST_TRAVERSE(&file_versions, iterator, list) {
00644 if (havename && strcasecmp(iterator->file, argv[4]))
00645 continue;
00646
00647 if (havepattern && regexec(®exbuf, iterator->file, 0, NULL, 0))
00648 continue;
00649
00650 ast_cli(fd, FORMAT, iterator->file, iterator->version);
00651 count_files++;
00652 if (havename)
00653 break;
00654 }
00655 AST_LIST_UNLOCK(&file_versions);
00656 if (!havename) {
00657 ast_cli(fd, "%d files listed.\n", count_files);
00658 }
00659
00660 if (havepattern)
00661 regfree(®exbuf);
00662
00663 return RESULT_SUCCESS;
00664 #undef FORMAT
00665 }
00666
00667 static char *complete_show_version_files_deprecated(const char *line, const char *word, int pos, int state)
00668 {
00669 struct file_version *find;
00670 int which = 0;
00671 char *ret = NULL;
00672 int matchlen = strlen(word);
00673
00674 if (pos != 3)
00675 return NULL;
00676
00677 AST_LIST_LOCK(&file_versions);
00678 AST_LIST_TRAVERSE(&file_versions, find, list) {
00679 if (!strncasecmp(word, find->file, matchlen) && ++which > state) {
00680 ret = ast_strdup(find->file);
00681 break;
00682 }
00683 }
00684 AST_LIST_UNLOCK(&file_versions);
00685
00686 return ret;
00687 }
00688
00689 static char *complete_show_version_files(const char *line, const char *word, int pos, int state)
00690 {
00691 struct file_version *find;
00692 int which = 0;
00693 char *ret = NULL;
00694 int matchlen = strlen(word);
00695
00696 if (pos != 4)
00697 return NULL;
00698
00699 AST_LIST_LOCK(&file_versions);
00700 AST_LIST_TRAVERSE(&file_versions, find, list) {
00701 if (!strncasecmp(word, find->file, matchlen) && ++which > state) {
00702 ret = ast_strdup(find->file);
00703 break;
00704 }
00705 }
00706 AST_LIST_UNLOCK(&file_versions);
00707
00708 return ret;
00709 }
00710
00711 #endif
00712
00713 int ast_register_atexit(void (*func)(void))
00714 {
00715 struct ast_atexit *ae;
00716
00717 if (!(ae = ast_calloc(1, sizeof(*ae))))
00718 return -1;
00719
00720 ae->func = func;
00721
00722 ast_unregister_atexit(func);
00723
00724 AST_LIST_LOCK(&atexits);
00725 AST_LIST_INSERT_HEAD(&atexits, ae, list);
00726 AST_LIST_UNLOCK(&atexits);
00727
00728 return 0;
00729 }
00730
00731 void ast_unregister_atexit(void (*func)(void))
00732 {
00733 struct ast_atexit *ae = NULL;
00734
00735 AST_LIST_LOCK(&atexits);
00736 AST_LIST_TRAVERSE_SAFE_BEGIN(&atexits, ae, list) {
00737 if (ae->func == func) {
00738 AST_LIST_REMOVE_CURRENT(&atexits, list);
00739 break;
00740 }
00741 }
00742 AST_LIST_TRAVERSE_SAFE_END
00743 AST_LIST_UNLOCK(&atexits);
00744
00745 if (ae)
00746 free(ae);
00747 }
00748
00749
00750 static int fdsend(int fd, const char *s)
00751 {
00752 return write(fd, s, strlen(s) + 1);
00753 }
00754
00755
00756 static int fdprint(int fd, const char *s)
00757 {
00758 return write(fd, s, strlen(s));
00759 }
00760
00761
00762 static void null_sig_handler(int signal)
00763 {
00764
00765 }
00766
00767 AST_MUTEX_DEFINE_STATIC(safe_system_lock);
00768
00769
00770 static unsigned int safe_system_level = 0;
00771 static void *safe_system_prev_handler;
00772
00773 void ast_replace_sigchld(void)
00774 {
00775 unsigned int level;
00776
00777 ast_mutex_lock(&safe_system_lock);
00778 level = safe_system_level++;
00779
00780
00781 if (level == 0)
00782 safe_system_prev_handler = signal(SIGCHLD, null_sig_handler);
00783
00784 ast_mutex_unlock(&safe_system_lock);
00785 }
00786
00787 void ast_unreplace_sigchld(void)
00788 {
00789 unsigned int level;
00790
00791 ast_mutex_lock(&safe_system_lock);
00792 level = --safe_system_level;
00793
00794
00795 if (level == 0)
00796 signal(SIGCHLD, safe_system_prev_handler);
00797
00798 ast_mutex_unlock(&safe_system_lock);
00799 }
00800
00801 int ast_safe_system(const char *s)
00802 {
00803 pid_t pid;
00804 #ifdef HAVE_WORKING_FORK
00805 int x;
00806 #endif
00807 int res;
00808 struct rusage rusage;
00809 int status;
00810
00811 #if defined(HAVE_WORKING_FORK) || defined(HAVE_WORKING_VFORK)
00812 ast_replace_sigchld();
00813
00814 #ifdef HAVE_WORKING_FORK
00815 pid = fork();
00816 #else
00817 pid = vfork();
00818 #endif
00819
00820 if (pid == 0) {
00821 #ifdef HAVE_WORKING_FORK
00822 if (ast_opt_high_priority)
00823 ast_set_priority(0);
00824
00825 for (x = STDERR_FILENO + 1; x < 4096; x++)
00826 close(x);
00827 #endif
00828 execl("/bin/sh", "/bin/sh", "-c", s, (char *) NULL);
00829 _exit(1);
00830 } else if (pid > 0) {
00831 for(;;) {
00832 res = wait4(pid, &status, 0, &rusage);
00833 if (res > -1) {
00834 res = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
00835 break;
00836 } else if (errno != EINTR)
00837 break;
00838 }
00839 } else {
00840 ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno));
00841 res = -1;
00842 }
00843
00844 ast_unreplace_sigchld();
00845 #else
00846 res = -1;
00847 #endif
00848
00849 return res;
00850 }
00851
00852
00853
00854
00855 void ast_console_toggle_mute(int fd, int silent) {
00856 int x;
00857 for (x = 0;x < AST_MAX_CONNECTS; x++) {
00858 if (fd == consoles[x].fd) {
00859 if (consoles[x].mute) {
00860 consoles[x].mute = 0;
00861 if (!silent)
00862 ast_cli(fd, "Console is not muted anymore.\n");
00863 } else {
00864 consoles[x].mute = 1;
00865 if (!silent)
00866 ast_cli(fd, "Console is muted.\n");
00867 }
00868 return;
00869 }
00870 }
00871 ast_cli(fd, "Couldn't find remote console.\n");
00872 }
00873
00874
00875
00876
00877 static void ast_network_puts_mutable(const char *string)
00878 {
00879 int x;
00880 for (x = 0;x < AST_MAX_CONNECTS; x++) {
00881 if (consoles[x].mute)
00882 continue;
00883 if (consoles[x].fd > -1)
00884 fdprint(consoles[x].p[1], string);
00885 }
00886 }
00887
00888
00889
00890
00891
00892 void ast_console_puts_mutable(const char *string)
00893 {
00894 fputs(string, stdout);
00895 fflush(stdout);
00896 ast_network_puts_mutable(string);
00897 }
00898
00899
00900
00901
00902 static void ast_network_puts(const char *string)
00903 {
00904 int x;
00905 for (x=0; x < AST_MAX_CONNECTS; x++) {
00906 if (consoles[x].fd > -1)
00907 fdprint(consoles[x].p[1], string);
00908 }
00909 }
00910
00911
00912
00913
00914
00915 void ast_console_puts(const char *string)
00916 {
00917 fputs(string, stdout);
00918 fflush(stdout);
00919 ast_network_puts(string);
00920 }
00921
00922 static void network_verboser(const char *s)
00923 {
00924 ast_network_puts_mutable(s);
00925 }
00926
00927 static pthread_t lthread;
00928
00929 static void *netconsole(void *vconsole)
00930 {
00931 struct console *con = vconsole;
00932 char hostname[MAXHOSTNAMELEN] = "";
00933 char tmp[512];
00934 int res;
00935 struct pollfd fds[2];
00936
00937 if (gethostname(hostname, sizeof(hostname)-1))
00938 ast_copy_string(hostname, "<Unknown>", sizeof(hostname));
00939 snprintf(tmp, sizeof(tmp), "%s/%ld/%s\n", hostname, (long)ast_mainpid, ASTERISK_VERSION);
00940 fdprint(con->fd, tmp);
00941 for(;;) {
00942 fds[0].fd = con->fd;
00943 fds[0].events = POLLIN;
00944 fds[0].revents = 0;
00945 fds[1].fd = con->p[0];
00946 fds[1].events = POLLIN;
00947 fds[1].revents = 0;
00948
00949 res = poll(fds, 2, -1);
00950 if (res < 0) {
00951 if (errno != EINTR)
00952 ast_log(LOG_WARNING, "poll returned < 0: %s\n", strerror(errno));
00953 continue;
00954 }
00955 if (fds[0].revents) {
00956 res = read(con->fd, tmp, sizeof(tmp));
00957 if (res < 1) {
00958 break;
00959 }
00960 tmp[res] = 0;
00961 ast_cli_command_multiple(con->fd, res, tmp);
00962 }
00963 if (fds[1].revents) {
00964 res = read(con->p[0], tmp, sizeof(tmp));
00965 if (res < 1) {
00966 ast_log(LOG_ERROR, "read returned %d\n", res);
00967 break;
00968 }
00969 res = write(con->fd, tmp, res);
00970 if (res < 1)
00971 break;
00972 }
00973 }
00974 if (option_verbose > 2)
00975 ast_verbose(VERBOSE_PREFIX_3 "Remote UNIX connection disconnected\n");
00976 close(con->fd);
00977 close(con->p[0]);
00978 close(con->p[1]);
00979 con->fd = -1;
00980
00981 return NULL;
00982 }
00983
00984 static void *listener(void *unused)
00985 {
00986 struct sockaddr_un sunaddr;
00987 int s;
00988 socklen_t len;
00989 int x;
00990 int flags;
00991 struct pollfd fds[1];