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