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