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