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