/* $Header:quota.c 12.0$ */
/* $ACIS:quota.c 12.0$ */
/* $Source: /ibm/acis/usr/src/ucb/RCS/quota.c,v $ */

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

#include <sys/nfs_defines.h>

/*
 * Copyright (c) 1980 Regents of the University of California.
 * All rights reserved.  The Berkeley software License Agreement
 * specifies the terms and conditions for redistribution.
 */

#ifndef lint
char copyright[] =
"@(#) Copyright (c) 1980 Regents of the University of California.\n\
 All rights reserved.\n";
#endif not lint

#ifndef lint
static char sccsid[] = "@(#)quota.c	5.4 (Berkeley) 2/24/86";
#endif not lint

#ifdef VFS
/* @(#)quota.c	1.1	87/07/28 3.2/4.3 NFSSRC */
#endif VFS

/*
 * Disk quota reporting program.
 */
#include <stdio.h>
#ifndef VFS
#include <fstab.h>
#else !VFS
#include <mntent.h>
#endif !VFS
#include <ctype.h>
#include <pwd.h>
#include <errno.h>

#include <sys/param.h>
#ifndef VFS
#include <sys/quota.h>
#endif !VFS
#include <sys/file.h>
#include <sys/stat.h>
#ifdef VFS
#include <sys/time.h>
#include <ufs/quota.h>
#endif VFS

#ifndef VFS
int	qflag;
#endif !VFS
int	vflag;
#ifndef VFS
int	done;
int	morethanone;
char	*qfname = "quotas";
#else !VFS
#define QFNAME	"quotas"
#endif !VFS

#ifdef VFS
#define kb(n)   (howmany(dbtob(n), 1024))

#endif VFS
main(argc, argv)
	char *argv[];
{
	register char *cp;
#ifndef VFS
	extern int errno;
#endif !VFS

#ifndef VFS
	if (quota(Q_SYNC, 0, 0, (caddr_t)0) < 0 && errno == EINVAL) {
		fprintf(stderr, "There are no quotas on this system\n");
		exit(0);
	}
#endif !VFS
	argc--,argv++;
	while (argc > 0) {
		if (argv[0][0] == '-')
			for (cp = &argv[0][1]; *cp; cp++) switch (*cp) {

			case 'v':
				vflag++;
				break;

#ifndef VFS
			case 'q':
				qflag++;
				break;

#endif !VFS
			default:
				fprintf(stderr, "quota: %c: unknown option\n",
					*cp);
				exit(1);
			}
		else
			break;
		argc--, argv++;
	}
#ifndef VFS
	morethanone = argc > 1;
#endif !VFS
	if (argc == 0) {
		showuid(getuid());
		exit(0);
	}
	for (; argc > 0; argc--, argv++) {
		if (alldigits(*argv))
			showuid(atoi(*argv));
		else
			showname(*argv);
	}
#ifdef VFS
	exit(0);
#endif VFS
}

showuid(uid)
	int uid;
{
	struct passwd *pwd = getpwuid(uid);

#ifdef VFS
	if (uid == 0) {
		if (vflag)
			printf("no disk quota for uid 0\n");
		return;
	}
#endif VFS
	if (pwd == NULL)
		showquotas(uid, "(no account)");
	else
		showquotas(uid, pwd->pw_name);
}

showname(name)
	char *name;
{
	struct passwd *pwd = getpwnam(name);

	if (pwd == NULL) {
		fprintf(stderr, "quota: %s: unknown user\n", name);
		return;
	}
#ifdef VFS
	if (pwd->pw_uid == 0) {
		if (vflag)
			printf("no disk quota for %s (uid 0)\n", name);
		return;
	}
#endif VFS
	showquotas(pwd->pw_uid, name);
}

