amfs_host.c revision 310490
1241279Smarcel/* 2241279Smarcel * Copyright (c) 1997-2014 Erez Zadok 3241279Smarcel * Copyright (c) 1990 Jan-Simon Pendry 4241279Smarcel * Copyright (c) 1990 Imperial College of Science, Technology & Medicine 5241279Smarcel * Copyright (c) 1990 The Regents of the University of California. 6241279Smarcel * All rights reserved. 7241279Smarcel * 8249033Ssjg * This code is derived from software contributed to Berkeley by 9241279Smarcel * Jan-Simon Pendry at Imperial College, London. 10249033Ssjg * 11241279Smarcel * Redistribution and use in source and binary forms, with or without 12241279Smarcel * modification, are permitted provided that the following conditions 13241279Smarcel * are met: 14241279Smarcel * 1. Redistributions of source code must retain the above copyright 15241279Smarcel * notice, this list of conditions and the following disclaimer. 16241279Smarcel * 2. Redistributions in binary form must reproduce the above copyright 17241279Smarcel * notice, this list of conditions and the following disclaimer in the 18241279Smarcel * documentation and/or other materials provided with the distribution. 19241279Smarcel * 3. Neither the name of the University nor the names of its contributors 20241279Smarcel * may be used to endorse or promote products derived from this software 21241279Smarcel * without specific prior written permission. 22241279Smarcel * 23241279Smarcel * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24241279Smarcel * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25241279Smarcel * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26241279Smarcel * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27241279Smarcel * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28241279Smarcel * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29241279Smarcel * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30241279Smarcel * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31241279Smarcel * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32241279Smarcel * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33241279Smarcel * SUCH DAMAGE. 34241279Smarcel * 35241279Smarcel * 36241279Smarcel * File: am-utils/amd/amfs_host.c 37241279Smarcel * 38249033Ssjg */ 39241279Smarcel 40241279Smarcel/* 41241279Smarcel * NFS host file system. 42241279Smarcel * Mounts all exported filesystems from a given host. 43241279Smarcel * This has now degenerated into a mess but will not 44241279Smarcel * be rewritten. Amd 6 will support the abstractions 45241279Smarcel * needed to make this work correctly. 46241279Smarcel */ 47241279Smarcel 48241279Smarcel#ifdef HAVE_CONFIG_H 49241279Smarcel# include <config.h> 50241279Smarcel#endif /* HAVE_CONFIG_H */ 51243115Ssjg#include <am_defs.h> 52241279Smarcel#include <amd.h> 53241279Smarcel 54241279Smarcelstatic char *amfs_host_match(am_opts *fo); 55241279Smarcelstatic int amfs_host_init(mntfs *mf); 56241279Smarcelstatic int amfs_host_mount(am_node *am, mntfs *mf); 57241279Smarcelstatic int amfs_host_umount(am_node *am, mntfs *mf); 58241279Smarcelstatic void amfs_host_umounted(mntfs *mf); 59241279Smarcel 60241279Smarcel/* 61241279Smarcel * Ops structure 62241279Smarcel */ 63241279Smarcelam_ops amfs_host_ops = 64243115Ssjg{ 65241279Smarcel "host", 66241279Smarcel amfs_host_match, 67241279Smarcel amfs_host_init, 68241279Smarcel amfs_host_mount, 69241279Smarcel amfs_host_umount, 70241279Smarcel amfs_error_lookup_child, 71241279Smarcel amfs_error_mount_child, 72241279Smarcel amfs_error_readdir, 73241279Smarcel 0, /* amfs_host_readlink */ 74241279Smarcel 0, /* amfs_host_mounted */ 75241279Smarcel amfs_host_umounted, 76241279Smarcel find_nfs_srvr, 77241279Smarcel 0, /* amfs_host_get_wchan */ 78241279Smarcel FS_MKMNT | FS_BACKGROUND | FS_AMQINFO, 79241279Smarcel#ifdef HAVE_FS_AUTOFS 80241279Smarcel AUTOFS_HOST_FS_FLAGS, 81241279Smarcel#endif /* HAVE_FS_AUTOFS */ 82241279Smarcel}; 83246325Ssjg 84241279Smarcel 85241279Smarcel/* 86241279Smarcel * Determine the mount point: 87241279Smarcel * 88246325Ssjg * The next change we put in to better handle PCs. This is a bit 89241279Smarcel * disgusting, so you'd better sit down. We change the make_mntpt function 90241279Smarcel * to look for exported file systems without a leading '/'. If they don't 91241279Smarcel * have a leading '/', we add one. If the export is 'a:' through 'z:' 92241279Smarcel * (without a leading slash), we change it to 'a%' (or b% or z%). This 93241279Smarcel * allows the entire PC disk to be mounted. 94241279Smarcel */ 95241279Smarcelstatic void 96241279Smarcelmake_mntpt(char *mntpt, size_t l, const exports ex, const char *mf_mount) 97241279Smarcel{ 98241279Smarcel if (ex->ex_dir[0] == '/') { 99241279Smarcel if (ex->ex_dir[1] == 0) 100241279Smarcel xstrlcpy(mntpt, mf_mount, l); 101241279Smarcel else 102241279Smarcel xsnprintf(mntpt, l, "%s%s", mf_mount, ex->ex_dir); 103241279Smarcel } else if (ex->ex_dir[0] >= 'a' && 104241279Smarcel ex->ex_dir[0] <= 'z' && 105241279Smarcel ex->ex_dir[1] == ':' && 106241279Smarcel ex->ex_dir[2] == '/' && 107241279Smarcel ex->ex_dir[3] == 0) 108241279Smarcel xsnprintf(mntpt, l, "%s/%c%%", mf_mount, ex->ex_dir[0]); 109 else 110 xsnprintf(mntpt, l, "%s/%s", mf_mount, ex->ex_dir); 111} 112 113 114/* 115 * Execute needs the same as NFS plus a helper command 116 */ 117static char * 118amfs_host_match(am_opts *fo) 119{ 120 extern am_ops nfs_ops; 121 122 /* 123 * Make sure rfs is specified to keep nfs_match happy... 124 */ 125 if (!fo->opt_rfs) 126 fo->opt_rfs = "/"; 127 128 return (*nfs_ops.fs_match) (fo); 129} 130 131 132static int 133amfs_host_init(mntfs *mf) 134{ 135 u_short mountd_port; 136 137 if (strchr(mf->mf_info, ':') == 0) 138 return ENOENT; 139 140 /* 141 * This is primarily to schedule a wakeup so that as soon 142 * as our fileserver is ready, we can continue setting up 143 * the host filesystem. If we don't do this, the standard 144 * amfs_auto code will set up a fileserver structure, but it will 145 * have to wait for another nfs request from the client to come 146 * in before finishing. Our way is faster since we don't have 147 * to wait for the client to resend its request (which could 148 * take a second or two). 149 */ 150 /* 151 * First, we find the fileserver for this mntfs and then call 152 * get_mountd_port with our mntfs passed as the wait channel. 153 * get_mountd_port will check some things and then schedule 154 * it so that when the fileserver is ready, a wakeup is done 155 * on this mntfs. amfs_cont() is already sleeping on this mntfs 156 * so as soon as that wakeup happens amfs_cont() is called and 157 * this mount is retried. 158 */ 159 if (mf->mf_server) 160 /* 161 * We don't really care if there's an error returned. 162 * Since this is just to help speed things along, the 163 * error will get handled properly elsewhere. 164 */ 165 get_mountd_port(mf->mf_server, &mountd_port, get_mntfs_wchan(mf)); 166 167 return 0; 168} 169 170 171static int 172do_mount(am_nfs_handle_t *fhp, char *mntdir, char *fs_name, mntfs *mf) 173{ 174 struct stat stb; 175 176 dlog("amfs_host: mounting fs %s on %s\n", fs_name, mntdir); 177 178 (void) mkdirs(mntdir, 0555); 179 if (stat(mntdir, &stb) < 0 || (stb.st_mode & S_IFMT) != S_IFDIR) { 180 plog(XLOG_ERROR, "No mount point for %s - skipping", mntdir); 181 return ENOENT; 182 } 183 184 return mount_nfs_fh(fhp, mntdir, fs_name, mf); 185} 186 187 188static int 189sortfun(const voidp x, const voidp y) 190{ 191 exports *a = (exports *) x; 192 exports *b = (exports *) y; 193 194 return strcmp((*a)->ex_dir, (*b)->ex_dir); 195} 196 197 198/* 199 * Get filehandle 200 */ 201static int 202fetch_fhandle(CLIENT *client, char *dir, am_nfs_handle_t *fhp, u_long nfs_version) 203{ 204 struct timeval tv; 205 enum clnt_stat clnt_stat; 206 struct fhstatus res; 207#ifdef HAVE_FS_NFS3 208 struct am_mountres3 res3; 209#endif /* HAVE_FS_NFS3 */ 210 211 /* 212 * Pick a number, any number... 213 */ 214 tv.tv_sec = 20; 215 tv.tv_usec = 0; 216 217 dlog("Fetching fhandle for %s", dir); 218 219 /* 220 * Call the mount daemon on the remote host to 221 * get the filehandle. Use NFS version specific call. 222 */ 223 224 plog(XLOG_INFO, "fetch_fhandle: NFS version %d", (int) nfs_version); 225#ifdef HAVE_FS_NFS3 226 if (nfs_version == NFS_VERSION3 227#ifdef HAVE_FS_NFS4 228#ifndef NO_FALLBACK 229 || nfs_version == NFS_VERSION4 230#endif /* NO_FALLBACK */ 231#endif /* HAVE_FS_NFS4 */ 232 ) { 233 234 memset((char *) &res3, 0, sizeof(res3)); 235 clnt_stat = clnt_call(client, 236 MOUNTPROC_MNT, 237 (XDRPROC_T_TYPE) xdr_dirpath, 238 (SVC_IN_ARG_TYPE) &dir, 239 (XDRPROC_T_TYPE) xdr_am_mountres3, 240 (SVC_IN_ARG_TYPE) &res3, 241 tv); 242 if (clnt_stat != RPC_SUCCESS) { 243 plog(XLOG_ERROR, "mountd rpc failed: %s", clnt_sperrno(clnt_stat)); 244 return EIO; 245 } 246 /* Check the status of the filehandle */ 247 if ((errno = res3.fhs_status)) { 248 dlog("fhandle fetch for mount version 3 failed: %m"); 249 return errno; 250 } 251 memset((voidp) &fhp->v3, 0, sizeof(am_nfs_fh3)); 252 fhp->v3.am_fh3_length = res3.mountres3_u.mountinfo.fhandle.fhandle3_len; 253 memmove(fhp->v3.am_fh3_data, 254 res3.mountres3_u.mountinfo.fhandle.fhandle3_val, 255 fhp->v3.am_fh3_length); 256 } else { /* not NFS_VERSION3 mount */ 257#endif /* HAVE_FS_NFS3 */ 258 clnt_stat = clnt_call(client, 259 MOUNTPROC_MNT, 260 (XDRPROC_T_TYPE) xdr_dirpath, 261 (SVC_IN_ARG_TYPE) &dir, 262 (XDRPROC_T_TYPE) xdr_fhstatus, 263 (SVC_IN_ARG_TYPE) &res, 264 tv); 265 if (clnt_stat != RPC_SUCCESS) { 266 plog(XLOG_ERROR, "mountd rpc failed: %s", clnt_sperrno(clnt_stat)); 267 return EIO; 268 } 269 /* Check status of filehandle */ 270 if (res.fhs_status) { 271 errno = res.fhs_status; 272 dlog("fhandle fetch for mount version 1 failed: %m"); 273 return errno; 274 } 275 memmove(&fhp->v2, &res.fhs_fh, NFS_FHSIZE); 276#ifdef HAVE_FS_NFS3 277 } /* end of "if (nfs_version == NFS_VERSION3)" statement */ 278#endif /* HAVE_FS_NFS3 */ 279 280 /* all is well */ 281 return 0; 282} 283 284 285/* 286 * Scan mount table to see if something already mounted 287 */ 288static int 289already_mounted(mntlist *mlist, char *dir) 290{ 291 mntlist *ml; 292 293 for (ml = mlist; ml; ml = ml->mnext) 294 if (STREQ(ml->mnt->mnt_dir, dir)) 295 return 1; 296 return 0; 297} 298 299 300static int 301amfs_host_mount(am_node *am, mntfs *mf) 302{ 303 struct timeval tv2; 304 CLIENT *client; 305 enum clnt_stat clnt_stat; 306 int n_export; 307 int j, k; 308 exports exlist = 0, ex; 309 exports *ep = NULL; 310 am_nfs_handle_t *fp = NULL; 311 char *host; 312 int error = 0; 313 struct sockaddr_in sin; 314 int sock = RPC_ANYSOCK; 315 int ok = FALSE; 316 mntlist *mlist; 317 char fs_name[MAXPATHLEN], *rfs_dir; 318 char mntpt[MAXPATHLEN]; 319 struct timeval tv; 320 u_long mnt_version; 321 322 /* 323 * WebNFS servers don't necessarily run mountd. 324 */ 325 if (mf->mf_flags & MFF_WEBNFS) { 326 plog(XLOG_ERROR, "amfs_host_mount: cannot support WebNFS"); 327 return EIO; 328 } 329 330 /* 331 * Read the mount list 332 */ 333 mlist = read_mtab(mf->mf_mount, mnttab_file_name); 334 335#ifdef MOUNT_TABLE_ON_FILE 336 /* 337 * Unlock the mount list 338 */ 339 unlock_mntlist(); 340#endif /* MOUNT_TABLE_ON_FILE */ 341 342 /* 343 * Take a copy of the server hostname, address, and nfs version 344 * to mount version conversion. 345 */ 346 host = mf->mf_server->fs_host; 347 sin = *mf->mf_server->fs_ip; 348 plog(XLOG_INFO, "amfs_host_mount: NFS version %d", (int) mf->mf_server->fs_version); 349#ifdef HAVE_FS_NFS3 350 if (mf->mf_server->fs_version == NFS_VERSION3) 351 mnt_version = AM_MOUNTVERS3; 352 else 353#endif /* HAVE_FS_NFS3 */ 354 mnt_version = MOUNTVERS; 355 356 /* 357 * The original 10 second per try timeout is WAY too large, especially 358 * if we're only waiting 10 or 20 seconds max for the response. 359 * That would mean we'd try only once in 10 seconds, and we could 360 * lose the transmit or receive packet, and never try again. 361 * A 2-second per try timeout here is much more reasonable. 362 * 09/28/92 Mike Mitchell, mcm@unx.sas.com 363 */ 364 tv.tv_sec = 2; 365 tv.tv_usec = 0; 366 367 /* 368 * Create a client attached to mountd 369 */ 370 client = get_mount_client(host, &sin, &tv, &sock, mnt_version); 371 if (client == NULL) { 372#ifdef HAVE_CLNT_SPCREATEERROR 373 plog(XLOG_ERROR, "get_mount_client failed for %s: %s", 374 host, clnt_spcreateerror("")); 375#else /* not HAVE_CLNT_SPCREATEERROR */ 376 plog(XLOG_ERROR, "get_mount_client failed for %s", host); 377#endif /* not HAVE_CLNT_SPCREATEERROR */ 378 error = EIO; 379 goto out; 380 } 381 if (!nfs_auth) { 382 error = make_nfs_auth(); 383 if (error) 384 goto out; 385 } 386 client->cl_auth = nfs_auth; 387 388 dlog("Fetching export list from %s", host); 389 390 /* 391 * Fetch the export list 392 */ 393 tv2.tv_sec = 10; 394 tv2.tv_usec = 0; 395 clnt_stat = clnt_call(client, 396 MOUNTPROC_EXPORT, 397 (XDRPROC_T_TYPE) xdr_void, 398 0, 399 (XDRPROC_T_TYPE) xdr_exports, 400 (SVC_IN_ARG_TYPE) & exlist, 401 tv2); 402 if (clnt_stat != RPC_SUCCESS) { 403 const char *msg = clnt_sperrno(clnt_stat); 404 plog(XLOG_ERROR, "host_mount rpc failed: %s", msg); 405 /* clnt_perror(client, "rpc"); */ 406 error = EIO; 407 goto out; 408 } 409 410 /* 411 * Figure out how many exports were returned 412 */ 413 for (n_export = 0, ex = exlist; ex; ex = ex->ex_next) { 414 n_export++; 415 } 416 417 /* 418 * Allocate an array of pointers into the list 419 * so that they can be sorted. If the filesystem 420 * is already mounted then ignore it. 421 */ 422 ep = (exports *) xmalloc(n_export * sizeof(exports)); 423 for (j = 0, ex = exlist; ex; ex = ex->ex_next) { 424 make_mntpt(mntpt, sizeof(mntpt), ex, mf->mf_mount); 425 if (already_mounted(mlist, mntpt)) 426 /* we have at least one mounted f/s, so don't fail the mount */ 427 ok = TRUE; 428 else 429 ep[j++] = ex; 430 } 431 n_export = j; 432 433 /* 434 * Sort into order. 435 * This way the mounts are done in order down the tree, 436 * instead of any random order returned by the mount 437 * daemon (the protocol doesn't specify...). 438 */ 439 qsort(ep, n_export, sizeof(exports), sortfun); 440 441 /* 442 * Allocate an array of filehandles 443 */ 444 fp = (am_nfs_handle_t *) xmalloc(n_export * sizeof(am_nfs_handle_t)); 445 446 /* 447 * Try to obtain filehandles for each directory. 448 * If a fetch fails then just zero out the array 449 * reference but discard the error. 450 */ 451 for (j = k = 0; j < n_export; j++) { 452 /* Check and avoid a duplicated export entry */ 453 if (j > k && ep[k] && STREQ(ep[j]->ex_dir, ep[k]->ex_dir)) { 454 dlog("avoiding dup fhandle requested for %s", ep[j]->ex_dir); 455 ep[j] = NULL; 456 } else { 457 k = j; 458 error = fetch_fhandle(client, ep[j]->ex_dir, &fp[j], 459 mf->mf_server->fs_version); 460 if (error) 461 ep[j] = NULL; 462 } 463 } 464 465 /* 466 * Mount each filesystem for which we have a filehandle. 467 * If any of the mounts succeed then mark "ok" and return 468 * error code 0 at the end. If they all fail then return 469 * the last error code. 470 */ 471 xstrlcpy(fs_name, mf->mf_info, sizeof(fs_name)); 472 if ((rfs_dir = strchr(fs_name, ':')) == (char *) NULL) { 473 plog(XLOG_FATAL, "amfs_host_mount: mf_info has no colon"); 474 error = EINVAL; 475 goto out; 476 } 477 ++rfs_dir; 478 for (j = 0; j < n_export; j++) { 479 ex = ep[j]; 480 if (ex) { 481 /* 482 * Note: the sizeof space left in rfs_dir is what's left in fs_name 483 * after strchr() above returned a pointer _inside_ fs_name. The 484 * calculation below also takes into account that rfs_dir was 485 * incremented by the ++ above. 486 */ 487 xstrlcpy(rfs_dir, ex->ex_dir, sizeof(fs_name) - (rfs_dir - fs_name)); 488 make_mntpt(mntpt, sizeof(mntpt), ex, mf->mf_mount); 489 if (do_mount(&fp[j], mntpt, fs_name, mf) == 0) 490 ok = TRUE; 491 } 492 } 493 494 /* 495 * Clean up and exit 496 */ 497out: 498 discard_mntlist(mlist); 499 XFREE(ep); 500 XFREE(fp); 501 if (sock != RPC_ANYSOCK) 502 (void) amu_close(sock); 503 if (client) 504 clnt_destroy(client); 505 if (exlist) 506 xdr_pri_free((XDRPROC_T_TYPE) xdr_exports, (caddr_t) &exlist); 507 if (ok) 508 return 0; 509 return error; 510} 511 512 513/* 514 * Return true if pref is a directory prefix of dir. 515 * 516 * XXX TODO: 517 * Does not work if pref is "/". 518 */ 519static int 520directory_prefix(char *pref, char *dir) 521{ 522 int len = strlen(pref); 523 524 if (!NSTREQ(pref, dir, len)) 525 return FALSE; 526 if (dir[len] == '/' || dir[len] == '\0') 527 return TRUE; 528 return FALSE; 529} 530 531 532/* 533 * Unmount a mount tree 534 */ 535static int 536amfs_host_umount(am_node *am, mntfs *mf) 537{ 538 mntlist *ml, *mprev; 539 int unmount_flags = (mf->mf_flags & MFF_ON_AUTOFS) ? AMU_UMOUNT_AUTOFS : 0; 540 int xerror = 0; 541 542 /* 543 * Read the mount list 544 */ 545 mntlist *mlist = read_mtab(mf->mf_mount, mnttab_file_name); 546 547#ifdef MOUNT_TABLE_ON_FILE 548 /* 549 * Unlock the mount list 550 */ 551 unlock_mntlist(); 552#endif /* MOUNT_TABLE_ON_FILE */ 553 554 /* 555 * Reverse list... 556 */ 557 ml = mlist; 558 mprev = NULL; 559 while (ml) { 560 mntlist *ml2 = ml->mnext; 561 ml->mnext = mprev; 562 mprev = ml; 563 ml = ml2; 564 } 565 mlist = mprev; 566 567 /* 568 * Unmount all filesystems... 569 */ 570 for (ml = mlist; ml && !xerror; ml = ml->mnext) { 571 char *dir = ml->mnt->mnt_dir; 572 if (directory_prefix(mf->mf_mount, dir)) { 573 int error; 574 dlog("amfs_host: unmounts %s", dir); 575 /* 576 * Unmount "dir" 577 */ 578 error = UMOUNT_FS(dir, mnttab_file_name, unmount_flags); 579 /* 580 * Keep track of errors 581 */ 582 if (error) { 583 /* 584 * If we have not already set xerror and error is not ENOENT, 585 * then set xerror equal to error and log it. 586 * 'xerror' is the return value for this function. 587 * 588 * We do not want to pass ENOENT as an error because if the 589 * directory does not exists our work is done anyway. 590 */ 591 if (!xerror && error != ENOENT) 592 xerror = error; 593 if (error != EBUSY) { 594 errno = error; 595 plog(XLOG_ERROR, "Tree unmount of %s failed: %m", ml->mnt->mnt_dir); 596 } 597 } else { 598 (void) rmdirs(dir); 599 } 600 } 601 } 602 603 /* 604 * Throw away mount list 605 */ 606 discard_mntlist(mlist); 607 608 /* 609 * Try to remount, except when we are shutting down. 610 */ 611 if (xerror && amd_state != Finishing) { 612 xerror = amfs_host_mount(am, mf); 613 if (!xerror) { 614 /* 615 * Don't log this - it's usually too verbose 616 plog(XLOG_INFO, "Remounted host %s", mf->mf_info); 617 */ 618 xerror = EBUSY; 619 } 620 } 621 return xerror; 622} 623 624 625/* 626 * Tell mountd we're done. 627 * This is not quite right, because we may still 628 * have other filesystems mounted, but the existing 629 * mountd protocol is badly broken anyway. 630 */ 631static void 632amfs_host_umounted(mntfs *mf) 633{ 634 char *host; 635 CLIENT *client; 636 enum clnt_stat clnt_stat; 637 struct sockaddr_in sin; 638 int sock = RPC_ANYSOCK; 639 struct timeval tv; 640 u_long mnt_version; 641 642 if (mf->mf_error || mf->mf_refc > 1 || !mf->mf_server) 643 return; 644 645 /* 646 * WebNFS servers shouldn't ever get here. 647 */ 648 if (mf->mf_flags & MFF_WEBNFS) { 649 plog(XLOG_ERROR, "amfs_host_umounted: cannot support WebNFS"); 650 return; 651 } 652 653 /* 654 * Take a copy of the server hostname, address, and NFS version 655 * to mount version conversion. 656 */ 657 host = mf->mf_server->fs_host; 658 sin = *mf->mf_server->fs_ip; 659 plog(XLOG_INFO, "amfs_host_umounted: NFS version %d", (int) mf->mf_server->fs_version); 660#ifdef HAVE_FS_NFS3 661 if (mf->mf_server->fs_version == NFS_VERSION3) 662 mnt_version = AM_MOUNTVERS3; 663 else 664#endif /* HAVE_FS_NFS3 */ 665 mnt_version = MOUNTVERS; 666 667 /* 668 * Create a client attached to mountd 669 */ 670 tv.tv_sec = 10; 671 tv.tv_usec = 0; 672 client = get_mount_client(host, &sin, &tv, &sock, mnt_version); 673 if (client == NULL) { 674#ifdef HAVE_CLNT_SPCREATEERROR 675 plog(XLOG_ERROR, "get_mount_client failed for %s: %s", 676 host, clnt_spcreateerror("")); 677#else /* not HAVE_CLNT_SPCREATEERROR */ 678 plog(XLOG_ERROR, "get_mount_client failed for %s", host); 679#endif /* not HAVE_CLNT_SPCREATEERROR */ 680 goto out; 681 } 682 683 if (!nfs_auth) { 684 if (make_nfs_auth()) 685 goto out; 686 } 687 client->cl_auth = nfs_auth; 688 689 dlog("Unmounting all from %s", host); 690 691 clnt_stat = clnt_call(client, 692 MOUNTPROC_UMNTALL, 693 (XDRPROC_T_TYPE) xdr_void, 694 0, 695 (XDRPROC_T_TYPE) xdr_void, 696 0, 697 tv); 698 if (clnt_stat != RPC_SUCCESS && clnt_stat != RPC_SYSTEMERROR) { 699 /* RPC_SYSTEMERROR seems to be returned for no good reason ... */ 700 const char *msg = clnt_sperrno(clnt_stat); 701 plog(XLOG_ERROR, "unmount all from %s rpc failed: %s", host, msg); 702 goto out; 703 } 704 705out: 706 if (sock != RPC_ANYSOCK) 707 (void) amu_close(sock); 708 if (client) 709 clnt_destroy(client); 710} 711