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

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


#ifndef lint
static char rcsid_savervd_c[] = "$Header:savervd.c 12.0$";
#endif lint

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


/* Save or restore one or more RVD's to tape.
 * Syntax:
 *	savervd [-m database] [-f tape] disk ...
 */

#include	<stdio.h>
#include	<signal.h>
#include	<sys/types.h>
#include	<netinet/in.h>
#include	<sys/file.h>
#include	<machineio/vdconst.h>

#include	"rvd_types.h"
#include	"custom.h"
#include	"obj.h"
#include	"queue.h"
#include	"ctl_pkt.h"
#include	"physd.h"
#include	"logging.h"
#include	"virtd.h"
#include	"extern.h"
#include	"savervd.h"


unsigned log_flag = LOG_ERR;
char	*rvddb = RVDDB;
char	*tape = TAPE;
char	sbuf[BUFLEN];
char	rbuf[BUFLEN];
char	passw[VD_CAPAB_LEN];
char	bigbuf[BIGBUFSIZE];
boolean	su = FALSE;
boolean	save = FALSE;
boolean	zap = FALSE;
boolean	savephys = FALSE;
boolean	sendctl = FALSE;

/* The following variables are bogus.  They're just here so
 * this routine can link with the physd, virtd routines.  They were
 * added during KERBEROS changes.
 */
char	server_name[1];
boolean	passw_flag = TRUE;
char	*myname;

main (argc, argv)
int	argc;
char	**argv;
{
	char *		cmdname;
	register FILE	*db;
	register char	*pw;
	register int	i;
	register int	len;
	static	char	lbuf[BUFLEN];
	register struct	virtd	*vd;

	setlinebuf(stderr);
	su = (getuid() == 0);

	if (cmdname = (char *) rindex(argv[0], '/'))
		cmdname++;
	else
		cmdname = argv[0];
	myname = cmdname;

	if (strcmp(cmdname, "savervd") == 0)
		save = TRUE;
	else if (strcmp(cmdname, "zaprvd") == 0)
		zap = TRUE;
	else if (strcmp(cmdname, "savephys") == 0) {
		savephys = TRUE;
		save = TRUE;
	} else
		exit(1);

	for (i = 1; i < argc; i++)
		if (argv[i][0] == '-') {
			switch(argv[i][1]) {
			case 'm':		/* set master file name */
				if (++i >= argc)
					goto usage;
				rvddb = argv[i];
				break;

			case 'f':		/* set tape name */
				if (++i >= argc)
					goto usage;
				tape = argv[i];
				break;

			default:
	usage:
				printf("usage: %s [-m database] [-f tape] %s ...\n",
				    cmdname, (savephys ? "physical" :
				    "virtual"));
				exit(1);
			}
		} else
			break;


	while ((len = readlink(rvddb, lbuf, BUFLEN)) > 0) {
		lbuf[len] = '\0';
		rvddb = lbuf;
	}
	if ((db = fopen(rvddb, "r")) == NULL) {
		perror(rvddb);
		exit(1);
	}
	if (flock(fileno(db), LOCK_EX | LOCK_NB) < 0) {
		perror("Unable to lock database file");
		exit(1);
	}

	input_db(db);

	fclose(db);

	for (; i < argc; i++)
		if (savephys)
			do_savephys(argv[i]);
		else {
			if ((vd = vd_lookup(argv[i])) == NULL) {
				fprintf(stderr, "Unknown virtual disk %s\n",
				    argv[i]);
				continue;
			}
			printf("Doing disk %s; this will take about %.2f minutes.\n",
			    vd->vd_pack, vd->vd_blocks / IO_RATE);
			do_op(vd, save);
		}

	exit(0);
}


input_db(db)

/* Input the database file open on the specified file descriptor, building
 * an internal representation of the database.
 */

register FILE	*db;
{
	register int	len;
	struct	sockaddr_in	temp;		/* just for temp */

	pd_init();
	while ((len = get_message(db, sbuf, BUFLEN)) > 0)
		ctl_domsg(&temp, sbuf, len);
}


get_message(infile, buf, len)

/* Read the next message (until an empty line) from the specified input file
 * into the specified buffer, up to len characters.  Returns the size of the
 * message in bytes, or 0 if end-of-file or error.
 */

register FILE	*infile;
char	*buf;
int	len;
{
	register char	*p;
	register int	left;

	for (p = buf, left = len; fgets(p, left, infile) != NULL && *p != '\n';
	    left -= strlen(p), p += strlen(p))
		;
	return(len - left);
}


