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