xref: /titanic_54/usr/src/cmd/rmvolmgr/vold.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  * Vold compatibility for rmvolmgr: emulate old commands as well as
30*18c2aff7Sartem  * action_filemgr.so to notify legacy apps via /tmp/.removable pipes.
31*18c2aff7Sartem  * A lot of this code is copied verbatim from vold sources.
32*18c2aff7Sartem  *
33*18c2aff7Sartem  * Here's the original description of action_filemgr.so:
34*18c2aff7Sartem  *
35*18c2aff7Sartem  * action_filemgr.so - filemgr interface routines for rmmount
36*18c2aff7Sartem  *
37*18c2aff7Sartem  * This shared object allows rmmount to communicate with filemgr.
38*18c2aff7Sartem  * This is done by communicating over a named pipe that filemgr
39*18c2aff7Sartem  * creates in directory NOTIFY_DIR.  The name of the pipe must
40*18c2aff7Sartem  * begin with NOTIFY_NAME.  This source file contains #define
41*18c2aff7Sartem  * compiler directives set the values of NOTIFY_DIR and NOTIFY_NAME.
42*18c2aff7Sartem  *
43*18c2aff7Sartem  * After a partition on a medium has been mounted as a result of
44*18c2aff7Sartem  * either insertion or remounting of the medium, the action()
45*18c2aff7Sartem  * method creates a file named with the symbolic name of the
46*18c2aff7Sartem  * device in which the medium is inserted and the partition name
47*18c2aff7Sartem  * (e.g. "jaz0-s2") in NOTIFY_DIR.  The file consists of one text
48*18c2aff7Sartem  * line containing a string naming the mount point of the partition,
49*18c2aff7Sartem  * a string giving the raw device path to the partition, and a
50*18c2aff7Sartem  * string naming the file system type on the partition.  The action()
51*18c2aff7Sartem  * method then sends a single character ('i' for insertion, 'r' for
52*18c2aff7Sartem  * remounting) through the named pipe NOTIFY_NAME to tell filemgr to
53*18c2aff7Sartem  * look for new files in NOTIFY_DIR.
54*18c2aff7Sartem  *
55*18c2aff7Sartem  * If a medium containing no mountable partitions is inserted
56*18c2aff7Sartem  * or remounted in a device, the action() method creates a file
57*18c2aff7Sartem  * named with the symbolic name of the device in NOTIFY_DIR.
58*18c2aff7Sartem  * The file consists of one text line containing a string
59*18c2aff7Sartem  * giving the symbolic name of the device and a string naming
60*18c2aff7Sartem  * the reason that the medium couldn't be mounted.  The action
61*18c2aff7Sartem  * method then sends either an 'i' or an 'r' through the named
62*18c2aff7Sartem  * pipe to tell filemgr to look for new files in NOTIFY_DIR.
63*18c2aff7Sartem  *
64*18c2aff7Sartem  * When a medium is ejected or unmounted, the action() method
65*18c2aff7Sartem  * removes the files that were created in NOTIFY_DIR when the medium
66*18c2aff7Sartem  * was inserted or remounted and sends a single character ('e' for
67*18c2aff7Sartem  * ejection, 'u' for unmounting) through the named pipe.
68*18c2aff7Sartem  *
69*18c2aff7Sartem  * The following environment variables must be set before calling action():
70*18c2aff7Sartem  *
71*18c2aff7Sartem  *	VOLUME_ACTION		action that occurred (e.g. "insert", "eject")
72*18c2aff7Sartem  *	VOLUME_SYMDEV		symbolic name (e.g. "cdrom0", "floppy1")
73*18c2aff7Sartem  *	VOLUME_NAME		volume name (e.g. "unnamed_cdrom", "s2")
74*18c2aff7Sartem  */
75*18c2aff7Sartem 
76*18c2aff7Sartem 
77*18c2aff7Sartem #include <stdio.h>
78*18c2aff7Sartem #include <stdlib.h>
79*18c2aff7Sartem #include <unistd.h>
80*18c2aff7Sartem #include <fcntl.h>
81*18c2aff7Sartem #include <string.h>
82*18c2aff7Sartem #include <strings.h>
83*18c2aff7Sartem #include <dirent.h>
84*18c2aff7Sartem #include <signal.h>
85*18c2aff7Sartem #include <errno.h>
86*18c2aff7Sartem #include <libintl.h>
87*18c2aff7Sartem #include <zone.h>
88*18c2aff7Sartem #include <pwd.h>
89*18c2aff7Sartem #include <sys/types.h>
90*18c2aff7Sartem #include <sys/stat.h>
91*18c2aff7Sartem #include <sys/dkio.h>
92*18c2aff7Sartem #include <sys/cdio.h>
93*18c2aff7Sartem #include <sys/vtoc.h>
94*18c2aff7Sartem #include <sys/param.h>
95*18c2aff7Sartem #include <sys/wait.h>
96*18c2aff7Sartem #include <libcontract.h>
97*18c2aff7Sartem #include <sys/contract/process.h>
98*18c2aff7Sartem #include <sys/ctfs.h>
99*18c2aff7Sartem #include <tsol/label.h>
100*18c2aff7Sartem 
101*18c2aff7Sartem #include "vold.h"
102*18c2aff7Sartem #include "rmm_common.h"
103*18c2aff7Sartem 
104*18c2aff7Sartem int		rmm_debug = 0;
105*18c2aff7Sartem boolean_t	rmm_vold_actions_enabled = B_FALSE;
106*18c2aff7Sartem boolean_t	rmm_vold_mountpoints_enabled = B_FALSE;
107*18c2aff7Sartem 
108*18c2aff7Sartem static char	*prog_name = NULL;
109*18c2aff7Sartem static pid_t	prog_pid = 0;
110*18c2aff7Sartem static int	system_labeled = 0;
111*18c2aff7Sartem static uid_t	mnt_uid = -1;
112*18c2aff7Sartem static gid_t	mnt_gid = -1;
113*18c2aff7Sartem static zoneid_t	mnt_zoneid = -1;
114*18c2aff7Sartem static char	mnt_zoneroot[MAXPATHLEN];
115*18c2aff7Sartem static char	mnt_userdir[MAXPATHLEN];
116*18c2aff7Sartem 
117*18c2aff7Sartem /*
118*18c2aff7Sartem  * Private attribute types and attributes.
119*18c2aff7Sartem  */
120*18c2aff7Sartem static const char notify_characters[] = {
121*18c2aff7Sartem 	'e',
122*18c2aff7Sartem 	'i',
123*18c2aff7Sartem 	'r',
124*18c2aff7Sartem 	'u'
125*18c2aff7Sartem };
126*18c2aff7Sartem 
127*18c2aff7Sartem static const char *result_strings[] = {
128*18c2aff7Sartem 	"FALSE",
129*18c2aff7Sartem 	"TRUE"
130*18c2aff7Sartem };
131*18c2aff7Sartem 
132*18c2aff7Sartem #define	NOTIFY_DIR	"/tmp/.removable"	/* dir where filemgr looks */
133*18c2aff7Sartem #define	NOTIFY_NAME	"notify"		/* named pipe to talk over */
134*18c2aff7Sartem 
135*18c2aff7Sartem static void	volrmmount_usage();
136*18c2aff7Sartem static void	volcheck_usage();
137*18c2aff7Sartem static int	vold_action(struct action_arg *aap);
138*18c2aff7Sartem static void	vold_update_mountpoints(struct action_arg *aap);
139*18c2aff7Sartem static char	*not_mountable(struct action_arg *aa);
140*18c2aff7Sartem static int	create_one_notify_file(char *fstype,
141*18c2aff7Sartem 				char *mount_point,
142*18c2aff7Sartem 				char *notify_file,
143*18c2aff7Sartem 				char *raw_partitionp,
144*18c2aff7Sartem 				char *reason,
145*18c2aff7Sartem 				char *symdev);
146*18c2aff7Sartem static int	create_notify_files(struct action_arg **aa);
147*18c2aff7Sartem static boolean_t notify_clients(action_t action, int do_notify);
148*18c2aff7Sartem static void	popdir(int fd);
149*18c2aff7Sartem static int	pushdir(const char *dir);
150*18c2aff7Sartem static boolean_t remove_notify_files(struct action_arg **aa);
151*18c2aff7Sartem 
152*18c2aff7Sartem /*
153*18c2aff7Sartem  * should be called once from main()
154*18c2aff7Sartem  */
155*18c2aff7Sartem /* ARGSUSED */
156*18c2aff7Sartem void
157*18c2aff7Sartem vold_init(int argc, char **argv)
158*18c2aff7Sartem {
159*18c2aff7Sartem 	system_labeled = is_system_labeled();
160*18c2aff7Sartem }
161*18c2aff7Sartem 
162*18c2aff7Sartem /*
163*18c2aff7Sartem  * Old version of rmmount(1M)
164*18c2aff7Sartem  */
165*18c2aff7Sartem /* ARGSUSED */
166*18c2aff7Sartem int
167*18c2aff7Sartem vold_rmmount(int argc, char **argv)
168*18c2aff7Sartem {
169*18c2aff7Sartem 	char		*volume_action;
170*18c2aff7Sartem 	char		*volume_mediatype;
171*18c2aff7Sartem 	char		*volume_mount_mode;
172*18c2aff7Sartem 	char		*volume_name;
173*18c2aff7Sartem 	char		*volume_path;
174*18c2aff7Sartem 	char		*volume_pcfs_id;
175*18c2aff7Sartem 	char		*volume_symdev;
176*18c2aff7Sartem 	char		*volume_zonename;
177*18c2aff7Sartem 	char		*volume_user;
178*18c2aff7Sartem 	action_t	action;
179*18c2aff7Sartem 	char		mountpoint[MAXPATHLEN];
180*18c2aff7Sartem 	char		*zonemountpoint;
181*18c2aff7Sartem 	char		*arg_mountpoint = NULL;
182*18c2aff7Sartem 	LibHalContext	*hal_ctx;
183*18c2aff7Sartem 	DBusError	error;
184*18c2aff7Sartem 	rmm_error_t	rmm_error;
185*18c2aff7Sartem 	int		ret;
186*18c2aff7Sartem 
187*18c2aff7Sartem 	prog_name = argv[0];
188*18c2aff7Sartem 	prog_pid = getpid();
189*18c2aff7Sartem 
190*18c2aff7Sartem 	mnt_zoneroot[0] = '\0';
191*18c2aff7Sartem 	mnt_userdir[0] = '\0';
192*18c2aff7Sartem 
193*18c2aff7Sartem 	volume_action = getenv("VOLUME_ACTION");
194*18c2aff7Sartem 	volume_mediatype = getenv("VOLUME_MEDIATYPE");
195*18c2aff7Sartem 	volume_mount_mode = getenv("VOLUME_MOUNT_MODE");
196*18c2aff7Sartem 	volume_name = getenv("VOLUME_NAME");
197*18c2aff7Sartem 	volume_path = getenv("VOLUME_PATH");
198*18c2aff7Sartem 	volume_pcfs_id = getenv("VOLUME_PCFS_ID");
199*18c2aff7Sartem 	volume_symdev = getenv("VOLUME_SYMDEV");
200*18c2aff7Sartem 
201*18c2aff7Sartem 	if (system_labeled) {
202*18c2aff7Sartem 		volume_zonename = getenv("VOLUME_ZONE_NAME");
203*18c2aff7Sartem 		volume_user = getenv("VOLUME_USER");
204*18c2aff7Sartem 	}
205*18c2aff7Sartem 	if (volume_action == NULL) {
206*18c2aff7Sartem 		dprintf("%s(%ld): VOLUME_ACTION was null!!\n",
207*18c2aff7Sartem 		    prog_name, prog_pid);
208*18c2aff7Sartem 		return (-1);
209*18c2aff7Sartem 	}
210*18c2aff7Sartem 	if (volume_mediatype == NULL) {
211*18c2aff7Sartem 		dprintf("%s(%ld): VOLUME_MEDIATYPE was null!!\n",
212*18c2aff7Sartem 		    prog_name, prog_pid);
213*18c2aff7Sartem 		return (-1);
214*18c2aff7Sartem 	}
215*18c2aff7Sartem 	if (volume_mount_mode == NULL) {
216*18c2aff7Sartem 		volume_mount_mode = "rw";
217*18c2aff7Sartem 	}
218*18c2aff7Sartem 	if (volume_name == NULL) {
219*18c2aff7Sartem 		dprintf("%s(%ld): VOLUME_NAME was null!!\n",
220*18c2aff7Sartem 		    prog_name, prog_pid);
221*18c2aff7Sartem 		return (-1);
222*18c2aff7Sartem 	}
223*18c2aff7Sartem 	if (volume_path == NULL) {
224*18c2aff7Sartem 		dprintf("%s(%ld): VOLUME_PATH was null!!\n",
225*18c2aff7Sartem 		    prog_name, prog_pid);
226*18c2aff7Sartem 		return (-1);
227*18c2aff7Sartem 	}
228*18c2aff7Sartem 	if (volume_pcfs_id == NULL) {
229*18c2aff7Sartem 		volume_pcfs_id = "";
230*18c2aff7Sartem 	}
231*18c2aff7Sartem 	if (volume_symdev == NULL) {
232*18c2aff7Sartem 		dprintf("%s(%ld): VOLUME_SYMDEV was null!!\n",
233*18c2aff7Sartem 		    prog_name, prog_pid);
234*18c2aff7Sartem 		return (-1);
235*18c2aff7Sartem 	}
236*18c2aff7Sartem 
237*18c2aff7Sartem 	if (system_labeled) {
238*18c2aff7Sartem 		if (volume_zonename != NULL &&
239*18c2aff7Sartem 		    strcmp(volume_zonename, GLOBAL_ZONENAME) != 0) {
240*18c2aff7Sartem 			if ((mnt_zoneid =
241*18c2aff7Sartem 			    getzoneidbyname(volume_zonename)) != -1) {
242*18c2aff7Sartem 				if (zone_getattr(mnt_zoneid, ZONE_ATTR_ROOT,
243*18c2aff7Sartem 				    mnt_zoneroot, MAXPATHLEN) == -1) {
244*18c2aff7Sartem 					dprintf("%s(%ld): NO ZONEPATH!!\n",
245*18c2aff7Sartem 					    prog_name, prog_pid);
246*18c2aff7Sartem 					return (-1);
247*18c2aff7Sartem 				}
248*18c2aff7Sartem 			}
249*18c2aff7Sartem 		} else {
250*18c2aff7Sartem 			mnt_zoneid = GLOBAL_ZONEID;
251*18c2aff7Sartem 			mnt_zoneroot[0] = '\0';
252*18c2aff7Sartem 		}
253*18c2aff7Sartem 		if (volume_user != NULL) {
254*18c2aff7Sartem 			struct passwd	 *pw;
255*18c2aff7Sartem 
256*18c2aff7Sartem 			if ((pw = getpwnam(volume_user)) == NULL) {
257*18c2aff7Sartem 				dprintf("%s(%ld) %s\n", prog_name, prog_pid,
258*18c2aff7Sartem 				    ": VOLUME_USER was not a valid user!");
259*18c2aff7Sartem 				return (-1);
260*18c2aff7Sartem 			}
261*18c2aff7Sartem 			mnt_uid = pw->pw_uid;
262*18c2aff7Sartem 			mnt_gid = pw->pw_gid;
263*18c2aff7Sartem 
264*18c2aff7Sartem 			if (snprintf(mnt_userdir, sizeof (mnt_userdir),
265*18c2aff7Sartem 			    "/%s-%s", volume_user, volume_symdev) >=
266*18c2aff7Sartem 			    sizeof (mnt_userdir))
267*18c2aff7Sartem 				return (-1);
268*18c2aff7Sartem 		} else {
269*18c2aff7Sartem 			mnt_uid = 0;
270*18c2aff7Sartem 			mnt_userdir[0] = '\0';
271*18c2aff7Sartem 		}
272*18c2aff7Sartem 
273*18c2aff7Sartem 		rmm_vold_mountpoints_enabled = B_FALSE;
274*18c2aff7Sartem 		rmm_vold_actions_enabled = B_TRUE;
275*18c2aff7Sartem 	} else {
276*18c2aff7Sartem 		rmm_vold_mountpoints_enabled = B_TRUE;
277*18c2aff7Sartem 		rmm_vold_actions_enabled = B_TRUE;
278*18c2aff7Sartem 	}
279*18c2aff7Sartem 
280*18c2aff7Sartem 	if ((hal_ctx = rmm_hal_init(0, 0, 0, &error, &rmm_error)) == NULL) {
281*18c2aff7Sartem 		rmm_dbus_error_free(&error);
282*18c2aff7Sartem 
283*18c2aff7Sartem 		/* if HAL's not running, must be root */
284*18c2aff7Sartem 		if (geteuid() != 0) {
285*18c2aff7Sartem 			(void) fprintf(stderr,
286*18c2aff7Sartem 			    gettext("%s(%ld) error: must be root to execute\n"),
287*18c2aff7Sartem 			    prog_name, prog_pid);
288*18c2aff7Sartem 			return (-1);
289*18c2aff7Sartem 		}
290*18c2aff7Sartem 	}
291*18c2aff7Sartem 
292*18c2aff7Sartem 	if (strcmp(volume_action, "eject") == 0) {
293*18c2aff7Sartem 		action = EJECT;
294*18c2aff7Sartem 	} else if (strcmp(volume_action, "insert") == 0) {
295*18c2aff7Sartem 		action = INSERT;
296*18c2aff7Sartem 
297*18c2aff7Sartem 		if (system_labeled) {
298*18c2aff7Sartem 			/*
299*18c2aff7Sartem 			 * create mount point
300*18c2aff7Sartem 			 */
301*18c2aff7Sartem 			if (strlen(mnt_userdir) > 0) {
302*18c2aff7Sartem 				if (snprintf(mountpoint, MAXPATHLEN,
303*18c2aff7Sartem 				    "%s/%s%s", mnt_zoneroot, volume_mediatype,
304*18c2aff7Sartem 				    mnt_userdir) > MAXPATHLEN) {
305*18c2aff7Sartem 					return (-1);
306*18c2aff7Sartem 
307*18c2aff7Sartem 				}
308*18c2aff7Sartem 				(void) makepath(mountpoint, 0700);
309*18c2aff7Sartem 				(void) chown(mountpoint, mnt_uid, mnt_gid);
310*18c2aff7Sartem 				/*
311*18c2aff7Sartem 				 * set the top level directory bits to 0755
312*18c2aff7Sartem 				 * so user can access it.
313*18c2aff7Sartem 				 */
314*18c2aff7Sartem 				if (snprintf(mountpoint, MAXPATHLEN,
315*18c2aff7Sartem 				    "%s/%s", mnt_zoneroot,
316*18c2aff7Sartem 				    volume_mediatype) <= MAXPATHLEN) {
317*18c2aff7Sartem 					(void) chmod(mountpoint, 0755);
318*18c2aff7Sartem 				}
319*18c2aff7Sartem 			}
320*18c2aff7Sartem 			if (snprintf(mountpoint, MAXPATHLEN,
321*18c2aff7Sartem 			    "%s/%s%s/%s", mnt_zoneroot, volume_mediatype,
322*18c2aff7Sartem 			    mnt_userdir, volume_name) > MAXPATHLEN) {
323*18c2aff7Sartem 				(void) fprintf(stderr,
324*18c2aff7Sartem 				    gettext("%s(%ld) error: path too long\n"),
325*18c2aff7Sartem 				    prog_name, prog_pid);
326*18c2aff7Sartem 				return (-1);
327*18c2aff7Sartem 			}
328*18c2aff7Sartem 
329*18c2aff7Sartem 			/* make our mountpoint */
330*18c2aff7Sartem 			(void) makepath(mountpoint, 0755);
331*18c2aff7Sartem 
332*18c2aff7Sartem 			arg_mountpoint = mountpoint;
333*18c2aff7Sartem 		}
334*18c2aff7Sartem 	} else if (strcmp(volume_action, "remount") == 0) {
335*18c2aff7Sartem 		action = REMOUNT;
336*18c2aff7Sartem 	} else if (strcmp(volume_action, "unmount") == 0) {
337*18c2aff7Sartem 		action = UNMOUNT;
338*18c2aff7Sartem 	}
339*18c2aff7Sartem 
340*18c2aff7Sartem 	ret = rmm_action(hal_ctx, volume_symdev, action, 0, 0, 0,
341*18c2aff7Sartem 	    arg_mountpoint) ? 0 : 1;
342*18c2aff7Sartem 
343*18c2aff7Sartem 	if (hal_ctx != NULL) {
344*18c2aff7Sartem 		rmm_hal_fini(hal_ctx);
345*18c2aff7Sartem 	}
346*18c2aff7Sartem 
347*18c2aff7Sartem 	return (ret);
348*18c2aff7Sartem }
349*18c2aff7Sartem 
350*18c2aff7Sartem 
351*18c2aff7Sartem /*
352*18c2aff7Sartem  * this should be called after rmm_hal_{mount,unmount,eject}
353*18c2aff7Sartem  */
354*18c2aff7Sartem int
355*18c2aff7Sartem vold_postprocess(LibHalContext *hal_ctx, const char *udi,
356*18c2aff7Sartem     struct action_arg *aap)
357*18c2aff7Sartem {
358*18c2aff7Sartem 	int	ret = 0;
359*18c2aff7Sartem 
360*18c2aff7Sartem 	/* valid mountpoint required */
361*18c2aff7Sartem 	if ((aap->aa_action == INSERT) || (aap->aa_action == REMOUNT)) {
362*18c2aff7Sartem 		rmm_volume_aa_update_mountpoint(hal_ctx, udi, aap);
363*18c2aff7Sartem 		if ((aap->aa_mountpoint == NULL) ||
364*18c2aff7Sartem 		    (strlen(aap->aa_mountpoint) == 0)) {
365*18c2aff7Sartem 			return (1);
366*18c2aff7Sartem 		}
367*18c2aff7Sartem 	}
368*18c2aff7Sartem 
369*18c2aff7Sartem 	if (rmm_vold_mountpoints_enabled) {
370*18c2aff7Sartem 		vold_update_mountpoints(aap);
371*18c2aff7Sartem 	}
372*18c2aff7Sartem 	if (rmm_vold_actions_enabled) {
373*18c2aff7Sartem 		ret = vold_action(aap);
374*18c2aff7Sartem 	}
375*18c2aff7Sartem 
376*18c2aff7Sartem 	return (ret);
377*18c2aff7Sartem }
378*18c2aff7Sartem 
379*18c2aff7Sartem /*
380*18c2aff7Sartem  * update legacy symlinks
381*18c2aff7Sartem  *
382*18c2aff7Sartem  * For cdrom:
383*18c2aff7Sartem  *
384*18c2aff7Sartem  *	/cdrom/<name> -> original mountpoint
385*18c2aff7Sartem  *	/cdrom/cdrom0 -> ./<name>
386*18c2aff7Sartem  *	/cdrom/cdrom -> cdrom0  (only for cdrom0)
387*18c2aff7Sartem  *
388*18c2aff7Sartem  * If it's a slice or partition, /cdrom/<name> becomes a directory:
389*18c2aff7Sartem  *
390*18c2aff7Sartem  *	/cdrom/<name>/s0
391*18c2aff7Sartem  *
392*18c2aff7Sartem  * Same for rmdisk and floppy.
393*18c2aff7Sartem  *
394*18c2aff7Sartem  * On labeled system (Trusted Solaris), links are in a user directory.
395*18c2aff7Sartem  */
396*18c2aff7Sartem static void
397*18c2aff7Sartem vold_update_mountpoints(struct action_arg *aap)
398*18c2aff7Sartem {
399*18c2aff7Sartem 	boolean_t	is_partition;
400*18c2aff7Sartem 	char		part_dir[2 * MAXNAMELEN];
401*18c2aff7Sartem 	char		symname_mp[2 * MAXNAMELEN];
402*18c2aff7Sartem 	char		symcontents_mp[MAXNAMELEN];
403*18c2aff7Sartem 	char		symname[2 * MAXNAMELEN];
404*18c2aff7Sartem 	char		symcontents[MAXNAMELEN];
405*18c2aff7Sartem 
406*18c2aff7Sartem 	is_partition = (aap->aa_partname != NULL);
407*18c2aff7Sartem 
408*18c2aff7Sartem 	if (!system_labeled) {
409*18c2aff7Sartem 		if (!is_partition) {
410*18c2aff7Sartem 			/* /cdrom/<name> -> original mountpoint */
411*18c2aff7Sartem 			(void) snprintf(symcontents_mp, sizeof (symcontents_mp),
412*18c2aff7Sartem 			    "%s", aap->aa_mountpoint);
413*18c2aff7Sartem 			(void) snprintf(symname_mp, sizeof (symname_mp),
414*18c2aff7Sartem 			    "/%s/%s", aap->aa_media, aap->aa_name);
415*18c2aff7Sartem 		} else {
416*18c2aff7Sartem 			/* /cdrom/<name>/slice -> original mountpoint */
417*18c2aff7Sartem 			(void) snprintf(part_dir, sizeof (part_dir),
418*18c2aff7Sartem 			    "/%s/%s", aap->aa_media, aap->aa_name);
419*18c2aff7Sartem 			(void) snprintf(symcontents_mp, sizeof (symcontents_mp),
420*18c2aff7Sartem 			    "%s", aap->aa_mountpoint);
421*18c2aff7Sartem 			(void) snprintf(symname_mp, sizeof (symname_mp),
422*18c2aff7Sartem 			    "/%s/%s/%s", aap->aa_media, aap->aa_name,
423*18c2aff7Sartem 			    aap->aa_partname);
424*18c2aff7Sartem 
425*18c2aff7Sartem 		}
426*18c2aff7Sartem 		/* /cdrom/cdrom0 -> ./<name> */
427*18c2aff7Sartem 		(void) snprintf(symcontents, sizeof (symcontents),
428*18c2aff7Sartem 		    "./%s", aap->aa_name);
429*18c2aff7Sartem 		(void) snprintf(symname, sizeof (symname),
430*18c2aff7Sartem 		    "/%s/%s", aap->aa_media, aap->aa_symdev);
431*18c2aff7Sartem 	} else {
432*18c2aff7Sartem 		if (!is_partition) {
433*18c2aff7Sartem 			/* /cdrom/<user>/<name> -> original mountpoint */
434*18c2aff7Sartem 			(void) snprintf(symcontents_mp, sizeof (symcontents_mp),
435*18c2aff7Sartem 			    "%s", aap->aa_mountpoint);
436*18c2aff7Sartem 			(void) snprintf(symname_mp, sizeof (symname_mp),
437*18c2aff7Sartem 			    "%s/%s/%s", mnt_zoneroot, aap->aa_media,
438*18c2aff7Sartem 			    aap->aa_symdev);
439*18c2aff7Sartem 		} else {
440*18c2aff7Sartem 			/* /cdrom/<user>/<name>/slice -> original mountpoint */
441*18c2aff7Sartem 			(void) snprintf(symcontents_mp, sizeof (symcontents_mp),
442*18c2aff7Sartem 			    "%s", aap->aa_mountpoint);
443*18c2aff7Sartem 			(void) snprintf(symname_mp, sizeof (symname_mp),
444*18c2aff7Sartem 			    "%s/%s/%s", mnt_zoneroot, aap->aa_media,
445*18c2aff7Sartem 			    aap->aa_symdev, aap->aa_partname);
446*18c2aff7Sartem 		}
447*18c2aff7Sartem 
448*18c2aff7Sartem 		/* /cdrom/<user>/cdrom0 -> ./<user>/<name> */
449*18c2aff7Sartem 		(void) snprintf(symcontents, sizeof (symcontents),
450*18c2aff7Sartem 		    ".%s/%s", mnt_userdir, aap->aa_name);
451*18c2aff7Sartem 		(void) snprintf(symname, sizeof (symname), "%s/%s/%s",
452*18c2aff7Sartem 		    mnt_zoneroot, aap->aa_media, aap->aa_symdev);
453*18c2aff7Sartem 	}
454*18c2aff7Sartem 
455*18c2aff7Sartem 	(void) unlink(symname);
456*18c2aff7Sartem 	(void) unlink(symname_mp);
457*18c2aff7Sartem 	if (is_partition) {
458*18c2aff7Sartem 		(void) rmdir(part_dir);
459*18c2aff7Sartem 	}
460*18c2aff7Sartem 
461*18c2aff7Sartem 	if ((aap->aa_action == INSERT) || (aap->aa_action == REMOUNT)) {
462*18c2aff7Sartem 		(void) mkdir(aap->aa_media, 0755);
463*18c2aff7Sartem 		if (is_partition) {
464*18c2aff7Sartem 			(void) mkdir(part_dir, 0755);
465*18c2aff7Sartem 		}
466*18c2aff7Sartem 		(void) symlink(symcontents_mp, symname_mp);
467*18c2aff7Sartem 		(void) symlink(symcontents, symname);
468*18c2aff7Sartem 	}
469*18c2aff7Sartem }
470*18c2aff7Sartem 
471*18c2aff7Sartem 
472*18c2aff7Sartem static int
473*18c2aff7Sartem vold_action(struct action_arg *aap)
474*18c2aff7Sartem {
475*18c2aff7Sartem 	action_t	action;
476*18c2aff7Sartem 	int		result;
477*18c2aff7Sartem 	int		do_notify = FALSE;
478*18c2aff7Sartem 	action_t	notify_act = EJECT;
479*18c2aff7Sartem 	struct action_arg *aa[2];
480*18c2aff7Sartem 	struct action_arg a1;
481*18c2aff7Sartem 
482*18c2aff7Sartem 	dprintf("%s[%d]: entering action()\n", __FILE__, __LINE__);
483*18c2aff7Sartem 
484*18c2aff7Sartem 	/*
485*18c2aff7Sartem 	 * on Trusted Extensions, actions are executed in the user's zone
486*18c2aff7Sartem 	 */
487*18c2aff7Sartem 	if (mnt_zoneid > GLOBAL_ZONEID) {
488*18c2aff7Sartem 		pid_t	pid;
489*18c2aff7Sartem 		int	status;
490*18c2aff7Sartem 		int	ifx;
491*18c2aff7Sartem 		int	tmpl_fd;
492*18c2aff7Sartem 		int	err = 0;
493*18c2aff7Sartem 
494*18c2aff7Sartem 		tmpl_fd = open64(CTFS_ROOT "/process/template",
495*18c2aff7Sartem 		    O_RDWR);
496*18c2aff7Sartem 		if (tmpl_fd == -1)
497*18c2aff7Sartem 			return (1);
498*18c2aff7Sartem 
499*18c2aff7Sartem 		/*
500*18c2aff7Sartem 		 * Deliver no events, don't inherit,
501*18c2aff7Sartem 		 * and allow it to be orphaned.
502*18c2aff7Sartem 		 */
503*18c2aff7Sartem 		err |= ct_tmpl_set_critical(tmpl_fd, 0);
504*18c2aff7Sartem 		err |= ct_tmpl_set_informative(tmpl_fd, 0);
505*18c2aff7Sartem 		err |= ct_pr_tmpl_set_fatal(tmpl_fd,
506*18c2aff7Sartem 		    CT_PR_EV_HWERR);
507*18c2aff7Sartem 		err |= ct_pr_tmpl_set_param(tmpl_fd,
508*18c2aff7Sartem 		    CT_PR_PGRPONLY |
509*18c2aff7Sartem 		    CT_PR_REGENT);
510*18c2aff7Sartem 		if (err || ct_tmpl_activate(tmpl_fd)) {
511*18c2aff7Sartem 			(void) close(tmpl_fd);
512*18c2aff7Sartem 			return (1);
513*18c2aff7Sartem 		}
514*18c2aff7Sartem 		switch (pid = fork1()) {
515*18c2aff7Sartem 		case 0:
516*18c2aff7Sartem 			(void) ct_tmpl_clear(tmpl_fd);
517*18c2aff7Sartem 			for (ifx = 0; ifx < _NFILE; ifx++)
518*18c2aff7Sartem 				(void) close(ifx);
519*18c2aff7Sartem 
520*18c2aff7Sartem 			if (zone_enter(mnt_zoneid) == -1)
521*18c2aff7Sartem 				_exit(0);
522*18c2aff7Sartem 
523*18c2aff7Sartem 			/* entered zone, proceed to action */
524*18c2aff7Sartem 			break;
525*18c2aff7Sartem 		case -1:
526*18c2aff7Sartem 			dprintf("fork1 failed \n ");
527*18c2aff7Sartem 			return (1);
528*18c2aff7Sartem 		default :
529*18c2aff7Sartem 			(void) ct_tmpl_clear(tmpl_fd);
530*18c2aff7Sartem 			(void) close(tmpl_fd);
531*18c2aff7Sartem 			if (waitpid(pid, &status, 0) < 0) {
532*18c2aff7Sartem 				dprintf("%s(%ld): waitpid() "
533*18c2aff7Sartem 				    "failed (errno %d) \n",
534*18c2aff7Sartem 				    prog_name, prog_pid, errno);
535*18c2aff7Sartem 				return (1);
536*18c2aff7Sartem 			}
537*18c2aff7Sartem 		    }
538*18c2aff7Sartem 
539*18c2aff7Sartem 	}
540*18c2aff7Sartem 
541*18c2aff7Sartem 	/* only support one action at a time XXX */
542*18c2aff7Sartem 	a1.aa_path = NULL;
543*18c2aff7Sartem 	aa[0] = aap;
544*18c2aff7Sartem 	aa[1] = &a1;
545*18c2aff7Sartem 
546*18c2aff7Sartem 	action = aa[0]->aa_action;
547*18c2aff7Sartem 
548*18c2aff7Sartem 	if (action == CLEAR_MOUNTS) {
549*18c2aff7Sartem 		/*
550*18c2aff7Sartem 		 * Remove the notifications files, but don't
551*18c2aff7Sartem 		 * notify the client.  The "clear_mounts" action
552*18c2aff7Sartem 		 * simply clears all existing mounts of a medium's
553*18c2aff7Sartem 		 * partitions after a medium has been repartitioned.
554*18c2aff7Sartem 		 * Then vold builds a new file system that reflects
555*18c2aff7Sartem 		 * the medium's new partition structure and mounts
556*18c2aff7Sartem 		 * the new partitions by calling rmmount, and therefore
557*18c2aff7Sartem 		 * action(), with the VOLUME_ACTION environment variable
558*18c2aff7Sartem 		 * set to "remount".
559*18c2aff7Sartem 		 */
560*18c2aff7Sartem 		result = remove_notify_files(aa);
561*18c2aff7Sartem 		result = TRUE;
562*18c2aff7Sartem 	} else if (action == EJECT) {
563*18c2aff7Sartem 		result = remove_notify_files(aa);
564*18c2aff7Sartem 		if (result == TRUE) {
565*18c2aff7Sartem 			do_notify = TRUE;
566*18c2aff7Sartem 			notify_act = EJECT;
567*18c2aff7Sartem 		}
568*18c2aff7Sartem 	} else if (action = INSERT) {
569*18c2aff7Sartem 		result = create_notify_files(aa);
570*18c2aff7Sartem 		if (result == TRUE) {
571*18c2aff7Sartem 			do_notify = TRUE;
572*18c2aff7Sartem 			notify_act = INSERT;
573*18c2aff7Sartem 		}
574*18c2aff7Sartem 	} else if (action == REMOUNT) {
575*18c2aff7Sartem 		result = create_notify_files(aa);
576*18c2aff7Sartem 		if (result == TRUE) {
577*18c2aff7Sartem 			do_notify = TRUE;
578*18c2aff7Sartem 			notify_act = REMOUNT;
579*18c2aff7Sartem 		}
580*18c2aff7Sartem 	} else if (action == UNMOUNT) {
581*18c2aff7Sartem 		result = remove_notify_files(aa);
582*18c2aff7Sartem 		if (result == TRUE) {
583*18c2aff7Sartem 			do_notify = TRUE;
584*18c2aff7Sartem 			notify_act = UNMOUNT;
585*18c2aff7Sartem 		}
586*18c2aff7Sartem 	} else {
587*18c2aff7Sartem 		dprintf("%s[%d]: action(): invalid action: %s\n",
588*18c2aff7Sartem 			__FILE__, __LINE__, action);
589*18c2aff7Sartem 		result = FALSE;
590*18c2aff7Sartem 	}
591*18c2aff7Sartem 
592*18c2aff7Sartem 	if (result == TRUE) {
593*18c2aff7Sartem 		result = notify_clients(notify_act, do_notify);
594*18c2aff7Sartem 	}
595*18c2aff7Sartem 
596*18c2aff7Sartem 	dprintf("%s[%d]: leaving action(), result = %s\n",
597*18c2aff7Sartem 		__FILE__, __LINE__, result_strings[result]);
598*18c2aff7Sartem 
599*18c2aff7Sartem 	if (mnt_zoneid > GLOBAL_ZONEID) {
600*18c2aff7Sartem 		/* exit forked local zone process */
601*18c2aff7Sartem 		_exit(0);
602*18c2aff7Sartem 	}
603*18c2aff7Sartem 
604*18c2aff7Sartem 	if (result == TRUE) {
605*18c2aff7Sartem 		/*
606*18c2aff7Sartem 		 * File Manager is running. return 0.
607*18c2aff7Sartem 		 * see man page rmmount.conf(4).
608*18c2aff7Sartem 		 */
609*18c2aff7Sartem 		return (0);
610*18c2aff7Sartem 	} else {
611*18c2aff7Sartem 		return (1);
612*18c2aff7Sartem 	}
613*18c2aff7Sartem }
614*18c2aff7Sartem 
615*18c2aff7Sartem 
616*18c2aff7Sartem /*
617*18c2aff7Sartem  * Returns NULL if a medium or partition is mountable
618*18c2aff7Sartem  * and a string stating the reason the medium or partition
619*18c2aff7Sartem  * can't be mounted if the medium or partition isn't mountable.
620*18c2aff7Sartem  *
621*18c2aff7Sartem  * If the volume_name of the medium or partition is one of the
622*18c2aff7Sartem  * following, the medium or partition isn't mountable.
623*18c2aff7Sartem  *
624*18c2aff7Sartem  * unlabeled_<media_type>
625*18c2aff7Sartem  * unknown_format
626*18c2aff7Sartem  * password_protected
627*18c2aff7Sartem  */
628*18c2aff7Sartem /* ARGSUSED */
629*18c2aff7Sartem static char *
630*18c2aff7Sartem not_mountable(struct action_arg *aa)
631*18c2aff7Sartem {
632*18c2aff7Sartem 	return (NULL);
633*18c2aff7Sartem }
634*18c2aff7Sartem 
635*18c2aff7Sartem static int
636*18c2aff7Sartem create_notify_files(struct action_arg **aa)
637*18c2aff7Sartem {
638*18c2aff7Sartem 	int	ai;
639*18c2aff7Sartem 	char	*fstype;
640*18c2aff7Sartem 	char	*mount_point;
641*18c2aff7Sartem 	char	notify_file[64];
642*18c2aff7Sartem 	char	*raw_partitionp;
643*18c2aff7Sartem 	char	*reason; /* Why the medium wasn't mounted */
644*18c2aff7Sartem 	int	result;
645*18c2aff7Sartem 	char	*symdev;
646*18c2aff7Sartem 
647*18c2aff7Sartem 	dprintf("%s[%d]: entering create_notify_files()\n", __FILE__, __LINE__);
648*18c2aff7Sartem 
649*18c2aff7Sartem 	ai = 0;
650*18c2aff7Sartem 	result = FALSE;
651*18c2aff7Sartem 	symdev = aa[ai]->aa_symdev;
652*18c2aff7Sartem 	while ((aa[ai] != NULL) && (aa[ai]->aa_path != NULL)) {
653*18c2aff7Sartem 		if (aa[ai]->aa_mountpoint != NULL) {
654*18c2aff7Sartem 			if (aa[ai]->aa_type) {
655*18c2aff7Sartem 				fstype = aa[ai]->aa_type;
656*18c2aff7Sartem 			} else {
657*18c2aff7Sartem 				fstype = "unknown";
658*18c2aff7Sartem 			}
659*18c2aff7Sartem 			mount_point = aa[ai]->aa_mountpoint;
660*18c2aff7Sartem 			if (aa[ai]->aa_partname != NULL) {
661*18c2aff7Sartem 				/*
662*18c2aff7Sartem 				 * Is aa_partname ever NULL?
663*18c2aff7Sartem 				 * When time permits, check.
664*18c2aff7Sartem 				 * If it is, the action taken
665*18c2aff7Sartem 				 * in the else clause could produce
666*18c2aff7Sartem 				 * file name conflicts.
667*18c2aff7Sartem 				 */
668*18c2aff7Sartem 				sprintf(notify_file, "%s-%s", symdev,
669*18c2aff7Sartem 						aa[ai]->aa_partname);
670*18c2aff7Sartem 			} else {
671*18c2aff7Sartem 				sprintf(notify_file, "%s-0", symdev);
672*18c2aff7Sartem 			}
673*18c2aff7Sartem 			reason = NULL;
674*18c2aff7Sartem 		} else {
675*18c2aff7Sartem 			/*
676*18c2aff7Sartem 			 * The partition isn't mounted.
677*18c2aff7Sartem 			 */
678*18c2aff7Sartem 			fstype = "none";
679*18c2aff7Sartem 			mount_point = "none";
680*18c2aff7Sartem 			reason = not_mountable(aa[ai]);
681*18c2aff7Sartem 			if (reason != NULL) {
682*18c2aff7Sartem 				sprintf(notify_file, "%s-0", symdev);
683*18c2aff7Sartem 			} else {
684*18c2aff7Sartem 				/*
685*18c2aff7Sartem 				 * Either the partition is a backup slice, or
686*18c2aff7Sartem 				 * rmmount tried to mount the partition, but
687*18c2aff7Sartem 				 * idenf_fs couldn't identify the file system
688*18c2aff7Sartem 				 * type; that can occur when rmmount is
689*18c2aff7Sartem 				 * trying to mount all the slices in a Solaris
690*18c2aff7Sartem 				 * VTOC, and one or more partitions don't have
691*18c2aff7Sartem 				 * file systems in them.
692*18c2aff7Sartem 				 */
693*18c2aff7Sartem 				if (aa[0]->aa_partname != NULL) {
694*18c2aff7Sartem 					/*
695*18c2aff7Sartem 					 * Is aa_partname ever NULL?
696*18c2aff7Sartem 					 * When time permits, check.
697*18c2aff7Sartem 					 * If it is, the action taken
698*18c2aff7Sartem 					 * in the else clause could produce
699*18c2aff7Sartem 					 * file name conflicts.
700*18c2aff7Sartem 					 */
701*18c2aff7Sartem 					sprintf(notify_file, "%s-%s", symdev,
702*18c2aff7Sartem 							aa[0]->aa_partname);
703*18c2aff7Sartem 				} else {
704*18c2aff7Sartem 					sprintf(notify_file, "%s-0", symdev);
705*18c2aff7Sartem 				}
706*18c2aff7Sartem 				if ((aa[0]->aa_type != NULL) &&
707*18c2aff7Sartem 					(strcmp(aa[0]->aa_type, "backup_slice")
708*18c2aff7Sartem 						== 0)) {
709*18c2aff7Sartem 					reason = "backup_slice";
710*18c2aff7Sartem 				} else {
711*18c2aff7Sartem 					reason = "unformatted_media";
712*18c2aff7Sartem 				}
713*18c2aff7Sartem 				/*
714*18c2aff7Sartem 				 * "unformatted_media" should be
715*18c2aff7Sartem 				 * changed to "unformmated_medium" for
716*18c2aff7Sartem 				 * grammatical correctness, but
717*18c2aff7Sartem 				 * "unformatted_media" is now specified
718*18c2aff7Sartem 				 * in the interface to filemgr, so the
719*18c2aff7Sartem 				 * change can't be made without the
720*18c2aff7Sartem 				 * approval of the CDE group.
721*18c2aff7Sartem 				 */
722*18c2aff7Sartem 			}
723*18c2aff7Sartem 		}
724*18c2aff7Sartem 		raw_partitionp = aa[0]->aa_rawpath;
725*18c2aff7Sartem 		result = create_one_notify_file(fstype,
726*18c2aff7Sartem 				mount_point,
727*18c2aff7Sartem 				notify_file,
728*18c2aff7Sartem 				raw_partitionp,
729*18c2aff7Sartem 				reason,
730*18c2aff7Sartem 				symdev);
731*18c2aff7Sartem 		ai++;
732*18c2aff7Sartem 	}
733*18c2aff7Sartem 	dprintf("%s[%d]: leaving create_notify_files(), result = %s\n",
734*18c2aff7Sartem 		__FILE__, __LINE__, result_strings[result]);
735*18c2aff7Sartem 	return (result);
736*18c2aff7Sartem }
737*18c2aff7Sartem 
738*18c2aff7Sartem static int
739*18c2aff7Sartem create_one_notify_file(char *fstype,
740*18c2aff7Sartem 	char *mount_point,
741*18c2aff7Sartem 	char *notify_file,
742*18c2aff7Sartem 	char *raw_partitionp,
743*18c2aff7Sartem 	char *reason,
744*18c2aff7Sartem 	char *symdev)
745*18c2aff7Sartem {
746*18c2aff7Sartem 	/*
747*18c2aff7Sartem 	 * For a mounted partition, create a notification file
748*18c2aff7Sartem 	 * indicating the mount point,  the raw device pathname
749*18c2aff7Sartem 	 * of the partition, and the partition's file system
750*18c2aff7Sartem 	 * type.  For an unmounted partition, create a
751*18c2aff7Sartem 	 * notification file containing the reason that the
752*18c2aff7Sartem 	 * partition wasn't mounted and the raw device pathname
753*18c2aff7Sartem 	 * of the partition.
754*18c2aff7Sartem 	 *
755*18c2aff7Sartem 	 * Create the file as root in a world-writable
756*18c2aff7Sartem 	 * directory that resides in a world-writable directory.
757*18c2aff7Sartem 	 *
758*18c2aff7Sartem 	 * Handle two possible race conditions that could
759*18c2aff7Sartem 	 * allow security breaches.
760*18c2aff7Sartem 	 */
761*18c2aff7Sartem 
762*18c2aff7Sartem 	int	current_working_dir_fd;
763*18c2aff7Sartem 	int	file_descriptor;
764*18c2aff7Sartem 	FILE	*filep;
765*18c2aff7Sartem 	int	result;
766*18c2aff7Sartem 
767*18c2aff7Sartem 	dprintf("%s[%d]:Entering create_one_notify_file()\n",
768*18c2aff7Sartem 		__FILE__, __LINE__);
769*18c2aff7Sartem 	dprintf("\tcreate_one_notify_file(): fstype = %s\n", fstype);
770*18c2aff7Sartem 	dprintf("\tcreate_one_notify_file(): mount_point = %s\n", mount_point);
771*18c2aff7Sartem 	dprintf("\tcreate_one_notify_file(): notify_file = %s\n", notify_file);
772*18c2aff7Sartem 	dprintf("\tcreate_one_notify_file(): raw_partitionp = %s\n",
773*18c2aff7Sartem 		raw_partitionp);
774*18c2aff7Sartem 	if (reason != NULL) {
775*18c2aff7Sartem 		dprintf("\tcreate_one_notify_file(): reason = %s\n", reason);
776*18c2aff7Sartem 	} else {
777*18c2aff7Sartem 		dprintf("\tcreate_one_notify_file(): reason = NULL\n");
778*18c2aff7Sartem 	}
779*18c2aff7Sartem 	dprintf("\tcreate_one_notify_file(): symdev = %s\n", symdev);
780*18c2aff7Sartem 
781*18c2aff7Sartem 	result = TRUE;
782*18c2aff7Sartem 	/*
783*18c2aff7Sartem 	 * Handle Race Condition One:
784*18c2aff7Sartem 	 *
785*18c2aff7Sartem 	 *   If NOTIFY_DIR exists, make sure it is not a symlink.
786*18c2aff7Sartem 	 *   if it is, remove it and try to create it.  Check
787*18c2aff7Sartem 	 *   again to make sure NOTIFY_DIR isn't a symlink.
788*18c2aff7Sartem 	 *   If it is, remove it and return without creating
789*18c2aff7Sartem 	 *   a notification file.  The condition can only occur if
790*18c2aff7Sartem 	 *   someone is trying to break into the system by running
791*18c2aff7Sartem 	 *   a program that repeatedly creates NOTIFY_DIR as a
792*18c2aff7Sartem 	 *   symlink.  If NOTIFY_DIR exists and isn't a symlink,
793*18c2aff7Sartem 	 *   change the working directory to NOTIFY_DIR.
794*18c2aff7Sartem 	 */
795*18c2aff7Sartem 	current_working_dir_fd = pushdir(NOTIFY_DIR);
796*18c2aff7Sartem 	if (current_working_dir_fd < 0) {
797*18c2aff7Sartem 		(void) makepath(NOTIFY_DIR, 0777);
798*18c2aff7Sartem 		current_working_dir_fd = pushdir(NOTIFY_DIR);
799*18c2aff7Sartem 		if (current_working_dir_fd < 0) {
800*18c2aff7Sartem 			result = FALSE;
801*18c2aff7Sartem 		}
802*18c2aff7Sartem 	}
803*18c2aff7Sartem 	/*
804*18c2aff7Sartem 	 * Handle Race Condition Two:
805*18c2aff7Sartem 	 *
806*18c2aff7Sartem 	 * Create the notification file in NOTIFY_DIR.
807*18c2aff7Sartem 	 * Remove any files with the same name that may already be
808*18c2aff7Sartem 	 * there, using remove(), as it safely removes directories.
809*18c2aff7Sartem 	 * Then open the file O_CREAT|O_EXCL, which doesn't follow
810*18c2aff7Sartem 	 * symlinks and requires that the file not exist already,
811*18c2aff7Sartem 	 * so the new file actually resides in the current working
812*18c2aff7Sartem 	 * directory.  Create the file with access mode 644, which
813*18c2aff7Sartem 	 * renders it unusable by anyone trying to break into the
814*18c2aff7Sartem 	 * system.
815*18c2aff7Sartem 	 */
816*18c2aff7Sartem 	if (result == TRUE) {
817*18c2aff7Sartem 		/*
818*18c2aff7Sartem 		 * The current working directory is now NOTIFY_DIR.
819*18c2aff7Sartem 		 */
820*18c2aff7Sartem 		(void) remove(notify_file);
821*18c2aff7Sartem 		file_descriptor =
822*18c2aff7Sartem 			open(notify_file, O_CREAT|O_EXCL|O_WRONLY, 0644);
823*18c2aff7Sartem 		if (file_descriptor < 0) {
824*18c2aff7Sartem 			dprintf("%s[%d]: can't create %s/%s; %m\n",
825*18c2aff7Sartem 				__FILE__, __LINE__, NOTIFY_DIR, notify_file);
826*18c2aff7Sartem 			result = FALSE;
827*18c2aff7Sartem 		} else {
828*18c2aff7Sartem 			filep = fdopen(file_descriptor, "w");
829*18c2aff7Sartem 			if (filep != NULL) {
830*18c2aff7Sartem 				if (reason == NULL) {
831*18c2aff7Sartem 					(void) fprintf(filep, "%s %s %s",
832*18c2aff7Sartem 						mount_point,
833*18c2aff7Sartem 						raw_partitionp,
834*18c2aff7Sartem 						fstype);
835*18c2aff7Sartem 					(void) fclose(filep);
836*18c2aff7Sartem 				dprintf("%s[%d]: Just wrote %s %s %s to %s\n",
837*18c2aff7Sartem 						__FILE__,
838*18c2aff7Sartem 						__LINE__,
839*18c2aff7Sartem 						mount_point,
840*18c2aff7Sartem 						raw_partitionp,
841*18c2aff7Sartem 						fstype,
842*18c2aff7Sartem 						notify_file);
843*18c2aff7Sartem 				} else {
844*18c2aff7Sartem 					(void) fprintf(filep, "%s %s",
845*18c2aff7Sartem 						reason, raw_partitionp);
846*18c2aff7Sartem 					(void) fclose(filep);
847*18c2aff7Sartem 				dprintf("%s[%d]: Just wrote %s %s to %s\n",
848*18c2aff7Sartem 						__FILE__,
849*18c2aff7Sartem 						__LINE__,
850*18c2aff7Sartem 						reason,
851*18c2aff7Sartem 						raw_partitionp,
852*18c2aff7Sartem 						notify_file);
853*18c2aff7Sartem 				}
854*18c2aff7Sartem 			} else {
855*18c2aff7Sartem 				dprintf("%s[%d]: can't write %s/%s; %m\n",
856*18c2aff7Sartem 					__FILE__, __LINE__,
857*18c2aff7Sartem 					NOTIFY_DIR, notify_file);
858*18c2aff7Sartem 				(void) close(file_descriptor);
859*18c2aff7Sartem 				result = FALSE;
860*18c2aff7Sartem 			}
861*18c2aff7Sartem 		}
862*18c2aff7Sartem 		popdir(current_working_dir_fd);
863*18c2aff7Sartem 	}
864*18c2aff7Sartem 	dprintf("%s[%d]: leaving create_one_notify_file, result = %s\n",
865*18c2aff7Sartem 		__FILE__, __LINE__, result_strings[result]);
866*18c2aff7Sartem 	return (result);
867*18c2aff7Sartem }
868*18c2aff7Sartem 
869*18c2aff7Sartem static boolean_t
870*18c2aff7Sartem notify_clients(action_t action, int do_notify)
871*18c2aff7Sartem {
872*18c2aff7Sartem 	/*
873*18c2aff7Sartem 	 * Notify interested applications of changes in the state
874*18c2aff7Sartem 	 * of removable media.  Interested applications are those
875*18c2aff7Sartem 	 * that create a named pipe in NOTIFY_DIR with a name that
876*18c2aff7Sartem 	 * begins with "notify".  Open the pipe and write a
877*18c2aff7Sartem 	 * character through it that indicates the type of state
878*18c2aff7Sartem 	 * change = 'e' for ejections, 'i' for insertions, 'r'
879*18c2aff7Sartem 	 * for remounts of the file systems on repartitioned media,
880*18c2aff7Sartem 	 * and 'u' for unmounts of file systems.
881*18c2aff7Sartem 	 */
882*18c2aff7Sartem 
883*18c2aff7Sartem 	int		current_working_dir_fd;
884*18c2aff7Sartem 	DIR		*dirp;
885*18c2aff7Sartem 	struct dirent	*dir_entryp;
886*18c2aff7Sartem 	size_t		len;
887*18c2aff7Sartem 	int		fd;
888*18c2aff7Sartem 	char		namebuf[MAXPATHLEN];
889*18c2aff7Sartem 	char		notify_character;
890*18c2aff7Sartem 	void		(*old_signal_handler)();
891*18c2aff7Sartem 	int		result;
892*18c2aff7Sartem 	struct stat	sb;
893*18c2aff7Sartem 
894*18c2aff7Sartem 	dprintf("%s[%d]: entering notify_clients()\n", __FILE__, __LINE__);
895*18c2aff7Sartem 
896*18c2aff7Sartem 	result = TRUE;
897*18c2aff7Sartem 	/*
898*18c2aff7Sartem 	 * Use relative pathnames after changing the
899*18c2aff7Sartem 	 * working directory to the notification directory.
900*18c2aff7Sartem 	 * Check to make sure that each "notify" file is a
901*18c2aff7Sartem 	 * named pipe to make sure that it hasn't changed
902*18c2aff7Sartem 	 * its file type, which could mean that someone is
903*18c2aff7Sartem 	 * trying to use "notify" files to break into the
904*18c2aff7Sartem 	 * system.
905*18c2aff7Sartem 	 */
906*18c2aff7Sartem 	if ((current_working_dir_fd = pushdir(NOTIFY_DIR)) < 0) {
907*18c2aff7Sartem 		result = FALSE;
908*18c2aff7Sartem 	}
909*18c2aff7Sartem 	if (result == TRUE) {
910*18c2aff7Sartem 		dirp = opendir(".");
911*18c2aff7Sartem 		if (dirp == NULL) {
912*18c2aff7Sartem 			dprintf("%s[%d]:opendir failed on '.'; %m\n",
913*18c2aff7Sartem 				__FILE__, __LINE__);
914*18c2aff7Sartem 			popdir(current_working_dir_fd);
915*18c2aff7Sartem 			result = FALSE;
916*18c2aff7Sartem 		}
917*18c2aff7Sartem 	}
918*18c2aff7Sartem 	if (result == TRUE) {
919*18c2aff7Sartem 		/*
920*18c2aff7Sartem 		 * Read through the directory and write a notify
921*18c2aff7Sartem 		 * character to all files whose names start with "notify".
922*18c2aff7Sartem 		 */
923*18c2aff7Sartem 		result = FALSE;
924*18c2aff7Sartem 		old_signal_handler = signal(SIGPIPE, SIG_IGN);
925*18c2aff7Sartem 		len = strlen(NOTIFY_NAME);
926*18c2aff7Sartem 		while (dir_entryp = readdir(dirp)) {
927*18c2aff7Sartem 			if (strncmp(dir_entryp->d_name, NOTIFY_NAME, len)
928*18c2aff7Sartem 			    != 0) {
929*18c2aff7Sartem 				continue;
930*18c2aff7Sartem 			}
931*18c2aff7Sartem 			result = TRUE;
932*18c2aff7Sartem 			if (do_notify != TRUE) {
933*18c2aff7Sartem 				continue;
934*18c2aff7Sartem 			}
935*18c2aff7Sartem 			(void) sprintf(namebuf, "%s/%s",
936*18c2aff7Sartem 				NOTIFY_DIR, dir_entryp->d_name);
937*18c2aff7Sartem 			if ((fd = open(namebuf, O_WRONLY|O_NDELAY)) < 0) {
938*18c2aff7Sartem 				dprintf("%s[%d]: open failed for %s; %m\n",
939*18c2aff7Sartem 				    __FILE__, __LINE__, namebuf);
940*18c2aff7Sartem 				continue;
941*18c2aff7Sartem 			}
942*18c2aff7Sartem 			/*
943*18c2aff7Sartem 			 * Check to be sure that the entry is a named pipe.
944*18c2aff7Sartem 			 * That closes a small security hole that could
945*18c2aff7Sartem 			 * enable unauthorized access to the system root.
946*18c2aff7Sartem 			 */
947*18c2aff7Sartem 			if ((fstat(fd, &sb) < 0) || (!S_ISFIFO(sb.st_mode))) {
948*18c2aff7Sartem 				dprintf("%s[%d]: %s isn't a named pipe\n",
949*18c2aff7Sartem 					__FILE__, __LINE__, namebuf);
950*18c2aff7Sartem 
951*18c2aff7Sartem 				(void) close(fd);
952*18c2aff7Sartem 				continue;
953*18c2aff7Sartem 			}
954*18c2aff7Sartem 			notify_character = notify_characters[action];
955*18c2aff7Sartem 			if (write(fd, &notify_character, 1) < 0) {
956*18c2aff7Sartem 				dprintf("%s[%d]: write failed for %s; %m\n",
957*18c2aff7Sartem 				    __FILE__, __LINE__, namebuf);
958*18c2aff7Sartem 				(void) close(fd);
959*18c2aff7Sartem 				continue;
960*18c2aff7Sartem 			}
961*18c2aff7Sartem 			(void) close(fd);
962*18c2aff7Sartem 		}
963*18c2aff7Sartem 		(void) closedir(dirp);
964*18c2aff7Sartem 		(void) signal(SIGPIPE, old_signal_handler);
965*18c2aff7Sartem 		popdir(current_working_dir_fd);
966*18c2aff7Sartem 	}
967*18c2aff7Sartem 	dprintf("%s[%d]: leaving notify_clients(), result = %s\n",
968*18c2aff7Sartem 		__FILE__, __LINE__, result_strings[result]);
969*18c2aff7Sartem 	return (result);
970*18c2aff7Sartem }
971*18c2aff7Sartem 
972*18c2aff7Sartem static void
973*18c2aff7Sartem popdir(int fd)
974*18c2aff7Sartem {
975*18c2aff7Sartem 	/*
976*18c2aff7Sartem 	 * Change the current working directory to the directory
977*18c2aff7Sartem 	 * specified by fd and close the fd.  Exit the program
978*18c2aff7Sartem 	 * on failure.
979*18c2aff7Sartem 	 */
980*18c2aff7Sartem 	if (fchdir(fd) < 0) {
981*18c2aff7Sartem 		dprintf("%s[%d]: popdir() failed\n", __FILE__, __LINE__);
982*18c2aff7Sartem 		exit(1);
983*18c2aff7Sartem 	}
984*18c2aff7Sartem 	(void) close(fd);
985*18c2aff7Sartem }
986*18c2aff7Sartem 
987*18c2aff7Sartem static int
988*18c2aff7Sartem pushdir(const char *dir)
989*18c2aff7Sartem {
990*18c2aff7Sartem 	/*
991*18c2aff7Sartem 	 * Change the current working directory to dir and
992*18c2aff7Sartem 	 * return a file descriptor for the old working
993*18c2aff7Sartem 	 * directory.
994*18c2aff7Sartem 	 *
995*18c2aff7Sartem 	 * Exception handling:
996*18c2aff7Sartem 	 *
997*18c2aff7Sartem 	 * If dir doesn't exist, leave the current working
998*18c2aff7Sartem 	 * directory the same and return -1.
999*18c2aff7Sartem 	 *
1000*18c2aff7Sartem 	 * If dir isn't a directory, remove it, leave the
1001*18c2aff7Sartem 	 * current working directory the same, and return -1.
1002*18c2aff7Sartem 	 *
1003*18c2aff7Sartem 	 * If open() fails on the current working directory
1004*18c2aff7Sartem 	 * or the chdir operation fails on dir, leave the
1005*18c2aff7Sartem 	 * current working directory the same and return -1.
1006*18c2aff7Sartem 	 */
1007*18c2aff7Sartem 
1008*18c2aff7Sartem 	int		current_working_dir_fd;
1009*18c2aff7Sartem 	struct stat	stat_buf;
1010*18c2aff7Sartem 
1011*18c2aff7Sartem 	if (lstat(dir, &stat_buf) < 0) {
1012*18c2aff7Sartem 		dprintf("%s[%d]: push_dir_and_check(): %s does not exist\n",
1013*18c2aff7Sartem 			__FILE__, __LINE__, dir);
1014*18c2aff7Sartem 		return (-1);
1015*18c2aff7Sartem 	}
1016*18c2aff7Sartem 
1017*18c2aff7Sartem 	if (!(S_ISDIR(stat_buf.st_mode))) {
1018*18c2aff7Sartem 		dprintf("%s[%d]: push_dir_and_check(): %s not a directory.\n",
1019*18c2aff7Sartem 			__FILE__, __LINE__, dir);
1020*18c2aff7Sartem 		(void) remove(dir);
1021*18c2aff7Sartem 		return (-1);
1022*18c2aff7Sartem 	}
1023*18c2aff7Sartem 	if ((current_working_dir_fd = open(".", O_RDONLY)) < 0) {
1024*18c2aff7Sartem 		dprintf("%s[%d]: push_dir_and_check(): can't open %s.\n",
1025*18c2aff7Sartem 			__FILE__, __LINE__, dir);
1026*18c2aff7Sartem 		return (-1);
1027*18c2aff7Sartem 	}
1028*18c2aff7Sartem 	if (chdir(dir) < 0) {
1029*18c2aff7Sartem 		(void) close(current_working_dir_fd);
1030*18c2aff7Sartem 		dprintf("%s[%d]: push_dir_and_check(): can't chdir() to %s.\n",
1031*18c2aff7Sartem 			__FILE__, __LINE__, dir);
1032*18c2aff7Sartem 		return (-1);
1033*18c2aff7Sartem 	}
1034*18c2aff7Sartem 	return (current_working_dir_fd);
1035*18c2aff7Sartem }
1036*18c2aff7Sartem 
1037*18c2aff7Sartem static boolean_t
1038*18c2aff7Sartem remove_notify_files(struct action_arg **aa)
1039*18c2aff7Sartem {
1040*18c2aff7Sartem 	int	ai;
1041*18c2aff7Sartem 	int	current_working_dir_fd;
1042*18c2aff7Sartem 	char	notify_file[64];
1043*18c2aff7Sartem 	int	result;
1044*18c2aff7Sartem 	char	*symdev;
1045*18c2aff7Sartem 
1046*18c2aff7Sartem 	dprintf("%s[%d]: entering remove_notify_files()\n", __FILE__, __LINE__);
1047*18c2aff7Sartem 
1048*18c2aff7Sartem 	ai = 0;
1049*18c2aff7Sartem 	result = TRUE;
1050*18c2aff7Sartem 	symdev = aa[ai]->aa_symdev;
1051*18c2aff7Sartem 	while ((result == TRUE) &&
1052*18c2aff7Sartem 		(aa[ai] != NULL) &&
1053*18c2aff7Sartem 		(aa[ai]->aa_path != NULL)) {
1054*18c2aff7Sartem 
1055*18c2aff7Sartem 		if (not_mountable(aa[ai])) {
1056*18c2aff7Sartem 			sprintf(notify_file, "%s-0", symdev);
1057*18c2aff7Sartem 		} else if (aa[ai]->aa_partname != NULL) {
1058*18c2aff7Sartem 			/*
1059*18c2aff7Sartem 			 * Is aa_partname ever NULL?
1060*18c2aff7Sartem 			 * When time permits, check.
1061*18c2aff7Sartem 			 * If it is, the action taken
1062*18c2aff7Sartem 			 * in the else clause could produce
1063*18c2aff7Sartem 			 * file name conflicts.
1064*18c2aff7Sartem 			 */
1065*18c2aff7Sartem 			sprintf(notify_file, "%s-%s",
1066*18c2aff7Sartem 				symdev, aa[0]->aa_partname);
1067*18c2aff7Sartem 		} else {
1068*18c2aff7Sartem 			sprintf(notify_file, "%s-0", symdev);
1069*18c2aff7Sartem 		}
1070*18c2aff7Sartem 
1071*18c2aff7Sartem 		current_working_dir_fd = pushdir(NOTIFY_DIR);
1072*18c2aff7Sartem 		if (current_working_dir_fd < 0) {
1073*18c2aff7Sartem 			result = FALSE;
1074*18c2aff7Sartem 		}
1075*18c2aff7Sartem 		if ((result == TRUE) && (remove(notify_file) < 0)) {
1076*18c2aff7Sartem 			dprintf("%s[%d]: remove %s/%s; %m\n",
1077*18c2aff7Sartem 				__FILE__, __LINE__, NOTIFY_DIR, notify_file);
1078*18c2aff7Sartem 			result = FALSE;
1079*18c2aff7Sartem 		}
1080*18c2aff7Sartem 		if (current_working_dir_fd != -1) {
1081*18c2aff7Sartem 			popdir(current_working_dir_fd);
1082*18c2aff7Sartem 		}
1083*18c2aff7Sartem 		ai++;
1084*18c2aff7Sartem 	}
1085*18c2aff7Sartem 	dprintf("%s[%d]: leaving remove_notify_files(), result = %s\n",
1086*18c2aff7Sartem 		__FILE__, __LINE__, result_strings[result]);
1087*18c2aff7Sartem 
1088*18c2aff7Sartem 	return (result);
1089*18c2aff7Sartem }
1090