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