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
00061
00062 #include "asterisk.h"
00063
00064 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 296534 $")
00065
00066 #include "asterisk/_private.h"
00067
00068 #undef sched_setscheduler
00069 #undef setpriority
00070 #include <sys/time.h>
00071 #include <fcntl.h>
00072 #include <signal.h>
00073 #include <sched.h>
00074 #include <sys/un.h>
00075 #include <sys/wait.h>
00076 #include <ctype.h>
00077 #include <sys/resource.h>
00078 #include <grp.h>
00079 #include <pwd.h>
00080 #include <sys/stat.h>
00081 #if defined(HAVE_SYSINFO)
00082 #include <sys/sysinfo.h>
00083 #elif defined(HAVE_SYSCTL)
00084 #include <sys/param.h>
00085 #include <sys/sysctl.h>
00086 #if !defined(__OpenBSD__)
00087 #include <sys/vmmeter.h>
00088 #if defined(__FreeBSD__)
00089 #include <vm/vm_param.h>
00090 #endif
00091 #endif
00092 #if defined(HAVE_SWAPCTL)
00093 #include <sys/swap.h>
00094 #endif
00095 #endif
00096 #include <regex.h>
00097
00098 #if defined(SOLARIS)
00099 int daemon(int, int);
00100 #include <sys/loadavg.h>
00101 #endif
00102
00103 #ifdef linux
00104 #include <sys/prctl.h>
00105 #ifdef HAVE_CAP
00106 #include <sys/capability.h>
00107 #endif
00108 #endif
00109
00110 #include "asterisk/paths.h"
00111 #include "asterisk/network.h"
00112 #include "asterisk/cli.h"
00113 #include "asterisk/channel.h"
00114 #include "asterisk/features.h"
00115 #include "asterisk/ulaw.h"
00116 #include "asterisk/alaw.h"
00117 #include "asterisk/callerid.h"
00118 #include "asterisk/image.h"
00119 #include "asterisk/tdd.h"
00120 #include "asterisk/term.h"
00121 #include "asterisk/manager.h"
00122 #include "asterisk/cdr.h"
00123 #include "asterisk/cel.h"
00124 #include "asterisk/pbx.h"
00125 #include "asterisk/enum.h"
00126 #include "asterisk/http.h"
00127 #include "asterisk/udptl.h"
00128 #include "asterisk/app.h"
00129 #include "asterisk/lock.h"
00130 #include "asterisk/utils.h"
00131 #include "asterisk/file.h"
00132 #include "asterisk/io.h"
00133 #include "editline/histedit.h"
00134 #include "asterisk/config.h"
00135 #include "asterisk/ast_version.h"
00136 #include "asterisk/linkedlists.h"
00137 #include "asterisk/devicestate.h"
00138 #include "asterisk/module.h"
00139 #include "asterisk/dsp.h"
00140 #include "asterisk/buildinfo.h"
00141 #include "asterisk/xmldoc.h"
00142 #include "asterisk/poll-compat.h"
00143 #include "asterisk/ccss.h"
00144 #include "asterisk/test.h"
00145 #include "asterisk/aoc.h"
00146
00147 #include "../defaults.h"
00148
00149 #ifndef AF_LOCAL
00150 #define AF_LOCAL AF_UNIX
00151 #define PF_LOCAL PF_UNIX
00152 #endif
00153
00154 #define AST_MAX_CONNECTS 128
00155 #define NUM_MSGS 64
00156
00157
00158 #define WELCOME_MESSAGE \
00159 ast_verbose("Asterisk %s, Copyright (C) 1999 - 2010 Digium, Inc. and others.\n" \
00160 "Created by Mark Spencer <markster@digium.com>\n" \
00161 "Asterisk comes with ABSOLUTELY NO WARRANTY; type 'core show warranty' for details.\n" \
00162 "This is free software, with components licensed under the GNU General Public\n" \
00163 "License version 2 and other licenses; you are welcome to redistribute it under\n" \
00164 "certain conditions. Type 'core show license' for details.\n" \
00165 "=========================================================================\n", ast_get_version()) \
00166
00167
00168
00169
00170
00171
00172
00173
00174 struct ast_flags ast_options = { AST_DEFAULT_OPTIONS };
00175 struct ast_flags ast_compat = { 0 };
00176
00177 int option_verbose;
00178 int option_debug;
00179 double option_maxload;
00180 int option_maxcalls;
00181 int option_maxfiles;
00182 #if defined(HAVE_SYSINFO)
00183 long option_minmemfree;
00184 #endif
00185
00186
00187
00188 struct ast_eid ast_eid_default;
00189
00190
00191 char record_cache_dir[AST_CACHE_DIR_LEN] = DEFAULT_TMP_DIR;
00192
00193 static int ast_socket = -1;
00194 static int ast_consock = -1;
00195 pid_t ast_mainpid;
00196 struct console {
00197 int fd;
00198 int p[2];
00199 pthread_t t;
00200 int mute;
00201 int uid;
00202 int gid;
00203 int levels[NUMLOGLEVELS];
00204 };
00205
00206 struct ast_atexit {
00207 void (*func)(void);
00208 AST_RWLIST_ENTRY(ast_atexit) list;
00209 };
00210
00211 static AST_RWLIST_HEAD_STATIC(atexits, ast_atexit);
00212
00213 struct timeval ast_startuptime;
00214 struct timeval ast_lastreloadtime;
00215
00216 static History *el_hist;
00217 static EditLine *el;
00218 static char *remotehostname;
00219
00220 struct console consoles[AST_MAX_CONNECTS];
00221
00222 char defaultlanguage[MAX_LANGUAGE] = DEFAULT_LANGUAGE;
00223
00224 static int ast_el_add_history(char *);
00225 static int ast_el_read_history(char *);
00226 static int ast_el_write_history(char *);
00227
00228 struct _cfg_paths {
00229 char config_dir[PATH_MAX];
00230 char module_dir[PATH_MAX];
00231 char spool_dir[PATH_MAX];
00232 char monitor_dir[PATH_MAX];
00233 char var_dir[PATH_MAX];
00234 char data_dir[PATH_MAX];
00235 char log_dir[PATH_MAX];
00236 char agi_dir[PATH_MAX];
00237 char run_dir[PATH_MAX];
00238 char key_dir[PATH_MAX];
00239
00240 char config_file[PATH_MAX];
00241 char db_path[PATH_MAX];
00242 char pid_path[PATH_MAX];
00243 char socket_path[PATH_MAX];
00244 char run_user[PATH_MAX];
00245 char run_group[PATH_MAX];
00246 char system_name[128];
00247 };
00248
00249 static struct _cfg_paths cfg_paths;
00250
00251 const char *ast_config_AST_CONFIG_DIR = cfg_paths.config_dir;
00252 const char *ast_config_AST_CONFIG_FILE = cfg_paths.config_file;
00253 const char *ast_config_AST_MODULE_DIR = cfg_paths.module_dir;
00254 const char *ast_config_AST_SPOOL_DIR = cfg_paths.spool_dir;
00255 const char *ast_config_AST_MONITOR_DIR = cfg_paths.monitor_dir;
00256 const char *ast_config_AST_VAR_DIR = cfg_paths.var_dir;
00257 const char *ast_config_AST_DATA_DIR = cfg_paths.data_dir;
00258 const char *ast_config_AST_LOG_DIR = cfg_paths.log_dir;
00259 const char *ast_config_AST_AGI_DIR = cfg_paths.agi_dir;
00260 const char *ast_config_AST_KEY_DIR = cfg_paths.key_dir;
00261 const char *ast_config_AST_RUN_DIR = cfg_paths.run_dir;
00262
00263 const char *ast_config_AST_DB = cfg_paths.db_path;
00264 const char *ast_config_AST_PID = cfg_paths.pid_path;
00265 const char *ast_config_AST_SOCKET = cfg_paths.socket_path;
00266 const char *ast_config_AST_RUN_USER = cfg_paths.run_user;
00267 const char *ast_config_AST_RUN_GROUP = cfg_paths.run_group;
00268 const char *ast_config_AST_SYSTEM_NAME = cfg_paths.system_name;
00269
00270 static char ast_config_AST_CTL_PERMISSIONS[PATH_MAX];
00271 static char ast_config_AST_CTL_OWNER[PATH_MAX] = "\0";
00272 static char ast_config_AST_CTL_GROUP[PATH_MAX] = "\0";
00273 static char ast_config_AST_CTL[PATH_MAX] = "asterisk.ctl";
00274
00275 extern unsigned int ast_FD_SETSIZE;
00276
00277 static char *_argv[256];
00278 static int shuttingdown;
00279 static int restartnow;
00280 static pthread_t consolethread = AST_PTHREADT_NULL;
00281 static pthread_t mon_sig_flags;
00282 static int canary_pid = 0;
00283 static char canary_filename[128];
00284
00285 static char randompool[256];
00286
00287 static int sig_alert_pipe[2] = { -1, -1 };
00288 static struct {
00289 unsigned int need_reload:1;
00290 unsigned int need_quit:1;
00291 } sig_flags;
00292
00293 #if !defined(LOW_MEMORY)
00294 struct file_version {
00295 AST_RWLIST_ENTRY(file_version) list;
00296 const char *file;
00297 char *version;
00298 };
00299
00300 static AST_RWLIST_HEAD_STATIC(file_versions, file_version);
00301
00302 void ast_register_file_version(const char *file, const char *version)
00303 {
00304 struct file_version *new;
00305 char *work;
00306 size_t version_length;
00307
00308 work = ast_strdupa(version);
00309 work = ast_strip(ast_strip_quoted(work, "$", "$"));
00310 version_length = strlen(work) + 1;
00311
00312 if (!(new = ast_calloc(1, sizeof(*new) + version_length)))
00313 return;
00314
00315 new->file = file;
00316 new->version = (char *) new + sizeof(*new);
00317 memcpy(new->version, work, version_length);
00318 AST_RWLIST_WRLOCK(&file_versions);
00319 AST_RWLIST_INSERT_HEAD(&file_versions, new, list);
00320 AST_RWLIST_UNLOCK(&file_versions);
00321 }
00322
00323 void ast_unregister_file_version(const char *file)
00324 {
00325 struct file_version *find;
00326
00327 AST_RWLIST_WRLOCK(&file_versions);
00328 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&file_versions, find, list) {
00329 if (!strcasecmp(find->file, file)) {
00330 AST_RWLIST_REMOVE_CURRENT(list);
00331 break;
00332 }
00333 }
00334 AST_RWLIST_TRAVERSE_SAFE_END;
00335 AST_RWLIST_UNLOCK(&file_versions);
00336
00337 if (find)
00338 ast_free(find);
00339 }
00340
00341 char *ast_complete_source_filename(const char *partial, int n)
00342 {
00343 struct file_version *find;
00344 size_t len = strlen(partial);
00345 int count = 0;
00346 char *res = NULL;
00347
00348 AST_RWLIST_RDLOCK(&file_versions);
00349 AST_RWLIST_TRAVERSE(&file_versions, find, list) {
00350 if (!strncasecmp(find->file, partial, len) && ++count > n) {
00351 res = ast_strdup(find->file);
00352 break;
00353 }
00354 }
00355 AST_RWLIST_UNLOCK(&file_versions);
00356 return res;
00357 }
00358
00359
00360 const char *ast_file_version_find(const char *file)
00361 {
00362 struct file_version *iterator;
00363
00364 AST_RWLIST_WRLOCK(&file_versions);
00365 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&file_versions, iterator, list) {
00366 if (!strcasecmp(iterator->file, file))
00367 break;
00368 }
00369 AST_RWLIST_TRAVERSE_SAFE_END;
00370 AST_RWLIST_UNLOCK(&file_versions);
00371 if (iterator)
00372 return iterator->version;
00373 return NULL;
00374 }
00375
00376
00377
00378 struct thread_list_t {
00379 AST_RWLIST_ENTRY(thread_list_t) list;
00380 char *name;
00381 pthread_t id;
00382 };
00383
00384 static AST_RWLIST_HEAD_STATIC(thread_list, thread_list_t);
00385
00386 void ast_register_thread(char *name)
00387 {
00388 struct thread_list_t *new = ast_calloc(1, sizeof(*new));
00389
00390 if (!new)
00391 return;
00392 new->id = pthread_self();
00393 new->name = name;
00394 AST_RWLIST_WRLOCK(&thread_list);
00395 AST_RWLIST_INSERT_HEAD(&thread_list, new, list);
00396 AST_RWLIST_UNLOCK(&thread_list);
00397 }
00398
00399 void ast_unregister_thread(void *id)
00400 {
00401 struct thread_list_t *x;
00402
00403 AST_RWLIST_WRLOCK(&thread_list);
00404 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&thread_list, x, list) {
00405 if ((void *) x->id == id) {
00406 AST_RWLIST_REMOVE_CURRENT(list);
00407 break;
00408 }
00409 }
00410 AST_RWLIST_TRAVERSE_SAFE_END;
00411 AST_RWLIST_UNLOCK(&thread_list);
00412 if (x) {
00413 ast_free(x->name);
00414 ast_free(x);
00415 }
00416 }
00417
00418
00419 static char *handle_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00420 {
00421 char buf[BUFSIZ];
00422 struct ast_tm tm;
00423 char eid_str[128];
00424
00425 switch (cmd) {
00426 case CLI_INIT:
00427 e->command = "core show settings";
00428 e->usage = "Usage: core show settings\n"
00429 " Show core misc settings";
00430 return NULL;
00431 case CLI_GENERATE:
00432 return NULL;
00433 }
00434
00435 ast_eid_to_str(eid_str, sizeof(eid_str), &ast_eid_default);
00436
00437 ast_cli(a->fd, "\nPBX Core settings\n");
00438 ast_cli(a->fd, "-----------------\n");
00439 ast_cli(a->fd, " Version: %s\n", ast_get_version());
00440 ast_cli(a->fd, " Build Options: %s\n", S_OR(AST_BUILDOPTS, "(none)"));
00441 if (option_maxcalls)
00442 ast_cli(a->fd, " Maximum calls: %d (Current %d)\n", option_maxcalls, ast_active_channels());
00443 else
00444 ast_cli(a->fd, " Maximum calls: Not set\n");
00445 if (option_maxfiles)
00446 ast_cli(a->fd, " Maximum open file handles: %d\n", option_maxfiles);
00447 else
00448 ast_cli(a->fd, " Maximum open file handles: Not set\n");
00449 ast_cli(a->fd, " Verbosity: %d\n", option_verbose);
00450 ast_cli(a->fd, " Debug level: %d\n", option_debug);
00451 ast_cli(a->fd, " Maximum load average: %lf\n", option_maxload);
00452 #if defined(HAVE_SYSINFO)
00453 ast_cli(a->fd, " Minimum free memory: %ld MB\n", option_minmemfree);
00454 #endif
00455 if (ast_localtime(&ast_startuptime, &tm, NULL)) {
00456 ast_strftime(buf, sizeof(buf), "%H:%M:%S", &tm);
00457 ast_cli(a->fd, " Startup time: %s\n", buf);
00458 }
00459 if (ast_localtime(&ast_lastreloadtime, &tm, NULL)) {
00460 ast_strftime(buf, sizeof(buf), "%H:%M:%S", &tm);
00461 ast_cli(a->fd, " Last reload time: %s\n", buf);
00462 }
00463 ast_cli(a->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);
00464 ast_cli(a->fd, " System name: %s\n", ast_config_AST_SYSTEM_NAME);
00465 ast_cli(a->fd, " Entity ID: %s\n", eid_str);
00466 ast_cli(a->fd, " Default language: %s\n", defaultlanguage);
00467 ast_cli(a->fd, " Language prefix: %s\n", ast_language_is_prefix ? "Enabled" : "Disabled");
00468 ast_cli(a->fd, " User name and group: %s/%s\n", ast_config_AST_RUN_USER, ast_config_AST_RUN_GROUP);
00469 ast_cli(a->fd, " Executable includes: %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_EXEC_INCLUDES) ? "Enabled" : "Disabled");
00470 ast_cli(a->fd, " Transcode via SLIN: %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_TRANSCODE_VIA_SLIN) ? "Enabled" : "Disabled");
00471 ast_cli(a->fd, " Internal timing: %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_INTERNAL_TIMING) ? "Enabled" : "Disabled");
00472 ast_cli(a->fd, " Transmit silence during rec: %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_TRANSMIT_SILENCE) ? "Enabled" : "Disabled");
00473 ast_cli(a->fd, " Generic PLC: %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_GENERIC_PLC) ? "Enabled" : "Disabled");
00474
00475 ast_cli(a->fd, "\n* Subsystems\n");
00476 ast_cli(a->fd, " -------------\n");
00477 ast_cli(a->fd, " Manager (AMI): %s\n", check_manager_enabled() ? "Enabled" : "Disabled");
00478 ast_cli(a->fd, " Web Manager (AMI/HTTP): %s\n", check_webmanager_enabled() ? "Enabled" : "Disabled");
00479 ast_cli(a->fd, " Call data records: %s\n", check_cdr_enabled() ? "Enabled" : "Disabled");
00480 ast_cli(a->fd, " Realtime Architecture (ARA): %s\n", ast_realtime_enabled() ? "Enabled" : "Disabled");
00481
00482
00483
00484 ast_cli(a->fd, "\n* Directories\n");
00485 ast_cli(a->fd, " -------------\n");
00486 ast_cli(a->fd, " Configuration file: %s\n", ast_config_AST_CONFIG_FILE);
00487 ast_cli(a->fd, " Configuration directory: %s\n", ast_config_AST_CONFIG_DIR);
00488 ast_cli(a->fd, " Module directory: %s\n", ast_config_AST_MODULE_DIR);
00489 ast_cli(a->fd, " Spool directory: %s\n", ast_config_AST_SPOOL_DIR);
00490 ast_cli(a->fd, " Log directory: %s\n", ast_config_AST_LOG_DIR);
00491 ast_cli(a->fd, " Run/Sockets directory: %s\n", ast_config_AST_RUN_DIR);
00492 ast_cli(a->fd, " PID file: %s\n", ast_config_AST_PID);
00493 ast_cli(a->fd, " VarLib directory: %s\n", ast_config_AST_VAR_DIR);
00494 ast_cli(a->fd, " Data directory: %s\n", ast_config_AST_DATA_DIR);
00495 ast_cli(a->fd, " ASTDB: %s\n", ast_config_AST_DB);
00496 ast_cli(a->fd, " IAX2 Keys directory: %s\n", ast_config_AST_KEY_DIR);
00497 ast_cli(a->fd, " AGI Scripts directory: %s\n", ast_config_AST_AGI_DIR);
00498 ast_cli(a->fd, "\n\n");
00499 return CLI_SUCCESS;
00500 }
00501
00502 static char *handle_show_threads(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00503 {
00504 int count = 0;
00505 struct thread_list_t *cur;
00506 switch (cmd) {
00507 case CLI_INIT:
00508 e->command = "core show threads";
00509 e->usage =
00510 "Usage: core show threads\n"
00511 " List threads currently active in the system.\n";
00512 return NULL;
00513 case CLI_GENERATE:
00514 return NULL;
00515 }
00516
00517 AST_RWLIST_RDLOCK(&thread_list);
00518 AST_RWLIST_TRAVERSE(&thread_list, cur, list) {
00519 ast_cli(a->fd, "%p %s\n", (void *)cur->id, cur->name);
00520 count++;
00521 }
00522 AST_RWLIST_UNLOCK(&thread_list);
00523 ast_cli(a->fd, "%d threads listed.\n", count);
00524 return CLI_SUCCESS;
00525 }
00526
00527 #if defined (HAVE_SYSCTL) && defined(HAVE_SWAPCTL)
00528
00529
00530
00531
00532 static int swapmode(int *used, int *total)
00533 {
00534 struct swapent *swdev;
00535 int nswap, rnswap, i;
00536
00537 nswap = swapctl(SWAP_NSWAP, 0, 0);
00538 if (nswap == 0)
00539 return 0;
00540
00541 swdev = ast_calloc(nswap, sizeof(*swdev));
00542 if (swdev == NULL)
00543 return 0;
00544
00545 rnswap = swapctl(SWAP_STATS, swdev, nswap);
00546 if (rnswap == -1) {
00547 ast_free(swdev);
00548 return 0;
00549 }
00550
00551
00552
00553
00554 *total = *used = 0;
00555 for (i = 0; i < nswap; i++) {
00556 if (swdev[i].se_flags & SWF_ENABLE) {
00557 *used += (swdev[i].se_inuse / (1024 / DEV_BSIZE));
00558 *total += (swdev[i].se_nblks / (1024 / DEV_BSIZE));
00559 }
00560 }
00561 ast_free(swdev);
00562 return 1;
00563 }
00564 #elif defined(HAVE_SYSCTL) && !defined(HAVE_SYSINFO)
00565 static int swapmode(int *used, int *total)
00566 {
00567 *used = *total = 0;
00568 return 1;
00569 }
00570 #endif
00571
00572 #if defined(HAVE_SYSINFO) || defined(HAVE_SYSCTL)
00573
00574 static char *handle_show_sysinfo(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00575 {
00576 uint64_t physmem, freeram;
00577 uint64_t freeswap = 0;
00578 int totalswap = 0;
00579 int nprocs = 0;
00580 long uptime = 0;
00581 #if defined(HAVE_SYSINFO)
00582 struct sysinfo sys_info;
00583 sysinfo(&sys_info);
00584 uptime = sys_info.uptime / 3600;
00585 physmem = sys_info.totalram * sys_info.mem_unit;
00586 freeram = (sys_info.freeram * sys_info.mem_unit) / 1024;
00587 totalswap = (sys_info.totalswap * sys_info.mem_unit) / 1024;
00588 freeswap = (sys_info.freeswap * sys_info.mem_unit) / 1024;
00589 nprocs = sys_info.procs;
00590 #elif defined(HAVE_SYSCTL)
00591 static int pageshift;
00592 struct vmtotal vmtotal;
00593 struct timeval boottime;
00594 time_t now;
00595 int mib[2], pagesize, usedswap = 0;
00596 size_t len;
00597
00598 time(&now);
00599 mib[0] = CTL_KERN;
00600 mib[1] = KERN_BOOTTIME;
00601 len = sizeof(boottime);
00602 if (sysctl(mib, 2, &boottime, &len, NULL, 0) != -1) {
00603 uptime = now - boottime.tv_sec;
00604 }
00605 uptime = uptime/3600;
00606
00607 mib[0] = CTL_HW;
00608 #if defined(HW_PHYSMEM64)
00609 mib[1] = HW_PHYSMEM64;
00610 #else
00611 mib[1] = HW_PHYSMEM;
00612 #endif
00613 len = sizeof(physmem);
00614 sysctl(mib, 2, &physmem, &len, NULL, 0);
00615
00616 pagesize = getpagesize();
00617 pageshift = 0;
00618 while (pagesize > 1) {
00619 pageshift++;
00620 pagesize >>= 1;
00621 }
00622
00623
00624 pageshift -= 10;
00625
00626
00627 mib[0] = CTL_VM;
00628 mib[1] = VM_METER;
00629 len = sizeof(vmtotal);
00630 sysctl(mib, 2, &vmtotal, &len, NULL, 0);
00631 freeram = (vmtotal.t_free << pageshift);
00632
00633 swapmode(&usedswap, &totalswap);
00634 freeswap = (totalswap - usedswap);
00635
00636 #if defined(__OpenBSD__)
00637 mib[0] = CTL_KERN;
00638 mib[1] = KERN_NPROCS;
00639 len = sizeof(nprocs);
00640 sysctl(mib, 2, &nprocs, &len, NULL, 0);
00641 #endif
00642 #endif
00643
00644 switch (cmd) {
00645 case CLI_INIT:
00646 e->command = "core show sysinfo";
00647 e->usage =
00648 "Usage: core show sysinfo\n"
00649 " List current system information.\n";
00650 return NULL;
00651 case CLI_GENERATE:
00652 return NULL;
00653 }
00654
00655 ast_cli(a->fd, "\nSystem Statistics\n");
00656 ast_cli(a->fd, "-----------------\n");
00657 ast_cli(a->fd, " System Uptime: %lu hours\n", uptime);
00658 ast_cli(a->fd, " Total RAM: %" PRIu64 " KiB\n", physmem / 1024);
00659 ast_cli(a->fd, " Free RAM: %" PRIu64 " KiB\n", freeram);
00660 #if defined(HAVE_SYSINFO)
00661 ast_cli(a->fd, " Buffer RAM: %" PRIu64 " KiB\n", ((uint64_t) sys_info.bufferram * sys_info.mem_unit) / 1024);
00662 #endif
00663 #if defined (HAVE_SYSCTL) && defined(HAVE_SWAPCTL)
00664 ast_cli(a->fd, " Total Swap Space: %u KiB\n", totalswap);
00665 ast_cli(a->fd, " Free Swap Space: %" PRIu64 " KiB\n\n", freeswap);
00666 #endif
00667 ast_cli(a->fd, " Number of Processes: %d \n\n", nprocs);
00668 return CLI_SUCCESS;
00669 }
00670 #endif
00671
00672 struct profile_entry {
00673 const char *name;
00674 uint64_t scale;
00675 int64_t mark;
00676 int64_t value;
00677 int64_t events;
00678 };
00679
00680 struct profile_data {
00681 int entries;
00682 int max_size;
00683 struct profile_entry e[0];
00684 };
00685
00686 static struct profile_data *prof_data;
00687
00688
00689
00690
00691 int ast_add_profile(const char *name, uint64_t scale)
00692 {
00693 int l = sizeof(struct profile_data);
00694 int n = 10;
00695
00696 if (prof_data == NULL) {
00697 prof_data = ast_calloc(1, l + n*sizeof(struct profile_entry));
00698 if (prof_data == NULL)
00699 return -1;
00700 prof_data->entries = 0;
00701 prof_data->max_size = n;
00702 }
00703 if (prof_data->entries >= prof_data->max_size) {
00704 void *p;
00705 n = prof_data->max_size + 20;
00706 p = ast_realloc(prof_data, l + n*sizeof(struct profile_entry));
00707 if (p == NULL)
00708 return -1;
00709 prof_data = p;
00710 prof_data->max_size = n;
00711 }
00712 n = prof_data->entries++;
00713 prof_data->e[n].name = ast_strdup(name);
00714 prof_data->e[n].value = 0;
00715 prof_data->e[n].events = 0;
00716 prof_data->e[n].mark = 0;
00717 prof_data->e[n].scale = scale;
00718 return n;
00719 }
00720
00721 int64_t ast_profile(int i, int64_t delta)
00722 {
00723 if (!prof_data || i < 0 || i > prof_data->entries)
00724 return 0;
00725 if (prof_data->e[i].scale > 1)
00726 delta /= prof_data->e[i].scale;
00727 prof_data->e[i].value += delta;
00728 prof_data->e[i].events++;
00729 return prof_data->e[i].value;
00730 }
00731
00732
00733
00734
00735 #if defined ( __i686__) && (defined(__FreeBSD__) || defined(linux))
00736 #if defined(__FreeBSD__)
00737 #include <machine/cpufunc.h>
00738 #elif defined(linux)
00739 static __inline uint64_t
00740 rdtsc(void)
00741 {
00742 uint64_t rv;
00743
00744 __asm __volatile(".byte 0x0f, 0x31" : "=A" (rv));
00745 return (rv);
00746 }
00747 #endif
00748 #else
00749 static __inline uint64_t
00750 rdtsc(void)
00751 {
00752 return 0;
00753 }
00754 #endif
00755
00756 int64_t ast_mark(int i, int startstop)
00757 {
00758 if (!prof_data || i < 0 || i > prof_data->entries)
00759 return 0;
00760 if (startstop == 1)
00761 prof_data->e[i].mark = rdtsc();
00762 else {
00763 prof_data->e[i].mark = (rdtsc() - prof_data->e[i].mark);
00764 if (prof_data->e[i].scale > 1)
00765 prof_data->e[i].mark /= prof_data->e[i].scale;
00766 prof_data->e[i].value += prof_data->e[i].mark;
00767 prof_data->e[i].events++;
00768 }
00769 return prof_data->e[i].mark;
00770 }
00771
00772 #define DEFINE_PROFILE_MIN_MAX_VALUES min = 0; \
00773 max = prof_data->entries;\
00774 if (a->argc > 3) { \
00775 if (isdigit(a->argv[3][0])) { \
00776 min = atoi(a->argv[3]); \
00777 if (a->argc == 5 && strcmp(a->argv[4], "-")) \
00778 max = atoi(a->argv[4]); \
00779 } else \
00780 search = a->argv[3]; \
00781 } \
00782 if (max > prof_data->entries) \
00783 max = prof_data->entries;
00784
00785 static char *handle_show_profile(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00786 {
00787 int i, min, max;
00788 const char *search = NULL;
00789 switch (cmd) {
00790 case CLI_INIT:
00791 e->command = "core show profile";
00792 e->usage = "Usage: core show profile\n"
00793 " show profile information";
00794 return NULL;
00795 case CLI_GENERATE:
00796 return NULL;
00797 }
00798
00799 if (prof_data == NULL)
00800 return 0;
00801
00802 DEFINE_PROFILE_MIN_MAX_VALUES;
00803 ast_cli(a->fd, "profile values (%d, allocated %d)\n-------------------\n",
00804 prof_data->entries, prof_data->max_size);
00805 ast_cli(a->fd, "%6s %8s %10s %12s %12s %s\n", "ID", "Scale", "Events",
00806 "Value", "Average", "Name");
00807 for (i = min; i < max; i++) {
00808 struct profile_entry *entry = &prof_data->e[i];
00809 if (!search || strstr(entry->name, search))
00810 ast_cli(a->fd, "%6d: [%8ld] %10ld %12lld %12lld %s\n",
00811 i,
00812 (long)entry->scale,
00813 (long)entry->events, (long long)entry->value,
00814 (long long)(entry->events ? entry->value / entry->events : entry->value),
00815 entry->name);
00816 }
00817 return CLI_SUCCESS;
00818 }
00819
00820 static char *handle_clear_profile(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00821 {
00822 int i, min, max;
00823 const char *search = NULL;
00824 switch (cmd) {
00825 case CLI_INIT:
00826 e->command = "core clear profile";
00827 e->usage = "Usage: core clear profile\n"
00828 " clear profile information";
00829 return NULL;
00830 case CLI_GENERATE:
00831 return NULL;
00832 }
00833
00834 if (prof_data == NULL)
00835 return 0;
00836
00837 DEFINE_PROFILE_MIN_MAX_VALUES;
00838 for (i= min; i < max; i++) {
00839 if (!search || strstr(prof_data->e[i].name, search)) {
00840 prof_data->e[i].value = 0;
00841 prof_data->e[i].events = 0;
00842 }
00843 }
00844 return CLI_SUCCESS;
00845 }
00846 #undef DEFINE_PROFILE_MIN_MAX_VALUES
00847
00848
00849 static char *handle_show_version_files(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00850 {
00851 #define FORMAT "%-25.25s %-40.40s\n"
00852 struct file_version *iterator;
00853 regex_t regexbuf;
00854 int havepattern = 0;
00855 int havename = 0;
00856 int count_files = 0;
00857 char *ret = NULL;
00858 int matchlen, which = 0;
00859 struct file_version *find;
00860
00861 switch (cmd) {
00862 case CLI_INIT:
00863 e->command = "core show file version [like]";
00864 e->usage =
00865 "Usage: core show file version [like <pattern>]\n"
00866 " Lists the revision numbers of the files used to build this copy of Asterisk.\n"
00867 " Optional regular expression pattern is used to filter the file list.\n";
00868 return NULL;
00869 case CLI_GENERATE:
00870 matchlen = strlen(a->word);
00871 if (a->pos != 3)
00872 return NULL;
00873 AST_RWLIST_RDLOCK(&file_versions);
00874 AST_RWLIST_TRAVERSE(&file_versions, find, list) {
00875 if (!strncasecmp(a->word, find->file, matchlen) && ++which > a->n) {
00876 ret = ast_strdup(find->file);
00877 break;
00878 }
00879 }
00880 AST_RWLIST_UNLOCK(&file_versions);
00881 return ret;
00882 }
00883
00884
00885 switch (a->argc) {
00886 case 6:
00887 if (!strcasecmp(a->argv[4], "like")) {
00888 if (regcomp(®exbuf, a->argv[5], REG_EXTENDED | REG_NOSUB))
00889 return CLI_SHOWUSAGE;
00890 havepattern = 1;
00891 } else
00892 return CLI_SHOWUSAGE;
00893 break;
00894 case 5:
00895 havename = 1;
00896 break;
00897 case 4:
00898 break;
00899 default:
00900 return CLI_SHOWUSAGE;
00901 }
00902
00903 ast_cli(a->fd, FORMAT, "File", "Revision");
00904 ast_cli(a->fd, FORMAT, "----", "--------");
00905 AST_RWLIST_RDLOCK(&file_versions);
00906 AST_RWLIST_TRAVERSE(&file_versions, iterator, list) {
00907 if (havename && strcasecmp(iterator->file, a->argv[4]))
00908 continue;
00909
00910 if (havepattern && regexec(®exbuf, iterator->file, 0, NULL, 0))
00911 continue;
00912
00913 ast_cli(a->fd, FORMAT, iterator->file, iterator->version);
00914 count_files++;
00915 if (havename)
00916 break;
00917 }
00918 AST_RWLIST_UNLOCK(&file_versions);
00919 if (!havename) {
00920 ast_cli(a->fd, "%d files listed.\n", count_files);
00921 }
00922
00923 if (havepattern)
00924 regfree(®exbuf);
00925
00926 return CLI_SUCCESS;
00927 #undef FORMAT
00928 }
00929
00930 #endif
00931
00932 int ast_register_atexit(void (*func)(void))
00933 {
00934 struct ast_atexit *ae;
00935
00936 if (!(ae = ast_calloc(1, sizeof(*ae))))
00937 return -1;
00938
00939 ae->func = func;
00940
00941 ast_unregister_atexit(func);
00942
00943 AST_RWLIST_WRLOCK(&atexits);
00944 AST_RWLIST_INSERT_HEAD(&atexits, ae, list);
00945 AST_RWLIST_UNLOCK(&atexits);
00946
00947 return 0;
00948 }
00949
00950 void ast_unregister_atexit(void (*func)(void))
00951 {
00952 struct ast_atexit *ae = NULL;
00953
00954 AST_RWLIST_WRLOCK(&atexits);
00955 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&atexits, ae, list) {
00956 if (ae->func == func) {
00957 AST_RWLIST_REMOVE_CURRENT(list);
00958 break;
00959 }
00960 }
00961 AST_RWLIST_TRAVERSE_SAFE_END;
00962 AST_RWLIST_UNLOCK(&atexits);
00963
00964 free(ae);
00965 }
00966
00967
00968 static int fdsend(int fd, const char *s)
00969 {
00970 return write(fd, s, strlen(s) + 1);
00971 }
00972
00973
00974 static int fdprint(int fd, const char *s)
00975 {
00976 return write(fd, s, strlen(s));
00977 }
00978
00979
00980 static void _null_sig_handler(int sig)
00981 {
00982
00983 }
00984
00985 static struct sigaction null_sig_handler = {
00986 .sa_handler = _null_sig_handler,
00987 .sa_flags = SA_RESTART,
00988 };
00989
00990 static struct sigaction ignore_sig_handler = {
00991 .sa_handler = SIG_IGN,
00992 };
00993
00994 AST_MUTEX_DEFINE_STATIC(safe_system_lock);
00995
00996
00997 static unsigned int safe_system_level = 0;
00998 static struct sigaction safe_system_prev_handler;
00999
01000 void ast_replace_sigchld(void)
01001 {
01002 unsigned int level;
01003
01004 ast_mutex_lock(&safe_system_lock);
01005 level = safe_system_level++;
01006
01007
01008 if (level == 0) {
01009 sigaction(SIGCHLD, &null_sig_handler, &safe_system_prev_handler);
01010 }
01011
01012 ast_mutex_unlock(&safe_system_lock);
01013 }
01014
01015 void ast_unreplace_sigchld(void)
01016 {
01017 unsigned int level;
01018
01019 ast_mutex_lock(&safe_system_lock);
01020 level = --safe_system_level;
01021
01022
01023 if (level == 0) {
01024 sigaction(SIGCHLD, &safe_system_prev_handler, NULL);
01025 }
01026
01027 ast_mutex_unlock(&safe_system_lock);
01028 }
01029
01030 int ast_safe_system(const char *s)
01031 {
01032 pid_t pid;
01033 int res;
01034 struct rusage rusage;
01035 int status;
01036
01037 #if defined(HAVE_WORKING_FORK) || defined(HAVE_WORKING_VFORK)
01038 ast_replace_sigchld();
01039
01040 #ifdef HAVE_WORKING_FORK
01041 pid = fork();
01042 #else
01043 pid = vfork();
01044 #endif
01045
01046 if (pid == 0) {
01047 #ifdef HAVE_CAP
01048 cap_t cap = cap_from_text("cap_net_admin-eip");
01049
01050 if (cap_set_proc(cap)) {
01051
01052 ast_log(LOG_WARNING, "Unable to remove capabilities.\n");
01053 }
01054 cap_free(cap);
01055 #endif
01056 #ifdef HAVE_WORKING_FORK
01057 if (ast_opt_high_priority)
01058 ast_set_priority(0);
01059
01060 ast_close_fds_above_n(STDERR_FILENO);
01061 #endif
01062 execl("/bin/sh", "/bin/sh", "-c", s, (char *) NULL);
01063 _exit(1);
01064 } else if (pid > 0) {
01065 for (;;) {
01066 res = wait4(pid, &status, 0, &rusage);
01067 if (res > -1) {
01068 res = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
01069 break;
01070 } else if (errno != EINTR)
01071 break;
01072 }
01073 } else {
01074 ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno));
01075 res = -1;
01076 }
01077
01078 ast_unreplace_sigchld();
01079 #else
01080 res = -1;
01081 #endif
01082
01083 return res;
01084 }
01085
01086 void ast_console_toggle_loglevel(int fd, int level, int state)
01087 {
01088 int x;
01089 for (x = 0;x < AST_MAX_CONNECTS; x++) {
01090 if (fd == consoles[x].fd) {
01091 consoles[x].levels[level] = state;
01092 return;
01093 }
01094 }
01095 }
01096
01097
01098
01099
01100 void ast_console_toggle_mute(int fd, int silent) {
01101 int x;
01102 for (x = 0;x < AST_MAX_CONNECTS; x++) {
01103 if (fd == consoles[x].fd) {
01104 if (consoles[x].mute) {
01105 consoles[x].mute = 0;
01106 if (!silent)
01107 ast_cli(fd, "Console is not muted anymore.\n");
01108 } else {
01109 consoles[x].mute = 1;
01110 if (!silent)
01111 ast_cli(fd, "Console is muted.\n");
01112 }
01113 return;
01114 }
01115 }
01116 ast_cli(fd, "Couldn't find remote console.\n");
01117 }
01118
01119
01120
01121
01122 static void ast_network_puts_mutable(const char *string, int level)
01123 {
01124 int x;
01125 for (x = 0;x < AST_MAX_CONNECTS; x++) {
01126 if (consoles[x].mute)
01127 continue;
01128 if (consoles[x].fd > -1) {
01129 if (!consoles[x].levels[level])
01130 fdprint(consoles[x].p[1], string);
01131 }
01132 }
01133 }
01134
01135
01136
01137
01138
01139 void ast_console_puts_mutable(const char *string, int level)
01140 {
01141 fputs(string, stdout);
01142 fflush(stdout);
01143 ast_network_puts_mutable(string, level);
01144 }
01145
01146
01147
01148
01149 static void ast_network_puts(const char *string)
01150 {
01151 int x;
01152 for (x = 0; x < AST_MAX_CONNECTS; x++) {
01153 if (consoles[x].fd > -1)
01154 fdprint(consoles[x].p[1], string);
01155 }
01156 }
01157
01158
01159
01160
01161
01162 void ast_console_puts(const char *string)
01163 {
01164 fputs(string, stdout);
01165 fflush(stdout);
01166 ast_network_puts(string);
01167 }
01168
01169 static void network_verboser(const char *s)
01170 {
01171 ast_network_puts_mutable(s, __LOG_VERBOSE);
01172 }
01173
01174 static pthread_t lthread;
01175
01176
01177
01178
01179
01180
01181
01182
01183
01184
01185
01186 static int read_credentials(int fd, char *buffer, size_t size, struct console *con)
01187 {
01188 #if defined(SO_PEERCRED)
01189 struct ucred cred;
01190 socklen_t len = sizeof(cred);
01191 #endif
01192 #if defined(HAVE_GETPEEREID)
01193 uid_t uid;
01194 gid_t gid;
01195 #else
01196 int uid, gid;
01197 #endif
01198 int result;
01199
01200 result = read(fd, buffer, size);
01201 if (result < 0) {
01202 return result;
01203 }
01204
01205 #if defined(SO_PEERCRED) && (defined(HAVE_STRUCT_UCRED_UID) || defined(HAVE_STRUCT_UCRED_CR_UID))
01206 if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cred, &len)) {
01207 return result;
01208 }
01209 #if defined(HAVE_STRUCT_UCRED_UID)
01210 uid = cred.uid;
01211 gid = cred.gid;
01212 #else
01213 uid = cred.cr_uid;
01214 gid = cred.cr_gid;
01215 #endif
01216
01217 #elif defined(HAVE_GETPEEREID)
01218 if (getpeereid(fd, &uid, &gid)) {
01219 return result;
01220 }
01221 #else
01222 return result;
01223 #endif
01224 con->uid = uid;
01225 con->gid = gid;
01226
01227 return result;
01228 }
01229
01230 static void *netconsole(void *vconsole)
01231 {
01232 struct console *con = vconsole;
01233 char hostname[MAXHOSTNAMELEN] = "";
01234 char tmp[512];
01235 int res;
01236 struct pollfd fds[2];
01237
01238 if (gethostname(hostname, sizeof(hostname)-1))
01239 ast_copy_string(hostname, "<Unknown>", sizeof(hostname));
01240 snprintf(tmp, sizeof(tmp), "%s/%ld/%s\n", hostname, (long)ast_mainpid, ast_get_version());
01241 fdprint(con->fd, tmp);
01242 for (;;) {
01243 fds[0].fd = con->fd;
01244 fds[0].events = POLLIN;
01245 fds[0].revents = 0;
01246 fds[1].fd = con->p[0];
01247 fds[1].events = POLLIN;
01248 fds[1].revents = 0;
01249
01250 res = ast_poll(fds, 2, -1);
01251 if (res < 0) {
01252 if (errno != EINTR)
01253 ast_log(LOG_WARNING, "poll returned < 0: %s\n", strerror(errno));
01254 continue;
01255 }
01256 if (fds[0].revents) {
01257 res = read_credentials(con->fd, tmp, sizeof(tmp) - 1, con);
01258 if (res < 1) {
01259 break;
01260 }
01261 tmp[res] = 0;
01262 if (strncmp(tmp, "cli quit after ", 15) == 0) {
01263 ast_cli_command_multiple_full(con->uid, con->gid, con->fd, res - 15, tmp + 15);
01264 break;
01265 }
01266 ast_cli_command_multiple_full(con->uid, con->gid, con->fd, res, tmp);
01267 }
01268 if (fds[1].revents) {
01269 res = read_credentials(con->p[0], tmp, sizeof(tmp), con);
01270 if (res < 1) {
01271 ast_log(LOG_ERROR, "read returned %d\n", res);
01272 break;
01273 }
01274 res = write(con->fd, tmp, res);
01275 if (res < 1)
01276 break;
01277 }
01278 }
01279 if (!ast_opt_hide_connect) {
01280 ast_verb(3, "Remote UNIX connection disconnected\n");
01281 }
01282 close(con->fd);
01283 close(con->p[0]);
01284 close(con->p[1]);
01285 con->fd = -1;
01286
01287 return NULL;
01288 }
01289
01290 static void *listener(void *unused)
01291 {
01292 struct sockaddr_un sunaddr;
01293 int s;
01294 socklen_t len;
01295 int x;
01296 int flags;
01297 struct pollfd fds[1];
01298 for (;;) {
01299 if (ast_socket < 0)
01300 return NULL;
01301 fds[0].fd = ast_socket;
01302 fds[0].events = POLLIN;
01303 s = ast_poll(fds, 1, -1);
01304 pthread_testcancel();
01305 if (s < 0) {
01306 if (errno != EINTR)
01307 ast_log(LOG_WARNING, "poll returned error: %s\n", strerror(errno));
01308 continue;
01309 }
01310 len = sizeof(sunaddr);
01311 s = accept(ast_socket, (struct sockaddr *)&sunaddr, &len);
01312 if (s < 0) {
01313 if (errno != EINTR)
01314 ast_log(LOG_WARNING, "Accept returned %d: %s\n", s, strerror(errno));
01315 } else {
01316 #if !defined(SO_PASSCRED)
01317 {
01318 #else
01319 int sckopt = 1;
01320
01321 if (setsockopt(s, SOL_SOCKET, SO_PASSCRED, &sckopt, sizeof(sckopt)) < 0) {
01322 ast_log(LOG_WARNING, "Unable to turn on socket credentials passing\n");
01323 } else {
01324 #endif
01325 for (x = 0; x < AST_MAX_CONNECTS; x++) {
01326 if (consoles[x].fd >= 0) {
01327 continue;
01328 }
01329 if (socketpair(AF_LOCAL, SOCK_STREAM, 0, consoles[x].p)) {
01330 ast_log(LOG_ERROR, "Unable to create pipe: %s\n", strerror(errno));
01331 consoles[x].fd = -1;
01332 fdprint(s, "Server failed to create pipe\n");
01333 close(s);
01334 break;
01335 }
01336 flags = fcntl(consoles[x].p[1], F_GETFL);
01337 fcntl(consoles[x].p[1], F_SETFL, flags | O_NONBLOCK);
01338 consoles[x].fd = s;
01339 consoles[x].mute = 1;
01340
01341
01342 consoles[x].uid = -2;
01343 consoles[x].gid = -2;
01344 if (ast_pthread_create_detached_background(&consoles[x].t, NULL, netconsole, &consoles[x])) {
01345 ast_log(LOG_ERROR, "Unable to spawn thread to handle connection: %s\n", strerror(errno));
01346 close(consoles[x].p[0]);
01347 close(consoles[x].p[1]);
01348 consoles[x].fd = -1;
01349 fdprint(s, "Server failed to spawn thread\n");
01350 close(s);
01351 }
01352 break;
01353 }
01354 if (x >= AST_MAX_CONNECTS) {
01355 fdprint(s, "No more connections allowed\n");
01356 ast_log(LOG_WARNING, "No more connections allowed\n");
01357 close(s);
01358 } else if ((consoles[x].fd > -1) && (!ast_opt_hide_connect)) {
01359 ast_verb(3, "Remote UNIX connection\n");
01360 }
01361 }
01362 }
01363 }
01364 return NULL;
01365 }
01366
01367 static int ast_makesocket(void)
01368 {
01369 struct sockaddr_un sunaddr;
01370 int res;
01371 int x;
01372 uid_t uid = -1;
01373 gid_t gid = -1;
01374
01375 for (x = 0; x < AST_MAX_CONNECTS; x++)
01376 consoles[x].fd = -1;
01377 unlink(ast_config_AST_SOCKET);
01378 ast_socket = socket(PF_LOCAL, SOCK_STREAM, 0);
01379 if (ast_socket < 0) {
01380 ast_log(LOG_WARNING, "Unable to create control socket: %s\n", strerror(errno));
01381 return -1;
01382 }
01383 memset(&sunaddr, 0, sizeof(sunaddr));
01384 sunaddr.sun_family = AF_LOCAL;
01385 ast_copy_string(sunaddr.sun_path, ast_config_AST_SOCKET, sizeof(sunaddr.sun_path));
01386 res = bind(ast_socket, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
01387 if (res) {
01388 ast_log(LOG_WARNING, "Unable to bind socket to %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
01389 close(ast_socket);
01390 ast_socket = -1;
01391 return -1;
01392 }
01393 res = listen(ast_socket, 2);
01394 if (res < 0) {
01395 ast_log(LOG_WARNING, "Unable to listen on socket %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
01396 close(ast_socket);
01397 ast_socket = -1;
01398 return -1;
01399 }
01400 if (ast_register_verbose(network_verboser)) {
01401 ast_log(LOG_WARNING, "Unable to register network verboser?\n");
01402 }
01403
01404 ast_pthread_create_background(<hread, NULL, listener, NULL);
01405
01406 if (!ast_strlen_zero(ast_config_AST_CTL_OWNER)) {
01407 struct passwd *pw;
01408 if ((pw = getpwnam(ast_config_AST_CTL_OWNER)) == NULL)
01409 ast_log(LOG_WARNING, "Unable to find uid of user %s\n", ast_config_AST_CTL_OWNER);
01410 else
01411 uid = pw->pw_uid;
01412 }
01413
01414 if (!ast_strlen_zero(ast_config_AST_CTL_GROUP)) {
01415 struct group *grp;
01416 if ((grp = getgrnam(ast_config_AST_CTL_GROUP)) == NULL)
01417 ast_log(LOG_WARNING, "Unable to find gid of group %s\n", ast_config_AST_CTL_GROUP);
01418 else
01419 gid = grp->gr_gid;
01420 }
01421
01422 if (chown(ast_config_AST_SOCKET, uid, gid) < 0)
01423 ast_log(LOG_WARNING, "Unable to change ownership of %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
01424
01425 if (!ast_strlen_zero(ast_config_AST_CTL_PERMISSIONS)) {
01426 int p1;
01427 mode_t p;
01428 sscanf(ast_config_AST_CTL_PERMISSIONS, "%30o", &p1);
01429 p = p1;
01430 if ((chmod(ast_config_AST_SOCKET, p)) < 0)
01431 ast_log(LOG_WARNING, "Unable to change file permissions of %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
01432 }
01433
01434 return 0;
01435 }
01436
01437 static int ast_tryconnect(void)
01438 {
01439 struct sockaddr_un sunaddr;
01440 int res;
01441 ast_consock = socket(PF_LOCAL, SOCK_STREAM, 0);
01442 if (ast_consock < 0) {
01443 ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno));
01444 return 0;
01445 }
01446 memset(&sunaddr, 0, sizeof(sunaddr));
01447 sunaddr.sun_family = AF_LOCAL;
01448 ast_copy_string(sunaddr.sun_path, ast_config_AST_SOCKET, sizeof(sunaddr.sun_path));
01449 res = connect(ast_consock, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
01450 if (res) {
01451 close(ast_consock);
01452 ast_consock = -1;
01453 return 0;
01454 } else
01455 return 1;
01456 }
01457
01458
01459
01460
01461
01462
01463
01464 static void _urg_handler(int num)
01465 {
01466 return;
01467 }
01468
01469 static struct sigaction urg_handler = {
01470 .sa_handler = _urg_handler,
01471 .sa_flags = SA_RESTART,
01472 };
01473
01474 static void _hup_handler(int num)
01475 {
01476 int a = 0;
01477 if (option_verbose > 1)
01478 printf("Received HUP signal -- Reloading configs\n");
01479 if (restartnow)
01480 execvp(_argv[0], _argv);
01481 sig_flags.need_reload = 1;
01482 if (sig_alert_pipe[1] != -1) {
01483 if (write(sig_alert_pipe[1], &a, sizeof(a)) < 0) {
01484 fprintf(stderr, "hup_handler: write() failed: %s\n", strerror(errno));
01485 }
01486 }
01487 }
01488
01489 static struct sigaction hup_handler = {
01490 .sa_handler = _hup_handler,
01491 .sa_flags = SA_RESTART,
01492 };
01493
01494 static void _child_handler(int sig)
01495 {
01496
01497 int n, status;
01498
01499
01500
01501
01502 for (n = 0; wait4(-1, &status, WNOHANG, NULL) > 0; n++)
01503 ;
01504 if (n == 0 && option_debug)
01505 printf("Huh? Child handler, but nobody there?\n");
01506 }
01507
01508 static struct sigaction child_handler = {
01509 .sa_handler = _child_handler,
01510 .sa_flags = SA_RESTART,
01511 };
01512
01513
01514 static void set_ulimit(int value)
01515 {
01516 struct rlimit l = {0, 0};
01517
01518 if (value <= 0) {
01519 ast_log(LOG_WARNING, "Unable to change max files open to invalid value %i\n",value);
01520 return;
01521 }
01522
01523 l.rlim_cur = value;
01524 l.rlim_max = value;
01525
01526 if (setrlimit(RLIMIT_NOFILE, &l)) {
01527 ast_log(LOG_WARNING, "Unable to disable core size resource limit: %s\n",strerror(errno));
01528 return;
01529 }
01530
01531 ast_log(LOG_NOTICE, "Setting max files open to %d\n",value);
01532
01533 return;
01534 }
01535
01536
01537 static void set_title(char *text)
01538 {
01539 if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
01540 fprintf(stdout, "\033]2;%s\007", text);
01541 }
01542
01543 static void set_icon(char *text)
01544 {
01545 if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
01546 fprintf(stdout, "\033]1;%s\007", text);
01547 }
01548
01549
01550
01551 int ast_set_priority(int pri)
01552 {
01553 struct sched_param sched;
01554 memset(&sched, 0, sizeof(sched));
01555 #ifdef __linux__
01556 if (pri) {
01557 sched.sched_priority = 10;
01558 if (sched_setscheduler(0, SCHED_RR, &sched)) {
01559 ast_log(LOG_WARNING, "Unable to set high priority\n");
01560 return -1;
01561 } else
01562 if (option_verbose)
01563 ast_verbose("Set to realtime thread\n");
01564 } else {
01565 sched.sched_priority = 0;
01566
01567 sched_setscheduler(0, SCHED_OTHER, &sched);
01568 }
01569 #else
01570 if (pri) {
01571 if (setpriority(PRIO_PROCESS, 0, -10) == -1) {
01572 ast_log(LOG_WARNING, "Unable to set high priority\n");
01573 return -1;
01574 } else
01575 if (option_verbose)
01576 ast_verbose("Set to high priority\n");
01577 } else {
01578
01579 setpriority(PRIO_PROCESS, 0, 0);
01580 }
01581 #endif
01582 return 0;
01583 }
01584
01585 static void ast_run_atexits(void)
01586 {
01587 struct ast_atexit *ae;
01588 AST_RWLIST_RDLOCK(&atexits);
01589 AST_RWLIST_TRAVERSE(&atexits, ae, list) {
01590 if (ae->func)
01591 ae->func();
01592 }
01593 AST_RWLIST_UNLOCK(&atexits);
01594 }
01595
01596 static void quit_handler(int num, int niceness, int safeshutdown, int restart)
01597 {
01598 char filename[80] = "";
01599 time_t s,e;
01600 int x;
01601
01602 ast_cdr_engine_term();
01603 if (safeshutdown) {
01604 shuttingdown = 1;
01605 if (!niceness) {
01606
01607 ast_begin_shutdown(1);
01608 if (option_verbose && ast_opt_console)
01609 ast_verbose("Beginning asterisk %s....\n", restart ? "restart" : "shutdown");
01610 time(&s);
01611 for (;;) {
01612 time(&e);
01613
01614 if ((e - s) > 15)
01615 break;
01616 if (!ast_active_channels())
01617 break;
01618 if (!shuttingdown)
01619 break;
01620
01621 usleep(100000);
01622 }
01623 } else {
01624 if (niceness < 2)
01625 ast_begin_shutdown(0);
01626 if (option_verbose && ast_opt_console)
01627 ast_verbose("Waiting for inactivity to perform %s...\n", restart ? "restart" : "halt");
01628 for (;;) {
01629 if (!ast_active_channels())
01630 break;
01631 if (!shuttingdown)
01632 break;
01633 sleep(1);
01634 }
01635 }
01636
01637 if (!shuttingdown) {
01638 if (option_verbose && ast_opt_console)
01639 ast_verbose("Asterisk %s cancelled.\n", restart ? "restart" : "shutdown");
01640 return;
01641 }
01642
01643 if (niceness)
01644 ast_module_shutdown();
01645 }
01646 if (ast_opt_console || (ast_opt_remote && !ast_opt_exec)) {
01647 pthread_t thisthread = pthread_self();
01648 if (getenv("HOME")) {
01649 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
01650 }
01651 if (!ast_strlen_zero(filename)) {
01652 ast_el_write_history(filename);
01653 }
01654 if (consolethread == AST_PTHREADT_NULL || consolethread == thisthread || mon_sig_flags == thisthread) {
01655
01656 if (el != NULL) {
01657 el_end(el);
01658 }
01659 if (el_hist != NULL) {
01660 history_end(el_hist);
01661 }
01662 }
01663 }
01664 if (option_verbose)
01665 ast_verbose("Executing last minute cleanups\n");
01666 ast_run_atexits();
01667
01668 if (option_verbose && ast_opt_console)
01669 ast_verbose("Asterisk %s ending (%d).\n", ast_active_channels() ? "uncleanly" : "cleanly", num);
01670 ast_debug(1, "Asterisk ending (%d).\n", num);
01671 manager_event(EVENT_FLAG_SYSTEM, "Shutdown", "Shutdown: %s\r\nRestart: %s\r\n", ast_active_channels() ? "Uncleanly" : "Cleanly", restart ? "True" : "False");
01672 if (ast_socket > -1) {
01673 pthread_cancel(lthread);
01674 close(ast_socket);
01675 ast_socket = -1;
01676 unlink(ast_config_AST_SOCKET);
01677 }
01678 if (ast_consock > -1)
01679 close(ast_consock);
01680 if (!ast_opt_remote)
01681 unlink(ast_config_AST_PID);
01682 printf("%s", term_quit());
01683 if (restart) {
01684 if (option_verbose || ast_opt_console)
01685 ast_verbose("Preparing for Asterisk restart...\n");
01686
01687 for (x=3; x < 32768; x++) {
01688 fcntl(x, F_SETFD, FD_CLOEXEC);
01689 }
01690 if (option_verbose || ast_opt_console)
01691 ast_verbose("Asterisk is now restarting...\n");
01692 restartnow = 1;
01693
01694
01695 close_logger();
01696
01697
01698
01699 if ((consolethread != AST_PTHREADT_NULL) && (consolethread != pthread_self())) {
01700 pthread_kill(consolethread, SIGHUP);
01701
01702 sleep(2);
01703 } else
01704 execvp(_argv[0], _argv);
01705
01706 } else {
01707
01708 close_logger();
01709 }
01710 exit(0);
01711 }
01712
01713 static void __quit_handler(int num)
01714 {
01715 int a = 0;
01716 sig_flags.need_quit = 1;
01717 if (sig_alert_pipe[1] != -1) {
01718 if (write(sig_alert_pipe[1], &a, sizeof(a)) < 0) {
01719 fprintf(stderr, "quit_handler: write() failed: %s\n", strerror(errno));
01720 }
01721 }
01722
01723
01724 }
01725
01726 static void __remote_quit_handler(int num)
01727 {
01728 sig_flags.need_quit = 1;
01729 }
01730
01731 static const char *fix_header(char *outbuf, int maxout, const char *s, char *cmp)
01732 {
01733 const char *c;
01734
01735
01736 if (*s == 127) {
01737 s++;
01738 }
01739
01740 if (!strncmp(s, cmp, strlen(cmp))) {
01741 c = s + strlen(cmp);
01742 term_color(outbuf, cmp, COLOR_GRAY, 0, maxout);
01743 return c;
01744 }
01745 return NULL;
01746 }
01747
01748 static void console_verboser(const char *s)
01749 {
01750 char tmp[80];
01751 const char *c = NULL;
01752
01753 if ((c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_4)) ||
01754 (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_3)) ||
01755 (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_2)) ||
01756 (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_1))) {
01757 fputs(tmp, stdout);
01758 fputs(c, stdout);
01759 } else {
01760 if (*s == 127) {
01761 s++;
01762 }
01763 fputs(s, stdout);
01764 }
01765
01766 fflush(stdout);
01767
01768
01769 if (ast_opt_console && consolethread != AST_PTHREADT_NULL)
01770 pthread_kill(consolethread, SIGURG);
01771 }
01772
01773 static int ast_all_zeros(char *s)
01774 {
01775 while (*s) {
01776 if (*s > 32)
01777 return 0;
01778 s++;
01779 }
01780 return 1;
01781 }
01782
01783 static void consolehandler(char *s)
01784 {
01785 printf("%s", term_end());
01786 fflush(stdout);
01787
01788
01789 if (!ast_all_zeros(s))
01790 ast_el_add_history(s);
01791
01792 if (s[0] == '!') {
01793 if (s[1])
01794 ast_safe_system(s+1);
01795 else
01796 ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
01797 } else
01798 ast_cli_command(STDOUT_FILENO, s);
01799 }
01800
01801 static int remoteconsolehandler(char *s)
01802 {
01803 int ret = 0;
01804
01805
01806 if (!ast_all_zeros(s))
01807 ast_el_add_history(s);
01808
01809 if (s[0] == '!') {
01810 if (s[1])
01811 ast_safe_system(s+1);
01812 else
01813 ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
01814 ret = 1;
01815 }
01816 if ((strncasecmp(s, "quit", 4) == 0 || strncasecmp(s, "exit", 4) == 0) &&
01817 (s[4] == '\0' || isspace(s[4]))) {
01818 quit_handler(0, 0, 0, 0);
01819 ret = 1;
01820 }
01821
01822 return ret;
01823 }
01824
01825 static char *handle_version(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01826 {
01827 switch (cmd) {
01828 case CLI_INIT:
01829 e->command = "core show version";
01830 e->usage =
01831 "Usage: core show version\n"
01832 " Shows Asterisk version information.\n";
01833 return NULL;
01834 case CLI_GENERATE:
01835 return NULL;
01836 }
01837
01838 if (a->argc != 3)
01839 return CLI_SHOWUSAGE;
01840 ast_cli(a->fd, "Asterisk %s built by %s @ %s on a %s running %s on %s\n",
01841 ast_get_version(), ast_build_user, ast_build_hostname,
01842 ast_build_machine, ast_build_os, ast_build_date);
01843 return CLI_SUCCESS;
01844 }
01845
01846 #if 0
01847 static int handle_quit(int fd, int argc, char *argv[])
01848 {
01849 if (argc != 1)
01850 return RESULT_SHOWUSAGE;
01851 quit_handler(0, 0, 1, 0);
01852 return RESULT_SUCCESS;
01853 }
01854 #endif
01855
01856 static char *handle_stop_now(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01857 {
01858 switch (cmd) {
01859 case CLI_INIT:
01860 e->command = "core stop now";
01861 e->usage =
01862 "Usage: core stop now\n"
01863 " Shuts down a running Asterisk immediately, hanging up all active calls .\n";
01864 return NULL;
01865 case CLI_GENERATE:
01866 return NULL;
01867 }
01868
01869 if (a->argc != e->args)
01870 return CLI_SHOWUSAGE;
01871 quit_handler(0, 0 , 1 , 0 );
01872 return CLI_SUCCESS;
01873 }
01874
01875 static char *handle_stop_gracefully(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01876 {
01877 switch (cmd) {
01878 case CLI_INIT:
01879 e->command = "core stop gracefully";
01880 e->usage =
01881 "Usage: core stop gracefully\n"
01882 " Causes Asterisk to not accept new calls, and exit when all\n"
01883 " active calls have terminated normally.\n";
01884 return NULL;
01885 case CLI_GENERATE:
01886 return NULL;
01887 }
01888
01889 if (a->argc != e->args)
01890 return CLI_SHOWUSAGE;
01891 quit_handler(0, 1 , 1 , 0 );
01892 return CLI_SUCCESS;
01893 }
01894
01895 static char *handle_stop_when_convenient(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01896 {
01897 switch (cmd) {
01898 case CLI_INIT:
01899 e->command = "core stop when convenient";
01900 e->usage =
01901 "Usage: core stop when convenient\n"
01902 " Causes Asterisk to perform a shutdown when all active calls have ended.\n";
01903 return NULL;
01904 case CLI_GENERATE:
01905 return NULL;
01906 }
01907
01908 if (a->argc != e->args)
01909 return CLI_SHOWUSAGE;
01910 ast_cli(a->fd, "Waiting for inactivity to perform halt\n");
01911 quit_handler(0, 2 , 1 , 0 );
01912 return CLI_SUCCESS;
01913 }
01914
01915 static char *handle_restart_now(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01916 {
01917 switch (cmd) {
01918 case CLI_INIT:
01919 e->command = "core restart now";
01920 e->usage =
01921 "Usage: core restart now\n"
01922 " Causes Asterisk to hangup all calls and exec() itself performing a cold\n"
01923 " restart.\n";
01924 return NULL;
01925 case CLI_GENERATE:
01926 return NULL;
01927 }
01928
01929 if (a->argc != e->args)
01930 return CLI_SHOWUSAGE;
01931 quit_handler(0, 0 , 1 , 1 );
01932 return CLI_SUCCESS;
01933 }
01934
01935 static char *handle_restart_gracefully(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01936 {
01937 switch (cmd) {
01938 case CLI_INIT:
01939 e->command = "core restart gracefully";
01940 e->usage =
01941 "Usage: core restart gracefully\n"
01942 " Causes Asterisk to stop accepting new calls and exec() itself performing a cold\n"
01943 " restart when all active calls have ended.\n";
01944 return NULL;
01945 case CLI_GENERATE:
01946 return NULL;
01947 }
01948
01949 if (a->argc != e->args)
01950 return CLI_SHOWUSAGE;
01951 quit_handler(0, 1 , 1 , 1 );
01952 return CLI_SUCCESS;
01953 }
01954
01955 static char *handle_restart_when_convenient(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01956 {
01957 switch (cmd) {
01958 case CLI_INIT:
01959 e->command = "core restart when convenient";
01960 e->usage =
01961 "Usage: core restart when convenient\n"
01962 " Causes Asterisk to perform a cold restart when all active calls have ended.\n";
01963 return NULL;
01964 case CLI_GENERATE:
01965 return NULL;
01966 }
01967
01968 if (a->argc != e->args)
01969 return CLI_SHOWUSAGE;
01970 ast_cli(a->fd, "Waiting for inactivity to perform restart\n");
01971 quit_handler(0, 2 , 1 , 1 );
01972 return CLI_SUCCESS;
01973 }
01974
01975 static char *handle_abort_shutdown(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01976 {
01977 switch (cmd) {
01978 case CLI_INIT:
01979 e->command = "core abort shutdown";
01980 e->usage =
01981 "Usage: core abort shutdown\n"
01982 " Causes Asterisk to abort an executing shutdown or restart, and resume normal\n"
01983 " call operations.\n";
01984 return NULL;
01985 case CLI_GENERATE:
01986 return NULL;
01987 }
01988
01989 if (a->argc != e->args)
01990 return CLI_SHOWUSAGE;
01991 ast_cancel_shutdown();
01992 shuttingdown = 0;
01993 return CLI_SUCCESS;
01994 }
01995
01996 static char *handle_bang(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01997 {
01998 switch (cmd) {
01999 case CLI_INIT:
02000 e->command = "!";
02001 e->usage =
02002 "Usage: !<command>\n"
02003 " Executes a given shell command\n";
02004 return NULL;
02005 case CLI_GENERATE:
02006 return NULL;
02007 }
02008
02009 return CLI_SUCCESS;
02010 }
02011 static const char warranty_lines[] = {
02012 "\n"
02013 " NO WARRANTY\n"
02014 "\n"
02015 "BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\n"
02016 "FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN\n"
02017 "OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\n"
02018 "PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\n"
02019 "OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n"
02020 "MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS\n"
02021 "TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE\n"
02022 "PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\n"
02023 "REPAIR OR CORRECTION.\n"
02024 "\n"
02025 "IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\n"
02026 "WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\n"
02027 "REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\n"
02028 "INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\n"
02029 "OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\n"
02030 "TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\n"
02031 "YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\n"
02032 "PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\n"
02033 "POSSIBILITY OF SUCH DAMAGES.\n"
02034 };
02035
02036 static char *show_warranty(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
02037 {
02038 switch (cmd) {
02039 case CLI_INIT:
02040 e->command = "core show warranty";
02041 e->usage =
02042 "Usage: core show warranty\n"
02043 " Shows the warranty (if any) for this copy of Asterisk.\n";
02044 return NULL;
02045 case CLI_GENERATE:
02046 return NULL;
02047 }
02048
02049 ast_cli(a->fd, "%s", warranty_lines);
02050
02051 return CLI_SUCCESS;
02052 }
02053
02054 static const char license_lines[] = {
02055 "\n"
02056 "This program is free software; you can redistribute it and/or modify\n"
02057 "it under the terms of the GNU General Public License version 2 as\n"
02058 "published by the Free Software Foundation.\n"
02059 "\n"
02060 "This program also contains components licensed under other licenses.\n"
02061 "They include:\n"
02062 "\n"
02063 "This program is distributed in the hope that it will be useful,\n"
02064 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
02065 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
02066 "GNU General Public License for more details.\n"
02067 "\n"
02068 "You should have received a copy of the GNU General Public License\n"
02069 "along with this program; if not, write to the Free Software\n"
02070 "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n"
02071 };
02072
02073 static char *show_license(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
02074 {
02075 switch (cmd) {
02076 case CLI_INIT:
02077 e->command = "core show license";
02078 e->usage =
02079 "Usage: core show license\n"
02080 " Shows the license(s) for this copy of Asterisk.\n";
02081 return NULL;
02082 case CLI_GENERATE:
02083 return NULL;
02084 }
02085
02086 ast_cli(a->fd, "%s", license_lines);
02087
02088 return CLI_SUCCESS;
02089 }
02090
02091 #define ASTERISK_PROMPT "*CLI> "
02092
02093 #define ASTERISK_PROMPT2 "%s*CLI> "
02094
02095 static struct ast_cli_entry cli_asterisk[] = {
02096 AST_CLI_DEFINE(handle_abort_shutdown, "Cancel a running shutdown"),
02097 AST_CLI_DEFINE(handle_stop_now, "Shut down Asterisk immediately"),
02098 AST_CLI_DEFINE(handle_stop_gracefully, "Gracefully shut down Asterisk"),
02099 AST_CLI_DEFINE(handle_stop_when_convenient, "Shut down Asterisk at empty call volume"),
02100 AST_CLI_DEFINE(handle_restart_now, "Restart Asterisk immediately"),
02101 AST_CLI_DEFINE(handle_restart_gracefully, "Restart Asterisk gracefully"),
02102 AST_CLI_DEFINE(handle_restart_when_convenient, "Restart Asterisk at empty call volume"),
02103 AST_CLI_DEFINE(show_warranty, "Show the warranty (if any) for this copy of Asterisk"),
02104 AST_CLI_DEFINE(show_license, "Show the license(s) for this copy of Asterisk"),
02105 AST_CLI_DEFINE(handle_version, "Display version info"),
02106 AST_CLI_DEFINE(handle_bang, "Execute a shell command"),
02107 #if !defined(LOW_MEMORY)
02108 AST_CLI_DEFINE(handle_show_version_files, "List versions of files used to build Asterisk"),
02109 AST_CLI_DEFINE(handle_show_threads, "Show running threads"),
02110 #if defined(HAVE_SYSINFO) || defined(HAVE_SYSCTL)
02111 AST_CLI_DEFINE(handle_show_sysinfo, "Show System Information"),
02112 #endif
02113 AST_CLI_DEFINE(handle_show_profile, "Display profiling info"),
02114 AST_CLI_DEFINE(handle_show_settings, "Show some core settings"),
02115 AST_CLI_DEFINE(handle_clear_profile, "Clear profiling info"),
02116 #endif
02117 };
02118
02119 static int ast_el_read_char(EditLine *editline, char *cp)
02120 {
02121 int num_read = 0;
02122 int lastpos = 0;
02123 struct pollfd fds[2];
02124 int res;
02125 int max;
02126 #define EL_BUF_SIZE 512
02127 char buf[EL_BUF_SIZE];
02128
02129 for (;;) {
02130 max = 1;
02131 fds[0].fd = ast_consock;
02132 fds[0].events = POLLIN;
02133 if (!ast_opt_exec) {
02134 fds[1].fd = STDIN_FILENO;
02135 fds[1].events = POLLIN;
02136 max++;
02137 }
02138 res = ast_poll(fds, max, -1);
02139 if (res < 0) {
02140 if (sig_flags.need_quit)
02141 break;
02142 if (errno == EINTR)
02143 continue;
02144 ast_log(LOG_ERROR, "poll failed: %s\n", strerror(errno));
02145 break;
02146 }
02147
02148 if (!ast_opt_exec && fds[1].revents) {
02149 num_read = read(STDIN_FILENO, cp, 1);
02150 if (num_read < 1) {
02151 break;
02152 } else
02153 return (num_read);
02154 }
02155 if (fds[0].revents) {
02156 char *tmp;
02157 res = read(ast_consock, buf, sizeof(buf) - 1);
02158
02159 if (res < 1) {
02160 fprintf(stderr, "\nDisconnected from Asterisk server\n");
02161 if (!ast_opt_reconnect) {
02162 quit_handler(0, 0, 0, 0);
02163 } else {
02164 int tries;
02165 int reconnects_per_second = 20;
02166 fprintf(stderr, "Attempting to reconnect for 30 seconds\n");
02167 for (tries = 0; tries < 30 * reconnects_per_second; tries++) {
02168 if (ast_tryconnect()) {
02169 fprintf(stderr, "Reconnect succeeded after %.3f seconds\n", 1.0 / reconnects_per_second * tries);
02170 printf("%s", term_quit());
02171 WELCOME_MESSAGE;
02172 if (!ast_opt_mute)
02173 fdsend(ast_consock, "logger mute silent");
02174 else
02175 printf("log and verbose output currently muted ('logger mute' to unmute)\n");
02176 break;
02177 } else
02178 usleep(1000000 / reconnects_per_second);
02179 }
02180 if (tries >= 30 * reconnects_per_second) {
02181 fprintf(stderr, "Failed to reconnect for 30 seconds. Quitting.\n");
02182 quit_handler(0, 0, 0, 0);
02183 }
02184 }
02185 }
02186
02187 buf[res] = '\0';
02188
02189
02190 for (tmp = buf; *tmp; tmp++) {
02191 if (*tmp == 127) {
02192 memmove(tmp, tmp + 1, strlen(tmp));
02193 tmp--;
02194 res--;
02195 }
02196 }
02197
02198
02199 if (!ast_opt_exec && !lastpos) {
02200 if (write(STDOUT_FILENO, "\r[0K", 5) < 0) {
02201 }
02202 }
02203 if (write(STDOUT_FILENO, buf, res) < 0) {
02204 }
02205 if ((res < EL_BUF_SIZE - 1) && ((buf[res-1] == '\n') || (buf[res-2] == '\n'))) {
02206 *cp = CC_REFRESH;
02207 return(1);
02208 } else
02209 lastpos = 1;
02210 }
02211 }
02212
02213 *cp = '\0';
02214 return (0);
02215 }
02216
02217 static struct ast_str *prompt = NULL;
02218
02219 static char *cli_prompt(EditLine *editline)
02220 {
02221 char tmp[100];
02222 char *pfmt;
02223 int color_used = 0;
02224 static int cli_prompt_changes = 0;
02225 char term_code[20];
02226 struct passwd *pw;
02227 struct group *gr;
02228
02229 if (prompt == NULL) {
02230 prompt = ast_str_create(100);
02231 } else if (!cli_prompt_changes) {
02232 return ast_str_buffer(prompt);
02233 } else {
02234 ast_str_reset(prompt);
02235 }
02236
02237 if ((pfmt = getenv("ASTERISK_PROMPT"))) {
02238 char *t = pfmt;
02239 struct timeval ts = ast_tvnow();
02240 while (*t != '\0') {
02241 if (*t == '%') {
02242 char hostname[MAXHOSTNAMELEN] = "";
02243 int i, which;
02244 struct ast_tm tm = { 0, };
02245 int fgcolor = COLOR_WHITE, bgcolor = COLOR_BLACK;
02246
02247 t++;
02248 switch (*t) {
02249 case 'C':
02250 t++;
02251 if (sscanf(t, "%30d;%30d%n", &fgcolor, &bgcolor, &i) == 2) {
02252 ast_str_append(&prompt, 0, "%s", term_color_code(term_code, fgcolor, bgcolor, sizeof(term_code)));
02253 t += i - 1;
02254 } else if (sscanf(t, "%30d%n", &fgcolor, &i) == 1) {
02255 ast_str_append(&prompt, 0, "%s", term_color_code(term_code, fgcolor, 0, sizeof(term_code)));
02256 t += i - 1;
02257 }
02258
02259
02260 color_used = ((fgcolor == COLOR_WHITE) && (bgcolor == COLOR_BLACK)) ? 0 : 1;
02261 break;
02262 case 'd':
02263 if (ast_localtime(&ts, &tm, NULL)) {
02264 ast_strftime(tmp, sizeof(tmp), "%Y-%m-%d", &tm);
02265 ast_str_append(&prompt, 0, "%s", tmp);
02266 cli_prompt_changes++;
02267 }
02268 break;
02269 case 'g':
02270 if ((gr = getgrgid(getgid()))) {
02271 ast_str_append(&prompt, 0, "%s", gr->gr_name);
02272 }
02273 break;
02274 case 'h':
02275 if (!gethostname(hostname, sizeof(hostname) - 1)) {
02276 ast_str_append(&prompt, 0, "%s", hostname);
02277 } else {
02278 ast_str_append(&prompt, 0, "%s", "localhost");
02279 }
02280 break;
02281 case 'H':
02282 if (!gethostname(hostname, sizeof(hostname) - 1)) {
02283 char *dotptr;
02284 if ((dotptr = strchr(hostname, '.'))) {
02285 *dotptr = '\0';
02286 }
02287 ast_str_append(&prompt, 0, "%s", hostname);
02288 } else {
02289 ast_str_append(&prompt, 0, "%s", "localhost");
02290 }
02291 break;
02292 #ifdef HAVE_GETLOADAVG
02293 case 'l':
02294 t++;
02295 if (sscanf(t, "%30d", &which) == 1 && which > 0 && which <= 3) {
02296 double list[3];
02297 getloadavg(list, 3);
02298 ast_str_append(&prompt, 0, "%.2f", list[which - 1]);
02299 cli_prompt_changes++;
02300 }
02301 break;
02302 #endif
02303 case 's':
02304 ast_str_append(&prompt, 0, "%s", ast_config_AST_SYSTEM_NAME);
02305 break;
02306 case 't':
02307 if (ast_localtime(&ts, &tm, NULL)) {
02308 ast_strftime(tmp, sizeof(tmp), "%H:%M:%S", &tm);
02309 ast_str_append(&prompt, 0, "%s", tmp);
02310 cli_prompt_changes++;
02311 }
02312 break;
02313 case 'u':
02314 if ((pw = getpwuid(getuid()))) {
02315 ast_str_append(&prompt, 0, "%s", pw->pw_name);
02316 }
02317 break;
02318 case '#':
02319 ast_str_append(&prompt, 0, "%c", ast_opt_remote ? '>' : '#');
02320 break;
02321 case '%':
02322 ast_str_append(&prompt, 0, "%c", '%');
02323 break;
02324 case '\0':
02325 t--;
02326 break;
02327 }
02328 } else {
02329 ast_str_append(&prompt, 0, "%c", *t);
02330 }
02331 t++;
02332 }
02333 if (color_used) {
02334
02335 ast_str_append(&prompt, 0, "%s", term_color_code(term_code, 0, 0, sizeof(term_code)));
02336 }
02337 } else if (remotehostname) {
02338 ast_str_set(&prompt, 0, ASTERISK_PROMPT2, remotehostname);
02339 } else {
02340 ast_str_set(&prompt, 0, "%s", ASTERISK_PROMPT);
02341 }
02342
02343 return ast_str_buffer(prompt);
02344 }
02345
02346 static char **ast_el_strtoarr(char *buf)
02347 {
02348 char **match_list = NULL, **match_list_tmp, *retstr;
02349 size_t match_list_len;
02350 int matches = 0;
02351
02352 match_list_len = 1;
02353 while ( (retstr = strsep(&buf, " ")) != NULL) {
02354
02355 if (!strcmp(retstr, AST_CLI_COMPLETE_EOF))
02356 break;
02357 if (matches + 1 >= match_list_len) {
02358 match_list_len <<= 1;
02359 if ((match_list_tmp = ast_realloc(match_list, match_list_len * sizeof(char *)))) {
02360 match_list = match_list_tmp;
02361 } else {
02362 if (match_list)
02363 ast_free(match_list);
02364 return (char **) NULL;
02365 }
02366 }
02367
02368 match_list[matches++] = ast_strdup(retstr);
02369 }
02370
02371 if (!match_list)
02372 return (char **) NULL;
02373
02374 if (matches >= match_list_len) {
02375 if ((match_list_tmp = ast_realloc(match_list, (match_list_len + 1) * sizeof(char *)))) {
02376 match_list = match_list_tmp;
02377 } else {
02378 if (match_list)
02379 ast_free(match_list);
02380 return (char **) NULL;
02381 }
02382 }
02383
02384 match_list[matches] = (char *) NULL;
02385
02386 return match_list;
02387 }
02388
02389 static int ast_el_sort_compare(const void *i1, const void *i2)
02390 {
02391 char *s1, *s2;
02392
02393 s1 = ((char **)i1)[0];
02394 s2 = ((char **)i2)[0];
02395
02396 return strcasecmp(s1, s2);
02397 }
02398
02399 static int ast_cli_display_match_list(char **matches, int len, int max)
02400 {
02401 int i, idx, limit, count;
02402 int screenwidth = 0;
02403 int numoutput = 0, numoutputline = 0;
02404
02405 screenwidth = ast_get_termcols(STDOUT_FILENO);
02406
02407
02408 limit = screenwidth / (max + 2);
02409 if (limit == 0)
02410 limit = 1;
02411
02412
02413 count = len / limit;
02414 if (count * limit < len)
02415 count++;
02416
02417 idx = 1;
02418
02419 qsort(&matches[0], (size_t)(len), sizeof(char *), ast_el_sort_compare);
02420
02421 for (; count > 0; count--) {
02422 numoutputline = 0;
02423 for (i = 0; i < limit && matches[idx]; i++, idx++) {
02424
02425
02426 if ( (matches[idx+1] != NULL && strcmp(matches[idx], matches[idx+1]) == 0 ) ) {
02427 i--;
02428 ast_free(matches[idx]);
02429 matches[idx] = NULL;
02430 continue;
02431 }
02432
02433 numoutput++;
02434 numoutputline++;
02435 fprintf(stdout, "%-*s ", max, matches[idx]);
02436 ast_free(matches[idx]);
02437 matches[idx] = NULL;
02438 }
02439 if (numoutputline > 0)
02440 fprintf(stdout, "\n");
02441 }
02442
02443 return numoutput;
02444 }
02445
02446
02447 static char *cli_complete(EditLine *editline, int ch)
02448 {
02449 int len = 0;
02450 char *ptr;
02451 int nummatches = 0;
02452 char **matches;
02453 int retval = CC_ERROR;
02454 char buf[2048], savechr;
02455 int res;
02456
02457 LineInfo *lf = (LineInfo *)el_line(editline);
02458
02459 savechr = *(char *)lf->cursor;
02460 *(char *)lf->cursor = '\0';
02461 ptr = (char *)lf->cursor;
02462 if (ptr) {
02463 while (ptr > lf->buffer) {
02464 if (isspace(*ptr)) {
02465 ptr++;
02466 break;
02467 }
02468 ptr--;
02469 }
02470 }
02471
02472 len = lf->cursor - ptr;
02473
02474 if (ast_opt_remote) {
02475 snprintf(buf, sizeof(buf), "_COMMAND NUMMATCHES \"%s\" \"%s\"", lf->buffer, ptr);
02476 fdsend(ast_consock, buf);
02477 res = read(ast_consock, buf, sizeof(buf) - 1);
02478 buf[res] = '\0';
02479 nummatches = atoi(buf);
02480
02481 if (nummatches > 0) {
02482 char *mbuf;
02483 int mlen = 0, maxmbuf = 2048;
02484
02485 if (!(mbuf = ast_malloc(maxmbuf))) {
02486 lf->cursor[0] = savechr;
02487 return (char *)(CC_ERROR);
02488 }
02489 snprintf(buf, sizeof(buf), "_COMMAND MATCHESARRAY \"%s\" \"%s\"", lf->buffer, ptr);
02490 fdsend(ast_consock, buf);
02491 res = 0;
02492 mbuf[0] = '\0';
02493 while (!strstr(mbuf, AST_CLI_COMPLETE_EOF) && res != -1) {
02494 if (mlen + 1024 > maxmbuf) {
02495
02496 maxmbuf += 1024;
02497 if (!(mbuf = ast_realloc(mbuf, maxmbuf))) {
02498 lf->cursor[0] = savechr;
02499 return (char *)(CC_ERROR);
02500 }
02501 }
02502
02503 res = read(ast_consock, mbuf + mlen, 1024);
02504 if (res > 0)
02505 mlen += res;
02506 }
02507 mbuf[mlen] = '\0';
02508
02509 matches = ast_el_strtoarr(mbuf);
02510 ast_free(mbuf);
02511 } else
02512 matches = (char **) NULL;
02513 } else {
02514 char **p, *oldbuf=NULL;
02515 nummatches = 0;
02516 matches = ast_cli_completion_matches((char *)lf->buffer,ptr);
02517 for (p = matches; p && *p; p++) {
02518 if (!oldbuf || strcmp(*p,oldbuf))
02519 nummatches++;
02520 oldbuf = *p;
02521 }
02522 }
02523
02524 if (matches) {
02525 int i;
02526 int matches_num, maxlen, match_len;
02527
02528 if (matches[0][0] != '\0') {
02529 el_deletestr(editline, (int) len);
02530 el_insertstr(editline, matches[0]);
02531 retval = CC_REFRESH;
02532 }
02533
02534 if (nummatches == 1) {
02535
02536 el_insertstr(editline, " ");
02537 retval = CC_REFRESH;
02538 } else {
02539
02540 for (i = 1, maxlen = 0; matches[i]; i++) {
02541 match_len = strlen(matches[i]);
02542 if (match_len > maxlen)
02543 maxlen = match_len;
02544 }
02545 matches_num = i - 1;
02546 if (matches_num >1) {
02547 fprintf(stdout, "\n");
02548 ast_cli_display_match_list(matches, nummatches, maxlen);
02549 retval = CC_REDISPLAY;
02550 } else {
02551 el_insertstr(editline," ");
02552 retval = CC_REFRESH;
02553 }
02554 }
02555 for (i = 0; matches[i]; i++)
02556 ast_free(matches[i]);
02557 ast_free(matches);
02558 }
02559
02560 lf->cursor[0] = savechr;
02561
02562 return (char *)(long)retval;
02563 }
02564
02565 static int ast_el_initialize(void)
02566 {
02567 HistEvent ev;
02568 char *editor = getenv("AST_EDITOR");
02569
02570 if (el != NULL)
02571 el_end(el);
02572 if (el_hist != NULL)
02573 history_end(el_hist);
02574
02575 el = el_init("asterisk", stdin, stdout, stderr);
02576 el_set(el, EL_PROMPT, cli_prompt);
02577
02578 el_set(el, EL_EDITMODE, 1);
02579 el_set(el, EL_EDITOR, editor ? editor : "emacs");
02580 el_hist = history_init();
02581 if (!el || !el_hist)
02582 return -1;
02583
02584
02585 history(el_hist, &ev, H_SETSIZE, 100);
02586
02587 el_set(el, EL_HIST, history, el_hist);
02588
02589 el_set(el, EL_ADDFN, "ed-complete", "Complete argument", cli_complete);
02590
02591 el_set(el, EL_BIND, "^I", "ed-complete", NULL);
02592
02593 el_set(el, EL_BIND, "?", "ed-complete", NULL);
02594
02595 el_set(el, EL_BIND, "^D", "ed-redisplay", NULL);
02596
02597 return 0;
02598 }
02599
02600 #define MAX_HISTORY_COMMAND_LENGTH 256
02601
02602 static int ast_el_add_history(char *buf)
02603 {
02604 HistEvent ev;
02605
02606 if (el_hist == NULL || el == NULL)
02607 ast_el_initialize();
02608 if (strlen(buf) > (MAX_HISTORY_COMMAND_LENGTH - 1))
02609 return 0;
02610 return (history(el_hist, &ev, H_ENTER, ast_strip(ast_strdupa(buf))));
02611 }
02612
02613 static int ast_el_write_history(char *filename)
02614 {
02615 HistEvent ev;
02616
02617 if (el_hist == NULL || el == NULL)
02618 ast_el_initialize();
02619
02620 return (history(el_hist, &ev, H_SAVE, filename));
02621 }
02622
02623 static int ast_el_read_history(char *filename)
02624 {
02625 char buf[MAX_HISTORY_COMMAND_LENGTH];
02626 FILE *f;
02627 int ret = -1;
02628
02629 if (el_hist == NULL || el == NULL)
02630 ast_el_initialize();
02631
02632 if ((f = fopen(filename, "r")) == NULL)
02633 return ret;
02634
02635 while (!feof(f)) {
02636 if (!fgets(buf, sizeof(buf), f))
02637 break;
02638 if (!strcmp(buf, "_HiStOrY_V2_\n"))
02639 continue;
02640 if (ast_all_zeros(buf))
02641 continue;
02642 if ((ret = ast_el_add_history(buf)) == -1)
02643 break;
02644 }
02645 fclose(f);
02646
02647 return ret;
02648 }
02649
02650 static void ast_remotecontrol(char *data)
02651 {
02652 char buf[80];
02653 int res;
02654 char filename[80] = "";
02655 char *hostname;
02656 char *cpid;
02657 char *version;
02658 int pid;
02659 char *stringp = NULL;
02660
02661 char *ebuf;
02662 int num = 0;
02663
02664 memset(&sig_flags, 0, sizeof(sig_flags));
02665 signal(SIGINT, __remote_quit_handler);
02666 signal(SIGTERM, __remote_quit_handler);
02667 signal(SIGHUP, __remote_quit_handler);
02668
02669 if (read(ast_consock, buf, sizeof(buf)) < 0) {
02670 ast_log(LOG_ERROR, "read() failed: %s\n", strerror(errno));
02671 return;
02672 }
02673 if (data) {
02674 char prefix[] = "cli quit after ";
02675 char *tmp = alloca(strlen(data) + strlen(prefix) + 1);
02676 sprintf(tmp, "%s%s", prefix, data);
02677 if (write(ast_consock, tmp, strlen(tmp) + 1) < 0) {
02678 ast_log(LOG_ERROR, "write() failed: %s\n", strerror(errno));
02679 if (sig_flags.need_quit == 1) {
02680 return;
02681 }
02682 }
02683 }
02684 stringp = buf;
02685 hostname = strsep(&stringp, "/");
02686 cpid = strsep(&stringp, "/");
02687 version = strsep(&stringp, "\n");
02688 if (!version)
02689 version = "<Version Unknown>";
02690 stringp = hostname;
02691 strsep(&stringp, ".");
02692 if (cpid)
02693 pid = atoi(cpid);
02694 else
02695 pid = -1;
02696 if (!data) {
02697 char tmp[80];
02698 snprintf(tmp, sizeof(tmp), "core set verbose atleast %d", option_verbose);
02699 fdsend(ast_consock, tmp);
02700 snprintf(tmp, sizeof(tmp), "core set debug atleast %d", option_debug);
02701 fdsend(ast_consock, tmp);
02702 if (!ast_opt_mute)
02703 fdsend(ast_consock, "logger mute silent");
02704 else
02705 printf("log and verbose output currently muted ('logger mute' to unmute)\n");
02706 }
02707
02708 if (ast_opt_exec && data) {
02709 struct pollfd fds;
02710 fds.fd = ast_consock;
02711 fds.events = POLLIN;
02712 fds.revents = 0;
02713 while (ast_poll(&fds, 1, 60000) > 0) {
02714 char buffer[512] = "", *curline = buffer, *nextline;
02715 int not_written = 1;
02716
02717 if (sig_flags.need_quit == 1) {
02718 break;
02719 }
02720
02721 if (read(ast_consock, buffer, sizeof(buffer) - 1) <= 0) {
02722 break;
02723 }
02724
02725 do {
02726 if ((nextline = strchr(curline, '\n'))) {
02727 nextline++;
02728 } else {
02729 nextline = strchr(curline, '\0');
02730 }
02731
02732
02733 if (*curline != 127) {
02734 not_written = 0;
02735 if (write(STDOUT_FILENO, curline, nextline - curline) < 0) {
02736 ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno));
02737 }
02738 }
02739 curline = nextline;
02740 } while (!ast_strlen_zero(curline));
02741
02742
02743 if (not_written) {
02744 break;
02745 }
02746 }
02747 return;
02748 }
02749
02750 ast_verbose("Connected to Asterisk %s currently running on %s (pid = %d)\n", version, hostname, pid);
02751 remotehostname = hostname;
02752 if (getenv("HOME"))
02753 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
02754 if (el_hist == NULL || el == NULL)
02755 ast_el_initialize();
02756
02757 el_set(el, EL_GETCFN, ast_el_read_char);
02758
02759 if (!ast_strlen_zero(filename))
02760 ast_el_read_history(filename);
02761
02762 for (;;) {
02763 ebuf = (char *)el_gets(el, &num);
02764
02765 if (sig_flags.need_quit == 1) {
02766 break;
02767 }
02768
02769 if (!ebuf && write(1, "", 1) < 0)
02770 break;
02771
02772 if (!ast_strlen_zero(ebuf)) {
02773 if (ebuf[strlen(ebuf)-1] == '\n')
02774 ebuf[strlen(ebuf)-1] = '\0';
02775 if (!remoteconsolehandler(ebuf)) {
02776
02777 char *temp;
02778 for (temp = ebuf; *temp; temp++) {
02779 if (*temp == 127) {
02780 memmove(temp, temp + 1, strlen(temp));
02781 temp--;
02782 }
02783 }
02784 res = write(ast_consock, ebuf, strlen(ebuf) + 1);
02785 if (res < 1) {
02786 ast_log(LOG_WARNING, "Unable to write: %s\n", strerror(errno));
02787 break;
02788 }
02789 }
02790 }
02791 }
02792 printf("\nDisconnected from Asterisk server\n");
02793 }
02794
02795 static int show_version(void)
02796 {
02797 printf("Asterisk %s\n", ast_get_version());
02798 return 0;
02799 }
02800
02801 static int show_cli_help(void) {
02802 printf("Asterisk %s, Copyright (C) 1999 - 2010, Digium, Inc. and others.\n", ast_get_version());
02803 printf("Usage: asterisk [OPTIONS]\n");
02804 printf("Valid Options:\n");
02805 printf(" -V Display version number and exit\n");
02806 printf(" -C <configfile> Use an alternate configuration file\n");
02807 printf(" -G <group> Run as a group other than the caller\n");
02808 printf(" -U <user> Run as a user other than the caller\n");
02809 printf(" -c Provide console CLI\n");
02810 printf(" -d Enable extra debugging\n");
02811 #if HAVE_WORKING_FORK
02812 printf(" -f Do not fork\n");
02813 printf(" -F Always fork\n");
02814 #endif
02815 printf(" -g Dump core in case of a crash\n");
02816 printf(" -h This help screen\n");
02817 printf(" -i Initialize crypto keys at startup\n");
02818 printf(" -I Enable internal timing if DAHDI timer is available\n");
02819 printf(" -L <load> Limit the maximum load average before rejecting new calls\n");
02820 printf(" -M <value> Limit the maximum number of calls to the specified value\n");
02821 printf(" -m Mute debugging and console output on the console\n");
02822 printf(" -n Disable console colorization\n");
02823 printf(" -p Run as pseudo-realtime thread\n");
02824 printf(" -q Quiet mode (suppress output)\n");
02825 printf(" -r Connect to Asterisk on this machine\n");
02826 printf(" -R Same as -r, except attempt to reconnect if disconnected\n");
02827 printf(" -s <socket> Connect to Asterisk via socket <socket> (only valid with -r)\n");
02828 printf(" -t Record soundfiles in /var/tmp and move them where they\n");
02829 printf(" belong after they are done\n");
02830 printf(" -T Display the time in [Mmm dd hh:mm:ss] format for each line\n");
02831 printf(" of output to the CLI\n");
02832 printf(" -v Increase verbosity (multiple v's = more verbose)\n");
02833 printf(" -x <cmd> Execute command <cmd> (only valid with -r)\n");
02834 printf(" -X Execute includes by default (allows #exec in asterisk.conf)\n");
02835 printf(" -W Adjust terminal colors to compensate for a light background\n");
02836 printf("\n");
02837 return 0;
02838 }
02839
02840 static void ast_readconfig(void)
02841 {
02842 struct ast_config *cfg;
02843 struct ast_variable *v;
02844 char *config = DEFAULT_CONFIG_FILE;
02845 char hostname[MAXHOSTNAMELEN] = "";
02846 struct ast_flags config_flags = { CONFIG_FLAG_NOREALTIME };
02847 struct {
02848 unsigned int dbdir:1;
02849 unsigned int keydir:1;
02850 } found = { 0, 0 };
02851
02852 if (ast_opt_override_config) {
02853 cfg = ast_config_load2(ast_config_AST_CONFIG_FILE, "" , config_flags);
02854 if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID)
02855 ast_log(LOG_WARNING, "Unable to open specified master config file '%s', using built-in defaults\n", ast_config_AST_CONFIG_FILE);
02856 } else
02857 cfg = ast_config_load2(config, "" , config_flags);
02858
02859
02860 ast_copy_string(cfg_paths.config_dir, DEFAULT_CONFIG_DIR, sizeof(cfg_paths.config_dir));
02861 ast_copy_string(cfg_paths.spool_dir, DEFAULT_SPOOL_DIR, sizeof(cfg_paths.spool_dir));
02862 ast_copy_string(cfg_paths.module_dir, DEFAULT_MODULE_DIR, sizeof(cfg_paths.module_dir));
02863 snprintf(cfg_paths.monitor_dir, sizeof(cfg_paths.monitor_dir), "%s/monitor", cfg_paths.spool_dir);
02864 ast_copy_string(cfg_paths.var_dir, DEFAULT_VAR_DIR, sizeof(cfg_paths.var_dir));
02865 ast_copy_string(cfg_paths.data_dir, DEFAULT_DATA_DIR, sizeof(cfg_paths.data_dir));
02866 ast_copy_string(cfg_paths.log_dir, DEFAULT_LOG_DIR, sizeof(cfg_paths.log_dir));
02867 ast_copy_string(cfg_paths.agi_dir, DEFAULT_AGI_DIR, sizeof(cfg_paths.agi_dir));
02868 ast_copy_string(cfg_paths.db_path, DEFAULT_DB, sizeof(cfg_paths.db_path));
02869 ast_copy_string(cfg_paths.key_dir, DEFAULT_KEY_DIR, sizeof(cfg_paths.key_dir));
02870 ast_copy_string(cfg_paths.pid_path, DEFAULT_PID, sizeof(cfg_paths.pid_path));
02871 ast_copy_string(cfg_paths.socket_path, DEFAULT_SOCKET, sizeof(cfg_paths.socket_path));
02872 ast_copy_string(cfg_paths.run_dir, DEFAULT_RUN_DIR, sizeof(cfg_paths.run_dir));
02873
02874 ast_set_default_eid(&ast_eid_default);
02875
02876
02877 if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) {
02878 return;
02879 }
02880
02881 for (v = ast_variable_browse(cfg, "files"); v; v = v->next) {
02882 if (!strcasecmp(v->name, "astctlpermissions"))
02883 ast_copy_string(ast_config_AST_CTL_PERMISSIONS, v->value, sizeof(ast_config_AST_CTL_PERMISSIONS));
02884 else if (!strcasecmp(v->name, "astctlowner"))
02885 ast_copy_string(ast_config_AST_CTL_OWNER, v->value, sizeof(ast_config_AST_CTL_OWNER));
02886 else if (!strcasecmp(v->name, "astctlgroup"))
02887 ast_copy_string(ast_config_AST_CTL_GROUP, v->value, sizeof(ast_config_AST_CTL_GROUP));
02888 else if (!strcasecmp(v->name, "astctl"))
02889 ast_copy_string(ast_config_AST_CTL, v->value, sizeof(ast_config_AST_CTL));
02890 }
02891
02892 for (v = ast_variable_browse(cfg, "directories"); v; v = v->next) {
02893 if (!strcasecmp(v->name, "astetcdir")) {
02894 ast_copy_string(cfg_paths.config_dir, v->value, sizeof(cfg_paths.config_dir));
02895 } else if (!strcasecmp(v->name, "astspooldir")) {
02896 ast_copy_string(cfg_paths.spool_dir, v->value, sizeof(cfg_paths.spool_dir));
02897 snprintf(cfg_paths.monitor_dir, sizeof(cfg_paths.monitor_dir), "%s/monitor", v->value);
02898 } else if (!strcasecmp(v->name, "astvarlibdir")) {
02899 ast_copy_string(cfg_paths.var_dir, v->value, sizeof(cfg_paths.var_dir));
02900 if (!found.dbdir)
02901 snprintf(cfg_paths.db_path, sizeof(cfg_paths.db_path), "%s/astdb", v->value);
02902 } else if (!strcasecmp(v->name, "astdbdir")) {
02903 snprintf(cfg_paths.db_path, sizeof(cfg_paths.db_path), "%s/astdb", v->value);
02904 found.dbdir = 1;
02905 } else if (!strcasecmp(v->name, "astdatadir")) {
02906 ast_copy_string(cfg_paths.data_dir, v->value, sizeof(cfg_paths.data_dir));
02907 if (!found.keydir)
02908 snprintf(cfg_paths.key_dir, sizeof(cfg_paths.key_dir), "%s/keys", v->value);
02909 } else if (!strcasecmp(v->name, "astkeydir")) {
02910 snprintf(cfg_paths.key_dir, sizeof(cfg_paths.key_dir), "%s/keys", v->value);
02911 found.keydir = 1;
02912 } else if (!strcasecmp(v->name, "astlogdir")) {
02913 ast_copy_string(cfg_paths.log_dir, v->value, sizeof(cfg_paths.log_dir));
02914 } else if (!strcasecmp(v->name, "astagidir")) {
02915 ast_copy_string(cfg_paths.agi_dir, v->value, sizeof(cfg_paths.agi_dir));
02916 } else if (!strcasecmp(v->name, "astrundir")) {
02917 snprintf(cfg_paths.pid_path, sizeof(cfg_paths.pid_path), "%s/%s", v->value, "asterisk.pid");
02918 snprintf(cfg_paths.socket_path, sizeof(cfg_paths.socket_path), "%s/%s", v->value, ast_config_AST_CTL);
02919 ast_copy_string(cfg_paths.run_dir, v->value, sizeof(cfg_paths.run_dir));
02920 } else if (!strcasecmp(v->name, "astmoddir")) {
02921 ast_copy_string(cfg_paths.module_dir, v->value, sizeof(cfg_paths.module_dir));
02922 }
02923 }
02924
02925 for (v = ast_variable_browse(cfg, "options"); v; v = v->next) {
02926
02927 if (!strcasecmp(v->name, "verbose")) {
02928 option_verbose = atoi(v->value);
02929
02930 } else if (!strcasecmp(v->name, "timestamp")) {
02931 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TIMESTAMP);
02932
02933 } else if (!strcasecmp(v->name, "execincludes")) {
02934 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_EXEC_INCLUDES);
02935
02936 } else if (!strcasecmp(v->name, "debug")) {
02937 option_debug = 0;
02938 if (sscanf(v->value, "%30d", &option_debug) != 1) {
02939 option_debug = ast_true(v->value);
02940 }
02941 #if HAVE_WORKING_FORK
02942
02943 } else if (!strcasecmp(v->name, "nofork")) {
02944 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_FORK);
02945
02946 } else if (!strcasecmp(v->name, "alwaysfork")) {
02947 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_ALWAYS_FORK);
02948 #endif
02949
02950 } else if (!strcasecmp(v->name, "quiet")) {
02951 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_QUIET);
02952
02953 } else if (!strcasecmp(v->name, "console")) {
02954 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_CONSOLE);
02955
02956 } else if (!strcasecmp(v->name, "highpriority")) {
02957 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_HIGH_PRIORITY);
02958
02959 } else if (!strcasecmp(v->name, "initcrypto")) {
02960 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_INIT_KEYS);
02961
02962 } else if (!strcasecmp(v->name, "nocolor")) {
02963 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_COLOR);
02964
02965 } else if (!strcasecmp(v->name, "dontwarn")) {
02966 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_DONT_WARN);
02967
02968 } else if (!strcasecmp(v->name, "dumpcore")) {
02969 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_DUMP_CORE);
02970
02971 } else if (!strcasecmp(v->name, "cache_record_files")) {
02972 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_CACHE_RECORD_FILES);
02973
02974 } else if (!strcasecmp(v->name, "record_cache_dir")) {
02975 ast_copy_string(record_cache_dir, v->value, AST_CACHE_DIR_LEN);
02976
02977 } else if (!strcasecmp(v->name, "transcode_via_sln")) {
02978 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TRANSCODE_VIA_SLIN);
02979
02980 } else if (!strcasecmp(v->name, "transmit_silence_during_record") || !strcasecmp(v->name, "transmit_silence")) {
02981 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TRANSMIT_SILENCE);
02982
02983 } else if (!strcasecmp(v->name, "internal_timing")) {
02984 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_INTERNAL_TIMING);
02985 } else if (!strcasecmp(v->name, "maxcalls")) {
02986 if ((sscanf(v->value, "%30d", &option_maxcalls) != 1) || (option_maxcalls < 0)) {
02987 option_maxcalls = 0;
02988 }
02989 } else if (!strcasecmp(v->name, "maxload")) {
02990 double test[1];
02991
02992 if (getloadavg(test, 1) == -1) {
02993 ast_log(LOG_ERROR, "Cannot obtain load average on this system. 'maxload' option disabled.\n");
02994 option_maxload = 0.0;
02995 } else if ((sscanf(v->value, "%30lf", &option_maxload) != 1) || (option_maxload < 0.0)) {
02996 option_maxload = 0.0;
02997 }
02998
02999 } else if (!strcasecmp(v->name, "maxfiles")) {
03000 option_maxfiles = atoi(v->value);
03001 set_ulimit(option_maxfiles);
03002
03003 } else if (!strcasecmp(v->name, "runuser")) {
03004 ast_copy_string(cfg_paths.run_user, v->value, sizeof(cfg_paths.run_user));
03005
03006 } else if (!strcasecmp(v->name, "rungroup")) {
03007 ast_copy_string(cfg_paths.run_group, v->value, sizeof(cfg_paths.run_group));
03008 } else if (!strcasecmp(v->name, "systemname")) {
03009 ast_copy_string(cfg_paths.system_name, v->value, sizeof(cfg_paths.system_name));
03010 } else if (!strcasecmp(v->name, "autosystemname")) {
03011 if (ast_true(v->value)) {
03012 if (!gethostname(hostname, sizeof(hostname) - 1))
03013 ast_copy_string(cfg_paths.system_name, hostname, sizeof(cfg_paths.system_name));
03014 else {
03015 if (ast_strlen_zero(ast_config_AST_SYSTEM_NAME)){
03016 ast_copy_string(cfg_paths.system_name, "localhost", sizeof(cfg_paths.system_name));
03017 }
03018 ast_log(LOG_ERROR, "Cannot obtain hostname for this system. Using '%s' instead.\n", ast_config_AST_SYSTEM_NAME);
03019 }
03020 }
03021 } else if (!strcasecmp(v->name, "languageprefix")) {
03022 ast_language_is_prefix = ast_true(v->value);
03023 } else if (!strcasecmp(v->name, "lockmode")) {
03024 if (!strcasecmp(v->value, "lockfile")) {
03025 ast_set_lock_type(AST_LOCK_TYPE_LOCKFILE);
03026 } else if (!strcasecmp(v->value, "flock")) {
03027 ast_set_lock_type(AST_LOCK_TYPE_FLOCK);
03028 } else {
03029 ast_log(LOG_WARNING, "'%s' is not a valid setting for the lockmode option, "
03030 "defaulting to 'lockfile'\n", v->value);
03031 ast_set_lock_type(AST_LOCK_TYPE_LOCKFILE);
03032 }
03033 #if defined(HAVE_SYSINFO)
03034 } else if (!strcasecmp(v->name, "minmemfree")) {
03035
03036
03037 if ((sscanf(v->value, "%30ld", &option_minmemfree) != 1) || (option_minmemfree < 0)) {
03038 option_minmemfree = 0;
03039 }
03040 #endif
03041 } else if (!strcasecmp(v->name, "entityid")) {
03042 struct ast_eid tmp_eid;
03043 if (!ast_str_to_eid(&tmp_eid, v->value)) {
03044 ast_verbose("Successfully set global EID to '%s'\n", v->value);
03045 ast_eid_default = tmp_eid;
03046 } else
03047 ast_verbose("Invalid Entity ID '%s' provided\n", v->value);
03048 } else if (!strcasecmp(v->name, "lightbackground")) {
03049 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_LIGHT_BACKGROUND);
03050 } else if (!strcasecmp(v->name, "forceblackbackground")) {
03051 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_FORCE_BLACK_BACKGROUND);
03052 } else if (!strcasecmp(v->name, "hideconnect")) {
03053 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_HIDE_CONSOLE_CONNECT);
03054 } else if (!strcasecmp(v->name, "lockconfdir")) {
03055 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_LOCK_CONFIG_DIR);
03056 }
03057 }
03058 for (v = ast_variable_browse(cfg, "compat"); v; v = v->next) {
03059 float version;
03060 if (sscanf(v->value, "%30f", &version) != 1) {
03061 ast_log(LOG_WARNING, "Compatibility version for option '%s' is not a number: '%s'\n", v->name, v->value);
03062 continue;
03063 }
03064 if (!strcasecmp(v->name, "app_set")) {
03065 ast_set2_flag(&ast_compat, version < 1.5 ? 1 : 0, AST_COMPAT_APP_SET);
03066 } else if (!strcasecmp(v->name, "res_agi")) {
03067 ast_set2_flag(&ast_compat, version < 1.5 ? 1 : 0, AST_COMPAT_DELIM_RES_AGI);
03068 } else if (!strcasecmp(v->name, "pbx_realtime")) {
03069 ast_set2_flag(&ast_compat, version < 1.5 ? 1 : 0, AST_COMPAT_DELIM_PBX_REALTIME);
03070 }
03071 }
03072 ast_config_destroy(cfg);
03073 }
03074
03075 static void *monitor_sig_flags(void *unused)
03076 {
03077 for (;;) {
03078 struct pollfd p = { sig_alert_pipe[0], POLLIN, 0 };
03079 int a;
03080 ast_poll(&p, 1, -1);
03081 if (sig_flags.need_reload) {
03082 sig_flags.need_reload = 0;
03083 ast_module_reload(NULL);
03084 }
03085 if (sig_flags.need_quit) {
03086 sig_flags.need_quit = 0;
03087 quit_handler(0, 0, 1, 0);
03088 }
03089 if (read(sig_alert_pipe[0], &a, sizeof(a)) != sizeof(a)) {
03090 }
03091 }
03092
03093 return NULL;
03094 }
03095
03096 static void *canary_thread(void *unused)
03097 {
03098 struct stat canary_stat;
03099 struct timeval now;
03100
03101
03102 sleep(120);
03103
03104 for (;;) {
03105 stat(canary_filename, &canary_stat);
03106 now = ast_tvnow();
03107 if (now.tv_sec > canary_stat.st_mtime + 60) {
03108 ast_log(LOG_WARNING, "The canary is no more. He has ceased to be! He's expired and gone to meet his maker! He's a stiff! Bereft of life, he rests in peace. His metabolic processes are now history! He's off the twig! He's kicked the bucket. He's shuffled off his mortal coil, run down the curtain, and joined the bleeding choir invisible!! THIS is an EX-CANARY. (Reducing priority)\n");
03109 ast_set_priority(0);
03110 pthread_exit(NULL);
03111 }
03112
03113
03114 sleep(60);
03115 }
03116 }
03117
03118
03119 static void canary_exit(void)
03120 {
03121 if (canary_pid > 0)
03122 kill(canary_pid, SIGKILL);
03123 }
03124
03125 static void run_startup_commands(void)
03126 {
03127 int fd;
03128 struct ast_config *cfg;
03129 struct ast_flags cfg_flags = { 0 };
03130 struct ast_variable *v;
03131
03132 if (!(cfg = ast_config_load2("cli.conf", "" , cfg_flags)))
03133 return;
03134 if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) {
03135 return;
03136 }
03137
03138 fd = open("/dev/null", O_RDWR);
03139 if (fd < 0) {
03140 ast_config_destroy(cfg);
03141 return;
03142 }
03143
03144 for (v = ast_variable_browse(cfg, "startup_commands"); v; v = v->next) {
03145 if (ast_true(v->value))
03146 ast_cli_command(fd, v->name);
03147 }
03148
03149 close(fd);
03150 ast_config_destroy(cfg);
03151 }
03152
03153 static void env_init(void)
03154 {
03155 setenv("AST_SYSTEMNAME", ast_config_AST_SYSTEM_NAME, 1);
03156 setenv("AST_BUILD_HOST", ast_build_hostname, 1);
03157 setenv("AST_BUILD_DATE", ast_build_date, 1);
03158 setenv("AST_BUILD_KERNEL", ast_build_kernel, 1);
03159 setenv("AST_BUILD_MACHINE", ast_build_machine, 1);
03160 setenv("AST_BUILD_OS", ast_build_os, 1);
03161 setenv("AST_BUILD_USER", ast_build_user, 1);
03162 setenv("AST_VERSION", ast_get_version(), 1);
03163 }
03164
03165 int main(int argc, char *argv[])
03166 {
03167 int c;
03168 char filename[80] = "";
03169 char hostname[MAXHOSTNAMELEN] = "";
03170 char tmp[80];
03171 char * xarg = NULL;
03172 int x;
03173 FILE *f;
03174 sigset_t sigs;
03175 int num;
03176 int isroot = 1, rundir_exists = 0;
03177 char *buf;
03178 const char *runuser = NULL, *rungroup = NULL;
03179 char *remotesock = NULL;
03180 int moduleresult;
03181 struct rlimit l;
03182
03183
03184 if (argc > ARRAY_LEN(_argv) - 1) {
03185 fprintf(stderr, "Truncating argument size to %d\n", (int)ARRAY_LEN(_argv) - 1);
03186 argc = ARRAY_LEN(_argv) - 1;
03187 }
03188 for (x = 0; x < argc; x++)
03189 _argv[x] = argv[x];
03190 _argv[x] = NULL;
03191
03192 if (geteuid() != 0)
03193 isroot = 0;
03194
03195
03196 if (argv[0] && (strstr(argv[0], "rasterisk")) != NULL) {
03197 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE);
03198 }
03199 if (gethostname(hostname, sizeof(hostname)-1))
03200 ast_copy_string(hostname, "<Unknown>", sizeof(hostname));
03201 ast_mainpid = getpid();
03202 ast_ulaw_init();
03203 ast_alaw_init();
03204 callerid_init();
03205 ast_builtins_init();
03206 ast_utils_init();
03207 tdd_init();
03208 ast_tps_init();
03209 ast_fd_init();
03210 ast_pbx_init();
03211
03212 if (getenv("HOME"))
03213 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
03214
03215 while ((c = getopt(argc, argv, "BC:cde:FfG:ghIiL:M:mnpqRrs:TtU:VvWXx:")) != -1) {
03216
03217
03218
03219 switch (c) {
03220 case 'B':
03221 ast_set_flag(&ast_options, AST_OPT_FLAG_FORCE_BLACK_BACKGROUND);
03222 ast_clear_flag(&ast_options, AST_OPT_FLAG_LIGHT_BACKGROUND);
03223 break;
03224 case 'X':
03225 ast_set_flag(&ast_options, AST_OPT_FLAG_EXEC_INCLUDES);
03226 break;
03227 case 'C':
03228 ast_copy_string(cfg_paths.config_file, optarg, sizeof(cfg_paths.config_file));
03229 ast_set_flag(&ast_options, AST_OPT_FLAG_OVERRIDE_CONFIG);
03230 break;
03231 case 'c':
03232 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_CONSOLE);
03233 break;
03234 case 'd':
03235 option_debug++;
03236 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);
03237 break;
03238 #if defined(HAVE_SYSINFO)
03239 case 'e':
03240 if ((sscanf(&optarg[1], "%30ld", &option_minmemfree) != 1) || (option_minmemfree < 0)) {
03241 option_minmemfree = 0;
03242 }
03243 break;
03244 #endif
03245 #if HAVE_WORKING_FORK
03246 case 'F':
03247 ast_set_flag(&ast_options, AST_OPT_FLAG_ALWAYS_FORK);
03248 break;
03249 case 'f':
03250 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);
03251 break;
03252 #endif
03253 case 'G':
03254 rungroup = ast_strdupa(optarg);
03255 break;
03256 case 'g':
03257 ast_set_flag(&ast_options, AST_OPT_FLAG_DUMP_CORE);
03258 break;
03259 case 'h':
03260 show_cli_help();
03261 exit(0);
03262 case 'I':
03263 ast_set_flag(&ast_options, AST_OPT_FLAG_INTERNAL_TIMING);
03264 break;
03265 case 'i':
03266 ast_set_flag(&ast_options, AST_OPT_FLAG_INIT_KEYS);
03267 break;
03268 case 'L':
03269 if ((sscanf(optarg, "%30lf", &option_maxload) != 1) || (option_maxload < 0.0)) {
03270 option_maxload = 0.0;
03271 }
03272 break;
03273 case 'M':
03274 if ((sscanf(optarg, "%30d", &option_maxcalls) != 1) || (option_maxcalls < 0)) {
03275 option_maxcalls = 0;
03276 }
03277 break;
03278 case 'm':
03279 ast_set_flag(&ast_options, AST_OPT_FLAG_MUTE);
03280 break;
03281 case 'n':
03282 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_COLOR);
03283 break;
03284 case 'p':
03285 ast_set_flag(&ast_options, AST_OPT_FLAG_HIGH_PRIORITY);
03286 break;
03287 case 'q':
03288 ast_set_flag(&ast_options, AST_OPT_FLAG_QUIET);
03289 break;
03290 case 'R':
03291 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE | AST_OPT_FLAG_RECONNECT);
03292 break;
03293 case 'r':
03294 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE);
03295 break;
03296 case 's':
03297 remotesock = ast_strdupa(optarg);
03298 break;
03299 case 'T':
03300 ast_set_flag(&ast_options, AST_OPT_FLAG_TIMESTAMP);
03301 break;
03302 case 't':
03303 ast_set_flag(&ast_options, AST_OPT_FLAG_CACHE_RECORD_FILES);
03304 break;
03305 case 'U':
03306 runuser = ast_strdupa(optarg);
03307 break;
03308 case 'V':
03309 show_version();
03310 exit(0);
03311 case 'v':
03312 option_verbose++;
03313 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);
03314 break;
03315 case 'W':
03316 ast_set_flag(&ast_options, AST_OPT_FLAG_LIGHT_BACKGROUND);
03317 ast_clear_flag(&ast_options, AST_OPT_FLAG_FORCE_BLACK_BACKGROUND);
03318 break;
03319 case 'x':
03320 ast_set_flag(&ast_options, AST_OPT_FLAG_EXEC);
03321 xarg = ast_strdupa(optarg);
03322 break;
03323 case '?':
03324 exit(1);
03325 }
03326 }
03327
03328 if (ast_opt_console || option_verbose || (ast_opt_remote && !ast_opt_exec)) {
03329 if (ast_register_verbose(console_verboser)) {
03330 ast_log(LOG_WARNING, "Unable to register console verboser?\n");
03331 }
03332 WELCOME_MESSAGE;
03333 }
03334
03335 if (ast_opt_console && !option_verbose)
03336 ast_verbose("[ Booting...\n");
03337
03338
03339
03340
03341 if (ast_opt_remote) {
03342 strcpy(argv[0], "rasterisk");
03343 for (x = 1; x < argc; x++) {
03344 argv[x] = argv[0] + 10;
03345 }
03346 }
03347
03348 if (ast_opt_console && !option_verbose) {
03349 ast_verbose("[ Reading Master Configuration ]\n");
03350 }
03351
03352 ast_readconfig();
03353 env_init();
03354
03355 if (ast_opt_remote && remotesock != NULL)
03356 ast_copy_string((char *) cfg_paths.socket_path, remotesock, sizeof(cfg_paths.socket_path));
03357
03358 if (!ast_language_is_prefix && !ast_opt_remote)
03359 ast_log(LOG_WARNING, "The 'languageprefix' option in asterisk.conf is deprecated; in a future release it will be removed, and your sound files will need to be organized in the 'new style' language layout.\n");
03360
03361 if (ast_opt_always_fork && (ast_opt_remote || ast_opt_console)) {
03362 ast_log(LOG_WARNING, "'alwaysfork' is not compatible with console or remote console mode; ignored\n");
03363 ast_clear_flag(&ast_options, AST_OPT_FLAG_ALWAYS_FORK);
03364 }
03365
03366 if (ast_opt_dump_core) {
03367 memset(&l, 0, sizeof(l));
03368 l.rlim_cur = RLIM_INFINITY;
03369 l.rlim_max = RLIM_INFINITY;
03370 if (setrlimit(RLIMIT_CORE, &l)) {
03371 ast_log(LOG_WARNING, "Unable to disable core size resource limit: %s\n", strerror(errno));
03372 }
03373 }
03374
03375 if (getrlimit(RLIMIT_NOFILE, &l)) {
03376 ast_log(LOG_WARNING, "Unable to check file descriptor limit: %s\n", strerror(errno));
03377 }
03378
03379 #if !defined(CONFIGURE_RAN_AS_ROOT)
03380
03381 do {
03382 int fd, fd2;
03383 ast_fdset readers;
03384 struct timeval tv = { 0, };
03385
03386 if (l.rlim_cur <= FD_SETSIZE) {
03387
03388
03389 break;
03390 }
03391
03392 if (!(fd = open("/dev/null", O_RDONLY))) {
03393 ast_log(LOG_ERROR, "Cannot open a file descriptor at boot? %s\n", strerror(errno));
03394 break;
03395 }
03396
03397 fd2 = (l.rlim_cur > sizeof(readers) * 8 ? sizeof(readers) * 8 : l.rlim_cur) - 1;
03398 if (dup2(fd, fd2) < 0) {
03399 ast_log(LOG_WARNING, "Cannot open maximum file descriptor %d at boot? %s\n", fd2, strerror(errno));
03400 break;
03401 }
03402
03403 FD_ZERO(&readers);
03404 FD_SET(fd2, &readers);
03405 if (ast_select(fd2 + 1, &readers, NULL, NULL, &tv) < 0) {
03406 ast_log(LOG_WARNING, "Maximum select()able file descriptor is %d\n", FD_SETSIZE);
03407 }
03408 } while (0);
03409 #elif defined(HAVE_VARIABLE_FDSET)
03410 ast_FD_SETSIZE = l.rlim_cur;
03411 #endif
03412
03413 if ((!rungroup) && !ast_strlen_zero(ast_config_AST_RUN_GROUP))
03414 rungroup = ast_config_AST_RUN_GROUP;
03415 if ((!runuser) && !ast_strlen_zero(ast_config_AST_RUN_USER))
03416 runuser = ast_config_AST_RUN_USER;
03417
03418
03419
03420
03421 sigaction(SIGCHLD, &child_handler, NULL);
03422
03423
03424
03425 if (mkdir(ast_config_AST_RUN_DIR, 0755)) {
03426 if (errno == EEXIST) {
03427 rundir_exists = 1;
03428 } else {
03429 ast_log(LOG_WARNING, "Unable to create socket file directory. Remote consoles will not be able to connect! (%s)\n", strerror(x));
03430 }
03431 }
03432
03433 #ifndef __CYGWIN__
03434
03435 if (isroot) {
03436 ast_set_priority(ast_opt_high_priority);
03437 }
03438
03439 if (isroot && rungroup) {
03440 struct group *gr;
03441 gr = getgrnam(rungroup);
03442 if (!gr) {
03443 ast_log(LOG_WARNING, "No such group '%s'!\n", rungroup);
03444 exit(1);
03445 }
03446 if (!rundir_exists && chown(ast_config_AST_RUN_DIR, -1, gr->gr_gid)) {
03447 ast_log(LOG_WARNING, "Unable to chgrp run directory to %d (%s)\n", (int) gr->gr_gid, rungroup);
03448 }
03449 if (setgid(gr->gr_gid)) {
03450 ast_log(LOG_WARNING, "Unable to setgid to %d (%s)\n", (int)gr->gr_gid, rungroup);
03451 exit(1);
03452 }
03453 if (setgroups(0, NULL)) {
03454 ast_log(LOG_WARNING, "Unable to drop unneeded groups\n");
03455 exit(1);
03456 }
03457 if (option_verbose)
03458 ast_verbose("Running as group '%s'\n", rungroup);
03459 }
03460
03461 if (runuser && !ast_test_flag(&ast_options, AST_OPT_FLAG_REMOTE)) {
03462 #ifdef HAVE_CAP
03463 int has_cap = 1;
03464 #endif
03465 struct passwd *pw;
03466 pw = getpwnam(runuser);
03467 if (!pw) {
03468 ast_log(LOG_WARNING, "No such user '%s'!\n", runuser);
03469 exit(1);
03470 }
03471 if (chown(ast_config_AST_RUN_DIR, pw->pw_uid, -1)) {
03472 ast_log(LOG_WARNING, "Unable to chown run directory to %d (%s)\n", (int) pw->pw_uid, runuser);
03473 }
03474 #ifdef HAVE_CAP
03475 if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0)) {
03476 ast_log(LOG_WARNING, "Unable to keep capabilities.\n");
03477 has_cap = 0;
03478 }
03479 #endif
03480 if (!isroot && pw->pw_uid != geteuid()) {
03481 ast_log(LOG_ERROR, "Asterisk started as nonroot, but runuser '%s' requested.\n", runuser);
03482 exit(1);
03483 }
03484 if (!rungroup) {
03485 if (setgid(pw->pw_gid)) {
03486 ast_log(LOG_WARNING, "Unable to setgid to %d!\n", (int)pw->pw_gid);
03487 exit(1);
03488 }
03489 if (isroot && initgroups(pw->pw_name, pw->pw_gid)) {
03490 ast_log(LOG_WARNING, "Unable to init groups for '%s'\n", runuser);
03491 exit(1);
03492 }
03493 }
03494 if (setuid(pw->pw_uid)) {
03495 ast_log(LOG_WARNING, "Unable to setuid to %d (%s)\n", (int)pw->pw_uid, runuser);
03496 exit(1);
03497 }
03498 if (option_verbose)
03499 ast_verbose("Running as user '%s'\n", runuser);
03500 #ifdef HAVE_CAP
03501 if (has_cap) {
03502 cap_t cap;
03503
03504 cap = cap_from_text("cap_net_admin=eip");
03505
03506 if (cap_set_proc(cap))
03507 ast_log(LOG_WARNING, "Unable to install capabilities.\n");
03508
03509 if (cap_free(cap))
03510 ast_log(LOG_WARNING, "Unable to drop capabilities.\n");
03511 }
03512 #endif
03513 }
03514
03515 #endif
03516
03517 #ifdef linux
03518 if (geteuid() && ast_opt_dump_core) {
03519 if (prctl(PR_SET_DUMPABLE, 1, 0, 0, 0) < 0) {
03520 ast_log(LOG_WARNING, "Unable to set the process for core dumps after changing to a non-root user. %s\n", strerror(errno));
03521 }
03522 }
03523 #endif
03524
03525 {
03526 #if defined(HAVE_EACCESS) || defined(HAVE_EUIDACCESS)
03527 #if defined(HAVE_EUIDACCESS) && !defined(HAVE_EACCESS)
03528 #define eaccess euidaccess
03529 #endif
03530 char dir[PATH_MAX];
03531 if (!getcwd(dir, sizeof(dir)) || eaccess(dir, R_OK | X_OK | F_OK)) {
03532 ast_log(LOG_ERROR, "Unable to access the running directory (%s). Changing to '/' for compatibility.\n", strerror(errno));
03533
03534
03535 if (chdir("/")) {
03536
03537 ast_log(LOG_ERROR, "chdir(\"/\") failed?!! %s\n", strerror(errno));
03538 }
03539 } else
03540 #endif
03541 if (!ast_opt_no_fork && !ast_opt_dump_core) {
03542
03543 if (chdir("/")) {
03544 ast_log(LOG_ERROR, "Unable to chdir(\"/\") ?!! %s\n", strerror(errno));
03545 }
03546 }
03547 }
03548
03549 ast_term_init();
03550 printf("%s", term_end());
03551 fflush(stdout);
03552
03553 if (ast_opt_console && !option_verbose)
03554 ast_verbose("[ Initializing Custom Configuration Options ]\n");
03555
03556 register_config_cli();
03557 read_config_maps();
03558
03559 if (ast_opt_console) {
03560 if (el_hist == NULL || el == NULL)
03561 ast_el_initialize();
03562
03563 if (!ast_strlen_zero(filename))
03564 ast_el_read_history(filename);
03565 }
03566
03567 if (ast_tryconnect()) {
03568
03569 if (ast_opt_remote) {
03570 if (ast_opt_exec) {
03571 ast_remotecontrol(xarg);
03572 quit_handler(0, 0, 0, 0);
03573 exit(0);
03574 }
03575 printf("%s", term_quit());
03576 ast_remotecontrol(NULL);
03577 quit_handler(0, 0, 0, 0);
03578 exit(0);
03579 } else {
03580 ast_log(LOG_ERROR, "Asterisk already running on %s. Use 'asterisk -r' to connect.\n", ast_config_AST_SOCKET);
03581 printf("%s", term_quit());
03582 exit(1);
03583 }
03584 } else if (ast_opt_remote || ast_opt_exec) {
03585 ast_log(LOG_ERROR, "Unable to connect to remote asterisk (does %s exist?)\n", ast_config_AST_SOCKET);
03586 printf("%s", term_quit());
03587 exit(1);
03588 }
03589
03590 unlink(ast_config_AST_PID);
03591 f = fopen(ast_config_AST_PID, "w");
03592 if (f) {
03593 fprintf(f, "%ld\n", (long)getpid());
03594 fclose(f);
03595 } else
03596 ast_log(LOG_WARNING, "Unable to open pid file '%s': %s\n", ast_config_AST_PID, strerror(errno));
03597
03598 #if HAVE_WORKING_FORK
03599 if (ast_opt_always_fork || !ast_opt_no_fork) {
03600 #ifndef HAVE_SBIN_LAUNCHD
03601 if (daemon(1, 0) < 0) {
03602 ast_log(LOG_ERROR, "daemon() failed: %s\n", strerror(errno));
03603 }
03604 ast_mainpid = getpid();
03605
03606 unlink(ast_config_AST_PID);
03607 f = fopen(ast_config_AST_PID, "w");
03608 if (f) {
03609 fprintf(f, "%ld\n", (long)ast_mainpid);
03610 fclose(f);
03611 } else
03612 ast_log(LOG_WARNING, "Unable to open pid file '%s': %s\n", ast_config_AST_PID, strerror(errno));
03613 #else
03614 ast_log(LOG_WARNING, "Mac OS X detected. Use 'launchctl load /Library/LaunchDaemon/org.asterisk.asterisk.plist'.\n");
03615 #endif
03616 }
03617 #endif
03618
03619
03620 if (isroot && ast_opt_high_priority) {
03621 snprintf(canary_filename, sizeof(canary_filename), "%s/alt.asterisk.canary.tweet.tweet.tweet", ast_config_AST_RUN_DIR);
03622
03623
03624 sigaction(SIGPIPE, &ignore_sig_handler, NULL);
03625
03626 canary_pid = fork();
03627 if (canary_pid == 0) {
03628 char canary_binary[128], *lastslash, ppid[12];
03629
03630
03631 signal(SIGCHLD, SIG_DFL);
03632 signal(SIGPIPE, SIG_DFL);
03633
03634 ast_close_fds_above_n(0);
03635 ast_set_priority(0);
03636 snprintf(ppid, sizeof(ppid), "%d", (int) ast_mainpid);
03637
03638 execlp("astcanary", "astcanary", canary_filename, ppid, (char *)NULL);
03639
03640
03641 ast_copy_string(canary_binary, argv[0], sizeof(canary_binary));
03642 if ((lastslash = strrchr(canary_binary, '/'))) {
03643 ast_copy_string(lastslash + 1, "astcanary", sizeof(canary_binary) + canary_binary - (lastslash + 1));
03644 execl(canary_binary, "astcanary", canary_filename, (char *)NULL);
03645 }
03646
03647
03648 _exit(1);
03649 } else if (canary_pid > 0) {
03650 pthread_t dont_care;
03651 ast_pthread_create_detached(&dont_care, NULL, canary_thread, NULL);
03652 }
03653
03654
03655 ast_register_atexit(canary_exit);
03656 }
03657
03658 if (ast_event_init()) {
03659 printf("%s", term_quit());
03660 exit(1);
03661 }
03662
03663 #ifdef TEST_FRAMEWORK
03664 if (ast_test_init()) {
03665 printf("%s", term_quit());
03666 exit(1);
03667 }
03668 #endif
03669
03670 ast_aoc_cli_init();
03671
03672 ast_makesocket();
03673 sigemptyset(&sigs);
03674 sigaddset(&sigs, SIGHUP);
03675 sigaddset(&sigs, SIGTERM);
03676 sigaddset(&sigs, SIGINT);
03677 sigaddset(&sigs, SIGPIPE);
03678 sigaddset(&sigs, SIGWINCH);
03679 pthread_sigmask(SIG_BLOCK, &sigs, NULL);
03680 sigaction(SIGURG, &urg_handler, NULL);
03681 signal(SIGINT, __quit_handler);
03682 signal(SIGTERM, __quit_handler);
03683 sigaction(SIGHUP, &hup_handler, NULL);
03684 sigaction(SIGPIPE, &ignore_sig_handler, NULL);
03685
03686
03687
03688
03689 srand((unsigned int) getpid() + (unsigned int) time(NULL));
03690 initstate((unsigned int) getpid() * 65536 + (unsigned int) time(NULL), randompool, sizeof(randompool));
03691
03692 if (init_logger()) {
03693 printf("%s", term_quit());
03694 exit(1);
03695 }
03696
03697 threadstorage_init();
03698
03699 astobj2_init();
03700
03701 ast_autoservice_init();
03702
03703 if (ast_timing_init()) {
03704 printf("%s", term_quit());
03705 exit(1);
03706 }
03707
03708 if (ast_ssl_init()) {
03709 printf("%s", term_quit());
03710 exit(1);
03711 }
03712
03713 #ifdef AST_XML_DOCS
03714
03715 ast_xmldoc_load_documentation();
03716 #endif
03717
03718
03719 if (ast_data_init()) {
03720 printf ("%s", term_quit());
03721 exit(1);
03722 }
03723
03724 ast_channels_init();
03725
03726 if ((moduleresult = load_modules(1))) {
03727 printf("%s", term_quit());
03728 exit(moduleresult == -2 ? 2 : 1);
03729 }
03730
03731 if (dnsmgr_init()) {
03732 printf("%s", term_quit());
03733 exit(1);
03734 }
03735
03736 ast_http_init();
03737
03738 if (init_manager()) {
03739 printf("%s", term_quit());
03740 exit(1);
03741 }
03742
03743 if (ast_cdr_engine_init()) {
03744 printf("%s", term_quit());
03745 exit(1);
03746 }
03747
03748 if (ast_cel_engine_init()) {
03749 printf("%s", term_quit());
03750 exit(1);
03751 }
03752
03753 if (ast_device_state_engine_init()) {
03754 printf("%s", term_quit());
03755 exit(1);
03756 }
03757
03758 ast_dsp_init();
03759 ast_udptl_init();
03760
03761 if (ast_image_init()) {
03762 printf("%s", term_quit());
03763 exit(1);
03764 }
03765
03766 if (ast_file_init()) {
03767 printf("%s", term_quit());
03768 exit(1);
03769 }
03770
03771 if (load_pbx()) {
03772 printf("%s", term_quit());
03773 exit(1);
03774 }
03775
03776 if (ast_indications_init()) {
03777 printf("%s", term_quit());
03778 exit(1);
03779 }
03780
03781 ast_features_init();
03782
03783 if (init_framer()) {
03784 printf("%s", term_quit());
03785 exit(1);
03786 }
03787
03788 if (astdb_init()) {
03789 printf("%s", term_quit());
03790 exit(1);
03791 }
03792
03793 if (ast_enum_init()) {
03794 printf("%s", term_quit());
03795 exit(1);
03796 }
03797
03798 if (ast_cc_init()) {
03799 printf("%s", term_quit());
03800 exit(1);
03801 }
03802
03803 if ((moduleresult = load_modules(0))) {
03804 printf("%s", term_quit());
03805 exit(moduleresult == -2 ? 2 : 1);
03806 }
03807
03808
03809 ast_cli_perms_init(0);
03810
03811 ast_stun_init();
03812
03813 dnsmgr_start_refresh();
03814
03815
03816
03817 if (ast_opt_console && !option_verbose)
03818 ast_verbose(" ]\n");
03819 if (option_verbose || ast_opt_console)
03820 ast_verbose("%s", term_color(tmp, "Asterisk Ready.\n", COLOR_BRWHITE, COLOR_BLACK, sizeof(tmp)));
03821 if (ast_opt_no_fork)
03822 consolethread = pthread_self();
03823
03824 if (pipe(sig_alert_pipe))
03825 sig_alert_pipe[0] = sig_alert_pipe[1] = -1;
03826
03827 ast_set_flag(&ast_options, AST_OPT_FLAG_FULLY_BOOTED);
03828 manager_event(EVENT_FLAG_SYSTEM, "FullyBooted", "Status: Fully Booted\r\n");
03829
03830 ast_process_pending_reloads();
03831
03832 pthread_sigmask(SIG_UNBLOCK, &sigs, NULL);
03833
03834 #ifdef __AST_DEBUG_MALLOC
03835 __ast_mm_init();
03836 #endif
03837
03838 ast_lastreloadtime = ast_startuptime = ast_tvnow();
03839 ast_cli_register_multiple(cli_asterisk, ARRAY_LEN(cli_asterisk));
03840
03841 run_startup_commands();
03842
03843 if (ast_opt_console) {
03844
03845
03846 char title[256];
03847
03848 ast_pthread_create_detached(&mon_sig_flags, NULL, monitor_sig_flags, NULL);
03849
03850 set_icon("Asterisk");
03851 snprintf(title, sizeof(title), "Asterisk Console on '%s' (pid %ld)", hostname, (long)ast_mainpid);
03852 set_title(title);
03853
03854 for (;;) {
03855 buf = (char *) el_gets(el, &num);
03856
03857 if (!buf && write(1, "", 1) < 0)
03858 goto lostterm;
03859
03860 if (buf) {
03861 if (buf[strlen(buf)-1] == '\n')
03862 buf[strlen(buf)-1] = '\0';
03863
03864 consolehandler((char *)buf);
03865 } else if (ast_opt_remote && (write(STDOUT_FILENO, "\nUse EXIT or QUIT to exit the asterisk console\n",
03866 strlen("\nUse EXIT or QUIT to exit the asterisk console\n")) < 0)) {
03867
03868 int fd;
03869 fd = open("/dev/null", O_RDWR);
03870 if (fd > -1) {
03871 dup2(fd, STDOUT_FILENO);
03872 dup2(fd, STDIN_FILENO);
03873 } else
03874 ast_log(LOG_WARNING, "Failed to open /dev/null to recover from dead console. Bad things will happen!\n");
03875 break;
03876 }
03877 }
03878 }
03879
03880 monitor_sig_flags(NULL);
03881
03882 lostterm:
03883 return 0;
03884 }