Пример #1
0
int main(int argc, char **argv)
#endif
{
	char *start, *end;
	char buf[32];
	int i;

	if (argc == 0)
	{
		fprintf(stderr, "No command name found!\n");
		return 1;
	}

	/* Check argv[0] */

	if (argc > 0)
	{
		end = start = argv[0];
		while (*end)
			end++;
		if ((end-4 >= start) && (end[-4] == '.') && (end[-3] == 'e') && (end[-2] == 'x') && (end[-1] == 'e'))
			end = end-4;
		for (i = 0; i < nelem(tools); i++)
		{
			strcpy(buf, "mupdf");
			strcat(buf, tools[i].name);
			if (namematch(end, start, buf) || namematch(end, start, buf+2))
				return tools[i].func(argc, argv);
			strcpy(buf, "mu");
			strcat(buf, tools[i].name);
			if (namematch(end, start, buf))
				return tools[i].func(argc, argv);
		}
	}

	/* Check argv[1] */

	if (argc > 1)
	{
		for (i = 0; i < nelem(tools); i++)
			if (!strcmp(tools[i].name, argv[1]))
				return tools[i].func(argc - 1, argv + 1);
		if (!strcmp(argv[1], "-v"))
		{
			fprintf(stderr, "mutool version %s\n", FZ_VERSION);
			return 0;
		}
	}

	/* Print usage */

	fprintf(stderr, "usage: mutool <command> [options]\n");

	for (i = 0; i < nelem(tools); i++)
		fprintf(stderr, "\t%s\t-- %s\n", tools[i].name, tools[i].desc);

	return 1;
}
void printmsg(message *msg, struct proc *src, struct proc *dst,
	char operation, int printparams)
{
	const char *name;
	int mtype = msg->m_type, mightbecall = 0;

#ifdef DEBUG_DUMPIPC_NAMES
  {
	char *names[] = DEBUG_DUMPIPC_NAMES;
	int nnames = sizeof(names)/sizeof(names[0]);

	/* skip printing messages for messages neither to
	 * or from DEBUG_DUMPIPC_EP if it is defined; either
	 * can be NULL to indicate kernel
	 */
	if(!(src && namematch(names, nnames, src->p_name)) &&
	   !(dst && namematch(names, nnames, dst->p_name))) {
		return;
	}
  }
#endif

	/* source, destination and message type */
	printf("%c", operation);
	printproc(src);
	printproc(dst);
	name = mtypename(mtype, &mightbecall);
	if (name) {
		printf(" %s(%d/0x%x)", name, mtype, mtype);
	} else {
		printf(" %d/0x%x", mtype, mtype);
	}

	if (mightbecall && printparams) {
#define IDENT(x, y) if (mtype == x) printparam(#y, &msg->y, sizeof(msg->y));
#include "kernel/extracted-mfield.h"
#undef IDENT
	}
	printf("\n");
}
Пример #3
0
/*
 * NFS stuff and unmount(2) call
 */
