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