/*
 * $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.
 *
 */

/*	Copyright (c) 1984 AT&T	*/
/*	  All Rights Reserved  	*/

/*	THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T	*/
/*	The copyright notice above does not evidence any   	*/
/*	actual or intended publication of such source code.	*/

#ident	"$Header: swap.c 1.6 89/12/20 $@(#)swap:swap.c	1.3"
/*	Swap administrative interface
 *	Used to add/delete/list swap devices in use by paging.
 */

#include	<stdio.h>
#include	<fcntl.h>
#include	<sys/types.h>
#include	<sys/param.h>
#include	<dirent.h>
#include	<sys/sysmacros.h>
#include	<sys/swap.h>
#include	<sys/stat.h>
#include        <sys/sysi86.h>

/*	This is gross, but it will have
 *	to do for now.  How about a sysadm(2)?
 */

#define swapfunc(X)     sysi86(SI86SWPI, X)


typedef struct SwapDirs {
	char	*sd_name;	/* Name of directory to search.	*/
	DIR	*sd_dir;	/* Directory descriptor.	*/
} SwapDirs_t;

SwapDirs_t	SwapDirs[] = {
	{"/dev/dsk"},
	{"/dev"},
};

#define	NbrSwapDirs	(sizeof(SwapDirs) / sizeof(SwapDirs_t))

main(argc, argv)
int	argc;
char	*argv[];
{
	if(argc < 2  ||  argv[1][0] != '-'){
		usage();
		exit(1);
	}

	switch(argv[1][1]){
		case 'l':
			list();
			break;
		
		case 'd':
			if(argc < 4){
				usage();
				exit(2);
			}
			delete(argv[2], argv[3]);
			break;
		
		case 'a':
			if(argc < 4){
				usage();
				exit(2);
			}
			add(argv[2], argv[3]);
			break;
		default:
			usage();
			exit(1);
	}
	exit(0);
}


usage()
{
	printf("usage:\tswap -l\n");
	printf("\tswap -a <special dev> <nbr of blocks>\n");
}

list()
{
	register int	swplo;
	register int	blkcnt;
	register struct swdevt	*st;
	register swpi_t	*si;
	register int	i;
	struct swdevt	swdevt[MSFILES];
	swpi_t		swpi;
	char		*path;
	int		length;
	char		*GetPath();

	st = swdevt;
	si = &swpi;
	si->si_cmd = SI_LIST;
	si->si_buf = (char *)st;

	if(swapfunc(si) < 0){
		perror("swap");
		exit(3);
	}

	InitPath();

	printf("path               dev      swaplo   blocks\n");

	for(i = 0  ;  i < MSFILES  ;  i++, st++){
		if(st->sw_dev == NULL)
			continue;
		path = GetPath(st->sw_dev);
		if(path == NULL){
			printf("%.18s", "??????                 ");
		} else {
			length = 18 -strlen(path);
			if(length < 0)
				length = 0;
			printf("%s%.*s", path, length, "               ");

		}
		printf("%3d,%-5d %6d %8d", 
			major(st->sw_dev),
			minor(st->sw_dev),
			0,
			st->sw_nblks);
			printf("\n");
	}

}

delete(path, lo)
char	*path;
char	*lo;
{
	register int	swplo;
	register swpi_t	*si;
	swpi_t		swpi;

	swplo = atoi(lo);
	si = &swpi;
	si->si_cmd = SI_DEL;
	si->si_buf = path;
	si->si_swplo = swplo;

	if(swapfunc(si) < 0){
		perror("swap");
		exit(3);
	}
}

add(path, cnt)
char	*path;
char	*cnt;
{
	register int	blkcnt;
	register swpi_t	*si;
	swpi_t		swpi;

	blkcnt = atoi(cnt);
	si = &swpi;
	si->si_cmd = SI_ADD;
	si->si_buf = path;
	si->si_swplo = 0;
	si->si_nblks = blkcnt;

	if(swapfunc(si) < 0){
		perror("swap");
		exit(3);
	}

}


/*	Initialization for the path search routine.
*/

InitPath()
{
	register int	i;

	for(i = 0  ;  i < NbrSwapDirs  ;  i++){
		SwapDirs[i].sd_dir =
			opendir(SwapDirs[i].sd_name);
		if(SwapDirs[i].sd_dir == NULL){
			fprintf(stderr, "Couldn't open directory %s",
				SwapDirs[i].sd_name);
			fprintf(stderr, " - not being searched.\n");
			perror("swap");
		}
	}
}


/*	Get path name corresponding to a device.
*/

#define	MAXPATH	MAXPATHLEN

char	PathBuf[MAXPATH];

char	*
GetPath(dev)
register int	dev;
{
	register int	sdndx;
	register char	*path;
	char		*SearchDir();

	for(sdndx = 0  ;  sdndx < NbrSwapDirs  ;  sdndx++){

		/*	Skip any directories which we
		**	couldn't open.
		*/

		if(SwapDirs[sdndx].sd_dir == NULL)
			continue;
		
		/*	Change to directory we want to search.
		*/

		if(chdir(SwapDirs[sdndx].sd_name) < 0){
			fprintf(stderr, "Couldn't chdir to %s",
				SwapDirs[sdndx].sd_name);
			fprintf(stderr, " - directory not searched.\n");
			perror("swap");
			SwapDirs[sdndx].sd_dir = NULL;
			continue;
		}

		/*	Position at start of directory.
		*/

		seekdir(SwapDirs[sdndx].sd_dir, 0);

		if(path = SearchDir(&SwapDirs[sdndx], dev))
			return(path);
	}
	return(NULL);
}


char	*
SearchDir(sdp, dev)
register SwapDirs_t	*sdp;
register int		dev;
{
	register int	i;
	register struct dirent	*dp;
	struct stat	statbuf;

	for (dp = readdir(sdp->sd_dir); dp != NULL; dp = readdir(sdp->sd_dir)) {
		if(dp->d_ino == 0)
			continue;
		sprintf(PathBuf, "%.14s", dp->d_name);
		if(stat(PathBuf, &statbuf) <0){
			fprintf(stderr,
				"Could not stat %s.n",
				PathBuf);
			perror("swap");
			continue;
		}
		if(statbuf.st_rdev != dev)
			continue;
		if((statbuf.st_mode & S_IFMT) != S_IFBLK)
			continue;
		strcpy(PathBuf, sdp->sd_name);
		strcat(PathBuf, "/");
		sprintf(&PathBuf[strlen(PathBuf)], "%.14s",
			dp->d_name);
		return(PathBuf);
	}
	return(NULL);
}