int
umountfs(struct statfs *sfs)
{
	char fsidbuf[64];
	enum clnt_stat clnt_stat;
	struct timeval try;
	struct addrinfo *ai, hints;
	int do_rpc;
	CLIENT *clp;
	char *nfsdirname, *orignfsdirname;
	char *hostp, *delimp;

	ai = NULL;
	do_rpc = 0;
	hostp = NULL;
	nfsdirname = delimp = orignfsdirname = NULL;
	memset(&hints, 0, sizeof hints);

	if (strcmp(sfs->f_fstypename, "nfs") == 0) {
		if ((nfsdirname = strdup(sfs->f_mntfromname)) == NULL)
			err(1, "strdup");
		orignfsdirname = nfsdirname;
		if (*nfsdirname == '[' &&
		    (delimp = strchr(nfsdirname + 1, ']')) != NULL &&
		    *(delimp + 1) == ':') {
			hostp = nfsdirname + 1;
			nfsdirname = delimp + 2;
		} else if ((delimp = strrchr(nfsdirname, ':')) != NULL) {
			hostp = nfsdirname;
			nfsdirname = delimp + 1;
		}
		if (hostp != NULL) {
			*delimp = '\0';
			getaddrinfo(hostp, NULL, &hints, &ai);
			if (ai == NULL) {
				warnx("can't get net id for host");
			}
		}

		/*
		 * Check if we have to start the rpc-call later.
		 * If there are still identical nfs-names mounted,
		 * we skip the rpc-call. Obviously this has to
		 * happen before unmount(2), but it should happen
		 * after the previous namecheck.
		 * A non-NULL return means that this is the last
		 * mount from mntfromname that is still mounted.
		 */
		if (getmntentry(sfs->f_mntfromname, NULL, NULL,
		    CHECKUNIQUE) != NULL)
			do_rpc = 1;
	}

	if (!namematch(ai)) {
		free(orignfsdirname);
		return (1);
	}
	/* First try to unmount using the file system ID. */
	snprintf(fsidbuf, sizeof(fsidbuf), "FSID:%d:%d", sfs->f_fsid.val[0],
	    sfs->f_fsid.val[1]);
	if (unmount(fsidbuf, fflag | MNT_BYFSID) != 0) {
		/* XXX, non-root users get a zero fsid, so don't warn. */
		if (errno != ENOENT || sfs->f_fsid.val[0] != 0 ||
		    sfs->f_fsid.val[1] != 0)
			warn("unmount of %s failed", sfs->f_mntonname);
		if (errno != ENOENT) {
			free(orignfsdirname);
			return (1);
		}
		/* Compatibility for old kernels. */
		if (sfs->f_fsid.val[0] != 0 || sfs->f_fsid.val[1] != 0)
			warnx("retrying using path instead of file system ID");
		if (unmount(sfs->f_mntonname, fflag) != 0) {
			warn("unmount of %s failed", sfs->f_mntonname);
			free(orignfsdirname);
			return (1);
		}
	}
	/* Mark this this file system as unmounted. */
	getmntentry(NULL, NULL, &sfs->f_fsid, REMOVE);
	if (vflag)
		(void)printf("%s: unmount from %s\n", sfs->f_mntfromname,
		    sfs->f_mntonname);
	/*
	 * Report to mountd-server which nfsname
	 * has been unmounted.
	 */
	if (ai != NULL && !(fflag & MNT_FORCE) && do_rpc) {
		clp = clnt_create(hostp, MOUNTPROG, MOUNTVERS, "udp");
		if (clp  == NULL) {
			warnx("%s: %s", hostp,
			    clnt_spcreateerror("MOUNTPROG"));
			free(orignfsdirname);
			return (1);
		}
		clp->cl_auth = authsys_create_default();
		try.tv_sec = 20;
		try.tv_usec = 0;
		clnt_stat = clnt_call(clp, MOUNTPROC_UMNT, (xdrproc_t)xdr_dir,
		    nfsdirname, (xdrproc_t)xdr_void, (caddr_t)0, try);
		if (clnt_stat != RPC_SUCCESS) {
			warnx("%s: %s", hostp,
			    clnt_sperror(clp, "RPCMNT_UMOUNT"));
			free(orignfsdirname);
			return (1);
		}
		/*
		 * Remove the unmounted entry from /var/db/mounttab.
		 */
		if (read_mtab()) {
			clean_mtab(hostp, nfsdirname, vflag);
			if(!write_mtab(vflag))
				warnx("cannot remove mounttab entry %s:%s",
				    hostp, nfsdirname);
			free_mtab();
		}
		auth_destroy(clp->cl_auth);
		clnt_destroy(clp);
	}
Пример #4
0
int
umountfs(char *oname)
{
	enum clnt_stat clnt_stat;
	struct hostent *hp;
	struct sockaddr_in saddr;
	struct stat sb;
	struct timeval pertry, try;
	CLIENT *clp;
	int so;
	char *delimp, *hostp, *mntpt;
	char *name, *newname, rname[MAXPATHLEN], type[MFSNAMELEN];

	if (realpath(oname, rname) == NULL)
		mntpt = name = oname;
	else
		mntpt = name = rname;
	newname = NULL;

	/* If we can stat the file, check to see if it is a device or non-dir */
	if (stat(name, &sb) == 0) {
	    if (S_ISBLK(sb.st_mode)) {
		if ((mntpt = getmntname(name, MNTON, type)) == NULL) {
			warnx("%s: not currently mounted", name);
			return (1);
		}
	    } else if (!S_ISDIR(sb.st_mode)) {
		warnx("%s: not a directory or special device", name);
		return (1);
	    }
	}

	/*
	 * Look up the name in the mount table.
	 * 99.9% of the time the path in the kernel is the one
	 * realpath() returns but check the original just in case...
	 */
	if (!(newname = getmntname(name, MNTFROM, type)) &&
	    !(mntpt = getmntname(name, MNTON, type)) ) {
		mntpt = oname;
		if (!(newname = getmntname(oname, MNTFROM, type)) &&
		    !(mntpt = getmntname(oname, MNTON, type))) {
			warnx("%s: not currently mounted", oname);
			return (1);
		}
	}
	if (newname)
		name = newname;

	if (!selected(type))
		return (1);

	if (!strncmp(type, MOUNT_NFS, MFSNAMELEN)) {
		if ((delimp = strchr(name, '@')) != NULL) {
			hostp = delimp + 1;
			*delimp = '\0';
			hp = gethostbyname(hostp);
			*delimp = '@';
		} else if ((delimp = strchr(name, ':')) != NULL) {
			*delimp = '\0';
			hostp = name;
			hp = gethostbyname(hostp);
			name = delimp + 1;
			*delimp = ':';
		} else
			hp = NULL;
		if (!namematch(hp))
			return (1);
	}

	if (verbose)
		(void)printf("%s: unmount from %s\n", name, mntpt);

	if (unmount(mntpt, fflag) < 0) {
		warn("%s", mntpt);
		return (1);
	}

	if (!strncmp(type, MOUNT_NFS, MFSNAMELEN) &&
	    (hp != NULL) && !(fflag & MNT_FORCE)) {
		*delimp = '\0';
		memset(&saddr, 0, sizeof(saddr));
		saddr.sin_family = AF_INET;
		saddr.sin_port = 0;
		memmove(&saddr.sin_addr, hp->h_addr, hp->h_length);
		pertry.tv_sec = 3;
		pertry.tv_usec = 0;
		so = RPC_ANYSOCK;
		if ((clp = clntudp_create(&saddr,
		    RPCPROG_MNT, RPCMNT_VER1, pertry, &so)) == NULL) {
			clnt_pcreateerror("Cannot MNT PRC");
			return (1);
		}
		clp->cl_auth = authunix_create_default();
		try.tv_sec = 20;
		try.tv_usec = 0;
		clnt_stat = clnt_call(clp,
		    RPCMNT_UMOUNT, xdr_dir, name, xdr_void, (caddr_t)0, try);
		if (clnt_stat != RPC_SUCCESS) {
			clnt_perror(clp, "Bad MNT RPC");
			return (1);
		}
		auth_destroy(clp->cl_auth);
		clnt_destroy(clp);
	}
Пример #5
0
static int criteriamatch(activealerts_t *alert, criteria_t *crit, criteria_t *rulecrit, int *anymatch, time_t *nexttime)
{
	/*
	 * See if the "crit" matches the "alert".
	 * Match on pagespec, dgspec, hostspec, svcspec, classspec, groupspec, colors, timespec, minduration, maxduration, sendrecovered
	 */

	static char *pgnames = NULL;
	int pgmatchres, pgexclres;
	time_t duration = (getcurrenttime(NULL) - alert->eventstart);
	int result, cfid = 0;
	char *pgtok, *cfline = NULL;
	void *hinfo = hostinfo(alert->hostname);

	/* The top-level page needs a name - cannot match against an empty string */
	if (pgnames) xfree(pgnames);
	pgnames = strdup((*alert->location == '\0') ? "/" : alert->location);

	if (crit) { cfid = crit->cfid; cfline = crit->cfline; }
	if (!cfid && rulecrit) cfid = rulecrit->cfid;
	if (!cfline && rulecrit) cfline = rulecrit->cfline;
	if (!cfline) cfline = "<undefined>";

	traceprintf("Matching host:service:dgroup:page '%s:%s:%s:%s' against rule line %d\n",
			alert->hostname, alert->testname, xmh_item(hinfo, XMH_DGNAME), alert->location, cfid);

	if (alert->state == A_PAGING) {
		/* Check max-duration now - it's fast and easy. */
		if (crit && crit->maxduration && (duration > crit->maxduration)) { 
			traceprintf("Failed '%s' (max. duration %d>%d)\n", cfline, duration, crit->maxduration);
			if (!printmode) return 0; 
		}
	}

	if (crit && crit->classspec && !namematch(alert->classname, crit->classspec, crit->classspecre)) { 
		traceprintf("Failed '%s' (class not in include list)\n", cfline);
		return 0; 
	}
	if (crit && crit->exclassspec && namematch(alert->classname, crit->exclassspec, crit->exclassspecre)) { 
		traceprintf("Failed '%s' (class excluded)\n", cfline);
		return 0; 
	}

	/* alert->groups is a comma-separated list of groups, so it needs some special handling */
	/* 
	 * NB: Dont check groups when RECOVERED - the group list for recovery messages is always empty.
	 * It doesn't matter if we match a recipient who was not in the group that originally
	 * got the alert - we will later check who has received the alert, and only those that
	 * have will get the recovery message.
	 */
	if (crit && (crit->groupspec || crit->exgroupspec) && (alert->state != A_RECOVERED)) {
		char *grouplist;
		char *tokptr;

		grouplist = (alert->groups && (*(alert->groups))) ? strdup(alert->groups) : NULL;
		if (crit->groupspec) {
			char *onegroup;
			int iswanted = 0;

			if (grouplist) {
				/* There is a group label on the alert, so it must match */
				onegroup = strtok_r(grouplist, ",", &tokptr);
				while (onegroup && !iswanted) {
					iswanted = (namematch(onegroup, crit->groupspec, crit->groupspecre));
					onegroup = strtok_r(NULL, ",", &tokptr);
				}
			}

			if (!iswanted) {
				/*
				 * Either the alert had a group list that didn't match, or
				 * there was no group list and the rule listed one.
				 * In both cases, it's a failed match.
				 */
				traceprintf("Failed '%s' (group not in include list)\n", cfline);
				if (grouplist) xfree(grouplist);
				return 0; 
			}
		}

		if (crit->exgroupspec && grouplist) {
			char *onegroup;

			/* Excluded groups are only handled when the alert does have a group list */

			strcpy(grouplist, alert->groups); /* Might have been used in the include list */
			onegroup = strtok_r(grouplist, ",", &tokptr);
			while (onegroup) {
				if (namematch(onegroup, crit->exgroupspec, crit->exgroupspecre)) { 
					traceprintf("Failed '%s' (group excluded)\n", cfline);
					xfree(grouplist);
					return 0; 
				}
				onegroup = strtok_r(NULL, ",", &tokptr);
			}
		}

		if (grouplist) xfree(grouplist);
	}

	pgmatchres = pgexclres = -1;
	pgtok = strtok(pgnames, ",");
	while (pgtok) {
		if (crit && crit->pagespec && (pgmatchres != 1))
			pgmatchres = (namematch(pgtok, crit->pagespec, crit->pagespecre) ? 1 : 0);

		if (crit && crit->expagespec && (pgexclres != 1))
			pgexclres = (namematch(pgtok, crit->expagespec, crit->expagespecre) ? 1 : 0);

		pgtok = strtok(NULL, ",");
	}
	if (pgexclres == 1) {
		traceprintf("Failed '%s' (pagename excluded)\n", cfline);
		return 0; 
	}
	if (pgmatchres == 0) {
		traceprintf("Failed '%s' (pagename not in include list)\n", cfline);
		return 0;
	}

	if (crit && crit->dgspec && !namematch(xmh_item(hinfo, XMH_DGNAME), crit->dgspec, crit->dgspecre)) { 
		traceprintf("Failed '%s' (displaygroup not in include list)\n", cfline);
		return 0; 
	}
	if (crit && crit->exdgspec && namematch(xmh_item(hinfo, XMH_DGNAME), crit->exdgspec, crit->exdgspecre)) { 
		traceprintf("Failed '%s' (displaygroup excluded)\n", cfline);
		return 0; 
	}

	if (crit && crit->hostspec && !namematch(alert->hostname, crit->hostspec, crit->hostspecre)) { 
		traceprintf("Failed '%s' (hostname not in include list)\n", cfline);
		return 0; 
	}
	if (crit && crit->exhostspec && namematch(alert->hostname, crit->exhostspec, crit->exhostspecre)) { 
		traceprintf("Failed '%s' (hostname excluded)\n", cfline);
		return 0; 
	}

	if (crit && crit->svcspec && !namematch(alert->testname, crit->svcspec, crit->svcspecre))  { 
		traceprintf("Failed '%s' (service not in include list)\n", cfline);
		return 0; 
	}
	if (crit && crit->exsvcspec && namematch(alert->testname, crit->exsvcspec, crit->exsvcspecre))  { 
		traceprintf("Failed '%s' (service excluded)\n", cfline);
		return 0; 
	}

	if (alert->state == A_NOTIFY) {
		/*
		 * Dont do the check until we are checking individual recipients (rulecrit is set).
		 * You dont need to have NOTICE on the top-level rule, it's enough if a recipient
		 * has it set. However, we do want to allow there to be a default defined in the
		 * rule; but it doesn't take effect until we start checking the recipients.
		 */
		if (rulecrit) {
			int n = (crit ? crit->sendnotice : -1);
			traceprintf("Checking NOTICE setting %d (rule:%d)\n", n, rulecrit->sendnotice);
			if (crit && (crit->sendnotice == SR_NOTWANTED)) result = 0;	/* Explicit NONOTICE */
			else if (crit && (crit->sendnotice == SR_WANTED)) result = 1;	/* Explicit NOTICE */
			else result = (rulecrit->sendnotice == SR_WANTED);		/* Not set, but rule has NOTICE */
		}
		else {
			result = 1;
		}

		if (!result) traceprintf("Failed '%s' (notice not wanted)\n", cfline);
		return result;
	}

	/* At this point, we know the configuration may result in an alert. */
	if (anymatch) (*anymatch)++;

	/* 
	 * Duration checks should be done on real paging messages only. 
	 * Not on recovery- or notify-messages.
	 */
	if (alert->state == A_PAGING) {
		if (crit && crit->minduration && (duration < crit->minduration)) { 
			if (nexttime) {
				time_t mynext = alert->eventstart + crit->minduration;

				if ((*nexttime == -1) || (*nexttime > mynext)) *nexttime = mynext;
			}
			traceprintf("Failed '%s' (min. duration %d<%d)\n", cfline, duration, crit->minduration);
			if (!printmode) return 0; 
		}
	}

	/*
	 * Time restrictions apply to ALL messages.
	 * Before 4.2, these were only applied to ALERT messages,
	 * not RECOVERED and NOTIFY messages. This caused some
	 * unfortunate alerts in the middle of the night because
	 * some random system recovered ... not good. So apply
	 * this check to all messages.
	 */
	if (crit && crit->timespec && !timematch(xmh_item(hinfo, XMH_HOLIDAYS), crit->timespec)) {
		traceprintf("Failed '%s' (time criteria)\n", cfline);
		if (!printmode) return 0; 
	}

	/* Check color. For RECOVERED messages, this holds the color of the alert, not the recovery state */
	if (crit && crit->colors) {
		result = (((1 << alert->color) & crit->colors) != 0);
		if (printmode) return 1;
	}
	else {
		result = (((1 << alert->color) & defaultcolors) != 0);
		if (printmode) return 1;
	}
	if (!result) {
		traceprintf("Failed '%s' (color)\n", cfline);
		return result;
	}

	if ((alert->state == A_RECOVERED) || (alert->state == A_DISABLED)) {
		/*
		 * Dont do the check until we are checking individual recipients (rulecrit is set).
		 * You dont need to have RECOVERED on the top-level rule, it's enough if a recipient
		 * has it set. However, we do want to allow there to be a default defined in the
		 * rule; but it doesn't take effect until we start checking the recipients.
		 */
		if (rulecrit) {
			int n = (crit ? crit->sendrecovered : -1);
			traceprintf("Checking recovered setting %d (rule:%d)\n", n, rulecrit->sendrecovered);
			if (crit && (crit->sendrecovered == SR_NOTWANTED)) result = 0;		/* Explicit NORECOVERED */
			else if (crit && (crit->sendrecovered == SR_WANTED)) result = 1;	/* Explicit RECOVERED */
			else result = (rulecrit->sendrecovered == SR_WANTED);	/* Not set, but rule has RECOVERED */
		}
		else {
			result = 1;
		}

		if (printmode) return result;
	}

	if (result) {
		traceprintf("*** Match with '%s' ***\n", cfline);
	}

	return result;
}
Пример #6
0
int
umountfs(char *name, char **typelist)
{
	enum clnt_stat clnt_stat;
	struct hostent *hp;
	struct mtablist *mtab;
	struct sockaddr_in saddr;
	struct timeval pertry, try;
	CLIENT *clp;
	size_t len;
	int so, speclen, do_rpc;
	char *mntonname, *mntfromname;
	char *mntfromnamerev;
	char *nfsdirname, *orignfsdirname;
	char *resolved, realname[MAXPATHLEN];
	char *type, *delimp, *hostp, *origname;

	len = 0;
	mtab = NULL;
	mntfromname = mntonname = delimp = hostp = orignfsdirname = NULL;

	/*
	 * 1. Check if the name exists in the mounttable.
	 */
	(void)checkmntlist(name, &mntfromname, &mntonname, &type);
	/*
	 * 2. Remove trailing slashes if there are any. After that
	 * we look up the name in the mounttable again.
	 */
	if (mntfromname == NULL && mntonname == NULL) {
		speclen = strlen(name);
		for (speclen = strlen(name); 
		    speclen > 1 && name[speclen - 1] == '/';
		    speclen--)
			name[speclen - 1] = '\0';
		(void)checkmntlist(name, &mntfromname, &mntonname, &type);
		resolved = name;
		/* Save off original name in origname */
		if ((origname = strdup(name)) == NULL)
			err(1, "strdup");
		/*
		 * 3. Check if the deprecated nfs-syntax with an '@'
		 * has been used and translate it to the ':' syntax.
		 * Look up the name in the mounttable again.
		 */
		if (mntfromname == NULL && mntonname == NULL) {
			if ((delimp = strrchr(name, '@')) != NULL) {
				hostp = delimp + 1;
				if (*hostp != '\0') {
					/*
					 * Make both '@' and ':'
					 * notations equal 
					 */
					char *host = strdup(hostp);
					len = strlen(hostp);
					if (host == NULL)
						err(1, "strdup");
					memmove(name + len + 1, name,
					    (size_t)(delimp - name));
					name[len] = ':';
					memmove(name, host, len);
					free(host);
				}
				for (speclen = strlen(name); 
				    speclen > 1 && name[speclen - 1] == '/';
				    speclen--)
					name[speclen - 1] = '\0';
				name[len + speclen + 1] = '\0';
				(void)checkmntlist(name, &mntfromname,
				    &mntonname, &type);
				resolved = name;
			}
			/*
			 * 4. Check if a relative mountpoint has been
			 * specified. This should happen as last check,
			 * the order is important. To prevent possible
			 * nfs-hangs, we just call realpath(3) on the
			 * basedir of mountpoint and add the dirname again.
			 * Check the name in mounttable one last time.
			 */
			if (mntfromname == NULL && mntonname == NULL) {
				(void)strcpy(name, origname);
				if ((getrealname(name, realname)) != NULL) {
					(void)checkmntlist(realname,
					    &mntfromname, &mntonname, &type);
					resolved = realname;
				}
				/*
				 * All tests failed, return to main()
				 */
				if (mntfromname == NULL && mntonname == NULL) {
					(void)strcpy(name, origname);
					warnx("%s: not currently mounted",
					    origname);
					free(origname);
					return (1);
				}
			}
		}
		free(origname);
	} else
		resolved = name;

	if (checkvfsname(type, typelist))
		return (1);

	hp = NULL;
	nfsdirname = NULL;
	if (!strcmp(type, "nfs")) {
		if ((nfsdirname = strdup(mntfromname)) == NULL)
			err(1, "strdup");
		orignfsdirname = nfsdirname;
		if ((delimp = strchr(nfsdirname, ':')) != NULL) {
			*delimp = '\0';
			hostp = nfsdirname;
			if ((hp = gethostbyname(hostp)) == NULL) {
				warnx("can't get net id for host");
			}
			nfsdirname = delimp + 1;
		}
	}
	/*
	 * Check if the reverse entrys of the mounttable are really the
	 * same as the normal ones.
	 */
	if ((mntfromnamerev = strdup(getmntname(getmntname(mntfromname,
	    NULL, MNTON, &type, NAME), NULL, MNTFROM, &type, NAME))) == NULL)
		err(1, "strdup");
	/*
	 * Mark the uppermost mount as unmounted.
	 */
	(void)getmntname(mntfromname, mntonname, NOTHING, &type, MARK);
	/*
	 * If several equal mounts are in the mounttable, check the order
	 * and warn the user if necessary.
	 */
	if (strcmp(mntfromnamerev, mntfromname ) != 0 &&
	    strcmp(resolved, mntonname) != 0) {
		warnx("cannot umount %s, %s\n        "
		    "is mounted there, umount it first",
		    mntonname, mntfromnamerev);

		/* call getmntname again to set mntcheck[i] to 0 */
		(void)getmntname(mntfromname, mntonname,
		    NOTHING, &type, UNMARK);
		return (1);
	}
	free(mntfromnamerev);
	/*
	 * Check if we have to start the rpc-call later.
	 * If there are still identical nfs-names mounted,
	 * we skip the rpc-call. Obviously this has to
	 * happen before unmount(2), but it should happen
	 * after the previous namecheck.
	 */
	if (strcmp(type, "nfs") == 0 && getmntname(mntfromname, NULL, NOTHING,
	    &type, COUNT) != NULL)
		do_rpc = 1;
	else
		do_rpc = 0;
	if (!namematch(hp))
		return (1);
	if (unmount(mntonname, fflag) != 0 ) {
		warn("unmount of %s failed", mntonname);
		return (1);
	}
	if (vflag)
		(void)printf("%s: unmount from %s\n", mntfromname, mntonname);
	/*
	 * Report to mountd-server which nfsname
	 * has been unmounted.
	 */
	if (hp != NULL && !(fflag & MNT_FORCE) && do_rpc) {
		memset(&saddr, 0, sizeof(saddr));
		saddr.sin_family = AF_INET;
		saddr.sin_port = 0;
		memmove(&saddr.sin_addr, hp->h_addr, 
		    MIN(hp->h_length, sizeof(saddr.sin_addr)));
		pertry.tv_sec = 3;
		pertry.tv_usec = 0;
		so = RPC_ANYSOCK;
		if ((clp = clntudp_create(&saddr,
		    RPCPROG_MNT, RPCMNT_VER1, pertry, &so)) == NULL) {
			clnt_pcreateerror("Cannot MNT PRC");
			return (1);
		}
		clp->cl_auth = authunix_create_default();
		try.tv_sec = 20;
		try.tv_usec = 0;
		clnt_stat = clnt_call(clp, RPCMNT_UMOUNT, xdr_dir,
		    nfsdirname, xdr_void, (caddr_t)0, try);
		if (clnt_stat != RPC_SUCCESS) {
			clnt_perror(clp, "Bad MNT RPC");
			return (1);
		}
		/*
		 * Remove the unmounted entry from /var/db/mounttab.
		 */
		if (read_mtab(mtab)) {
			mtab = mtabhead;
			clean_mtab(hostp, nfsdirname);
			if(!write_mtab())
				warnx("cannot remove entry %s:%s",
				    hostp, nfsdirname);
			free_mtab();
		}
		free(orignfsdirname);
		auth_destroy(clp->cl_auth);
		clnt_destroy(clp);
	}