do_savephys(phys)

/* Save all virtual disks on one physical disk.
 */

char	*phys;				/* physical disk name */
{
	register struct	physd	*pd;
	register struct	virtd	*vd, *td;
	register int	sum;
	int	tapecnt;

	if ((pd = pd_lookup(phys)) == NULL) {
		fprintf(stderr, "Unknown physical disk %s\n", phys);
		return;
	}

	td = (struct virtd *) &(pd->vd_forw);
	vd = q_head(td, struct virtd *);

	while(td != vd) {
		sum += vd->vd_blocks;
		vd = q_head(vd, struct virtd *);
	}

	tapecnt = (sum + (MAXTAPEPOS - 1)) / MAXTAPEPOS;
	printf("This will take %D tape%c\n", tapecnt, (tapecnt != 1 ? 's' :
	    ' '));
	printf("and about %.2f minutes.\n", (sum / IO_RATE));

	td = (struct virtd *) &(pd->vd_forw);
	vd = q_head(td, struct virtd *);

	while(td != vd) {
		do_op(vd, TRUE);
		vd = q_head(vd, struct virtd *);
	}
}


do_op(vd, save)

/* Do a save or zap for one virtual disk, as appropriate.
 */

register struct	virtd	*vd;
boolean	save;				/* true if saving, false if zapping */
{
	static	int	tapepos = 0;	/* current tape block number */
	register int	done;
	register int	nblk;
	register int	cnt;
	int	ifd, ofd;		/* input and output file descs */
	int	pdfd;			/* physical disk desc */

	if (vd->vd_blocks > MAXTAPEPOS) {
		fprintf(stderr, "Can't handle virtual disk %s - disk too big\n",
		    vd->vd_pack);
		return;
	}

	if (!su) {
		printf("%s password for %s: ", save ? "Readonly" : "Exclusive",
		    vd->vd_pack);
		if (strcmp(getpass(""), save ? vd->vd_ropasswd
		  : vd->vd_expasswd) != 0) {
			fprintf(stderr, "Permission denied\n");
			return;
		}
	}

	if (tapepos + vd->vd_blocks > MAXTAPEPOS) {
		printf("Mount next tape; type <CR> to proceed: ");
		getchar();
		tapepos = 0;
	}

	if (save) {
		if ((ifd = open(vd->pd_forw->pd_file, O_RDONLY, 0)) < 0) {
			perror("Physical disk open error");
			fprintf(stderr, "Trying to open %s\n", 
			    vd->pd_forw->pd_file);
			return;
		}
		if ((ofd = open(tape, O_WRONLY, 0)) < 0) {
			perror("Tape open error");
			close(ifd);
			return;
		}
		pdfd = ifd;
	} else {
		if ((ofd = open(vd->pd_forw->pd_file, O_WRONLY, 0)) < 0) {
			perror("Physical disk open error");
			fprintf(stderr, "Trying to open %s\n", 
			    vd->pd_forw->pd_file);
			return;
		}
		if ((ifd = open(tape, O_RDONLY, 0)) < 0) {
			perror("Tape open error");
			close(ofd);
			return;
		}
		pdfd = ofd;
	}

	if (lseek(pdfd, vd->vd_offset * BYTESPERBLOCK, 0) < 0) {
		perror("Seek error");
		fprintf(stderr, "Seeking to virtual disk %s\n", vd->vd_pack);
		close(ifd);
		close(ofd);
		return;
	}

	for (done = 0, nblk = BLKFACTOR; done < vd->vd_blocks; done += nblk) {
		if (vd->vd_blocks - done < BLKFACTOR)
			nblk = vd->vd_blocks - done;

		if ((cnt = read(ifd, bigbuf, nblk * BYTESPERBLOCK)) <= 0) {
			if (cnt < 0) {
				perror("Read error");
				fprintf(stderr,"Doing virtual disk %s\n",
				  vd->vd_pack);
			}
			break;
		}
		if (write(ofd, bigbuf, cnt) != cnt) {
			perror("Write error");
			fprintf(stderr,"Doing virtual disk %s\n", vd->vd_pack);
			break;
		}
	}

	tapepos += vd->vd_blocks;

	close(ifd);
	close(ofd);
}


ctl_exch()
{
	bughalt("ctl_exch called\n");
}


resolve_host()
{
	bughalt("resolve_host called\n");
}
