4.3BSD/usr/contrib/dsh/src/dsh.c

Compare this file to the similar file:
Show the results in this format:

#include <sys/types.h>
#include <stdio.h>
#include <errno.h>
#include <sys/wait.h>
#include "dsh.h"

int	errno;		/* global error location */

/* options */
bool	fflg = FALSE;		/* if TRUE fanout stdin */
bool	hflg = FALSE;		/* if TRUE use specified host */
bool	vflg = FALSE;		/* tell hosts */
bool	nflg = FALSE;		/* same as for rsh */
bool	aflg = FALSE;		/* true if all nodes to be used */
bool	sflg = FALSE;		/* like -n for make */

/* files to be rcp'd for input or output */
struct rcpfile {
    char	*r_name;	/* name of the file */
    struct rcpfile *r_next;
};
struct rcpfile	*rcpin = 0;	/* list of files to copy to */
struct rcpfile	*rcpout = 0;	/* list of files to copy from */

char		*av[100];	/* the command */
union wait	pstatus;	/* the return status of the job */
struct hostdef	*thehost;	/* the hosts */
char		*spechost;	/* the specified host */

/* external routines */
int		error();
struct hostdef	*highest();
int		getbids();
double		atof();
bool		aresynonyms();

main(argc, argv)
int	argc;
char	*argv[];
{
    int	inda, indc, ind;
    struct rcpfile *lin, *lout, *next;
    struct hostdef *hp;
    
    /* now worry about the commands */
    for (inda = 1; inda < argc; inda++) {
	
	/* process an opton */
	if (argv[inda][0] == '-') {
	    ind = inda;
	    for (indc = 1; argv[ind][indc] != NULL; indc++) {
		switch (argv[ind][indc]) {

		/* all nodes are specified */
		case 'a':
		    aflg = TRUE;
		    break;

		case 's':
		    sflg = TRUE;
		    break;
		
		/* fanout input */
		case 'f':
		    fflg = TRUE;
		    break;

		/* specify  hosts */
		case 'h':
		    inda++;
		    if (inda < argc) {
			hflg = TRUE;
			spechost = argv[inda];
		    } else {
			fprintf (stderr, "%s: no host after -h\n", argv[0]);
			exit (-1);
		    }
		    break;

		/* specify input files */
		case 'i':
		    inda++;
		    if (inda < argc) {
			next = new (struct rcpfile);
			if (rcpin == 0) {
			    rcpin = next;
			} else {
			    lin->r_next = next;
			}
			lin = next;
			lin->r_next = 0;
			lin->r_name = argv[inda];
		    } else {
			fprintf (stderr, "%s: no input file after -i\n", argv[0]);
			exit (-1);
		    }
		    break;

		/* specify output files */
		case 'o':
		    inda++;
		    if (inda < argc) {
			next = new (struct rcpfile);
			if (rcpout == 0) {
			    rcpout = next;
			} else {
			    lout->r_next = next;
			}
			lout = next;
			lout->r_next = 0;
			lout->r_name = argv[inda];
		    } else {
			fprintf (stderr, "%s: no output file after -o\n", argv[0]);
			exit (-1);
		    }
		    break;

		/* pipe from /dev/null */
		case 'n':
		    nflg = TRUE;
		    break;

		/* tell which machine we're using */
		case 'v':
		    vflg = TRUE;
		    break;

		default:
		    fprintf (stderr, "usage: %s [-anv][-io file] <command>\n", argv[0]);
		    exit (-1);
		}
	    }
	} else {
	    break;
	}
    }

    /* pick up the command */
    for (ind = 0; inda < argc; inda++, ind++) {
	av[ind] = argv[inda];
    }
    av[ind] = 0;

    /* process the defaults file */
    getnodes();

    /* see if anyone wants to bid */
    getbids(av, thehost);

    /* execute the command */
    hp = highest ();
    if (hp == 0) {
	error ("no machine bid for the command");
    }
    if (aflg) {
	do {
	    rexecute (hp);
	    hp = highest ();
	} while (hp != 0);
    } else {
	rexecute (hp);
    }

    if (pstatus.w_T.w_Termsig != 0) {
	fprintf (stderr, "(signal %d)", pstatus.w_T.w_Termsig);
	pstatus.w_T.w_Retcode = 0;
    }
    if (pstatus.w_T.w_Coredump == 1) {
	fprintf (stderr, "(core dumped)\n");
	pstatus.w_T.w_Retcode = 0;
    } 

    exit (pstatus.w_T.w_Retcode);
}

/*
 *	find out which nodes to use 
 */
char *
skipgrey(p)
char	*p;
{
    while (*p == ' ' || *p == '\t' || *p == ',' || *p == ')' || *p == '*')
	p++;
    return (p);
}

char *
token (to, sp)
char *to;
char *sp;
{
    while (*sp != ' ' && *sp != '\t' && *sp != ',' && *sp !=')' && *sp != 0) {
	*to++ = *sp++;
    }
    return (sp);
}

getnodes()
{
    char *sp;
    struct hostdef *last, *next;
    bool account;
    double weight;
    char buf[132];
    int rv;

    thehost = 0;
    rv = getstringrc (".dshrc", "hosts", buf);
    if (rv < 0) {
	rv = getstringrc ("/usr/lib/dshrc", "hosts", buf);
	if (rv < 0) {
	    error ("dsh: no hosts in rc files");
	}
    }

    /* convert to reasonable format */
    sp = buf;
    while (*sp != 0) {
	sp = skipgrey (sp);

	/* get the multiplier */
	weight = 1.0;
	if ((*sp >= '0' && *sp <= '9') || *sp == '.') {
	    weight = atof (sp);
	    for (;*sp != '*' && *sp != 0; sp++);
	    sp = skipgrey (sp);
	}

	if (*sp != 0) {

	    /* allocate some space and chain it in */
	    next = new (struct hostdef);
	    if (thehost == 0) {
		thehost = next;
	    } else {
		last->h_next = next;
	    }
	    last = next;
	    last->h_next = 0;
	    last->h_weight = weight;

	    /* pick up the entry */
	    if (*sp == '(') {
		sp++;
		sp = skipgrey (sp);
		account = TRUE;
	    } else {
		account = FALSE;
	    }
	    sp = token (last->h_name, sp);
	    if (account) {
		sp = skipgrey (sp);
		sp = token (last->h_user, sp);
	    } else {
		*(last->h_user) = 0;
	    }
	}
    }
}

