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