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