/* $Id: jsh.c,v 1.7 2001/08/14 04:43:47 garbled Exp $ */
/*
* Copyright (c) 2000
* Tim Rightnour. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Tim Rightnour.
* 4. The name of Tim Rightnour may not be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY TIM RIGHTNOUR ``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 TIM RIGHTNOUR 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.
*/
#include <errno.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#include "../common/common.h"
#include "../common/sockcommon.h"
#if !defined(lint) && defined(__NetBSD__)
__COPYRIGHT(
"@(#) Copyright (c) 2000\n\
Tim Rightnour. All rights reserved\n");
__RCSID("$Id: jsh.c,v 1.7 2001/08/14 04:43:47 garbled Exp $");
#endif
#ifndef __P
#define __P(protos) protos
#endif
void do_command __P((char **, int, char *));
char *check_node __P((void));
void free_node __P((char *));
void log_bailout __P((int));
/* globals */
int debug, exclusion, grouping;
int errorflag, iportnum, oportnum;
char **rungroup;
char **lumplist;
char *progname, *jsd_host;
group_t *grouplist;
node_t *nodelink;
/*
* jsh contacts the jsd daemon, and asks for a node to work on.
*/
int
main(int argc, char *argv[])
{
int someflag, ch, allflag, showflag;
char *p, *q, *group, *nodename, *username;
node_t *nodeptr;
extern char *optarg;
extern int optind;
iportnum = oportnum = 0;
someflag = 0;
showflag = 0;
exclusion = 0;
debug = 0;
errorflag = 0;
allflag = 0;
grouping = 0;
username = NULL;
nodename = NULL;
group = NULL;
nodeptr = NULL;
nodelink = NULL;
jsd_host = NULL;
progname = p = q = argv[0];
while (progname != NULL) {
q = progname;
progname = (char *)strsep(&p, "/");
}
progname = strdup(q);
while ((ch = getopt(argc, argv, "?adeil:k:p:")) != -1)
switch (ch) {
case 'a': /* set the allrun flag */
allflag = 1;
break;
case 'd': /* set the debug flag */
debug = 1;
break;
case 'e': /* we want stderr to be printed */
errorflag = 1;
break;
case 'i': /* we want tons of extra info */
debug = 1;
break;
case 'l': /* invoke me as some other user */
username = strdup(optarg);
break;
case 'o': /* port to get nodes from jsd on */
oportnum = atoi(optarg);
break;
case 'p': /* port to release nodes to jsd on */
iportnum = atoi(optarg);
break;
case 'h': /* host to connect to jsd on */
jsd_host = strdup(optarg);
break;
case '?': /* you blew it */
(void)fprintf(stderr,
"usage: %s [-aei] [-l username] [-p port] [-o port] "
"[-h hostname] [command ...]\n", progname);
exit(EXIT_FAILURE);
break;
default:
break;
}
argc -= optind;
argv += optind;
if (!iportnum) {
if (getenv("JSD_IPORT"))
iportnum = atoi(getenv("JSD_IPORT"));
else
iportnum = JSDIPORT;
}
if (!oportnum) {
if (getenv("JSD_OPORT"))
oportnum = atoi(getenv("JSD_OPORT"));
else
oportnum = JSDOPORT;
}
if (jsd_host == NULL) {
if (getenv("JSD_HOST"))
jsd_host = strdup(getenv("JSD_HOST"));
else
jsd_host = strdup("localhost");
}
if (jsd_host == NULL)
bailout(__LINE__);
do_command(argv, allflag, username);
exit(EXIT_SUCCESS);
}
char *
check_node()
{
char *buf;
int sock, i;
struct sockaddr_in name;
struct hostent *hostinfo;
/* create socket */
sock = socket(PF_INET, SOCK_STREAM, 0);
if (sock < 0)
bailout(__LINE__);
name.sin_family = AF_INET;
name.sin_port = htons(oportnum);
hostinfo = gethostbyname(jsd_host);
if (hostinfo == NULL) {
(void)fprintf(stderr, "Unknown host %s.\n", jsd_host);
exit(EXIT_FAILURE);
}
name.sin_addr = *(struct in_addr *)hostinfo->h_addr;
if (connect(sock, (struct sockaddr *)&name, sizeof(name)) < 0)
bailout(__LINE__);
i = read_from_client(sock, &buf); /* get a node */
buf[i] = '\0';
if (debug)
printf("Got node %s\n", buf);
(void)close(sock);
return(buf);
}
void
free_node(nodename)
char *nodename;
{
int sock;
char *buf;
struct sockaddr_in name;
struct hostent *hostinfo;
/* create socket */
sock = socket(PF_INET, SOCK_STREAM, 0);
if (sock < 0)
bailout(__LINE__);
name.sin_family = AF_INET;
name.sin_port = htons(iportnum);
hostinfo = gethostbyname(jsd_host);
if (hostinfo == NULL) {
(void)fprintf(stderr, "Unknown host %s.\n", jsd_host);
exit(EXIT_FAILURE);
}
name.sin_addr = *(struct in_addr *)hostinfo->h_addr;
if (connect(sock, (struct sockaddr *)&name, sizeof(name)) < 0)
bailout(__LINE__);
if (debug)
printf("Freeing node %s\n", nodename);
read_from_client(sock, &buf);
if (write_to_client(sock, nodename) != 0)
bailout(__LINE__);
if (debug)
printf("freed node %s\n", nodename);
(void)close(sock);
}
/*
* Do the actual dirty work of the program, now that the arguments
* have all been parsed out.
*/
void
do_command(argv, allrun, username)
char **argv;
char *username;
int allrun;
{
FILE *fd, *in;
char buf[MAXBUF];
char *nodename;
int status, i, piping;
char *p, *command, *rsh;
pipe_t out, err;
pid_t childpid;
i = 0;
piping = 0;
in = NULL;
nodename = NULL;
if (debug)
if (username != NULL)
(void)printf("As User: %s\n", username);
/* construct the command from the remains of argv */
command = (char *)malloc(MAXBUF * sizeof(char));
memcpy(command, "\0", MAXBUF * sizeof(char));
for (p = *argv; p != NULL; p = *++argv ) {
strcat(command, p);
strcat(command, " ");
}
if (debug) {
(void)printf("\nDo Command: %s\n", command);
}
if (strcmp(command,"") == 0) {
piping = 1;
if (isatty(STDIN_FILENO) && piping)
/* are we a terminal? then go interactive! */
(void)printf("%s>", progname);
in = fdopen(STDIN_FILENO, "r");
command = fgets(buf, sizeof(buf), in);
/* start reading stuff from stdin and process */
if (command != NULL)
if (strcmp(command,"\n") == 0)
command = NULL;
} else {
close(STDIN_FILENO);
if (open("/dev/null", O_RDONLY, NULL) != 0)
bailout(__LINE__);
}
if (allrun)
nodename = check_node();
while (command != NULL) {
if (!allrun)
nodename = check_node();
if (debug)
printf("Working node: %s\n", nodename);
if (pipe(out.fds) != 0)
bailout(__LINE__);
if (pipe(err.fds) != 0)
bailout(__LINE__);
/* we set up pipes for each node, to prepare
* for the oncoming barrage of data.
*/
childpid = fork();
switch (childpid) {
/* its the ol fork and switch routine eh? */
case -1:
bailout(__LINE__);
break;
case 0:
if (piping)
close(STDIN_FILENO);
if (dup2(out.fds[1], STDOUT_FILENO) != STDOUT_FILENO)
/* stupid unix tricks vol 1 */
bailout(__LINE__);
if (dup2(err.fds[1], STDERR_FILENO) != STDERR_FILENO)
bailout(__LINE__);
if (close(out.fds[0]) != 0)
bailout(__LINE__);
if (close(err.fds[0]) != 0)
bailout(__LINE__);
rsh = getenv("RCMD_CMD");
if (rsh == NULL)
rsh = strdup("rsh");
if (rsh == NULL)
bailout(__LINE__);
if (debug)
printf("%s %s %s\n", rsh, nodename, command);
if (username != NULL)
/* interestingly enough, this -l thing works great with ssh */
execlp(rsh, rsh, "-l", username, nodename,
command, (char *)0);
else
execlp(rsh, rsh, nodename, command, (char *)0);
bailout(__LINE__);
} /* end switch */
if (close(out.fds[1]) != 0)
/* now close off the useless stuff, and read the goodies */
bailout(__LINE__);
if (close(err.fds[1]) != 0)
bailout(__LINE__);
fd = fdopen(out.fds[0], "r"); /* stdout */
while ((p = fgets(buf, sizeof(buf), fd)))
(void)printf("%s: %s", nodename, p);
fclose(fd);
fd = fdopen(err.fds[0], "r"); /* stderr */
while ((p = fgets(buf, sizeof(buf), fd)))
if (errorflag)
(void)printf("%s: %s", nodename, p);
fclose(fd);
(void)wait(&status);
if (piping) {
if (isatty(STDIN_FILENO) && piping)
/* yes, this is code repetition, no need to adjust your monitor */
(void)printf("%s>", progname);
command = fgets(buf, sizeof(buf), in);
if (command != NULL)
if (strcmp(command,"\n") == 0)
command = NULL;
} else
command = NULL;
if (!allrun)
free_node(nodename);
} /* while loop */
if (allrun)
free_node(nodename);
if (piping) { /* I learned this the hard way */
fflush(in);
fclose(in);
}
}
void
log_bailout(line)
{
bailout(line);
}
syntax highlighted by Code2HTML, v. 0.9.1