17c478bdstevel@tonic-gate/*
27c478bdstevel@tonic-gate * CDDL HEADER START
37c478bdstevel@tonic-gate *
47c478bdstevel@tonic-gate * The contents of this file are subject to the terms of the
5004388ecasper * Common Development and Distribution License (the "License").
6004388ecasper * You may not use this file except in compliance with the License.
77c478bdstevel@tonic-gate *
87c478bdstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bdstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bdstevel@tonic-gate * See the License for the specific language governing permissions
117c478bdstevel@tonic-gate * and limitations under the License.
127c478bdstevel@tonic-gate *
137c478bdstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bdstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bdstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bdstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bdstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bdstevel@tonic-gate *
197c478bdstevel@tonic-gate * CDDL HEADER END
207c478bdstevel@tonic-gate */
217c478bdstevel@tonic-gate/*
22d67944fScott Rotondo * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23004388ecasper * Use is subject to license terms.
2448bbca8Daniel Hoffman * Copyright (c) 2016 by Delphix. All rights reserved.
257c478bdstevel@tonic-gate */
267c478bdstevel@tonic-gate
277c478bdstevel@tonic-gate/*
287c478bdstevel@tonic-gate * routines in this module are meant to be called by other libvolmgt
297c478bdstevel@tonic-gate * routines only
307c478bdstevel@tonic-gate */
317c478bdstevel@tonic-gate
327c478bdstevel@tonic-gate#include	<stdio.h>
337c478bdstevel@tonic-gate#include	<string.h>
347c478bdstevel@tonic-gate#include	<dirent.h>
357c478bdstevel@tonic-gate#include	<fcntl.h>
367c478bdstevel@tonic-gate#include	<string.h>
377c478bdstevel@tonic-gate#ifdef	DEBUG
387c478bdstevel@tonic-gate#include	<errno.h>
397c478bdstevel@tonic-gate#endif
407c478bdstevel@tonic-gate#include	<libintl.h>
417c478bdstevel@tonic-gate#include	<limits.h>
427c478bdstevel@tonic-gate#include	<unistd.h>
437c478bdstevel@tonic-gate#include	<stdlib.h>
447c478bdstevel@tonic-gate#include	<volmgt.h>
457c478bdstevel@tonic-gate#include	<sys/types.h>
467c478bdstevel@tonic-gate#include	<sys/mkdev.h>
477c478bdstevel@tonic-gate#include	<sys/stat.h>
487c478bdstevel@tonic-gate#include	<sys/dkio.h>
497c478bdstevel@tonic-gate#include	<sys/param.h>
507c478bdstevel@tonic-gate#include	<sys/wait.h>
517c478bdstevel@tonic-gate#include	<sys/mnttab.h>
527c478bdstevel@tonic-gate#include	"volmgt_private.h"
537c478bdstevel@tonic-gate
547c478bdstevel@tonic-gate
557c478bdstevel@tonic-gate#define	NULL_PATH		"/dev/null"
567c478bdstevel@tonic-gate
577c478bdstevel@tonic-gate
58d67944fScott Rotondostatic int	vol_getmntdev(FILE *, struct mnttab *, dev_t,
59d67944fScott Rotondo			    struct dk_cinfo *);
607c478bdstevel@tonic-gate
617c478bdstevel@tonic-gate/*
627c478bdstevel@tonic-gate * This is an ON Consolidation Private interface.
637c478bdstevel@tonic-gate *
647c478bdstevel@tonic-gate * Is the specified path mounted?
657c478bdstevel@tonic-gate *
667c478bdstevel@tonic-gate * This function is really inadequate for ejection testing.  For example,
677c478bdstevel@tonic-gate * I could have /dev/fd0a mounted and eject /dev/fd0c, and it would be
687c478bdstevel@tonic-gate * ejected.  There needs to be some better way to make this check, although
697c478bdstevel@tonic-gate * short of looking up the mounted dev_t in the kernel mount table and
707c478bdstevel@tonic-gate * building in all kinds of knowledge into this function,  I'm not sure
717c478bdstevel@tonic-gate * how to do it.
727c478bdstevel@tonic-gate */
737c478bdstevel@tonic-gateint
747c478bdstevel@tonic-gate_dev_mounted(char *path)
757c478bdstevel@tonic-gate{
767c478bdstevel@tonic-gate	int		fd = -1;
777c478bdstevel@tonic-gate	struct dk_cinfo	info;
787c478bdstevel@tonic-gate	static FILE 	*fp = NULL;		/* mnttab file pointer */
797c478bdstevel@tonic-gate	struct mnttab	mnt;			/* set bug not used */
807c478bdstevel@tonic-gate	char		*cn = NULL;		/* char spcl pathname */
817c478bdstevel@tonic-gate	struct stat64	sb;
827c478bdstevel@tonic-gate	int		ret_val = 0;
837c478bdstevel@tonic-gate
847c478bdstevel@tonic-gate
857c478bdstevel@tonic-gate	/* ensure we have the block spcl pathname */
867c478bdstevel@tonic-gate	if ((cn = (char *)volmgt_getfullrawname(path)) == NULL) {
877c478bdstevel@tonic-gate		goto dun;
887c478bdstevel@tonic-gate	}
897c478bdstevel@tonic-gate
90004388ecasper	if ((fp = fopen(MNTTAB, "rF")) == NULL) {
9148bbca8Daniel Hoffman		/* mtab is gone... let it go */
927c478bdstevel@tonic-gate		goto dun;
937c478bdstevel@tonic-gate	}
947c478bdstevel@tonic-gate
957c478bdstevel@tonic-gate	if ((fd = open(cn, O_RDONLY|O_NDELAY)) < 0) {
967c478bdstevel@tonic-gate		goto dun;
977c478bdstevel@tonic-gate	}
987c478bdstevel@tonic-gate
997c478bdstevel@tonic-gate	if (fstat64(fd, &sb) < 0) {
1007c478bdstevel@tonic-gate		goto dun;
1017c478bdstevel@tonic-gate	}
1027c478bdstevel@tonic-gate
1037c478bdstevel@tonic-gate	if (ioctl(fd, DKIOCINFO, &info) != 0) {
1047c478bdstevel@tonic-gate		goto dun;
1057c478bdstevel@tonic-gate	}
1067c478bdstevel@tonic-gate
1077c478bdstevel@tonic-gate	if (vol_getmntdev(fp, &mnt, sb.st_rdev, &info) != 0) {
1087c478bdstevel@tonic-gate		ret_val = 1;			/* match found! */
1097c478bdstevel@tonic-gate	}
1107c478bdstevel@tonic-gate
1117c478bdstevel@tonic-gatedun:
1127c478bdstevel@tonic-gate	if (cn != NULL) {
1137c478bdstevel@tonic-gate		free(cn);
1147c478bdstevel@tonic-gate	}
1157c478bdstevel@tonic-gate	if (fp != NULL) {
1167c478bdstevel@tonic-gate		(void) fclose(fp);
1177c478bdstevel@tonic-gate	}
1187c478bdstevel@tonic-gate	if (fd >= 0) {
1197c478bdstevel@tonic-gate		(void) close(fd);
1207c478bdstevel@tonic-gate	}
1217c478bdstevel@tonic-gate	return (ret_val);
1227c478bdstevel@tonic-gate}
1237c478bdstevel@tonic-gate
1247c478bdstevel@tonic-gate
125d67944fScott Rotondostatic int	call_unmount_prog(int, int, char *, int, char *,
126d67944fScott Rotondo			    char *);
127d67944fScott Rotondostatic int	get_media_info(char *, char **, int *, char **);
1287c478bdstevel@tonic-gate/*
1297c478bdstevel@tonic-gate * This is an ON Consolidation Private interface.
1307c478bdstevel@tonic-gate *
1317c478bdstevel@tonic-gate * Forks off rmmount and (in essence) returns the result
1327c478bdstevel@tonic-gate *
1337c478bdstevel@tonic-gate * a return value of 0 (FALSE) means failure, non-zero (TRUE) means success
1347c478bdstevel@tonic-gate */
1357c478bdstevel@tonic-gateint
1367c478bdstevel@tonic-gate_dev_unmount(char *path)
1377c478bdstevel@tonic-gate{
1387c478bdstevel@tonic-gate	char		*bn = NULL;		/* block name */
1397c478bdstevel@tonic-gate	char		*mtype = NULL;		/* media type */
1407c478bdstevel@tonic-gate	char		*spcl = NULL;		/* special dev. path */
1417c478bdstevel@tonic-gate	char		*spcl_failed = NULL;	/* spcl that failed */
1427c478bdstevel@tonic-gate	int		ret_val = FALSE;	/* what we return */
1437c478bdstevel@tonic-gate	char		*vr;			/* volmgt root dir */
1447c478bdstevel@tonic-gate	int		media_info_gotten = 0;
1457c478bdstevel@tonic-gate	int		mnum = 0;
1467c478bdstevel@tonic-gate	int		volume_is_not_managed;
1477c478bdstevel@tonic-gate	char		*pathbuf, *absname;
1487c478bdstevel@tonic-gate
1497c478bdstevel@tonic-gate
1507c478bdstevel@tonic-gate	if ((bn = (char *)volmgt_getfullblkname(path)) == NULL) {
1517c478bdstevel@tonic-gate		goto dun;
1527c478bdstevel@tonic-gate	}
1537c478bdstevel@tonic-gate
1547c478bdstevel@tonic-gate	if ((pathbuf = malloc(PATH_MAX+1)) == NULL)
1557c478bdstevel@tonic-gate		goto dun;
1567c478bdstevel@tonic-gate
1577c478bdstevel@tonic-gate	absname = bn;
1587c478bdstevel@tonic-gate	if (realpath(bn, pathbuf) != NULL)
1597c478bdstevel@tonic-gate		absname = pathbuf;
1607c478bdstevel@tonic-gate
1617c478bdstevel@tonic-gate	volume_is_not_managed = !volmgt_running() ||
162d67944fScott Rotondo	    (!volmgt_ownspath(absname) && volmgt_symname(bn) == NULL);
1637c478bdstevel@tonic-gate
1647c478bdstevel@tonic-gate	free(pathbuf);
1657c478bdstevel@tonic-gate
1667c478bdstevel@tonic-gate	/* decide of we should use rmmount to unmount the media */
1677c478bdstevel@tonic-gate	if (!volume_is_not_managed) {
1687c478bdstevel@tonic-gate		int		use_rmm = FALSE;	/* use rmmount??  */
1697c478bdstevel@tonic-gate
1707c478bdstevel@tonic-gate		/* at least volmgt is running */
1717c478bdstevel@tonic-gate		vr = (char *)volmgt_root();
1727c478bdstevel@tonic-gate		if (strncmp(bn, vr, strlen(vr)) == 0) {
1737c478bdstevel@tonic-gate			/* the block path is rooted in /vol */
1747c478bdstevel@tonic-gate			use_rmm = TRUE;
1757c478bdstevel@tonic-gate		}
1767c478bdstevel@tonic-gate
1777c478bdstevel@tonic-gate		/* try to get info about media */
1787c478bdstevel@tonic-gate		media_info_gotten = get_media_info(bn, &mtype, &mnum, &spcl);
1797c478bdstevel@tonic-gate
1807c478bdstevel@tonic-gate		ret_val = call_unmount_prog(media_info_gotten, use_rmm, mtype,
1817c478bdstevel@tonic-gate		    mnum, spcl, bn);
1827c478bdstevel@tonic-gate
1837c478bdstevel@tonic-gate	} else {
1847c478bdstevel@tonic-gate
1857c478bdstevel@tonic-gate		/* volmgt is *not* running */
1867c478bdstevel@tonic-gate
1877c478bdstevel@tonic-gate		if (get_media_info(bn, &mtype, &mnum, &spcl)) {
1887c478bdstevel@tonic-gate
1897c478bdstevel@tonic-gate			/*
1907c478bdstevel@tonic-gate			 * volmgt is off and get_media_info() has returned
1917c478bdstevel@tonic-gate			 * info on the media -- soo (this is kinda' a hack)
1927c478bdstevel@tonic-gate			 * ... we iterate, looking for multiple slices
1937c478bdstevel@tonic-gate			 * of (say) a floppy being mounted
1947c478bdstevel@tonic-gate			 *
1957c478bdstevel@tonic-gate			 * note: if an unmount fails we don't want to try
1967c478bdstevel@tonic-gate			 * to unmount the same device on the next try, so
1977c478bdstevel@tonic-gate			 * we try to watch for that
1987c478bdstevel@tonic-gate			 */
1997c478bdstevel@tonic-gate
2007c478bdstevel@tonic-gate			do {
2017c478bdstevel@tonic-gate				/*
2027c478bdstevel@tonic-gate				 * don't call the unmount program is we're just
2037c478bdstevel@tonic-gate				 * trying to unmount the same device that
2047c478bdstevel@tonic-gate				 * failed last time -- if that's the case,
2057c478bdstevel@tonic-gate				 * then bail
2067c478bdstevel@tonic-gate				 */
2077c478bdstevel@tonic-gate				if (spcl_failed != NULL) {
2087c478bdstevel@tonic-gate					if (strcmp(spcl, spcl_failed) == 0) {
2097c478bdstevel@tonic-gate						break;
2107c478bdstevel@tonic-gate					}
2117c478bdstevel@tonic-gate				}
2127c478bdstevel@tonic-gate				ret_val = call_unmount_prog(TRUE, FALSE,
2137c478bdstevel@tonic-gate				    mtype, mnum, spcl, bn);
2147c478bdstevel@tonic-gate
2157c478bdstevel@tonic-gate				if (!ret_val) {
2167c478bdstevel@tonic-gate					/* save spcl device name that failed */
2177c478bdstevel@tonic-gate					spcl_failed = strdup(spcl);
2187c478bdstevel@tonic-gate				} else {
2197c478bdstevel@tonic-gate					/*
2207c478bdstevel@tonic-gate					 * unmount succeeded, so clean up
2217c478bdstevel@tonic-gate					 */
2227c478bdstevel@tonic-gate					if (spcl_failed != NULL) {
2237c478bdstevel@tonic-gate						free(spcl_failed);
2247c478bdstevel@tonic-gate						spcl_failed = NULL;
2257c478bdstevel@tonic-gate					}
2267c478bdstevel@tonic-gate				}
2277c478bdstevel@tonic-gate
2287c478bdstevel@tonic-gate			} while (get_media_info(bn, &mtype, &mnum, &spcl));
2297c478bdstevel@tonic-gate
2307c478bdstevel@tonic-gate		} else {
2317c478bdstevel@tonic-gate
2327c478bdstevel@tonic-gate			/* just do the unmmount cycle once */
2337c478bdstevel@tonic-gate			ret_val = call_unmount_prog(FALSE, FALSE, NULL, 0,
2347c478bdstevel@tonic-gate			    NULL, bn);
2357c478bdstevel@tonic-gate		}
2367c478bdstevel@tonic-gate
2377c478bdstevel@tonic-gate	}
2387c478bdstevel@tonic-gate
2397c478bdstevel@tonic-gate	if (mtype != NULL) {
2407c478bdstevel@tonic-gate		free(mtype);
2417c478bdstevel@tonic-gate	}
2427c478bdstevel@tonic-gate	if (spcl != NULL) {
2437c478bdstevel@tonic-gate		free(spcl);
2447c478bdstevel@tonic-gate	}
2457c478bdstevel@tonic-gate	if (spcl_failed != NULL) {
2467c478bdstevel@tonic-gate		free(spcl_failed);
2477c478bdstevel@tonic-gate	}
2487c478bdstevel@tonic-gate	if (bn != NULL) {
2497c478bdstevel@tonic-gate		free(bn);
2507c478bdstevel@tonic-gate	}
2517c478bdstevel@tonic-gate
2527c478bdstevel@tonic-gatedun:
2537c478bdstevel@tonic-gate
2547c478bdstevel@tonic-gate	return (ret_val);
2557c478bdstevel@tonic-gate}
2567c478bdstevel@tonic-gate
2577c478bdstevel@tonic-gate
2587c478bdstevel@tonic-gate/*
2597c478bdstevel@tonic-gate * find a mnttab entry that has the same dev as the supplied dev,
2607c478bdstevel@tonic-gate *  returning it and a non-zero value if found, else returning 0
2617c478bdstevel@tonic-gate *
2627c478bdstevel@tonic-gate * this is just like getmntany(), except that it scans based on st_rdev,
2637c478bdstevel@tonic-gate * and it even finds different slices on the same device/unit (thanx to
2647c478bdstevel@tonic-gate * code copied from format.c)
2657c478bdstevel@tonic-gate */
2667c478bdstevel@tonic-gatestatic int
2677c478bdstevel@tonic-gatevol_getmntdev(FILE *fp, struct mnttab *mp, dev_t dev, struct dk_cinfo *ip)
2687c478bdstevel@tonic-gate{
2697c478bdstevel@tonic-gate	int		fd;		/* dev-in-question fd */
2707c478bdstevel@tonic-gate	struct stat64	sb;		/* dev-in-question stat struct */
2717c478bdstevel@tonic-gate	int		ret_val = 0;	/* default value: no match found */
2727c478bdstevel@tonic-gate	char		*cn;		/* char pathname */
2737c478bdstevel@tonic-gate	struct dk_cinfo	dkinfo;		/* for testing for slices */
2747c478bdstevel@tonic-gate
2757c478bdstevel@tonic-gate
2767c478bdstevel@tonic-gate#ifdef	DEBUG
2777c478bdstevel@tonic-gate	denter(
2787c478bdstevel@tonic-gate	    "vol_getmntdev: entering for %d.%d, ctype/cnum/unit = %d/%d/%d\n",
2797c478bdstevel@tonic-gate	    (int)major(dev), (int)minor(dev), ip->dki_ctype, ip->dki_cnum,
2807c478bdstevel@tonic-gate	    ip->dki_unit);
2817c478bdstevel@tonic-gate#endif
2827c478bdstevel@tonic-gate
2837c478bdstevel@tonic-gate	/* reset the mnttab -- just in case */
2847c478bdstevel@tonic-gate	rewind(fp);
2857c478bdstevel@tonic-gate
2867c478bdstevel@tonic-gate	/* scan each entry in mnttab */
2877c478bdstevel@tonic-gate	while (getmntent(fp, mp) == 0) {
2887c478bdstevel@tonic-gate
2897c478bdstevel@tonic-gate		/* don't even try unless it's a local pathname */
2907c478bdstevel@tonic-gate		if (mp->mnt_special[0] != '/') {
2917c478bdstevel@tonic-gate			continue;
2927c478bdstevel@tonic-gate		}
2937c478bdstevel@tonic-gate
2947c478bdstevel@tonic-gate		/* get char pathname */
2957c478bdstevel@tonic-gate		if ((cn = volmgt_getfullrawname(mp->mnt_special)) == NULL) {
2967c478bdstevel@tonic-gate			continue;
2977c478bdstevel@tonic-gate		}
2987c478bdstevel@tonic-gate		if (cn[0] == NULLC) {
2997c478bdstevel@tonic-gate			free(cn);
3007c478bdstevel@tonic-gate			continue;	/* couldn't get raw name */
3017c478bdstevel@tonic-gate		}
3027c478bdstevel@tonic-gate
3037c478bdstevel@tonic-gate		/* open the device */
3047c478bdstevel@tonic-gate		if ((fd = open(cn, O_RDONLY|O_NDELAY)) < 0) {
3057c478bdstevel@tonic-gate			/* if we can't open it *assume* it's not a match */
3067c478bdstevel@tonic-gate			free(cn);
3077c478bdstevel@tonic-gate			continue;
3087c478bdstevel@tonic-gate		}
3097c478bdstevel@tonic-gate
3107c478bdstevel@tonic-gate		/* stat the device */
3117c478bdstevel@tonic-gate		if (fstat64(fd, &sb) < 0) {
3127c478bdstevel@tonic-gate			free(cn);
3137c478bdstevel@tonic-gate			(void) close(fd);
3147c478bdstevel@tonic-gate			continue;	/* ain't there: can't be a match */
3157c478bdstevel@tonic-gate		}
3167c478bdstevel@tonic-gate
3177c478bdstevel@tonic-gate		/* ensure we have a spcl device (a double check) */
3187c478bdstevel@tonic-gate		if (!S_ISBLK(sb.st_mode) && !S_ISCHR(sb.st_mode)) {
3197c478bdstevel@tonic-gate			free(cn);
3207c478bdstevel@tonic-gate			(void) close(fd);
3217c478bdstevel@tonic-gate			continue;
3227c478bdstevel@tonic-gate		}
3237c478bdstevel@tonic-gate
3247c478bdstevel@tonic-gate		/* (almost) finally -- check the dev_t for equality */
3257c478bdstevel@tonic-gate		if (sb.st_rdev == dev) {
3267c478bdstevel@tonic-gate			ret_val = 1;		/* match found! */
3277c478bdstevel@tonic-gate			free(cn);
3287c478bdstevel@tonic-gate			(void) close(fd);
3297c478bdstevel@tonic-gate			break;
3307c478bdstevel@tonic-gate		}
3317c478bdstevel@tonic-gate
3327c478bdstevel@tonic-gate		/*
3337c478bdstevel@tonic-gate		 * check that the major numbers match, since if they
3347c478bdstevel@tonic-gate		 * don't then there's no reason to use the DKIOCINFO
3357c478bdstevel@tonic-gate		 * ioctl to see if we have to major/minor pairs that
3367c478bdstevel@tonic-gate		 * really point to the same device
3377c478bdstevel@tonic-gate		 */
3387c478bdstevel@tonic-gate		if (major(sb.st_rdev) != major(dev)) {
3397c478bdstevel@tonic-gate			/* no use continuing, since major devs are different */
3407c478bdstevel@tonic-gate			free(cn);
3417c478bdstevel@tonic-gate			(void) close(fd);
3427c478bdstevel@tonic-gate			continue;
3437c478bdstevel@tonic-gate		}
3447c478bdstevel@tonic-gate
3457c478bdstevel@tonic-gate		/* one last check -- for diff. slices of the same dev/unit */
3467c478bdstevel@tonic-gate		if (ioctl(fd, DKIOCINFO, &dkinfo) < 0) {
3477c478bdstevel@tonic-gate			free(cn);
3487c478bdstevel@tonic-gate			(void) close(fd);
3497c478bdstevel@tonic-gate			continue;
3507c478bdstevel@tonic-gate		}
3517c478bdstevel@tonic-gate
3527c478bdstevel@tonic-gate		free(cn);		/* all done with raw pathname */
3537c478bdstevel@tonic-gate		(void) close(fd);	/* all done with file descriptor */
3547c478bdstevel@tonic-gate
3557c478bdstevel@tonic-gate		/* if ctrler type/number and unit match, it's a match */
3567c478bdstevel@tonic-gate		if ((ip->dki_ctype == dkinfo.dki_ctype) &&
3577c478bdstevel@tonic-gate		    (ip->dki_cnum == dkinfo.dki_cnum) &&
3587c478bdstevel@tonic-gate		    (ip->dki_unit == dkinfo.dki_unit)) {
3597c478bdstevel@tonic-gate			/*
3607c478bdstevel@tonic-gate			 * even though minor numbers differ we have a
3617c478bdstevel@tonic-gate			 * match
3627c478bdstevel@tonic-gate			 */
3637c478bdstevel@tonic-gate			ret_val = 1;
3647c478bdstevel@tonic-gate			break;
3657c478bdstevel@tonic-gate		}
3667c478bdstevel@tonic-gate
3677c478bdstevel@tonic-gate		/* go around again */
3687c478bdstevel@tonic-gate	}
3697c478bdstevel@tonic-gate
3707c478bdstevel@tonic-gate	return (ret_val);
3717c478bdstevel@tonic-gate}
3727c478bdstevel@tonic-gate
3737c478bdstevel@tonic-gate
3747c478bdstevel@tonic-gatechar *
3757c478bdstevel@tonic-gatevol_basename(char *path)
3767c478bdstevel@tonic-gate{
3777c478bdstevel@tonic-gate	char	*cp;
3787c478bdstevel@tonic-gate
3797c478bdstevel@tonic-gate
3807c478bdstevel@tonic-gate	/* check for the degenerate case */
3817c478bdstevel@tonic-gate	if (strcmp(path, "/") == 0) {
3827c478bdstevel@tonic-gate		return (path);
3837c478bdstevel@tonic-gate	}
3847c478bdstevel@tonic-gate
3857c478bdstevel@tonic-gate	/* look for the last slash in the name */
3867c478bdstevel@tonic-gate	if ((cp = strrchr(path, '/')) == NULL) {
3877c478bdstevel@tonic-gate		/* no slash */
3887c478bdstevel@tonic-gate		return (path);
3897c478bdstevel@tonic-gate	}
3907c478bdstevel@tonic-gate
3917c478bdstevel@tonic-gate	/* ensure something is after the slash */
3927c478bdstevel@tonic-gate	if (*++cp != NULLC) {
3937c478bdstevel@tonic-gate		return (cp);
3947c478bdstevel@tonic-gate	}
3957c478bdstevel@tonic-gate
3967c478bdstevel@tonic-gate	/* a name that ends in slash -- back up until previous slash */
3977c478bdstevel@tonic-gate	while (cp != path) {
3987c478bdstevel@tonic-gate		if (*--cp == '/') {
3997c478bdstevel@tonic-gate			return (--cp);
4007c478bdstevel@tonic-gate		}
4017c478bdstevel@tonic-gate	}
4027c478bdstevel@tonic-gate
4037c478bdstevel@tonic-gate	/* the only slash is the end of the name */
4047c478bdstevel@tonic-gate	return (path);
4057c478bdstevel@tonic-gate}
4067c478bdstevel@tonic-gate
407d67944fScott Rotondostatic int	vol_getmntdev(FILE *, struct mnttab *, dev_t,
408d67944fScott Rotondo			    struct dk_cinfo *);
4097c478bdstevel@tonic-gate
4107c478bdstevel@tonic-gatestatic int
4117c478bdstevel@tonic-gateget_media_info(char *path, char **mtypep, int *mnump, char **spclp)
4127c478bdstevel@tonic-gate{
4137c478bdstevel@tonic-gate	FILE		*fp = NULL;
4147c478bdstevel@tonic-gate	int		fd = -1;
4157c478bdstevel@tonic-gate	char		*cn = NULL;		/* char spcl pathname */
4167c478bdstevel@tonic-gate	struct stat64	sb;
4177c478bdstevel@tonic-gate	struct dk_cinfo	info;
4187c478bdstevel@tonic-gate	struct mnttab	mnt;
4197c478bdstevel@tonic-gate	int		ret_val = FALSE;
4207c478bdstevel@tonic-gate
421004388ecasper	if ((fp = fopen(MNTTAB, "rF")) == NULL) {
42248bbca8Daniel Hoffman		/* mtab is gone... let it go */
4237c478bdstevel@tonic-gate		goto dun;
4247c478bdstevel@tonic-gate	}
4257c478bdstevel@tonic-gate
4267c478bdstevel@tonic-gate	/* get char spcl pathname */
4277c478bdstevel@tonic-gate	if ((cn = volmgt_getfullrawname(path)) == NULL) {
4287c478bdstevel@tonic-gate		goto dun;
4297c478bdstevel@tonic-gate	}
4307c478bdstevel@tonic-gate	if (cn[0] == NULLC) {
4317c478bdstevel@tonic-gate		goto dun;
4327c478bdstevel@tonic-gate	}
4337c478bdstevel@tonic-gate
4347c478bdstevel@tonic-gate	if ((fd = open(cn, O_RDONLY|O_NDELAY)) < 0) {
4357c478bdstevel@tonic-gate		goto dun;
4367c478bdstevel@tonic-gate	}
4377c478bdstevel@tonic-gate
4387c478bdstevel@tonic-gate	if (fstat64(fd, &sb) < 0) {
4397c478bdstevel@tonic-gate		goto dun;
4407c478bdstevel@tonic-gate	}
4417c478bdstevel@tonic-gate
4427c478bdstevel@tonic-gate	if (ioctl(fd, DKIOCINFO, &info) != 0) {
4437c478bdstevel@tonic-gate		goto dun;
4447c478bdstevel@tonic-gate	}
4457c478bdstevel@tonic-gate
4467c478bdstevel@tonic-gate	/* if we found the entry then disect it */
4477c478bdstevel@tonic-gate	if (vol_getmntdev(fp, &mnt, sb.st_rdev, &info) != 0) {
4487c478bdstevel@tonic-gate		char		*cp;
4497c478bdstevel@tonic-gate		char		*mtype;
4507c478bdstevel@tonic-gate		char		*mnt_dir;
4517c478bdstevel@tonic-gate		int		mtype_len;
4527c478bdstevel@tonic-gate		DIR		*dirp = NULL;
4537c478bdstevel@tonic-gate		struct dirent64	*dp;
4547c478bdstevel@tonic-gate		char		*volname;
4557c478bdstevel@tonic-gate
4567c478bdstevel@tonic-gate
4577c478bdstevel@tonic-gate		/* return the spcl device name found */
4587c478bdstevel@tonic-gate		*spclp = strdup(mnt.mnt_special);
4597c478bdstevel@tonic-gate
4607c478bdstevel@tonic-gate		/*
4617c478bdstevel@tonic-gate		 * try to get the media type (e.g. "floppy") from the mount
4627c478bdstevel@tonic-gate		 * point (e.g. "/floppy/NAME") if vold is running
4637c478bdstevel@tonic-gate		 */
4647c478bdstevel@tonic-gate
4657c478bdstevel@tonic-gate		if (!volmgt_running() ||
4667c478bdstevel@tonic-gate		    (!volmgt_ownspath(*spclp) &&
467d67944fScott Rotondo		    volmgt_symname(*spclp) == NULL)) {
4687c478bdstevel@tonic-gate			ret_val = TRUE;		/* success (if limited) */
4697c478bdstevel@tonic-gate			goto dun;
4707c478bdstevel@tonic-gate		}
4717c478bdstevel@tonic-gate
4727c478bdstevel@tonic-gate		/* get the first part of the mount point (e.g. "floppy") */
4737c478bdstevel@tonic-gate		cp = mnt.mnt_mountp;
4747c478bdstevel@tonic-gate		if (*cp++ != '/') {
4757c478bdstevel@tonic-gate			goto dun;
4767c478bdstevel@tonic-gate		}
4777c478bdstevel@tonic-gate		mtype = cp;
4787c478bdstevel@tonic-gate		if ((cp = strchr(mtype, '/')) == NULL) {
4797c478bdstevel@tonic-gate			goto dun;
4807c478bdstevel@tonic-gate		}
4817c478bdstevel@tonic-gate		*cp++ = NULLC;
4827c478bdstevel@tonic-gate		mnt_dir = mnt.mnt_mountp;	/* save dir path */
4837c478bdstevel@tonic-gate
4847c478bdstevel@tonic-gate		/* get the volume name (e.g. "unnamed_floppy") */
4857c478bdstevel@tonic-gate		volname = cp;
4867c478bdstevel@tonic-gate
4877c478bdstevel@tonic-gate		/* scan for the symlink that points to our volname */
4887c478bdstevel@tonic-gate		if ((dirp = opendir(mnt_dir)) == NULL) {
4897c478bdstevel@tonic-gate			goto dun;
4907c478bdstevel@tonic-gate		}
4917c478bdstevel@tonic-gate		mtype_len = strlen(mtype);
4927c478bdstevel@tonic-gate		while ((dp = readdir64(dirp)) != NULL) {
4937c478bdstevel@tonic-gate			char		lpath[2 * (MAXNAMELEN+1)];
4947c478bdstevel@tonic-gate			char		linkbuf[MAXPATHLEN+4];
4957c478bdstevel@tonic-gate			int		lb_len;
4967c478bdstevel@tonic-gate			struct stat64	sb;
4977c478bdstevel@tonic-gate
4987c478bdstevel@tonic-gate
4997c478bdstevel@tonic-gate			if (strncmp(dp->d_name, mtype, mtype_len) != 0) {
5007c478bdstevel@tonic-gate				continue;	/* not even close */
5017c478bdstevel@tonic-gate			}
5027c478bdstevel@tonic-gate
5037c478bdstevel@tonic-gate			(void) sprintf(lpath, "%s/%s", mnt_dir,
5047c478bdstevel@tonic-gate			    dp->d_name);
5057c478bdstevel@tonic-gate			if (lstat64(lpath, &sb) < 0) {
5067c478bdstevel@tonic-gate				continue;	/* what? */
5077c478bdstevel@tonic-gate			}
5087c478bdstevel@tonic-gate			if (!S_ISLNK(sb.st_mode)) {
5097c478bdstevel@tonic-gate				continue;	/* not our baby */
5107c478bdstevel@tonic-gate			}
5117c478bdstevel@tonic-gate			if ((lb_len = readlink(lpath, linkbuf,
5127c478bdstevel@tonic-gate			    sizeof (linkbuf))) < 0) {
5137c478bdstevel@tonic-gate				continue;
5147c478bdstevel@tonic-gate			}
5157c478bdstevel@tonic-gate			linkbuf[lb_len] = NULLC; /* null terminate */
5167c478bdstevel@tonic-gate			if ((cp = vol_basename(linkbuf)) == NULL) {
5177c478bdstevel@tonic-gate				continue;
5187c478bdstevel@tonic-gate			}
5197c478bdstevel@tonic-gate			/* now we have the name! */
5207c478bdstevel@tonic-gate			if (strcmp(cp, volname) == 0) {
5217c478bdstevel@tonic-gate				/* found it !! */
5227c478bdstevel@tonic-gate				if (sscanf(dp->d_name + mtype_len, "%d",
5237c478bdstevel@tonic-gate				    mnump) == 1) {
5247c478bdstevel@tonic-gate					*mtypep = strdup(mtype);
5257c478bdstevel@tonic-gate					ret_val = TRUE;
5267c478bdstevel@tonic-gate				}
5277c478bdstevel@tonic-gate				break;
5287c478bdstevel@tonic-gate			}
5297c478bdstevel@tonic-gate		}
5307c478bdstevel@tonic-gate		(void) closedir(dirp);
5317c478bdstevel@tonic-gate	}
5327c478bdstevel@tonic-gate
5337c478bdstevel@tonic-gatedun:
5347c478bdstevel@tonic-gate	if (fp != NULL) {
5357c478bdstevel@tonic-gate		(void) fclose(fp);
5367c478bdstevel@tonic-gate	}
5377c478bdstevel@tonic-gate	if (fd >= 0) {
5387c478bdstevel@tonic-gate		(void) close(fd);
5397c478bdstevel@tonic-gate	}
5407c478bdstevel@tonic-gate	if (cn != NULL) {
5417c478bdstevel@tonic-gate		free(cn);
5427c478bdstevel@tonic-gate	}
5437c478bdstevel@tonic-gate#ifdef	DEBUG
5447c478bdstevel@tonic-gate	if (ret_val) {
5457c478bdstevel@tonic-gate		dexit("get_media_info: returning mtype=%s, mnum=%d, spcl=%s\n",
5467c478bdstevel@tonic-gate		    *mtypep == NULL ? "<null ptr>" : *mtypep,
5477c478bdstevel@tonic-gate		    *mnump,
5487c478bdstevel@tonic-gate		    *spclp == NULL ? "<null ptr>" : *spclp);
5497c478bdstevel@tonic-gate	} else {
5507c478bdstevel@tonic-gate		dexit("get_media_info: FAILED\n");
5517c478bdstevel@tonic-gate	}
5527c478bdstevel@tonic-gate#endif
5537c478bdstevel@tonic-gate	return (ret_val);
5547c478bdstevel@tonic-gate}
5557c478bdstevel@tonic-gate
5567c478bdstevel@tonic-gate
5577c478bdstevel@tonic-gate/*
5587c478bdstevel@tonic-gate * call the appropriate unmount program, returning its success (TRUE)
5597c478bdstevel@tonic-gate * or failure (FALSE)
5607c478bdstevel@tonic-gate */
5617c478bdstevel@tonic-gatestatic int
5627c478bdstevel@tonic-gatecall_unmount_prog(int mi_gotten, int use_rmm, char *mtype, int mnum,
5637c478bdstevel@tonic-gate    char *spcl, char *bn)
5647c478bdstevel@tonic-gate{
5657c478bdstevel@tonic-gate	pid_t		pid;			/* forked proc's pid */
5667c478bdstevel@tonic-gate	int		ret_val = FALSE;
5677c478bdstevel@tonic-gate	const char	*etc_umount = "/etc/umount";
5687c478bdstevel@tonic-gate	const char	*rmm = "/usr/sbin/rmmount";
5697c478bdstevel@tonic-gate	int		rval;			/* proc's return value */
5707c478bdstevel@tonic-gate
5717c478bdstevel@tonic-gate
5727c478bdstevel@tonic-gate#ifdef	DEBUG
5737c478bdstevel@tonic-gate	denter(
5747c478bdstevel@tonic-gate	"call_unmount_prog(%s, %s, \"%s\", %d, \"%s\", \"%s\"): entering\n",
5757c478bdstevel@tonic-gate	    mi_gotten ? "TRUE" : "FALSE", use_rmm ? "TRUE" : "FALSE",
5767c478bdstevel@tonic-gate	    mtype ? mtype : "<null ptr>", mnum, spcl ? spcl : "<null ptr>",
5777c478bdstevel@tonic-gate	    bn);
5787c478bdstevel@tonic-gate#endif
5797c478bdstevel@tonic-gate	/* create a child to unmount the path */
5807c478bdstevel@tonic-gate	if ((pid = fork()) < 0) {
5817c478bdstevel@tonic-gate		goto dun;
5827c478bdstevel@tonic-gate	}
5837c478bdstevel@tonic-gate
5847c478bdstevel@tonic-gate	if (pid == 0) {
5857c478bdstevel@tonic-gate		/* the child */
5867c478bdstevel@tonic-gate#ifndef	DEBUG
5877c478bdstevel@tonic-gate		int		xfd;
5887c478bdstevel@tonic-gate#endif
5897c478bdstevel@tonic-gate		char		env_buf[MAXPATHLEN];
5907c478bdstevel@tonic-gate
5917c478bdstevel@tonic-gate#ifndef	DEBUG
5927c478bdstevel@tonic-gate		/* get rid of those nasty err messages */
5937c478bdstevel@tonic-gate		if ((xfd = open(NULL_PATH, O_RDWR)) >= 0) {
5947c478bdstevel@tonic-gate			(void) dup2(xfd, fileno(stdin));
5957c478bdstevel@tonic-gate			(void) dup2(xfd, fileno(stdout));
5967c478bdstevel@tonic-gate			(void) dup2(xfd, fileno(stderr));
5977c478bdstevel@tonic-gate		}
5987c478bdstevel@tonic-gate#endif
5997c478bdstevel@tonic-gate
6007c478bdstevel@tonic-gate		if (use_rmm) {
6017c478bdstevel@tonic-gate			/* set up environment vars */
6027c478bdstevel@tonic-gate			(void) putenv("VOLUME_ACTION=eject");
6037c478bdstevel@tonic-gate			(void) putenv(strdup(env_buf));
6047c478bdstevel@tonic-gate			if (mi_gotten) {
6057c478bdstevel@tonic-gate				(void) sprintf(env_buf,
6067c478bdstevel@tonic-gate				    "VOLUME_MEDIATYPE=%s", mtype);
6077c478bdstevel@tonic-gate				(void) putenv(strdup(env_buf));
6087c478bdstevel@tonic-gate				(void) sprintf(env_buf, "VOLUME_SYMDEV=%s%d",
6097c478bdstevel@tonic-gate				    mtype, mnum);
6107c478bdstevel@tonic-gate				(void) putenv(strdup(env_buf));
6117c478bdstevel@tonic-gate				(void) sprintf(env_buf, "VOLUME_PATH=%s",
6127c478bdstevel@tonic-gate				    spcl);
6137c478bdstevel@tonic-gate				(void) putenv(strdup(env_buf));
6147c478bdstevel@tonic-gate				(void) sprintf(env_buf, "VOLUME_NAME=%s",
6157c478bdstevel@tonic-gate				    vol_basename(spcl));
6167c478bdstevel@tonic-gate				(void) putenv(strdup(env_buf));
6177c478bdstevel@tonic-gate			} else {
6187c478bdstevel@tonic-gate				(void) sprintf(env_buf, "VOLUME_PATH=%s", bn);
6197c478bdstevel@tonic-gate				(void) putenv(strdup(env_buf));
6207c478bdstevel@tonic-gate				(void) sprintf(env_buf, "VOLUME_NAME=%s",
6217c478bdstevel@tonic-gate				    vol_basename(bn));
6227c478bdstevel@tonic-gate				(void) putenv(strdup(env_buf));
6237c478bdstevel@tonic-gate			}
6247c478bdstevel@tonic-gate#ifdef	DEBUG
6257c478bdstevel@tonic-gate			dprintf("call_unmount_prog: calling \"%s -D\"\n", rmm);
6267c478bdstevel@tonic-gate			(void) execl(rmm, rmm, "-D", NULL);
6277c478bdstevel@tonic-gate#else
6287c478bdstevel@tonic-gate			(void) execl(rmm, rmm, NULL);
6297c478bdstevel@tonic-gate#endif
6307c478bdstevel@tonic-gate		} else {
6317c478bdstevel@tonic-gate#ifdef	DEBUG
6327c478bdstevel@tonic-gate			dprintf("call_unmount_prog: calling \"%s %s\"\n",
6337c478bdstevel@tonic-gate			    etc_umount, mi_gotten ? spcl : bn);
6347c478bdstevel@tonic-gate#endif
6357c478bdstevel@tonic-gate			(void) execl(etc_umount, etc_umount,
6367c478bdstevel@tonic-gate			    mi_gotten ? spcl : bn,
6377c478bdstevel@tonic-gate			    NULL);
6387c478bdstevel@tonic-gate		}
6397c478bdstevel@tonic-gate		exit(-1);
6407c478bdstevel@tonic-gate		/*NOTREACHED*/
6417c478bdstevel@tonic-gate	}
6427c478bdstevel@tonic-gate
6437c478bdstevel@tonic-gate	/* wait for the umount command to exit */
6447c478bdstevel@tonic-gate	if (waitpid(pid, &rval, 0) == pid) {
6457c478bdstevel@tonic-gate		if (WIFEXITED(rval)) {
6467c478bdstevel@tonic-gate			if (WEXITSTATUS(rval) == 0) {
6477c478bdstevel@tonic-gate				ret_val = TRUE;	/* success */
6487c478bdstevel@tonic-gate			}
6497c478bdstevel@tonic-gate		}
6507c478bdstevel@tonic-gate	}
6517c478bdstevel@tonic-gate
6527c478bdstevel@tonic-gatedun:
6537c478bdstevel@tonic-gate	return (ret_val);
6547c478bdstevel@tonic-gate}
655