xref: /titanic_50/usr/src/cmd/rmvolmgr/vold.c (revision 97ddcdce0091922bf2049977a3d42ba4fc0857a6)
118c2aff7Sartem /*
218c2aff7Sartem  * CDDL HEADER START
318c2aff7Sartem  *
418c2aff7Sartem  * The contents of this file are subject to the terms of the
518c2aff7Sartem  * Common Development and Distribution License (the "License").
618c2aff7Sartem  * You may not use this file except in compliance with the License.
718c2aff7Sartem  *
818c2aff7Sartem  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
918c2aff7Sartem  * or http://www.opensolaris.org/os/licensing.
1018c2aff7Sartem  * See the License for the specific language governing permissions
1118c2aff7Sartem  * and limitations under the License.
1218c2aff7Sartem  *
1318c2aff7Sartem  * When distributing Covered Code, include this CDDL HEADER in each
1418c2aff7Sartem  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1518c2aff7Sartem  * If applicable, add the following below this CDDL HEADER, with the
1618c2aff7Sartem  * fields enclosed by brackets "[]" replaced with your own identifying
1718c2aff7Sartem  * information: Portions Copyright [yyyy] [name of copyright owner]
1818c2aff7Sartem  *
1918c2aff7Sartem  * CDDL HEADER END
2018c2aff7Sartem  */
2118c2aff7Sartem /*
22*97ddcdceSArtem Kachitchkine  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
2318c2aff7Sartem  * Use is subject to license terms.
2418c2aff7Sartem  */
2518c2aff7Sartem 
2618c2aff7Sartem /*
2718c2aff7Sartem  * Vold compatibility for rmvolmgr: emulate old commands as well as
2818c2aff7Sartem  * action_filemgr.so to notify legacy apps via /tmp/.removable pipes.
2918c2aff7Sartem  * A lot of this code is copied verbatim from vold sources.
3018c2aff7Sartem  *
3118c2aff7Sartem  * Here's the original description of action_filemgr.so:
3218c2aff7Sartem  *
3318c2aff7Sartem  * action_filemgr.so - filemgr interface routines for rmmount
3418c2aff7Sartem  *
3518c2aff7Sartem  * This shared object allows rmmount to communicate with filemgr.
3618c2aff7Sartem  * This is done by communicating over a named pipe that filemgr
3718c2aff7Sartem  * creates in directory NOTIFY_DIR.  The name of the pipe must
3818c2aff7Sartem  * begin with NOTIFY_NAME.  This source file contains #define
3918c2aff7Sartem  * compiler directives set the values of NOTIFY_DIR and NOTIFY_NAME.
4018c2aff7Sartem  *
4118c2aff7Sartem  * After a partition on a medium has been mounted as a result of
4218c2aff7Sartem  * either insertion or remounting of the medium, the action()
4318c2aff7Sartem  * method creates a file named with the symbolic name of the
4418c2aff7Sartem  * device in which the medium is inserted and the partition name
4518c2aff7Sartem  * (e.g. "jaz0-s2") in NOTIFY_DIR.  The file consists of one text
4618c2aff7Sartem  * line containing a string naming the mount point of the partition,
4718c2aff7Sartem  * a string giving the raw device path to the partition, and a
4818c2aff7Sartem  * string naming the file system type on the partition.  The action()
4918c2aff7Sartem  * method then sends a single character ('i' for insertion, 'r' for
5018c2aff7Sartem  * remounting) through the named pipe NOTIFY_NAME to tell filemgr to
5118c2aff7Sartem  * look for new files in NOTIFY_DIR.
5218c2aff7Sartem  *
5318c2aff7Sartem  * If a medium containing no mountable partitions is inserted
5418c2aff7Sartem  * or remounted in a device, the action() method creates a file
5518c2aff7Sartem  * named with the symbolic name of the device in NOTIFY_DIR.
5618c2aff7Sartem  * The file consists of one text line containing a string
5718c2aff7Sartem  * giving the symbolic name of the device and a string naming
5818c2aff7Sartem  * the reason that the medium couldn't be mounted.  The action
5918c2aff7Sartem  * method then sends either an 'i' or an 'r' through the named
6018c2aff7Sartem  * pipe to tell filemgr to look for new files in NOTIFY_DIR.
6118c2aff7Sartem  *
6218c2aff7Sartem  * When a medium is ejected or unmounted, the action() method
6318c2aff7Sartem  * removes the files that were created in NOTIFY_DIR when the medium
6418c2aff7Sartem  * was inserted or remounted and sends a single character ('e' for
6518c2aff7Sartem  * ejection, 'u' for unmounting) through the named pipe.
6618c2aff7Sartem  *
6718c2aff7Sartem  * The following environment variables must be set before calling action():
6818c2aff7Sartem  *
6918c2aff7Sartem  *	VOLUME_ACTION		action that occurred (e.g. "insert", "eject")
7018c2aff7Sartem  *	VOLUME_SYMDEV		symbolic name (e.g. "cdrom0", "floppy1")
7118c2aff7Sartem  *	VOLUME_NAME		volume name (e.g. "unnamed_cdrom", "s2")
7218c2aff7Sartem  */
7318c2aff7Sartem 
7418c2aff7Sartem 
7518c2aff7Sartem #include <stdio.h>
7618c2aff7Sartem #include <stdlib.h>
7718c2aff7Sartem #include <unistd.h>
7818c2aff7Sartem #include <fcntl.h>
7918c2aff7Sartem #include <string.h>
8018c2aff7Sartem #include <strings.h>
8118c2aff7Sartem #include <dirent.h>
8218c2aff7Sartem #include <signal.h>
8318c2aff7Sartem #include <errno.h>
8418c2aff7Sartem #include <libintl.h>
8518c2aff7Sartem #include <zone.h>
8618c2aff7Sartem #include <pwd.h>
8718c2aff7Sartem #include <sys/types.h>
8818c2aff7Sartem #include <sys/stat.h>
8918c2aff7Sartem #include <sys/dkio.h>
9018c2aff7Sartem #include <sys/cdio.h>
9118c2aff7Sartem #include <sys/vtoc.h>
9218c2aff7Sartem #include <sys/param.h>
9318c2aff7Sartem #include <sys/wait.h>
9418c2aff7Sartem #include <libcontract.h>
9518c2aff7Sartem #include <sys/contract/process.h>
9618c2aff7Sartem #include <sys/ctfs.h>
9718c2aff7Sartem #include <tsol/label.h>
9818c2aff7Sartem 
9918c2aff7Sartem #include "vold.h"
10018c2aff7Sartem #include "rmm_common.h"
10118c2aff7Sartem 
10218c2aff7Sartem int		rmm_debug = 0;
10318c2aff7Sartem boolean_t	rmm_vold_actions_enabled = B_FALSE;
10418c2aff7Sartem boolean_t	rmm_vold_mountpoints_enabled = B_FALSE;
10518c2aff7Sartem 
10618c2aff7Sartem static char	*prog_name = NULL;
10718c2aff7Sartem static pid_t	prog_pid = 0;
10818c2aff7Sartem static int	system_labeled = 0;
109f48205beScasper static uid_t	mnt_uid = (uid_t)-1;
110f48205beScasper static gid_t	mnt_gid = (gid_t)-1;
11118c2aff7Sartem static zoneid_t	mnt_zoneid = -1;
11218c2aff7Sartem static char	mnt_zoneroot[MAXPATHLEN];
11318c2aff7Sartem static char	mnt_userdir[MAXPATHLEN];
11418c2aff7Sartem 
11518c2aff7Sartem /*
11618c2aff7Sartem  * Private attribute types and attributes.
11718c2aff7Sartem  */
11818c2aff7Sartem static const char notify_characters[] = {
11918c2aff7Sartem 	'e',
12018c2aff7Sartem 	'i',
12118c2aff7Sartem 	'r',
12218c2aff7Sartem 	'u'
12318c2aff7Sartem };
12418c2aff7Sartem 
12518c2aff7Sartem static const char *result_strings[] = {
12618c2aff7Sartem 	"FALSE",
12718c2aff7Sartem 	"TRUE"
12818c2aff7Sartem };
12918c2aff7Sartem 
13018c2aff7Sartem #define	NOTIFY_DIR	"/tmp/.removable"	/* dir where filemgr looks */
13118c2aff7Sartem #define	NOTIFY_NAME	"notify"		/* named pipe to talk over */
13218c2aff7Sartem 
13318c2aff7Sartem static void	volrmmount_usage();
13418c2aff7Sartem static void	volcheck_usage();
13518c2aff7Sartem static int	vold_action(struct action_arg *aap);
13618c2aff7Sartem static void	vold_update_mountpoints(struct action_arg *aap);
13718c2aff7Sartem static char	*not_mountable(struct action_arg *aa);
13818c2aff7Sartem static int	create_one_notify_file(char *fstype,
13918c2aff7Sartem 				char *mount_point,
14018c2aff7Sartem 				char *notify_file,
14118c2aff7Sartem 				char *raw_partitionp,
14218c2aff7Sartem 				char *reason,
14318c2aff7Sartem 				char *symdev);
14418c2aff7Sartem static int	create_notify_files(struct action_arg **aa);
14518c2aff7Sartem static boolean_t notify_clients(action_t action, int do_notify);
14618c2aff7Sartem static void	popdir(int fd);
14718c2aff7Sartem static int	pushdir(const char *dir);
14818c2aff7Sartem static boolean_t remove_notify_files(struct action_arg **aa);
14918c2aff7Sartem 
15018c2aff7Sartem /*
15118c2aff7Sartem  * should be called once from main()
15218c2aff7Sartem  */
15318c2aff7Sartem /* ARGSUSED */
15418c2aff7Sartem void
vold_init(int argc,char ** argv)15518c2aff7Sartem vold_init(int argc, char **argv)
15618c2aff7Sartem {
15718c2aff7Sartem 	system_labeled = is_system_labeled();
15818c2aff7Sartem }
15918c2aff7Sartem 
16018c2aff7Sartem /*
16118c2aff7Sartem  * Old version of rmmount(1M)
16218c2aff7Sartem  */
16318c2aff7Sartem /* ARGSUSED */
16418c2aff7Sartem int
vold_rmmount(int argc,char ** argv)16518c2aff7Sartem vold_rmmount(int argc, char **argv)
16618c2aff7Sartem {
16718c2aff7Sartem 	char		*volume_action;
16818c2aff7Sartem 	char		*volume_mediatype;
16918c2aff7Sartem 	char		*volume_mount_mode;
17018c2aff7Sartem 	char		*volume_name;
17118c2aff7Sartem 	char		*volume_path;
17218c2aff7Sartem 	char		*volume_pcfs_id;
17318c2aff7Sartem 	char		*volume_symdev;
17418c2aff7Sartem 	char		*volume_zonename;
17518c2aff7Sartem 	char		*volume_user;
17618c2aff7Sartem 	action_t	action;
17718c2aff7Sartem 	char		mountpoint[MAXPATHLEN];
17818c2aff7Sartem 	char		*zonemountpoint;
17918c2aff7Sartem 	char		*arg_mountpoint = NULL;
18018c2aff7Sartem 	LibHalContext	*hal_ctx;
18118c2aff7Sartem 	DBusError	error;
18218c2aff7Sartem 	rmm_error_t	rmm_error;
18318c2aff7Sartem 	int		ret;
18418c2aff7Sartem 
18518c2aff7Sartem 	prog_name = argv[0];
18618c2aff7Sartem 	prog_pid = getpid();
18718c2aff7Sartem 
18818c2aff7Sartem 	mnt_zoneroot[0] = '\0';
18918c2aff7Sartem 	mnt_userdir[0] = '\0';
19018c2aff7Sartem 
19118c2aff7Sartem 	volume_action = getenv("VOLUME_ACTION");
19218c2aff7Sartem 	volume_mediatype = getenv("VOLUME_MEDIATYPE");
19318c2aff7Sartem 	volume_mount_mode = getenv("VOLUME_MOUNT_MODE");
19418c2aff7Sartem 	volume_name = getenv("VOLUME_NAME");
19518c2aff7Sartem 	volume_path = getenv("VOLUME_PATH");
19618c2aff7Sartem 	volume_pcfs_id = getenv("VOLUME_PCFS_ID");
19718c2aff7Sartem 	volume_symdev = getenv("VOLUME_SYMDEV");
19818c2aff7Sartem 
19918c2aff7Sartem 	if (system_labeled) {
20018c2aff7Sartem 		volume_zonename = getenv("VOLUME_ZONE_NAME");
20118c2aff7Sartem 		volume_user = getenv("VOLUME_USER");
20218c2aff7Sartem 	}
20318c2aff7Sartem 	if (volume_action == NULL) {
20418c2aff7Sartem 		dprintf("%s(%ld): VOLUME_ACTION was null!!\n",
20518c2aff7Sartem 		    prog_name, prog_pid);
20618c2aff7Sartem 		return (-1);
20718c2aff7Sartem 	}
20818c2aff7Sartem 	if (volume_mediatype == NULL) {
20918c2aff7Sartem 		dprintf("%s(%ld): VOLUME_MEDIATYPE was null!!\n",
21018c2aff7Sartem 		    prog_name, prog_pid);
21118c2aff7Sartem 		return (-1);
21218c2aff7Sartem 	}
21318c2aff7Sartem 	if (volume_mount_mode == NULL) {
21418c2aff7Sartem 		volume_mount_mode = "rw";
21518c2aff7Sartem 	}
21618c2aff7Sartem 	if (volume_name == NULL) {
21718c2aff7Sartem 		dprintf("%s(%ld): VOLUME_NAME was null!!\n",
21818c2aff7Sartem 		    prog_name, prog_pid);
21918c2aff7Sartem 		return (-1);
22018c2aff7Sartem 	}
22118c2aff7Sartem 	if (volume_path == NULL) {
22218c2aff7Sartem 		dprintf("%s(%ld): VOLUME_PATH was null!!\n",
22318c2aff7Sartem 		    prog_name, prog_pid);
22418c2aff7Sartem 		return (-1);
22518c2aff7Sartem 	}
22618c2aff7Sartem 	if (volume_pcfs_id == NULL) {
22718c2aff7Sartem 		volume_pcfs_id = "";
22818c2aff7Sartem 	}
22918c2aff7Sartem 	if (volume_symdev == NULL) {
23018c2aff7Sartem 		dprintf("%s(%ld): VOLUME_SYMDEV was null!!\n",
23118c2aff7Sartem 		    prog_name, prog_pid);
23218c2aff7Sartem 		return (-1);
23318c2aff7Sartem 	}
23418c2aff7Sartem 
23518c2aff7Sartem 	if (system_labeled) {
23618c2aff7Sartem 		if (volume_zonename != NULL &&
23718c2aff7Sartem 		    strcmp(volume_zonename, GLOBAL_ZONENAME) != 0) {
23818c2aff7Sartem 			if ((mnt_zoneid =
23918c2aff7Sartem 			    getzoneidbyname(volume_zonename)) != -1) {
24018c2aff7Sartem 				if (zone_getattr(mnt_zoneid, ZONE_ATTR_ROOT,
24118c2aff7Sartem 				    mnt_zoneroot, MAXPATHLEN) == -1) {
24218c2aff7Sartem 					dprintf("%s(%ld): NO ZONEPATH!!\n",
24318c2aff7Sartem 					    prog_name, prog_pid);
24418c2aff7Sartem 					return (-1);
24518c2aff7Sartem 				}
24618c2aff7Sartem 			}
24718c2aff7Sartem 		} else {
24818c2aff7Sartem 			mnt_zoneid = GLOBAL_ZONEID;
24918c2aff7Sartem 			mnt_zoneroot[0] = '\0';
25018c2aff7Sartem 		}
25118c2aff7Sartem 		if (volume_user != NULL) {
25218c2aff7Sartem 			struct passwd	 *pw;
25318c2aff7Sartem 
25418c2aff7Sartem 			if ((pw = getpwnam(volume_user)) == NULL) {
25518c2aff7Sartem 				dprintf("%s(%ld) %s\n", prog_name, prog_pid,
25618c2aff7Sartem 				    ": VOLUME_USER was not a valid user!");
25718c2aff7Sartem 				return (-1);
25818c2aff7Sartem 			}
25918c2aff7Sartem 			mnt_uid = pw->pw_uid;
26018c2aff7Sartem 			mnt_gid = pw->pw_gid;
26118c2aff7Sartem 
26218c2aff7Sartem 			if (snprintf(mnt_userdir, sizeof (mnt_userdir),
26318c2aff7Sartem 			    "/%s-%s", volume_user, volume_symdev) >=
26418c2aff7Sartem 			    sizeof (mnt_userdir))
26518c2aff7Sartem 				return (-1);
26618c2aff7Sartem 		} else {
26718c2aff7Sartem 			mnt_uid = 0;
26818c2aff7Sartem 			mnt_userdir[0] = '\0';
26918c2aff7Sartem 		}
27018c2aff7Sartem 
27118c2aff7Sartem 		rmm_vold_mountpoints_enabled = B_FALSE;
27218c2aff7Sartem 		rmm_vold_actions_enabled = B_TRUE;
27318c2aff7Sartem 	} else {
27418c2aff7Sartem 		rmm_vold_mountpoints_enabled = B_TRUE;
27518c2aff7Sartem 		rmm_vold_actions_enabled = B_TRUE;
27618c2aff7Sartem 	}
27718c2aff7Sartem 
278*97ddcdceSArtem Kachitchkine 	if ((hal_ctx = rmm_hal_init(0, 0, 0, 0, &error, &rmm_error)) == NULL) {
27918c2aff7Sartem 		rmm_dbus_error_free(&error);
28018c2aff7Sartem 
28118c2aff7Sartem 		/* if HAL's not running, must be root */
28218c2aff7Sartem 		if (geteuid() != 0) {
28318c2aff7Sartem 			(void) fprintf(stderr,
28418c2aff7Sartem 			    gettext("%s(%ld) error: must be root to execute\n"),
28518c2aff7Sartem 			    prog_name, prog_pid);
28618c2aff7Sartem 			return (-1);
28718c2aff7Sartem 		}
28818c2aff7Sartem 	}
28918c2aff7Sartem 
29018c2aff7Sartem 	if (strcmp(volume_action, "eject") == 0) {
29118c2aff7Sartem 		action = EJECT;
29218c2aff7Sartem 	} else if (strcmp(volume_action, "insert") == 0) {
29318c2aff7Sartem 		action = INSERT;
29418c2aff7Sartem 
29518c2aff7Sartem 		if (system_labeled) {
29618c2aff7Sartem 			/*
29718c2aff7Sartem 			 * create mount point
29818c2aff7Sartem 			 */
29918c2aff7Sartem 			if (strlen(mnt_userdir) > 0) {
30018c2aff7Sartem 				if (snprintf(mountpoint, MAXPATHLEN,
30118c2aff7Sartem 				    "%s/%s%s", mnt_zoneroot, volume_mediatype,
30218c2aff7Sartem 				    mnt_userdir) > MAXPATHLEN) {
30318c2aff7Sartem 					return (-1);
30418c2aff7Sartem 
30518c2aff7Sartem 				}
30618c2aff7Sartem 				(void) makepath(mountpoint, 0700);
30718c2aff7Sartem 				(void) chown(mountpoint, mnt_uid, mnt_gid);
30818c2aff7Sartem 				/*
30918c2aff7Sartem 				 * set the top level directory bits to 0755
31018c2aff7Sartem 				 * so user can access it.
31118c2aff7Sartem 				 */
31218c2aff7Sartem 				if (snprintf(mountpoint, MAXPATHLEN,
31318c2aff7Sartem 				    "%s/%s", mnt_zoneroot,
31418c2aff7Sartem 				    volume_mediatype) <= MAXPATHLEN) {
31518c2aff7Sartem 					(void) chmod(mountpoint, 0755);
31618c2aff7Sartem 				}
31718c2aff7Sartem 			}
31818c2aff7Sartem 			if (snprintf(mountpoint, MAXPATHLEN,
31918c2aff7Sartem 			    "%s/%s%s/%s", mnt_zoneroot, volume_mediatype,
32018c2aff7Sartem 			    mnt_userdir, volume_name) > MAXPATHLEN) {
32118c2aff7Sartem 				(void) fprintf(stderr,
32218c2aff7Sartem 				    gettext("%s(%ld) error: path too long\n"),
32318c2aff7Sartem 				    prog_name, prog_pid);
32418c2aff7Sartem 				return (-1);
32518c2aff7Sartem 			}
32618c2aff7Sartem 
32718c2aff7Sartem 			/* make our mountpoint */
32818c2aff7Sartem 			(void) makepath(mountpoint, 0755);
32918c2aff7Sartem 
33018c2aff7Sartem 			arg_mountpoint = mountpoint;
33118c2aff7Sartem 		}
33218c2aff7Sartem 	} else if (strcmp(volume_action, "remount") == 0) {
33318c2aff7Sartem 		action = REMOUNT;
33418c2aff7Sartem 	} else if (strcmp(volume_action, "unmount") == 0) {
33518c2aff7Sartem 		action = UNMOUNT;
33618c2aff7Sartem 	}
33718c2aff7Sartem 
33818c2aff7Sartem 	ret = rmm_action(hal_ctx, volume_symdev, action, 0, 0, 0,
33918c2aff7Sartem 	    arg_mountpoint) ? 0 : 1;
34018c2aff7Sartem 
34118c2aff7Sartem 	if (hal_ctx != NULL) {
34218c2aff7Sartem 		rmm_hal_fini(hal_ctx);
34318c2aff7Sartem 	}
34418c2aff7Sartem 
34518c2aff7Sartem 	return (ret);
34618c2aff7Sartem }
34718c2aff7Sartem 
34818c2aff7Sartem 
34918c2aff7Sartem /*
35018c2aff7Sartem  * this should be called after rmm_hal_{mount,unmount,eject}
35118c2aff7Sartem  */
35218c2aff7Sartem int
vold_postprocess(LibHalContext * hal_ctx,const char * udi,struct action_arg * aap)35318c2aff7Sartem vold_postprocess(LibHalContext *hal_ctx, const char *udi,
35418c2aff7Sartem     struct action_arg *aap)
35518c2aff7Sartem {
35618c2aff7Sartem 	int	ret = 0;
35718c2aff7Sartem 
35818c2aff7Sartem 	/* valid mountpoint required */
35918c2aff7Sartem 	if ((aap->aa_action == INSERT) || (aap->aa_action == REMOUNT)) {
36018c2aff7Sartem 		rmm_volume_aa_update_mountpoint(hal_ctx, udi, aap);
36118c2aff7Sartem 		if ((aap->aa_mountpoint == NULL) ||
36218c2aff7Sartem 		    (strlen(aap->aa_mountpoint) == 0)) {
36318c2aff7Sartem 			return (1);
36418c2aff7Sartem 		}
36518c2aff7Sartem 	}
36618c2aff7Sartem 
36718c2aff7Sartem 	if (rmm_vold_mountpoints_enabled) {
36818c2aff7Sartem 		vold_update_mountpoints(aap);
36918c2aff7Sartem 	}
37018c2aff7Sartem 	if (rmm_vold_actions_enabled) {
37118c2aff7Sartem 		ret = vold_action(aap);
37218c2aff7Sartem 	}
37318c2aff7Sartem 
37418c2aff7Sartem 	return (ret);
37518c2aff7Sartem }
37618c2aff7Sartem 
37718c2aff7Sartem /*
37818c2aff7Sartem  * update legacy symlinks
37918c2aff7Sartem  *
38018c2aff7Sartem  * For cdrom:
38118c2aff7Sartem  *
38218c2aff7Sartem  *	/cdrom/<name> -> original mountpoint
38318c2aff7Sartem  *	/cdrom/cdrom0 -> ./<name>
38418c2aff7Sartem  *	/cdrom/cdrom -> cdrom0  (only for cdrom0)
38518c2aff7Sartem  *
38618c2aff7Sartem  * If it's a slice or partition, /cdrom/<name> becomes a directory:
38718c2aff7Sartem  *
38818c2aff7Sartem  *	/cdrom/<name>/s0
38918c2aff7Sartem  *
39018c2aff7Sartem  * Same for rmdisk and floppy.
39118c2aff7Sartem  *
39218c2aff7Sartem  * On labeled system (Trusted Solaris), links are in a user directory.
39318c2aff7Sartem  */
39418c2aff7Sartem static void
vold_update_mountpoints(struct action_arg * aap)39518c2aff7Sartem vold_update_mountpoints(struct action_arg *aap)
39618c2aff7Sartem {
39718c2aff7Sartem 	boolean_t	is_partition;
39818c2aff7Sartem 	char		part_dir[2 * MAXNAMELEN];
39918c2aff7Sartem 	char		symname_mp[2 * MAXNAMELEN];
40018c2aff7Sartem 	char		symcontents_mp[MAXNAMELEN];
40118c2aff7Sartem 	char		symname[2 * MAXNAMELEN];
40218c2aff7Sartem 	char		symcontents[MAXNAMELEN];
40318c2aff7Sartem 
40418c2aff7Sartem 	is_partition = (aap->aa_partname != NULL);
40518c2aff7Sartem 
40618c2aff7Sartem 	if (!system_labeled) {
40718c2aff7Sartem 		if (!is_partition) {
40818c2aff7Sartem 			/* /cdrom/<name> -> original mountpoint */
40918c2aff7Sartem 			(void) snprintf(symcontents_mp, sizeof (symcontents_mp),
41018c2aff7Sartem 			    "%s", aap->aa_mountpoint);
41118c2aff7Sartem 			(void) snprintf(symname_mp, sizeof (symname_mp),
41218c2aff7Sartem 			    "/%s/%s", aap->aa_media, aap->aa_name);
41318c2aff7Sartem 		} else {
41418c2aff7Sartem 			/* /cdrom/<name>/slice -> original mountpoint */
41518c2aff7Sartem 			(void) snprintf(part_dir, sizeof (part_dir),
41618c2aff7Sartem 			    "/%s/%s", aap->aa_media, aap->aa_name);
41718c2aff7Sartem 			(void) snprintf(symcontents_mp, sizeof (symcontents_mp),
41818c2aff7Sartem 			    "%s", aap->aa_mountpoint);
41918c2aff7Sartem 			(void) snprintf(symname_mp, sizeof (symname_mp),
42018c2aff7Sartem 			    "/%s/%s/%s", aap->aa_media, aap->aa_name,
42118c2aff7Sartem 			    aap->aa_partname);
42218c2aff7Sartem 
42318c2aff7Sartem 		}
42418c2aff7Sartem 		/* /cdrom/cdrom0 -> ./<name> */
42518c2aff7Sartem 		(void) snprintf(symcontents, sizeof (symcontents),
42618c2aff7Sartem 		    "./%s", aap->aa_name);
42718c2aff7Sartem 		(void) snprintf(symname, sizeof (symname),
42818c2aff7Sartem 		    "/%s/%s", aap->aa_media, aap->aa_symdev);
42918c2aff7Sartem 	} else {
43018c2aff7Sartem 		if (!is_partition) {
43118c2aff7Sartem 			/* /cdrom/<user>/<name> -> original mountpoint */
43218c2aff7Sartem 			(void) snprintf(symcontents_mp, sizeof (symcontents_mp),
43318c2aff7Sartem 			    "%s", aap->aa_mountpoint);
43418c2aff7Sartem 			(void) snprintf(symname_mp, sizeof (symname_mp),
43518c2aff7Sartem 			    "%s/%s/%s", mnt_zoneroot, aap->aa_media,
43618c2aff7Sartem 			    aap->aa_symdev);
43718c2aff7Sartem 		} else {
43818c2aff7Sartem 			/* /cdrom/<user>/<name>/slice -> original mountpoint */
43918c2aff7Sartem 			(void) snprintf(symcontents_mp, sizeof (symcontents_mp),
44018c2aff7Sartem 			    "%s", aap->aa_mountpoint);
44118c2aff7Sartem 			(void) snprintf(symname_mp, sizeof (symname_mp),
44218c2aff7Sartem 			    "%s/%s/%s", mnt_zoneroot, aap->aa_media,
44318c2aff7Sartem 			    aap->aa_symdev, aap->aa_partname);
44418c2aff7Sartem 		}
44518c2aff7Sartem 
44618c2aff7Sartem 		/* /cdrom/<user>/cdrom0 -> ./<user>/<name> */
44718c2aff7Sartem 		(void) snprintf(symcontents, sizeof (symcontents),
44818c2aff7Sartem 		    ".%s/%s", mnt_userdir, aap->aa_name);
44918c2aff7Sartem 		(void) snprintf(symname, sizeof (symname), "%s/%s/%s",
45018c2aff7Sartem 		    mnt_zoneroot, aap->aa_media, aap->aa_symdev);
45118c2aff7Sartem 	}
45218c2aff7Sartem 
45318c2aff7Sartem 	(void) unlink(symname);
45418c2aff7Sartem 	(void) unlink(symname_mp);
45518c2aff7Sartem 	if (is_partition) {
45618c2aff7Sartem 		(void) rmdir(part_dir);
45718c2aff7Sartem 	}
45818c2aff7Sartem 
45918c2aff7Sartem 	if ((aap->aa_action == INSERT) || (aap->aa_action == REMOUNT)) {
46018c2aff7Sartem 		(void) mkdir(aap->aa_media, 0755);
46118c2aff7Sartem 		if (is_partition) {
46218c2aff7Sartem 			(void) mkdir(part_dir, 0755);
46318c2aff7Sartem 		}
46418c2aff7Sartem 		(void) symlink(symcontents_mp, symname_mp);
46518c2aff7Sartem 		(void) symlink(symcontents, symname);
46618c2aff7Sartem 	}
46718c2aff7Sartem }
46818c2aff7Sartem 
46918c2aff7Sartem 
47018c2aff7Sartem static int
vold_action(struct action_arg * aap)47118c2aff7Sartem vold_action(struct action_arg *aap)
47218c2aff7Sartem {
47318c2aff7Sartem 	action_t	action;
47418c2aff7Sartem 	int		result;
47518c2aff7Sartem 	int		do_notify = FALSE;
47618c2aff7Sartem 	action_t	notify_act = EJECT;
47718c2aff7Sartem 	struct action_arg *aa[2];
47818c2aff7Sartem 	struct action_arg a1;
47918c2aff7Sartem 
48018c2aff7Sartem 	dprintf("%s[%d]: entering action()\n", __FILE__, __LINE__);
48118c2aff7Sartem 
48218c2aff7Sartem 	/*
48318c2aff7Sartem 	 * on Trusted Extensions, actions are executed in the user's zone
48418c2aff7Sartem 	 */
48518c2aff7Sartem 	if (mnt_zoneid > GLOBAL_ZONEID) {
48618c2aff7Sartem 		pid_t	pid;
48718c2aff7Sartem 		int	status;
48818c2aff7Sartem 		int	ifx;
48918c2aff7Sartem 		int	tmpl_fd;
49018c2aff7Sartem 		int	err = 0;
49118c2aff7Sartem 
49218c2aff7Sartem 		tmpl_fd = open64(CTFS_ROOT "/process/template",
49318c2aff7Sartem 		    O_RDWR);
49418c2aff7Sartem 		if (tmpl_fd == -1)
49518c2aff7Sartem 			return (1);
49618c2aff7Sartem 
49718c2aff7Sartem 		/*
49818c2aff7Sartem 		 * Deliver no events, don't inherit,
49918c2aff7Sartem 		 * and allow it to be orphaned.
50018c2aff7Sartem 		 */
50118c2aff7Sartem 		err |= ct_tmpl_set_critical(tmpl_fd, 0);
50218c2aff7Sartem 		err |= ct_tmpl_set_informative(tmpl_fd, 0);
50318c2aff7Sartem 		err |= ct_pr_tmpl_set_fatal(tmpl_fd,
50418c2aff7Sartem 		    CT_PR_EV_HWERR);
50518c2aff7Sartem 		err |= ct_pr_tmpl_set_param(tmpl_fd,
50618c2aff7Sartem 		    CT_PR_PGRPONLY |
50718c2aff7Sartem 		    CT_PR_REGENT);
50818c2aff7Sartem 		if (err || ct_tmpl_activate(tmpl_fd)) {
50918c2aff7Sartem 			(void) close(tmpl_fd);
51018c2aff7Sartem 			return (1);
51118c2aff7Sartem 		}
51218c2aff7Sartem 		switch (pid = fork1()) {
51318c2aff7Sartem 		case 0:
51418c2aff7Sartem 			(void) ct_tmpl_clear(tmpl_fd);
51518c2aff7Sartem 			for (ifx = 0; ifx < _NFILE; ifx++)
51618c2aff7Sartem 				(void) close(ifx);
51718c2aff7Sartem 
51818c2aff7Sartem 			if (zone_enter(mnt_zoneid) == -1)
51918c2aff7Sartem 				_exit(0);
52018c2aff7Sartem 
52118c2aff7Sartem 			/* entered zone, proceed to action */
52218c2aff7Sartem 			break;
52318c2aff7Sartem 		case -1:
52418c2aff7Sartem 			dprintf("fork1 failed \n ");
52518c2aff7Sartem 			return (1);
52618c2aff7Sartem 		default :
52718c2aff7Sartem 			(void) ct_tmpl_clear(tmpl_fd);
52818c2aff7Sartem 			(void) close(tmpl_fd);
52918c2aff7Sartem 			if (waitpid(pid, &status, 0) < 0) {
53018c2aff7Sartem 				dprintf("%s(%ld): waitpid() "
53118c2aff7Sartem 				    "failed (errno %d) \n",
53218c2aff7Sartem 				    prog_name, prog_pid, errno);
53318c2aff7Sartem 				return (1);
53418c2aff7Sartem 			}
53518c2aff7Sartem 		}
53618c2aff7Sartem 	}
53718c2aff7Sartem 
53818c2aff7Sartem 	/* only support one action at a time XXX */
53918c2aff7Sartem 	a1.aa_path = NULL;
54018c2aff7Sartem 	aa[0] = aap;
54118c2aff7Sartem 	aa[1] = &a1;
54218c2aff7Sartem 
54318c2aff7Sartem 	action = aa[0]->aa_action;
54418c2aff7Sartem 
54518c2aff7Sartem 	if (action == CLEAR_MOUNTS) {
54618c2aff7Sartem 		/*
54718c2aff7Sartem 		 * Remove the notifications files, but don't
54818c2aff7Sartem 		 * notify the client.  The "clear_mounts" action
54918c2aff7Sartem 		 * simply clears all existing mounts of a medium's
55018c2aff7Sartem 		 * partitions after a medium has been repartitioned.
55118c2aff7Sartem 		 * Then vold builds a new file system that reflects
55218c2aff7Sartem 		 * the medium's new partition structure and mounts
55318c2aff7Sartem 		 * the new partitions by calling rmmount, and therefore
55418c2aff7Sartem 		 * action(), with the VOLUME_ACTION environment variable
55518c2aff7Sartem 		 * set to "remount".
55618c2aff7Sartem 		 */
55718c2aff7Sartem 		result = remove_notify_files(aa);
55818c2aff7Sartem 		result = TRUE;
55918c2aff7Sartem 	} else if (action == EJECT) {
56018c2aff7Sartem 		result = remove_notify_files(aa);
56118c2aff7Sartem 		if (result == TRUE) {
56218c2aff7Sartem 			do_notify = TRUE;
56318c2aff7Sartem 			notify_act = EJECT;
56418c2aff7Sartem 		}
56518c2aff7Sartem 	} else if (action = INSERT) {
56618c2aff7Sartem 		result = create_notify_files(aa);
56718c2aff7Sartem 		if (result == TRUE) {
56818c2aff7Sartem 			do_notify = TRUE;
56918c2aff7Sartem 			notify_act = INSERT;
57018c2aff7Sartem 		}
57118c2aff7Sartem 	} else if (action == REMOUNT) {
57218c2aff7Sartem 		result = create_notify_files(aa);
57318c2aff7Sartem 		if (result == TRUE) {
57418c2aff7Sartem 			do_notify = TRUE;
57518c2aff7Sartem 			notify_act = REMOUNT;
57618c2aff7Sartem 		}
57718c2aff7Sartem 	} else if (action == UNMOUNT) {
57818c2aff7Sartem 		result = remove_notify_files(aa);
57918c2aff7Sartem 		if (result == TRUE) {
58018c2aff7Sartem 			do_notify = TRUE;
58118c2aff7Sartem 			notify_act = UNMOUNT;
58218c2aff7Sartem 		}
58318c2aff7Sartem 	} else {
58418c2aff7Sartem 		dprintf("%s[%d]: action(): invalid action: %s\n",
58518c2aff7Sartem 		    __FILE__, __LINE__, action);
58618c2aff7Sartem 		result = FALSE;
58718c2aff7Sartem 	}
58818c2aff7Sartem 
58918c2aff7Sartem 	if (result == TRUE) {
59018c2aff7Sartem 		result = notify_clients(notify_act, do_notify);
59118c2aff7Sartem 	}
59218c2aff7Sartem 
59318c2aff7Sartem 	dprintf("%s[%d]: leaving action(), result = %s\n",
59418c2aff7Sartem 	    __FILE__, __LINE__, result_strings[result]);
59518c2aff7Sartem 
59618c2aff7Sartem 	if (mnt_zoneid > GLOBAL_ZONEID) {
59718c2aff7Sartem 		/* exit forked local zone process */
59818c2aff7Sartem 		_exit(0);
59918c2aff7Sartem 	}
60018c2aff7Sartem 
60118c2aff7Sartem 	if (result == TRUE) {
60218c2aff7Sartem 		/*
60318c2aff7Sartem 		 * File Manager is running. return 0.
60418c2aff7Sartem 		 * see man page rmmount.conf(4).
60518c2aff7Sartem 		 */
60618c2aff7Sartem 		return (0);
60718c2aff7Sartem 	} else {
60818c2aff7Sartem 		return (1);
60918c2aff7Sartem 	}
61018c2aff7Sartem }
61118c2aff7Sartem 
61218c2aff7Sartem 
61318c2aff7Sartem /*
61418c2aff7Sartem  * Returns NULL if a medium or partition is mountable
61518c2aff7Sartem  * and a string stating the reason the medium or partition
61618c2aff7Sartem  * can't be mounted if the medium or partition isn't mountable.
61718c2aff7Sartem  *
61818c2aff7Sartem  * If the volume_name of the medium or partition is one of the
61918c2aff7Sartem  * following, the medium or partition isn't mountable.
62018c2aff7Sartem  *
62118c2aff7Sartem  * unlabeled_<media_type>
62218c2aff7Sartem  * unknown_format
62318c2aff7Sartem  * password_protected
62418c2aff7Sartem  */
62518c2aff7Sartem /* ARGSUSED */
62618c2aff7Sartem static char *
not_mountable(struct action_arg * aa)62718c2aff7Sartem not_mountable(struct action_arg *aa)
62818c2aff7Sartem {
62918c2aff7Sartem 	return (NULL);
63018c2aff7Sartem }
63118c2aff7Sartem 
63218c2aff7Sartem static int
create_notify_files(struct action_arg ** aa)63318c2aff7Sartem create_notify_files(struct action_arg **aa)
63418c2aff7Sartem {
63518c2aff7Sartem 	int	ai;
63618c2aff7Sartem 	char	*fstype;
63718c2aff7Sartem 	char	*mount_point;
63818c2aff7Sartem 	char	notify_file[64];
63918c2aff7Sartem 	char	*raw_partitionp;
64018c2aff7Sartem 	char	*reason; /* Why the medium wasn't mounted */
64118c2aff7Sartem 	int	result;
64218c2aff7Sartem 	char	*symdev;
64318c2aff7Sartem 
64418c2aff7Sartem 	dprintf("%s[%d]: entering create_notify_files()\n", __FILE__, __LINE__);
64518c2aff7Sartem 
64618c2aff7Sartem 	ai = 0;
64718c2aff7Sartem 	result = FALSE;
64818c2aff7Sartem 	symdev = aa[ai]->aa_symdev;
64918c2aff7Sartem 	while ((aa[ai] != NULL) && (aa[ai]->aa_path != NULL)) {
65018c2aff7Sartem 		if (aa[ai]->aa_mountpoint != NULL) {
65118c2aff7Sartem 			if (aa[ai]->aa_type) {
65218c2aff7Sartem 				fstype = aa[ai]->aa_type;
65318c2aff7Sartem 			} else {
65418c2aff7Sartem 				fstype = "unknown";
65518c2aff7Sartem 			}
65618c2aff7Sartem 			mount_point = aa[ai]->aa_mountpoint;
65718c2aff7Sartem 			if (aa[ai]->aa_partname != NULL) {
65818c2aff7Sartem 				/*
65918c2aff7Sartem 				 * Is aa_partname ever NULL?
66018c2aff7Sartem 				 * When time permits, check.
66118c2aff7Sartem 				 * If it is, the action taken
66218c2aff7Sartem 				 * in the else clause could produce
66318c2aff7Sartem 				 * file name conflicts.
66418c2aff7Sartem 				 */
66518c2aff7Sartem 				sprintf(notify_file, "%s-%s", symdev,
66618c2aff7Sartem 				    aa[ai]->aa_partname);
66718c2aff7Sartem 			} else {
66818c2aff7Sartem 				sprintf(notify_file, "%s-0", symdev);
66918c2aff7Sartem 			}
67018c2aff7Sartem 			reason = NULL;
67118c2aff7Sartem 		} else {
67218c2aff7Sartem 			/*
67318c2aff7Sartem 			 * The partition isn't mounted.
67418c2aff7Sartem 			 */
67518c2aff7Sartem 			fstype = "none";
67618c2aff7Sartem 			mount_point = "none";
67718c2aff7Sartem 			reason = not_mountable(aa[ai]);
67818c2aff7Sartem 			if (reason != NULL) {
67918c2aff7Sartem 				sprintf(notify_file, "%s-0", symdev);
68018c2aff7Sartem 			} else {
68118c2aff7Sartem 				/*
68218c2aff7Sartem 				 * Either the partition is a backup slice, or
68318c2aff7Sartem 				 * rmmount tried to mount the partition, but
68418c2aff7Sartem 				 * idenf_fs couldn't identify the file system
68518c2aff7Sartem 				 * type; that can occur when rmmount is
68618c2aff7Sartem 				 * trying to mount all the slices in a Solaris
68718c2aff7Sartem 				 * VTOC, and one or more partitions don't have
68818c2aff7Sartem 				 * file systems in them.
68918c2aff7Sartem 				 */
69018c2aff7Sartem 				if (aa[0]->aa_partname != NULL) {
69118c2aff7Sartem 					/*
69218c2aff7Sartem 					 * Is aa_partname ever NULL?
69318c2aff7Sartem 					 * When time permits, check.
69418c2aff7Sartem 					 * If it is, the action taken
69518c2aff7Sartem 					 * in the else clause could produce
69618c2aff7Sartem 					 * file name conflicts.
69718c2aff7Sartem 					 */
69818c2aff7Sartem 					sprintf(notify_file, "%s-%s", symdev,
69918c2aff7Sartem 					    aa[0]->aa_partname);
70018c2aff7Sartem 				} else {
70118c2aff7Sartem 					sprintf(notify_file, "%s-0", symdev);
70218c2aff7Sartem 				}
70318c2aff7Sartem 				if ((aa[0]->aa_type != NULL) &&
70418c2aff7Sartem 				    (strcmp(aa[0]->aa_type, "backup_slice")
70518c2aff7Sartem 				    == 0)) {
70618c2aff7Sartem 					reason = "backup_slice";
70718c2aff7Sartem 				} else {
70818c2aff7Sartem 					reason = "unformatted_media";
70918c2aff7Sartem 				}
71018c2aff7Sartem 				/*
71118c2aff7Sartem 				 * "unformatted_media" should be
71218c2aff7Sartem 				 * changed to "unformmated_medium" for
71318c2aff7Sartem 				 * grammatical correctness, but
71418c2aff7Sartem 				 * "unformatted_media" is now specified
71518c2aff7Sartem 				 * in the interface to filemgr, so the
71618c2aff7Sartem 				 * change can't be made without the
71718c2aff7Sartem 				 * approval of the CDE group.
71818c2aff7Sartem 				 */
71918c2aff7Sartem 			}
72018c2aff7Sartem 		}
72118c2aff7Sartem 		raw_partitionp = aa[0]->aa_rawpath;
72218c2aff7Sartem 		result = create_one_notify_file(fstype,
72318c2aff7Sartem 		    mount_point,
72418c2aff7Sartem 		    notify_file,
72518c2aff7Sartem 		    raw_partitionp,
72618c2aff7Sartem 		    reason,
72718c2aff7Sartem 		    symdev);
72818c2aff7Sartem 		ai++;
72918c2aff7Sartem 	}
73018c2aff7Sartem 	dprintf("%s[%d]: leaving create_notify_files(), result = %s\n",
73118c2aff7Sartem 	    __FILE__, __LINE__, result_strings[result]);
73218c2aff7Sartem 	return (result);
73318c2aff7Sartem }
73418c2aff7Sartem 
73518c2aff7Sartem static int
create_one_notify_file(char * fstype,char * mount_point,char * notify_file,char * raw_partitionp,char * reason,char * symdev)73618c2aff7Sartem create_one_notify_file(char *fstype,
73718c2aff7Sartem 	char *mount_point,
73818c2aff7Sartem 	char *notify_file,
73918c2aff7Sartem 	char *raw_partitionp,
74018c2aff7Sartem 	char *reason,
74118c2aff7Sartem 	char *symdev)
74218c2aff7Sartem {
74318c2aff7Sartem 	/*
74418c2aff7Sartem 	 * For a mounted partition, create a notification file
74518c2aff7Sartem 	 * indicating the mount point,  the raw device pathname
74618c2aff7Sartem 	 * of the partition, and the partition's file system
74718c2aff7Sartem 	 * type.  For an unmounted partition, create a
74818c2aff7Sartem 	 * notification file containing the reason that the
74918c2aff7Sartem 	 * partition wasn't mounted and the raw device pathname
75018c2aff7Sartem 	 * of the partition.
75118c2aff7Sartem 	 *
75218c2aff7Sartem 	 * Create the file as root in a world-writable
75318c2aff7Sartem 	 * directory that resides in a world-writable directory.
75418c2aff7Sartem 	 *
75518c2aff7Sartem 	 * Handle two possible race conditions that could
75618c2aff7Sartem 	 * allow security breaches.
75718c2aff7Sartem 	 */
75818c2aff7Sartem 
75918c2aff7Sartem 	int	current_working_dir_fd;
76018c2aff7Sartem 	int	file_descriptor;
76118c2aff7Sartem 	FILE	*filep;
76218c2aff7Sartem 	int	result;
76318c2aff7Sartem 
76418c2aff7Sartem 	dprintf("%s[%d]:Entering create_one_notify_file()\n",
76518c2aff7Sartem 	    __FILE__, __LINE__);
76618c2aff7Sartem 	dprintf("\tcreate_one_notify_file(): fstype = %s\n", fstype);
76718c2aff7Sartem 	dprintf("\tcreate_one_notify_file(): mount_point = %s\n", mount_point);
76818c2aff7Sartem 	dprintf("\tcreate_one_notify_file(): notify_file = %s\n", notify_file);
76918c2aff7Sartem 	dprintf("\tcreate_one_notify_file(): raw_partitionp = %s\n",
77018c2aff7Sartem 	    raw_partitionp);
77118c2aff7Sartem 	if (reason != NULL) {
77218c2aff7Sartem 		dprintf("\tcreate_one_notify_file(): reason = %s\n", reason);
77318c2aff7Sartem 	} else {
77418c2aff7Sartem 		dprintf("\tcreate_one_notify_file(): reason = NULL\n");
77518c2aff7Sartem 	}
77618c2aff7Sartem 	dprintf("\tcreate_one_notify_file(): symdev = %s\n", symdev);
77718c2aff7Sartem 
77818c2aff7Sartem 	result = TRUE;
77918c2aff7Sartem 	/*
78018c2aff7Sartem 	 * Handle Race Condition One:
78118c2aff7Sartem 	 *
78218c2aff7Sartem 	 *   If NOTIFY_DIR exists, make sure it is not a symlink.
78318c2aff7Sartem 	 *   if it is, remove it and try to create it.  Check
78418c2aff7Sartem 	 *   again to make sure NOTIFY_DIR isn't a symlink.
78518c2aff7Sartem 	 *   If it is, remove it and return without creating
78618c2aff7Sartem 	 *   a notification file.  The condition can only occur if
78718c2aff7Sartem 	 *   someone is trying to break into the system by running
78818c2aff7Sartem 	 *   a program that repeatedly creates NOTIFY_DIR as a
78918c2aff7Sartem 	 *   symlink.  If NOTIFY_DIR exists and isn't a symlink,
79018c2aff7Sartem 	 *   change the working directory to NOTIFY_DIR.
79118c2aff7Sartem 	 */
79218c2aff7Sartem 	current_working_dir_fd = pushdir(NOTIFY_DIR);
79318c2aff7Sartem 	if (current_working_dir_fd < 0) {
79418c2aff7Sartem 		(void) makepath(NOTIFY_DIR, 0777);
79518c2aff7Sartem 		current_working_dir_fd = pushdir(NOTIFY_DIR);
79618c2aff7Sartem 		if (current_working_dir_fd < 0) {
79718c2aff7Sartem 			result = FALSE;
79818c2aff7Sartem 		}
79918c2aff7Sartem 	}
80018c2aff7Sartem 	/*
80118c2aff7Sartem 	 * Handle Race Condition Two:
80218c2aff7Sartem 	 *
80318c2aff7Sartem 	 * Create the notification file in NOTIFY_DIR.
80418c2aff7Sartem 	 * Remove any files with the same name that may already be
80518c2aff7Sartem 	 * there, using remove(), as it safely removes directories.
80618c2aff7Sartem 	 * Then open the file O_CREAT|O_EXCL, which doesn't follow
80718c2aff7Sartem 	 * symlinks and requires that the file not exist already,
80818c2aff7Sartem 	 * so the new file actually resides in the current working
80918c2aff7Sartem 	 * directory.  Create the file with access mode 644, which
81018c2aff7Sartem 	 * renders it unusable by anyone trying to break into the
81118c2aff7Sartem 	 * system.
81218c2aff7Sartem 	 */
81318c2aff7Sartem 	if (result == TRUE) {
81418c2aff7Sartem 		/*
81518c2aff7Sartem 		 * The current working directory is now NOTIFY_DIR.
81618c2aff7Sartem 		 */
81718c2aff7Sartem 		(void) remove(notify_file);
81818c2aff7Sartem 		file_descriptor =
81918c2aff7Sartem 		    open(notify_file, O_CREAT|O_EXCL|O_WRONLY, 0644);
82018c2aff7Sartem 		if (file_descriptor < 0) {
82118c2aff7Sartem 			dprintf("%s[%d]: can't create %s/%s; %m\n",
82218c2aff7Sartem 			    __FILE__, __LINE__, NOTIFY_DIR, notify_file);
82318c2aff7Sartem 			result = FALSE;
82418c2aff7Sartem 		} else {
82518c2aff7Sartem 			filep = fdopen(file_descriptor, "w");
82618c2aff7Sartem 			if (filep != NULL) {
82718c2aff7Sartem 				if (reason == NULL) {
82818c2aff7Sartem 					(void) fprintf(filep, "%s %s %s",
82918c2aff7Sartem 					    mount_point,
83018c2aff7Sartem 					    raw_partitionp,
83118c2aff7Sartem 					    fstype);
83218c2aff7Sartem 					(void) fclose(filep);
83318c2aff7Sartem 				dprintf("%s[%d]: Just wrote %s %s %s to %s\n",
83418c2aff7Sartem 				    __FILE__,
83518c2aff7Sartem 				    __LINE__,
83618c2aff7Sartem 				    mount_point,
83718c2aff7Sartem 				    raw_partitionp,
83818c2aff7Sartem 				    fstype,
83918c2aff7Sartem 				    notify_file);
84018c2aff7Sartem 				} else {
84118c2aff7Sartem 					(void) fprintf(filep, "%s %s",
84218c2aff7Sartem 					    reason, raw_partitionp);
84318c2aff7Sartem 					(void) fclose(filep);
84418c2aff7Sartem 				dprintf("%s[%d]: Just wrote %s %s to %s\n",
84518c2aff7Sartem 				    __FILE__,
84618c2aff7Sartem 				    __LINE__,
84718c2aff7Sartem 				    reason,
84818c2aff7Sartem 				    raw_partitionp,
84918c2aff7Sartem 				    notify_file);
85018c2aff7Sartem 				}
85118c2aff7Sartem 			} else {
85218c2aff7Sartem 				dprintf("%s[%d]: can't write %s/%s; %m\n",
85318c2aff7Sartem 				    __FILE__, __LINE__,
85418c2aff7Sartem 				    NOTIFY_DIR, notify_file);
85518c2aff7Sartem 				(void) close(file_descriptor);
85618c2aff7Sartem 				result = FALSE;
85718c2aff7Sartem 			}
85818c2aff7Sartem 		}
85918c2aff7Sartem 		popdir(current_working_dir_fd);
86018c2aff7Sartem 	}
86118c2aff7Sartem 	dprintf("%s[%d]: leaving create_one_notify_file, result = %s\n",
86218c2aff7Sartem 	    __FILE__, __LINE__, result_strings[result]);
86318c2aff7Sartem 	return (result);
86418c2aff7Sartem }
86518c2aff7Sartem 
86618c2aff7Sartem static boolean_t
notify_clients(action_t action,int do_notify)86718c2aff7Sartem notify_clients(action_t action, int do_notify)
86818c2aff7Sartem {
86918c2aff7Sartem 	/*
87018c2aff7Sartem 	 * Notify interested applications of changes in the state
87118c2aff7Sartem 	 * of removable media.  Interested applications are those
87218c2aff7Sartem 	 * that create a named pipe in NOTIFY_DIR with a name that
87318c2aff7Sartem 	 * begins with "notify".  Open the pipe and write a
87418c2aff7Sartem 	 * character through it that indicates the type of state
87518c2aff7Sartem 	 * change = 'e' for ejections, 'i' for insertions, 'r'
87618c2aff7Sartem 	 * for remounts of the file systems on repartitioned media,
87718c2aff7Sartem 	 * and 'u' for unmounts of file systems.
87818c2aff7Sartem 	 */
87918c2aff7Sartem 
88018c2aff7Sartem 	int		current_working_dir_fd;
88118c2aff7Sartem 	DIR		*dirp;
88218c2aff7Sartem 	struct dirent	*dir_entryp;
88318c2aff7Sartem 	size_t		len;
88418c2aff7Sartem 	int		fd;
88518c2aff7Sartem 	char		namebuf[MAXPATHLEN];
88618c2aff7Sartem 	char		notify_character;
88718c2aff7Sartem 	void		(*old_signal_handler)();
88818c2aff7Sartem 	int		result;
88918c2aff7Sartem 	struct stat	sb;
89018c2aff7Sartem 
89118c2aff7Sartem 	dprintf("%s[%d]: entering notify_clients()\n", __FILE__, __LINE__);
89218c2aff7Sartem 
89318c2aff7Sartem 	result = TRUE;
89418c2aff7Sartem 	/*
89518c2aff7Sartem 	 * Use relative pathnames after changing the
89618c2aff7Sartem 	 * working directory to the notification directory.
89718c2aff7Sartem 	 * Check to make sure that each "notify" file is a
89818c2aff7Sartem 	 * named pipe to make sure that it hasn't changed
89918c2aff7Sartem 	 * its file type, which could mean that someone is
90018c2aff7Sartem 	 * trying to use "notify" files to break into the
90118c2aff7Sartem 	 * system.
90218c2aff7Sartem 	 */
90318c2aff7Sartem 	if ((current_working_dir_fd = pushdir(NOTIFY_DIR)) < 0) {
90418c2aff7Sartem 		result = FALSE;
90518c2aff7Sartem 	}
90618c2aff7Sartem 	if (result == TRUE) {
90718c2aff7Sartem 		dirp = opendir(".");
90818c2aff7Sartem 		if (dirp == NULL) {
90918c2aff7Sartem 			dprintf("%s[%d]:opendir failed on '.'; %m\n",
91018c2aff7Sartem 			    __FILE__, __LINE__);
91118c2aff7Sartem 			popdir(current_working_dir_fd);
91218c2aff7Sartem 			result = FALSE;
91318c2aff7Sartem 		}
91418c2aff7Sartem 	}
91518c2aff7Sartem 	if (result == TRUE) {
91618c2aff7Sartem 		/*
91718c2aff7Sartem 		 * Read through the directory and write a notify
91818c2aff7Sartem 		 * character to all files whose names start with "notify".
91918c2aff7Sartem 		 */
92018c2aff7Sartem 		result = FALSE;
92118c2aff7Sartem 		old_signal_handler = signal(SIGPIPE, SIG_IGN);
92218c2aff7Sartem 		len = strlen(NOTIFY_NAME);
92318c2aff7Sartem 		while (dir_entryp = readdir(dirp)) {
92418c2aff7Sartem 			if (strncmp(dir_entryp->d_name, NOTIFY_NAME, len)
92518c2aff7Sartem 			    != 0) {
92618c2aff7Sartem 				continue;
92718c2aff7Sartem 			}
92818c2aff7Sartem 			result = TRUE;
92918c2aff7Sartem 			if (do_notify != TRUE) {
93018c2aff7Sartem 				continue;
93118c2aff7Sartem 			}
93218c2aff7Sartem 			(void) sprintf(namebuf, "%s/%s",
93318c2aff7Sartem 			    NOTIFY_DIR, dir_entryp->d_name);
93418c2aff7Sartem 			if ((fd = open(namebuf, O_WRONLY|O_NDELAY)) < 0) {
93518c2aff7Sartem 				dprintf("%s[%d]: open failed for %s; %m\n",
93618c2aff7Sartem 				    __FILE__, __LINE__, namebuf);
93718c2aff7Sartem 				continue;
93818c2aff7Sartem 			}
93918c2aff7Sartem 			/*
94018c2aff7Sartem 			 * Check to be sure that the entry is a named pipe.
94118c2aff7Sartem 			 * That closes a small security hole that could
94218c2aff7Sartem 			 * enable unauthorized access to the system root.
94318c2aff7Sartem 			 */
94418c2aff7Sartem 			if ((fstat(fd, &sb) < 0) || (!S_ISFIFO(sb.st_mode))) {
94518c2aff7Sartem 				dprintf("%s[%d]: %s isn't a named pipe\n",
94618c2aff7Sartem 				    __FILE__, __LINE__, namebuf);
94718c2aff7Sartem 
94818c2aff7Sartem 				(void) close(fd);
94918c2aff7Sartem 				continue;
95018c2aff7Sartem 			}
95118c2aff7Sartem 			notify_character = notify_characters[action];
95218c2aff7Sartem 			if (write(fd, &notify_character, 1) < 0) {
95318c2aff7Sartem 				dprintf("%s[%d]: write failed for %s; %m\n",
95418c2aff7Sartem 				    __FILE__, __LINE__, namebuf);
95518c2aff7Sartem 				(void) close(fd);
95618c2aff7Sartem 				continue;
95718c2aff7Sartem 			}
95818c2aff7Sartem 			(void) close(fd);
95918c2aff7Sartem 		}
96018c2aff7Sartem 		(void) closedir(dirp);
96118c2aff7Sartem 		(void) signal(SIGPIPE, old_signal_handler);
96218c2aff7Sartem 		popdir(current_working_dir_fd);
96318c2aff7Sartem 	}
96418c2aff7Sartem 	dprintf("%s[%d]: leaving notify_clients(), result = %s\n",
96518c2aff7Sartem 	    __FILE__, __LINE__, result_strings[result]);
96618c2aff7Sartem 	return (result);
96718c2aff7Sartem }
96818c2aff7Sartem 
96918c2aff7Sartem static void
popdir(int fd)97018c2aff7Sartem popdir(int fd)
97118c2aff7Sartem {
97218c2aff7Sartem 	/*
97318c2aff7Sartem 	 * Change the current working directory to the directory
97418c2aff7Sartem 	 * specified by fd and close the fd.  Exit the program
97518c2aff7Sartem 	 * on failure.
97618c2aff7Sartem 	 */
97718c2aff7Sartem 	if (fchdir(fd) < 0) {
97818c2aff7Sartem 		dprintf("%s[%d]: popdir() failed\n", __FILE__, __LINE__);
97918c2aff7Sartem 		exit(1);
98018c2aff7Sartem 	}
98118c2aff7Sartem 	(void) close(fd);
98218c2aff7Sartem }
98318c2aff7Sartem 
98418c2aff7Sartem static int
pushdir(const char * dir)98518c2aff7Sartem pushdir(const char *dir)
98618c2aff7Sartem {
98718c2aff7Sartem 	/*
98818c2aff7Sartem 	 * Change the current working directory to dir and
98918c2aff7Sartem 	 * return a file descriptor for the old working
99018c2aff7Sartem 	 * directory.
99118c2aff7Sartem 	 *
99218c2aff7Sartem 	 * Exception handling:
99318c2aff7Sartem 	 *
99418c2aff7Sartem 	 * If dir doesn't exist, leave the current working
99518c2aff7Sartem 	 * directory the same and return -1.
99618c2aff7Sartem 	 *
99718c2aff7Sartem 	 * If dir isn't a directory, remove it, leave the
99818c2aff7Sartem 	 * current working directory the same, and return -1.
99918c2aff7Sartem 	 *
100018c2aff7Sartem 	 * If open() fails on the current working directory
100118c2aff7Sartem 	 * or the chdir operation fails on dir, leave the
100218c2aff7Sartem 	 * current working directory the same and return -1.
100318c2aff7Sartem 	 */
100418c2aff7Sartem 
100518c2aff7Sartem 	int		current_working_dir_fd;
100618c2aff7Sartem 	struct stat	stat_buf;
100718c2aff7Sartem 
100818c2aff7Sartem 	if (lstat(dir, &stat_buf) < 0) {
100918c2aff7Sartem 		dprintf("%s[%d]: push_dir_and_check(): %s does not exist\n",
101018c2aff7Sartem 		    __FILE__, __LINE__, dir);
101118c2aff7Sartem 		return (-1);
101218c2aff7Sartem 	}
101318c2aff7Sartem 
101418c2aff7Sartem 	if (!(S_ISDIR(stat_buf.st_mode))) {
101518c2aff7Sartem 		dprintf("%s[%d]: push_dir_and_check(): %s not a directory.\n",
101618c2aff7Sartem 		    __FILE__, __LINE__, dir);
101718c2aff7Sartem 		(void) remove(dir);
101818c2aff7Sartem 		return (-1);
101918c2aff7Sartem 	}
102018c2aff7Sartem 	if ((current_working_dir_fd = open(".", O_RDONLY)) < 0) {
102118c2aff7Sartem 		dprintf("%s[%d]: push_dir_and_check(): can't open %s.\n",
102218c2aff7Sartem 		    __FILE__, __LINE__, dir);
102318c2aff7Sartem 		return (-1);
102418c2aff7Sartem 	}
102518c2aff7Sartem 	if (chdir(dir) < 0) {
102618c2aff7Sartem 		(void) close(current_working_dir_fd);
102718c2aff7Sartem 		dprintf("%s[%d]: push_dir_and_check(): can't chdir() to %s.\n",
102818c2aff7Sartem 		    __FILE__, __LINE__, dir);
102918c2aff7Sartem 		return (-1);
103018c2aff7Sartem 	}
103118c2aff7Sartem 	return (current_working_dir_fd);
103218c2aff7Sartem }
103318c2aff7Sartem 
103418c2aff7Sartem static boolean_t
remove_notify_files(struct action_arg ** aa)103518c2aff7Sartem remove_notify_files(struct action_arg **aa)
103618c2aff7Sartem {
103718c2aff7Sartem 	int	ai;
103818c2aff7Sartem 	int	current_working_dir_fd;
103918c2aff7Sartem 	char	notify_file[64];
104018c2aff7Sartem 	int	result;
104118c2aff7Sartem 	char	*symdev;
104218c2aff7Sartem 
104318c2aff7Sartem 	dprintf("%s[%d]: entering remove_notify_files()\n", __FILE__, __LINE__);
104418c2aff7Sartem 
104518c2aff7Sartem 	ai = 0;
104618c2aff7Sartem 	result = TRUE;
104718c2aff7Sartem 	symdev = aa[ai]->aa_symdev;
104818c2aff7Sartem 	while ((result == TRUE) &&
104918c2aff7Sartem 	    (aa[ai] != NULL) &&
105018c2aff7Sartem 	    (aa[ai]->aa_path != NULL)) {
105118c2aff7Sartem 
105218c2aff7Sartem 		if (not_mountable(aa[ai])) {
105318c2aff7Sartem 			sprintf(notify_file, "%s-0", symdev);
105418c2aff7Sartem 		} else if (aa[ai]->aa_partname != NULL) {
105518c2aff7Sartem 			/*
105618c2aff7Sartem 			 * Is aa_partname ever NULL?
105718c2aff7Sartem 			 * When time permits, check.
105818c2aff7Sartem 			 * If it is, the action taken
105918c2aff7Sartem 			 * in the else clause could produce
106018c2aff7Sartem 			 * file name conflicts.
106118c2aff7Sartem 			 */
106218c2aff7Sartem 			sprintf(notify_file, "%s-%s",
106318c2aff7Sartem 			    symdev, aa[0]->aa_partname);
106418c2aff7Sartem 		} else {
106518c2aff7Sartem 			sprintf(notify_file, "%s-0", symdev);
106618c2aff7Sartem 		}
106718c2aff7Sartem 
106818c2aff7Sartem 		current_working_dir_fd = pushdir(NOTIFY_DIR);
106918c2aff7Sartem 		if (current_working_dir_fd < 0) {
107018c2aff7Sartem 			result = FALSE;
107118c2aff7Sartem 		}
107218c2aff7Sartem 		if ((result == TRUE) && (remove(notify_file) < 0)) {
107318c2aff7Sartem 			dprintf("%s[%d]: remove %s/%s; %m\n",
107418c2aff7Sartem 			    __FILE__, __LINE__, NOTIFY_DIR, notify_file);
107518c2aff7Sartem 			result = FALSE;
107618c2aff7Sartem 		}
107718c2aff7Sartem 		if (current_working_dir_fd != -1) {
107818c2aff7Sartem 			popdir(current_working_dir_fd);
107918c2aff7Sartem 		}
108018c2aff7Sartem 		ai++;
108118c2aff7Sartem 	}
108218c2aff7Sartem 	dprintf("%s[%d]: leaving remove_notify_files(), result = %s\n",
108318c2aff7Sartem 	    __FILE__, __LINE__, result_strings[result]);
108418c2aff7Sartem 
108518c2aff7Sartem 	return (result);
108618c2aff7Sartem }
1087