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