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: 335716 $")
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 - 2011 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 unsigned int need_quit_handler:1;
00292 } sig_flags;
00293
00294 #if !defined(LOW_MEMORY)
00295 struct file_version {
00296 AST_RWLIST_ENTRY(file_version) list;
00297 const char *file;
00298 char *version;
00299 };
00300
00301 static AST_RWLIST_HEAD_STATIC(file_versions, file_version);
00302
00303 void ast_register_file_version(const char *file, const char *version)
00304 {
00305 struct file_version *new;
00306 char *work;
00307 size_t version_length;
00308
00309 work = ast_strdupa(version);
00310 work = ast_strip(ast_strip_quoted(work, "$", "$"));
00311 version_length = strlen(work) + 1;
00312
00313 if (!(new = ast_calloc(1, sizeof(*new) + version_length)))
00314 return;
00315
00316 new->file = file;
00317 new->version = (char *) new + sizeof(*new);
00318 memcpy(new->version, work, version_length);
00319 AST_RWLIST_WRLOCK(&file_versions);
00320 AST_RWLIST_INSERT_HEAD(&file_versions, new, list);
00321 AST_RWLIST_UNLOCK(&file_versions);
00322 }
00323
00324 void ast_unregister_file_version(const char *file)
00325 {
00326 struct file_version *find;
00327
00328 AST_RWLIST_WRLOCK(&file_versions);
00329 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&file_versions, find, list) {
00330 if (!strcasecmp(find->file, file)) {
00331 AST_RWLIST_REMOVE_CURRENT(list);
00332 break;
00333 }
00334 }
00335 AST_RWLIST_TRAVERSE_SAFE_END;
00336 AST_RWLIST_UNLOCK(&file_versions);
00337
00338 if (find)
00339 ast_free(find);
00340 }
00341
00342 char *ast_complete_source_filename(const char *partial, int n)
00343 {
00344 struct file_version *find;
00345 size_t len = strlen(partial);
00346 int count = 0;
00347 char *res = NULL;
00348
00349 AST_RWLIST_RDLOCK(&file_versions);
00350 AST_RWLIST_TRAVERSE(&file_versions, find, list) {
00351 if (!strncasecmp(find->file, partial, len) && ++count > n) {
00352 res = ast_strdup(find->file);
00353 break;
00354 }
00355 }
00356 AST_RWLIST_UNLOCK(&file_versions);
00357 return res;
00358 }
00359
00360
00361 const char *ast_file_version_find(const char *file)
00362 {
00363 struct file_version *iterator;
00364
00365 AST_RWLIST_WRLOCK(&file_versions);
00366 AST_RWLIST_TRAVERSE(&file_versions, iterator, list) {
00367 if (!strcasecmp(iterator->file, file))
00368 break;
00369 }
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 nprocs = 0;
00579 long uptime = 0;
00580 int totalswap = 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
01087
01088
01089 void ast_console_toggle_loglevel(int fd, int level, int state)
01090 {
01091 int x;
01092 for (x = 0;x < AST_MAX_CONNECTS; x++) {
01093 if (fd == consoles[x].fd) {
01094
01095
01096
01097
01098 consoles[x].levels[level] = state ? 0 : 1;
01099 return;
01100 }
01101 }
01102 }
01103
01104
01105
01106
01107 void ast_console_toggle_mute(int fd, int silent) {
01108 int x;
01109 for (x = 0;x < AST_MAX_CONNECTS; x++) {
01110 if (fd == consoles[x].fd) {
01111 if (consoles[x].mute) {
01112 consoles[x].mute = 0;
01113 if (!silent)
01114 ast_cli(fd, "Console is not muted anymore.\n");
01115 } else {
01116 consoles[x].mute = 1;
01117 if (!silent)
01118 ast_cli(fd, "Console is muted.\n");
01119 }
01120 return;
01121 }
01122 }
01123 ast_cli(fd, "Couldn't find remote console.\n");
01124 }
01125
01126
01127
01128
01129 static void ast_network_puts_mutable(const char *string, int level)
01130 {
01131 int x;
01132 for (x = 0;x < AST_MAX_CONNECTS; x++) {
01133 if (consoles[x].mute)
01134 continue;
01135 if (consoles[x].fd > -1) {
01136 if (!consoles[x].levels[level])
01137 fdprint(consoles[x].p[1], string);
01138 }
01139 }
01140 }
01141
01142
01143
01144
01145
01146 void ast_console_puts_mutable(const char *string, int level)
01147 {
01148 fputs(string, stdout);
01149 fflush(stdout);
01150 ast_network_puts_mutable(string, level);
01151 }
01152
01153
01154
01155
01156 static void ast_network_puts(const char *string)
01157 {
01158 int x;
01159 for (x = 0; x < AST_MAX_CONNECTS; x++) {
01160 if (consoles[x].fd > -1)
01161 fdprint(consoles[x].p[1], string);
01162 }
01163 }
01164
01165
01166
01167
01168
01169 void ast_console_puts(const char *string)
01170 {
01171 fputs(string, stdout);
01172 fflush(stdout);
01173 ast_network_puts(string);
01174 }
01175
01176 static void network_verboser(const char *s)
01177 {
01178 ast_network_puts_mutable(s, __LOG_VERBOSE);
01179 }
01180
01181 static pthread_t lthread;
01182
01183
01184
01185
01186
01187
01188
01189
01190
01191
01192
01193 static int read_credentials(int fd, char *buffer, size_t size, struct console *con)
01194 {
01195 #if defined(SO_PEERCRED)
01196 struct ucred cred;
01197 socklen_t len = sizeof(cred);
01198 #endif
01199 #if defined(HAVE_GETPEEREID)
01200 uid_t uid;
01201 gid_t gid;
01202 #else
01203 int uid, gid;
01204 #endif
01205 int result;
01206
01207 result = read(fd, buffer, size);
01208 if (result < 0) {
01209 return result;
01210 }
01211
01212 #if defined(SO_PEERCRED) && (defined(HAVE_STRUCT_UCRED_UID) || defined(HAVE_STRUCT_UCRED_CR_UID))
01213 if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cred, &len)) {
01214 return result;
01215 }
01216 #if defined(HAVE_STRUCT_UCRED_UID)
01217 uid = cred.uid;
01218 gid = cred.gid;
01219 #else
01220 uid = cred.cr_uid;
01221 gid = cred.cr_gid;
01222 #endif
01223
01224 #elif defined(HAVE_GETPEEREID)
01225 if (getpeereid(fd, &uid, &gid)) {
01226 return result;
01227 }
01228 #else
01229 return result;
01230 #endif
01231 con->uid = uid;
01232 con->gid = gid;
01233
01234 return result;
01235 }
01236
01237 static void *netconsole(void *vconsole)
01238 {
01239 struct console *con = vconsole;
01240 char hostname[MAXHOSTNAMELEN] = "";
01241 char tmp[512];
01242 int res;
01243 struct pollfd fds[2];
01244
01245 if (gethostname(hostname, sizeof(hostname)-1))
01246 ast_copy_string(hostname, "<Unknown>", sizeof(hostname));
01247 snprintf(tmp, sizeof(tmp), "%s/%ld/%s\n", hostname, (long)ast_mainpid, ast_get_version());
01248 fdprint(con->fd, tmp);
01249 for (;;) {
01250 fds[0].fd = con->fd;
01251 fds[0].events = POLLIN;
01252 fds[0].revents = 0;
01253 fds[1].fd = con->p[0];
01254 fds[1].events = POLLIN;
01255 fds[1].revents = 0;
01256
01257 res = ast_poll(fds, 2, -1);
01258 if (res < 0) {
01259 if (errno != EINTR)
01260 ast_log(LOG_WARNING, "poll returned < 0: %s\n", strerror(errno));
01261 continue;
01262 }
01263 if (fds[0].revents) {
01264 res = read_credentials(con->fd, tmp, sizeof(tmp) - 1, con);
01265 if (res < 1) {
01266 break;
01267 }
01268 tmp[res] = 0;
01269 if (strncmp(tmp, "cli quit after ", 15) == 0) {
01270 ast_cli_command_multiple_full(con->uid, con->gid, con->fd, res - 15, tmp + 15);
01271 break;
01272 }
01273 ast_cli_command_multiple_full(con->uid, con->gid, con->fd, res, tmp);
01274 }
01275 if (fds[1].revents) {
01276 res = read_credentials(con->p[0], tmp, sizeof(tmp), con);
01277 if (res < 1) {
01278 ast_log(LOG_ERROR, "read returned %d\n", res);
01279 break;
01280 }
01281 res = write(con->fd, tmp, res);
01282 if (res < 1)
01283 break;
01284 }
01285 }
01286 if (!ast_opt_hide_connect) {
01287 ast_verb(3, "Remote UNIX connection disconnected\n");
01288 }
01289 close(con->fd);
01290 close(con->p[0]);
01291 close(con->p[1]);
01292 con->fd = -1;
01293
01294 return NULL;
01295 }
01296
01297 static void *listener(void *unused)
01298 {
01299 struct sockaddr_un sunaddr;
01300 int s;
01301 socklen_t len;
01302 int x;
01303 int flags;
01304 struct pollfd fds[1];
01305 for (;;) {
01306 if (ast_socket < 0)
01307 return NULL;
01308 fds[0].fd = ast_socket;
01309 fds[0].events = POLLIN;
01310 s = ast_poll(fds, 1, -1);
01311 pthread_testcancel();
01312 if (s < 0) {
01313 if (errno != EINTR)
01314 ast_log(LOG_WARNING, "poll returned error: %s\n", strerror(errno));
01315 continue;
01316 }
01317 len = sizeof(sunaddr);
01318 s = accept(ast_socket, (struct sockaddr *)&sunaddr, &len);
01319 if (s < 0) {
01320 if (errno != EINTR)
01321 ast_log(LOG_WARNING, "Accept returned %d: %s\n", s, strerror(errno));
01322 } else {
01323 #if !defined(SO_PASSCRED)
01324 {
01325 #else
01326 int sckopt = 1;
01327
01328 if (setsockopt(s, SOL_SOCKET, SO_PASSCRED, &sckopt, sizeof(sckopt)) < 0) {
01329 ast_log(LOG_WARNING, "Unable to turn on socket credentials passing\n");
01330 } else {
01331 #endif
01332 for (x = 0; x < AST_MAX_CONNECTS; x++) {
01333 if (consoles[x].fd >= 0) {
01334 continue;
01335 }
01336 if (socketpair(AF_LOCAL, SOCK_STREAM, 0, consoles[x].p)) {
01337 ast_log(LOG_ERROR, "Unable to create pipe: %s\n", strerror(errno));
01338 consoles[x].fd = -1;
01339 fdprint(s, "Server failed to create pipe\n");
01340 close(s);
01341 break;
01342 }
01343 flags = fcntl(consoles[x].p[1], F_GETFL);
01344 fcntl(consoles[x].p[1], F_SETFL, flags | O_NONBLOCK);
01345 consoles[x].fd = s;
01346 consoles[x].mute = 1;
01347
01348
01349 consoles[x].uid = -2;
01350 consoles[x].gid = -2;
01351 if (ast_pthread_create_detached_background(&consoles[x].t, NULL, netconsole, &consoles[x])) {
01352 ast_log(LOG_ERROR, "Unable to spawn thread to handle connection: %s\n", strerror(errno));
01353 close(consoles[x].p[0]);
01354 close(consoles[x].p[1]);
01355 consoles[x].fd = -1;
01356 fdprint(s, "Server failed to spawn thread\n");
01357 close(s);
01358 }
01359 break;
01360 }
01361 if (x >= AST_MAX_CONNECTS) {
01362 fdprint(s, "No more connections allowed\n");
01363 ast_log(LOG_WARNING, "No more connections allowed\n");
01364 close(s);
01365 } else if ((consoles[x].fd > -1) && (!ast_opt_hide_connect)) {
01366 ast_verb(3, "Remote UNIX connection\n");
01367 }
01368 }
01369 }
01370 }
01371 return NULL;
01372 }
01373
01374 static int ast_makesocket(void)
01375 {
01376 struct sockaddr_un sunaddr;
01377 int res;
01378 int x;
01379 uid_t uid = -1;
01380 gid_t gid = -1;
01381
01382 for (x = 0; x < AST_MAX_CONNECTS; x++)
01383 consoles[x].fd = -1;
01384 unlink(ast_config_AST_SOCKET);
01385 ast_socket = socket(PF_LOCAL, SOCK_STREAM, 0);
01386 if (ast_socket < 0) {
01387 ast_log(LOG_WARNING, "Unable to create control socket: %s\n", strerror(errno));
01388 return -1;
01389 }
01390 memset(&sunaddr, 0, sizeof(sunaddr));
01391 sunaddr.sun_family = AF_LOCAL;
01392 ast_copy_string(sunaddr.sun_path, ast_config_AST_SOCKET, sizeof(sunaddr.sun_path));
01393 res = bind(ast_socket, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
01394 if (res) {
01395 ast_log(LOG_WARNING, "Unable to bind socket to %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
01396 close(ast_socket);
01397 ast_socket = -1;
01398 return -1;
01399 }
01400 res = listen(ast_socket, 2);
01401 if (res < 0) {
01402 ast_log(LOG_WARNING, "Unable to listen on socket %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
01403 close(ast_socket);
01404 ast_socket = -1;
01405 return -1;
01406 }
01407 if (ast_register_verbose(network_verboser)) {
01408 ast_log(LOG_WARNING, "Unable to register network verboser?\n");
01409 }
01410
01411 ast_pthread_create_background(<hread, NULL, listener, NULL);
01412
01413 if (!ast_strlen_zero(ast_config_AST_CTL_OWNER)) {
01414 struct passwd *pw;
01415 if ((pw = getpwnam(ast_config_AST_CTL_OWNER)) == NULL)
01416 ast_log(LOG_WARNING, "Unable to find uid of user %s\n", ast_config_AST_CTL_OWNER);
01417 else
01418 uid = pw->pw_uid;
01419 }
01420
01421 if (!ast_strlen_zero(ast_config_AST_CTL_GROUP)) {
01422 struct group *grp;
01423 if ((grp = getgrnam(ast_config_AST_CTL_GROUP)) == NULL)
01424 ast_log(LOG_WARNING, "Unable to find gid of group %s\n", ast_config_AST_CTL_GROUP);
01425 else
01426 gid = grp->gr_gid;
01427 }
01428
01429 if (chown(ast_config_AST_SOCKET, uid, gid) < 0)
01430 ast_log(LOG_WARNING, "Unable to change ownership of %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
01431
01432 if (!ast_strlen_zero(ast_config_AST_CTL_PERMISSIONS)) {
01433 int p1;
01434 mode_t p;
01435 sscanf(ast_config_AST_CTL_PERMISSIONS, "%30o", &p1);
01436 p = p1;
01437 if ((chmod(ast_config_AST_SOCKET, p)) < 0)
01438 ast_log(LOG_WARNING, "Unable to change file permissions of %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
01439 }
01440
01441 return 0;
01442 }
01443
01444 static int ast_tryconnect(void)
01445 {
01446 struct sockaddr_un sunaddr;
01447 int res;
01448 ast_consock = socket(PF_LOCAL, SOCK_STREAM, 0);
01449 if (ast_consock < 0) {
01450 ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno));
01451 return 0;
01452 }
01453 memset(&sunaddr, 0, sizeof(sunaddr));
01454 sunaddr.sun_family = AF_LOCAL;
01455 ast_copy_string(sunaddr.sun_path, ast_config_AST_SOCKET, sizeof(sunaddr.sun_path));
01456 res = connect(ast_consock, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
01457 if (res) {
01458 close(ast_consock);
01459 ast_consock = -1;
01460 return 0;
01461 } else
01462 return 1;
01463 }
01464
01465
01466
01467
01468
01469
01470
01471 static void _urg_handler(int num)
01472 {
01473 return;
01474 }
01475
01476 static struct sigaction urg_handler = {
01477 .sa_handler = _urg_handler,
01478 .sa_flags = SA_RESTART,
01479 };
01480
01481 static void _hup_handler(int num)
01482 {
01483 int a = 0, save_errno = errno;
01484 if (option_verbose > 1)
01485 printf("Received HUP signal -- Reloading configs\n");
01486 if (restartnow)
01487 execvp(_argv[0], _argv);
01488 sig_flags.need_reload = 1;
01489 if (sig_alert_pipe[1] != -1) {
01490 if (write(sig_alert_pipe[1], &a, sizeof(a)) < 0) {
01491 fprintf(stderr, "hup_handler: write() failed: %s\n", strerror(errno));
01492 }
01493 }
01494 errno = save_errno;
01495 }
01496
01497 static struct sigaction hup_handler = {
01498 .sa_handler = _hup_handler,
01499 .sa_flags = SA_RESTART,
01500 };
01501
01502 static void _child_handler(int sig)
01503 {
01504
01505 int n, status, save_errno = errno;
01506
01507
01508
01509
01510 for (n = 0; wait4(-1, &status, WNOHANG, NULL) > 0; n++)
01511 ;
01512 if (n == 0 && option_debug)
01513 printf("Huh? Child handler, but nobody there?\n");
01514 errno = save_errno;
01515 }
01516
01517 static struct sigaction child_handler = {
01518 .sa_handler = _child_handler,
01519 .sa_flags = SA_RESTART,
01520 };
01521
01522
01523 static void set_ulimit(int value)
01524 {
01525 struct rlimit l = {0, 0};
01526
01527 if (value <= 0) {
01528 ast_log(LOG_WARNING, "Unable to change max files open to invalid value %i\n",value);
01529 return;
01530 }
01531
01532 l.rlim_cur = value;
01533 l.rlim_max = value;
01534
01535 if (setrlimit(RLIMIT_NOFILE, &l)) {
01536 ast_log(LOG_WARNING, "Unable to disable core size resource limit: %s\n",strerror(errno));
01537 return;
01538 }
01539
01540 ast_log(LOG_NOTICE, "Setting max files open to %d\n",value);
01541
01542 return;
01543 }
01544
01545
01546 static void set_title(char *text)
01547 {
01548 if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
01549 fprintf(stdout, "\033]2;%s\007", text);
01550 }
01551
01552 static void set_icon(char *text)
01553 {
01554 if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
01555 fprintf(stdout, "\033]1;%s\007", text);
01556 }
01557
01558
01559
01560 int ast_set_priority(int pri)
01561 {
01562 struct sched_param sched;
01563 memset(&sched, 0, sizeof(sched));
01564 #ifdef __linux__
01565 if (pri) {
01566 sched.sched_priority = 10;
01567 if (sched_setscheduler(0, SCHED_RR, &sched)) {
01568 ast_log(LOG_WARNING, "Unable to set high priority\n");
01569 return -1;
01570 } else
01571 if (option_verbose)
01572 ast_verbose("Set to realtime thread\n");
01573 } else {
01574 sched.sched_priority = 0;
01575
01576 sched_setscheduler(0, SCHED_OTHER, &sched);
01577 }
01578 #else
01579 if (pri) {
01580 if (setpriority(PRIO_PROCESS, 0, -10) == -1) {
01581 ast_log(LOG_WARNING, "Unable to set high priority\n");
01582 return -1;
01583 } else
01584 if (option_verbose)
01585 ast_verbose("Set to high priority\n");
01586 } else {
01587
01588 setpriority(PRIO_PROCESS, 0, 0);
01589 }
01590 #endif
01591 return 0;
01592 }
01593
01594 static void ast_run_atexits(void)
01595 {
01596 struct ast_atexit *ae;
01597 AST_RWLIST_RDLOCK(&atexits);
01598 AST_RWLIST_TRAVERSE(&atexits, ae, list) {
01599 if (ae->func)
01600 ae->func();
01601 }
01602 AST_RWLIST_UNLOCK(&atexits);
01603 }
01604
01605 static void quit_handler(int num, int niceness, int safeshutdown, int restart)
01606 {
01607 char filename[80] = "";
01608 time_t s,e;
01609 int x;
01610
01611 ast_cdr_engine_term();
01612 if (safeshutdown) {
01613 shuttingdown = 1;
01614 if (!niceness) {
01615
01616 ast_begin_shutdown(1);
01617 if (option_verbose && ast_opt_console)
01618 ast_verbose("Beginning asterisk %s....\n", restart ? "restart" : "shutdown");
01619 time(&s);
01620 for (;;) {
01621 time(&e);
01622
01623 if ((e - s) > 15)
01624 break;
01625 if (!ast_active_channels())
01626 break;
01627 if (!shuttingdown)
01628 break;
01629
01630 usleep(100000);
01631 }
01632 } else {
01633 if (niceness < 2)
01634 ast_begin_shutdown(0);
01635 if (option_verbose && ast_opt_console)
01636 ast_verbose("Waiting for inactivity to perform %s...\n", restart ? "restart" : "halt");
01637 for (;;) {
01638 if (!ast_active_channels())
01639 break;
01640 if (!shuttingdown)
01641 break;
01642 sleep(1);
01643 }
01644 }
01645
01646 if (!shuttingdown) {
01647 if (option_verbose && ast_opt_console)
01648 ast_verbose("Asterisk %s cancelled.\n", restart ? "restart" : "shutdown");
01649 return;
01650 }
01651
01652 if (niceness)
01653 ast_module_shutdown();
01654 }
01655 if (ast_opt_console || (ast_opt_remote && !ast_opt_exec)) {
01656 if (getenv("HOME")) {
01657 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
01658 }
01659 if (!ast_strlen_zero(filename)) {
01660 ast_el_write_history(filename);
01661 }
01662 if (consolethread == AST_PTHREADT_NULL || consolethread == pthread_self()) {
01663
01664 if (el != NULL) {
01665 el_end(el);
01666 }
01667 if (el_hist != NULL) {
01668 history_end(el_hist);
01669 }
01670 } else if (mon_sig_flags == pthread_self()) {
01671 if (consolethread != AST_PTHREADT_NULL) {
01672 pthread_kill(consolethread, SIGURG);
01673 }
01674 }
01675 }
01676 if (option_verbose)
01677 ast_verbose("Executing last minute cleanups\n");
01678 ast_run_atexits();
01679
01680 if (option_verbose && ast_opt_console)
01681 ast_verbose("Asterisk %s ending (%d).\n", ast_active_channels() ? "uncleanly" : "cleanly", num);
01682 ast_debug(1, "Asterisk ending (%d).\n", num);
01683 manager_event(EVENT_FLAG_SYSTEM, "Shutdown", "Shutdown: %s\r\nRestart: %s\r\n", ast_active_channels() ? "Uncleanly" : "Cleanly", restart ? "True" : "False");
01684 if (ast_socket > -1) {
01685 pthread_cancel(lthread);
01686 close(ast_socket);
01687 ast_socket = -1;
01688 unlink(ast_config_AST_SOCKET);
01689 }
01690 if (ast_consock > -1)
01691 close(ast_consock);
01692 if (!ast_opt_remote)
01693 unlink(ast_config_AST_PID);
01694 printf("%s", term_quit());
01695 if (restart) {
01696 if (option_verbose || ast_opt_console)
01697 ast_verbose("Preparing for Asterisk restart...\n");
01698
01699 for (x=3; x < 32768; x++) {
01700 fcntl(x, F_SETFD, FD_CLOEXEC);
01701 }
01702 if (option_verbose || ast_opt_console)
01703 ast_verbose("Asterisk is now restarting...\n");
01704 restartnow = 1;
01705
01706
01707 close_logger();
01708
01709
01710
01711 if ((consolethread != AST_PTHREADT_NULL) && (consolethread != pthread_self())) {
01712 pthread_kill(consolethread, SIGHUP);
01713
01714 sleep(2);
01715 } else
01716 execvp(_argv[0], _argv);
01717
01718 } else {
01719
01720 close_logger();
01721 }
01722 exit(0);
01723 }
01724
01725 static void __quit_handler(int num)
01726 {
01727 int a = 0;
01728 sig_flags.need_quit = 1;
01729 if (sig_alert_pipe[1] != -1) {
01730 if (write(sig_alert_pipe[1], &a, sizeof(a)) < 0) {
01731 fprintf(stderr, "quit_handler: write() failed: %s\n", strerror(errno));
01732 }
01733 }
01734
01735
01736 }
01737
01738 static void __remote_quit_handler(int num)
01739 {
01740 sig_flags.need_quit = 1;
01741 }
01742
01743 static const char *fix_header(char *outbuf, int maxout, const char *s, char *cmp)
01744 {
01745 const char *c;
01746
01747
01748 if (*s == 127) {
01749 s++;
01750 }
01751
01752 if (!strncmp(s, cmp, strlen(cmp))) {
01753 c = s + strlen(cmp);
01754 term_color(outbuf, cmp, COLOR_GRAY, 0, maxout);
01755 return c;
01756 }
01757 return NULL;
01758 }
01759
01760 static void console_verboser(const char *s)
01761 {
01762 char tmp[80];
01763 const char *c = NULL;
01764
01765 if ((c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_4)) ||
01766 (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_3)) ||
01767 (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_2)) ||
01768 (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_1))) {
01769 fputs(tmp, stdout);
01770 fputs(c, stdout);
01771 } else {
01772 if (*s == 127) {
01773 s++;
01774 }
01775 fputs(s, stdout);
01776 }
01777
01778 fflush(stdout);
01779
01780
01781 if (ast_opt_console && consolethread != AST_PTHREADT_NULL)
01782 pthread_kill(consolethread, SIGURG);
01783 }
01784
01785 static int ast_all_zeros(char *s)
01786 {
01787 while (*s) {
01788 if (*s > 32)
01789 return 0;
01790 s++;
01791 }
01792 return 1;
01793 }
01794
01795 static void consolehandler(char *s)
01796 {
01797 printf("%s", term_end());
01798 fflush(stdout);
01799
01800
01801 if (!ast_all_zeros(s))
01802 ast_el_add_history(s);
01803
01804 if (s[0] == '!') {
01805 if (s[1])
01806 ast_safe_system(s+1);
01807 else
01808 ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
01809 } else
01810 ast_cli_command(STDOUT_FILENO, s);
01811 }
01812
01813 static int remoteconsolehandler(char *s)
01814 {
01815 int ret = 0;
01816
01817
01818 if (!ast_all_zeros(s))
01819 ast_el_add_history(s);
01820
01821 if (s[0] == '!') {
01822 if (s[1])
01823 ast_safe_system(s+1);
01824 else
01825 ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
01826 ret = 1;
01827 }
01828 if ((strncasecmp(s, "quit", 4) == 0 || strncasecmp(s, "exit", 4) == 0) &&
01829 (s[4] == '\0' || isspace(s[4]))) {
01830 quit_handler(0, 0, 0, 0);
01831 ret = 1;
01832 }
01833
01834 return ret;
01835 }
01836
01837 static char *handle_version(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01838 {
01839 switch (cmd) {
01840 case CLI_INIT:
01841 e->command = "core show version";
01842 e->usage =
01843 "Usage: core show version\n"
01844 " Shows Asterisk version information.\n";
01845 return NULL;
01846 case CLI_GENERATE:
01847 return NULL;
01848 }
01849
01850 if (a->argc != 3)
01851 return CLI_SHOWUSAGE;
01852 ast_cli(a->fd, "Asterisk %s built by %s @ %s on a %s running %s on %s\n",
01853 ast_get_version(), ast_build_user, ast_build_hostname,
01854 ast_build_machine, ast_build_os, ast_build_date);
01855 return CLI_SUCCESS;
01856 }
01857
01858 #if 0
01859 static int handle_quit(int fd, int argc, char *argv[])
01860 {
01861 if (argc != 1)
01862 return RESULT_SHOWUSAGE;
01863 quit_handler(0, 0, 1, 0);
01864 return RESULT_SUCCESS;
01865 }
01866 #endif
01867
01868 static char *handle_stop_now(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01869 {
01870 switch (cmd) {
01871 case CLI_INIT:
01872 e->command = "core stop now";
01873 e->usage =
01874 "Usage: core stop now\n"
01875 " Shuts down a running Asterisk immediately, hanging up all active calls .\n";
01876 return NULL;
01877 case CLI_GENERATE:
01878 return NULL;
01879 }
01880
01881 if (a->argc != e->args)
01882 return CLI_SHOWUSAGE;
01883 quit_handler(0, 0 , 1 , 0 );
01884 return CLI_SUCCESS;
01885 }
01886
01887 static char *handle_stop_gracefully(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01888 {
01889 switch (cmd) {
01890 case CLI_INIT:
01891 e->command = "core stop gracefully";
01892 e->usage =
01893 "Usage: core stop gracefully\n"
01894 " Causes Asterisk to not accept new calls, and exit when all\n"
01895 " active calls have terminated normally.\n";
01896 return NULL;
01897 case CLI_GENERATE:
01898 return NULL;
01899 }
01900
01901 if (a->argc != e->args)
01902 return CLI_SHOWUSAGE;
01903 quit_handler(0, 1 , 1 , 0 );
01904 return CLI_SUCCESS;
01905 }
01906
01907 static char *handle_stop_when_convenient(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01908 {
01909 switch (cmd) {
01910 case CLI_INIT:
01911 e->command = "core stop when convenient";
01912 e->usage =
01913 "Usage: core stop when convenient\n"
01914 " Causes Asterisk to perform a shutdown when all active calls have ended.\n";
01915 return NULL;
01916 case CLI_GENERATE:
01917 return NULL;
01918 }
01919
01920 if (a->argc != e->args)
01921 return CLI_SHOWUSAGE;
01922 ast_cli(a->fd, "Waiting for inactivity to perform halt\n");
01923 quit_handler(0, 2 , 1 , 0 );
01924 return CLI_SUCCESS;
01925 }
01926
01927 static char *handle_restart_now(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01928 {
01929 switch (cmd) {
01930 case CLI_INIT:
01931 e->command = "core restart now";
01932 e->usage =
01933 "Usage: core restart now\n"
01934 " Causes Asterisk to hangup all calls and exec() itself performing a cold\n"
01935 " restart.\n";
01936 return NULL;
01937 case CLI_GENERATE:
01938 return NULL;
01939 }
01940
01941 if (a->argc != e->args)
01942 return CLI_SHOWUSAGE;
01943 quit_handler(0, 0 , 1 , 1 );
01944 return CLI_SUCCESS;
01945 }
01946
01947 static char *handle_restart_gracefully(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01948 {
01949 switch (cmd) {
01950 case CLI_INIT:
01951 e->command = "core restart gracefully";
01952 e->usage =
01953 "Usage: core restart gracefully\n"
01954 " Causes Asterisk to stop accepting new calls and exec() itself performing a cold\n"
01955 " restart when all active calls have ended.\n";
01956 return NULL;
01957 case CLI_GENERATE:
01958 return NULL;
01959 }
01960
01961 if (a->argc != e->args)
01962 return CLI_SHOWUSAGE;
01963 quit_handler(0, 1 , 1 , 1 );
01964 return CLI_SUCCESS;
01965 }
01966
01967 static char *handle_restart_when_convenient(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01968 {
01969 switch (cmd) {
01970 case CLI_INIT:
01971 e->command = "core restart when convenient";
01972 e->usage =
01973 "Usage: core restart when convenient\n"
01974 " Causes Asterisk to perform a cold restart when all active calls have ended.\n";
01975 return NULL;
01976 case CLI_GENERATE:
01977 return NULL;
01978 }
01979
01980 if (a->argc != e->args)
01981 return CLI_SHOWUSAGE;
01982 ast_cli(a->fd, "Waiting for inactivity to perform restart\n");
01983 quit_handler(0, 2 , 1 , 1 );
01984 return CLI_SUCCESS;
01985 }
01986
01987 static char *handle_abort_shutdown(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01988 {
01989 switch (cmd) {
01990 case CLI_INIT:
01991 e->command = "core abort shutdown";
01992 e->usage =
01993 "Usage: core abort shutdown\n"
01994 " Causes Asterisk to abort an executing shutdown or restart, and resume normal\n"
01995 " call operations.\n";
01996 return NULL;
01997 case CLI_GENERATE:
01998 return NULL;
01999 }
02000
02001 if (a->argc != e->args)
02002 return CLI_SHOWUSAGE;
02003 ast_cancel_shutdown();
02004 shuttingdown = 0;
02005 return CLI_SUCCESS;
02006 }
02007
02008 static char *handle_bang(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
02009 {
02010 switch (cmd) {
02011 case CLI_INIT:
02012 e->command = "!";
02013 e->usage =
02014 "Usage: !<command>\n"
02015 " Executes a given shell command\n";
02016 return NULL;
02017 case CLI_GENERATE:
02018 return NULL;
02019 }
02020
02021 return CLI_SUCCESS;
02022 }
02023 static const char warranty_lines[] = {
02024 "\n"
02025 " NO WARRANTY\n"
02026 "\n"
02027 "BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\n"
02028 "FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN\n"
02029 "OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\n"
02030 "PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\n"
02031 "OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n"
02032 "MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS\n"
02033 "TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE\n"
02034 "PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\n"
02035 "REPAIR OR CORRECTION.\n"
02036 "\n"
02037 "IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\n"
02038 "WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\n"
02039 "REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\n"
02040 "INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\n"
02041 "OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\n"
02042 "TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\n"
02043 "YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\n"
02044 "PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\n"
02045 "POSSIBILITY OF SUCH DAMAGES.\n"
02046 };
02047
02048 static char *show_warranty(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
02049 {
02050 switch (cmd) {
02051 case CLI_INIT:
02052 e->command = "core show warranty";
02053 e->usage =
02054 "Usage: core show warranty\n"
02055 " Shows the warranty (if any) for this copy of Asterisk.\n";
02056 return NULL;
02057 case CLI_GENERATE:
02058 return NULL;
02059 }
02060
02061 ast_cli(a->fd, "%s", warranty_lines);
02062
02063 return CLI_SUCCESS;
02064 }
02065
02066 static const char license_lines[] = {
02067 "\n"
02068 "This program is free software; you can redistribute it and/or modify\n"
02069 "it under the terms of the GNU General Public License version 2 as\n"
02070 "published by the Free Software Foundation.\n"
02071 "\n"
02072 "This program also contains components licensed under other licenses.\n"
02073 "They include:\n"
02074 "\n"
02075 "This program is distributed in the hope that it will be useful,\n"
02076 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
02077 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
02078 "GNU General Public License for more details.\n"
02079 "\n"
02080 "You should have received a copy of the GNU General Public License\n"
02081 "along with this program; if not, write to the Free Software\n"
02082 "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n"
02083 };
02084
02085 static char *show_license(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
02086 {
02087 switch (cmd) {
02088 case CLI_INIT:
02089 e->command = "core show license";
02090 e->usage =
02091 "Usage: core show license\n"
02092 " Shows the license(s) for this copy of Asterisk.\n";
02093 return NULL;
02094 case CLI_GENERATE:
02095 return NULL;
02096 }
02097
02098 ast_cli(a->fd, "%s", license_lines);
02099
02100 return CLI_SUCCESS;
02101 }
02102
02103 #define ASTERISK_PROMPT "*CLI> "
02104
02105 #define ASTERISK_PROMPT2 "%s*CLI> "
02106
02107 static struct ast_cli_entry cli_asterisk[] = {
02108 AST_CLI_DEFINE(handle_abort_shutdown, "Cancel a running shutdown"),
02109 AST_CLI_DEFINE(handle_stop_now, "Shut down Asterisk immediately"),
02110 AST_CLI_DEFINE(handle_stop_gracefully, "Gracefully shut down Asterisk"),
02111 AST_CLI_DEFINE(handle_stop_when_convenient, "Shut down Asterisk at empty call volume"),
02112 AST_CLI_DEFINE(handle_restart_now, "Restart Asterisk immediately"),
02113 AST_CLI_DEFINE(handle_restart_gracefully, "Restart Asterisk gracefully"),
02114 AST_CLI_DEFINE(handle_restart_when_convenient, "Restart Asterisk at empty call volume"),
02115 AST_CLI_DEFINE(show_warranty, "Show the warranty (if any) for this copy of Asterisk"),
02116 AST_CLI_DEFINE(show_license, "Show the license(s) for this copy of Asterisk"),
02117 AST_CLI_DEFINE(handle_version, "Display version info"),
02118 AST_CLI_DEFINE(handle_bang, "Execute a shell command"),
02119 #if !defined(LOW_MEMORY)
02120 AST_CLI_DEFINE(handle_show_version_files, "List versions of files used to build Asterisk"),
02121 AST_CLI_DEFINE(handle_show_threads, "Show running threads"),
02122 #if defined(HAVE_SYSINFO) || defined(HAVE_SYSCTL)
02123 AST_CLI_DEFINE(handle_show_sysinfo, "Show System Information"),
02124 #endif
02125 AST_CLI_DEFINE(handle_show_profile, "Display profiling info"),
02126 AST_CLI_DEFINE(handle_show_settings, "Show some core settings"),
02127 AST_CLI_DEFINE(handle_clear_profile, "Clear profiling info"),
02128 #endif
02129 };
02130
02131 static int ast_el_read_char(EditLine *editline, char *cp)
02132 {
02133 int num_read = 0;
02134 int lastpos = 0;
02135 struct pollfd fds[2];
02136 int res;
02137 int max;
02138 #define EL_BUF_SIZE 512
02139 char buf[EL_BUF_SIZE];
02140
02141 for (;;) {
02142 max = 1;
02143 fds[0].fd = ast_consock;
02144 fds[0].events = POLLIN;
02145 if (!ast_opt_exec) {
02146 fds[1].fd = STDIN_FILENO;
02147 fds[1].events = POLLIN;
02148 max++;
02149 }
02150 res = ast_poll(fds, max, -1);
02151 if (res < 0) {
02152 if (sig_flags.need_quit || sig_flags.need_quit_handler)
02153 break;
02154 if (errno == EINTR)
02155 continue;
02156 ast_log(LOG_ERROR, "poll failed: %s\n", strerror(errno));
02157 break;
02158 }
02159
02160 if (!ast_opt_exec && fds[1].revents) {
02161 num_read = read(STDIN_FILENO, cp, 1);
02162 if (num_read < 1) {
02163 break;
02164 } else
02165 return (num_read);
02166 }
02167 if (fds[0].revents) {
02168 char *tmp;
02169 res = read(ast_consock, buf, sizeof(buf) - 1);
02170
02171 if (res < 1) {
02172 fprintf(stderr, "\nDisconnected from Asterisk server\n");
02173 if (!ast_opt_reconnect) {
02174 quit_handler(0, 0, 0, 0);
02175 } else {
02176 int tries;
02177 int reconnects_per_second = 20;
02178 fprintf(stderr, "Attempting to reconnect for 30 seconds\n");
02179 for (tries = 0; tries < 30 * reconnects_per_second; tries++) {
02180 if (ast_tryconnect()) {
02181 fprintf(stderr, "Reconnect succeeded after %.3f seconds\n", 1.0 / reconnects_per_second * tries);
02182 printf("%s", term_quit());
02183 WELCOME_MESSAGE;
02184 if (!ast_opt_mute)
02185 fdsend(ast_consock, "logger mute silent");
02186 else
02187 printf("log and verbose output currently muted ('logger mute' to unmute)\n");
02188 break;
02189 } else
02190 usleep(1000000 / reconnects_per_second);
02191 }
02192 if (tries >= 30 * reconnects_per_second) {
02193 fprintf(stderr, "Failed to reconnect for 30 seconds. Quitting.\n");
02194 quit_handler(0, 0, 0, 0);
02195 }
02196 }
02197 }
02198
02199 buf[res] = '\0';
02200
02201
02202 for (tmp = buf; *tmp; tmp++) {
02203 if (*tmp == 127) {
02204 memmove(tmp, tmp + 1, strlen(tmp));
02205 tmp--;
02206 res--;
02207 }
02208 }
02209
02210
02211 if (!ast_opt_exec && !lastpos) {
02212 if (write(STDOUT_FILENO, "\r[0K", 5) < 0) {
02213 }
02214 }
02215 if (write(STDOUT_FILENO, buf, res) < 0) {
02216 }
02217 if ((res < EL_BUF_SIZE - 1) && ((buf[res-1] == '\n') || (buf[res-2] == '\n'))) {
02218 *cp = CC_REFRESH;
02219 return(1);
02220 } else
02221 lastpos = 1;
02222 }
02223 }
02224
02225 *cp = '\0';
02226 return (0);
02227 }
02228
02229 static struct ast_str *prompt = NULL;
02230
02231 static char *cli_prompt(EditLine *editline)
02232 {
02233 char tmp[100];
02234 char *pfmt;
02235 int color_used = 0;
02236 static int cli_prompt_changes = 0;
02237 char term_code[20];
02238 struct passwd *pw;
02239 struct group *gr;
02240
02241 if (prompt == NULL) {
02242 prompt = ast_str_create(100);
02243 } else if (!cli_prompt_changes) {
02244 return ast_str_buffer(prompt);
02245 } else {
02246 ast_str_reset(prompt);
02247 }
02248
02249 if ((pfmt = getenv("ASTERISK_PROMPT"))) {
02250 char *t = pfmt;
02251 struct timeval ts = ast_tvnow();
02252 while (*t != '\0') {
02253 if (*t == '%') {
02254 char hostname[MAXHOSTNAMELEN] = "";
02255 int i, which;
02256 struct ast_tm tm = { 0, };
02257 int fgcolor = COLOR_WHITE, bgcolor = COLOR_BLACK;
02258
02259 t++;
02260 switch (*t) {
02261 case 'C':
02262 t++;
02263 if (sscanf(t, "%30d;%30d%n", &fgcolor, &bgcolor, &i) == 2) {
02264 ast_str_append(&prompt, 0, "%s", term_color_code(term_code, fgcolor, bgcolor, sizeof(term_code)));
02265 t += i - 1;
02266 } else if (sscanf(t, "%30d%n", &fgcolor, &i) == 1) {
02267 ast_str_append(&prompt, 0, "%s", term_color_code(term_code, fgcolor, 0, sizeof(term_code)));
02268 t += i - 1;
02269 }
02270
02271
02272 color_used = ((fgcolor == COLOR_WHITE) && (bgcolor == COLOR_BLACK)) ? 0 : 1;
02273 break;
02274 case 'd':
02275 if (ast_localtime(&ts, &tm, NULL)) {
02276 ast_strftime(tmp, sizeof(tmp), "%Y-%m-%d", &tm);
02277 ast_str_append(&prompt, 0, "%s", tmp);
02278 cli_prompt_changes++;
02279 }
02280 break;
02281 case 'g':
02282 if ((gr = getgrgid(getgid()))) {
02283 ast_str_append(&prompt, 0, "%s", gr->gr_name);
02284 }
02285 break;
02286 case 'h':
02287 if (!gethostname(hostname, sizeof(hostname) - 1)) {
02288 ast_str_append(&prompt, 0, "%s", hostname);
02289 } else {
02290 ast_str_append(&prompt, 0, "%s", "localhost");
02291 }
02292 break;
02293 case 'H':
02294 if (!gethostname(hostname, sizeof(hostname) - 1)) {
02295 char *dotptr;
02296 if ((dotptr = strchr(hostname, '.'))) {
02297 *dotptr = '\0';
02298 }
02299 ast_str_append(&prompt, 0, "%s", hostname);
02300 } else {
02301 ast_str_append(&prompt, 0, "%s", "localhost");
02302 }
02303 break;
02304 #ifdef HAVE_GETLOADAVG
02305 case 'l':
02306 t++;
02307 if (sscanf(t, "%30d", &which) == 1 && which > 0 && which <= 3) {
02308 double list[3];
02309 getloadavg(list, 3);
02310 ast_str_append(&prompt, 0, "%.2f", list[which - 1]);
02311 cli_prompt_changes++;
02312 }
02313 break;
02314 #endif
02315 case 's':
02316 ast_str_append(&prompt, 0, "%s", ast_config_AST_SYSTEM_NAME);
02317 break;
02318 case 't':
02319 if (ast_localtime(&ts, &tm, NULL)) {
02320 ast_strftime(tmp, sizeof(tmp), "%H:%M:%S", &tm);
02321 ast_str_append(&prompt, 0, "%s", tmp);
02322 cli_prompt_changes++;
02323 }
02324 break;
02325 case 'u':
02326 if ((pw = getpwuid(getuid()))) {
02327 ast_str_append(&prompt, 0, "%s", pw->pw_name);
02328 }
02329 break;
02330 case '#':
02331 ast_str_append(&prompt, 0, "%c", ast_opt_remote ? '>' : '#');
02332 break;
02333 case '%':
02334 ast_str_append(&prompt, 0, "%c", '%');
02335 break;
02336 case '\0':
02337 t--;
02338 break;
02339 }
02340 } else {
02341 ast_str_append(&prompt, 0, "%c", *t);
02342 }
02343 t++;
02344 }
02345 if (color_used) {
02346
02347 ast_str_append(&prompt, 0, "%s", term_color_code(term_code, 0, 0, sizeof(term_code)));
02348 }
02349 } else if (remotehostname) {
02350 ast_str_set(&prompt, 0, ASTERISK_PROMPT2, remotehostname);
02351 } else {
02352 ast_str_set(&prompt, 0, "%s", ASTERISK_PROMPT);
02353 }
02354
02355 return ast_str_buffer(prompt);
02356 }
02357
02358 static char **ast_el_strtoarr(char *buf)
02359 {
02360 char **match_list = NULL, **match_list_tmp, *retstr;
02361 size_t match_list_len;
02362 int matches = 0;
02363
02364 match_list_len = 1;
02365 while ( (retstr = strsep(&buf, " ")) != NULL) {
02366
02367 if (!strcmp(retstr, AST_CLI_COMPLETE_EOF))
02368 break;
02369 if (matches + 1 >= match_list_len) {
02370 match_list_len <<= 1;
02371 if ((match_list_tmp = ast_realloc(match_list, match_list_len * sizeof(char *)))) {
02372 match_list = match_list_tmp;
02373 } else {
02374 if (match_list)
02375 ast_free(match_list);
02376 return (char **) NULL;
02377 }
02378 }
02379
02380 match_list[matches++] = ast_strdup(retstr);
02381 }
02382
02383 if (!match_list)
02384 return (char **) NULL;
02385
02386 if (matches >= match_list_len) {
02387 if ((match_list_tmp = ast_realloc(match_list, (match_list_len + 1) * sizeof(char *)))) {
02388 match_list = match_list_tmp;
02389 } else {
02390 if (match_list)
02391 ast_free(match_list);
02392 return (char **) NULL;
02393 }
02394 }
02395
02396 match_list[matches] = (char *) NULL;
02397
02398 return match_list;
02399 }
02400
02401 static int ast_el_sort_compare(const void *i1, const void *i2)
02402 {
02403 char *s1, *s2;
02404
02405 s1 = ((char **)i1)[0];
02406 s2 = ((char **)i2)[0];
02407
02408 return strcasecmp(s1, s2);
02409 }
02410
02411 static int ast_cli_display_match_list(char **matches, int len, int max)
02412 {
02413 int i, idx, limit, count;
02414 int screenwidth = 0;
02415 int numoutput = 0, numoutputline = 0;
02416
02417 screenwidth = ast_get_termcols(STDOUT_FILENO);
02418
02419
02420 limit = screenwidth / (max + 2);
02421 if (limit == 0)
02422 limit = 1;
02423
02424
02425 count = len / limit;
02426 if (count * limit < len)
02427 count++;
02428
02429 idx = 1;
02430
02431 qsort(&matches[0], (size_t)(len), sizeof(char *), ast_el_sort_compare);
02432
02433 for (; count > 0; count--) {
02434 numoutputline = 0;
02435 for (i = 0; i < limit && matches[idx]; i++, idx++) {
02436
02437
02438 if ( (matches[idx+1] != NULL && strcmp(matches[idx], matches[idx+1]) == 0 ) ) {
02439 i--;
02440 ast_free(matches[idx]);
02441 matches[idx] = NULL;
02442 continue;
02443 }
02444
02445 numoutput++;
02446 numoutputline++;
02447 fprintf(stdout, "%-*s ", max, matches[idx]);
02448 ast_free(matches[idx]);
02449 matches[idx] = NULL;
02450 }
02451 if (numoutputline > 0)
02452 fprintf(stdout, "\n");
02453 }
02454
02455 return numoutput;
02456 }
02457
02458
02459 static char *cli_complete(EditLine *editline, int ch)
02460 {
02461 int len = 0;
02462 char *ptr;
02463 int nummatches = 0;
02464 char **matches;
02465 int retval = CC_ERROR;
02466 char buf[2048], savechr;
02467 int res;
02468
02469 LineInfo *lf = (LineInfo *)el_line(editline);
02470
02471 savechr = *(char *)lf->cursor;
02472 *(char *)lf->cursor = '\0';
02473 ptr = (char *)lf->cursor;
02474 if (ptr) {
02475 while (ptr > lf->buffer) {
02476 if (isspace(*ptr)) {
02477 ptr++;
02478 break;
02479 }
02480 ptr--;
02481 }
02482 }
02483
02484 len = lf->cursor - ptr;
02485
02486 if (ast_opt_remote) {
02487 snprintf(buf, sizeof(buf), "_COMMAND NUMMATCHES \"%s\" \"%s\"", lf->buffer, ptr);
02488 fdsend(ast_consock, buf);
02489 res = read(ast_consock, buf, sizeof(buf) - 1);
02490 buf[res] = '\0';
02491 nummatches = atoi(buf);
02492
02493 if (nummatches > 0) {
02494 char *mbuf;
02495 int mlen = 0, maxmbuf = 2048;
02496
02497 if (!(mbuf = ast_malloc(maxmbuf))) {
02498 lf->cursor[0] = savechr;
02499 return (char *)(CC_ERROR);
02500 }
02501 snprintf(buf, sizeof(buf), "_COMMAND MATCHESARRAY \"%s\" \"%s\"", lf->buffer, ptr);
02502 fdsend(ast_consock, buf);
02503 res = 0;
02504 mbuf[0] = '\0';
02505 while (!strstr(mbuf, AST_CLI_COMPLETE_EOF) && res != -1) {
02506 if (mlen + 1024 > maxmbuf) {
02507
02508 maxmbuf += 1024;
02509 if (!(mbuf = ast_realloc(mbuf, maxmbuf))) {
02510 lf->cursor[0] = savechr;
02511 return (char *)(CC_ERROR);
02512 }
02513 }
02514
02515 res = read(ast_consock, mbuf + mlen, 1024);
02516 if (res > 0)
02517 mlen += res;
02518 }
02519 mbuf[mlen] = '\0';
02520
02521 matches = ast_el_strtoarr(mbuf);
02522 ast_free(mbuf);
02523 } else
02524 matches = (char **) NULL;
02525 } else {
02526 char **p, *oldbuf=NULL;
02527 nummatches = 0;
02528 matches = ast_cli_completion_matches((char *)lf->buffer,ptr);
02529 for (p = matches; p && *p; p++) {
02530 if (!oldbuf || strcmp(*p,oldbuf))
02531 nummatches++;
02532 oldbuf = *p;
02533 }
02534 }
02535
02536 if (matches) {
02537 int i;
02538 int matches_num, maxlen, match_len;
02539
02540 if (matches[0][0] != '\0') {
02541 el_deletestr(editline, (int) len);
02542 el_insertstr(editline, matches[0]);
02543 retval = CC_REFRESH;
02544 }
02545
02546 if (nummatches == 1) {
02547
02548 el_insertstr(editline, " ");
02549 retval = CC_REFRESH;
02550 } else {
02551
02552 for (i = 1, maxlen = 0; matches[i]; i++) {
02553 match_len = strlen(matches[i]);
02554 if (match_len > maxlen)
02555 maxlen = match_len;
02556 }
02557 matches_num = i - 1;
02558 if (matches_num >1) {
02559 fprintf(stdout, "\n");
02560 ast_cli_display_match_list(matches, nummatches, maxlen);
02561 retval = CC_REDISPLAY;
02562 } else {
02563 el_insertstr(editline," ");
02564 retval = CC_REFRESH;
02565 }
02566 }
02567 for (i = 0; matches[i]; i++)
02568 ast_free(matches[i]);
02569 ast_free(matches);
02570 }
02571
02572 lf->cursor[0] = savechr;
02573
02574 return (char *)(long)retval;
02575 }
02576
02577 static int ast_el_initialize(void)
02578 {
02579 HistEvent ev;
02580 char *editor = getenv("AST_EDITOR");
02581
02582 if (el != NULL)
02583 el_end(el);
02584 if (el_hist != NULL)
02585 history_end(el_hist);
02586
02587 el = el_init("asterisk", stdin, stdout, stderr);
02588 el_set(el, EL_PROMPT, cli_prompt);
02589
02590 el_set(el, EL_EDITMODE, 1);
02591 el_set(el, EL_EDITOR, editor ? editor : "emacs");
02592 el_hist = history_init();
02593 if (!el || !el_hist)
02594 return -1;
02595
02596
02597 history(el_hist, &ev, H_SETSIZE, 100);
02598
02599 el_set(el, EL_HIST, history, el_hist);
02600
02601 el_set(el, EL_ADDFN, "ed-complete", "Complete argument", cli_complete);
02602
02603 el_set(el, EL_BIND, "^I", "ed-complete", NULL);
02604
02605 el_set(el, EL_BIND, "?", "ed-complete", NULL);
02606
02607 el_set(el, EL_BIND, "^D", "ed-redisplay", NULL);
02608
02609 return 0;
02610 }
02611
02612 #define MAX_HISTORY_COMMAND_LENGTH 256
02613
02614 static int ast_el_add_history(char *buf)
02615 {
02616 HistEvent ev;
02617
02618 if (el_hist == NULL || el == NULL)
02619 ast_el_initialize();
02620 if (strlen(buf) > (MAX_HISTORY_COMMAND_LENGTH - 1))
02621 return 0;
02622 return (history(el_hist, &ev, H_ENTER, ast_strip(ast_strdupa(buf))));
02623 }
02624
02625 static int ast_el_write_history(char *filename)
02626 {
02627 HistEvent ev;
02628
02629 if (el_hist == NULL || el == NULL)
02630 ast_el_initialize();
02631
02632 return (history(el_hist, &ev, H_SAVE, filename));
02633 }
02634
02635 static int ast_el_read_history(char *filename)
02636 {
02637 char buf[MAX_HISTORY_COMMAND_LENGTH];
02638 FILE *f;
02639 int ret = -1;
02640
02641 if (el_hist == NULL || el == NULL)
02642 ast_el_initialize();
02643
02644 if ((f = fopen(filename, "r")) == NULL)
02645 return ret;
02646
02647 while (!feof(f)) {
02648 if (!fgets(buf, sizeof(buf), f))
02649 break;
02650 if (!strcmp(buf, "_HiStOrY_V2_\n"))
02651 continue;
02652 if (ast_all_zeros(buf))
02653 continue;
02654 if ((ret = ast_el_add_history(buf)) == -1)
02655 break;
02656 }
02657 fclose(f);
02658
02659 return ret;
02660 }
02661
02662 static void ast_remotecontrol(char *data)
02663 {
02664 char buf[80];
02665 int res;
02666 char filename[80] = "";
02667 char *hostname;
02668 char *cpid;
02669 char *version;
02670 int pid;
02671 char *stringp = NULL;
02672
02673 char *ebuf;
02674 int num = 0;
02675
02676 memset(&sig_flags, 0, sizeof(sig_flags));
02677 signal(SIGINT, __remote_quit_handler);
02678 signal(SIGTERM, __remote_quit_handler);
02679 signal(SIGHUP, __remote_quit_handler);
02680
02681 if (read(ast_consock, buf, sizeof(buf)) < 0) {
02682 ast_log(LOG_ERROR, "read() failed: %s\n", strerror(errno));
02683 return;
02684 }
02685 if (data) {
02686 char prefix[] = "cli quit after ";
02687 char *tmp = alloca(strlen(data) + strlen(prefix) + 1);
02688 sprintf(tmp, "%s%s", prefix, data);
02689 if (write(ast_consock, tmp, strlen(tmp) + 1) < 0) {
02690 ast_log(LOG_ERROR, "write() failed: %s\n", strerror(errno));
02691 if (sig_flags.need_quit || sig_flags.need_quit_handler) {
02692 return;
02693 }
02694 }
02695 }
02696 stringp = buf;
02697 hostname = strsep(&stringp, "/");
02698 cpid = strsep(&stringp, "/");
02699 version = strsep(&stringp, "\n");
02700 if (!version)
02701 version = "<Version Unknown>";
02702 stringp = hostname;
02703 strsep(&stringp, ".");
02704 if (cpid)
02705 pid = atoi(cpid);
02706 else
02707 pid = -1;
02708 if (!data) {
02709 char tmp[80];
02710 snprintf(tmp, sizeof(tmp), "core set verbose atleast %d", option_verbose);
02711 fdsend(ast_consock, tmp);
02712 snprintf(tmp, sizeof(tmp), "core set debug atleast %d", option_debug);
02713 fdsend(ast_consock, tmp);
02714 if (!ast_opt_mute)
02715 fdsend(ast_consock, "logger mute silent");
02716 else
02717 printf("log and verbose output currently muted ('logger mute' to unmute)\n");
02718 }
02719
02720 if (ast_opt_exec && data) {
02721 struct pollfd fds;
02722 fds.fd = ast_consock;
02723 fds.events = POLLIN;
02724 fds.revents = 0;
02725 while (ast_poll(&fds, 1, 60000) > 0) {
02726 char buffer[512] = "", *curline = buffer, *nextline;
02727 int not_written = 1;
02728
02729 if (sig_flags.need_quit || sig_flags.need_quit_handler) {
02730 break;
02731 }
02732
02733 if (read(ast_consock, buffer, sizeof(buffer) - 1) <= 0) {
02734 break;
02735 }
02736
02737 do {
02738 if ((nextline = strchr(curline, '\n'))) {
02739 nextline++;
02740 } else {
02741 nextline = strchr(curline, '\0');
02742 }
02743
02744
02745 if (*curline != 127) {
02746 not_written = 0;
02747 if (write(STDOUT_FILENO, curline, nextline - curline) < 0) {
02748 ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno));
02749 }
02750 }
02751 curline = nextline;
02752 } while (!ast_strlen_zero(curline));
02753
02754
02755 if (not_written) {
02756 break;
02757 }
02758 }
02759 return;
02760 }
02761
02762 ast_verbose("Connected to Asterisk %s currently running on %s (pid = %d)\n", version, hostname, pid);
02763 remotehostname = hostname;
02764 if (getenv("HOME"))
02765 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
02766 if (el_hist == NULL || el == NULL)
02767 ast_el_initialize();
02768
02769 el_set(el, EL_GETCFN, ast_el_read_char);
02770
02771 if (!ast_strlen_zero(filename))
02772 ast_el_read_history(filename);
02773
02774 for (;;) {
02775 ebuf = (char *)el_gets(el, &num);
02776
02777 if (sig_flags.need_quit || sig_flags.need_quit_handler) {
02778 break;
02779 }
02780
02781 if (!ebuf && write(1, "", 1) < 0)
02782 break;
02783
02784 if (!ast_strlen_zero(ebuf)) {
02785 if (ebuf[strlen(ebuf)-1] == '\n')
02786 ebuf[strlen(ebuf)-1] = '\0';
02787 if (!remoteconsolehandler(ebuf)) {
02788
02789 char *temp;
02790 for (temp = ebuf; *temp; temp++) {
02791 if (*temp == 127) {
02792 memmove(temp, temp + 1, strlen(temp));
02793 temp--;
02794 }
02795 }
02796 res = write(ast_consock, ebuf, strlen(ebuf) + 1);
02797 if (res < 1) {
02798 ast_log(LOG_WARNING, "Unable to write: %s\n", strerror(errno));
02799 break;
02800 }
02801 }
02802 }
02803 }
02804 printf("\nDisconnected from Asterisk server\n");
02805 }
02806
02807 static int show_version(void)
02808 {
02809 printf("Asterisk %s\n", ast_get_version());
02810 return 0;
02811 }
02812
02813 static int show_cli_help(void) {
02814 printf("Asterisk %s, Copyright (C) 1999 - 2010, Digium, Inc. and others.\n", ast_get_version());
02815 printf("Usage: asterisk [OPTIONS]\n");
02816 printf("Valid Options:\n");
02817 printf(" -V Display version number and exit\n");
02818 printf(" -C <configfile> Use an alternate configuration file\n");
02819 printf(" -G <group> Run as a group other than the caller\n");
02820 printf(" -U <user> Run as a user other than the caller\n");
02821 printf(" -c Provide console CLI\n");
02822 printf(" -d Enable extra debugging\n");
02823 #if HAVE_WORKING_FORK
02824 printf(" -f Do not fork\n");
02825 printf(" -F Always fork\n");
02826 #endif
02827 printf(" -g Dump core in case of a crash\n");
02828 printf(" -h This help screen\n");
02829 printf(" -i Initialize crypto keys at startup\n");
02830 printf(" -I Enable internal timing if DAHDI timer is available\n");
02831 printf(" -L <load> Limit the maximum load average before rejecting new calls\n");
02832 printf(" -M <value> Limit the maximum number of calls to the specified value\n");
02833 printf(" -m Mute debugging and console output on the console\n");
02834 printf(" -n Disable console colorization\n");
02835 printf(" -p Run as pseudo-realtime thread\n");
02836 printf(" -q Quiet mode (suppress output)\n");
02837 printf(" -r Connect to Asterisk on this machine\n");
02838 printf(" -R Same as -r, except attempt to reconnect if disconnected\n");
02839 printf(" -s <socket> Connect to Asterisk via socket <socket> (only valid with -r)\n");
02840 printf(" -t Record soundfiles in /var/tmp and move them where they\n");
02841 printf(" belong after they are done\n");
02842 printf(" -T Display the time in [Mmm dd hh:mm:ss] format for each line\n");
02843 printf(" of output to the CLI\n");
02844 printf(" -v Increase verbosity (multiple v's = more verbose)\n");
02845 printf(" -x <cmd> Execute command <cmd> (only valid with -r)\n");
02846 printf(" -X Execute includes by default (allows #exec in asterisk.conf)\n");
02847 printf(" -W Adjust terminal colors to compensate for a light background\n");
02848 printf("\n");
02849 return 0;
02850 }
02851
02852 static void ast_readconfig(void)
02853 {
02854 struct ast_config *cfg;
02855 struct ast_variable *v;
02856 char *config = DEFAULT_CONFIG_FILE;
02857 char hostname[MAXHOSTNAMELEN] = "";
02858 struct ast_flags config_flags = { CONFIG_FLAG_NOREALTIME };
02859 struct {
02860 unsigned int dbdir:1;
02861 unsigned int keydir:1;
02862 } found = { 0, 0 };
02863
02864 if (ast_opt_override_config) {
02865 cfg = ast_config_load2(ast_config_AST_CONFIG_FILE, "" , config_flags);
02866 if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID)
02867 ast_log(LOG_WARNING, "Unable to open specified master config file '%s', using built-in defaults\n", ast_config_AST_CONFIG_FILE);
02868 } else
02869 cfg = ast_config_load2(config, "" , config_flags);
02870
02871
02872 ast_copy_string(cfg_paths.config_dir, DEFAULT_CONFIG_DIR, sizeof(cfg_paths.config_dir));
02873 ast_copy_string(cfg_paths.spool_dir, DEFAULT_SPOOL_DIR, sizeof(cfg_paths.spool_dir));
02874 ast_copy_string(cfg_paths.module_dir, DEFAULT_MODULE_DIR, sizeof(cfg_paths.module_dir));
02875 snprintf(cfg_paths.monitor_dir, sizeof(cfg_paths.monitor_dir), "%s/monitor", cfg_paths.spool_dir);
02876 ast_copy_string(cfg_paths.var_dir, DEFAULT_VAR_DIR, sizeof(cfg_paths.var_dir));
02877 ast_copy_string(cfg_paths.data_dir, DEFAULT_DATA_DIR, sizeof(cfg_paths.data_dir));
02878 ast_copy_string(cfg_paths.log_dir, DEFAULT_LOG_DIR, sizeof(cfg_paths.log_dir));
02879 ast_copy_string(cfg_paths.agi_dir, DEFAULT_AGI_DIR, sizeof(cfg_paths.agi_dir));
02880 ast_copy_string(cfg_paths.db_path, DEFAULT_DB, sizeof(cfg_paths.db_path));
02881 ast_copy_string(cfg_paths.key_dir, DEFAULT_KEY_DIR, sizeof(cfg_paths.key_dir));
02882 ast_copy_string(cfg_paths.pid_path, DEFAULT_PID, sizeof(cfg_paths.pid_path));
02883 ast_copy_string(cfg_paths.socket_path, DEFAULT_SOCKET, sizeof(cfg_paths.socket_path));
02884 ast_copy_string(cfg_paths.run_dir, DEFAULT_RUN_DIR, sizeof(cfg_paths.run_dir));
02885
02886 ast_set_default_eid(&ast_eid_default);
02887
02888
02889 if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) {
02890 return;
02891 }
02892
02893 for (v = ast_variable_browse(cfg, "files"); v; v = v->next) {
02894 if (!strcasecmp(v->name, "astctlpermissions"))
02895 ast_copy_string(ast_config_AST_CTL_PERMISSIONS, v->value, sizeof(ast_config_AST_CTL_PERMISSIONS));
02896 else if (!strcasecmp(v->name, "astctlowner"))
02897 ast_copy_string(ast_config_AST_CTL_OWNER, v->value, sizeof(ast_config_AST_CTL_OWNER));
02898 else if (!strcasecmp(v->name, "astctlgroup"))
02899 ast_copy_string(ast_config_AST_CTL_GROUP, v->value, sizeof(ast_config_AST_CTL_GROUP));
02900 else if (!strcasecmp(v->name, "astctl"))
02901 ast_copy_string(ast_config_AST_CTL, v->value, sizeof(ast_config_AST_CTL));
02902 }
02903
02904 for (v = ast_variable_browse(cfg, "directories"); v; v = v->next) {
02905 if (!strcasecmp(v->name, "astetcdir")) {
02906 ast_copy_string(cfg_paths.config_dir, v->value, sizeof(cfg_paths.config_dir));
02907 } else if (!strcasecmp(v->name, "astspooldir")) {
02908 ast_copy_string(cfg_paths.spool_dir, v->value, sizeof(cfg_paths.spool_dir));
02909 snprintf(cfg_paths.monitor_dir, sizeof(cfg_paths.monitor_dir), "%s/monitor", v->value);
02910 } else if (!strcasecmp(v->name, "astvarlibdir")) {
02911 ast_copy_string(cfg_paths.var_dir, v->value, sizeof(cfg_paths.var_dir));
02912 if (!found.dbdir)
02913 snprintf(cfg_paths.db_path, sizeof(cfg_paths.db_path), "%s/astdb", v->value);
02914 } else if (!strcasecmp(v->name, "astdbdir")) {
02915 snprintf(cfg_paths.db_path, sizeof(cfg_paths.db_path), "%s/astdb", v->value);
02916 found.dbdir = 1;
02917 } else if (!strcasecmp(v->name, "astdatadir")) {
02918 ast_copy_string(cfg_paths.data_dir, v->value, sizeof(cfg_paths.data_dir));
02919 if (!found.keydir)
02920 snprintf(cfg_paths.key_dir, sizeof(cfg_paths.key_dir), "%s/keys", v->value);
02921 } else if (!strcasecmp(v->name, "astkeydir")) {
02922 snprintf(cfg_paths.key_dir, sizeof(cfg_paths.key_dir), "%s/keys", v->value);
02923 found.keydir = 1;
02924 } else if (!strcasecmp(v->name, "astlogdir")) {
02925 ast_copy_string(cfg_paths.log_dir, v->value, sizeof(cfg_paths.log_dir));
02926 } else if (!strcasecmp(v->name, "astagidir")) {
02927 ast_copy_string(cfg_paths.agi_dir, v->value, sizeof(cfg_paths.agi_dir));
02928 } else if (!strcasecmp(v->name, "astrundir")) {
02929 snprintf(cfg_paths.pid_path, sizeof(cfg_paths.pid_path), "%s/%s", v->value, "asterisk.pid");
02930 snprintf(cfg_paths.socket_path, sizeof(cfg_paths.socket_path), "%s/%s", v->value, ast_config_AST_CTL);
02931 ast_copy_string(cfg_paths.run_dir, v->value, sizeof(cfg_paths.run_dir));
02932 } else if (!strcasecmp(v->name, "astmoddir")) {
02933 ast_copy_string(cfg_paths.module_dir, v->value, sizeof(cfg_paths.module_dir));
02934 }
02935 }
02936
02937 for (v = ast_variable_browse(cfg, "options"); v; v = v->next) {
02938
02939 if (!strcasecmp(v->name, "verbose")) {
02940 option_verbose = atoi(v->value);
02941
02942 } else if (!strcasecmp(v->name, "timestamp")) {
02943 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TIMESTAMP);
02944
02945 } else if (!strcasecmp(v->name, "execincludes")) {
02946 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_EXEC_INCLUDES);
02947
02948 } else if (!strcasecmp(v->name, "debug")) {
02949 option_debug = 0;
02950 if (sscanf(v->value, "%30d", &option_debug) != 1) {
02951 option_debug = ast_true(v->value);
02952 }
02953 #if HAVE_WORKING_FORK
02954
02955 } else if (!strcasecmp(v->name, "nofork")) {
02956 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_FORK);
02957
02958 } else if (!strcasecmp(v->name, "alwaysfork")) {
02959 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_ALWAYS_FORK);
02960 #endif
02961
02962 } else if (!strcasecmp(v->name, "quiet")) {
02963 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_QUIET);
02964
02965 } else if (!strcasecmp(v->name, "console")) {
02966 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_CONSOLE);
02967
02968 } else if (!strcasecmp(v->name, "highpriority")) {
02969 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_HIGH_PRIORITY);
02970
02971 } else if (!strcasecmp(v->name, "initcrypto")) {
02972 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_INIT_KEYS);
02973
02974 } else if (!strcasecmp(v->name, "nocolor")) {
02975 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_COLOR);
02976
02977 } else if (!strcasecmp(v->name, "dontwarn")) {
02978 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_DONT_WARN);
02979
02980 } else if (!strcasecmp(v->name, "dumpcore")) {
02981 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_DUMP_CORE);
02982
02983 } else if (!strcasecmp(v->name, "cache_record_files")) {
02984 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_CACHE_RECORD_FILES);
02985
02986 } else if (!strcasecmp(v->name, "record_cache_dir")) {
02987 ast_copy_string(record_cache_dir, v->value, AST_CACHE_DIR_LEN);
02988
02989 } else if (!strcasecmp(v->name, "transcode_via_sln")) {
02990 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TRANSCODE_VIA_SLIN);
02991
02992 } else if (!strcasecmp(v->name, "transmit_silence_during_record") || !strcasecmp(v->name, "transmit_silence")) {
02993 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TRANSMIT_SILENCE);
02994
02995 } else if (!strcasecmp(v->name, "internal_timing")) {
02996 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_INTERNAL_TIMING);
02997 } else if (!strcasecmp(v->name, "maxcalls")) {
02998 if ((sscanf(v->value, "%30d", &option_maxcalls) != 1) || (option_maxcalls < 0)) {
02999 option_maxcalls = 0;
03000 }
03001 } else if (!strcasecmp(v->name, "maxload")) {
03002 double test[1];
03003
03004 if (getloadavg(test, 1) == -1) {
03005 ast_log(LOG_ERROR, "Cannot obtain load average on this system. 'maxload' option disabled.\n");
03006 option_maxload = 0.0;
03007 } else if ((sscanf(v->value, "%30lf", &option_maxload) != 1) || (option_maxload < 0.0)) {
03008 option_maxload = 0.0;
03009 }
03010
03011 } else if (!strcasecmp(v->name, "maxfiles")) {
03012 option_maxfiles = atoi(v->value);
03013 set_ulimit(option_maxfiles);
03014
03015 } else if (!strcasecmp(v->name, "runuser")) {
03016 ast_copy_string(cfg_paths.run_user, v->value, sizeof(cfg_paths.run_user));
03017
03018 } else if (!strcasecmp(v->name, "rungroup")) {
03019 ast_copy_string(cfg_paths.run_group, v->value, sizeof(cfg_paths.run_group));
03020 } else if (!strcasecmp(v->name, "systemname")) {
03021 ast_copy_string(cfg_paths.system_name, v->value, sizeof(cfg_paths.system_name));
03022 } else if (!strcasecmp(v->name, "autosystemname")) {
03023 if (ast_true(v->value)) {
03024 if (!gethostname(hostname, sizeof(hostname) - 1))
03025 ast_copy_string(cfg_paths.system_name, hostname, sizeof(cfg_paths.system_name));
03026 else {
03027 if (ast_strlen_zero(ast_config_AST_SYSTEM_NAME)){
03028 ast_copy_string(cfg_paths.system_name, "localhost", sizeof(cfg_paths.system_name));
03029 }
03030 ast_log(LOG_ERROR, "Cannot obtain hostname for this system. Using '%s' instead.\n", ast_config_AST_SYSTEM_NAME);
03031 }
03032 }
03033 } else if (!strcasecmp(v->name, "languageprefix")) {
03034 ast_language_is_prefix = ast_true(v->value);
03035 } else if (!strcasecmp(v->name, "defaultlanguage")) {
03036 ast_copy_string(defaultlanguage, v->value, MAX_LANGUAGE);
03037 } else if (!strcasecmp(v->name, "lockmode")) {
03038 if (!strcasecmp(v->value, "lockfile")) {
03039 ast_set_lock_type(AST_LOCK_TYPE_LOCKFILE);
03040 } else if (!strcasecmp(v->value, "flock")) {
03041 ast_set_lock_type(AST_LOCK_TYPE_FLOCK);
03042 } else {
03043 ast_log(LOG_WARNING, "'%s' is not a valid setting for the lockmode option, "
03044 "defaulting to 'lockfile'\n", v->value);
03045 ast_set_lock_type(AST_LOCK_TYPE_LOCKFILE);
03046 }
03047 #if defined(HAVE_SYSINFO)
03048 } else if (!strcasecmp(v->name, "minmemfree")) {
03049
03050
03051 if ((sscanf(v->value, "%30ld", &option_minmemfree) != 1) || (option_minmemfree < 0)) {
03052 option_minmemfree = 0;
03053 }
03054 #endif
03055 } else if (!strcasecmp(v->name, "entityid")) {
03056 struct ast_eid tmp_eid;
03057 if (!ast_str_to_eid(&tmp_eid, v->value)) {
03058 ast_verbose("Successfully set global EID to '%s'\n", v->value);
03059 ast_eid_default = tmp_eid;
03060 } else
03061 ast_verbose("Invalid Entity ID '%s' provided\n", v->value);
03062 } else if (!strcasecmp(v->name, "lightbackground")) {
03063 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_LIGHT_BACKGROUND);
03064 } else if (!strcasecmp(v->name, "forceblackbackground")) {
03065 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_FORCE_BLACK_BACKGROUND);
03066 } else if (!strcasecmp(v->name, "hideconnect")) {
03067 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_HIDE_CONSOLE_CONNECT);
03068 } else if (!strcasecmp(v->name, "lockconfdir")) {
03069 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_LOCK_CONFIG_DIR);
03070 }
03071 }
03072 for (v = ast_variable_browse(cfg, "compat"); v; v = v->next) {
03073 float version;
03074 if (sscanf(v->value, "%30f", &version) != 1) {
03075 ast_log(LOG_WARNING, "Compatibility version for option '%s' is not a number: '%s'\n", v->name, v->value);
03076 continue;
03077 }
03078 if (!strcasecmp(v->name, "app_set")) {
03079 ast_set2_flag(&ast_compat, version < 1.5 ? 1 : 0, AST_COMPAT_APP_SET);
03080 } else if (!strcasecmp(v->name, "res_agi")) {
03081 ast_set2_flag(&ast_compat, version < 1.5 ? 1 : 0, AST_COMPAT_DELIM_RES_AGI);
03082 } else if (!strcasecmp(v->name, "pbx_realtime")) {
03083 ast_set2_flag(&ast_compat, version < 1.5 ? 1 : 0, AST_COMPAT_DELIM_PBX_REALTIME);
03084 }
03085 }
03086 ast_config_destroy(cfg);
03087 }
03088
03089 static void *monitor_sig_flags(void *unused)
03090 {
03091 for (;;) {
03092 struct pollfd p = { sig_alert_pipe[0], POLLIN, 0 };
03093 int a;
03094 ast_poll(&p, 1, -1);
03095 if (sig_flags.need_reload) {
03096 sig_flags.need_reload = 0;
03097 ast_module_reload(NULL);
03098 }
03099 if (sig_flags.need_quit) {
03100 sig_flags.need_quit = 0;
03101 if (consolethread != AST_PTHREADT_NULL) {
03102 sig_flags.need_quit_handler = 1;
03103 pthread_kill(consolethread, SIGURG);
03104 } else {
03105 quit_handler(0, 0, 1, 0);
03106 }
03107 }
03108 if (read(sig_alert_pipe[0], &a, sizeof(a)) != sizeof(a)) {
03109 }
03110 }
03111
03112 return NULL;
03113 }
03114
03115 static void *canary_thread(void *unused)
03116 {
03117 struct stat canary_stat;
03118 struct timeval now;
03119
03120
03121 sleep(120);
03122
03123 for (;;) {
03124 stat(canary_filename, &canary_stat);
03125 now = ast_tvnow();
03126 if (now.tv_sec > canary_stat.st_mtime + 60) {
03127 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");
03128 ast_set_priority(0);
03129 pthread_exit(NULL);
03130 }
03131
03132
03133 sleep(60);
03134 }
03135 }
03136
03137
03138 static void canary_exit(void)
03139 {
03140 if (canary_pid > 0)
03141 kill(canary_pid, SIGKILL);
03142 }
03143
03144 static void run_startup_commands(void)
03145 {
03146 int fd;
03147 struct ast_config *cfg;
03148 struct ast_flags cfg_flags = { 0 };
03149 struct ast_variable *v;
03150
03151 if (!(cfg = ast_config_load2("cli.conf", "" , cfg_flags)))
03152 return;
03153 if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) {
03154 return;
03155 }
03156
03157 fd = open("/dev/null", O_RDWR);
03158 if (fd < 0) {
03159 ast_config_destroy(cfg);
03160 return;
03161 }
03162
03163 for (v = ast_variable_browse(cfg, "startup_commands"); v; v = v->next) {
03164 if (ast_true(v->value))
03165 ast_cli_command(fd, v->name);
03166 }
03167
03168 close(fd);
03169 ast_config_destroy(cfg);
03170 }
03171
03172 static void env_init(void)
03173 {
03174 setenv("AST_SYSTEMNAME", ast_config_AST_SYSTEM_NAME, 1);
03175 setenv("AST_BUILD_HOST", ast_build_hostname, 1);
03176 setenv("AST_BUILD_DATE", ast_build_date, 1);
03177 setenv("AST_BUILD_KERNEL", ast_build_kernel, 1);
03178 setenv("AST_BUILD_MACHINE", ast_build_machine, 1);
03179 setenv("AST_BUILD_OS", ast_build_os, 1);
03180 setenv("AST_BUILD_USER", ast_build_user, 1);
03181 setenv("AST_VERSION", ast_get_version(), 1);
03182 }
03183
03184 int main(int argc, char *argv[])
03185 {
03186 int c;
03187 char filename[80] = "";
03188 char hostname[MAXHOSTNAMELEN] = "";
03189 char tmp[80];
03190 char * xarg = NULL;
03191 int x;
03192 FILE *f;
03193 sigset_t sigs;
03194 int num;
03195 int isroot = 1, rundir_exists = 0;
03196 char *buf;
03197 const char *runuser = NULL, *rungroup = NULL;
03198 char *remotesock = NULL;
03199 int moduleresult;
03200 struct rlimit l;
03201
03202
03203 if (argc > ARRAY_LEN(_argv) - 1) {
03204 fprintf(stderr, "Truncating argument size to %d\n", (int)ARRAY_LEN(_argv) - 1);
03205 argc = ARRAY_LEN(_argv) - 1;
03206 }
03207 for (x = 0; x < argc; x++)
03208 _argv[x] = argv[x];
03209 _argv[x] = NULL;
03210
03211 if (geteuid() != 0)
03212 isroot = 0;
03213
03214
03215 if (argv[0] && (strstr(argv[0], "rasterisk")) != NULL) {
03216 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE);
03217 }
03218 if (gethostname(hostname, sizeof(hostname)-1))
03219 ast_copy_string(hostname, "<Unknown>", sizeof(hostname));
03220 ast_mainpid = getpid();
03221 ast_ulaw_init();
03222 ast_alaw_init();
03223 callerid_init();
03224 ast_builtins_init();
03225 ast_utils_init();
03226 tdd_init();
03227 ast_tps_init();
03228 ast_fd_init();
03229 ast_pbx_init();
03230
03231 if (getenv("HOME"))
03232 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
03233
03234 while ((c = getopt(argc, argv, "BC:cde:FfG:ghIiL:M:mnpqRrs:TtU:VvWXx:")) != -1) {
03235
03236
03237
03238 switch (c) {
03239 case 'B':
03240 ast_set_flag(&ast_options, AST_OPT_FLAG_FORCE_BLACK_BACKGROUND);
03241 ast_clear_flag(&ast_options, AST_OPT_FLAG_LIGHT_BACKGROUND);
03242 break;
03243 case 'X':
03244 ast_set_flag(&ast_options, AST_OPT_FLAG_EXEC_INCLUDES);
03245 break;
03246 case 'C':
03247 ast_copy_string(cfg_paths.config_file, optarg, sizeof(cfg_paths.config_file));
03248 ast_set_flag(&ast_options, AST_OPT_FLAG_OVERRIDE_CONFIG);
03249 break;
03250 case 'c':
03251 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_CONSOLE);
03252 break;
03253 case 'd':
03254 option_debug++;
03255 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);
03256 break;
03257 #if defined(HAVE_SYSINFO)
03258 case 'e':
03259 if ((sscanf(&optarg[1], "%30ld", &option_minmemfree) != 1) || (option_minmemfree < 0)) {
03260 option_minmemfree = 0;
03261 }
03262 break;
03263 #endif
03264 #if HAVE_WORKING_FORK
03265 case 'F':
03266 ast_set_flag(&ast_options, AST_OPT_FLAG_ALWAYS_FORK);
03267 break;
03268 case 'f':
03269 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);
03270 break;
03271 #endif
03272 case 'G':
03273 rungroup = ast_strdupa(optarg);
03274 break;
03275 case 'g':
03276 ast_set_flag(&ast_options, AST_OPT_FLAG_DUMP_CORE);
03277 break;
03278 case 'h':
03279 show_cli_help();
03280 exit(0);
03281 case 'I':
03282 ast_set_flag(&ast_options, AST_OPT_FLAG_INTERNAL_TIMING);
03283 break;
03284 case 'i':
03285 ast_set_flag(&ast_options, AST_OPT_FLAG_INIT_KEYS);
03286 break;
03287 case 'L':
03288 if ((sscanf(optarg, "%30lf", &option_maxload) != 1) || (option_maxload < 0.0)) {
03289 option_maxload = 0.0;
03290 }
03291 break;
03292 case 'M':
03293 if ((sscanf(optarg, "%30d", &option_maxcalls) != 1) || (option_maxcalls < 0)) {
03294 option_maxcalls = 0;
03295 }
03296 break;
03297 case 'm':
03298 ast_set_flag(&ast_options, AST_OPT_FLAG_MUTE);
03299 break;
03300 case 'n':
03301 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_COLOR);
03302 break;
03303 case 'p':
03304 ast_set_flag(&ast_options, AST_OPT_FLAG_HIGH_PRIORITY);
03305 break;
03306 case 'q':
03307 ast_set_flag(&ast_options, AST_OPT_FLAG_QUIET);
03308 break;
03309 case 'R':
03310 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE | AST_OPT_FLAG_RECONNECT);
03311 break;
03312 case 'r':
03313 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE);
03314 break;
03315 case 's':
03316 remotesock = ast_strdupa(optarg);
03317 break;
03318 case 'T':
03319 ast_set_flag(&ast_options, AST_OPT_FLAG_TIMESTAMP);
03320 break;
03321 case 't':
03322 ast_set_flag(&ast_options, AST_OPT_FLAG_CACHE_RECORD_FILES);
03323 break;
03324 case 'U':
03325 runuser = ast_strdupa(optarg);
03326 break;
03327 case 'V':
03328 show_version();
03329 exit(0);
03330 case 'v':
03331 option_verbose++;
03332 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);
03333 break;
03334 case 'W':
03335 ast_set_flag(&ast_options, AST_OPT_FLAG_LIGHT_BACKGROUND);
03336 ast_clear_flag(&ast_options, AST_OPT_FLAG_FORCE_BLACK_BACKGROUND);
03337 break;
03338 case 'x':
03339 ast_set_flag(&ast_options, AST_OPT_FLAG_EXEC | AST_OPT_FLAG_NO_COLOR);
03340 xarg = ast_strdupa(optarg);
03341 break;
03342 case '?':
03343 exit(1);
03344 }
03345 }
03346
03347 if (ast_opt_console || option_verbose || (ast_opt_remote && !ast_opt_exec)) {
03348 if (ast_register_verbose(console_verboser)) {
03349 ast_log(LOG_WARNING, "Unable to register console verboser?\n");
03350 }
03351 WELCOME_MESSAGE;
03352 }
03353
03354 if (ast_opt_console && !option_verbose)
03355 ast_verbose("[ Booting...\n");
03356
03357
03358
03359
03360 if (ast_opt_remote) {
03361 strcpy(argv[0], "rasterisk");
03362 for (x = 1; x < argc; x++) {
03363 argv[x] = argv[0] + 10;
03364 }
03365 }
03366
03367 if (ast_opt_console && !option_verbose) {
03368 ast_verbose("[ Reading Master Configuration ]\n");
03369 }
03370
03371 ast_readconfig();
03372 env_init();
03373
03374 if (ast_opt_remote && remotesock != NULL)
03375 ast_copy_string((char *) cfg_paths.socket_path, remotesock, sizeof(cfg_paths.socket_path));
03376
03377 if (!ast_language_is_prefix && !ast_opt_remote)
03378 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");
03379
03380 if (ast_opt_always_fork && (ast_opt_remote || ast_opt_console)) {
03381 ast_log(LOG_WARNING, "'alwaysfork' is not compatible with console or remote console mode; ignored\n");
03382 ast_clear_flag(&ast_options, AST_OPT_FLAG_ALWAYS_FORK);
03383 }
03384
03385 if (ast_opt_dump_core) {
03386 memset(&l, 0, sizeof(l));
03387 l.rlim_cur = RLIM_INFINITY;
03388 l.rlim_max = RLIM_INFINITY;
03389 if (setrlimit(RLIMIT_CORE, &l)) {
03390 ast_log(LOG_WARNING, "Unable to disable core size resource limit: %s\n", strerror(errno));
03391 }
03392 }
03393
03394 if (getrlimit(RLIMIT_NOFILE, &l)) {
03395 ast_log(LOG_WARNING, "Unable to check file descriptor limit: %s\n", strerror(errno));
03396 }
03397
03398 #if !defined(CONFIGURE_RAN_AS_ROOT)
03399
03400 do {
03401 int fd, fd2;
03402 ast_fdset readers;
03403 struct timeval tv = { 0, };
03404
03405 if (l.rlim_cur <= FD_SETSIZE) {
03406
03407
03408 break;
03409 }
03410
03411 if (!(fd = open("/dev/null", O_RDONLY))) {
03412 ast_log(LOG_ERROR, "Cannot open a file descriptor at boot? %s\n", strerror(errno));
03413 break;
03414 }
03415
03416 fd2 = (l.rlim_cur > sizeof(readers) * 8 ? sizeof(readers) * 8 : l.rlim_cur) - 1;
03417 if (dup2(fd, fd2) < 0) {
03418 ast_log(LOG_WARNING, "Cannot open maximum file descriptor %d at boot? %s\n", fd2, strerror(errno));
03419 close(fd);
03420 break;
03421 }
03422
03423 FD_ZERO(&readers);
03424 FD_SET(fd2, &readers);
03425 if (ast_select(fd2 + 1, &readers, NULL, NULL, &tv) < 0) {
03426 ast_log(LOG_WARNING, "Maximum select()able file descriptor is %d\n", FD_SETSIZE);
03427 }
03428 ast_FD_SETSIZE = l.rlim_cur > ast_FDMAX ? ast_FDMAX : l.rlim_cur;
03429 close(fd);
03430 close(fd2);
03431 } while (0);
03432 #elif defined(HAVE_VARIABLE_FDSET)
03433 ast_FD_SETSIZE = l.rlim_cur > ast_FDMAX ? ast_FDMAX : l.rlim_cur;
03434 #endif
03435
03436 if ((!rungroup) && !ast_strlen_zero(ast_config_AST_RUN_GROUP))
03437 rungroup = ast_config_AST_RUN_GROUP;
03438 if ((!runuser) && !ast_strlen_zero(ast_config_AST_RUN_USER))
03439 runuser = ast_config_AST_RUN_USER;
03440
03441
03442
03443
03444 sigaction(SIGCHLD, &child_handler, NULL);
03445
03446
03447
03448 if (mkdir(ast_config_AST_RUN_DIR, 0755)) {
03449 if (errno == EEXIST) {
03450 rundir_exists = 1;
03451 } else {
03452 ast_log(LOG_WARNING, "Unable to create socket file directory. Remote consoles will not be able to connect! (%s)\n", strerror(x));
03453 }
03454 }
03455
03456 #ifndef __CYGWIN__
03457
03458 if (isroot) {
03459 ast_set_priority(ast_opt_high_priority);
03460 }
03461
03462 if (isroot && rungroup) {
03463 struct group *gr;
03464 gr = getgrnam(rungroup);
03465 if (!gr) {
03466 ast_log(LOG_WARNING, "No such group '%s'!\n", rungroup);
03467 exit(1);
03468 }
03469 if (!rundir_exists && chown(ast_config_AST_RUN_DIR, -1, gr->gr_gid)) {
03470 ast_log(LOG_WARNING, "Unable to chgrp run directory to %d (%s)\n", (int) gr->gr_gid, rungroup);
03471 }
03472 if (setgid(gr->gr_gid)) {
03473 ast_log(LOG_WARNING, "Unable to setgid to %d (%s)\n", (int)gr->gr_gid, rungroup);
03474 exit(1);
03475 }
03476 if (setgroups(0, NULL)) {
03477 ast_log(LOG_WARNING, "Unable to drop unneeded groups\n");
03478 exit(1);
03479 }
03480 if (option_verbose)
03481 ast_verbose("Running as group '%s'\n", rungroup);
03482 }
03483
03484 if (runuser && !ast_test_flag(&ast_options, AST_OPT_FLAG_REMOTE)) {
03485 #ifdef HAVE_CAP
03486 int has_cap = 1;
03487 #endif
03488 struct passwd *pw;
03489 pw = getpwnam(runuser);
03490 if (!pw) {
03491 ast_log(LOG_WARNING, "No such user '%s'!\n", runuser);
03492 exit(1);
03493 }
03494 if (chown(ast_config_AST_RUN_DIR, pw->pw_uid, -1)) {
03495 ast_log(LOG_WARNING, "Unable to chown run directory to %d (%s)\n", (int) pw->pw_uid, runuser);
03496 }
03497 #ifdef HAVE_CAP
03498 if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0)) {
03499 ast_log(LOG_WARNING, "Unable to keep capabilities.\n");
03500 has_cap = 0;
03501 }
03502 #endif
03503 if (!isroot && pw->pw_uid != geteuid()) {
03504 ast_log(LOG_ERROR, "Asterisk started as nonroot, but runuser '%s' requested.\n", runuser);
03505 exit(1);
03506 }
03507 if (!rungroup) {
03508 if (setgid(pw->pw_gid)) {
03509 ast_log(LOG_WARNING, "Unable to setgid to %d!\n", (int)pw->pw_gid);
03510 exit(1);
03511 }
03512 if (isroot && initgroups(pw->pw_name, pw->pw_gid)) {
03513 ast_log(LOG_WARNING, "Unable to init groups for '%s'\n", runuser);
03514 exit(1);
03515 }
03516 }
03517 if (setuid(pw->pw_uid)) {
03518 ast_log(LOG_WARNING, "Unable to setuid to %d (%s)\n", (int)pw->pw_uid, runuser);
03519 exit(1);
03520 }
03521 if (option_verbose)
03522 ast_verbose("Running as user '%s'\n", runuser);
03523 #ifdef HAVE_CAP
03524 if (has_cap) {
03525 cap_t cap;
03526
03527 cap = cap_from_text("cap_net_admin=eip");
03528
03529 if (cap_set_proc(cap))
03530 ast_log(LOG_WARNING, "Unable to install capabilities.\n");
03531
03532 if (cap_free(cap))
03533 ast_log(LOG_WARNING, "Unable to drop capabilities.\n");
03534 }
03535 #endif
03536 }
03537
03538 #endif
03539
03540 #ifdef linux
03541 if (geteuid() && ast_opt_dump_core) {
03542 if (prctl(PR_SET_DUMPABLE, 1, 0, 0, 0) < 0) {
03543 ast_log(LOG_WARNING, "Unable to set the process for core dumps after changing to a non-root user. %s\n", strerror(errno));
03544 }
03545 }
03546 #endif
03547
03548 {
03549 #if defined(HAVE_EACCESS) || defined(HAVE_EUIDACCESS)
03550 #if defined(HAVE_EUIDACCESS) && !defined(HAVE_EACCESS)
03551 #define eaccess euidaccess
03552 #endif
03553 char dir[PATH_MAX];
03554 if (!getcwd(dir, sizeof(dir)) || eaccess(dir, R_OK | X_OK | F_OK)) {
03555 ast_log(LOG_ERROR, "Unable to access the running directory (%s). Changing to '/' for compatibility.\n", strerror(errno));
03556
03557
03558 if (chdir("/")) {
03559
03560 ast_log(LOG_ERROR, "chdir(\"/\") failed?!! %s\n", strerror(errno));
03561 }
03562 } else
03563 #endif
03564 if (!ast_opt_no_fork && !ast_opt_dump_core) {
03565
03566 if (chdir("/")) {
03567 ast_log(LOG_ERROR, "Unable to chdir(\"/\") ?!! %s\n", strerror(errno));
03568 }
03569 }
03570 }
03571
03572 ast_term_init();
03573 printf("%s", term_end());
03574 fflush(stdout);
03575
03576 if (ast_opt_console && !option_verbose)
03577 ast_verbose("[ Initializing Custom Configuration Options ]\n");
03578
03579 register_config_cli();
03580 read_config_maps();
03581
03582 if (ast_opt_console) {
03583 if (el_hist == NULL || el == NULL)
03584 ast_el_initialize();
03585
03586 if (!ast_strlen_zero(filename))
03587 ast_el_read_history(filename);
03588 }
03589
03590 if (ast_tryconnect()) {
03591
03592 if (ast_opt_remote) {
03593 if (ast_opt_exec) {
03594 ast_remotecontrol(xarg);
03595 quit_handler(0, 0, 0, 0);
03596 exit(0);
03597 }
03598 printf("%s", term_quit());
03599 ast_remotecontrol(NULL);
03600 quit_handler(0, 0, 0, 0);
03601 exit(0);
03602 } else {
03603 ast_log(LOG_ERROR, "Asterisk already running on %s. Use 'asterisk -r' to connect.\n", ast_config_AST_SOCKET);
03604 printf("%s", term_quit());
03605 exit(1);
03606 }
03607 } else if (ast_opt_remote || ast_opt_exec) {
03608 ast_log(LOG_ERROR, "Unable to connect to remote asterisk (does %s exist?)\n", ast_config_AST_SOCKET);
03609 printf("%s", term_quit());
03610 exit(1);
03611 }
03612
03613 unlink(ast_config_AST_PID);
03614 f = fopen(ast_config_AST_PID, "w");
03615 if (f) {
03616 fprintf(f, "%ld\n", (long)getpid());
03617 fclose(f);
03618 } else
03619 ast_log(LOG_WARNING, "Unable to open pid file '%s': %s\n", ast_config_AST_PID, strerror(errno));
03620
03621 #if HAVE_WORKING_FORK
03622 if (ast_opt_always_fork || !ast_opt_no_fork) {
03623 #ifndef HAVE_SBIN_LAUNCHD
03624 if (daemon(1, 0) < 0) {
03625 ast_log(LOG_ERROR, "daemon() failed: %s\n", strerror(errno));
03626 }
03627 ast_mainpid = getpid();
03628
03629 unlink(ast_config_AST_PID);
03630 f = fopen(ast_config_AST_PID, "w");
03631 if (f) {
03632 fprintf(f, "%ld\n", (long)ast_mainpid);
03633 fclose(f);
03634 } else
03635 ast_log(LOG_WARNING, "Unable to open pid file '%s': %s\n", ast_config_AST_PID, strerror(errno));
03636 #else
03637 ast_log(LOG_WARNING, "Mac OS X detected. Use 'launchctl load /Library/LaunchDaemon/org.asterisk.asterisk.plist'.\n");
03638 #endif
03639 }
03640 #endif
03641
03642
03643 if (isroot && ast_opt_high_priority) {
03644 snprintf(canary_filename, sizeof(canary_filename), "%s/alt.asterisk.canary.tweet.tweet.tweet", ast_config_AST_RUN_DIR);
03645
03646
03647 sigaction(SIGPIPE, &ignore_sig_handler, NULL);
03648
03649 canary_pid = fork();
03650 if (canary_pid == 0) {
03651 char canary_binary[128], *lastslash, ppid[12];
03652
03653
03654 signal(SIGCHLD, SIG_DFL);
03655 signal(SIGPIPE, SIG_DFL);
03656
03657 ast_close_fds_above_n(0);
03658 ast_set_priority(0);
03659 snprintf(ppid, sizeof(ppid), "%d", (int) ast_mainpid);
03660
03661 execlp("astcanary", "astcanary", canary_filename, ppid, (char *)NULL);
03662
03663
03664 ast_copy_string(canary_binary, argv[0], sizeof(canary_binary));
03665 if ((lastslash = strrchr(canary_binary, '/'))) {
03666 ast_copy_string(lastslash + 1, "astcanary", sizeof(canary_binary) + canary_binary - (lastslash + 1));
03667 execl(canary_binary, "astcanary", canary_filename, ppid, (char *)NULL);
03668 }
03669
03670
03671 _exit(1);
03672 } else if (canary_pid > 0) {
03673 pthread_t dont_care;
03674 ast_pthread_create_detached(&dont_care, NULL, canary_thread, NULL);
03675 }
03676
03677
03678 ast_register_atexit(canary_exit);
03679 }
03680
03681 if (ast_event_init()) {
03682 printf("%s", term_quit());
03683 exit(1);
03684 }
03685
03686 #ifdef TEST_FRAMEWORK
03687 if (ast_test_init()) {
03688 printf("%s", term_quit());
03689 exit(1);
03690 }
03691 #endif
03692
03693 ast_aoc_cli_init();
03694
03695 ast_makesocket();
03696 sigemptyset(&sigs);
03697 sigaddset(&sigs, SIGHUP);
03698 sigaddset(&sigs, SIGTERM);
03699 sigaddset(&sigs, SIGINT);
03700 sigaddset(&sigs, SIGPIPE);
03701 sigaddset(&sigs, SIGWINCH);
03702 pthread_sigmask(SIG_BLOCK, &sigs, NULL);
03703 sigaction(SIGURG, &urg_handler, NULL);
03704 signal(SIGINT, __quit_handler);
03705 signal(SIGTERM, __quit_handler);
03706 sigaction(SIGHUP, &hup_handler, NULL);
03707 sigaction(SIGPIPE, &ignore_sig_handler, NULL);
03708
03709
03710
03711
03712 srand((unsigned int) getpid() + (unsigned int) time(NULL));
03713 initstate((unsigned int) getpid() * 65536 + (unsigned int) time(NULL), randompool, sizeof(randompool));
03714
03715 if (init_logger()) {
03716 printf("%s", term_quit());
03717 exit(1);
03718 }
03719
03720 threadstorage_init();
03721
03722 astobj2_init();
03723
03724 ast_autoservice_init();
03725
03726 if (ast_timing_init()) {
03727 printf("%s", term_quit());
03728 exit(1);
03729 }
03730
03731 if (ast_ssl_init()) {
03732 printf("%s", term_quit());
03733 exit(1);
03734 }
03735
03736 #ifdef AST_XML_DOCS
03737
03738 ast_xmldoc_load_documentation();
03739 #endif
03740
03741
03742 if (ast_data_init()) {
03743 printf ("%s", term_quit());
03744 exit(1);
03745 }
03746
03747 ast_channels_init();
03748
03749 if ((moduleresult = load_modules(1))) {
03750 printf("%s", term_quit());
03751 exit(moduleresult == -2 ? 2 : 1);
03752 }
03753
03754 if (dnsmgr_init()) {
03755 printf("%s", term_quit());
03756 exit(1);
03757 }
03758
03759 ast_http_init();
03760
03761 if (init_manager()) {
03762 printf("%s", term_quit());
03763 exit(1);
03764 }
03765
03766 if (ast_cdr_engine_init()) {
03767 printf("%s", term_quit());
03768 exit(1);
03769 }
03770
03771 if (ast_cel_engine_init()) {
03772 printf("%s", term_quit());
03773 exit(1);
03774 }
03775
03776 if (ast_device_state_engine_init()) {
03777 printf("%s", term_quit());
03778 exit(1);
03779 }
03780
03781 ast_dsp_init();
03782 ast_udptl_init();
03783
03784 if (ast_image_init()) {
03785 printf("%s", term_quit());
03786 exit(1);
03787 }
03788
03789 if (ast_file_init()) {
03790 printf("%s", term_quit());
03791 exit(1);
03792 }
03793
03794 if (load_pbx()) {
03795 printf("%s", term_quit());
03796 exit(1);
03797 }
03798
03799 if (ast_indications_init()) {
03800 printf("%s", term_quit());
03801 exit(1);
03802 }
03803
03804 if (ast_features_init()) {
03805 printf("%s", term_quit());
03806 exit(1);
03807 }
03808
03809 if (init_framer()) {
03810 printf("%s", term_quit());
03811 exit(1);
03812 }
03813
03814 if (astdb_init()) {
03815 printf("%s", term_quit());
03816 exit(1);
03817 }
03818
03819 if (ast_enum_init()) {
03820 printf("%s", term_quit());
03821 exit(1);
03822 }
03823
03824 if (ast_cc_init()) {
03825 printf("%s", term_quit());
03826 exit(1);
03827 }
03828
03829 if ((moduleresult = load_modules(0))) {
03830 printf("%s", term_quit());
03831 exit(moduleresult == -2 ? 2 : 1);
03832 }
03833
03834
03835 ast_cli_perms_init(0);
03836
03837 ast_stun_init();
03838
03839 dnsmgr_start_refresh();
03840
03841
03842
03843 if (ast_opt_console && !option_verbose)
03844 ast_verbose(" ]\n");
03845 if (option_verbose || ast_opt_console)
03846 ast_verbose("%s", term_color(tmp, "Asterisk Ready.\n", COLOR_BRWHITE, COLOR_BLACK, sizeof(tmp)));
03847 if (ast_opt_no_fork)
03848 consolethread = pthread_self();
03849
03850 if (pipe(sig_alert_pipe))
03851 sig_alert_pipe[0] = sig_alert_pipe[1] = -1;
03852
03853 ast_set_flag(&ast_options, AST_OPT_FLAG_FULLY_BOOTED);
03854 manager_event(EVENT_FLAG_SYSTEM, "FullyBooted", "Status: Fully Booted\r\n");
03855
03856 ast_process_pending_reloads();
03857
03858 pthread_sigmask(SIG_UNBLOCK, &sigs, NULL);
03859
03860 #ifdef __AST_DEBUG_MALLOC
03861 __ast_mm_init();
03862 #endif
03863
03864 ast_lastreloadtime = ast_startuptime = ast_tvnow();
03865 ast_cli_register_multiple(cli_asterisk, ARRAY_LEN(cli_asterisk));
03866
03867 run_startup_commands();
03868
03869 if (ast_opt_console) {
03870
03871
03872 char title[256];
03873
03874 ast_pthread_create_detached(&mon_sig_flags, NULL, monitor_sig_flags, NULL);
03875
03876 set_icon("Asterisk");
03877 snprintf(title, sizeof(title), "Asterisk Console on '%s' (pid %ld)", hostname, (long)ast_mainpid);
03878 set_title(title);
03879
03880 el_set(el, EL_GETCFN, ast_el_read_char);
03881
03882 for (;;) {
03883 if (sig_flags.need_quit || sig_flags.need_quit_handler) {
03884 quit_handler(0, 0, 0, 0);
03885 break;
03886 }
03887 buf = (char *) el_gets(el, &num);
03888
03889 if (!buf && write(1, "", 1) < 0)
03890 goto lostterm;
03891
03892 if (buf) {
03893 if (buf[strlen(buf)-1] == '\n')
03894 buf[strlen(buf)-1] = '\0';
03895
03896 consolehandler((char *)buf);
03897 } else if (ast_opt_remote && (write(STDOUT_FILENO, "\nUse EXIT or QUIT to exit the asterisk console\n",
03898 strlen("\nUse EXIT or QUIT to exit the asterisk console\n")) < 0)) {
03899
03900 int fd;
03901 fd = open("/dev/null", O_RDWR);
03902 if (fd > -1) {
03903 dup2(fd, STDOUT_FILENO);
03904 dup2(fd, STDIN_FILENO);
03905 } else
03906 ast_log(LOG_WARNING, "Failed to open /dev/null to recover from dead console. Bad things will happen!\n");
03907 break;
03908 }
03909 }
03910 }
03911
03912 monitor_sig_flags(NULL);
03913
03914 lostterm:
03915 return 0;
03916 }