Show rbsh.c syntax highlighted
/*
*
* Copyright (c) 2005 The Regents of the University of California. All
* rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Neither the name of the University nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/*
* rbsh: Remote Broadcast sh
*
* This utility is a broadcast remote shell
*
* $Id: rbsh.c,v 1.11 2006/07/15 22:25:19 girod Exp $
*/
char rbsh_c_id[] = "$Id: rbsh.c,v 1.11 2006/07/15 22:25:19 girod Exp $";
#include <emproxy/emproxy.h>
#include <readline/readline.h>
#include <readline/history.h>
#include <sys/wait.h>
#include <emrun/emrun.h>
#include <link/link.h>
#include <curses.h>
int session_id;
int seqno=1;
emproxy_client_context_t *client = NULL;
buf_t *script = NULL;
int batchmode = 0;
#define MAX_NODES 256
int reply_count=0;
int last_reply_count=0;
int curr_seqno=0;
node_id_t repliers[MAX_NODES];
node_id_t last_repliers[MAX_NODES];
g_event_t *delta_timer = NULL;
void usage(char *s)
{
char *p1, *p2;
char *m_usage;
char *m_expl;
misc_usage(&m_usage, &m_expl);
emproxy_usage(&p1, &p2);
fprintf(stderr,
"%s: %s\n"
" %s\n"
" [--timeout <ms>] [<shell command>]\n\n"
"%s%s"
" --timeout <ms>: end after <ms> delay (non-interactive only)\n"
"\n"
"Remaining arguments are interpreted as a shell command to execute.\n"
"If no shell command is specified on the command line, %s will run\n"
"in interactive mode.\n"
"\n"
,
s, p1, m_usage, p2, m_expl, s);
exit(1);
}
void rbsh_shutdown(void *data)
{
if (!batchmode)
rl_callback_handler_remove();
exit(0);
}
int rbsh_timeout(void *data, int interval, g_event_t *ev)
{
exit(0);
return TIMER_DONE;
}
void update_prompt()
{
if (!batchmode) {
char prompt[20];
sprintf(prompt, "[%d] rbsh %d> ", reply_count, seqno);
rl_set_prompt(prompt);
}
}
int __cmp(const void *a, const void *b)
{
return (*((int*)a) - *((int*)b));
}
void sort_repl(node_id_t *replies, int reply_count)
{
qsort(replies, reply_count, sizeof(node_id_t), __cmp);
}
void print_sorted()
{
int i;
sort_repl(repliers, reply_count);
for (i=0; i<reply_count; i++)
printf("%d ", repliers[i]);
printf("[%d total]\n", reply_count);
}
int change_since_last()
{
if (reply_count == last_reply_count) {
sort_repl(repliers, reply_count);
sort_repl(last_repliers, last_reply_count);
if (memcmp(repliers, last_repliers, reply_count*sizeof(node_id_t)) == 0)
return 0;
}
return 1;
}
void print_delta()
{
int i,j;
int missed=0;
int added=0;
sort_repl(repliers, reply_count);
sort_repl(last_repliers, last_reply_count);
for (i=0; i<last_reply_count; i++) {
for (j=0; j<reply_count; j++) {
if (last_repliers[i] == repliers[j])
goto found;
}
printf("%d ", last_repliers[i]);
missed++;
found:
continue;
}
if (missed) printf("[%d missed]\n", missed);
for (i=0; i<reply_count; i++) {
for (j=0; j<last_reply_count; j++) {
if (repliers[i] == last_repliers[j])
goto found2;
}
printf("%d ", repliers[i]);
added++;
found2:
continue;
}
if (added) printf("[%d added]\n", added);
}
int trigger_delta(void *data, int interval, g_event_t *ev)
{
if (change_since_last()) {
printf("\r \r");
print_delta();
rl_reset_line_state();
rl_forced_update_display();
}
return TIMER_DONE;
}
int check_seqno(int new_seqno)
{
if (curr_seqno < new_seqno) {
last_reply_count = reply_count;
memmove(last_repliers, repliers, sizeof(repliers));
reply_count = 0;
curr_seqno = new_seqno;
return 1;
}
else if (curr_seqno == new_seqno) return 1;
return 0;
}
int handle_result(emproxy_reply_hdr_t *reply, void *data)
{
int length = reply->data_length - sizeof(emproxy_cmd_reply_hdr_t);
char *buf = malloc(length+1);
emproxy_cmd_reply_hdr_t *hdr = (emproxy_cmd_reply_hdr_t *)(reply->data);
memmove(buf, hdr->data, length);
buf[length] = 0;
printf("\r \r");
char *node = "";
if (reply->node_id == SIM_COMPONENT_ID) node = "SIM";
else node = print_if_id(reply->node_id);
printf("Node=%s, reply to seqno=%d: ",
node, -(reply->data_id));
if (hdr->exited) {
if (WIFEXITED(hdr->exit_status))
printf("Exit status %d ", WEXITSTATUS(hdr->exit_status));
if (WIFSIGNALED(hdr->exit_status))
printf("Terminated, signal %s", signal_name(WTERMSIG(hdr->exit_status)));
}
else {
printf("Hasn't exited yet...");
}
printf("\n%s", buf);
if (strlen(buf) > 0 && buf[strlen(buf)-1] != '\n')
printf("\n");
/* reset.. */
if (check_seqno(-(reply->data_id))) {
int i;
for (i=0; i<reply_count; i++)
if (repliers[i] == reply->node_id)
goto found;
repliers[reply_count++] = reply->node_id;
}
found:
if (!batchmode) {
/* (re)set delta timer */
g_event_destroy(delta_timer);
g_timer_add(2000, trigger_delta, NULL, NULL, &(delta_timer));
update_prompt();
rl_reset_line_state();
rl_forced_update_display();
}
return EVENT_RENEW;
}
void rbsh_handle_line(char *line)
{
if (line) {
/* exit case.. */
if (strcmp(line, "exit") == 0)
rbsh_shutdown(NULL);
/* help */
if (strcmp(line, "help") == 0) {
printf("Prompt format: [X] rbsh Y>, where\n"
" X is the number of nodes that replied to the last request\n"
" Y is the sequence number of the next request\n"
"Local commands:\n"
" help: prints this message\n"
" abort: discards current command\n"
" check: prints current command\n"
" delta: prints out any missing/added nodes since last command\n"
" sorted: prints out sorted list of node IDs\n"
" exit: exits\n"
);
return;
}
/* abort */
if (strcmp(line, "abort") == 0) {
printf("ABORT! Discarding these commands:\n%s", script ? script->buf : "");
buf_free(script);
script = NULL;
return;
}
/* check */
if (strcmp(line, "check") == 0) {
printf("Commands entered so far:\n%s", script ? script->buf : "");
return;
}
/* delta case */
if (strcmp(line, "delta") == 0) {
print_delta();
return;
}
/* sorted case */
if (strcmp(line, "sorted") == 0) {
print_sorted();
return;
}
}
/* if there is something there.. */
if (line && strlen(line) > 0) {
if (script == NULL)
script = buf_new();
bufprintf(script, "%s\n", line);
/* add to history */
add_history(line);
}
else {
/* send the message */
char cmd[4096];
sprintf(cmd, "session=%d:type=command:seq=%d:src=%d\ncmd=%s\n",
session_id, seqno, my_node_id, script ? script->buf : "");
/* free the last script */
buf_free(script);
script = NULL;
/* thrice! */
emproxy_client_set_command(client, cmd);
emproxy_client_set_command(client, cmd);
emproxy_client_set_command(client, cmd);
/* note this seqno */
check_seqno(seqno);
/* inc seqno */
seqno++;
/* update prompt */
if (line) update_prompt();
}
}
int rbsh_handle_input(void *data, int fd, int cond, g_event_t *ev)
{
if (cond == FUSD_NOTIFY_INPUT)
rl_callback_read_char();
else {
fprintf(stderr, "Read error from stdin..\n");
rbsh_shutdown(NULL);
}
return EVENT_RENEW;
}
int main(int argc, char *argv[])
{
uint timeout=0;
emproxy_client_opts_t opts = {
handler: handle_result,
refresh_interval: -1
};
/* get group id, etc */
misc_init(&argc, argv, CVSTAG);
/* usage */
if (misc_parse_out_switch(&argc, argv, "help", 'h'))
usage(argv[0]);
/* delay */
misc_parse_option_as_uint(&argc, argv, "timeout", 0, &timeout);
/* emproxy options parsing */
emproxy_client_config(&opts, &argc, argv);
/* grab command line */
if (argc > 1) {
int i;
script = buf_new();
for (i=1; i<argc; i++) {
bufprintf(script, "%s ", argv[i]);
}
batchmode = 1;
}
session_id = random();
/* install event */
if (emproxy_client_open(&opts, &client) < 0) {
fprintf(stderr, "Error connecting to client: %m\n");
exit(1);
}
/* install event on stdin */
if (script == NULL) {
/* set xterm title bar */
buf_t *buf = buf_new();
emproxy_describe_opts_to_buf(buf, "rbsh", &opts);
printf("\033]0;%s\007", buf->buf);
buf_free(buf);
/* intro message */
printf("\nWelcome to the rbsh remote broadcast interactive shell.\n"
"Enter shell commands, followed by a blank line to send.\n\n");
/* start up readline */
rl_callback_handler_install("rbsh 1> ", rbsh_handle_line);
if (g_event_add(STDIN_FILENO, FUSD_NOTIFY_INPUT | FUSD_NOTIFY_EXCEPT,
rbsh_handle_input, NULL, NULL, NULL) < 0) {
elog(LOG_WARNING, "Can't create readline event: %m");
exit(1);
}
}
/* single command mode.. */
else {
rbsh_handle_line(NULL);
if (timeout)
g_timer_add(timeout, rbsh_timeout, NULL, NULL, NULL);
}
/* connect to emrun */
emrun_opts_t emrun_opts = {
shutdown: rbsh_shutdown,
};
emrun_init(&emrun_opts);
g_main();
return 1;
}
See more files for this project here