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