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