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
00061 #include <unistd.h>
00062 #include <stdlib.h>
00063 #include <sys/time.h>
00064 #include <fcntl.h>
00065 #include <stdio.h>
00066 #include <signal.h>
00067 #include <sched.h>
00068 #include <sys/socket.h>
00069 #include <sys/un.h>
00070 #include <sys/wait.h>
00071 #include <string.h>
00072 #include <errno.h>
00073 #include <ctype.h>
00074 #include <sys/resource.h>
00075 #include <grp.h>
00076 #include <pwd.h>
00077 #include <sys/stat.h>
00078 #include <regex.h>
00079
00080 #ifdef linux
00081 #include <sys/prctl.h>
00082 #endif
00083
00084 #if defined(__FreeBSD__) || defined( __NetBSD__ ) || defined(SOLARIS)
00085 #include <netdb.h>
00086 #if defined(SOLARIS)
00087 extern int daemon(int, int);
00088 #endif
00089 #endif
00090
00091 #include "asterisk.h"
00092
00093 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 40798 $")
00094
00095 #include "asterisk/logger.h"
00096 #include "asterisk/options.h"
00097 #include "asterisk/cli.h"
00098 #include "asterisk/channel.h"
00099 #include "asterisk/ulaw.h"
00100 #include "asterisk/alaw.h"
00101 #include "asterisk/callerid.h"
00102 #include "asterisk/module.h"
00103 #include "asterisk/image.h"
00104 #include "asterisk/tdd.h"
00105 #include "asterisk/term.h"
00106 #include "asterisk/manager.h"
00107 #include "asterisk/cdr.h"
00108 #include "asterisk/pbx.h"
00109 #include "asterisk/enum.h"
00110 #include "asterisk/rtp.h"
00111 #include "asterisk/app.h"
00112 #include "asterisk/lock.h"
00113 #include "asterisk/utils.h"
00114 #include "asterisk/file.h"
00115 #include "asterisk/io.h"
00116 #include "asterisk/lock.h"
00117 #include "editline/histedit.h"
00118 #include "asterisk/config.h"
00119 #include "asterisk/version.h"
00120 #include "asterisk/linkedlists.h"
00121 #include "asterisk/devicestate.h"
00122 #include "asterisk/compat.h"
00123
00124 #include "asterisk/doxyref.h"
00125
00126 #include "defaults.h"
00127
00128 #ifndef AF_LOCAL
00129 #define AF_LOCAL AF_UNIX
00130 #define PF_LOCAL PF_UNIX
00131 #endif
00132
00133 #define AST_MAX_CONNECTS 128
00134 #define NUM_MSGS 64
00135
00136
00137 #define WELCOME_MESSAGE \
00138 ast_verbose("Asterisk " ASTERISK_VERSION ", Copyright (C) 1999 - 2006 Digium, Inc. and others.\n"); \
00139 ast_verbose("Created by Mark Spencer <markster@digium.com>\n"); \
00140 ast_verbose("Asterisk comes with ABSOLUTELY NO WARRANTY; type 'show warranty' for details.\n"); \
00141 ast_verbose("This is free software, with components licensed under the GNU General Public\n"); \
00142 ast_verbose("License version 2 and other licenses; you are welcome to redistribute it under\n"); \
00143 ast_verbose("certain conditions. Type 'show license' for details.\n"); \
00144 ast_verbose("=========================================================================\n")
00145
00146
00147
00148
00149
00150
00151
00152 int option_verbose=0;
00153 int option_debug=0;
00154 int option_exec_includes=0;
00155 int option_nofork=0;
00156 int option_quiet=0;
00157 int option_console=0;
00158 int option_daemonize=0;
00159 int option_highpriority=0;
00160 int option_remote=0;
00161 int option_exec=0;
00162 int option_initcrypto=0;
00163 int option_nocolor;
00164 int option_dumpcore = 0;
00165 int option_cache_record_files = 0;
00166 int option_timestamp = 0;
00167 int option_overrideconfig = 0;
00168 int option_reconnect = 0;
00169 int option_transcode_slin = 1;
00170 int option_maxcalls = 0;
00171 double option_maxload = 0.0;
00172 int option_dontwarn = 0;
00173 int option_priority_jumping = 1;
00174 int option_transmit_silence_during_record = 0;
00175
00176
00177
00178 int fully_booted = 0;
00179 char record_cache_dir[AST_CACHE_DIR_LEN] = AST_TMP_DIR;
00180 char debug_filename[AST_FILENAME_MAX] = "";
00181
00182 static int ast_socket = -1;
00183 static int ast_consock = -1;
00184 int ast_mainpid;
00185 struct console {
00186 int fd;
00187 int p[2];
00188 pthread_t t;
00189 };
00190
00191 static struct ast_atexit {
00192 void (*func)(void);
00193 struct ast_atexit *next;
00194 } *atexits = NULL;
00195
00196 AST_MUTEX_DEFINE_STATIC(atexitslock);
00197
00198 time_t ast_startuptime;
00199 time_t ast_lastreloadtime;
00200
00201 static History *el_hist = NULL;
00202 static EditLine *el = NULL;
00203 static char *remotehostname;
00204
00205 struct console consoles[AST_MAX_CONNECTS];
00206
00207 char defaultlanguage[MAX_LANGUAGE] = DEFAULT_LANGUAGE;
00208
00209 static int ast_el_add_history(char *);
00210 static int ast_el_read_history(char *);
00211 static int ast_el_write_history(char *);
00212
00213 char ast_config_AST_CONFIG_DIR[AST_CONFIG_MAX_PATH];
00214 char ast_config_AST_CONFIG_FILE[AST_CONFIG_MAX_PATH];
00215 char ast_config_AST_MODULE_DIR[AST_CONFIG_MAX_PATH];
00216 char ast_config_AST_SPOOL_DIR[AST_CONFIG_MAX_PATH];
00217 char ast_config_AST_MONITOR_DIR[AST_CONFIG_MAX_PATH];
00218 char ast_config_AST_VAR_DIR[AST_CONFIG_MAX_PATH];
00219 char ast_config_AST_DATA_DIR[AST_CONFIG_MAX_PATH];
00220 char ast_config_AST_LOG_DIR[AST_CONFIG_MAX_PATH];
00221 char ast_config_AST_AGI_DIR[AST_CONFIG_MAX_PATH];
00222 char ast_config_AST_DB[AST_CONFIG_MAX_PATH];
00223 char ast_config_AST_KEY_DIR[AST_CONFIG_MAX_PATH];
00224 char ast_config_AST_PID[AST_CONFIG_MAX_PATH];
00225 char ast_config_AST_SOCKET[AST_CONFIG_MAX_PATH];
00226 char ast_config_AST_RUN_DIR[AST_CONFIG_MAX_PATH];
00227 char ast_config_AST_RUN_USER[AST_CONFIG_MAX_PATH];
00228 char ast_config_AST_RUN_GROUP[AST_CONFIG_MAX_PATH];
00229 char ast_config_AST_CTL_PERMISSIONS[AST_CONFIG_MAX_PATH];
00230 char ast_config_AST_CTL_OWNER[AST_CONFIG_MAX_PATH] = "\0";
00231 char ast_config_AST_CTL_GROUP[AST_CONFIG_MAX_PATH] = "\0";
00232 char ast_config_AST_CTL[AST_CONFIG_MAX_PATH] = "asterisk.ctl";
00233
00234 static char *_argv[256];
00235 static int shuttingdown = 0;
00236 static int restartnow = 0;
00237 static pthread_t consolethread = AST_PTHREADT_NULL;
00238
00239 #if !defined(LOW_MEMORY)
00240 struct file_version {
00241 AST_LIST_ENTRY(file_version) list;
00242 const char *file;
00243 char *version;
00244 };
00245
00246 static AST_LIST_HEAD_STATIC(file_versions, file_version);
00247
00248 void ast_register_file_version(const char *file, const char *version)
00249 {
00250 struct file_version *new;
00251 char *work;
00252 size_t version_length;
00253
00254 work = ast_strdupa(version);
00255 work = ast_strip(ast_strip_quoted(work, "$", "$"));
00256 version_length = strlen(work) + 1;
00257
00258 new = calloc(1, sizeof(*new) + version_length);
00259 if (!new)
00260 return;
00261
00262 new->file = file;
00263 new->version = (char *) new + sizeof(*new);
00264 memcpy(new->version, work, version_length);
00265 AST_LIST_LOCK(&file_versions);
00266 AST_LIST_INSERT_HEAD(&file_versions, new, list);
00267 AST_LIST_UNLOCK(&file_versions);
00268 }
00269
00270 void ast_unregister_file_version(const char *file)
00271 {
00272 struct file_version *find;
00273
00274 AST_LIST_LOCK(&file_versions);
00275 AST_LIST_TRAVERSE_SAFE_BEGIN(&file_versions, find, list) {
00276 if (!strcasecmp(find->file, file)) {
00277 AST_LIST_REMOVE_CURRENT(&file_versions, list);
00278 break;
00279 }
00280 }
00281 AST_LIST_TRAVERSE_SAFE_END;
00282 AST_LIST_UNLOCK(&file_versions);
00283 if (find)
00284 free(find);
00285 }
00286
00287 static char show_version_files_help[] =
00288 "Usage: show version files [like <pattern>]\n"
00289 " Shows the revision numbers of the files used to build this copy of Asterisk.\n"
00290 " Optional regular expression pattern is used to filter the file list.\n";
00291
00292
00293 static int handle_show_version_files(int fd, int argc, char *argv[])
00294 {
00295 #define FORMAT "%-25.25s %-40.40s\n"
00296 struct file_version *iterator;
00297 regex_t regexbuf;
00298 int havepattern = 0;
00299 int havename = 0;
00300 int count_files = 0;
00301
00302 switch (argc) {
00303 case 5:
00304 if (!strcasecmp(argv[3], "like")) {
00305 if (regcomp(®exbuf, argv[4], REG_EXTENDED | REG_NOSUB))
00306 return RESULT_SHOWUSAGE;
00307 havepattern = 1;
00308 } else
00309 return RESULT_SHOWUSAGE;
00310 break;
00311 case 4:
00312 havename = 1;
00313 break;
00314 case 3:
00315 break;
00316 default:
00317 return RESULT_SHOWUSAGE;
00318 }
00319
00320 ast_cli(fd, FORMAT, "File", "Revision");
00321 ast_cli(fd, FORMAT, "----", "--------");
00322 AST_LIST_LOCK(&file_versions);
00323 AST_LIST_TRAVERSE(&file_versions, iterator, list) {
00324 if (havename && strcasecmp(iterator->file, argv[3]))
00325 continue;
00326
00327 if (havepattern && regexec(®exbuf, iterator->file, 0, NULL, 0))
00328 continue;
00329
00330 ast_cli(fd, FORMAT, iterator->file, iterator->version);
00331 count_files++;
00332 if (havename)
00333 break;
00334 }
00335 AST_LIST_UNLOCK(&file_versions);
00336 if (!havename) {
00337 ast_cli(fd, "%d files listed.\n", count_files);
00338 }
00339
00340 if (havepattern)
00341 regfree(®exbuf);
00342
00343 return RESULT_SUCCESS;
00344 #undef FORMAT
00345 }
00346
00347 static char *complete_show_version_files(char *line, char *word, int pos, int state)
00348 {
00349 struct file_version *find;
00350 int which = 0;
00351 char *ret = NULL;
00352 int matchlen = strlen(word);
00353
00354 if (pos != 3)
00355 return NULL;
00356
00357 AST_LIST_LOCK(&file_versions);
00358 AST_LIST_TRAVERSE(&file_versions, find, list) {
00359 if (!strncasecmp(word, find->file, matchlen)) {
00360 if (++which > state) {
00361 ret = strdup(find->file);
00362 break;
00363 }
00364 }
00365 }
00366 AST_LIST_UNLOCK(&file_versions);
00367
00368 return ret;
00369 }
00370 #endif
00371
00372 int ast_register_atexit(void (*func)(void))
00373 {
00374 int res = -1;
00375 struct ast_atexit *ae;
00376 ast_unregister_atexit(func);
00377 ae = malloc(sizeof(struct ast_atexit));
00378 ast_mutex_lock(&atexitslock);
00379 if (ae) {
00380 memset(ae, 0, sizeof(struct ast_atexit));
00381 ae->next = atexits;
00382 ae->func = func;
00383 atexits = ae;
00384 res = 0;
00385 }
00386 ast_mutex_unlock(&atexitslock);
00387 return res;
00388 }
00389
00390 void ast_unregister_atexit(void (*func)(void))
00391 {
00392 struct ast_atexit *ae, *prev = NULL;
00393 ast_mutex_lock(&atexitslock);
00394 ae = atexits;
00395 while(ae) {
00396 if (ae->func == func) {
00397 if (prev)
00398 prev->next = ae->next;
00399 else
00400 atexits = ae->next;
00401 break;
00402 }
00403 prev = ae;
00404 ae = ae->next;
00405 }
00406 ast_mutex_unlock(&atexitslock);
00407 }
00408
00409 static int fdprint(int fd, const char *s)
00410 {
00411 return write(fd, s, strlen(s) + 1);
00412 }
00413
00414
00415 static void null_sig_handler(int signal)
00416 {
00417
00418 }
00419
00420 AST_MUTEX_DEFINE_STATIC(safe_system_lock);
00421 static unsigned int safe_system_level = 0;
00422 static void *safe_system_prev_handler;
00423
00424 int ast_safe_system(const char *s)
00425 {
00426 pid_t pid;
00427 int x;
00428 int res;
00429 struct rusage rusage;
00430 int status;
00431 unsigned int level;
00432
00433
00434
00435
00436 ast_mutex_lock(&safe_system_lock);
00437 level = safe_system_level++;
00438
00439
00440 if (level == 0)
00441 safe_system_prev_handler = signal(SIGCHLD, null_sig_handler);
00442
00443 ast_mutex_unlock(&safe_system_lock);
00444
00445 pid = fork();
00446
00447 if (pid == 0) {
00448 if (option_highpriority)
00449 ast_set_priority(0);
00450
00451 for (x = STDERR_FILENO + 1; x < 4096; x++)
00452 close(x);
00453 execl("/bin/sh", "/bin/sh", "-c", s, NULL);
00454 exit(1);
00455 } else if (pid > 0) {
00456 for(;;) {
00457 res = wait4(pid, &status, 0, &rusage);
00458 if (res > -1) {
00459 res = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
00460 break;
00461 } else if (errno != EINTR)
00462 break;
00463 }
00464 } else {
00465 ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno));
00466 res = -1;
00467 }
00468
00469 ast_mutex_lock(&safe_system_lock);
00470 level = --safe_system_level;
00471
00472
00473 if (level == 0)
00474 signal(SIGCHLD, safe_system_prev_handler);
00475
00476 ast_mutex_unlock(&safe_system_lock);
00477
00478 return res;
00479 }
00480
00481
00482
00483
00484 static void ast_network_puts(const char *string)
00485 {
00486 int x;
00487 for (x=0;x<AST_MAX_CONNECTS; x++) {
00488 if (consoles[x].fd > -1)
00489 fdprint(consoles[x].p[1], string);
00490 }
00491 }
00492
00493
00494
00495
00496
00497 void ast_console_puts(const char *string)
00498 {
00499 fputs(string, stdout);
00500 fflush(stdout);
00501 ast_network_puts(string);
00502 }
00503
00504 static void network_verboser(const char *s, int pos, int replace, int complete)
00505
00506 {
00507 if (replace) {
00508 char *t = alloca(strlen(s) + 2);
00509 if (t) {
00510 sprintf(t, "\r%s", s);
00511 if (complete)
00512 ast_network_puts(t);
00513 } else {
00514 ast_log(LOG_ERROR, "Out of memory\n");
00515 ast_network_puts(s);
00516 }
00517 } else {
00518 if (complete)
00519 ast_network_puts(s);
00520 }
00521 }
00522
00523 static pthread_t lthread;
00524
00525 static void *netconsole(void *vconsole)
00526 {
00527 struct console *con = vconsole;
00528 char hostname[MAXHOSTNAMELEN]="";
00529 char tmp[512];
00530 int res;
00531 struct pollfd fds[2];
00532
00533 if (gethostname(hostname, sizeof(hostname)-1))
00534 ast_copy_string(hostname, "<Unknown>", sizeof(hostname));
00535 snprintf(tmp, sizeof(tmp), "%s/%d/%s\n", hostname, ast_mainpid, ASTERISK_VERSION);
00536 fdprint(con->fd, tmp);
00537 for(;;) {
00538 fds[0].fd = con->fd;
00539 fds[0].events = POLLIN;
00540 fds[0].revents = 0;
00541 fds[1].fd = con->p[0];
00542 fds[1].events = POLLIN;
00543 fds[1].revents = 0;
00544
00545 res = poll(fds, 2, -1);
00546 if (res < 0) {
00547 if (errno != EINTR)
00548 ast_log(LOG_WARNING, "poll returned < 0: %s\n", strerror(errno));
00549 continue;
00550 }
00551 if (fds[0].revents) {
00552 res = read(con->fd, tmp, sizeof(tmp));
00553 if (res < 1) {
00554 break;
00555 }
00556 tmp[res] = 0;
00557 ast_cli_command(con->fd, tmp);
00558 }
00559 if (fds[1].revents) {
00560 res = read(con->p[0], tmp, sizeof(tmp));
00561 if (res < 1) {
00562 ast_log(LOG_ERROR, "read returned %d\n", res);
00563 break;
00564 }
00565 res = write(con->fd, tmp, res);
00566 if (res < 1)
00567 break;
00568 }
00569 }
00570 if (option_verbose > 2)
00571 ast_verbose(VERBOSE_PREFIX_3 "Remote UNIX connection disconnected\n");
00572 close(con->fd);
00573 close(con->p[0]);
00574 close(con->p[1]);
00575 con->fd = -1;
00576
00577 return NULL;
00578 }
00579
00580 static void *listener(void *unused)
00581 {
00582 struct sockaddr_un sunaddr;
00583 int s;
00584 socklen_t len;
00585 int x;
00586 int flags;
00587 struct pollfd fds[1];
00588 pthread_attr_t attr;
00589 pthread_attr_init(&attr);
00590 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
00591 for(;;) {
00592 if (ast_socket < 0)
00593 return NULL;
00594 fds[0].fd = ast_socket;
00595 fds[0].events= POLLIN;
00596 s = poll(fds, 1, -1);
00597 pthread_testcancel();
00598 if (s < 0) {
00599 if (errno != EINTR)
00600 ast_log(LOG_WARNING, "poll returned error: %s\n", strerror(errno));
00601 continue;
00602 }
00603 len = sizeof(sunaddr);
00604 s = accept(ast_socket, (struct sockaddr *)&sunaddr, &len);
00605 if (s < 0) {
00606 if (errno != EINTR)
00607 ast_log(LOG_WARNING, "Accept returned %d: %s\n", s, strerror(errno));
00608 } else {
00609 for (x=0;x<AST_MAX_CONNECTS;x++) {
00610 if (consoles[x].fd < 0) {
00611 if (socketpair(AF_LOCAL, SOCK_STREAM, 0, consoles[x].p)) {
00612 ast_log(LOG_ERROR, "Unable to create pipe: %s\n", strerror(errno));
00613 consoles[x].fd = -1;
00614 fdprint(s, "Server failed to create pipe\n");
00615 close(s);
00616 break;
00617 }
00618 flags = fcntl(consoles[x].p[1], F_GETFL);
00619 fcntl(consoles[x].p[1], F_SETFL, flags | O_NONBLOCK);
00620 consoles[x].fd = s;
00621 if (ast_pthread_create(&consoles[x].t, &attr, netconsole, &consoles[x])) {
00622 ast_log(LOG_ERROR, "Unable to spawn thread to handle connection: %s\n", strerror(errno));
00623 close(consoles[x].p[0]);
00624 close(consoles[x].p[1]);
00625 consoles[x].fd = -1;
00626 fdprint(s, "Server failed to spawn thread\n");
00627 close(s);
00628 }
00629 break;
00630 }
00631 }
00632 if (x >= AST_MAX_CONNECTS) {
00633 fdprint(s, "No more connections allowed\n");
00634 ast_log(LOG_WARNING, "No more connections allowed\n");
00635 close(s);
00636 } else if (consoles[x].fd > -1) {
00637 if (option_verbose > 2)
00638 ast_verbose(VERBOSE_PREFIX_3 "Remote UNIX connection\n");
00639 }
00640 }
00641 }
00642 return NULL;
00643 }
00644
00645 static int ast_makesocket(void)
00646 {
00647 struct sockaddr_un sunaddr;
00648 int res;
00649 int x;
00650 uid_t uid = -1;
00651 gid_t gid = -1;
00652
00653 for (x = 0; x < AST_MAX_CONNECTS; x++)
00654 consoles[x].fd = -1;
00655 unlink(ast_config_AST_SOCKET);
00656 ast_socket = socket(PF_LOCAL, SOCK_STREAM, 0);
00657 if (ast_socket < 0) {
00658 ast_log(LOG_WARNING, "Unable to create control socket: %s\n", strerror(errno));
00659 return -1;
00660 }
00661 memset(&sunaddr, 0, sizeof(sunaddr));
00662 sunaddr.sun_family = AF_LOCAL;
00663 ast_copy_string(sunaddr.sun_path, ast_config_AST_SOCKET, sizeof(sunaddr.sun_path));
00664 res = bind(ast_socket, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
00665 if (res) {
00666 ast_log(LOG_WARNING, "Unable to bind socket to %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
00667 close(ast_socket);
00668 ast_socket = -1;
00669 return -1;
00670 }
00671 res = listen(ast_socket, 2);
00672 if (res < 0) {
00673 ast_log(LOG_WARNING, "Unable to listen on socket %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
00674 close(ast_socket);
00675 ast_socket = -1;
00676 return -1;
00677 }
00678 ast_register_verbose(network_verboser);
00679 ast_pthread_create(<hread, NULL, listener, NULL);
00680
00681 if (!ast_strlen_zero(ast_config_AST_CTL_OWNER)) {
00682 struct passwd *pw;
00683 if ((pw = getpwnam(ast_config_AST_CTL_OWNER)) == NULL) {
00684 ast_log(LOG_WARNING, "Unable to find uid of user %s\n", ast_config_AST_CTL_OWNER);
00685 } else {
00686 uid = pw->pw_uid;
00687 }
00688 }
00689
00690 if (!ast_strlen_zero(ast_config_AST_CTL_GROUP)) {
00691 struct group *grp;
00692 if ((grp = getgrnam(ast_config_AST_CTL_GROUP)) == NULL) {
00693 ast_log(LOG_WARNING, "Unable to find gid of group %s\n", ast_config_AST_CTL_GROUP);
00694 } else {
00695 gid = grp->gr_gid;
00696 }
00697 }
00698
00699 if (chown(ast_config_AST_SOCKET, uid, gid) < 0)
00700 ast_log(LOG_WARNING, "Unable to change ownership of %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
00701
00702 if (!ast_strlen_zero(ast_config_AST_CTL_PERMISSIONS)) {
00703 int p1;
00704 mode_t p;
00705 sscanf(ast_config_AST_CTL_PERMISSIONS, "%o", &p1);
00706 p = p1;
00707 if ((chmod(ast_config_AST_SOCKET, p)) < 0)
00708 ast_log(LOG_WARNING, "Unable to change file permissions of %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
00709 }
00710
00711 return 0;
00712 }
00713
00714 static int ast_tryconnect(void)
00715 {
00716 struct sockaddr_un sunaddr;
00717 int res;
00718 ast_consock = socket(PF_LOCAL, SOCK_STREAM, 0);
00719 if (ast_consock < 0) {
00720 ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno));
00721 return 0;
00722 }
00723 memset(&sunaddr, 0, sizeof(sunaddr));
00724 sunaddr.sun_family = AF_LOCAL;
00725 ast_copy_string(sunaddr.sun_path, (char *)ast_config_AST_SOCKET, sizeof(sunaddr.sun_path));
00726 res = connect(ast_consock, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
00727 if (res) {
00728 close(ast_consock);
00729 ast_consock = -1;
00730 return 0;
00731 } else
00732 return 1;
00733 }
00734
00735
00736
00737
00738
00739
00740 static void urg_handler(int num)
00741 {
00742 signal(num, urg_handler);
00743 return;
00744 }
00745
00746 static void hup_handler(int num)
00747 {
00748 if (option_verbose > 1)
00749 printf("Received HUP signal -- Reloading configs\n");
00750 if (restartnow)
00751 execvp(_argv[0], _argv);
00752
00753 ast_module_reload(NULL);
00754 signal(num, hup_handler);
00755 }
00756
00757 static void child_handler(int sig)
00758 {
00759
00760 int n, status;
00761
00762
00763
00764
00765 for (n = 0; wait4(-1, &status, WNOHANG, NULL) > 0; n++)
00766 ;
00767 if (n == 0 && option_debug)
00768 printf("Huh? Child handler, but nobody there?\n");
00769 signal(sig, child_handler);
00770 }
00771
00772
00773 static void set_title(char *text)
00774 {
00775 if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
00776 fprintf(stdout, "\033]2;%s\007", text);
00777 }
00778
00779 static void set_icon(char *text)
00780 {
00781 if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
00782 fprintf(stdout, "\033]1;%s\007", text);
00783 }
00784
00785
00786
00787 int ast_set_priority(int pri)
00788 {
00789 struct sched_param sched;
00790 memset(&sched, 0, sizeof(sched));
00791 #ifdef __linux__
00792 if (pri) {
00793 sched.sched_priority = 10;
00794 if (sched_setscheduler(0, SCHED_RR, &sched)) {
00795 ast_log(LOG_WARNING, "Unable to set high priority\n");
00796 return -1;
00797 } else
00798 if (option_verbose)
00799 ast_verbose("Set to realtime thread\n");
00800 } else {
00801 sched.sched_priority = 0;
00802 if (sched_setscheduler(0, SCHED_OTHER, &sched)) {
00803 ast_log(LOG_WARNING, "Unable to set normal priority\n");
00804 return -1;
00805 }
00806 }
00807 #else
00808 if (pri) {
00809 if (setpriority(PRIO_PROCESS, 0, -10) == -1) {
00810 ast_log(LOG_WARNING, "Unable to set high priority\n");
00811 return -1;
00812 } else
00813 if (option_verbose)
00814 ast_verbose("Set to high priority\n");
00815 } else {
00816 if (setpriority(PRIO_PROCESS, 0, 0) == -1) {
00817 ast_log(LOG_WARNING, "Unable to set normal priority\n");
00818 return -1;
00819 }
00820 }
00821 #endif
00822 return 0;
00823 }
00824
00825 static void ast_run_atexits(void)
00826 {
00827 struct ast_atexit *ae;
00828 ast_mutex_lock(&atexitslock);
00829 ae = atexits;
00830 while(ae) {
00831 if (ae->func)
00832 ae->func();
00833 ae = ae->next;
00834 }
00835 ast_mutex_unlock(&atexitslock);
00836 }
00837
00838 static void quit_handler(int num, int nice, int safeshutdown, int restart)
00839 {
00840 char filename[80] = "";
00841 time_t s,e;
00842 int x;
00843
00844 ast_cdr_engine_term();
00845 if (safeshutdown) {
00846 shuttingdown = 1;
00847 if (!nice) {
00848
00849 ast_begin_shutdown(1);
00850 if (option_verbose && option_console)
00851 ast_verbose("Beginning asterisk %s....\n", restart ? "restart" : "shutdown");
00852 time(&s);
00853 for(;;) {
00854 time(&e);
00855
00856 if ((e - s) > 15)
00857 break;
00858 if (!ast_active_channels())
00859 break;
00860 if (!shuttingdown)
00861 break;
00862
00863 usleep(100000);
00864 }
00865 } else {
00866 if (nice < 2)
00867 ast_begin_shutdown(0);
00868 if (option_verbose && option_console)
00869 ast_verbose("Waiting for inactivity to perform %s...\n", restart ? "restart" : "halt");
00870 for(;;) {
00871 if (!ast_active_channels())
00872 break;
00873 if (!shuttingdown)
00874 break;
00875 sleep(1);
00876 }
00877 }
00878
00879 if (!shuttingdown) {
00880 if (option_verbose && option_console)
00881 ast_verbose("Asterisk %s cancelled.\n", restart ? "restart" : "shutdown");
00882 return;
00883 }
00884 }
00885 if (option_console || option_remote) {
00886 if (getenv("HOME"))
00887 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
00888 if (!ast_strlen_zero(filename))
00889 ast_el_write_history(filename);
00890 if (el != NULL)
00891 el_end(el);
00892 if (el_hist != NULL)
00893 history_end(el_hist);
00894 }
00895 if (option_verbose)
00896 ast_verbose("Executing last minute cleanups\n");
00897 ast_run_atexits();
00898
00899 if (option_verbose && option_console)
00900 ast_verbose("Asterisk %s ending (%d).\n", ast_active_channels() ? "uncleanly" : "cleanly", num);
00901 else if (option_debug)
00902 ast_log(LOG_DEBUG, "Asterisk ending (%d).\n", num);
00903 manager_event(EVENT_FLAG_SYSTEM, "Shutdown", "Shutdown: %s\r\nRestart: %s\r\n", ast_active_channels() ? "Uncleanly" : "Cleanly", restart ? "True" : "False");
00904 if (ast_socket > -1) {
00905 pthread_cancel(lthread);
00906 close(ast_socket);
00907 ast_socket = -1;
00908 unlink(ast_config_AST_SOCKET);
00909 }
00910 if (ast_consock > -1)
00911 close(ast_consock);
00912 if (!option_remote) unlink((char *)ast_config_AST_PID);
00913 printf(term_quit());
00914 if (restart) {
00915 if (option_verbose || option_console)
00916 ast_verbose("Preparing for Asterisk restart...\n");
00917
00918 for (x=3;x<32768;x++) {
00919 fcntl(x, F_SETFD, FD_CLOEXEC);
00920 }
00921 if (option_verbose || option_console)
00922 ast_verbose("Restarting Asterisk NOW...\n");
00923 restartnow = 1;
00924
00925
00926 close_logger();
00927
00928
00929
00930 if ((consolethread != AST_PTHREADT_NULL) && (consolethread != pthread_self())) {
00931 pthread_kill(consolethread, SIGHUP);
00932
00933 sleep(2);
00934 } else
00935 execvp(_argv[0], _argv);
00936
00937 } else {
00938
00939 close_logger();
00940 }
00941 exit(0);
00942 }
00943
00944 static void __quit_handler(int num)
00945 {
00946 quit_handler(num, 0, 1, 0);
00947 }
00948
00949 static const char *fix_header(char *outbuf, int maxout, const char *s, char *cmp)
00950 {
00951 const char *c;
00952 if (!strncmp(s, cmp, strlen(cmp))) {
00953 c = s + strlen(cmp);
00954 term_color(outbuf, cmp, COLOR_GRAY, 0, maxout);
00955 return c;
00956 }
00957 return NULL;
00958 }
00959
00960 static void console_verboser(const char *s, int pos, int replace, int complete)
00961 {
00962 char tmp[80];
00963 const char *c=NULL;
00964
00965 if (!pos) {
00966 fprintf(stdout, "\r");
00967 if ((c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_4)) ||
00968 (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_3)) ||
00969 (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_2)) ||
00970 (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_1)))
00971 fputs(tmp, stdout);
00972 }
00973 if (c)
00974 fputs(c + pos,stdout);
00975 else
00976 fputs(s + pos,stdout);
00977 fflush(stdout);
00978 if (complete) {
00979
00980 if (option_console && consolethread != AST_PTHREADT_NULL)
00981 pthread_kill(consolethread, SIGURG);
00982 }
00983 }
00984
00985 static int ast_all_zeros(char *s)
00986 {
00987 while(*s) {
00988 if (*s > 32)
00989 return 0;
00990 s++;
00991 }
00992 return 1;
00993 }
00994
00995 static void consolehandler(char *s)
00996 {
00997 printf(term_end());
00998 fflush(stdout);
00999
01000
01001 if (!ast_all_zeros(s))
01002 ast_el_add_history(s);
01003
01004 if (s[0] == '!') {
01005 if (s[1])
01006 ast_safe_system(s+1);
01007 else
01008 ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
01009 } else
01010 ast_cli_command(STDOUT_FILENO, s);
01011 }
01012
01013 static int remoteconsolehandler(char *s)
01014 {
01015 int ret = 0;
01016
01017
01018 if (!ast_all_zeros(s))
01019 ast_el_add_history(s);
01020
01021 if (s[0] == '!') {
01022 if (s[1])
01023 ast_safe_system(s+1);
01024 else
01025 ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
01026 ret = 1;
01027 }
01028 if ((strncasecmp(s, "quit", 4) == 0 || strncasecmp(s, "exit", 4) == 0) &&
01029 (s[4] == '\0' || isspace(s[4]))) {
01030 quit_handler(0, 0, 0, 0);
01031 ret = 1;
01032 }
01033
01034 return ret;
01035 }
01036
01037 static char abort_halt_help[] =
01038 "Usage: abort shutdown\n"
01039 " Causes Asterisk to abort an executing shutdown or restart, and resume normal\n"
01040 " call operations.\n";
01041
01042 static char shutdown_now_help[] =
01043 "Usage: stop now\n"
01044 " Shuts down a running Asterisk immediately, hanging up all active calls .\n";
01045
01046 static char shutdown_gracefully_help[] =
01047 "Usage: stop gracefully\n"
01048 " Causes Asterisk to not accept new calls, and exit when all\n"
01049 " active calls have terminated normally.\n";
01050
01051 static char shutdown_when_convenient_help[] =
01052 "Usage: stop when convenient\n"
01053 " Causes Asterisk to perform a shutdown when all active calls have ended.\n";
01054
01055 static char restart_now_help[] =
01056 "Usage: restart now\n"
01057 " Causes Asterisk to hangup all calls and exec() itself performing a cold\n"
01058 " restart.\n";
01059
01060 static char restart_gracefully_help[] =
01061 "Usage: restart gracefully\n"
01062 " Causes Asterisk to stop accepting new calls and exec() itself performing a cold\n"
01063 " restart when all active calls have ended.\n";
01064
01065 static char restart_when_convenient_help[] =
01066 "Usage: restart when convenient\n"
01067 " Causes Asterisk to perform a cold restart when all active calls have ended.\n";
01068
01069 static char bang_help[] =
01070 "Usage: !<command>\n"
01071 " Executes a given shell command\n";
01072
01073 static char show_warranty_help[] =
01074 "Usage: show warranty\n"
01075 " Shows the warranty (if any) for this copy of Asterisk.\n";
01076
01077 static char show_license_help[] =
01078 "Usage: show license\n"
01079 " Shows the license(s) for this copy of Asterisk.\n";
01080
01081 #if 0
01082 static int handle_quit(int fd, int argc, char *argv[])
01083 {
01084 if (argc != 1)
01085 return RESULT_SHOWUSAGE;
01086 quit_handler(0, 0, 1, 0);
01087 return RESULT_SUCCESS;
01088 }
01089 #endif
01090
01091 static int handle_shutdown_now(int fd, int argc, char *argv[])
01092 {
01093 if (argc != 2)
01094 return RESULT_SHOWUSAGE;
01095 quit_handler(0, 0 , 1 , 0 );
01096 return RESULT_SUCCESS;
01097 }
01098
01099 static int handle_shutdown_gracefully(int fd, int argc, char *argv[])
01100 {
01101 if (argc != 2)
01102 return RESULT_SHOWUSAGE;
01103 quit_handler(0, 1 , 1 , 0 );
01104 return RESULT_SUCCESS;
01105 }
01106
01107 static int handle_shutdown_when_convenient(int fd, int argc, char *argv[])
01108 {
01109 if (argc != 3)
01110 return RESULT_SHOWUSAGE;
01111 quit_handler(0, 2 , 1 , 0 );
01112 return RESULT_SUCCESS;
01113 }
01114
01115 static int handle_restart_now(int fd, int argc, char *argv[])
01116 {
01117 if (argc != 2)
01118 return RESULT_SHOWUSAGE;
01119 quit_handler(0, 0 , 1 , 1 );
01120 return RESULT_SUCCESS;
01121 }
01122
01123 static int handle_restart_gracefully(int fd, int argc, char *argv[])
01124 {
01125 if (argc != 2)
01126 return RESULT_SHOWUSAGE;
01127 quit_handler(0, 1 , 1 , 1 );
01128 return RESULT_SUCCESS;
01129 }
01130
01131 static int handle_restart_when_convenient(int fd, int argc, char *argv[])
01132 {
01133 if (argc != 3)
01134 return RESULT_SHOWUSAGE;
01135 quit_handler(0, 2 , 1 , 1 );
01136 return RESULT_SUCCESS;
01137 }
01138
01139 static int handle_abort_halt(int fd, int argc, char *argv[])
01140 {
01141 if (argc != 2)
01142 return RESULT_SHOWUSAGE;
01143 ast_cancel_shutdown();
01144 shuttingdown = 0;
01145 return RESULT_SUCCESS;
01146 }
01147
01148 static int handle_bang(int fd, int argc, char *argv[])
01149 {
01150 return RESULT_SUCCESS;
01151 }
01152 static const char *warranty_lines[] = {
01153 "\n",
01154 " NO WARRANTY\n",
01155 "\n",
01156 "BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\n",
01157 "FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN\n",
01158 "OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\n",
01159 "PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\n",
01160 "OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n",
01161 "MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS\n",
01162 "TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE\n",
01163 "PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\n",
01164 "REPAIR OR CORRECTION.\n",
01165 "\n",
01166 "IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\n",
01167 "WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\n",
01168 "REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\n",
01169 "INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\n",
01170 "OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\n",
01171 "TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\n",
01172 "YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\n",
01173 "PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\n",
01174 "POSSIBILITY OF SUCH DAMAGES.\n",
01175 };
01176
01177 static int show_warranty(int fd, int argc, char *argv[])
01178 {
01179 int x;
01180
01181 for (x = 0; x < sizeof(warranty_lines) / sizeof(warranty_lines[0]); x++)
01182 ast_cli(fd, (char *) warranty_lines[x]);
01183
01184 return RESULT_SUCCESS;
01185 }
01186
01187 static const char *license_lines[] = {
01188 "\n",
01189 "This program is free software; you can redistribute it and/or modify\n",
01190 "it under the terms of the GNU General Public License version 2 as\n",
01191 "published by the Free Software Foundation.\n",
01192 "\n",
01193 "This program also contains components licensed under other licenses.\n",
01194 "They include:\n",
01195 "\n",
01196 "This program is distributed in the hope that it will be useful,\n",
01197 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n",
01198 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n",
01199 "GNU General Public License for more details.\n",
01200 "\n",
01201 "You should have received a copy of the GNU General Public License\n",
01202 "along with this program; if not, write to the Free Software\n",
01203 "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n",
01204 };
01205
01206 static int show_license(int fd, int argc, char *argv[])
01207 {
01208 int x;
01209
01210 for (x = 0; x < sizeof(license_lines) / sizeof(license_lines[0]); x++)
01211 ast_cli(fd, (char *) license_lines[x]);
01212
01213 return RESULT_SUCCESS;
01214 }
01215
01216 #define ASTERISK_PROMPT "*CLI> "
01217
01218 #define ASTERISK_PROMPT2 "%s*CLI> "
01219
01220 static struct ast_cli_entry core_cli[] = {
01221 { { "abort", "halt", NULL }, handle_abort_halt,
01222 "Cancel a running halt", abort_halt_help },
01223 { { "stop", "now", NULL }, handle_shutdown_now,
01224 "Shut down Asterisk immediately", shutdown_now_help },
01225 { { "stop", "gracefully", NULL }, handle_shutdown_gracefully,
01226 "Gracefully shut down Asterisk", shutdown_gracefully_help },
01227 { { "stop", "when","convenient", NULL }, handle_shutdown_when_convenient,
01228 "Shut down Asterisk at empty call volume", shutdown_when_convenient_help },
01229 { { "restart", "now", NULL }, handle_restart_now,
01230 "Restart Asterisk immediately", restart_now_help },
01231 { { "restart", "gracefully", NULL }, handle_restart_gracefully,
01232 "Restart Asterisk gracefully", restart_gracefully_help },
01233 { { "restart", "when", "convenient", NULL }, handle_restart_when_convenient,
01234 "Restart Asterisk at empty call volume", restart_when_convenient_help },
01235 { { "show", "warranty", NULL }, show_warranty,
01236 "Show the warranty (if any) for this copy of Asterisk", show_warranty_help },
01237 { { "show", "license", NULL }, show_license,
01238 "Show the license(s) for this copy of Asterisk", show_license_help },
01239 { { "!", NULL }, handle_bang,
01240 "Execute a shell command", bang_help },
01241 #if !defined(LOW_MEMORY)
01242 { { "show", "version", "files", NULL }, handle_show_version_files,
01243 "Show versions of files used to build Asterisk", show_version_files_help, complete_show_version_files },
01244 #endif
01245 };
01246
01247 static int ast_el_read_char(EditLine *el, char *cp)
01248 {
01249 int num_read=0;
01250 int lastpos=0;
01251 struct pollfd fds[2];
01252 int res;
01253 int max;
01254 char buf[512];
01255
01256 for (;;) {
01257 max = 1;
01258 fds[0].fd = ast_consock;
01259 fds[0].events = POLLIN;
01260 if (!option_exec) {
01261 fds[1].fd = STDIN_FILENO;
01262 fds[1].events = POLLIN;
01263 max++;
01264 }
01265 res = poll(fds, max, -1);
01266 if (res < 0) {
01267 if (errno == EINTR)
01268 continue;
01269 ast_log(LOG_ERROR, "poll failed: %s\n", strerror(errno));
01270 break;
01271 }
01272
01273 if (!option_exec && fds[1].revents) {
01274 num_read = read(STDIN_FILENO, cp, 1);
01275 if (num_read < 1) {
01276 break;
01277 } else
01278 return (num_read);
01279 }
01280 if (fds[0].revents) {
01281 res = read(ast_consock, buf, sizeof(buf) - 1);
01282
01283 if (res < 1) {
01284 fprintf(stderr, "\nDisconnected from Asterisk server\n");
01285 if (!option_reconnect) {
01286 quit_handler(0, 0, 0, 0);
01287 } else {
01288 int tries;
01289 int reconnects_per_second = 20;
01290 fprintf(stderr, "Attempting to reconnect for 30 seconds\n");
01291 for (tries=0;tries<30 * reconnects_per_second;tries++) {
01292 if (ast_tryconnect()) {
01293 fprintf(stderr, "Reconnect succeeded after %.3f seconds\n", 1.0 / reconnects_per_second * tries);
01294 printf(term_quit());
01295 WELCOME_MESSAGE;
01296 break;
01297 } else {
01298 usleep(1000000 / reconnects_per_second);
01299 }
01300 }
01301 if (tries >= 30 * reconnects_per_second) {
01302 fprintf(stderr, "Failed to reconnect for 30 seconds. Quitting.\n");
01303 quit_handler(0, 0, 0, 0);
01304 }
01305 }
01306 }
01307
01308 buf[res] = '\0';
01309
01310 if (!option_exec && !lastpos)
01311 write(STDOUT_FILENO, "\r", 1);
01312 write(STDOUT_FILENO, buf, res);
01313 if ((buf[res-1] == '\n') || (buf[res-2] == '\n')) {
01314 *cp = CC_REFRESH;
01315 return(1);
01316 } else {
01317 lastpos = 1;
01318 }
01319 }
01320 }
01321
01322 *cp = '\0';
01323 return (0);
01324 }
01325
01326 static char *cli_prompt(EditLine *el)
01327 {
01328 static char prompt[200];
01329 char *pfmt;
01330 int color_used=0;
01331 char term_code[20];
01332
01333 if ((pfmt = getenv("ASTERISK_PROMPT"))) {
01334 char *t = pfmt, *p = prompt;
01335 memset(prompt, 0, sizeof(prompt));
01336 while (*t != '\0' && *p < sizeof(prompt)) {
01337 if (*t == '%') {
01338 char hostname[MAXHOSTNAMELEN]="";
01339 int i;
01340 time_t ts;
01341 struct tm tm;
01342 #ifdef linux
01343 FILE *LOADAVG;
01344 #endif
01345 int fgcolor = COLOR_WHITE, bgcolor = COLOR_BLACK;
01346
01347 t++;
01348 switch (*t) {
01349 case 'C':
01350 t++;
01351 if (sscanf(t, "%d;%d%n", &fgcolor, &bgcolor, &i) == 2) {
01352 strncat(p, term_color_code(term_code, fgcolor, bgcolor, sizeof(term_code)),sizeof(prompt) - strlen(prompt) - 1);
01353 t += i - 1;
01354 } else if (sscanf(t, "%d%n", &fgcolor, &i) == 1) {
01355 strncat(p, term_color_code(term_code, fgcolor, 0, sizeof(term_code)),sizeof(prompt) - strlen(prompt) - 1);
01356 t += i - 1;
01357 }
01358
01359
01360 if ((fgcolor == COLOR_WHITE) && (bgcolor == COLOR_BLACK)) {
01361 color_used = 0;
01362 } else {
01363 color_used = 1;
01364 }
01365 break;
01366 case 'd':
01367 memset(&tm, 0, sizeof(struct tm));
01368 time(&ts);
01369 if (localtime_r(&ts, &tm)) {
01370 strftime(p, sizeof(prompt) - strlen(prompt), "%Y-%m-%d", &tm);
01371 }
01372 break;
01373 case 'h':
01374 if (!gethostname(hostname, sizeof(hostname) - 1)) {
01375 strncat(p, hostname, sizeof(prompt) - strlen(prompt) - 1);
01376 } else {
01377 strncat(p, "localhost", sizeof(prompt) - strlen(prompt) - 1);
01378 }
01379 break;
01380 case 'H':
01381 if (!gethostname(hostname, sizeof(hostname) - 1)) {
01382 for (i=0;i<sizeof(hostname);i++) {
01383 if (hostname[i] == '.') {
01384 hostname[i] = '\0';
01385 break;
01386 }
01387 }
01388 strncat(p, hostname, sizeof(prompt) - strlen(prompt) - 1);
01389 } else {
01390 strncat(p, "localhost", sizeof(prompt) - strlen(prompt) - 1);
01391 }
01392 break;
01393 #ifdef linux
01394 case 'l':
01395 t++;
01396 if ((LOADAVG = fopen("/proc/loadavg", "r"))) {
01397 float avg1, avg2, avg3;
01398 int actproc, totproc, npid, which;
01399 fscanf(LOADAVG, "%f %f %f %d/%d %d",
01400 &avg1, &avg2, &avg3, &actproc, &totproc, &npid);
01401 if (sscanf(t, "%d", &which) == 1) {
01402 switch (which) {
01403 case 1:
01404 snprintf(p, sizeof(prompt) - strlen(prompt), "%.2f", avg1);
01405 break;
01406 case 2:
01407 snprintf(p, sizeof(prompt) - strlen(prompt), "%.2f", avg2);
01408 break;
01409 case 3:
01410 snprintf(p, sizeof(prompt) - strlen(prompt), "%.2f", avg3);
01411 break;
01412 case 4:
01413 snprintf(p, sizeof(prompt) - strlen(prompt), "%d/%d", actproc, totproc);
01414 break;
01415 case 5:
01416 snprintf(p, sizeof(prompt) - strlen(prompt), "%d", npid);
01417 break;
01418 }
01419 }
01420 }
01421 break;
01422 #endif
01423 case 't':
01424 memset(&tm, 0, sizeof(struct tm));
01425 time(&ts);
01426 if (localtime_r(&ts, &tm)) {
01427 strftime(p, sizeof(prompt) - strlen(prompt), "%H:%M:%S", &tm);
01428 }
01429 break;
01430 case '#':
01431 if (! option_remote) {
01432 strncat(p, "#", sizeof(prompt) - strlen(prompt) - 1);
01433 } else {
01434 strncat(p, ">", sizeof(prompt) - strlen(prompt) - 1);
01435 }
01436 break;
01437 case '%':
01438 strncat(p, "%", sizeof(prompt) - strlen(prompt) - 1);
01439 break;
01440 case '\0':
01441 t--;
01442 break;
01443 }
01444 while (*p != '\0') {
01445 p++;
01446 }
01447 t++;
01448 } else {
01449 *p = *t;
01450 p++;
01451 t++;
01452 }
01453 }
01454 if (color_used) {
01455
01456 term_color_code(term_code, COLOR_WHITE, COLOR_BLACK, sizeof(term_code));
01457 if (strlen(term_code) > sizeof(prompt) - strlen(prompt)) {
01458 strncat(prompt + sizeof(prompt) - strlen(term_code) - 1, term_code, strlen(term_code));
01459 } else {
01460 strncat(p, term_code, sizeof(term_code));
01461 }
01462 }
01463 } else if (remotehostname)
01464 snprintf(prompt, sizeof(prompt), ASTERISK_PROMPT2, remotehostname);
01465 else
01466 snprintf(prompt, sizeof(prompt), ASTERISK_PROMPT);
01467
01468 return(prompt);
01469 }
01470
01471 static char **ast_el_strtoarr(char *buf)
01472 {
01473 char **match_list = NULL, *retstr;
01474 size_t match_list_len;
01475 int matches = 0;
01476
01477 match_list_len = 1;
01478 while ( (retstr = strsep(&buf, " ")) != NULL) {
01479
01480 if (!strcmp(retstr, AST_CLI_COMPLETE_EOF))
01481 break;
01482 if (matches + 1 >= match_list_len) {
01483 match_list_len <<= 1;
01484 match_list = realloc(match_list, match_list_len * sizeof(char *));
01485 }
01486
01487 match_list[matches++] = strdup(retstr);
01488 }
01489
01490 if (!match_list)
01491 return (char **) NULL;
01492
01493 if (matches>= match_list_len)
01494 match_list = realloc(match_list, (match_list_len + 1) * sizeof(char *));
01495
01496 match_list[matches] = (char *) NULL;
01497
01498 return match_list;
01499 }
01500
01501 static int ast_el_sort_compare(const void *i1, const void *i2)
01502 {
01503 char *s1, *s2;
01504
01505 s1 = ((char **)i1)[0];
01506 s2 = ((char **)i2)[0];
01507
01508 return strcasecmp(s1, s2);
01509 }
01510
01511 static int ast_cli_display_match_list(char **matches, int len, int max)
01512 {
01513 int i, idx, limit, count;
01514 int screenwidth = 0;
01515 int numoutput = 0, numoutputline = 0;
01516
01517 screenwidth = ast_get_termcols(STDOUT_FILENO);
01518
01519
01520 limit = screenwidth / (max + 2);
01521 if (limit == 0)
01522 limit = 1;
01523
01524
01525 count = len / limit;
01526 if (count * limit < len)
01527 count++;
01528
01529 idx = 1;
01530
01531 qsort(&matches[0], (size_t)(len + 1), sizeof(char *), ast_el_sort_compare);
01532
01533 for (; count > 0; count--) {
01534 numoutputline = 0;
01535 for (i=0; i < limit && matches[idx]; i++, idx++) {
01536
01537
01538 if ( (matches[idx+1] != NULL && strcmp(matches[idx], matches[idx+1]) == 0 ) ) {
01539 i--;
01540 free(matches[idx]);
01541 matches[idx] = NULL;
01542 continue;
01543 }
01544
01545 numoutput++;
01546 numoutputline++;
01547 fprintf(stdout, "%-*s ", max, matches[idx]);
01548 free(matches[idx]);
01549 matches[idx] = NULL;
01550 }
01551 if (numoutputline > 0)
01552 fprintf(stdout, "\n");
01553 }
01554
01555 return numoutput;
01556 }
01557
01558
01559 static char *cli_complete(EditLine *el, int ch)
01560 {
01561 int len=0;
01562 char *ptr;
01563 int nummatches = 0;
01564 char **matches;
01565 int retval = CC_ERROR;
01566 char buf[2048];
01567 int res;
01568
01569 LineInfo *lf = (LineInfo *)el_line(el);
01570
01571 *(char *)lf->cursor = '\0';
01572 ptr = (char *)lf->cursor;
01573 if (ptr) {
01574 while (ptr > lf->buffer) {
01575 if (isspace(*ptr)) {
01576 ptr++;
01577 break;
01578 }
01579 ptr--;
01580 }
01581 }
01582
01583 len = lf->cursor - ptr;
01584
01585 if (option_remote) {
01586 snprintf(buf, sizeof(buf),"_COMMAND NUMMATCHES \"%s\" \"%s\"", lf->buffer, ptr);
01587 fdprint(ast_consock, buf);
01588 res = read(ast_consock, buf, sizeof(buf));
01589 buf[res] = '\0';
01590 nummatches = atoi(buf);
01591
01592 if (nummatches > 0) {
01593 char *mbuf;
01594 int mlen = 0, maxmbuf = 2048;
01595
01596 mbuf = malloc(maxmbuf);
01597 if (!mbuf)
01598 return (char *)(CC_ERROR);
01599 snprintf(buf, sizeof(buf),"_COMMAND MATCHESARRAY \"%s\" \"%s\"", lf->buffer, ptr);
01600 fdprint(ast_consock, buf);
01601 res = 0;
01602 mbuf[0] = '\0';
01603 while (!strstr(mbuf, AST_CLI_COMPLETE_EOF) && res != -1) {
01604 if (mlen + 1024 > maxmbuf) {
01605
01606 maxmbuf += 1024;
01607 mbuf = realloc(mbuf, maxmbuf);
01608 if (!mbuf)
01609 return (char *)(CC_ERROR);
01610 }
01611
01612 res = read(ast_consock, mbuf + mlen, 1024);
01613 if (res > 0)
01614 mlen += res;
01615 }
01616 mbuf[mlen] = '\0';
01617
01618 matches = ast_el_strtoarr(mbuf);
01619 free(mbuf);
01620 } else
01621 matches = (char **) NULL;
01622
01623
01624 } else {
01625
01626 nummatches = ast_cli_generatornummatches((char *)lf->buffer,ptr);
01627 matches = ast_cli_completion_matches((char *)lf->buffer,ptr);
01628 }
01629
01630 if (matches) {
01631 int i;
01632 int matches_num, maxlen, match_len;
01633
01634 if (matches[0][0] != '\0') {
01635 el_deletestr(el, (int) len);
01636 el_insertstr(el, matches[0]);
01637 retval = CC_REFRESH;
01638 }
01639
01640 if (nummatches == 1) {
01641
01642 el_insertstr(el, " ");
01643 retval = CC_REFRESH;
01644 } else {
01645
01646 for (i=1, maxlen=0; matches[i]; i++) {
01647 match_len = strlen(matches[i]);
01648 if (match_len > maxlen)
01649 maxlen = match_len;
01650 }
01651 matches_num = i - 1;
01652 if (matches_num >1) {
01653 fprintf(stdout, "\n");
01654 ast_cli_display_match_list(matches, nummatches, maxlen);
01655 retval = CC_REDISPLAY;
01656 } else {
01657 el_insertstr(el," ");
01658 retval = CC_REFRESH;
01659 }
01660 }
01661 free(matches);
01662 }
01663
01664 return (char *)(long)retval;
01665 }
01666
01667 static int ast_el_initialize(void)
01668 {
01669 HistEvent ev;
01670 char *editor = getenv("AST_EDITOR");
01671
01672 if (el != NULL)
01673 el_end(el);
01674 if (el_hist != NULL)
01675 history_end(el_hist);
01676
01677 el = el_init("asterisk", stdin, stdout, stderr);
01678 el_set(el, EL_PROMPT, cli_prompt);
01679
01680 el_set(el, EL_EDITMODE, 1);
01681 el_set(el, EL_EDITOR, editor ? editor : "emacs");
01682 el_hist = history_init();
01683 if (!el || !el_hist)
01684 return -1;
01685
01686
01687 history(el_hist, &ev, H_SETSIZE, 100);
01688
01689 el_set(el, EL_HIST, history, el_hist);
01690
01691 el_set(el, EL_ADDFN, "ed-complete", "Complete argument", cli_complete);
01692
01693 el_set(el, EL_BIND, "^I", "ed-complete", NULL);
01694
01695 el_set(el, EL_BIND, "?", "ed-complete", NULL);
01696
01697 el_set(el, EL_BIND, "^D", "ed-redisplay", NULL);
01698
01699 return 0;
01700 }
01701
01702 static int ast_el_add_history(char *buf)
01703 {
01704 HistEvent ev;
01705
01706 if (el_hist == NULL || el == NULL)
01707 ast_el_initialize();
01708 if (strlen(buf) > 256)
01709 return 0;
01710 return (history(el_hist, &ev, H_ENTER, buf));
01711 }
01712
01713 static int ast_el_write_history(char *filename)
01714 {
01715 HistEvent ev;
01716
01717 if (el_hist == NULL || el == NULL)
01718 ast_el_initialize();
01719
01720 return (history(el_hist, &ev, H_SAVE, filename));
01721 }
01722
01723 static int ast_el_read_history(char *filename)
01724 {
01725 char buf[256];
01726 FILE *f;
01727 int ret = -1;
01728
01729 if (el_hist == NULL || el == NULL)
01730 ast_el_initialize();
01731
01732 if ((f = fopen(filename, "r")) == NULL)
01733 return ret;
01734
01735 while (!feof(f)) {
01736 fgets(buf, sizeof(buf), f);
01737 if (!strcmp(buf, "_HiStOrY_V2_\n"))
01738 continue;
01739 if (ast_all_zeros(buf))
01740 continue;
01741 if ((ret = ast_el_add_history(buf)) == -1)
01742 break;
01743 }
01744 fclose(f);
01745
01746 return ret;
01747 }
01748
01749 static void ast_remotecontrol(char * data)
01750 {
01751 char buf[80];
01752 int res;
01753 char filename[80] = "";
01754 char *hostname;
01755 char *cpid;
01756 char *version;
01757 int pid;
01758 char tmp[80];
01759 char *stringp=NULL;
01760
01761 char *ebuf;
01762 int num = 0;
01763
01764 read(ast_consock, buf, sizeof(buf));
01765 if (data)
01766 write(ast_consock, data, strlen(data) + 1);
01767 stringp=buf;
01768 hostname = strsep(&stringp, "/");
01769 cpid = strsep(&stringp, "/");
01770 version = strsep(&stringp, "\n");
01771 if (!version)
01772 version = "<Version Unknown>";
01773 stringp=hostname;
01774 strsep(&stringp, ".");
01775 if (cpid)
01776 pid = atoi(cpid);
01777 else
01778 pid = -1;
01779 snprintf(tmp, sizeof(tmp), "set verbose atleast %d", option_verbose);
01780 fdprint(ast_consock, tmp);
01781 snprintf(tmp, sizeof(tmp), "set debug atleast %d", option_debug);
01782 fdprint(ast_consock, tmp);
01783 ast_verbose("Connected to Asterisk %s currently running on %s (pid = %d)\n", version, hostname, pid);
01784 remotehostname = hostname;
01785 if (getenv("HOME"))
01786 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
01787 if (el_hist == NULL || el == NULL)
01788 ast_el_initialize();
01789
01790 el_set(el, EL_GETCFN, ast_el_read_char);
01791
01792 if (!ast_strlen_zero(filename))
01793 ast_el_read_history(filename);
01794
01795 if (option_exec && data) {
01796 char tempchar;
01797 struct pollfd fds;
01798 fds.fd = ast_consock;
01799 fds.events = POLLIN;
01800 fds.revents = 0;
01801 while (poll(&fds, 1, 100) > 0)
01802 ast_el_read_char(el, &tempchar);
01803 return;
01804 }
01805 for(;;) {
01806 ebuf = (char *)el_gets(el, &num);
01807
01808 if (!ast_strlen_zero(ebuf)) {
01809 if (ebuf[strlen(ebuf)-1] == '\n')
01810 ebuf[strlen(ebuf)-1] = '\0';
01811 if (!remoteconsolehandler(ebuf)) {
01812 res = write(ast_consock, ebuf, strlen(ebuf) + 1);
01813 if (res < 1) {
01814 ast_log(LOG_WARNING, "Unable to write: %s\n", strerror(errno));
01815 break;
01816 }
01817 }
01818 }
01819 }
01820 printf("\nDisconnected from Asterisk server\n");
01821 }
01822
01823 static int show_version(void)
01824 {
01825 printf("Asterisk " ASTERISK_VERSION "\n");
01826 return 0;
01827 }
01828
01829 static int show_cli_help(void) {
01830 printf("Asterisk " ASTERISK_VERSION ", Copyright (C) 1999 - 2005, Digium, Inc. and others.\n");
01831 printf("Usage: asterisk [OPTIONS]\n");
01832 printf("Valid Options:\n");
01833 printf(" -V Display version number and exit\n");
01834 printf(" -C <configfile> Use an alternate configuration file\n");
01835 printf(" -G <group> Run as a group other than the caller\n");
01836 printf(" -U <user> Run as a user other than the caller\n");
01837 printf(" -c Provide console CLI\n");
01838 printf(" -F Force Fork even if -v or -d were given\n");
01839 printf(" -d Enable extra debugging\n");
01840 printf(" -f Do not fork\n");
01841 printf(" -g Dump core in case of a crash\n");
01842 printf(" -h This help screen\n");
01843 printf(" -i Initialize crypto keys at startup\n");
01844 printf(" -n Disable console colorization\n");
01845 printf(" -p Run as pseudo-realtime thread\n");
01846 printf(" -q Quiet mode (suppress output)\n");
01847 printf(" -r Connect to Asterisk on this machine\n");
01848 printf(" -R Connect to Asterisk, and attempt to reconnect if disconnected\n");
01849 printf(" -t Record soundfiles in /var/tmp and move them where they belong after they are done.\n");
01850 printf(" -T Display the time in [Mmm dd hh:mm:ss] format for each line of output to the CLI.\n");
01851 printf(" -v Increase verbosity (multiple v's = more verbose)\n");
01852 printf(" -x <cmd> Execute command <cmd> (only valid with -r)\n");
01853 printf("\n");
01854 return 0;
01855 }
01856
01857 static void ast_readconfig(void) {
01858 struct ast_config *cfg;
01859 struct ast_variable *v;
01860 char *config = AST_CONFIG_FILE;
01861
01862 if (option_overrideconfig == 1) {
01863 cfg = ast_config_load(ast_config_AST_CONFIG_FILE);
01864 if (!cfg)
01865 ast_log(LOG_WARNING, "Unable to open specified master config file '%s', using built-in defaults\n", ast_config_AST_CONFIG_FILE);
01866 } else {
01867 cfg = ast_config_load(config);
01868 }
01869
01870
01871 ast_copy_string(ast_config_AST_CONFIG_DIR, AST_CONFIG_DIR, sizeof(ast_config_AST_CONFIG_DIR));
01872 ast_copy_string(ast_config_AST_SPOOL_DIR, AST_SPOOL_DIR, sizeof(ast_config_AST_SPOOL_DIR));
01873 ast_copy_string(ast_config_AST_MODULE_DIR, AST_MODULE_DIR, sizeof(ast_config_AST_MODULE_DIR));
01874 snprintf(ast_config_AST_MONITOR_DIR, sizeof(ast_config_AST_MONITOR_DIR) - 1, "%s/monitor", ast_config_AST_SPOOL_DIR);
01875 ast_copy_string(ast_config_AST_VAR_DIR, AST_VAR_DIR, sizeof(ast_config_AST_VAR_DIR));
01876 ast_copy_string(ast_config_AST_DATA_DIR, AST_DATA_DIR, sizeof(ast_config_AST_DATA_DIR));
01877 ast_copy_string(ast_config_AST_LOG_DIR, AST_LOG_DIR, sizeof(ast_config_AST_LOG_DIR));
01878 ast_copy_string(ast_config_AST_AGI_DIR, AST_AGI_DIR, sizeof(ast_config_AST_AGI_DIR));
01879 ast_copy_string(ast_config_AST_DB, AST_DB, sizeof(ast_config_AST_DB));
01880 ast_copy_string(ast_config_AST_KEY_DIR, AST_KEY_DIR, sizeof(ast_config_AST_KEY_DIR));
01881 ast_copy_string(ast_config_AST_PID, AST_PID, sizeof(ast_config_AST_PID));
01882 ast_copy_string(ast_config_AST_SOCKET, AST_SOCKET, sizeof(ast_config_AST_SOCKET));
01883 ast_copy_string(ast_config_AST_RUN_DIR, AST_RUN_DIR, sizeof(ast_config_AST_RUN_DIR));
01884
01885
01886 if (!cfg) {
01887 return;
01888 }
01889 v = ast_variable_browse(cfg, "files");
01890 while (v) {
01891 if (!strcasecmp(v->name, "astctlpermissions")) {
01892 ast_copy_string(ast_config_AST_CTL_PERMISSIONS, v->value, sizeof(ast_config_AST_CTL_PERMISSIONS));
01893 } else if (!strcasecmp(v->name, "astctlowner")) {
01894 ast_copy_string(ast_config_AST_CTL_OWNER, v->value, sizeof(ast_config_AST_CTL_OWNER));
01895 } else if (!strcasecmp(v->name, "astctlgroup")) {
01896 ast_copy_string(ast_config_AST_CTL_GROUP, v->value, sizeof(ast_config_AST_CTL_GROUP));
01897 } else if (!strcasecmp(v->name, "astctl")) {
01898 ast_copy_string(ast_config_AST_CTL, v->value, sizeof(ast_config_AST_CTL));
01899 }
01900 v = v->next;
01901 }
01902 v = ast_variable_browse(cfg, "directories");
01903 while(v) {
01904 if (!strcasecmp(v->name, "astetcdir")) {
01905 ast_copy_string(ast_config_AST_CONFIG_DIR, v->value, sizeof(ast_config_AST_CONFIG_DIR));
01906 } else if (!strcasecmp(v->name, "astspooldir")) {
01907 ast_copy_string(ast_config_AST_SPOOL_DIR, v->value, sizeof(ast_config_AST_SPOOL_DIR));
01908 snprintf(ast_config_AST_MONITOR_DIR, sizeof(ast_config_AST_MONITOR_DIR) - 1, "%s/monitor", v->value);
01909 } else if (!strcasecmp(v->name, "astvarlibdir")) {
01910 ast_copy_string(ast_config_AST_VAR_DIR, v->value, sizeof(ast_config_AST_VAR_DIR));
01911 snprintf(ast_config_AST_DB, sizeof(ast_config_AST_DB), "%s/astdb", v->value);
01912 snprintf(ast_config_AST_KEY_DIR, sizeof(ast_config_AST_KEY_DIR), "%s/keys", v->value);
01913 } else if (!strcasecmp(v->name, "astdatadir")) {
01914 ast_copy_string(ast_config_AST_DATA_DIR, v->value, sizeof(ast_config_AST_DATA_DIR));
01915 } else if (!strcasecmp(v->name, "astlogdir")) {
01916 ast_copy_string(ast_config_AST_LOG_DIR, v->value, sizeof(ast_config_AST_LOG_DIR));
01917 } else if (!strcasecmp(v->name, "astagidir")) {
01918 ast_copy_string(ast_config_AST_AGI_DIR, v->value, sizeof(ast_config_AST_AGI_DIR));
01919 } else if (!strcasecmp(v->name, "astrundir")) {
01920 snprintf(ast_config_AST_PID, sizeof(ast_config_AST_PID), "%s/%s", v->value, "asterisk.pid");
01921 snprintf(ast_config_AST_SOCKET, sizeof(ast_config_AST_SOCKET), "%s/%s", v->value, ast_config_AST_CTL);
01922 ast_copy_string(ast_config_AST_RUN_DIR, v->value, sizeof(ast_config_AST_RUN_DIR));
01923 } else if (!strcasecmp(v->name, "astmoddir")) {
01924 ast_copy_string(ast_config_AST_MODULE_DIR, v->value, sizeof(ast_config_AST_MODULE_DIR));
01925 }
01926 v = v->next;
01927 }
01928 v = ast_variable_browse(cfg, "options");
01929 while(v) {
01930
01931 if (!strcasecmp(v->name, "verbose")) {
01932 option_verbose = atoi(v->value);
01933
01934 } else if (!strcasecmp(v->name, "timestamp")) {
01935 option_timestamp = ast_true(v->value);
01936
01937 } else if (!strcasecmp(v->name, "execincludes")) {
01938 option_exec_includes = ast_true(v->value);
01939
01940 } else if (!strcasecmp(v->name, "debug")) {
01941 option_debug = 0;
01942 if (sscanf(v->value, "%d", &option_debug) != 1) {
01943 option_debug = ast_true(v->value);
01944 }
01945
01946 } else if (!strcasecmp(v->name, "nofork")) {
01947 option_nofork = ast_true(v->value);
01948
01949 } else if (!strcasecmp(v->name, "quiet")) {
01950 option_quiet = ast_true(v->value);
01951
01952 } else if (!strcasecmp(v->name, "console")) {
01953 option_console = ast_true(v->value);
01954
01955 } else if (!strcasecmp(v->name, "highpriority")) {
01956 option_highpriority = ast_true(v->value);
01957
01958 } else if (!strcasecmp(v->name, "initcrypto")) {
01959 option_initcrypto = ast_true(v->value);
01960
01961 } else if (!strcasecmp(v->name, "nocolor")) {
01962 option_nocolor = ast_true(v->value);
01963
01964 } else if (!strcasecmp(v->name, "dontwarn")) {
01965 option_dontwarn = ast_true(v->value);
01966
01967 } else if (!strcasecmp(v->name, "dumpcore")) {
01968 option_dumpcore = ast_true(v->value);
01969
01970 } else if (!strcasecmp(v->name, "cache_record_files")) {
01971 option_cache_record_files = ast_true(v->value);
01972
01973 } else if (!strcasecmp(v->name, "record_cache_dir")) {
01974 ast_copy_string(record_cache_dir, v->value, AST_CACHE_DIR_LEN);
01975
01976 } else if (!strcasecmp(v->name, "transcode_via_sln")) {
01977 option_transcode_slin = ast_true(v->value);
01978
01979 } else if (!strcasecmp(v->name, "transmit_silence_during_record")) {
01980 option_transmit_silence_during_record = ast_true(v->value);
01981 } else if (!strcasecmp(v->name, "maxcalls")) {
01982 if ((sscanf(v->value, "%d", &option_maxcalls) != 1) || (option_maxcalls < 0)) {
01983 option_maxcalls = 0;
01984 }
01985 } else if (!strcasecmp(v->name, "maxload")) {
01986 double test[1];
01987
01988 if (getloadavg(test, 1) == -1) {
01989 ast_log(LOG_ERROR, "Cannot obtain load average on this system. 'maxload' option disabled.\n");
01990 option_maxload = 0.0;
01991 } else if ((sscanf(v->value, "%lf", &option_maxload) != 1) || (option_maxload < 0.0)) {
01992 option_maxload = 0.0;
01993 }
01994
01995 } else if (!strcasecmp(v->name, "runuser")) {
01996 ast_copy_string(ast_config_AST_RUN_USER, v->value, sizeof(ast_config_AST_RUN_USER));
01997
01998 } else if (!strcasecmp(v->name, "rungroup")) {
01999 ast_copy_string(ast_config_AST_RUN_GROUP, v->value, sizeof(ast_config_AST_RUN_GROUP));
02000 }
02001 v = v->next;
02002 }
02003 ast_config_destroy(cfg);
02004 }
02005
02006 int main(int argc, char *argv[])
02007 {
02008 int c;
02009 char filename[80] = "";
02010 char hostname[MAXHOSTNAMELEN]="";
02011 char tmp[80];
02012 char * xarg = NULL;
02013 int x;
02014 FILE *f;
02015 sigset_t sigs;
02016 int num;
02017 int is_child_of_nonroot=0;
02018 char *buf;
02019 char *runuser=NULL, *rungroup=NULL;
02020
02021
02022 if (argc > sizeof(_argv) / sizeof(_argv[0]) - 1) {
02023 fprintf(stderr, "Truncating argument size to %d\n", (int)(sizeof(_argv) / sizeof(_argv[0])) - 1);
02024 argc = sizeof(_argv) / sizeof(_argv[0]) - 1;
02025 }
02026 for (x=0;x<argc;x++)
02027 _argv[x] = argv[x];
02028 _argv[x] = NULL;
02029
02030
02031 if (argv[0] && (strstr(argv[0], "rasterisk")) != NULL) {
02032 option_remote++;
02033 option_nofork++;
02034 }
02035 if (gethostname(hostname, sizeof(hostname)-1))
02036 ast_copy_string(hostname, "<Unknown>", sizeof(hostname));
02037 ast_mainpid = getpid();
02038 ast_ulaw_init();
02039 ast_alaw_init();
02040 callerid_init();
02041 ast_utils_init();
02042 tdd_init();
02043
02044
02045
02046 if (getenv("ASTERISK_ALREADY_NONROOT"))
02047 is_child_of_nonroot=1;
02048 if (getenv("HOME"))
02049 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
02050
02051
02052
02053
02054
02055
02056
02057
02058 while((c=getopt(argc, argv, "tThfdvVqprRgcFinx:U:G:C:L:M:")) != -1) {
02059 switch(c) {
02060 case 'd':
02061 option_debug++;
02062 option_nofork++;
02063 break;
02064 case 'c':
02065 option_console++;
02066 option_nofork++;
02067 break;
02068 case 'F':
02069 option_daemonize++;
02070 break;
02071 case 'f':
02072 option_nofork++;
02073 break;
02074 case 'n':
02075 option_nocolor++;
02076 break;
02077 case 'r':
02078 option_remote++;
02079 option_nofork++;
02080 break;
02081 case 'R':
02082 option_remote++;
02083 option_nofork++;
02084 option_reconnect++;
02085 break;
02086 case 'p':
02087 option_highpriority++;
02088 break;
02089 case 'v':
02090 option_verbose++;
02091 option_nofork++;
02092 break;
02093 case 'M':
02094 if ((sscanf(optarg, "%d", &option_maxcalls) != 1) || (option_maxcalls < 0))
02095 option_maxcalls = 0;
02096 break;
02097 case 'L':
02098 if ((sscanf(optarg, "%lf", &option_maxload) != 1) || (option_maxload < 0.0))
02099 option_maxload = 0.0;
02100 break;
02101 case 'q':
02102 option_quiet++;
02103 break;
02104 case 't':
02105 option_cache_record_files++;
02106 break;
02107 case 'T':
02108 option_timestamp++;
02109 break;
02110 case 'x':
02111 option_exec++;
02112 xarg = optarg;
02113 break;
02114 case 'C':
02115 ast_copy_string((char *)ast_config_AST_CONFIG_FILE,optarg,sizeof(ast_config_AST_CONFIG_FILE));
02116 option_overrideconfig++;
02117 break;
02118 case 'i':
02119 option_initcrypto++;
02120 break;
02121 case'g':
02122 option_dumpcore++;
02123 break;
02124 case 'h':
02125 show_cli_help();
02126 exit(0);
02127 case 'V':
02128 show_version();
02129 exit(0);
02130 case 'U':
02131 runuser = optarg;
02132 break;
02133 case 'G':
02134 rungroup = optarg;
02135 break;
02136 case '?':
02137 exit(1);
02138 }
02139 }
02140
02141
02142
02143
02144 if (option_remote) {
02145 strcpy(argv[0], "rasterisk");
02146 for (x = 1; x < argc; x++) {
02147 argv[x] = argv[0] + 10;
02148 }
02149 }
02150
02151 if (option_console && !option_verbose)
02152 ast_verbose("[ Reading Master Configuration ]");
02153 ast_readconfig();
02154
02155 if (option_dumpcore) {
02156 struct rlimit l;
02157 memset(&l, 0, sizeof(l));
02158 l.rlim_cur = RLIM_INFINITY;
02159 l.rlim_max = RLIM_INFINITY;
02160 if (setrlimit(RLIMIT_CORE, &l)) {
02161 ast_log(LOG_WARNING, "Unable to disable core size resource limit: %s\n", strerror(errno));
02162 }
02163 }
02164
02165 if ((!rungroup) && !ast_strlen_zero(ast_config_AST_RUN_GROUP))
02166 rungroup = ast_config_AST_RUN_GROUP;
02167 if ((!runuser) && !ast_strlen_zero(ast_config_AST_RUN_USER))
02168 runuser = ast_config_AST_RUN_USER;
02169 #ifndef __CYGWIN__
02170
02171 if (!is_child_of_nonroot)
02172 ast_set_priority(option_highpriority);
02173
02174 if (!is_child_of_nonroot && rungroup) {
02175 struct group *gr;
02176 gr = getgrnam(rungroup);
02177 if (!gr) {
02178 ast_log(LOG_WARNING, "No such group '%s'!\n", rungroup);
02179 exit(1);
02180 }
02181 if (setgid(gr->gr_gid)) {
02182 ast_log(LOG_WARNING, "Unable to setgid to %d (%s)\n", (int)gr->gr_gid, rungroup);
02183 exit(1);
02184 }
02185 if (setgroups(0, NULL)) {
02186 ast_log(LOG_WARNING, "Unable to drop unneeded groups\n");
02187 exit(1);
02188 }
02189 if (option_verbose)
02190 ast_verbose("Running as group '%s'\n", rungroup);
02191 }
02192
02193 if (!is_child_of_nonroot && runuser) {
02194 struct passwd *pw;
02195 pw = getpwnam(runuser);
02196 if (!pw) {
02197 ast_log(LOG_WARNING, "No such user '%s'!\n", runuser);
02198 exit(1);
02199 }
02200 if (!rungroup) {
02201 if (setgid(pw->pw_gid)) {
02202 ast_log(LOG_WARNING, "Unable to setgid to %d!\n", (int)pw->pw_gid);
02203 exit(1);
02204 }
02205 if (initgroups(pw->pw_name, pw->pw_gid)) {
02206 ast_log(LOG_WARNING, "Unable to init groups for '%s'\n", runuser);
02207 exit(1);
02208 }
02209 }
02210 if (!rungroup && initgroups(runuser, pw->pw_gid)) {
02211 ast_log(LOG_WARNING, "Unable to initialize supplementary group list for %s\n", runuser);
02212 exit(1);
02213 }
02214 if (setuid(pw->pw_uid)) {
02215 ast_log(LOG_WARNING, "Unable to setuid to %d (%s)\n", (int)pw->pw_uid, runuser);
02216 exit(1);
02217 }
02218 setenv("ASTERISK_ALREADY_NONROOT","yes",1);
02219 if (option_verbose)
02220 ast_verbose("Running as user '%s'\n", runuser);
02221 }
02222
02223 #endif
02224
02225 #ifdef linux
02226
02227 if (geteuid() && option_dumpcore) {
02228 if (prctl(PR_SET_DUMPABLE, 1, 0, 0, 0) < 0) {
02229 ast_log(LOG_WARNING, "Unable to set the process for core dumps after changing to a non-root user. %s\n", strerror(errno));
02230 }
02231 }
02232
02233 #endif
02234
02235 term_init();
02236 printf(term_end());
02237 fflush(stdout);
02238
02239 if (option_console && !option_verbose)
02240 ast_verbose("[ Initializing Custom Configuration Options ]");
02241
02242 register_config_cli();
02243 read_config_maps();
02244
02245
02246 if (option_console) {
02247 if (el_hist == NULL || el == NULL)
02248 ast_el_initialize();
02249
02250 if (!ast_strlen_zero(filename))
02251 ast_el_read_history(filename);
02252 }
02253
02254 if (ast_tryconnect()) {
02255
02256 if (option_remote) {
02257 if (option_exec) {
02258 ast_remotecontrol(xarg);
02259 quit_handler(0, 0, 0, 0);
02260 exit(0);
02261 }
02262 printf(term_quit());
02263 ast_register_verbose(console_verboser);
02264 WELCOME_MESSAGE;
02265 ast_remotecontrol(NULL);
02266 quit_handler(0, 0, 0, 0);
02267 exit(0);
02268 } else {
02269 ast_log(LOG_ERROR, "Asterisk already running on %s. Use 'asterisk -r' to connect.\n", (char *)ast_config_AST_SOCKET);
02270 printf(term_quit());
02271 exit(1);
02272 }
02273 } else if (option_remote || option_exec) {
02274 ast_log(LOG_ERROR, "Unable to connect to remote asterisk (does %s exist?)\n",ast_config_AST_SOCKET);
02275 printf(term_quit());
02276 exit(1);
02277 }
02278
02279 unlink((char *)ast_config_AST_PID);
02280 f = fopen((char *)ast_config_AST_PID, "w");
02281 if (f) {
02282 fprintf(f, "%d\n", (int)getpid());
02283 fclose(f);
02284 } else
02285 ast_log(LOG_WARNING, "Unable to open pid file '%s': %s\n", (char *)ast_config_AST_PID, strerror(errno));
02286
02287 if (option_daemonize ||
02288 (!option_verbose && !option_debug && !option_nofork && !option_console)
02289 ) {
02290 daemon(0,0);
02291 ast_mainpid = getpid();
02292
02293 unlink((char *)ast_config_AST_PID);
02294 f = fopen((char *)ast_config_AST_PID, "w");
02295 if (f) {
02296 fprintf(f, "%d\n", ast_mainpid);
02297 fclose(f);
02298 } else
02299 ast_log(LOG_WARNING, "Unable to open pid file '%s': %s\n", (char *)ast_config_AST_PID, strerror(errno));
02300 ast_mainpid = getpid();
02301 }
02302
02303
02304 if (test_for_thread_safety())
02305 ast_verbose("Warning! Asterisk is not thread safe.\n");
02306
02307 ast_makesocket();
02308 sigemptyset(&sigs);
02309 sigaddset(&sigs, SIGHUP);
02310 sigaddset(&sigs, SIGTERM);
02311 sigaddset(&sigs, SIGINT);
02312 sigaddset(&sigs, SIGPIPE);
02313 sigaddset(&sigs, SIGWINCH);
02314 pthread_sigmask(SIG_BLOCK, &sigs, NULL);
02315 if (option_console || option_verbose || option_remote)
02316 ast_register_verbose(console_verboser);
02317
02318 if (option_verbose || option_console) {
02319 WELCOME_MESSAGE;
02320 }
02321 if (option_console && !option_verbose)
02322 ast_verbose("[ Booting...");
02323
02324 signal(SIGURG, urg_handler);
02325 signal(SIGINT, __quit_handler);
02326 signal(SIGTERM, __quit_handler);
02327 signal(SIGHUP, hup_handler);
02328 signal(SIGCHLD, child_handler);
02329 signal(SIGPIPE, SIG_IGN);
02330
02331
02332
02333
02334 srand((unsigned int) getpid() + (unsigned int) time(NULL));
02335 srandom((unsigned int) getpid() + (unsigned int) time(NULL));
02336
02337 if (init_logger()) {
02338 printf(term_quit());
02339 exit(1);
02340 }
02341 if (dnsmgr_init()) {
02342 printf(term_quit());
02343 exit(1);
02344 }
02345
02346 if (load_modules(1)) {
02347 printf(term_quit());
02348 exit(1);
02349 }
02350 ast_channels_init();
02351 if (init_manager()) {
02352 printf(term_quit());
02353 exit(1);
02354 }
02355 if (ast_cdr_engine_init()) {
02356 printf(term_quit());
02357 exit(1);
02358 }
02359 if (ast_device_state_engine_init()) {
02360 printf(term_quit());
02361 exit(1);
02362 }
02363 ast_rtp_init();
02364 if (ast_image_init()) {
02365 printf(term_quit());
02366 exit(1);
02367 }
02368 if (ast_file_init()) {
02369 printf(term_quit());
02370 exit(1);
02371 }
02372 if (load_pbx()) {
02373 printf(term_quit());
02374 exit(1);
02375 }
02376 if (init_framer()) {
02377 printf(term_quit());
02378 exit(1);
02379 }
02380 if (astdb_init()) {
02381 printf(term_quit());
02382 exit(1);
02383 }
02384 if (ast_enum_init()) {
02385 printf(term_quit());
02386 exit(1);
02387 }
02388 if (load_modules(0)) {
02389 printf(term_quit());
02390 exit(1);
02391 }
02392
02393 dnsmgr_start_refresh();
02394
02395 #if 0
02396
02397
02398 read_ast_cust_config();
02399 reload_logger(0);
02400 reload_manager();
02401 ast_enum_reload();
02402 ast_rtp_reload();
02403 #endif
02404
02405
02406
02407
02408 if (option_console && !option_verbose)
02409 ast_verbose(" ]\n");
02410 if (option_verbose || option_console)
02411 ast_verbose(term_color(tmp, "Asterisk Ready.\n", COLOR_BRWHITE, COLOR_BLACK, sizeof(tmp)));
02412 if (option_nofork)
02413 consolethread = pthread_self();
02414 fully_booted = 1;
02415 pthread_sigmask(SIG_UNBLOCK, &sigs, NULL);
02416 #ifdef __AST_DEBUG_MALLOC
02417 __ast_mm_init();
02418 #endif
02419 time(&ast_startuptime);
02420 ast_cli_register_multiple(core_cli, sizeof(core_cli) / sizeof(core_cli[0]));
02421 if (option_console) {
02422
02423
02424 char title[256];
02425 set_icon("Asterisk");
02426 snprintf(title, sizeof(title), "Asterisk Console on '%s' (pid %d)", hostname, ast_mainpid);
02427 set_title(title);
02428
02429 for (;;) {
02430 buf = (char *)el_gets(el, &num);
02431 if (buf) {
02432 if (buf[strlen(buf)-1] == '\n')
02433 buf[strlen(buf)-1] = '\0';
02434
02435 consolehandler((char *)buf);
02436 } else {
02437 if (write(STDOUT_FILENO, "\nUse EXIT or QUIT to exit the asterisk console\n",
02438 strlen("\nUse EXIT or QUIT to exit the asterisk console\n")) < 0) {
02439
02440 int fd;
02441 fd = open("/dev/null", O_RDWR);
02442 if (fd > -1) {
02443 dup2(fd, STDOUT_FILENO);
02444 dup2(fd, STDIN_FILENO);
02445 } else
02446 ast_log(LOG_WARNING, "Failed to open /dev/null to recover from dead console. Bad things will happen!\n");
02447 break;
02448 }
02449 }
02450 }
02451
02452 }
02453
02454 for(;;) {
02455 struct pollfd p = { -1 , 0, 0 };
02456 poll(&p, 0, -1);
02457 }
02458 return 0;
02459 }