showquotas(uid, name)
	int uid;
	char *name;
{
#ifndef VFS
	register struct fstab *fs;
	register char *msgi, *msgb;
	register enab = 1;
	dev_t	fsdev;
	struct	stat statb;
	struct	dqblk dqblk;
	int myuid, fd;
	char qfilename[MAXPATHLEN + 1], iwarn[8], dwarn[8];
#else !VFS
	register struct mntent *mntp;
	FILE *mtab;
	struct dqblk dqblk;
	int myuid;
#endif !VFS

	myuid = getuid();
	if (uid != myuid && myuid != 0) {
		printf("quota: %s (uid %d): permission denied\n", name, uid);
		return;
	}
#ifndef VFS
	done = 0;
	(void) setfsent();
	while (fs = getfsent()) {
		if (stat(fs->fs_spec, &statb) < 0)
#else !VFS
	if (vflag)
		heading(uid, name);
	mtab = setmntent(MOUNTED, "r");
	while (mntp = getmntent(mtab)) {
		if (strcmp(mntp->mnt_type, MNTTYPE_UFS) == 0 || strcmp(mntp->mnt_type, MNTTYPE_42) == 0 || strcmp(mntp->mnt_type, MNTTYPE_43) == 0) {
			if (quotactl(Q_GETQUOTA,
			      mntp->mnt_fsname, uid, &dqblk) != 0) {
				if (!vflag || !getdiskquota(mntp, uid, &dqblk))
					continue;
			}
		} else if (strcmp(mntp->mnt_type, MNTTYPE_NFS) == 0) {
			if ((!vflag && hasmntopt(mntp, MNTOPT_NOQUOTA)) ||
			    !getnfsquota(mntp, uid, &dqblk))
				continue;
		} else {
#endif !VFS
			continue;
#ifndef VFS
		msgi = msgb = (char *) 0;
		fsdev = statb.st_rdev;
		(void) sprintf(qfilename, "%s/%s", fs->fs_file, qfname);
		if (stat(qfilename, &statb) < 0 || statb.st_dev != fsdev)
#else !VFS
		}
		if (dqblk.dqb_bsoftlimit == 0 && dqblk.dqb_bhardlimit == 0 &&
		    dqblk.dqb_fsoftlimit == 0 && dqblk.dqb_fhardlimit == 0)
#endif !VFS
			continue;
#ifndef VFS
		if (quota(Q_GETDLIM, uid, fsdev, (caddr_t)&dqblk) != 0) {
			fd = open(qfilename, O_RDONLY);
			if (fd < 0)
				continue;
			(void) lseek(fd, (off_t)(uid * sizeof (dqblk)), L_SET);
			switch (read(fd, (char *)&dqblk, sizeof dqblk)) {
			case 0:			/* EOF */
				/*
				 * Convert implicit 0 quota (EOF)
				 * into an explicit one (zero'ed dqblk).
				 */
				bzero((caddr_t)&dqblk, sizeof dqblk);
				break;
#else !VFS
		if (vflag)
			prquota(mntp, &dqblk);
		else
			warn(mntp, &dqblk);
	}
	endmntent(mtab);
}
#endif !VFS

#ifndef VFS
			case sizeof dqblk:	/* OK */
				break;
#else !VFS
warn(mntp, dqp)
	register struct mntent *mntp;
	register struct dqblk *dqp;
{
	struct timeval tv;
#endif !VFS

#ifndef VFS
			default:		/* ERROR */
				fprintf(stderr, "quota: read error in ");
				perror(qfilename);
				(void) close(fd);
				continue;
			}
			(void) close(fd);
			if (!vflag && dqblk.dqb_isoftlimit == 0 &&
			    dqblk.dqb_bsoftlimit == 0)
				continue;
			enab = 0;
#else !VFS
	gettimeofday(&tv, NULL);
	if (dqp->dqb_bhardlimit &&
	     dqp->dqb_curblocks >= dqp->dqb_bhardlimit) {
		printf(
"Block limit reached on %s\n",
		    mntp->mnt_dir
		);
	} else if (dqp->dqb_bsoftlimit &&
	     dqp->dqb_curblocks >= dqp->dqb_bsoftlimit) {
		if (dqp->dqb_btimelimit == 0) {
			printf(
"Over disk quota on %s, remove %dK\n",
			    mntp->mnt_dir,
			    kb(dqp->dqb_curblocks - dqp->dqb_bsoftlimit + 1)
			);
		} else if (dqp->dqb_btimelimit > tv.tv_sec) {
			char btimeleft[80];

			fmttime(btimeleft, dqp->dqb_btimelimit - tv.tv_sec);
			printf(
"Over disk quota on %s, remove %dK within %s\n",
			    mntp->mnt_dir,
			    kb(dqp->dqb_curblocks - dqp->dqb_bsoftlimit + 1),
			    btimeleft
			);
		} else {
			printf(
"Over disk quota on %s, time limit has expired, remove %dK\n",
			    mntp->mnt_dir,
			    kb(dqp->dqb_curblocks - dqp->dqb_bsoftlimit + 1)
			);
#endif !VFS
		}
#ifndef VFS
		if (dqblk.dqb_ihardlimit &&
		    dqblk.dqb_curinodes >= dqblk.dqb_ihardlimit)
			msgi = "File count limit reached on %s";
		else if (enab && dqblk.dqb_iwarn == 0)
			msgi = "Out of inode warnings on %s";
		else if (dqblk.dqb_isoftlimit &&
		    dqblk.dqb_curinodes >= dqblk.dqb_isoftlimit)
			msgi = "Too many files on %s";
		if (dqblk.dqb_bhardlimit &&
		    dqblk.dqb_curblocks >= dqblk.dqb_bhardlimit)
			msgb = "Block limit reached on %s";
		else if (enab && dqblk.dqb_bwarn == 0)
			msgb = "Out of block warnings on %s";
		else if (dqblk.dqb_bsoftlimit &&
		    dqblk.dqb_curblocks >= dqblk.dqb_bsoftlimit)
			msgb = "Over disc quota on %s";
		if (dqblk.dqb_iwarn < MAX_IQ_WARN)
			(void) sprintf(iwarn, "%d", dqblk.dqb_iwarn);
		else
			iwarn[0] = '\0';
		if (dqblk.dqb_bwarn < MAX_DQ_WARN)
			(void) sprintf(dwarn, "%d", dqblk.dqb_bwarn);
		else
			dwarn[0] = '\0';
		if (qflag) {
			if (msgi != (char *)0 || msgb != (char *)0)
				heading(uid, name);
			if (msgi != (char *)0)
				xprintf(msgi, fs->fs_file);
			if (msgb != (char *)0)
				xprintf(msgb, fs->fs_file);
			continue;
		}
		if (vflag || dqblk.dqb_curblocks || dqblk.dqb_curinodes) {
			heading(uid, name);
			printf("%10s%8d%c%7d%8d%8s%8d%c%7d%8d%8s\n"
				, fs->fs_file
				, dbtob(dqblk.dqb_curblocks) / 1024
				, (msgb == (char *)0) ? ' ' : '*'
				, dbtob(dqblk.dqb_bsoftlimit) / 1024
				, dbtob(dqblk.dqb_bhardlimit) / 1024
				, dwarn
				, dqblk.dqb_curinodes
				, (msgi == (char *)0) ? ' ' : '*'
				, dqblk.dqb_isoftlimit
				, dqblk.dqb_ihardlimit
				, iwarn
#else !VFS
	}
	if (dqp->dqb_fhardlimit &&
	    dqp->dqb_curfiles >= dqp->dqb_fhardlimit) {
		printf(
"File count limit reached on %s\n",
		    mntp->mnt_dir
		);
	} else if (dqp->dqb_fsoftlimit &&
	    dqp->dqb_curfiles >= dqp->dqb_fsoftlimit) {
		if (dqp->dqb_ftimelimit == 0) {
			printf(
"Over file quota on %s, remove %d file%s\n",
			    mntp->mnt_dir,
			    dqp->dqb_curfiles - dqp->dqb_fsoftlimit + 1,
			    ((dqp->dqb_curfiles - dqp->dqb_fsoftlimit + 1) > 1 ?
				"s" :
				"" )
#endif !VFS
			);
#ifdef VFS
		} else if (dqp->dqb_ftimelimit > tv.tv_sec) {
			char ftimeleft[80];

			fmttime(ftimeleft, dqp->dqb_ftimelimit - tv.tv_sec);
			printf(
"Over file quota on %s, remove %d file%s within %s\n",
			    mntp->mnt_dir,
			    dqp->dqb_curfiles - dqp->dqb_fsoftlimit + 1,
			    ((dqp->dqb_curfiles - dqp->dqb_fsoftlimit + 1) > 1 ?
				"s" :
				"" ),
			    ftimeleft
			);
		} else {
			printf(
"Over file quota on %s, time limit has expired, remove %d file%s\n",
			    mntp->mnt_dir,
			    dqp->dqb_curfiles - dqp->dqb_fsoftlimit + 1,
			    ((dqp->dqb_curfiles - dqp->dqb_fsoftlimit + 1) > 1 ?
				"s" :
				"" )
			);
#endif VFS
		}
	}
#ifndef VFS
	(void) endfsent();
	if (!done && !qflag) {
		if (morethanone)
			(void) putchar('\n');
		xprintf("Disc quotas for %s (uid %d):", name, uid);
		xprintf("none.");
	}
	xprintf((char *)0);
#endif !VFS
}

heading(uid, name)
	int uid;
	char *name;
{
#ifndef VFS

	if (done++)
		return;
	xprintf((char *)0);
	if (qflag) {
		if (!morethanone)
			return;
		xprintf("User %s (uid %d):", name, uid);
		xprintf((char *)0);
		return;
	}
	(void) putchar('\n');
	xprintf("Disc quotas for %s (uid %d):", name, uid);
	xprintf((char *)0);
	printf("%10s%8s %7s%8s%8s%8s %7s%8s%8s\n"
		, "Filsys"
		, "current"
#else !VFS
	printf("Disk quotas for %s (uid %d):\n", name, uid);
	printf("%-12s %7s%7s%7s%12s%7s%7s%7s%12s\n"
		, "Filesystem"
		, "usage"
#endif !VFS
		, "quota"
		, "limit"
#ifndef VFS
		, "#warns"
#else !VFS
		, "timeleft"
#endif !VFS
		, "files"
		, "quota"
		, "limit"
#ifndef VFS
		, "#warns"
#else !VFS
		, "timeleft"
#endif !VFS
	);
}

#ifndef VFS
/*VARARGS1*/
xprintf(fmt, arg1, arg2, arg3, arg4, arg5, arg6)
	char *fmt;
#else !VFS
prquota(mntp, dqp)
	register struct mntent *mntp;
	register struct dqblk *dqp;
#endif !VFS
{
#ifndef VFS
	char	buf[100];
	static int column;
#else !VFS
	struct timeval tv;
	char ftimeleft[80], btimeleft[80];
	char *cp;
#endif !VFS

#ifndef VFS
	if (fmt == 0 && column || column >= 40) {
		(void) putchar('\n');
		column = 0;
#else !VFS
	gettimeofday(&tv, NULL);
	if (dqp->dqb_bsoftlimit && dqp->dqb_curblocks >= dqp->dqb_bsoftlimit) {
		if (dqp->dqb_btimelimit == 0) {
			strcpy(btimeleft, "NOT STARTED");
		} else if (dqp->dqb_btimelimit > tv.tv_sec) {
			fmttime(btimeleft, dqp->dqb_btimelimit - tv.tv_sec);
		} else {
			strcpy(btimeleft, "EXPIRED");
		}
	} else {
		btimeleft[0] = '\0';
#endif !VFS
	}
#ifndef VFS
	if (fmt == 0)
#else !VFS
	if (dqp->dqb_fsoftlimit && dqp->dqb_curfiles >= dqp->dqb_fsoftlimit) {
		if (dqp->dqb_ftimelimit == 0) {
			strcpy(ftimeleft, "NOT STARTED");
		} else if (dqp->dqb_ftimelimit > tv.tv_sec) {
			fmttime(ftimeleft, dqp->dqb_ftimelimit - tv.tv_sec);
		} else {
			strcpy(ftimeleft, "EXPIRED");
		}
	} else {
		ftimeleft[0] = '\0';
	}
	if (strlen(mntp->mnt_dir) > 12) {
		printf("%s\n", mntp->mnt_dir);
		cp = "";
	} else {
		cp = mntp->mnt_dir;
	}
	printf("%-12.12s %7d%7d%7d%12s%7d%7d%7d%12s\n",
	    cp,
	    kb(dqp->dqb_curblocks),
	    kb(dqp->dqb_bsoftlimit),
	    kb(dqp->dqb_bhardlimit),
	    btimeleft,
	    dqp->dqb_curfiles,
	    dqp->dqb_fsoftlimit,
	    dqp->dqb_fhardlimit,
	    ftimeleft
	);
}

fmttime(buf, time)
	char *buf;
	register long time;
{
	int i;
	static struct {
		int c_secs;		/* conversion units in secs */
		char * c_str;		/* unit string */
	} cunits [] = {
		{60*60*24*28, "months"},
		{60*60*24*7, "weeks"},
		{60*60*24, "days"},
		{60*60, "hours"},
		{60, "mins"},
		{1, "secs"}
	};

	if (time <= 0) {
		strcpy(buf, "EXPIRED");
#endif !VFS
		return;
#ifndef VFS
	(void) sprintf(buf, fmt, arg1, arg2, arg3, arg4, arg5, arg6);
	if (column != 0 && strlen(buf) < 39)
		while (column++ < 40)
			(void) putchar(' ');
	else if (column) {
		(void) putchar('\n');
		column = 0;
#endif !VFS
	}
#ifndef VFS
	printf("%s", buf);
	column += strlen(buf);
#else !VFS
	for (i = 0; i < sizeof(cunits)/sizeof(cunits[0]); i++) {
		if (time >= cunits[i].c_secs)
			break;
	}
	sprintf(buf, "%.1f %s", (double)time/cunits[i].c_secs, cunits[i].c_str);
#endif !VFS
}

alldigits(s)
	register char *s;
{
	register c;

	c = *s++;
	do {
		if (!isdigit(c))
			return (0);
	} while (c = *s++);
	return (1);
}

#ifdef VFS
int
getdiskquota(mntp, uid, dqp)
	struct mntent *mntp;
	int uid;
	struct dqblk *dqp;
{
	int fd;
	dev_t fsdev;
	struct stat statb;
	char qfilename[MAXPATHLEN];
	static int nolocalquota = 0;
	extern int errno;

	if (stat(mntp->mnt_fsname, &statb) < 0 ||
	    (statb.st_mode & S_IFMT) != S_IFBLK)
		return (0);
	fsdev = statb.st_rdev;
	sprintf(qfilename, "%s/%s", mntp->mnt_dir, QFNAME);
	if (stat(qfilename, &statb) < 0 || statb.st_dev != fsdev)
		return (0);
	if ((fd = open(qfilename, O_RDONLY)) < 0)
		return (0);
	if (quotactl(Q_SYNC, mntp->mnt_fsname, 0, NULL) < 0 && errno == EINVAL) {
		nolocalquota++;
		return(0);
	}
	(void)lseek(fd, (long)dqoff(uid), L_SET);
	if (read(fd, dqp, sizeof(struct dqblk)) != sizeof(struct dqblk)) {
		close(fd);
		return (0);
	}
	close(fd);
	return (1);
}

#include <rpc/rpc.h>
#include <rpc/pmap_prot.h>
#include <sys/socket.h>
#include <netdb.h>
#include <rpcsvc/rquota.h>

int
getnfsquota(mntp, uid, dqp)
	struct mntent *mntp;
	int uid;
	struct dqblk *dqp;
{
	char *hostp;
	char *cp;
	struct getquota_args gq_args;
	struct getquota_rslt gq_rslt;
	extern char *index();

	hostp = mntp->mnt_fsname;
	cp = index(mntp->mnt_fsname, ':');
	if (cp == 0) {
		fprintf(stderr, "cannot find hostname for %s\n", mntp->mnt_dir);
		return (0);
	}
	*cp = '\0';
	gq_args.gqa_pathp = cp + 1;
	gq_args.gqa_uid = uid;
	if (callaurpc(hostp, RQUOTAPROG, RQUOTAVERS,
	    (vflag? RQUOTAPROC_GETQUOTA: RQUOTAPROC_GETACTIVEQUOTA),
	    xdr_getquota_args, &gq_args, xdr_getquota_rslt, &gq_rslt) != 0) {
		*cp = ':';
		return (0);
	}
	switch (gq_rslt.gqr_status) {
	case Q_OK:
		{
		struct timeval tv;

		if (!vflag && gq_rslt.gqr_rquota.rq_active == FALSE)
			return (0);
		gettimeofday(&tv, NULL);
		dqp->dqb_bhardlimit =
		    gq_rslt.gqr_rquota.rq_bhardlimit *
		    gq_rslt.gqr_rquota.rq_bsize / DEV_BSIZE;
		dqp->dqb_bsoftlimit =
		    gq_rslt.gqr_rquota.rq_bsoftlimit *
		    gq_rslt.gqr_rquota.rq_bsize / DEV_BSIZE;
		dqp->dqb_curblocks =
		    gq_rslt.gqr_rquota.rq_curblocks *
		    gq_rslt.gqr_rquota.rq_bsize / DEV_BSIZE;
		dqp->dqb_fhardlimit = gq_rslt.gqr_rquota.rq_fhardlimit;
		dqp->dqb_fsoftlimit = gq_rslt.gqr_rquota.rq_fsoftlimit;
		dqp->dqb_curfiles = gq_rslt.gqr_rquota.rq_curfiles;
		dqp->dqb_btimelimit =
		    tv.tv_sec + gq_rslt.gqr_rquota.rq_btimeleft;
		dqp->dqb_ftimelimit =
		    tv.tv_sec + gq_rslt.gqr_rquota.rq_ftimeleft;
		*cp = ':';
		return (1);
		}

	case Q_NOQUOTA:
		break;

	case Q_EPERM:
		fprintf(stderr, "quota permission error, host: %s\n", hostp);
		break;

	default:
		fprintf(stderr, "bad rpc result, host: %s\n",  hostp);
		break;
	}
	*cp = ':';
	return (0);
}

callaurpc(host, prognum, versnum, procnum, inproc, in, outproc, out)
	char *host;
	xdrproc_t inproc, outproc;
	char *in, *out;
{
	struct sockaddr_in server_addr;
	enum clnt_stat clnt_stat;
	struct hostent *hp;
	struct timeval timeout, tottimeout;

	static CLIENT *client = NULL;
	static int socket = RPC_ANYSOCK;
	static int valid = 0;
	static int oldprognum, oldversnum;
	static char oldhost[256];

	if (valid && oldprognum == prognum && oldversnum == versnum
		&& strcmp(oldhost, host) == 0) {
		/* reuse old client */		
	}
	else {
		valid = 0;
		close(socket);
		socket = RPC_ANYSOCK;
		if (client) {
			clnt_destroy(client);
			client = NULL;
		}
		if ((hp = gethostbyname(host)) == NULL)
			return ((int) RPC_UNKNOWNHOST);
		timeout.tv_usec = 0;
		timeout.tv_sec = 6;
		bcopy(hp->h_addr, &server_addr.sin_addr, hp->h_length);
		server_addr.sin_family = AF_INET;
		/* ping the remote end via tcp to see if it is up */
#ifdef notdef
		server_addr.sin_port =  htons(PMAPPORT);
		if ((client = clnttcp_create(&server_addr, PMAPPROG,
		    PMAPVERS, &socket, 0, 0)) == NULL) {
			return ((int) rpc_createerr.cf_stat);
		} else {
			/* the fact we succeeded means the machine is up */
			close(socket);
			socket = RPC_ANYSOCK;
			clnt_destroy(client);
			client = NULL;
		}
#endif notdef
		/*
		 * We (UWash) replaced the ping above with this ping()
		 * routine.  The PMAP ping above was taking too long
		 * to time out.  We can control the timeout on this one.
		 */
		if (ping(hp)) {
			return (1);
		}else {
			socket = RPC_ANYSOCK;
			client = NULL;
		}
		/* now really create a udp client handle */
		server_addr.sin_port =  0;
		if ((client = clntudp_create(&server_addr, prognum,
		    versnum, timeout, &socket)) == NULL)
			return ((int) rpc_createerr.cf_stat);
		client->cl_auth = authunix_create_default();
		valid = 1;
		oldprognum = prognum;
		oldversnum = versnum;
		strcpy(oldhost, host);
	}
	tottimeout.tv_sec = 25;
	tottimeout.tv_usec = 0;
	clnt_stat = clnt_call(client, procnum, inproc, in,
	    outproc, out, tottimeout);
	/* 
	 * if call failed, empty cache
	 */
	if (clnt_stat != RPC_SUCCESS)
		valid = 0;
	return ((int) clnt_stat);
}

#define PACKETSIZE 64
#include <setjmp.h>;
jmp_buf jb;

int
ping(hp)
struct hostent *hp;
{
#include <netinet/in_systm.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
	struct protoent *proto;
	int s;
	u_char outpack[PACKETSIZE], packet[PACKETSIZE];
	register struct icmp *icp = (struct icmp *) outpack;
	int i, cc;
	register struct timeval *tp = (struct timeval *) &outpack[8];
	register u_char *datap = &outpack[8+sizeof(struct timeval)];
	struct sockaddr whereto;
	struct sockaddr_in *to = (struct sockaddr_in *)&whereto;
	struct sockaddr_in from;
	int datalen = PACKETSIZE-8;
	int fromlen = sizeof(from);
	int pingto();

	bzero((char *)&whereto, sizeof(struct sockaddr));
	if (hp) {
		to->sin_family = hp->h_addrtype;
		bcopy(hp->h_addr, (caddr_t)&to->sin_addr, hp->h_length);
	}else {
		return (1);
	}

	if ((proto = getprotobyname("icmp")) == NULL)
		return (1);

	if ((s = socket(AF_INET, SOCK_RAW, proto->p_proto)) < 0)
		return (1);

	icp->icmp_type = ICMP_ECHO;
	icp->icmp_code = 0;
	icp->icmp_cksum = 0;
	icp->icmp_seq = 0;
	icp->icmp_id = 0;

	cc = datalen+8;			/* skips ICMP portion */

	for( i=8; i<datalen; i++)	/* skip 8 for time */
		*datap++ = i;

	/* Compute ICMP checksum here */
	icp->icmp_cksum = in_cksum( icp, cc );

	i = sendto( s, outpack, cc, 0, &whereto, sizeof(struct sockaddr) );

	if( i < 0 || i != cc )
		return (1);
	
	signal(SIGALRM, pingto);
	if (setjmp(jb) == 0) {
		alarm(5);
		if (recvfrom(s, packet, PACKETSIZE, 0, &from, &fromlen) < 0)
			return (1);
		alarm(0);
	}else {
		return (1);
	}
	return (0);
}

int
pingto()
{
	longjmp(jb, 1);
}

/*
 *			I N _ C K S U M
 *
 * Checksum routine for Internet Protocol family headers (C Version)
 *
 */
in_cksum(addr, len)
u_short *addr;
int len;
{
	register int nleft = len;
	register u_short *w = addr;
	register u_short answer;
	register int sum = 0;

	/*
	 *  Our algorithm is simple, using a 32 bit accumulator (sum),
	 *  we add sequential 16 bit words to it, and at the end, fold
	 *  back all the carry bits from the top 16 bits into the lower
	 *  16 bits.
	 */
	while( nleft > 1 )  {
		sum += *w++;
		nleft -= 2;
	}

	/* mop up an odd byte, if necessary */
	if( nleft == 1 )
		sum += *(u_char *)w;

	/*
	 * add back carry outs from top 16 bits to low 16 bits
	 */
	sum = (sum >> 16) + (sum & 0xffff);	/* add hi 16 to low 16 */
	sum += (sum >> 16);			/* add carry */
	answer = ~sum;				/* truncate to 16 bits */
	return (answer);
}

#endif VFS
