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