/*
 * 5799-WZQ (C) COPYRIGHT = NONE
 * LICENSED MATERIALS - PROPERTY OF IBM
 */
/* $Header:rvdmotd.c 12.0$ */
/* $ACIS:rvdmotd.c 12.0$ */
/* $Source: /ibm/acis/usr/src/ibm/rvd/cntrl/RCS/rvdmotd.c,v $ */

#ifndef lint
static char *rcsid = "$Header:rvdmotd.c 12.0$";
#endif


#ifndef lint
static char *rcsid_rvdmotd_c = "$Header:rvdmotd.c 12.0$";
#endif	lint

/* Copyright 1984 by the Massachusetts Institute of Technology */
/* See permission and disclaimer notice in the file "notice.h" */
#include "notice.h"


#include <stdio.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/file.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <machineio/vdreg.h>

#include "canon.h"

#define	TIMEOUT		5
#define	NRXMIT		5
#define	BUFLEN		4096	/* Long enough to include an authenticator. */

#define	MSGSIZE		400
#define	MSGTHRSH	(MSGSIZE - 80)

extern errno;
extern	char	*myname;

char	*getpass();

static	char	msg[MSGSIZE], *p = msg;
static	int	msglen = 0;

rvdsetm(argc, argv)
	int	argc;
	char	**argv;
{
	struct	sockaddr_in	*phost;
	struct	sockaddr_in	*resolve_host();
	char	query[60];
	char	line[80], passwd[VD_CAPAB_LEN], *host;
	struct	in_addr	server;
	char	sbuf[BUFLEN];
	int	fflag = 0;
	int	rflag = 0;
	int	debug = 0;
	int	status;

	msg[0] = '\0';
	passwd[0] = '\0';

	/*
	 * check for debugging
	 */
	if(argc > 1 && ! strcmp(argv[1], "-d")) {
		--argc;
		++argv;
		debug = 1;
	}

	while(argc > 1 && *argv[1] == '-') {
	top:
		++argv[1];
		switch(*argv[1]) {
		case 'r':
			++rflag;
			goto top;
		case 'f':
			++fflag;
			goto top;
		default:
			fprintf(stderr, "%s: illegal flag '%c'\n", myname,
			  *argv[1]);
			exit(-5);
		case '\0':
			++argv;
			--argc;
			break;
		}
	}

	/*
	 * just server name
	 */
	if(argc == 3 && ! rflag) {
		sprintf(msg, "%s\n", argv[2]);
		++rflag;
	}
	else if(argc != 2) {
	/*
	 * argument count isn't kosher
	 */
		fprintf(stderr, "usage: %s [-r] [-f] server [message]\n",
		  myname);
		exit(-1);
	}

	host = argv[1];

	/*
	 * check server name
	 */
	if((phost = resolve_host(host)) != NULL)
		server = phost->sin_addr;
	else {
		fprintf(stderr, "%s: %s: unknown host\n", myname, argv[1]);
		exit(-2);
	}

	/*
	 * if no second arg, read message from stdin.
	 */
	if(! rflag) {
		if(isatty(0))	/* on terminal */
			printf("Message for %s:\n", host);

		while(msglen < MSGTHRSH
		  && fgets(line, sizeof(line), stdin) != NULL) {
			if(line[0] == '.' && line[1] == '\n' && line[2] == '\0')
				break;
			append(line);
		}
	}

	if(debug)
		fprintf(stderr, "\nmessage:\n%s\n", msg);


	/* Try an authenticated rvdsetm first.  If the set_message fails and
	 * fflag (force) is set then no password is used anyway so just exit.
	 */
#ifdef	KERBEROS
	strcpy(query, "operation=set_message\npassword=\nmessage=%s\n");
	csprintf(sbuf, query, msg);
	if (get_auth(sbuf, host, myname, debug)) {
		status = ctl_init_send_close(sbuf, inet_ntoa(server), debug);
		if (status == NULL || fflag)
			exit(status);
	}
#endif	KERBEROS


	strcpy(passwd, fflag ? "" : getpass("Password: ", VD_CAPAB_LEN));

	strcpy(query, "operation=set_message\npassword=%s\n");
#ifndef	MSGREQUIRED
	if(msg[0])
#endif	MSGREQUIRD
		strcat(query, "message=%s\n");

	csprintf(sbuf, query, passwd, msg);

	/*
	 * send to host
	 */
	exit(ctl_init_send_close(sbuf, inet_ntoa(server), debug));
}

