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