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