/*
 *	execute a command
 */
execute (argv, block, justtell, ignore)
char	*argv[];	/* the command */
bool	block;		/* if true, block till the command is done */
bool	justtell;	/* true if we shouldn't execute when debuging */
bool	ignore;		/* ignore output */
{
    int		argc;
    int		pid, rv;
    int		status, fd;

    if (sflg) {

	/* just say what we'll do */
	for (argc = 0;argv[argc] != 0; argc++) {
	    printf ("%s ", argv[argc]);
	}
	printf ("\n");
    }
    if (!(justtell && sflg)) {

	/* really do it */
	if (pid = fork()) {
	    if (block) {
		do {
		    rv = wait (&status);
		} while (rv != -1 && rv != pid);
	    }
	} else {
	    if (ignore) {
		fd = open ("/dev/null", 2);
		dup2 (fd, 1);
		dup2 (fd, 2);
	    }
	    execvp (argv[0], argv);
	    _exit (0);
	}
    }
}

/*
 *	remotely execute the command
 */
rexecute (hp)
struct hostdef	*hp;		/* the host to execute on */
{
    struct rcpfile *fp;
    int		rv;
    int		argc, ac;
    char	*argv[200];
    char	mydir[PATHSIZE];
    bool	local;
	
    if (vflg || aflg) {
	fprintf (stderr, ">>%s<<\n", hp->h_name);
    }
    argc = 0;
    local = aresynonyms (hp->h_name, myhostname());
    if (!local) {
	/* get our directory if we're going to copy files */
	if (rcpin != 0 || rcpout != 0) {
	    getwd (mydir);
	}

	/* make the directory we're going to use */
	argv[argc++] = "(";
	argv[argc++] = "mkdir";
	argv[argc++] = hp->h_dir;
	argv[argc++] = ";";

	/* and hop to it */
	argv[argc++] = "cd";
	argv[argc++] = hp->h_dir;
	argv[argc++] = ";";

	/* copy over any files */
	if (rcpin != 0) {
	    argv[argc++] = "rcp";
	    for (fp = rcpin; fp != 0; fp = fp->r_next) {
		argv[argc] = (char *) malloc (HOSTNAMESIZE+2*PATHSIZE);
		if (fp->r_name[0] == '/' || fp->r_name[0] == '~') {
		    sprintf (argv[argc++], "%s:%s", myhostname(), fp->r_name);
		} else {
		    sprintf (argv[argc++], "%s:%s/%s", myhostname(),
			mydir, fp->r_name);
		}
	    }
	    argv[argc++] = ".";
	    argv[argc++] = ";";
	}
    }

    /* execute the command */
    for (ac = 0; av[ac] != 0; ac++) {
	argv[argc++] = av[ac];
    }
    argv[argc++] = ";";

    if (!local) {

	/* copy back any files */
	if (rcpout != 0) {
	    argv[argc++] = "rcp";
	    for (fp = rcpout; fp != 0; fp = fp->r_next) {
		argv[argc++] = fp->r_name;
	    }
	    argv[argc] = (char *) malloc (HOSTNAMESIZE+2*PATHSIZE);
	    sprintf (argv[argc++], "%s:%s", myhostname(), mydir);
	    argv[argc++] = ";";
	}

	/* clean up the directory */
	argv[argc++] = "cd";
	argv[argc++] = "..";
	argv[argc++] = ";";
	argv[argc++] = "/bin/rm";
	argv[argc++] = "-fr";
	argv[argc++] = hp->h_dir;
	argv[argc++] = ")";
    }
    argv[argc] = 0;
    
    rshell (hp, argv, TRUE, nflg, TRUE, FALSE);
}

rshell (hp, av, block, usenflg, justtell, ignore)
struct hostdef	*hp;		/* all about the host */
char		*av[];		/* the command */
bool		block;		/* true if we should block */
bool		usenflg;	/* true if we should use the n flag */
bool		justtell;	/* true if we shouldn't execute when debuging */
bool		ignore;		/* ignore the output from the command */
{
    int		rv;
    int		argc, ac;
    char	*argv[100];
    char	command[256];
    char	*p, *p1;
    bool	local;
	
    argc = 0;
    local = aresynonyms (hp->h_name, myhostname());
    if (local) {
	argv[argc++] = "csh";
	argv[argc++] = "-c";
	argv[argc++] = command;
	p = command;
	for (ac = 0; av[ac] != 0; ac++) {
	    *p++ = ' ';
	    for (p1 = av[ac]; *p1 != 0;){
		*p++ = *p1++;
	    }
	}
	*p = 0;
    } else {
	argv[argc++] = "rsh";
	argv[argc++] = hp->h_name;
	if (usenflg) {
	    argv[argc++] = "-n";
	}
	if (*(hp->h_user) != 0) {
	    argv[argc++] = "-l";
	    argv[argc++] = hp->h_user;
	}
	for (ac = 0; av[ac] != 0; ac++) {
	    argv[argc++] = av[ac];
	}
    }
    argv[argc] = 0;
    execute (argv, block, justtell, ignore);
}