xref: /titanic_50/usr/src/cmd/eject/eject.c (revision 18c2aff776a775d34a4c9893a4c72e0434d68e36)
1*18c2aff7Sartem /*
2*18c2aff7Sartem  * CDDL HEADER START
3*18c2aff7Sartem  *
4*18c2aff7Sartem  * The contents of this file are subject to the terms of the
5*18c2aff7Sartem  * Common Development and Distribution License (the "License").
6*18c2aff7Sartem  * You may not use this file except in compliance with the License.
7*18c2aff7Sartem  *
8*18c2aff7Sartem  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*18c2aff7Sartem  * or http://www.opensolaris.org/os/licensing.
10*18c2aff7Sartem  * See the License for the specific language governing permissions
11*18c2aff7Sartem  * and limitations under the License.
12*18c2aff7Sartem  *
13*18c2aff7Sartem  * When distributing Covered Code, include this CDDL HEADER in each
14*18c2aff7Sartem  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*18c2aff7Sartem  * If applicable, add the following below this CDDL HEADER, with the
16*18c2aff7Sartem  * fields enclosed by brackets "[]" replaced with your own identifying
17*18c2aff7Sartem  * information: Portions Copyright [yyyy] [name of copyright owner]
18*18c2aff7Sartem  *
19*18c2aff7Sartem  * CDDL HEADER END
20*18c2aff7Sartem  */
21*18c2aff7Sartem /*
22*18c2aff7Sartem  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23*18c2aff7Sartem  * Use is subject to license terms.
24*18c2aff7Sartem  */
25*18c2aff7Sartem 
26*18c2aff7Sartem #pragma ident	"%Z%%M%	%I%	%E% SMI"
27*18c2aff7Sartem 
28*18c2aff7Sartem /*
29*18c2aff7Sartem  * Program to eject one or more pieces of media.
30*18c2aff7Sartem  */
31*18c2aff7Sartem 
32*18c2aff7Sartem #include	<stdio.h>
33*18c2aff7Sartem #include	<stdlib.h>
34*18c2aff7Sartem #include	<string.h>
35*18c2aff7Sartem #include	<sys/types.h>
36*18c2aff7Sartem #include	<sys/stat.h>
37*18c2aff7Sartem #include	<sys/fdio.h>
38*18c2aff7Sartem #include	<sys/dkio.h>
39*18c2aff7Sartem #include	<sys/cdio.h>
40*18c2aff7Sartem #include	<sys/param.h>
41*18c2aff7Sartem #include	<sys/wait.h>
42*18c2aff7Sartem #include	<dirent.h>
43*18c2aff7Sartem #include	<fcntl.h>
44*18c2aff7Sartem #include	<string.h>
45*18c2aff7Sartem #include	<errno.h>
46*18c2aff7Sartem #include	<locale.h>
47*18c2aff7Sartem #include	<libintl.h>
48*18c2aff7Sartem #include	<unistd.h>
49*18c2aff7Sartem #include	<pwd.h>
50*18c2aff7Sartem #include	<volmgt.h>
51*18c2aff7Sartem #include	<sys/mnttab.h>
52*18c2aff7Sartem #include	<signal.h>
53*18c2aff7Sartem 
54*18c2aff7Sartem static char		*prog_name = NULL;
55*18c2aff7Sartem static boolean_t	do_default = B_FALSE;
56*18c2aff7Sartem static boolean_t	do_list = B_FALSE;
57*18c2aff7Sartem static boolean_t	do_closetray = B_FALSE;
58*18c2aff7Sartem static boolean_t 	force_eject = B_FALSE;
59*18c2aff7Sartem static boolean_t	do_query = B_FALSE;
60*18c2aff7Sartem static boolean_t	is_direct = B_FALSE;
61*18c2aff7Sartem 
62*18c2aff7Sartem static int		work(char *, char *);
63*18c2aff7Sartem static void		usage(void);
64*18c2aff7Sartem static int		ejectit(char *);
65*18c2aff7Sartem static boolean_t	query(char *, boolean_t);
66*18c2aff7Sartem static boolean_t	floppy_in_drive(char *, int, boolean_t *);
67*18c2aff7Sartem static boolean_t	display_busy(char *, boolean_t);
68*18c2aff7Sartem static char		*eject_getfullblkname(char *, boolean_t);
69*18c2aff7Sartem extern char		*getfullrawname(char *);
70*18c2aff7Sartem 
71*18c2aff7Sartem /*
72*18c2aff7Sartem  * ON-private libvolmgt routines
73*18c2aff7Sartem  */
74*18c2aff7Sartem int		_dev_mounted(char *path);
75*18c2aff7Sartem int		_dev_unmount(char *path);
76*18c2aff7Sartem char		*_media_oldaliases(char *name);
77*18c2aff7Sartem void		_media_printaliases(void);
78*18c2aff7Sartem 
79*18c2aff7Sartem 
80*18c2aff7Sartem /*
81*18c2aff7Sartem  * Hold over from old eject.
82*18c2aff7Sartem  * returns exit codes:	(KEEP THESE - especially important for query)
83*18c2aff7Sartem  *	0 = -n, -d or eject operation was ok, -q = media in drive
84*18c2aff7Sartem  *	1 = -q only = media not in drive
85*18c2aff7Sartem  *	2 = various parameter errors, etc.
86*18c2aff7Sartem  *	3 = eject ioctl failed
87*18c2aff7Sartem  * New Value (2/94)
88*18c2aff7Sartem  *	4 = eject partially succeeded, but now manually remove media
89*18c2aff7Sartem  */
90*18c2aff7Sartem 
91*18c2aff7Sartem #define	EJECT_OK		0
92*18c2aff7Sartem #define	EJECT_NO_MEDIA		1
93*18c2aff7Sartem #define	EJECT_PARM_ERR		2
94*18c2aff7Sartem #define	EJECT_IOCTL_ERR		3
95*18c2aff7Sartem #define	EJECT_MAN_EJ		4
96*18c2aff7Sartem 
97*18c2aff7Sartem #define	AVAIL_MSG		"%s is available\n"
98*18c2aff7Sartem #define	NOT_AVAIL_MSG		"%s is not available\n"
99*18c2aff7Sartem 
100*18c2aff7Sartem #define	OK_TO_EJECT_MSG		"%s can now be manually ejected\n"
101*18c2aff7Sartem 
102*18c2aff7Sartem #define	FLOPPY_MEDIA_TYPE	"floppy"
103*18c2aff7Sartem #define	CDROM_MEDIA_TYPE	"cdrom"
104*18c2aff7Sartem 
105*18c2aff7Sartem 
106*18c2aff7Sartem int
107*18c2aff7Sartem main(int argc, char **argv)
108*18c2aff7Sartem {
109*18c2aff7Sartem 	int		c;
110*18c2aff7Sartem 	const char	*opts = "dqflnpt";
111*18c2aff7Sartem 	int		excode;
112*18c2aff7Sartem 	int		res;
113*18c2aff7Sartem 	boolean_t	err_seen = B_FALSE;
114*18c2aff7Sartem 	boolean_t	man_eject_seen = B_FALSE;
115*18c2aff7Sartem 	char		*rmmount_opt = NULL;
116*18c2aff7Sartem 
117*18c2aff7Sartem 	(void) setlocale(LC_ALL, "");
118*18c2aff7Sartem 
119*18c2aff7Sartem #if !defined(TEXT_DOMAIN)
120*18c2aff7Sartem #define	TEXT_DOMAIN	"SYS_TEST"
121*18c2aff7Sartem #endif
122*18c2aff7Sartem 
123*18c2aff7Sartem 	(void) textdomain(TEXT_DOMAIN);
124*18c2aff7Sartem 
125*18c2aff7Sartem 	prog_name = argv[0];
126*18c2aff7Sartem 
127*18c2aff7Sartem 	is_direct = (getenv("EJECT_DIRECT") != NULL);
128*18c2aff7Sartem 
129*18c2aff7Sartem 	/* process arguments */
130*18c2aff7Sartem 	while ((c = getopt(argc, argv, opts)) != EOF) {
131*18c2aff7Sartem 		switch (c) {
132*18c2aff7Sartem 		case 'd':
133*18c2aff7Sartem 			do_default = B_TRUE;
134*18c2aff7Sartem 			rmmount_opt = "-d";
135*18c2aff7Sartem 			break;
136*18c2aff7Sartem 		case 'q':
137*18c2aff7Sartem 			do_query = B_TRUE;
138*18c2aff7Sartem 			break;
139*18c2aff7Sartem 		case 'l':
140*18c2aff7Sartem 			do_list = B_TRUE;
141*18c2aff7Sartem 			rmmount_opt = "-l";
142*18c2aff7Sartem 			break;
143*18c2aff7Sartem 		case 'f':
144*18c2aff7Sartem 			force_eject = B_TRUE;
145*18c2aff7Sartem 			break;
146*18c2aff7Sartem 		case 'n':
147*18c2aff7Sartem 		case 'p':
148*18c2aff7Sartem 			/* obsolete options, just ignore */
149*18c2aff7Sartem 			break;
150*18c2aff7Sartem 		case 't':
151*18c2aff7Sartem 			do_closetray = B_TRUE;
152*18c2aff7Sartem 			break;
153*18c2aff7Sartem 		default:
154*18c2aff7Sartem 			usage();
155*18c2aff7Sartem 			exit(EJECT_PARM_ERR);
156*18c2aff7Sartem 		}
157*18c2aff7Sartem 	}
158*18c2aff7Sartem 
159*18c2aff7Sartem 	if (argc == optind) {
160*18c2aff7Sartem 		/* no argument -- use the default */
161*18c2aff7Sartem 		excode = work(NULL, rmmount_opt);
162*18c2aff7Sartem 	} else {
163*18c2aff7Sartem 		/* multiple things to eject */
164*18c2aff7Sartem 		for (; optind < argc; optind++) {
165*18c2aff7Sartem 			res = work(argv[optind], rmmount_opt);
166*18c2aff7Sartem 			if (res == EJECT_MAN_EJ) {
167*18c2aff7Sartem 				man_eject_seen = B_TRUE;
168*18c2aff7Sartem 			} else if (res != EJECT_OK) {
169*18c2aff7Sartem 				err_seen = B_TRUE;
170*18c2aff7Sartem 			}
171*18c2aff7Sartem 		}
172*18c2aff7Sartem 		if (err_seen) {
173*18c2aff7Sartem 			if (!is_direct) {
174*18c2aff7Sartem 				excode = res;
175*18c2aff7Sartem 			} else {
176*18c2aff7Sartem 				excode = EJECT_IOCTL_ERR;
177*18c2aff7Sartem 			}
178*18c2aff7Sartem 		} else if (man_eject_seen) {
179*18c2aff7Sartem 			excode = EJECT_MAN_EJ;
180*18c2aff7Sartem 		} else {
181*18c2aff7Sartem 			excode = EJECT_OK;
182*18c2aff7Sartem 		}
183*18c2aff7Sartem 	}
184*18c2aff7Sartem 
185*18c2aff7Sartem 	return (excode);
186*18c2aff7Sartem }
187*18c2aff7Sartem 
188*18c2aff7Sartem /*
189*18c2aff7Sartem  * the the real work of ejecting (and notifying)
190*18c2aff7Sartem  */
191*18c2aff7Sartem static int
192*18c2aff7Sartem work(char *arg, char *rmmount_opt)
193*18c2aff7Sartem {
194*18c2aff7Sartem 	char 		*name;
195*18c2aff7Sartem 	int		excode = EJECT_OK;
196*18c2aff7Sartem 	struct stat64	sb;
197*18c2aff7Sartem 	char		*arg1, *arg2;
198*18c2aff7Sartem 	pid_t		pid;
199*18c2aff7Sartem 	int		status = 1;
200*18c2aff7Sartem 
201*18c2aff7Sartem 	if (!is_direct) {
202*18c2aff7Sartem 		/* exec rmmount */
203*18c2aff7Sartem 		if (do_closetray) {
204*18c2aff7Sartem 			(void) putenv("EJECT_CLOSETRAY=1");
205*18c2aff7Sartem 		}
206*18c2aff7Sartem 		if (do_query) {
207*18c2aff7Sartem 			(void) putenv("EJECT_QUERY=1");
208*18c2aff7Sartem 		}
209*18c2aff7Sartem 		pid = fork();
210*18c2aff7Sartem 		if (pid < 0) {
211*18c2aff7Sartem 			exit(1);
212*18c2aff7Sartem 		} else if (pid == 0) {
213*18c2aff7Sartem 			/* child */
214*18c2aff7Sartem 			if (rmmount_opt != NULL) {
215*18c2aff7Sartem 				arg1 = rmmount_opt;
216*18c2aff7Sartem 				arg2 = arg;
217*18c2aff7Sartem 			} else {
218*18c2aff7Sartem 				arg1 = arg;
219*18c2aff7Sartem 				arg2 = NULL;
220*18c2aff7Sartem 			}
221*18c2aff7Sartem 
222*18c2aff7Sartem 			if (execl("/usr/bin/rmmount", "eject",
223*18c2aff7Sartem 			    arg1, arg2, 0) < 0) {
224*18c2aff7Sartem 				perror("execl");
225*18c2aff7Sartem 				exit(1);
226*18c2aff7Sartem 			} else {
227*18c2aff7Sartem 				exit(0);
228*18c2aff7Sartem 			}
229*18c2aff7Sartem 		}
230*18c2aff7Sartem 		/* parent */
231*18c2aff7Sartem 		if (waitpid(pid, &status, 0) != pid) {
232*18c2aff7Sartem 			excode = 1;
233*18c2aff7Sartem 		} else if (WIFEXITED(status) && (WEXITSTATUS(status) != 0)) {
234*18c2aff7Sartem 			excode = WEXITSTATUS(status);
235*18c2aff7Sartem 		} else {
236*18c2aff7Sartem 			excode = 0;
237*18c2aff7Sartem 		}
238*18c2aff7Sartem 	}
239*18c2aff7Sartem 
240*18c2aff7Sartem 	/*
241*18c2aff7Sartem 	 * rmmount returns 99 if HAL not running -
242*18c2aff7Sartem 	 * fallback to direct in that case
243*18c2aff7Sartem 	 */
244*18c2aff7Sartem 	if (is_direct || (excode == 99)) {
245*18c2aff7Sartem 		if (arg == NULL) {
246*18c2aff7Sartem 			arg = "floppy";
247*18c2aff7Sartem 		}
248*18c2aff7Sartem 		if ((name = _media_oldaliases(arg)) == NULL) {
249*18c2aff7Sartem 			name = arg;
250*18c2aff7Sartem 		}
251*18c2aff7Sartem 		if (do_default) {
252*18c2aff7Sartem 			(void) printf("%s\n", name);
253*18c2aff7Sartem 			goto out;
254*18c2aff7Sartem 		}
255*18c2aff7Sartem 		if (do_list) {
256*18c2aff7Sartem 			(void) printf("%s\t%s\n", name, arg);
257*18c2aff7Sartem 			goto out;
258*18c2aff7Sartem 		}
259*18c2aff7Sartem 		if (access(name, R_OK) != 0) {
260*18c2aff7Sartem 			if (do_query) {
261*18c2aff7Sartem 				(void) fprintf(stderr,
262*18c2aff7Sartem 				    gettext("%s: no media\n"), name);
263*18c2aff7Sartem 				return (EJECT_NO_MEDIA);
264*18c2aff7Sartem 			} else {
265*18c2aff7Sartem 				perror(name);
266*18c2aff7Sartem 				return (EJECT_PARM_ERR);
267*18c2aff7Sartem 			}
268*18c2aff7Sartem 		}
269*18c2aff7Sartem 
270*18c2aff7Sartem 		if (do_query) {
271*18c2aff7Sartem 			if ((stat64(name, &sb) == 0) && S_ISDIR(sb.st_mode)) {
272*18c2aff7Sartem 				(void) fprintf(stderr,
273*18c2aff7Sartem 				    gettext("%s: no media\n"), name);
274*18c2aff7Sartem 				return (EJECT_NO_MEDIA);
275*18c2aff7Sartem 			}
276*18c2aff7Sartem 			if (!query(name, B_TRUE)) {
277*18c2aff7Sartem 				excode = EJECT_NO_MEDIA;
278*18c2aff7Sartem 			}
279*18c2aff7Sartem 		} else {
280*18c2aff7Sartem 			excode = ejectit(name);
281*18c2aff7Sartem 		}
282*18c2aff7Sartem 	}
283*18c2aff7Sartem out:
284*18c2aff7Sartem 	return (excode);
285*18c2aff7Sartem }
286*18c2aff7Sartem 
287*18c2aff7Sartem 
288*18c2aff7Sartem static void
289*18c2aff7Sartem usage(void)
290*18c2aff7Sartem {
291*18c2aff7Sartem 	(void) fprintf(stderr,
292*18c2aff7Sartem 	    gettext("usage: %s [-fldqt] [name | nickname]\n"),
293*18c2aff7Sartem 	    prog_name);
294*18c2aff7Sartem 	(void) fprintf(stderr,
295*18c2aff7Sartem 	    gettext("options:\t-f force eject\n"));
296*18c2aff7Sartem 	(void) fprintf(stderr,
297*18c2aff7Sartem 	    gettext("\t\t-l list ejectable devices\n"));
298*18c2aff7Sartem 	(void) fprintf(stderr,
299*18c2aff7Sartem 	    gettext("\t\t-d show default device\n"));
300*18c2aff7Sartem 	(void) fprintf(stderr,
301*18c2aff7Sartem 	    gettext("\t\t-q query for media present\n"));
302*18c2aff7Sartem 	(void) fprintf(stderr,
303*18c2aff7Sartem 	    gettext("\t\t-t close tray\n"));
304*18c2aff7Sartem }
305*18c2aff7Sartem 
306*18c2aff7Sartem 
307*18c2aff7Sartem static int
308*18c2aff7Sartem ejectit(char *name)
309*18c2aff7Sartem {
310*18c2aff7Sartem 	int 		fd, r;
311*18c2aff7Sartem 	boolean_t	mejectable = B_FALSE;	/* manually ejectable */
312*18c2aff7Sartem 	int		result = EJECT_OK;
313*18c2aff7Sartem 
314*18c2aff7Sartem 	/*
315*18c2aff7Sartem 	 * If volume management is either not running or not being managed by
316*18c2aff7Sartem 	 * vold, and the device is mounted, we try to umount the device.  If we
317*18c2aff7Sartem 	 * fail, we give up, unless he used the -f flag.
318*18c2aff7Sartem 	 */
319*18c2aff7Sartem 
320*18c2aff7Sartem 	if (_dev_mounted(name)) {
321*18c2aff7Sartem 		r = _dev_unmount(name);
322*18c2aff7Sartem 		if (r == 0) {
323*18c2aff7Sartem 			if (!force_eject) {
324*18c2aff7Sartem 				(void) fprintf(stderr,
325*18c2aff7Sartem gettext("WARNING: can not unmount %s, the file system is (probably) busy\n"),
326*18c2aff7Sartem 				    name);
327*18c2aff7Sartem 				return (EJECT_PARM_ERR);
328*18c2aff7Sartem 			} else {
329*18c2aff7Sartem 				(void) fprintf(stderr,
330*18c2aff7Sartem gettext("WARNING: %s has a mounted filesystem, ejecting anyway\n"),
331*18c2aff7Sartem 				    name);
332*18c2aff7Sartem 			}
333*18c2aff7Sartem 		}
334*18c2aff7Sartem 	}
335*18c2aff7Sartem 
336*18c2aff7Sartem 	/*
337*18c2aff7Sartem 	 * Require O_NDELAY for when floppy is not formatted
338*18c2aff7Sartem 	 * will still id floppy in drive
339*18c2aff7Sartem 	 */
340*18c2aff7Sartem 
341*18c2aff7Sartem 	/*
342*18c2aff7Sartem 	 * make sure we are dealing with a raw device
343*18c2aff7Sartem 	 *
344*18c2aff7Sartem 	 * XXX: NOTE: results from getfullrawname()
345*18c2aff7Sartem 	 * really should be free()d when no longer
346*18c2aff7Sartem 	 * in use
347*18c2aff7Sartem 	 */
348*18c2aff7Sartem 	name = getfullrawname(name);
349*18c2aff7Sartem 
350*18c2aff7Sartem 	if ((fd = open(name, O_RDONLY | O_NDELAY)) < 0) {
351*18c2aff7Sartem 		if (errno == EBUSY) {
352*18c2aff7Sartem 			(void) fprintf(stderr,
353*18c2aff7Sartem gettext("%s is busy (try 'eject floppy' or 'eject cdrom'?)\n"),
354*18c2aff7Sartem 			    name);
355*18c2aff7Sartem 			return (EJECT_PARM_ERR);
356*18c2aff7Sartem 		}
357*18c2aff7Sartem 		perror(name);
358*18c2aff7Sartem 		return (EJECT_PARM_ERR);
359*18c2aff7Sartem 	}
360*18c2aff7Sartem 
361*18c2aff7Sartem 	if (do_closetray) {
362*18c2aff7Sartem 		if (ioctl(fd, CDROMCLOSETRAY) < 0) {
363*18c2aff7Sartem 			result = EJECT_IOCTL_ERR;
364*18c2aff7Sartem 		}
365*18c2aff7Sartem 	} else if (ioctl(fd, DKIOCEJECT, 0) < 0) {
366*18c2aff7Sartem 		/* check on why eject failed */
367*18c2aff7Sartem 
368*18c2aff7Sartem 		/* check for no floppy in manually ejectable drive */
369*18c2aff7Sartem 		if ((errno == ENOSYS) &&
370*18c2aff7Sartem 		    !floppy_in_drive(name, fd, &mejectable)) {
371*18c2aff7Sartem 			/* use code below to handle "not present" */
372*18c2aff7Sartem 			errno = ENXIO;
373*18c2aff7Sartem 		}
374*18c2aff7Sartem 
375*18c2aff7Sartem 		if (errno == ENOSYS || errno == ENOTSUP) {
376*18c2aff7Sartem 			(void) fprintf(stderr, gettext(OK_TO_EJECT_MSG), name);
377*18c2aff7Sartem 		}
378*18c2aff7Sartem 
379*18c2aff7Sartem 		if ((errno == ENOSYS || errno == ENOTSUP) && mejectable) {
380*18c2aff7Sartem 			/*
381*18c2aff7Sartem 			 * keep track of the fact that this is a manual
382*18c2aff7Sartem 			 * ejection
383*18c2aff7Sartem 			 */
384*18c2aff7Sartem 			result = EJECT_MAN_EJ;
385*18c2aff7Sartem 
386*18c2aff7Sartem 		} else if (errno == EBUSY) {
387*18c2aff7Sartem 			/*
388*18c2aff7Sartem 			 * if our pathname is s slice (UFS is great) then
389*18c2aff7Sartem 			 * check to see what really is busy
390*18c2aff7Sartem 			 */
391*18c2aff7Sartem 			if (!display_busy(name, B_FALSE)) {
392*18c2aff7Sartem 				perror(name);
393*18c2aff7Sartem 			}
394*18c2aff7Sartem 			result = EJECT_IOCTL_ERR;
395*18c2aff7Sartem 
396*18c2aff7Sartem 		} else if ((errno == EAGAIN) || (errno == ENODEV) ||
397*18c2aff7Sartem 		    (errno == ENXIO)) {
398*18c2aff7Sartem 			(void) fprintf(stderr,
399*18c2aff7Sartem 			    gettext("%s not present in a drive\n"),
400*18c2aff7Sartem 			    name);
401*18c2aff7Sartem 			result = EJECT_OK;
402*18c2aff7Sartem 		} else {
403*18c2aff7Sartem 			perror(name);
404*18c2aff7Sartem 			result = EJECT_IOCTL_ERR;
405*18c2aff7Sartem 		}
406*18c2aff7Sartem 	}
407*18c2aff7Sartem 
408*18c2aff7Sartem 	(void) close(fd);
409*18c2aff7Sartem 	return (result);
410*18c2aff7Sartem }
411*18c2aff7Sartem 
412*18c2aff7Sartem 
413*18c2aff7Sartem /*
414*18c2aff7Sartem  * return B_TRUE if a floppy is in the drive, B_FALSE otherwise
415*18c2aff7Sartem  *
416*18c2aff7Sartem  * this routine assumes that the file descriptor passed in is for
417*18c2aff7Sartem  * a floppy disk.  this works because it's only called if the device
418*18c2aff7Sartem  * is "manually ejectable", which only (currently) occurs for floppies.
419*18c2aff7Sartem  */
420*18c2aff7Sartem static boolean_t
421*18c2aff7Sartem floppy_in_drive(char *name, int fd, boolean_t *is_floppy)
422*18c2aff7Sartem {
423*18c2aff7Sartem 	int	ival = 0;
424*18c2aff7Sartem 	boolean_t rval = B_FALSE;
425*18c2aff7Sartem 
426*18c2aff7Sartem 
427*18c2aff7Sartem 	if (ioctl(fd, FDGETCHANGE, &ival) >= 0) {
428*18c2aff7Sartem 		if (!(ival & FDGC_CURRENT)) {
429*18c2aff7Sartem 			rval = B_TRUE;
430*18c2aff7Sartem 		}
431*18c2aff7Sartem 		*is_floppy = B_TRUE;
432*18c2aff7Sartem 	} else {
433*18c2aff7Sartem 		*is_floppy = B_FALSE;
434*18c2aff7Sartem 		(void) fprintf(stderr, gettext("%s is not a floppy disk\n"),
435*18c2aff7Sartem 		    name);
436*18c2aff7Sartem 	}
437*18c2aff7Sartem 
438*18c2aff7Sartem 	return (rval);
439*18c2aff7Sartem }
440*18c2aff7Sartem 
441*18c2aff7Sartem 
442*18c2aff7Sartem /*
443*18c2aff7Sartem  * display a "busy" message for the supplied pathname
444*18c2aff7Sartem  *
445*18c2aff7Sartem  * if the pathname is not a slice, then just display a busy message
446*18c2aff7Sartem  * else if the pathname is some slice subdirectory then look for the
447*18c2aff7Sartem  * *real* culprits
448*18c2aff7Sartem  *
449*18c2aff7Sartem  * if this is not done then the user can get a message like
450*18c2aff7Sartem  *	/vol/dev/rdsk/c0t6d0/solaris_2_5_sparc/s5: Device busy
451*18c2aff7Sartem  * when they try to eject "cdrom0", but "s0" (e.g.) may be the only busy
452*18c2aff7Sartem  * slice
453*18c2aff7Sartem  *
454*18c2aff7Sartem  * return B_TRUE iff we printed the appropriate error message, else
455*18c2aff7Sartem  * return B_FALSE (and caller will print error message itself)
456*18c2aff7Sartem  */
457*18c2aff7Sartem static boolean_t
458*18c2aff7Sartem display_busy(char *path, boolean_t vm_running)
459*18c2aff7Sartem {
460*18c2aff7Sartem 	int		errno_save = errno;	/* to save errno */
461*18c2aff7Sartem 	char		*blk;			/* block name */
462*18c2aff7Sartem 	FILE		*fp = NULL;		/* for scanning mnttab */
463*18c2aff7Sartem 	struct mnttab	mref;			/* for scanning mnttab */
464*18c2aff7Sartem 	struct mnttab	mp;			/* for scanning mnttab */
465*18c2aff7Sartem 	boolean_t	res = B_FALSE;		/* return value */
466*18c2aff7Sartem 	char		busy_base[MAXPATHLEN];	/* for keeping base dir name */
467*18c2aff7Sartem 	uint_t		bblen;			/* busy_base string length */
468*18c2aff7Sartem 	char		*cp;			/* for truncating path */
469*18c2aff7Sartem 
470*18c2aff7Sartem 
471*18c2aff7Sartem 
472*18c2aff7Sartem #ifdef	DEBUG
473*18c2aff7Sartem 	(void) fprintf(stderr, "display_busy(\"%s\"): entering\n", path);
474*18c2aff7Sartem #endif
475*18c2aff7Sartem 
476*18c2aff7Sartem 	/*
477*18c2aff7Sartem 	 * get the block pathname.
478*18c2aff7Sartem 	 * eject_getfullblkname returns NULL or pathname which
479*18c2aff7Sartem 	 * has length < MAXPATHLEN.
480*18c2aff7Sartem 	 */
481*18c2aff7Sartem 	blk = eject_getfullblkname(path, vm_running);
482*18c2aff7Sartem 	if (blk == NULL)
483*18c2aff7Sartem 		goto dun;
484*18c2aff7Sartem 
485*18c2aff7Sartem 	/* open mnttab for scanning */
486*18c2aff7Sartem 	if ((fp = fopen(MNTTAB, "r")) == NULL) {
487*18c2aff7Sartem 		/* can't open mnttab!? -- give up */
488*18c2aff7Sartem 		goto dun;
489*18c2aff7Sartem 	}
490*18c2aff7Sartem 
491*18c2aff7Sartem 	(void) memset((void *)&mref, '\0', sizeof (struct mnttab));
492*18c2aff7Sartem 	mref.mnt_special = blk;
493*18c2aff7Sartem 	if (getmntany(fp, &mp, &mref) == 0) {
494*18c2aff7Sartem 		/* we found our entry -- we're done */
495*18c2aff7Sartem 		goto dun;
496*18c2aff7Sartem 	}
497*18c2aff7Sartem 
498*18c2aff7Sartem 	/* perhaps we have a sub-slice (which is what we exist to test for) */
499*18c2aff7Sartem 
500*18c2aff7Sartem 	/* create a base pathname */
501*18c2aff7Sartem 	(void) strcpy(busy_base, blk);
502*18c2aff7Sartem 	if ((cp = strrchr(busy_base, '/')) == NULL) {
503*18c2aff7Sartem 		/* no last slash in pathname!!?? -- give up */
504*18c2aff7Sartem 		goto dun;
505*18c2aff7Sartem 	}
506*18c2aff7Sartem 	*cp = '\0';
507*18c2aff7Sartem 	bblen = strlen(busy_base);
508*18c2aff7Sartem 	/* bblen = (uint)(cp - busy_base); */
509*18c2aff7Sartem 
510*18c2aff7Sartem 	/* scan for matches */
511*18c2aff7Sartem 	rewind(fp);				/* rescan mnttab */
512*18c2aff7Sartem 	while (getmntent(fp, &mp) == 0) {
513*18c2aff7Sartem 		/*
514*18c2aff7Sartem 		 * work around problem where '-' in /etc/mnttab for
515*18c2aff7Sartem 		 * special device turns to NULL which isn't expected
516*18c2aff7Sartem 		 */
517*18c2aff7Sartem 		if (mp.mnt_special == NULL)
518*18c2aff7Sartem 			mp.mnt_special = "-";
519*18c2aff7Sartem 		if (strncmp(busy_base, mp.mnt_special, bblen) == 0) {
520*18c2aff7Sartem 			res = B_TRUE;
521*18c2aff7Sartem 			(void) fprintf(stderr, "%s: %s\n", mp.mnt_special,
522*18c2aff7Sartem 			    strerror(EBUSY));
523*18c2aff7Sartem 		}
524*18c2aff7Sartem 	}
525*18c2aff7Sartem 
526*18c2aff7Sartem dun:
527*18c2aff7Sartem 	if (fp != NULL) {
528*18c2aff7Sartem 		(void) fclose(fp);
529*18c2aff7Sartem 	}
530*18c2aff7Sartem #ifdef	DEBUG
531*18c2aff7Sartem 	(void) fprintf(stderr, "display_busy: returning %s\n",
532*18c2aff7Sartem 	    res ? "B_TRUE" : "B_FALSE");
533*18c2aff7Sartem #endif
534*18c2aff7Sartem 	errno = errno_save;
535*18c2aff7Sartem 	return (res);
536*18c2aff7Sartem }
537*18c2aff7Sartem 
538*18c2aff7Sartem 
539*18c2aff7Sartem /*
540*18c2aff7Sartem  * In my experience with removable media drivers so far... the
541*18c2aff7Sartem  * most reliable way to tell if a piece of media is in a drive
542*18c2aff7Sartem  * is simply to open it.  If the open works, there's something there,
543*18c2aff7Sartem  * if it fails, there's not.  We check for two errnos which we
544*18c2aff7Sartem  * want to interpret for the user,  ENOENT and EPERM.  All other
545*18c2aff7Sartem  * errors are considered to be "media isn't there".
546*18c2aff7Sartem  *
547*18c2aff7Sartem  * return B_TRUE if media found, else B_FALSE (XXX: was 0 and -1)
548*18c2aff7Sartem  */
549*18c2aff7Sartem static boolean_t
550*18c2aff7Sartem query(char *name, boolean_t doprint)
551*18c2aff7Sartem {
552*18c2aff7Sartem 	int		fd;
553*18c2aff7Sartem 	int		rval;			/* FDGETCHANGE return value */
554*18c2aff7Sartem 	enum dkio_state	state;
555*18c2aff7Sartem 
556*18c2aff7Sartem 	if ((fd = open(name, O_RDONLY|O_NONBLOCK)) < 0) {
557*18c2aff7Sartem 		if ((errno == EPERM) || (errno == ENOENT)) {
558*18c2aff7Sartem 			if (doprint) {
559*18c2aff7Sartem 				perror(name);
560*18c2aff7Sartem 			}
561*18c2aff7Sartem 		} else {
562*18c2aff7Sartem 			if (doprint) {
563*18c2aff7Sartem 				(void) fprintf(stderr, gettext(NOT_AVAIL_MSG),
564*18c2aff7Sartem 				    name);
565*18c2aff7Sartem 			}
566*18c2aff7Sartem 		}
567*18c2aff7Sartem 		return (B_FALSE);
568*18c2aff7Sartem 	}
569*18c2aff7Sartem 
570*18c2aff7Sartem 	rval = 0;
571*18c2aff7Sartem 	if (ioctl(fd, FDGETCHANGE, &rval) >= 0) {
572*18c2aff7Sartem 		/* hey, it worked, what a deal, it must be a floppy */
573*18c2aff7Sartem 		(void) close(fd);
574*18c2aff7Sartem 		if (!(rval & FDGC_CURRENT)) {
575*18c2aff7Sartem 			if (doprint) {
576*18c2aff7Sartem 				(void) fprintf(stderr, gettext(AVAIL_MSG),
577*18c2aff7Sartem 				    name);
578*18c2aff7Sartem 			}
579*18c2aff7Sartem 			return (B_TRUE);
580*18c2aff7Sartem 		}
581*18c2aff7Sartem 		if (rval & FDGC_CURRENT) {
582*18c2aff7Sartem 			if (doprint) {
583*18c2aff7Sartem 				(void) fprintf(stderr,	gettext(NOT_AVAIL_MSG),
584*18c2aff7Sartem 				    name);
585*18c2aff7Sartem 			}
586*18c2aff7Sartem 			return (B_FALSE);
587*18c2aff7Sartem 		}
588*18c2aff7Sartem 	}
589*18c2aff7Sartem 
590*18c2aff7Sartem again:
591*18c2aff7Sartem 	state = DKIO_NONE;
592*18c2aff7Sartem 	if (ioctl(fd, DKIOCSTATE, &state) >= 0) {
593*18c2aff7Sartem 		/* great, the fancy ioctl is supported. */
594*18c2aff7Sartem 		if (state == DKIO_INSERTED) {
595*18c2aff7Sartem 			if (doprint) {
596*18c2aff7Sartem 				(void) fprintf(stderr, gettext(AVAIL_MSG),
597*18c2aff7Sartem 				    name);
598*18c2aff7Sartem 			}
599*18c2aff7Sartem 			(void) close(fd);
600*18c2aff7Sartem 			return (B_TRUE);
601*18c2aff7Sartem 		}
602*18c2aff7Sartem 		if (state == DKIO_EJECTED) {
603*18c2aff7Sartem 			if (doprint) {
604*18c2aff7Sartem 				(void) fprintf(stderr,	gettext(NOT_AVAIL_MSG),
605*18c2aff7Sartem 				    name);
606*18c2aff7Sartem 			}
607*18c2aff7Sartem 			(void) close(fd);
608*18c2aff7Sartem 			return (B_FALSE);
609*18c2aff7Sartem 		}
610*18c2aff7Sartem 		/*
611*18c2aff7Sartem 		 * Silly retry loop.
612*18c2aff7Sartem 		 */
613*18c2aff7Sartem 		(void) sleep(1);
614*18c2aff7Sartem 		goto again;
615*18c2aff7Sartem 	}
616*18c2aff7Sartem 	(void) close(fd);
617*18c2aff7Sartem 
618*18c2aff7Sartem 	/*
619*18c2aff7Sartem 	 * Ok, we've tried the non-blocking/ioctl route.  The
620*18c2aff7Sartem 	 * device doesn't support any of our nice ioctls, so
621*18c2aff7Sartem 	 * we'll just say that if it opens it's there, if it
622*18c2aff7Sartem 	 * doesn't, it's not.
623*18c2aff7Sartem 	 */
624*18c2aff7Sartem 	if ((fd = open(name, O_RDONLY)) < 0) {
625*18c2aff7Sartem 		if (doprint) {
626*18c2aff7Sartem 			(void) fprintf(stderr, gettext(NOT_AVAIL_MSG), name);
627*18c2aff7Sartem 		}
628*18c2aff7Sartem 		return (B_FALSE);
629*18c2aff7Sartem 	}
630*18c2aff7Sartem 
631*18c2aff7Sartem 	(void) close(fd);
632*18c2aff7Sartem 	if (doprint) {
633*18c2aff7Sartem 		(void) fprintf(stderr, gettext(AVAIL_MSG), name);
634*18c2aff7Sartem 	}
635*18c2aff7Sartem 	return (B_TRUE);	/* success */
636*18c2aff7Sartem }
637*18c2aff7Sartem 
638*18c2aff7Sartem 
639*18c2aff7Sartem /*
640*18c2aff7Sartem  * this routine will return the volmgt block name given the volmgt
641*18c2aff7Sartem  *  raw (char spcl) name
642*18c2aff7Sartem  *
643*18c2aff7Sartem  * if anything but a volmgt raw pathname is supplied that pathname will
644*18c2aff7Sartem  *  be returned
645*18c2aff7Sartem  *
646*18c2aff7Sartem  * NOTE: non-null return value will point to static data, overwritten with
647*18c2aff7Sartem  *  each call
648*18c2aff7Sartem  *
649*18c2aff7Sartem  * e.g. names starting with "/vol/r" will be changed to start with "/vol/",
650*18c2aff7Sartem  * and names starting with "vol/dev/r" will be changed to start with
651*18c2aff7Sartem  * "/vol/dev/"
652*18c2aff7Sartem  */
653*18c2aff7Sartem static char *
654*18c2aff7Sartem eject_getfullblkname(char *path, boolean_t vm_running)
655*18c2aff7Sartem {
656*18c2aff7Sartem 	char		raw_root[MAXPATHLEN];
657*18c2aff7Sartem 	const char	*vm_root;
658*18c2aff7Sartem 	static char	res_buf[MAXPATHLEN];
659*18c2aff7Sartem 	uint_t		raw_root_len;
660*18c2aff7Sartem 
661*18c2aff7Sartem #ifdef	DEBUG
662*18c2aff7Sartem 	(void) fprintf(stderr, "eject_getfullblkname(\"%s\", %s): entering\n",
663*18c2aff7Sartem 	    path, vm_running ? "B_TRUE" : "B_FALSE");
664*18c2aff7Sartem #endif
665*18c2aff7Sartem 	/*
666*18c2aff7Sartem 	 * try different strategies based on whether or not vold is running
667*18c2aff7Sartem 	 */
668*18c2aff7Sartem 	if (vm_running) {
669*18c2aff7Sartem 
670*18c2aff7Sartem 		/* vold IS running -- look in /vol (or its alternate) */
671*18c2aff7Sartem 
672*18c2aff7Sartem 		/* get vm root dir */
673*18c2aff7Sartem 		vm_root = volmgt_root();
674*18c2aff7Sartem 
675*18c2aff7Sartem 		/* get first volmgt root dev directory (and its length) */
676*18c2aff7Sartem 		(void) snprintf(raw_root, sizeof (raw_root), "%s/r", vm_root);
677*18c2aff7Sartem 		raw_root_len = strlen(raw_root);
678*18c2aff7Sartem 
679*18c2aff7Sartem 		/* see if we have a raw volmgt pathname (e.g. "/vol/r*") */
680*18c2aff7Sartem 		if (strncmp(path, raw_root, raw_root_len) == 0) {
681*18c2aff7Sartem 			if (snprintf(res_buf, sizeof (res_buf), "%s/%s",
682*18c2aff7Sartem 			    vm_root, path + raw_root_len) >= sizeof (res_buf)) {
683*18c2aff7Sartem 				return (NULL);
684*18c2aff7Sartem 			}
685*18c2aff7Sartem 			goto dun;		/* found match in /vol */
686*18c2aff7Sartem 		}
687*18c2aff7Sartem 
688*18c2aff7Sartem 		/* get second volmgt root dev directory (and its length) */
689*18c2aff7Sartem 		(void) snprintf(raw_root, sizeof (raw_root),
690*18c2aff7Sartem 		    "%s/dev/r", vm_root);
691*18c2aff7Sartem 		raw_root_len = strlen(raw_root);
692*18c2aff7Sartem 
693*18c2aff7Sartem 		/* see if we have a raw volmgt pathname (e.g. "/vol/dev/r*") */
694*18c2aff7Sartem 		if (strncmp(path, raw_root, raw_root_len) == 0) {
695*18c2aff7Sartem 			if (snprintf(res_buf, sizeof (res_buf), "%s/dev/%s",
696*18c2aff7Sartem 			    vm_root, path + raw_root_len) >= sizeof (res_buf)) {
697*18c2aff7Sartem 				return (NULL);
698*18c2aff7Sartem 			}
699*18c2aff7Sartem 			goto dun;		/* found match in /vol/dev */
700*18c2aff7Sartem 		}
701*18c2aff7Sartem 
702*18c2aff7Sartem 	} else {
703*18c2aff7Sartem 
704*18c2aff7Sartem 		/* vold is NOT running -- look in /dev */
705*18c2aff7Sartem 
706*18c2aff7Sartem 		(void) strcpy(raw_root, "/dev/r");
707*18c2aff7Sartem 		raw_root_len = strlen(raw_root);
708*18c2aff7Sartem 		if (strncmp(path, raw_root, raw_root_len) == 0) {
709*18c2aff7Sartem 			if (snprintf(res_buf, sizeof (res_buf), "/dev/%s",
710*18c2aff7Sartem 			    path + raw_root_len) >= sizeof (res_buf)) {
711*18c2aff7Sartem 				return (NULL);
712*18c2aff7Sartem 			}
713*18c2aff7Sartem 			goto dun;		/* found match in /dev */
714*18c2aff7Sartem 		}
715*18c2aff7Sartem 	}
716*18c2aff7Sartem 
717*18c2aff7Sartem 	/* no match -- return what we got */
718*18c2aff7Sartem 	(void) strcpy(res_buf, path);
719*18c2aff7Sartem 
720*18c2aff7Sartem dun:
721*18c2aff7Sartem #ifdef	DEBUG
722*18c2aff7Sartem 	(void) fprintf(stderr, "eject_getfullblkname: returning %s\n",
723*18c2aff7Sartem 	    res_buf ? res_buf : "<null ptr>");
724*18c2aff7Sartem #endif
725*18c2aff7Sartem 	return (res_buf);
726*18c2aff7Sartem }
727