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