1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 /* 29 * routines in this module are meant to be called by other libvolmgt 30 * routines only 31 */ 32 33 #include <stdio.h> 34 #include <string.h> 35 #include <dirent.h> 36 #include <fcntl.h> 37 #include <string.h> 38 #ifdef DEBUG 39 #include <errno.h> 40 #endif 41 #include <libintl.h> 42 #include <limits.h> 43 #include <unistd.h> 44 #include <stdlib.h> 45 #include <volmgt.h> 46 #include <sys/types.h> 47 #include <sys/mkdev.h> 48 #include <sys/stat.h> 49 #include <sys/dkio.h> 50 #include <sys/param.h> 51 #include <sys/wait.h> 52 #include <sys/mnttab.h> 53 #include <sys/vol.h> 54 #include "volmgt_private.h" 55 56 57 #define NULL_PATH "/dev/null" 58 59 60 61 /* 62 * This is an ON Consolidation Private interface. 63 * 64 * Is the specified path mounted? 65 * 66 * This function is really inadequate for ejection testing. For example, 67 * I could have /dev/fd0a mounted and eject /dev/fd0c, and it would be 68 * ejected. There needs to be some better way to make this check, although 69 * short of looking up the mounted dev_t in the kernel mount table and 70 * building in all kinds of knowledge into this function, I'm not sure 71 * how to do it. 72 */ 73 int 74 _dev_mounted(char *path) 75 { 76 static int vol_getmntdev(FILE *, struct mnttab *, dev_t, 77 struct dk_cinfo *); 78 int fd = -1; 79 struct dk_cinfo info; 80 static FILE *fp = NULL; /* mnttab file pointer */ 81 struct mnttab mnt; /* set bug not used */ 82 char *cn = NULL; /* char spcl pathname */ 83 struct stat64 sb; 84 int ret_val = 0; 85 86 87 88 #ifdef DEBUG 89 denter("_dev_mounted(%s): entering\n", path); 90 #endif 91 92 /* ensure we have the block spcl pathname */ 93 if ((cn = (char *)volmgt_getfullrawname(path)) == NULL) { 94 #ifdef DEBUG 95 dprintf("_dev_mounted: volmgt_getfullrawname failed\n"); 96 #endif 97 goto dun; 98 } 99 100 #ifdef DEBUG_OPEN 101 dprintf("_dev_mounted: fopen()ing \"%s\"\n", MNTTAB); 102 #endif 103 if ((fp = fopen(MNTTAB, "rF")) == NULL) { 104 /* mtab is gone... let him go */ 105 #ifdef DEBUG 106 perror(MNTTAB); 107 #endif 108 goto dun; 109 } 110 111 #ifdef DEBUG_OPEN 112 dprintf("_dev_mounted: open()ing \"%s\"\n", cn); 113 #endif 114 if ((fd = open(cn, O_RDONLY|O_NDELAY)) < 0) { 115 #ifdef DEBUG 116 dprintf("_dev_mounted: can't open \"%s\" (%d)\n", cn, errno); 117 #endif 118 goto dun; 119 } 120 121 #ifdef DEBUG_STAT 122 dprintf("_dev_mounted: fstat()ing \"%s\"\n", cn); 123 #endif 124 if (fstat64(fd, &sb) < 0) { 125 #ifdef DEBUG 126 dprintf("_dev_mounted: stat of \"%s\" failed (%d)\n", cn, 127 errno); 128 #endif 129 goto dun; 130 } 131 132 #ifdef DEBUG_IOCTL 133 dprintf("_dev_mounted: ioctl(%s, DKIOCINFO)\n", cn); 134 #endif 135 if (ioctl(fd, DKIOCINFO, &info) != 0) { 136 #ifdef DEBUG 137 dprintf( 138 "_dev_mounted: ioctl(DKIOCINFO) on \"%s\" failed (%d)\n", 139 cn, errno); 140 #endif 141 goto dun; 142 } 143 144 if (vol_getmntdev(fp, &mnt, sb.st_rdev, &info) != 0) { 145 ret_val = 1; /* match found! */ 146 } 147 148 dun: 149 if (cn != NULL) { 150 free(cn); 151 } 152 if (fp != NULL) { 153 (void) fclose(fp); 154 } 155 if (fd >= 0) { 156 (void) close(fd); 157 } 158 #ifdef DEBUG 159 dexit("_dev_mounted: returning %s\n", 160 ret_val ? "TRUE" : "FALSE"); 161 #endif 162 return (ret_val); 163 } 164 165 166 /* 167 * This is an ON Consolidation Private interface. 168 * 169 * Forks off rmmount and (in essence) returns the result 170 * 171 * a return value of 0 (FALSE) means failure, non-zero (TRUE) means success 172 */ 173 int 174 _dev_unmount(char *path) 175 { 176 static int call_unmount_prog(int, int, char *, int, char *, 177 char *); 178 static int get_media_info(char *, char **, int *, char **); 179 char *bn = NULL; /* block name */ 180 char *mtype = NULL; /* media type */ 181 char *spcl = NULL; /* special dev. path */ 182 char *spcl_failed = NULL; /* spcl that failed */ 183 int ret_val = FALSE; /* what we return */ 184 char *vr; /* volmgt root dir */ 185 int media_info_gotten = 0; 186 int mnum = 0; 187 int volume_is_not_managed; 188 char *pathbuf, *absname; 189 190 #ifdef DEBUG 191 denter("_dev_unmount(%s): entering\n", path); 192 #endif 193 194 if ((bn = (char *)volmgt_getfullblkname(path)) == NULL) { 195 #ifdef DEBUG 196 dprintf("_dev_unmount: volmgt_getfullblkname failed\n"); 197 #endif 198 goto dun; 199 } 200 201 if ((pathbuf = malloc(PATH_MAX+1)) == NULL) 202 goto dun; 203 204 absname = bn; 205 if (realpath(bn, pathbuf) != NULL) 206 absname = pathbuf; 207 208 volume_is_not_managed = !volmgt_running() || 209 (!volmgt_ownspath(absname) && volmgt_symname(bn) == NULL); 210 211 free(pathbuf); 212 213 /* decide of we should use rmmount to unmount the media */ 214 if (!volume_is_not_managed) { 215 int use_rmm = FALSE; /* use rmmount?? */ 216 217 /* at least volmgt is running */ 218 vr = (char *)volmgt_root(); 219 if (strncmp(bn, vr, strlen(vr)) == 0) { 220 /* the block path is rooted in /vol */ 221 use_rmm = TRUE; 222 } 223 224 /* try to get info about media */ 225 media_info_gotten = get_media_info(bn, &mtype, &mnum, &spcl); 226 227 ret_val = call_unmount_prog(media_info_gotten, use_rmm, mtype, 228 mnum, spcl, bn); 229 230 } else { 231 232 /* volmgt is *not* running */ 233 234 if (get_media_info(bn, &mtype, &mnum, &spcl)) { 235 236 /* 237 * volmgt is off and get_media_info() has returned 238 * info on the media -- soo (this is kinda' a hack) 239 * ... we iterate, looking for multiple slices 240 * of (say) a floppy being mounted 241 * 242 * note: if an unmount fails we don't want to try 243 * to unmount the same device on the next try, so 244 * we try to watch for that 245 */ 246 247 do { 248 /* 249 * don't call the unmount program is we're just 250 * trying to unmount the same device that 251 * failed last time -- if that's the case, 252 * then bail 253 */ 254 if (spcl_failed != NULL) { 255 if (strcmp(spcl, spcl_failed) == 0) { 256 break; 257 } 258 } 259 ret_val = call_unmount_prog(TRUE, FALSE, 260 mtype, mnum, spcl, bn); 261 262 if (!ret_val) { 263 /* save spcl device name that failed */ 264 spcl_failed = strdup(spcl); 265 } else { 266 /* 267 * unmount succeeded, so clean up 268 */ 269 if (spcl_failed != NULL) { 270 free(spcl_failed); 271 spcl_failed = NULL; 272 } 273 } 274 275 } while (get_media_info(bn, &mtype, &mnum, &spcl)); 276 277 } else { 278 279 /* just do the unmmount cycle once */ 280 ret_val = call_unmount_prog(FALSE, FALSE, NULL, 0, 281 NULL, bn); 282 } 283 284 } 285 286 if (mtype != NULL) { 287 free(mtype); 288 } 289 if (spcl != NULL) { 290 free(spcl); 291 } 292 if (spcl_failed != NULL) { 293 free(spcl_failed); 294 } 295 if (bn != NULL) { 296 free(bn); 297 } 298 299 dun: 300 301 #ifdef DEBUG 302 dexit("_dev_unmount: returning %s\n", ret_val ? "TRUE" : "FALSE"); 303 #endif 304 return (ret_val); 305 } 306 307 308 /* 309 * find a mnttab entry that has the same dev as the supplied dev, 310 * returning it and a non-zero value if found, else returning 0 311 * 312 * this is just like getmntany(), except that it scans based on st_rdev, 313 * and it even finds different slices on the same device/unit (thanx to 314 * code copied from format.c) 315 */ 316 static int 317 vol_getmntdev(FILE *fp, struct mnttab *mp, dev_t dev, struct dk_cinfo *ip) 318 { 319 int fd; /* dev-in-question fd */ 320 struct stat64 sb; /* dev-in-question stat struct */ 321 int ret_val = 0; /* default value: no match found */ 322 char *cn; /* char pathname */ 323 struct dk_cinfo dkinfo; /* for testing for slices */ 324 325 326 #ifdef DEBUG 327 denter( 328 "vol_getmntdev: entering for %d.%d, ctype/cnum/unit = %d/%d/%d\n", 329 (int)major(dev), (int)minor(dev), ip->dki_ctype, ip->dki_cnum, 330 ip->dki_unit); 331 #endif 332 333 /* reset the mnttab -- just in case */ 334 rewind(fp); 335 336 /* scan each entry in mnttab */ 337 while (getmntent(fp, mp) == 0) { 338 339 /* don't even try unless it's a local pathname */ 340 if (mp->mnt_special[0] != '/') { 341 continue; 342 } 343 344 /* get char pathname */ 345 if ((cn = volmgt_getfullrawname(mp->mnt_special)) == NULL) { 346 continue; 347 } 348 if (cn[0] == NULLC) { 349 free(cn); 350 continue; /* couldn't get raw name */ 351 } 352 353 /* open the device */ 354 #ifdef DEBUG_OPEN 355 dprintf("vol_getmntdev: open()ing \"%s\"\n", cn); 356 #endif 357 if ((fd = open(cn, O_RDONLY|O_NDELAY)) < 0) { 358 /* if we can't open it *assume* it's not a match */ 359 #ifdef DEBUG 360 dprintf( 361 "vol_getmntdev: open of \"%s\" (%s) failed (%d)\n", 362 cn, mp->mnt_fstype, errno); 363 #endif 364 free(cn); 365 continue; 366 } 367 368 /* stat the device */ 369 #ifdef DEBUG_STAT 370 dprintf("vol_getmntdev: fstat()ing \"%s\"\n", cn); 371 #endif 372 if (fstat64(fd, &sb) < 0) { 373 #ifdef DEBUG 374 dprintf( 375 "vol_getmntdev: stat of \"%s\" (%s) failed (%d)\n", 376 cn, mp->mnt_fstype, errno); 377 #endif 378 free(cn); 379 (void) close(fd); 380 continue; /* ain't there: can't be a match */ 381 } 382 383 /* ensure we have a spcl device (a double check) */ 384 if (!S_ISBLK(sb.st_mode) && !S_ISCHR(sb.st_mode)) { 385 #ifdef DEBUG 386 dprintf( 387 "vol_getmntdev: \"%s\" not a blk- or chr-spcl device\n", 388 cn); 389 #endif 390 free(cn); 391 (void) close(fd); 392 continue; 393 } 394 395 /* (almost) finally -- check the dev_t for equality */ 396 if (sb.st_rdev == dev) { 397 ret_val = 1; /* match found! */ 398 free(cn); 399 (void) close(fd); 400 break; 401 } 402 403 /* 404 * check that the major numbers match, since if they 405 * don't then there's no reason to use the DKIOCINFO 406 * ioctl to see if we have to major/minor pairs that 407 * really point to the same device 408 */ 409 if (major(sb.st_rdev) != major(dev)) { 410 /* no use continuing, since major devs are different */ 411 free(cn); 412 (void) close(fd); 413 continue; 414 } 415 416 #ifdef DEBUG_IOCTL 417 dprintf("vol_getmntdev: ioctl(%s, DKIOCINFO)\n", cn); 418 #endif 419 /* one last check -- for diff. slices of the same dev/unit */ 420 if (ioctl(fd, DKIOCINFO, &dkinfo) < 0) { 421 #ifdef DEBUG 422 dprintf( 423 "vol_getmntdev: ioctl(DKIOCINFO) of \"%s\" failed (%d)\n", 424 cn, errno); 425 #endif 426 free(cn); 427 (void) close(fd); 428 continue; 429 } 430 431 free(cn); /* all done with raw pathname */ 432 (void) close(fd); /* all done with file descriptor */ 433 434 /* if ctrler type/number and unit match, it's a match */ 435 if ((ip->dki_ctype == dkinfo.dki_ctype) && 436 (ip->dki_cnum == dkinfo.dki_cnum) && 437 (ip->dki_unit == dkinfo.dki_unit)) { 438 /* 439 * even though minor numbers differ we have a 440 * match 441 */ 442 ret_val = 1; 443 break; 444 } 445 446 /* go around again */ 447 } 448 449 #ifdef DEBUG 450 dexit("vol_getmntdev: returning %d (%s)\n", ret_val, 451 ret_val == 1 ? "SUCCESS" : "FAILURE"); 452 #endif 453 return (ret_val); 454 } 455 456 457 char * 458 vol_basename(char *path) 459 { 460 char *cp; 461 462 463 /* check for the degenerate case */ 464 if (strcmp(path, "/") == 0) { 465 return (path); 466 } 467 468 /* look for the last slash in the name */ 469 if ((cp = strrchr(path, '/')) == NULL) { 470 /* no slash */ 471 return (path); 472 } 473 474 /* ensure something is after the slash */ 475 if (*++cp != NULLC) { 476 return (cp); 477 } 478 479 /* a name that ends in slash -- back up until previous slash */ 480 while (cp != path) { 481 if (*--cp == '/') { 482 return (--cp); 483 } 484 } 485 486 /* the only slash is the end of the name */ 487 return (path); 488 } 489 490 491 static int 492 get_media_info(char *path, char **mtypep, int *mnump, char **spclp) 493 { 494 static int vol_getmntdev(FILE *, struct mnttab *, dev_t, 495 struct dk_cinfo *); 496 FILE *fp = NULL; 497 int fd = -1; 498 char *cn = NULL; /* char spcl pathname */ 499 struct stat64 sb; 500 struct dk_cinfo info; 501 struct mnttab mnt; 502 int ret_val = FALSE; 503 504 505 506 #ifdef DEBUG 507 denter("get_media_info(%s): entering\n", path); 508 #endif 509 510 #ifdef DEBUG_OPEN 511 dprintf("get_media_info: fopen()ing \"%s\"\n", MNTTAB); 512 #endif 513 if ((fp = fopen(MNTTAB, "rF")) == NULL) { 514 /* mtab is gone... let him go */ 515 #ifdef DEBUG 516 dprintf("get_media_info: can't open \"%s\" (%d)\n", MNTTAB, 517 errno); 518 #endif 519 goto dun; 520 } 521 522 /* get char spcl pathname */ 523 if ((cn = volmgt_getfullrawname(path)) == NULL) { 524 goto dun; 525 } 526 if (cn[0] == NULLC) { 527 goto dun; 528 } 529 530 #ifdef DEBUG_OPEN 531 dprintf("get_media_info: open()ing \"%s\"\n", cn); 532 #endif 533 if ((fd = open(cn, O_RDONLY|O_NDELAY)) < 0) { 534 #ifdef DEBUG 535 dprintf("get_media_info(): can't open \"%s\" (%d)\n", cn, 536 errno); 537 #endif 538 goto dun; 539 } 540 541 #ifdef DEBUG_STAT 542 dprintf("get_media_info: fstat()ing \"%s\"\n", cn); 543 #endif 544 if (fstat64(fd, &sb) < 0) { 545 #ifdef DEBUG 546 dprintf("get_media_info: can't stat \"%s\" (%d)\n", cn, errno); 547 #endif 548 goto dun; 549 } 550 551 #ifdef DEBUG_IOCTL 552 dprintf("get_media_info: ioctl(%s, DKIOCINFO)\n", cn); 553 #endif 554 if (ioctl(fd, DKIOCINFO, &info) != 0) { 555 #ifdef DEBUG 556 dprintf( 557 "get_media_info: ioctl(DKIOCINFO) on \"%s\" failed (%d)\n", 558 cn, errno); 559 #endif 560 goto dun; 561 } 562 563 /* if we found the entry then disect it */ 564 if (vol_getmntdev(fp, &mnt, sb.st_rdev, &info) != 0) { 565 char *cp; 566 char *mtype; 567 char *mnt_dir; 568 int mtype_len; 569 DIR *dirp = NULL; 570 struct dirent64 *dp; 571 char *volname; 572 573 574 /* return the spcl device name found */ 575 *spclp = strdup(mnt.mnt_special); 576 577 /* 578 * try to get the media type (e.g. "floppy") from the mount 579 * point (e.g. "/floppy/NAME") if vold is running 580 */ 581 582 if (!volmgt_running() || 583 (!volmgt_ownspath(*spclp) && 584 volmgt_symname(*spclp) == NULL)) { 585 ret_val = TRUE; /* success (if limited) */ 586 goto dun; 587 } 588 589 /* get the first part of the mount point (e.g. "floppy") */ 590 cp = mnt.mnt_mountp; 591 if (*cp++ != '/') { 592 #ifdef DEBUG 593 dprintf( 594 "get_media_info warning: no leading '/' in mount point \"%s\"\n", 595 mnt.mnt_mountp); 596 #endif 597 goto dun; 598 } 599 mtype = cp; 600 if ((cp = strchr(mtype, '/')) == NULL) { 601 #ifdef DEBUG 602 dprintf( 603 "get_media_info warning: no 2nd '/' in mount point \"%s\"\n", 604 mnt.mnt_mountp); 605 #endif 606 goto dun; 607 } 608 *cp++ = NULLC; 609 mnt_dir = mnt.mnt_mountp; /* save dir path */ 610 611 /* get the volume name (e.g. "unnamed_floppy") */ 612 volname = cp; 613 614 /* scan for the symlink that points to our volname */ 615 if ((dirp = opendir(mnt_dir)) == NULL) { 616 #ifdef DEBUG 617 dprintf( 618 "get_media_info warning: can't open directory \"%s\"\n", 619 mnt_dir); 620 #endif 621 goto dun; 622 } 623 mtype_len = strlen(mtype); 624 while ((dp = readdir64(dirp)) != NULL) { 625 char lpath[2 * (MAXNAMELEN+1)]; 626 char linkbuf[MAXPATHLEN+4]; 627 int lb_len; 628 struct stat64 sb; 629 630 631 if (strncmp(dp->d_name, mtype, mtype_len) != 0) { 632 continue; /* not even close */ 633 } 634 635 (void) sprintf(lpath, "%s/%s", mnt_dir, 636 dp->d_name); 637 #ifdef DEBUG_STAT 638 dprintf("get_media_info: lstat()ing \"%s\"\n", lpath); 639 #endif 640 if (lstat64(lpath, &sb) < 0) { 641 continue; /* what? */ 642 } 643 if (!S_ISLNK(sb.st_mode)) { 644 continue; /* not our baby */ 645 } 646 if ((lb_len = readlink(lpath, linkbuf, 647 sizeof (linkbuf))) < 0) { 648 continue; 649 } 650 linkbuf[lb_len] = NULLC; /* null terminate */ 651 if ((cp = vol_basename(linkbuf)) == NULL) { 652 continue; 653 } 654 /* now we have the name! */ 655 if (strcmp(cp, volname) == 0) { 656 /* found it !! */ 657 if (sscanf(dp->d_name + mtype_len, "%d", 658 mnump) == 1) { 659 *mtypep = strdup(mtype); 660 ret_val = TRUE; 661 } 662 break; 663 } 664 } 665 (void) closedir(dirp); 666 } 667 668 dun: 669 if (fp != NULL) { 670 (void) fclose(fp); 671 } 672 if (fd >= 0) { 673 (void) close(fd); 674 } 675 if (cn != NULL) { 676 free(cn); 677 } 678 #ifdef DEBUG 679 if (ret_val) { 680 dexit("get_media_info: returning mtype=%s, mnum=%d, spcl=%s\n", 681 *mtypep == NULL ? "<null ptr>" : *mtypep, 682 *mnump, 683 *spclp == NULL ? "<null ptr>" : *spclp); 684 } else { 685 dexit("get_media_info: FAILED\n"); 686 } 687 #endif 688 return (ret_val); 689 } 690 691 692 /* 693 * call the appropriate unmount program, returning its success (TRUE) 694 * or failure (FALSE) 695 */ 696 static int 697 call_unmount_prog(int mi_gotten, int use_rmm, char *mtype, int mnum, 698 char *spcl, char *bn) 699 { 700 pid_t pid; /* forked proc's pid */ 701 int ret_val = FALSE; 702 const char *etc_umount = "/etc/umount"; 703 const char *rmm = "/usr/sbin/rmmount"; 704 int rval; /* proc's return value */ 705 706 707 #ifdef DEBUG 708 denter( 709 "call_unmount_prog(%s, %s, \"%s\", %d, \"%s\", \"%s\"): entering\n", 710 mi_gotten ? "TRUE" : "FALSE", use_rmm ? "TRUE" : "FALSE", 711 mtype ? mtype : "<null ptr>", mnum, spcl ? spcl : "<null ptr>", 712 bn); 713 #endif 714 /* create a child to unmount the path */ 715 if ((pid = fork()) < 0) { 716 #ifdef DEBUG 717 dprintf("error in call_unmount_prog: fork failed (errno %d)\n", 718 errno); 719 #endif 720 goto dun; 721 } 722 723 if (pid == 0) { 724 /* the child */ 725 #ifndef DEBUG 726 int xfd; 727 #endif 728 char env_buf[MAXPATHLEN]; 729 730 #ifndef DEBUG 731 /* get rid of those nasty err messages */ 732 if ((xfd = open(NULL_PATH, O_RDWR)) >= 0) { 733 (void) dup2(xfd, fileno(stdin)); 734 (void) dup2(xfd, fileno(stdout)); 735 (void) dup2(xfd, fileno(stderr)); 736 } 737 #endif 738 739 if (use_rmm) { 740 /* set up environment vars */ 741 (void) putenv("VOLUME_ACTION=eject"); 742 (void) putenv(strdup(env_buf)); 743 if (mi_gotten) { 744 (void) sprintf(env_buf, 745 "VOLUME_MEDIATYPE=%s", mtype); 746 (void) putenv(strdup(env_buf)); 747 (void) sprintf(env_buf, "VOLUME_SYMDEV=%s%d", 748 mtype, mnum); 749 (void) putenv(strdup(env_buf)); 750 (void) sprintf(env_buf, "VOLUME_PATH=%s", 751 spcl); 752 (void) putenv(strdup(env_buf)); 753 (void) sprintf(env_buf, "VOLUME_NAME=%s", 754 vol_basename(spcl)); 755 (void) putenv(strdup(env_buf)); 756 } else { 757 (void) sprintf(env_buf, "VOLUME_PATH=%s", bn); 758 (void) putenv(strdup(env_buf)); 759 (void) sprintf(env_buf, "VOLUME_NAME=%s", 760 vol_basename(bn)); 761 (void) putenv(strdup(env_buf)); 762 } 763 #ifdef DEBUG 764 dprintf("call_unmount_prog: calling \"%s -D\"\n", rmm); 765 (void) execl(rmm, rmm, "-D", NULL); 766 #else 767 (void) execl(rmm, rmm, NULL); 768 #endif 769 } else { 770 #ifdef DEBUG 771 dprintf("call_unmount_prog: calling \"%s %s\"\n", 772 etc_umount, mi_gotten ? spcl : bn); 773 #endif 774 (void) execl(etc_umount, etc_umount, 775 mi_gotten ? spcl : bn, 776 NULL); 777 } 778 #ifdef DEBUG 779 dprintf("call_unmount_prog: exec failed (errno %d)\n", errno); 780 #endif 781 exit(-1); 782 /*NOTREACHED*/ 783 } 784 785 /* wait for the umount command to exit */ 786 if (waitpid(pid, &rval, 0) == pid) { 787 if (WIFEXITED(rval)) { 788 if (WEXITSTATUS(rval) == 0) { 789 ret_val = TRUE; /* success */ 790 } 791 } 792 } 793 794 dun: 795 #ifdef DEBUG 796 dexit("call_unmount_prog: returning %s\n", ret_val ? "TRUE" : "FALSE"); 797 #endif 798 return (ret_val); 799 } 800