xref: /illumos-gate/usr/src/lib/libvolmgt/common/volmgt_on_private.c (revision 4de2612967d06c4fdbf524a62556a1e8118a006f)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright (c) 1996 by Sun Microsystems, Inc.
24  * All rights reserved.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 /*
30  * routines in this module are meant to be called by other libvolmgt
31  * routines only
32  */
33 
34 #include	<stdio.h>
35 #include	<string.h>
36 #include	<dirent.h>
37 #include	<fcntl.h>
38 #include	<string.h>
39 #ifdef	DEBUG
40 #include	<errno.h>
41 #endif
42 #include	<libintl.h>
43 #include	<limits.h>
44 #include	<unistd.h>
45 #include	<stdlib.h>
46 #include	<volmgt.h>
47 #include	<sys/types.h>
48 #include	<sys/mkdev.h>
49 #include	<sys/stat.h>
50 #include	<sys/dkio.h>
51 #include	<sys/param.h>
52 #include	<sys/wait.h>
53 #include	<sys/mnttab.h>
54 #include	<sys/vol.h>
55 #include	"volmgt_private.h"
56 
57 
58 #define	NULL_PATH		"/dev/null"
59 
60 
61 
62 /*
63  * This is an ON Consolidation Private interface.
64  *
65  * Is the specified path mounted?
66  *
67  * This function is really inadequate for ejection testing.  For example,
68  * I could have /dev/fd0a mounted and eject /dev/fd0c, and it would be
69  * ejected.  There needs to be some better way to make this check, although
70  * short of looking up the mounted dev_t in the kernel mount table and
71  * building in all kinds of knowledge into this function,  I'm not sure
72  * how to do it.
73  */
74 int
75 _dev_mounted(char *path)
76 {
77 	static int	vol_getmntdev(FILE *, struct mnttab *, dev_t,
78 			    struct dk_cinfo *);
79 	int		fd = -1;
80 	struct dk_cinfo	info;
81 	static FILE 	*fp = NULL;		/* mnttab file pointer */
82 	struct mnttab	mnt;			/* set bug not used */
83 	char		*cn = NULL;		/* char spcl pathname */
84 	struct stat64	sb;
85 	int		ret_val = 0;
86 
87 
88 
89 #ifdef	DEBUG
90 	denter("_dev_mounted(%s): entering\n", path);
91 #endif
92 
93 	/* ensure we have the block spcl pathname */
94 	if ((cn = (char *)volmgt_getfullrawname(path)) == NULL) {
95 #ifdef	DEBUG
96 		dprintf("_dev_mounted: volmgt_getfullrawname failed\n");
97 #endif
98 		goto dun;
99 	}
100 
101 #ifdef	DEBUG_OPEN
102 	dprintf("_dev_mounted: fopen()ing \"%s\"\n", MNTTAB);
103 #endif
104 	if ((fp = fopen(MNTTAB, "r")) == NULL) {
105 		/* mtab is gone... let him go */
106 #ifdef	DEBUG
107 		perror(MNTTAB);
108 #endif
109 		goto dun;
110 	}
111 
112 #ifdef	DEBUG_OPEN
113 	dprintf("_dev_mounted: open()ing \"%s\"\n", cn);
114 #endif
115 	if ((fd = open(cn, O_RDONLY|O_NDELAY)) < 0) {
116 #ifdef	DEBUG
117 		dprintf("_dev_mounted: can't open \"%s\" (%d)\n", cn, errno);
118 #endif
119 		goto dun;
120 	}
121 
122 #ifdef	DEBUG_STAT
123 	dprintf("_dev_mounted: fstat()ing \"%s\"\n", cn);
124 #endif
125 	if (fstat64(fd, &sb) < 0) {
126 #ifdef	DEBUG
127 		dprintf("_dev_mounted: stat of \"%s\" failed (%d)\n", cn,
128 		    errno);
129 #endif
130 		goto dun;
131 	}
132 
133 #ifdef	DEBUG_IOCTL
134 	dprintf("_dev_mounted: ioctl(%s, DKIOCINFO)\n", cn);
135 #endif
136 	if (ioctl(fd, DKIOCINFO, &info) != 0) {
137 #ifdef	DEBUG
138 		dprintf(
139 		    "_dev_mounted: ioctl(DKIOCINFO) on \"%s\" failed (%d)\n",
140 		    cn, errno);
141 #endif
142 		goto dun;
143 	}
144 
145 	if (vol_getmntdev(fp, &mnt, sb.st_rdev, &info) != 0) {
146 		ret_val = 1;			/* match found! */
147 	}
148 
149 dun:
150 	if (cn != NULL) {
151 		free(cn);
152 	}
153 	if (fp != NULL) {
154 		(void) fclose(fp);
155 	}
156 	if (fd >= 0) {
157 		(void) close(fd);
158 	}
159 #ifdef	DEBUG
160 	dexit("_dev_mounted: returning %s\n",
161 	    ret_val ? "TRUE" : "FALSE");
162 #endif
163 	return (ret_val);
164 }
165 
166 
167 /*
168  * This is an ON Consolidation Private interface.
169  *
170  * Forks off rmmount and (in essence) returns the result
171  *
172  * a return value of 0 (FALSE) means failure, non-zero (TRUE) means success
173  */
174 int
175 _dev_unmount(char *path)
176 {
177 	static int	call_unmount_prog(int, int, char *, int, char *,
178 			    char *);
179 	static int	get_media_info(char *, char **, int *, char **);
180 	char		*bn = NULL;		/* block name */
181 	char		*mtype = NULL;		/* media type */
182 	char		*spcl = NULL;		/* special dev. path */
183 	char		*spcl_failed = NULL;	/* spcl that failed */
184 	int		ret_val = FALSE;	/* what we return */
185 	char		*vr;			/* volmgt root dir */
186 	int		media_info_gotten = 0;
187 	int		mnum = 0;
188 	int		volume_is_not_managed;
189 	char		*pathbuf, *absname;
190 
191 #ifdef	DEBUG
192 	denter("_dev_unmount(%s): entering\n", path);
193 #endif
194 
195 	if ((bn = (char *)volmgt_getfullblkname(path)) == NULL) {
196 #ifdef	DEBUG
197 		dprintf("_dev_unmount: volmgt_getfullblkname failed\n");
198 #endif
199 		goto dun;
200 	}
201 
202 	if ((pathbuf = malloc(PATH_MAX+1)) == NULL)
203 		goto dun;
204 
205 	absname = bn;
206 	if (realpath(bn, pathbuf) != NULL)
207 		absname = pathbuf;
208 
209 	volume_is_not_managed = !volmgt_running() ||
210 		(!volmgt_ownspath(absname) && volmgt_symname(bn) == NULL);
211 
212 	free(pathbuf);
213 
214 	/* decide of we should use rmmount to unmount the media */
215 	if (!volume_is_not_managed) {
216 		int		use_rmm = FALSE;	/* use rmmount??  */
217 
218 		/* at least volmgt is running */
219 		vr = (char *)volmgt_root();
220 		if (strncmp(bn, vr, strlen(vr)) == 0) {
221 			/* the block path is rooted in /vol */
222 			use_rmm = TRUE;
223 		}
224 
225 		/* try to get info about media */
226 		media_info_gotten = get_media_info(bn, &mtype, &mnum, &spcl);
227 
228 		ret_val = call_unmount_prog(media_info_gotten, use_rmm, mtype,
229 		    mnum, spcl, bn);
230 
231 	} else {
232 
233 		/* volmgt is *not* running */
234 
235 		if (get_media_info(bn, &mtype, &mnum, &spcl)) {
236 
237 			/*
238 			 * volmgt is off and get_media_info() has returned
239 			 * info on the media -- soo (this is kinda' a hack)
240 			 * ... we iterate, looking for multiple slices
241 			 * of (say) a floppy being mounted
242 			 *
243 			 * note: if an unmount fails we don't want to try
244 			 * to unmount the same device on the next try, so
245 			 * we try to watch for that
246 			 */
247 
248 			do {
249 				/*
250 				 * don't call the unmount program is we're just
251 				 * trying to unmount the same device that
252 				 * failed last time -- if that's the case,
253 				 * then bail
254 				 */
255 				if (spcl_failed != NULL) {
256 					if (strcmp(spcl, spcl_failed) == 0) {
257 						break;
258 					}
259 				}
260 				ret_val = call_unmount_prog(TRUE, FALSE,
261 				    mtype, mnum, spcl, bn);
262 
263 				if (!ret_val) {
264 					/* save spcl device name that failed */
265 					spcl_failed = strdup(spcl);
266 				} else {
267 					/*
268 					 * unmount succeeded, so clean up
269 					 */
270 					if (spcl_failed != NULL) {
271 						free(spcl_failed);
272 						spcl_failed = NULL;
273 					}
274 				}
275 
276 			} while (get_media_info(bn, &mtype, &mnum, &spcl));
277 
278 		} else {
279 
280 			/* just do the unmmount cycle once */
281 			ret_val = call_unmount_prog(FALSE, FALSE, NULL, 0,
282 			    NULL, bn);
283 		}
284 
285 	}
286 
287 	if (mtype != NULL) {
288 		free(mtype);
289 	}
290 	if (spcl != NULL) {
291 		free(spcl);
292 	}
293 	if (spcl_failed != NULL) {
294 		free(spcl_failed);
295 	}
296 	if (bn != NULL) {
297 		free(bn);
298 	}
299 
300 dun:
301 
302 #ifdef	DEBUG
303 	dexit("_dev_unmount: returning %s\n", ret_val ? "TRUE" : "FALSE");
304 #endif
305 	return (ret_val);
306 }
307 
308 
309 /*
310  * find a mnttab entry that has the same dev as the supplied dev,
311  *  returning it and a non-zero value if found, else returning 0
312  *
313  * this is just like getmntany(), except that it scans based on st_rdev,
314  * and it even finds different slices on the same device/unit (thanx to
315  * code copied from format.c)
316  */
317 static int
318 vol_getmntdev(FILE *fp, struct mnttab *mp, dev_t dev, struct dk_cinfo *ip)
319 {
320 	int		fd;		/* dev-in-question fd */
321 	struct stat64	sb;		/* dev-in-question stat struct */
322 	int		ret_val = 0;	/* default value: no match found */
323 	char		*cn;		/* char pathname */
324 	struct dk_cinfo	dkinfo;		/* for testing for slices */
325 
326 
327 #ifdef	DEBUG
328 	denter(
329 	    "vol_getmntdev: entering for %d.%d, ctype/cnum/unit = %d/%d/%d\n",
330 	    (int)major(dev), (int)minor(dev), ip->dki_ctype, ip->dki_cnum,
331 	    ip->dki_unit);
332 #endif
333 
334 	/* reset the mnttab -- just in case */
335 	rewind(fp);
336 
337 	/* scan each entry in mnttab */
338 	while (getmntent(fp, mp) == 0) {
339 
340 		/* don't even try unless it's a local pathname */
341 		if (mp->mnt_special[0] != '/') {
342 			continue;
343 		}
344 
345 		/* get char pathname */
346 		if ((cn = volmgt_getfullrawname(mp->mnt_special)) == NULL) {
347 			continue;
348 		}
349 		if (cn[0] == NULLC) {
350 			free(cn);
351 			continue;	/* couldn't get raw name */
352 		}
353 
354 		/* open the device */
355 #ifdef	DEBUG_OPEN
356 		dprintf("vol_getmntdev: open()ing \"%s\"\n", cn);
357 #endif
358 		if ((fd = open(cn, O_RDONLY|O_NDELAY)) < 0) {
359 			/* if we can't open it *assume* it's not a match */
360 #ifdef	DEBUG
361 			dprintf(
362 			    "vol_getmntdev: open of \"%s\" (%s) failed (%d)\n",
363 			    cn, mp->mnt_fstype, errno);
364 #endif
365 			free(cn);
366 			continue;
367 		}
368 
369 		/* stat the device */
370 #ifdef	DEBUG_STAT
371 		dprintf("vol_getmntdev: fstat()ing \"%s\"\n", cn);
372 #endif
373 		if (fstat64(fd, &sb) < 0) {
374 #ifdef	DEBUG
375 			dprintf(
376 			    "vol_getmntdev: stat of \"%s\" (%s) failed (%d)\n",
377 			    cn, mp->mnt_fstype, errno);
378 #endif
379 			free(cn);
380 			(void) close(fd);
381 			continue;	/* ain't there: can't be a match */
382 		}
383 
384 		/* ensure we have a spcl device (a double check) */
385 		if (!S_ISBLK(sb.st_mode) && !S_ISCHR(sb.st_mode)) {
386 #ifdef	DEBUG
387 			dprintf(
388 		"vol_getmntdev: \"%s\" not a blk- or chr-spcl device\n",
389 			    cn);
390 #endif
391 			free(cn);
392 			(void) close(fd);
393 			continue;
394 		}
395 
396 		/* (almost) finally -- check the dev_t for equality */
397 		if (sb.st_rdev == dev) {
398 			ret_val = 1;		/* match found! */
399 			free(cn);
400 			(void) close(fd);
401 			break;
402 		}
403 
404 		/*
405 		 * check that the major numbers match, since if they
406 		 * don't then there's no reason to use the DKIOCINFO
407 		 * ioctl to see if we have to major/minor pairs that
408 		 * really point to the same device
409 		 */
410 		if (major(sb.st_rdev) != major(dev)) {
411 			/* no use continuing, since major devs are different */
412 			free(cn);
413 			(void) close(fd);
414 			continue;
415 		}
416 
417 #ifdef	DEBUG_IOCTL
418 		dprintf("vol_getmntdev: ioctl(%s, DKIOCINFO)\n", cn);
419 #endif
420 		/* one last check -- for diff. slices of the same dev/unit */
421 		if (ioctl(fd, DKIOCINFO, &dkinfo) < 0) {
422 #ifdef	DEBUG
423 			dprintf(
424 		"vol_getmntdev: ioctl(DKIOCINFO) of \"%s\" failed (%d)\n",
425 			    cn, errno);
426 #endif
427 			free(cn);
428 			(void) close(fd);
429 			continue;
430 		}
431 
432 		free(cn);		/* all done with raw pathname */
433 		(void) close(fd);	/* all done with file descriptor */
434 
435 		/* if ctrler type/number and unit match, it's a match */
436 		if ((ip->dki_ctype == dkinfo.dki_ctype) &&
437 		    (ip->dki_cnum == dkinfo.dki_cnum) &&
438 		    (ip->dki_unit == dkinfo.dki_unit)) {
439 			/*
440 			 * even though minor numbers differ we have a
441 			 * match
442 			 */
443 			ret_val = 1;
444 			break;
445 		}
446 
447 		/* go around again */
448 	}
449 
450 #ifdef	DEBUG
451 	dexit("vol_getmntdev: returning %d (%s)\n", ret_val,
452 	    ret_val == 1 ? "SUCCESS" : "FAILURE");
453 #endif
454 	return (ret_val);
455 }
456 
457 
458 char *
459 vol_basename(char *path)
460 {
461 	char	*cp;
462 
463 
464 	/* check for the degenerate case */
465 	if (strcmp(path, "/") == 0) {
466 		return (path);
467 	}
468 
469 	/* look for the last slash in the name */
470 	if ((cp = strrchr(path, '/')) == NULL) {
471 		/* no slash */
472 		return (path);
473 	}
474 
475 	/* ensure something is after the slash */
476 	if (*++cp != NULLC) {
477 		return (cp);
478 	}
479 
480 	/* a name that ends in slash -- back up until previous slash */
481 	while (cp != path) {
482 		if (*--cp == '/') {
483 			return (--cp);
484 		}
485 	}
486 
487 	/* the only slash is the end of the name */
488 	return (path);
489 }
490 
491 
492 static int
493 get_media_info(char *path, char **mtypep, int *mnump, char **spclp)
494 {
495 	static int	vol_getmntdev(FILE *, struct mnttab *, dev_t,
496 			    struct dk_cinfo *);
497 	FILE		*fp = NULL;
498 	int		fd = -1;
499 	char		*cn = NULL;		/* char spcl pathname */
500 	struct stat64	sb;
501 	struct dk_cinfo	info;
502 	struct mnttab	mnt;
503 	int		ret_val = FALSE;
504 
505 
506 
507 #ifdef	DEBUG
508 	denter("get_media_info(%s): entering\n", path);
509 #endif
510 
511 #ifdef	DEBUG_OPEN
512 	dprintf("get_media_info: fopen()ing \"%s\"\n", MNTTAB);
513 #endif
514 	if ((fp = fopen(MNTTAB, "r")) == NULL) {
515 		/* mtab is gone... let him go */
516 #ifdef	DEBUG
517 		dprintf("get_media_info: can't open \"%s\" (%d)\n", MNTTAB,
518 		    errno);
519 #endif
520 		goto dun;
521 	}
522 
523 	/* get char spcl pathname */
524 	if ((cn = volmgt_getfullrawname(path)) == NULL) {
525 		goto dun;
526 	}
527 	if (cn[0] == NULLC) {
528 		goto dun;
529 	}
530 
531 #ifdef	DEBUG_OPEN
532 	dprintf("get_media_info: open()ing \"%s\"\n", cn);
533 #endif
534 	if ((fd = open(cn, O_RDONLY|O_NDELAY)) < 0) {
535 #ifdef	DEBUG
536 		dprintf("get_media_info(): can't open \"%s\" (%d)\n", cn,
537 		    errno);
538 #endif
539 		goto dun;
540 	}
541 
542 #ifdef	DEBUG_STAT
543 	dprintf("get_media_info: fstat()ing \"%s\"\n", cn);
544 #endif
545 	if (fstat64(fd, &sb) < 0) {
546 #ifdef	DEBUG
547 		dprintf("get_media_info: can't stat \"%s\" (%d)\n", cn, errno);
548 #endif
549 		goto dun;
550 	}
551 
552 #ifdef	DEBUG_IOCTL
553 	dprintf("get_media_info: ioctl(%s, DKIOCINFO)\n", cn);
554 #endif
555 	if (ioctl(fd, DKIOCINFO, &info) != 0) {
556 #ifdef	DEBUG
557 		dprintf(
558 		    "get_media_info: ioctl(DKIOCINFO) on \"%s\" failed (%d)\n",
559 		    cn, errno);
560 #endif
561 		goto dun;
562 	}
563 
564 	/* if we found the entry then disect it */
565 	if (vol_getmntdev(fp, &mnt, sb.st_rdev, &info) != 0) {
566 		char		*cp;
567 		char		*mtype;
568 		char		*mnt_dir;
569 		int		mtype_len;
570 		DIR		*dirp = NULL;
571 		struct dirent64	*dp;
572 		char		*volname;
573 
574 
575 		/* return the spcl device name found */
576 		*spclp = strdup(mnt.mnt_special);
577 
578 		/*
579 		 * try to get the media type (e.g. "floppy") from the mount
580 		 * point (e.g. "/floppy/NAME") if vold is running
581 		 */
582 
583 		if (!volmgt_running() ||
584 		    (!volmgt_ownspath(*spclp) &&
585 			volmgt_symname(*spclp) == NULL)) {
586 			ret_val = TRUE;		/* success (if limited) */
587 			goto dun;
588 		}
589 
590 		/* get the first part of the mount point (e.g. "floppy") */
591 		cp = mnt.mnt_mountp;
592 		if (*cp++ != '/') {
593 #ifdef	DEBUG
594 			dprintf(
595 	"get_media_info warning: no leading '/' in mount point \"%s\"\n",
596 			    mnt.mnt_mountp);
597 #endif
598 			goto dun;
599 		}
600 		mtype = cp;
601 		if ((cp = strchr(mtype, '/')) == NULL) {
602 #ifdef	DEBUG
603 			dprintf(
604 		"get_media_info warning: no 2nd '/' in mount point \"%s\"\n",
605 			    mnt.mnt_mountp);
606 #endif
607 			goto dun;
608 		}
609 		*cp++ = NULLC;
610 		mnt_dir = mnt.mnt_mountp;	/* save dir path */
611 
612 		/* get the volume name (e.g. "unnamed_floppy") */
613 		volname = cp;
614 
615 		/* scan for the symlink that points to our volname */
616 		if ((dirp = opendir(mnt_dir)) == NULL) {
617 #ifdef	DEBUG
618 			dprintf(
619 		"get_media_info warning: can't open directory \"%s\"\n",
620 			    mnt_dir);
621 #endif
622 			goto dun;
623 		}
624 		mtype_len = strlen(mtype);
625 		while ((dp = readdir64(dirp)) != NULL) {
626 			char		lpath[2 * (MAXNAMELEN+1)];
627 			char		linkbuf[MAXPATHLEN+4];
628 			int		lb_len;
629 			struct stat64	sb;
630 
631 
632 			if (strncmp(dp->d_name, mtype, mtype_len) != 0) {
633 				continue;	/* not even close */
634 			}
635 
636 			(void) sprintf(lpath, "%s/%s", mnt_dir,
637 			    dp->d_name);
638 #ifdef	DEBUG_STAT
639 			dprintf("get_media_info: lstat()ing \"%s\"\n", lpath);
640 #endif
641 			if (lstat64(lpath, &sb) < 0) {
642 				continue;	/* what? */
643 			}
644 			if (!S_ISLNK(sb.st_mode)) {
645 				continue;	/* not our baby */
646 			}
647 			if ((lb_len = readlink(lpath, linkbuf,
648 			    sizeof (linkbuf))) < 0) {
649 				continue;
650 			}
651 			linkbuf[lb_len] = NULLC; /* null terminate */
652 			if ((cp = vol_basename(linkbuf)) == NULL) {
653 				continue;
654 			}
655 			/* now we have the name! */
656 			if (strcmp(cp, volname) == 0) {
657 				/* found it !! */
658 				if (sscanf(dp->d_name + mtype_len, "%d",
659 				    mnump) == 1) {
660 					*mtypep = strdup(mtype);
661 					ret_val = TRUE;
662 				}
663 				break;
664 			}
665 		}
666 		(void) closedir(dirp);
667 	}
668 
669 dun:
670 	if (fp != NULL) {
671 		(void) fclose(fp);
672 	}
673 	if (fd >= 0) {
674 		(void) close(fd);
675 	}
676 	if (cn != NULL) {
677 		free(cn);
678 	}
679 #ifdef	DEBUG
680 	if (ret_val) {
681 		dexit("get_media_info: returning mtype=%s, mnum=%d, spcl=%s\n",
682 		    *mtypep == NULL ? "<null ptr>" : *mtypep,
683 		    *mnump,
684 		    *spclp == NULL ? "<null ptr>" : *spclp);
685 	} else {
686 		dexit("get_media_info: FAILED\n");
687 	}
688 #endif
689 	return (ret_val);
690 }
691 
692 
693 /*
694  * call the appropriate unmount program, returning its success (TRUE)
695  * or failure (FALSE)
696  */
697 static int
698 call_unmount_prog(int mi_gotten, int use_rmm, char *mtype, int mnum,
699     char *spcl, char *bn)
700 {
701 	pid_t		pid;			/* forked proc's pid */
702 	int		ret_val = FALSE;
703 	const char	*etc_umount = "/etc/umount";
704 	const char	*rmm = "/usr/sbin/rmmount";
705 	int		rval;			/* proc's return value */
706 
707 
708 #ifdef	DEBUG
709 	denter(
710 	"call_unmount_prog(%s, %s, \"%s\", %d, \"%s\", \"%s\"): entering\n",
711 	    mi_gotten ? "TRUE" : "FALSE", use_rmm ? "TRUE" : "FALSE",
712 	    mtype ? mtype : "<null ptr>", mnum, spcl ? spcl : "<null ptr>",
713 	    bn);
714 #endif
715 	/* create a child to unmount the path */
716 	if ((pid = fork()) < 0) {
717 #ifdef	DEBUG
718 		dprintf("error in call_unmount_prog: fork failed (errno %d)\n",
719 		    errno);
720 #endif
721 		goto dun;
722 	}
723 
724 	if (pid == 0) {
725 		/* the child */
726 #ifndef	DEBUG
727 		int		xfd;
728 #endif
729 		char		env_buf[MAXPATHLEN];
730 
731 #ifndef	DEBUG
732 		/* get rid of those nasty err messages */
733 		if ((xfd = open(NULL_PATH, O_RDWR)) >= 0) {
734 			(void) dup2(xfd, fileno(stdin));
735 			(void) dup2(xfd, fileno(stdout));
736 			(void) dup2(xfd, fileno(stderr));
737 		}
738 #endif
739 
740 		if (use_rmm) {
741 			/* set up environment vars */
742 			(void) putenv("VOLUME_ACTION=eject");
743 			(void) putenv(strdup(env_buf));
744 			if (mi_gotten) {
745 				(void) sprintf(env_buf,
746 				    "VOLUME_MEDIATYPE=%s", mtype);
747 				(void) putenv(strdup(env_buf));
748 				(void) sprintf(env_buf, "VOLUME_SYMDEV=%s%d",
749 				    mtype, mnum);
750 				(void) putenv(strdup(env_buf));
751 				(void) sprintf(env_buf, "VOLUME_PATH=%s",
752 				    spcl);
753 				(void) putenv(strdup(env_buf));
754 				(void) sprintf(env_buf, "VOLUME_NAME=%s",
755 				    vol_basename(spcl));
756 				(void) putenv(strdup(env_buf));
757 			} else {
758 				(void) sprintf(env_buf, "VOLUME_PATH=%s", bn);
759 				(void) putenv(strdup(env_buf));
760 				(void) sprintf(env_buf, "VOLUME_NAME=%s",
761 				    vol_basename(bn));
762 				(void) putenv(strdup(env_buf));
763 			}
764 #ifdef	DEBUG
765 			dprintf("call_unmount_prog: calling \"%s -D\"\n", rmm);
766 			(void) execl(rmm, rmm, "-D", NULL);
767 #else
768 			(void) execl(rmm, rmm, NULL);
769 #endif
770 		} else {
771 #ifdef	DEBUG
772 			dprintf("call_unmount_prog: calling \"%s %s\"\n",
773 			    etc_umount, mi_gotten ? spcl : bn);
774 #endif
775 			(void) execl(etc_umount, etc_umount,
776 			    mi_gotten ? spcl : bn,
777 			    NULL);
778 		}
779 #ifdef	DEBUG
780 		dprintf("call_unmount_prog: exec failed (errno %d)\n", errno);
781 #endif
782 		exit(-1);
783 		/*NOTREACHED*/
784 	}
785 
786 	/* wait for the umount command to exit */
787 	if (waitpid(pid, &rval, 0) == pid) {
788 		if (WIFEXITED(rval)) {
789 			if (WEXITSTATUS(rval) == 0) {
790 				ret_val = TRUE;	/* success */
791 			}
792 		}
793 	}
794 
795 dun:
796 #ifdef	DEBUG
797 	dexit("call_unmount_prog: returning %s\n", ret_val ? "TRUE" : "FALSE");
798 #endif
799 	return (ret_val);
800 }
801