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