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