append(s)
char	*s;
{
	while(*s) {
		if(*s == '\n')
			*p++ = '\r';
		*p++ = *s++;
	}
	*p = '\0';
	msglen = p - msg;
}


static	struct in_addr	hosts[20];
static	int	nhosts = 0;
static	int	debug = 0;

char	*vd_control_name = "/dev/rvdcontrol";

rvdgetm(argc, argv)
char	**argv;
{
struct	vd_longstat	vd_stat;
struct	vd_longstat	*stats = &vd_stat;
struct	vd_long_dev	*drives;
struct sockaddr_in	*phost, *resolve_host();
int	i, error, vexit = 0;
int	vdcntrl;


	/*
	 * check for debugging
	 */
	if(argc > 1 && ! strcmp(argv[1], "-d")) {
		--argc;
		++argv;
		debug = 1;
	}

	/*
	 * check argument count
	 */
	if(argc < 1 || 2 < argc) {
		fprintf(stderr, "usage: %s [server]\n", myname);
		exit(-1);
	}

	/*
	 * if arg was given, interpret as hostname
	 */
	if(argc == 2)
		if((phost = resolve_host(argv[1])) != NULL)
			addhost(phost->sin_addr);
		else {
			fprintf(stderr, "%s: %s: unknown host\n", myname,
			  argv[1]);
			exit(-3);
		}
	/*
	 * otherwise, get hosts from vd_device info
	 */
	else {
		if((vdcntrl = open(vd_control_name, O_RDONLY, 0)) < 0) {
			perror(vd_control_name);
			return(1);
		}

		if(ioctl(vdcntrl, VDIOCGETSTAT, &stats)) {
			perror(myname);
			exit(1);
		}

		drives = (struct vd_long_dev *)
			malloc(vd_stat.num_drives * sizeof(struct vd_long_dev));
		if(drives == 0) {
			fprintf(stderr, "%s: Could not malloc drive structs\n",
				myname);
			exit(1);
		}
		if(ioctl(vdcntrl, VDIOCGETDRIVE, &drives)) {
			perror(myname);
			exit(1);
		}
		/*
		 * add each host associated with an active drive
		 */
		for(i = 0; i < vd_stat.num_drives; ++i)
			if(drives[i].vd_device.state == SPUNUP)
				addhost(drives[i].vd_device.server);
	}

	/*
	 * if no hosts are connected to, print a message so the
	 * user doesn't wonder what happened.
	 */
	if(! nhosts) {
		fprintf(stderr, "%s: no virtual disks active\n", myname);
		exit(0);
	}

	/*
	 * ping each host
	 */
	for(i = 0; i < nhosts; ++i)
		if((error = rvd_getmotd(hosts[i], debug)) != 0)
			vexit = error;

	exit(vexit);
}

rvd_getmotd(server, debug)

struct in_addr server;

{

int	vexit;
struct	hostent *hp;
char	*hname;

	if (hp = (struct hostent *)gethostbyaddr(&server,
	sizeof(server), AF_INET)) {
		hname = hp->h_name;
	} else {
		hname = (char *)inet_ntoa(server);
	}
	vexit = ctl_init_send_close("operation=get_message\n", hname, debug);
	if(vexit  == 0 && F(_MESSAGE))
		printf("RVD Message of the Day from %s:\n%s",
			hname, V(_MESSAGE));
	return(vexit);
}

/*
 * Search array of host addresses for this host.  If not present,
 * add it to the list.
 */

addhost(h)

struct in_addr	h;

{
	int i;

	for(i = 0; i < nhosts; ++i)
		if(hosts[i].s_addr == h.s_addr)
			return;

	if(debug)
		fprintf(stderr, "adding host [%s]\n", inet_ntoa(h));

	hosts[nhosts++] = h;
}
