/* $Copyright:	$
 * Copyright (c) 1984, 1985, 1986, 1987, 1988, 1989, 1990 
 * Sequent Computer Systems, Inc.   All rights reserved.
 *  
 * This software is furnished under a license and may be used
 * only in accordance with the terms of that license and with the
 * inclusion of the above copyright notice.   This software may not
 * be provided or otherwise made available to, or used by, any
 * other person.  No title to or ownership of the software is
 * hereby transferred.
 */

#ident "$Header: vtoc.c 1.5 89/05/31 $"

/*
 * vtoc - cons a vtoc driver on top of a raw physical disk.
 *
 *  This command is supposed to live in /etc/devcons.d and be
 *  called by devcons.  It's argument is a raw disk which
 *  is passed to the vtoc driver via an ioctl.  Then, as output,
 *  it prints out the name of the things which have been consed
 *  together.
 */

#include <sys/fcntl.h>
#include <sys/types.h>
#include <sys/devsw.h>
#include <sys/vtoc.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/errno.h>
#include <stdio.h>

#define VTOCDEV		"/dev/vtoc"
#define LINESIZ		80
#define DESTROYOPT	"-d"

#define USAGE		\
"usage:\tvtoc rawdisk"

#define strsize(str)    \
		(sizeof(str) - 1)       /* Length of static character array */

#ifdef	lint
struct	streamtab {
	int dummy;
};
#endif	/* lint */

extern int   errno;

extern void  exit();
extern void  perror();
extern char  *strrchr();
extern char  *strcat();
extern char  *strcpy();

main(argc, argv)
	int argc;
	char ** argv;
{
	int fd, fd1;
	char *disk;
	struct stat sb;

	if (strncmp(argv[1], DESTROYOPT, sizeof(DESTROYOPT)) == 0) {
		if (argc != 3) {
			(void)fprintf(stderr, "devbuild: vtoc %s\n", USAGE);
			exit(2);
		}
		exit(dodestroy(argv[2]));
	}

	if (argc != 2) {
		(void)fprintf(stderr, "devbuild: vtoc %s\n", USAGE);
		exit(2);
	}

	disk = argv[1];

	fd = open(VTOCDEV, O_RDONLY);
	if (fd < 0) {
		(void)fprintf(stderr, "devbuild: %s ", VTOCDEV);
		perror("open");
		exit(1);
	}
	
	if (stat(disk, &sb) < 0) {
		(void)fprintf(stderr, "%s: ", disk);
		perror("Cannot stat");
		exit(1);
	}
	if ((sb.st_mode & S_IFMT) != S_IFCHR) {
		(void)fprintf(stderr, "%s: Not a raw device\n", disk);
		exit(1);
	}
	if ((sb.st_rdev & (V_RAW_MINOR | DEV_DIAG_MASK)) != V_RAW_MINOR) {
		(void)fprintf(stderr, "%s: Not a unpartitioned disk device\n",
			disk);
		exit(1);
	}
	fd1 = open(disk, O_RDONLY);
	if (fd1 < 0) {
		char *p;
		char diag[DYNIX_MAXNAMLEN];

		/*
		 * If the open fails, give the benefit of the doubt, and
		 * see if the diagnostic device of the same name is
		 * openable.  If so, guess that its already built, and
		 * silently fail.  This allows devbuild -a to not
		 * complain about things already built.
		 */
		p = strrchr(disk, '/');
		if (p == NULL)
			p = disk;
		else
			p++;
		(void)strcpy(diag, "/dev/diag/rdsk/");
		(void)strcat(diag, p);
		if (open(diag, O_RDONLY) < 0) {
			(void)fprintf(stderr, "devbuild: %s ", disk);
			perror("open");
		}
		exit(1);
	}

	if (ioctl(fd, V_BUILD, fd1) < 0) {
		switch(errno) {
		case EINVAL:
			(void)fprintf(stderr,
			"devbuild: %s has a bad VTOC - use mkvtoc(1M)\n", disk);
			break;
		case EBUSY:
			(void)fprintf(stderr,
			"devbuild: %s is currently in use\n", disk);
			break;
		default:
			(void)fprintf(stderr, "devbuild: %s ", disk);
			perror("V_BUILD");
		}
		exit(1);
	}

	/*
	 * fd1 is implicitly closed by the V_BUILD operation
	 */
	(void)close(fd);
	(void)printf("vtoc %s\n", disk);
	exit(0);
	/*NOTREACHED*/
}

char	diagdev[LINESIZ];

/*
 * dodestroy
 *
 *	The device passed as argument is handed to the VTOCDEV via
 * a V_DESTROY ioctl.
 */

dodestroy(basedev)
	char	*basedev;
{
	int	fd, fd1;
	static	char	rawprefix[] =	"/dev/r";
	static	char	diagprefix[] =	"/dev/diag/r";
	struct	stat st;

	if (strncmp(basedev, rawprefix, strsize(rawprefix)) != 0) {
		(void)fprintf(stderr, "vtoc: Must specify raw device\n");
		return(1);
	}

	(void)strcpy(diagdev, diagprefix);
	(void)strcat(diagdev, basedev + strlen(rawprefix));

	if (stat(diagdev, &st) != 0 ||
	   (st.st_mode & S_IFMT) != S_IFCHR ||
	   (fd1 = open(diagdev, O_RDONLY)) < 0) {
		(void)fprintf(stderr,
		   "vtoc: unable to access diagnostic device %s\n", diagdev);
		return(1);
	}
	
	if ((fd = open(VTOCDEV, O_RDONLY)) < 0) {
		(void)fprintf(stderr, "vtoc: unable to open ");
		perror(VTOCDEV);
		(void)close(fd1);
		return(1);
	}

	if (ioctl(fd, V_DESTROY, fd1) < 0) {
		switch(errno) {
		case EINVAL:
			(void)fprintf(stderr,
		"%s: VTOC is corrupt or is not bound with a vtoc device\n",
				basedev);
			break;
		case EBUSY:
			(void)fprintf(stderr,
				"%s: some partition is currently in use\n",
				basedev);
			break;
		default:
			(void)fprintf(stderr,
				"vtoc: unable to do V_DESTROY on ");
			perror(diagdev);
		}
		(void)close(fd);
		(void)close(fd1);
		return(1);
	}

	(void)close(fd);
	return(0);
}
