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