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