amfs_host.c revision 38494
118334Speter/* 2169689Skan * Copyright (c) 1997-1998 Erez Zadok 3132718Skan * Copyright (c) 1990 Jan-Simon Pendry 418334Speter * Copyright (c) 1990 Imperial College of Science, Technology & Medicine 518334Speter * Copyright (c) 1990 The Regents of the University of California. 6132718Skan * All rights reserved. 718334Speter * 8132718Skan * This code is derived from software contributed to Berkeley by 918334Speter * Jan-Simon Pendry at Imperial College, London. 1018334Speter * 1118334Speter * Redistribution and use in source and binary forms, with or without 1218334Speter * modification, are permitted provided that the following conditions 13132718Skan * are met: 1418334Speter * 1. Redistributions of source code must retain the above copyright 1518334Speter * notice, this list of conditions and the following disclaimer. 1618334Speter * 2. Redistributions in binary form must reproduce the above copyright 1718334Speter * notice, this list of conditions and the following disclaimer in the 1818334Speter * documentation and/or other materials provided with the distribution. 19132718Skan * 3. All advertising materials mentioning features or use of this software 20169689Skan * must display the following acknowledgement: 21169689Skan * This product includes software developed by the University of 2218334Speter * California, Berkeley and its contributors. 2318334Speter * 4. Neither the name of the University nor the names of its contributors 2418334Speter * may be used to endorse or promote products derived from this software 2518334Speter * without specific prior written permission. 2618334Speter * 2718334Speter * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2818334Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2918334Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 3050397Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 31132718Skan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 32132718Skan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3318334Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3418334Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3518334Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3618334Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3750397Sobrien * SUCH DAMAGE. 3890075Sobrien * 39169689Skan * %W% (Berkeley) %G% 4018334Speter * 41132718Skan * $Id: amfs_host.c,v 5.2.2.2 1992/05/31 16:36:08 jsp Exp $ 42132718Skan * 43169689Skan */ 44132718Skan 45169689Skan/* 4618334Speter * NFS host file system. 47117395Skan * Mounts all exported filesystems from a given host. 4818334Speter * This has now degenerated into a mess but will not 4918334Speter * be rewritten. Amd 6 will support the abstractions 50117395Skan * needed to make this work correctly. 5150397Sobrien */ 5290075Sobrien 53169689Skan#ifdef HAVE_CONFIG_H 5418334Speter# include <config.h> 5550397Sobrien#endif /* HAVE_CONFIG_H */ 5650397Sobrien#include <am_defs.h> 5718334Speter#include <amd.h> 58132718Skan 5918334Speterstatic char *amfs_host_match(am_opts *fo); 6050397Sobrienstatic int amfs_host_fmount(mntfs *mf); 6150397Sobrienstatic int amfs_host_fumount(mntfs *mf); 6250397Sobrienstatic int amfs_host_init(mntfs *mf); 6350397Sobrienstatic void amfs_host_umounted(am_node *mp); 6450397Sobrien 6550397Sobrien/* 6650397Sobrien * Ops structure 6750397Sobrien */ 6850397Sobrienam_ops amfs_host_ops = 6950397Sobrien{ 7050397Sobrien "host", 71169689Skan amfs_host_match, 72169689Skan amfs_host_init, 73169689Skan amfs_auto_fmount, 74169689Skan amfs_host_fmount, 7550397Sobrien amfs_auto_fumount, 7650397Sobrien amfs_host_fumount, 7750397Sobrien amfs_error_lookuppn, 7850397Sobrien amfs_error_readdir, 7950397Sobrien 0, /* amfs_host_readlink */ 8050397Sobrien 0, /* amfs_host_mounted */ 8150397Sobrien amfs_host_umounted, 8250397Sobrien find_nfs_srvr, 8350397Sobrien FS_MKMNT | FS_BACKGROUND | FS_AMQINFO 8450397Sobrien}; 8550397Sobrien 8650397Sobrien 87169689Skan/* 8818334Speter * Determine the mount point: 8918334Speter * 90132718Skan * The next change we put in to better handle PCs. This is a bit 91132718Skan * disgusting, so you'd better sit down. We change the make_mntpt function 9218334Speter * to look for exported file systems without a leading '/'. If they don't 9318334Speter * have a leading '/', we add one. If the export is 'a:' through 'z:' 9450397Sobrien * (without a leading slash), we change it to 'a%' (or b% or z%). This 9518334Speter * allows the entire PC disk to be mounted. 9618334Speter */ 9750397Sobrienstatic void 9850397Sobrienmake_mntpt(char *mntpt, const exports ex, const mntfs *mf) 9950397Sobrien{ 10018334Speter if (ex->ex_dir[0] == '/') { 10150397Sobrien if (ex->ex_dir[1] == 0) 10250397Sobrien strcpy(mntpt, (mf)->mf_mount); 10350397Sobrien else 10450397Sobrien sprintf(mntpt, "%s%s", mf->mf_mount, ex->ex_dir); 105169689Skan } else if (ex->ex_dir[0] >= 'a' && 10618334Speter ex->ex_dir[0] <= 'z' && 10718334Speter ex->ex_dir[1] == ':' && 10818334Speter ex->ex_dir[2] == '/' && 10918334Speter ex->ex_dir[3] == 0) 11018334Speter sprintf(mntpt, "%s/%c%%", mf->mf_mount, ex->ex_dir[0]); 11118334Speter else 112169689Skan sprintf(mntpt, "%s/%s", mf->mf_mount, ex->ex_dir); 11318334Speter} 11418334Speter 11518334Speter 11618334Speter/* 11790075Sobrien * Execute needs the same as NFS plus a helper command 118169689Skan */ 11918334Speterstatic char * 120169689Skanamfs_host_match(am_opts *fo) 121132718Skan{ 12218334Speter extern am_ops nfs_ops; 123132718Skan 12452284Sobrien /* 12518334Speter * Make sure rfs is specified to keep nfs_match happy... 12618334Speter */ 127169689Skan if (!fo->opt_rfs) 12818334Speter fo->opt_rfs = "/"; 12990075Sobrien 13090075Sobrien return (*nfs_ops.fs_match) (fo); 13118334Speter} 13218334Speter 13318334Speter 134169689Skanstatic int 135117395Skanamfs_host_init(mntfs *mf) 136117395Skan{ 13718334Speter fserver *fs; 138169689Skan u_short port; 13918334Speter 14018334Speter if (strchr(mf->mf_info, ':') == 0) 14118334Speter return ENOENT; 142132718Skan 14318334Speter /* 14418334Speter * This is primarily to schedule a wakeup so that as soon 14518334Speter * as our fileserver is ready, we can continue setting up 14618334Speter * the host filesystem. If we don't do this, the standard 14718334Speter * amfs_auto code will set up a fileserver structure, but it will 14818334Speter * have to wait for another nfs request from the client to come 14918334Speter * in before finishing. Our way is faster since we don't have 150169689Skan * to wait for the client to resend its request (which could 15118334Speter * take a second or two). 15218334Speter */ 15318334Speter /* 154169689Skan * First, we find the fileserver for this mntfs and then call 15518334Speter * nfs_srvr_port with our mntfs passed as the wait channel. 15618334Speter * nfs_srvr_port will check some things and then schedule 157169689Skan * it so that when the fileserver is ready, a wakeup is done 15818334Speter * on this mntfs. amfs_auto_cont() is already sleeping on this mntfs 15918334Speter * so as soon as that wakeup happens amfs_auto_cont() is called and 16018334Speter * this mount is retried. 16118334Speter */ 162169689Skan if ((fs = mf->mf_server)) 163169689Skan /* 164169689Skan * We don't really care if there's an error returned. 165169689Skan * Since this is just to help speed things along, the 16690075Sobrien * error will get handled properly elsewhere. 167169689Skan */ 168169689Skan (void) nfs_srvr_port(fs, &port, (voidp) mf); 16918334Speter 170169689Skan return 0; 171169689Skan} 17218334Speter 17318334Speter 17418334Speterstatic int 17550397Sobriendo_mount(am_nfs_handle_t *fhp, char *dir, char *fs_name, char *opts, mntfs *mf) 17618334Speter{ 17718334Speter struct stat stb; 17818334Speter 17918334Speter#ifdef DEBUG 180117395Skan dlog("amfs_host: mounting fs %s on %s\n", fs_name, dir); 18150397Sobrien#endif /* DEBUG */ 18218334Speter 183117395Skan (void) mkdirs(dir, 0555); 18450397Sobrien if (stat(dir, &stb) < 0 || (stb.st_mode & S_IFMT) != S_IFDIR) { 18518334Speter plog(XLOG_ERROR, "No mount point for %s - skipping", dir); 186117395Skan return ENOENT; 18718334Speter } 188169689Skan 189169689Skan return mount_nfs_fh(fhp, dir, fs_name, opts, mf); 190169689Skan} 191169689Skan 19218334Speter 193169689Skanstatic int 194169689Skansortfun(const voidp x, const voidp y) 19518334Speter{ 19618334Speter exports *a = (exports *) x; 197169689Skan exports *b = (exports *) y; 19818334Speter 19918334Speter return strcmp((*a)->ex_dir, (*b)->ex_dir); 20018334Speter} 20118334Speter 20218334Speter 20318334Speter/* 20418334Speter * Get filehandle 205169689Skan */ 20618334Speterstatic int 20718334Speterfetch_fhandle(CLIENT * client, char *dir, am_nfs_handle_t *fhp, u_long nfs_version) 208169689Skan{ 209132718Skan struct timeval tv; 21018334Speter enum clnt_stat clnt_stat; 211169689Skan 21218334Speter /* 21318334Speter * Pick a number, any number... 21418334Speter */ 215169689Skan tv.tv_sec = 20; 21618334Speter tv.tv_usec = 0; 21718334Speter 218169689Skan#ifdef DEBUG 219169689Skan dlog("Fetching fhandle for %s", dir); 22018334Speter#endif /* DEBUG */ 22118334Speter 22218334Speter /* 22318334Speter * Call the mount daemon on the remote host to 22418334Speter * get the filehandle. Use NFS version specific call. 225132718Skan */ 22618334Speter 22718334Speter plog(XLOG_INFO, "fetch_fhandle: NFS version %d", nfs_version); 22850397Sobrien#ifdef HAVE_FS_NFS3 229169689Skan if (nfs_version == NFS_VERSION3) { 23018334Speter memset((char *) &fhp->v3, 0, sizeof(fhp->v3)); 231132718Skan clnt_stat = clnt_call(client, 23218334Speter MOUNTPROC_MNT, 23318334Speter (XDRPROC_T_TYPE) xdr_dirpath, 234169689Skan (SVC_IN_ARG_TYPE) &dir, 235169689Skan (XDRPROC_T_TYPE) xdr_mountres3, 23618334Speter (SVC_IN_ARG_TYPE) &fhp->v3, 237169689Skan tv); 23818334Speter if (clnt_stat != RPC_SUCCESS) { 23918334Speter plog(XLOG_ERROR, "mountd rpc failed: %s", clnt_sperrno(clnt_stat)); 24018334Speter return EIO; 24118334Speter } 242169689Skan /* Check the status of the filehandle */ 24350397Sobrien if ((errno = fhp->v3.fhs_status)) { 244169689Skan#ifdef DEBUG 24550397Sobrien dlog("fhandle fetch for mount version 3 failed: %m"); 246169689Skan#endif /* DEBUG */ 247169689Skan return errno; 248169689Skan } 249169689Skan } else { /* not NFS_VERSION3 mount */ 250169689Skan#endif /* HAVE_FS_NFS3 */ 251169689Skan clnt_stat = clnt_call(client, 252169689Skan MOUNTPROC_MNT, 253169689Skan (XDRPROC_T_TYPE) xdr_dirpath, 254169689Skan (SVC_IN_ARG_TYPE) &dir, 255169689Skan (XDRPROC_T_TYPE) xdr_fhstatus, 25618334Speter (SVC_IN_ARG_TYPE) &fhp->v2, 25718334Speter tv); 25818334Speter if (clnt_stat != RPC_SUCCESS) { 25918334Speter char *msg = clnt_sperrno(clnt_stat); 260169689Skan plog(XLOG_ERROR, "mountd rpc failed: %s", msg); 261169689Skan return EIO; 262169689Skan } 26318334Speter /* Check status of filehandle */ 26418334Speter if (fhp->v2.fhs_status) { 26518334Speter errno = fhp->v2.fhs_status; 26618334Speter#ifdef DEBUG 26718334Speter dlog("fhandle fetch for mount version 1 failed: %m"); 26818334Speter#endif /* DEBUG */ 269117395Skan return errno; 270169689Skan } 271169689Skan#ifdef HAVE_FS_NFS3 272169689Skan } /* end of "if (nfs_version == NFS_VERSION3)" statement */ 273169689Skan#endif /* HAVE_FS_NFS3 */ 274169689Skan 275169689Skan /* all is well */ 276169689Skan return 0; 277169689Skan} 278169689Skan 279169689Skan 280169689Skan/* 281169689Skan * Scan mount table to see if something already mounted 282169689Skan */ 283169689Skanstatic int 284169689Skanalready_mounted(mntlist *mlist, char *dir) 285169689Skan{ 286169689Skan mntlist *ml; 287169689Skan 288169689Skan for (ml = mlist; ml; ml = ml->mnext) 289169689Skan if (STREQ(ml->mnt->mnt_dir, dir)) 290169689Skan return 1; 291169689Skan return 0; 292169689Skan} 293169689Skan 294169689Skan 295169689Skan/* 296169689Skan * Mount the export tree from a host 297169689Skan */ 298169689Skanstatic int 299169689Skanamfs_host_fmount(mntfs *mf) 300169689Skan{ 301169689Skan struct timeval tv2; 302169689Skan CLIENT *client; 303169689Skan enum clnt_stat clnt_stat; 304169689Skan int n_export; 305169689Skan int j, k; 306169689Skan exports exlist = 0, ex; 307169689Skan exports *ep = 0; 308169689Skan am_nfs_handle_t *fp = 0; 309169689Skan char *host; 310169689Skan int error = 0; 311169689Skan struct sockaddr_in sin; 312169689Skan int sock = RPC_ANYSOCK; 313169689Skan int ok = FALSE; 314169689Skan mntlist *mlist; 315169689Skan char fs_name[MAXPATHLEN], *rfs_dir; 316169689Skan char mntpt[MAXPATHLEN]; 317169689Skan struct timeval tv; 318169689Skan u_long mnt_version; 319169689Skan 320169689Skan /* 321169689Skan * Read the mount list 322169689Skan */ 323169689Skan mlist = read_mtab(mf->mf_mount, mnttab_file_name); 324169689Skan 325169689Skan#ifdef MOUNT_TABLE_ON_FILE 326169689Skan /* 327169689Skan * Unlock the mount list 328169689Skan */ 329169689Skan unlock_mntlist(); 330169689Skan#endif /* MOUNT_TABLE_ON_FILE */ 331169689Skan 332169689Skan /* 333169689Skan * Take a copy of the server hostname, address, and nfs version 334169689Skan * to mount version conversion. 335169689Skan */ 336169689Skan host = mf->mf_server->fs_host; 337169689Skan sin = *mf->mf_server->fs_ip; 338169689Skan plog(XLOG_INFO, "amfs_host_fmount: NFS version %d", mf->mf_server->fs_version); 339169689Skan#ifdef HAVE_FS_NFS3 340169689Skan if (mf->mf_server->fs_version == NFS_VERSION3) 341169689Skan mnt_version = MOUNTVERS3; 342169689Skan else 343169689Skan#endif /* HAVE_FS_NFS3 */ 344169689Skan mnt_version = MOUNTVERS; 345169689Skan 346169689Skan /* 347169689Skan * The original 10 second per try timeout is WAY too large, especially 348169689Skan * if we're only waiting 10 or 20 seconds max for the response. 349169689Skan * That would mean we'd try only once in 10 seconds, and we could 350169689Skan * lose the transmitt or receive packet, and never try again. 351169689Skan * A 2-second per try timeout here is much more reasonable. 352169689Skan * 09/28/92 Mike Mitchell, mcm@unx.sas.com 353169689Skan */ 354169689Skan tv.tv_sec = 2; 355169689Skan tv.tv_usec = 0; 356169689Skan 357169689Skan /* 358169689Skan * Create a client attached to mountd 359117395Skan */ 360 client = get_mount_client(host, &sin, &tv, &sock, mnt_version); 361 if (client == NULL) { 362#ifdef HAVE_CLNT_SPCREATEERROR 363 plog(XLOG_ERROR, "get_mount_client failed for %s: %s", 364 host, clnt_spcreateerror("")); 365#else /* not HAVE_CLNT_SPCREATEERROR */ 366 plog(XLOG_ERROR, "get_mount_client failed for %s", host); 367#endif /* not HAVE_CLNT_SPCREATEERROR */ 368 error = EIO; 369 goto out; 370 } 371 if (!nfs_auth) { 372 error = make_nfs_auth(); 373 if (error) 374 goto out; 375 } 376 client->cl_auth = nfs_auth; 377 378#ifdef DEBUG 379 dlog("Fetching export list from %s", host); 380#endif /* DEBUG */ 381 382 /* 383 * Fetch the export list 384 */ 385 tv2.tv_sec = 10; 386 tv2.tv_usec = 0; 387 clnt_stat = clnt_call(client, 388 MOUNTPROC_EXPORT, 389 (XDRPROC_T_TYPE) xdr_void, 390 0, 391 (XDRPROC_T_TYPE) xdr_exports, 392 (SVC_IN_ARG_TYPE) & exlist, 393 tv2); 394 if (clnt_stat != RPC_SUCCESS) { 395 char *msg = clnt_sperrno(clnt_stat); 396 plog(XLOG_ERROR, "host_fmount rpc failed: %s", msg); 397 /* clnt_perror(client, "rpc"); */ 398 error = EIO; 399 goto out; 400 } 401 402 /* 403 * Figure out how many exports were returned 404 */ 405 for (n_export = 0, ex = exlist; ex; ex = ex->ex_next) { 406 /* printf("export %s\n", ex->ex_dir); */ 407 n_export++; 408 } 409 410 /* 411 * Allocate an array of pointers into the list 412 * so that they can be sorted. If the filesystem 413 * is already mounted then ignore it. 414 */ 415 ep = (exports *) xmalloc(n_export * sizeof(exports)); 416 for (j = 0, ex = exlist; ex; ex = ex->ex_next) { 417 make_mntpt(mntpt, ex, mf); 418 if (!already_mounted(mlist, mntpt)) 419 ep[j++] = ex; 420 } 421 n_export = j; 422 423 /* 424 * Sort into order. 425 * This way the mounts are done in order down the tree, 426 * instead of any random order returned by the mount 427 * daemon (the protocol doesn't specify...). 428 */ 429 qsort(ep, n_export, sizeof(exports), sortfun); 430 431 /* 432 * Allocate an array of filehandles 433 */ 434 fp = (am_nfs_handle_t *) xmalloc(n_export * sizeof(am_nfs_handle_t)); 435 436 /* 437 * Try to obtain filehandles for each directory. 438 * If a fetch fails then just zero out the array 439 * reference but discard the error. 440 */ 441 for (j = k = 0; j < n_export; j++) { 442 /* Check and avoid a duplicated export entry */ 443 if (j > k && ep[k] && STREQ(ep[j]->ex_dir, ep[k]->ex_dir)) { 444#ifdef DEBUG 445 dlog("avoiding dup fhandle requested for %s", ep[j]->ex_dir); 446#endif /* DEBUG */ 447 ep[j] = 0; 448 } else { 449 k = j; 450 error = fetch_fhandle(client, ep[j]->ex_dir, &fp[j], 451 mf->mf_server->fs_version); 452 if (error) 453 ep[j] = 0; 454 } 455 } 456 457 /* 458 * Mount each filesystem for which we have a filehandle. 459 * If any of the mounts succeed then mark "ok" and return 460 * error code 0 at the end. If they all fail then return 461 * the last error code. 462 */ 463 strncpy(fs_name, mf->mf_info, sizeof(fs_name)); 464 if ((rfs_dir = strchr(fs_name, ':')) == (char *) 0) { 465 plog(XLOG_FATAL, "amfs_host_fmount: mf_info has no colon"); 466 error = EINVAL; 467 goto out; 468 } 469 ++rfs_dir; 470 for (j = 0; j < n_export; j++) { 471 ex = ep[j]; 472 if (ex) { 473 strcpy(rfs_dir, ex->ex_dir); 474 make_mntpt(mntpt, ex, mf); 475 if (do_mount(&fp[j], mntpt, fs_name, mf->mf_mopts, mf) == 0) 476 ok = TRUE; 477 } 478 } 479 480 /* 481 * Clean up and exit 482 */ 483out: 484 discard_mntlist(mlist); 485 if (ep) 486 XFREE(ep); 487 if (fp) 488 XFREE(fp); 489 if (sock != RPC_ANYSOCK) 490 (void) amu_close(sock); 491 if (client) 492 clnt_destroy(client); 493 if (exlist) 494 xdr_pri_free((XDRPROC_T_TYPE) xdr_exports, (caddr_t) &exlist); 495 if (ok) 496 return 0; 497 return error; 498} 499 500 501/* 502 * Return true if pref is a directory prefix of dir. 503 * 504 * XXX TODO: 505 * Does not work if pref is "/". 506 */ 507static int 508directory_prefix(char *pref, char *dir) 509{ 510 int len = strlen(pref); 511 512 if (!NSTREQ(pref, dir, len)) 513 return FALSE; 514 if (dir[len] == '/' || dir[len] == '\0') 515 return TRUE; 516 return FALSE; 517} 518 519 520/* 521 * Unmount a mount tree 522 */ 523static int 524amfs_host_fumount(mntfs *mf) 525{ 526 mntlist *ml, *mprev; 527 int xerror = 0; 528 529 /* 530 * Read the mount list 531 */ 532 mntlist *mlist = read_mtab(mf->mf_mount, mnttab_file_name); 533 534#ifdef MOUNT_TABLE_ON_FILE 535 /* 536 * Unlock the mount list 537 */ 538 unlock_mntlist(); 539#endif /* MOUNT_TABLE_ON_FILE */ 540 541 /* 542 * Reverse list... 543 */ 544 ml = mlist; 545 mprev = 0; 546 while (ml) { 547 mntlist *ml2 = ml->mnext; 548 ml->mnext = mprev; 549 mprev = ml; 550 ml = ml2; 551 } 552 mlist = mprev; 553 554 /* 555 * Unmount all filesystems... 556 */ 557 for (ml = mlist; ml && !xerror; ml = ml->mnext) { 558 char *dir = ml->mnt->mnt_dir; 559 if (directory_prefix(mf->mf_mount, dir)) { 560 int error; 561#ifdef DEBUG 562 dlog("amfs_host: unmounts %s", dir); 563#endif /* DEBUG */ 564 /* 565 * Unmount "dir" 566 */ 567 error = UMOUNT_FS(dir, mnttab_file_name); 568 /* 569 * Keep track of errors 570 */ 571 if (error) { 572 if (!xerror) 573 xerror = error; 574 if (error != EBUSY) { 575 errno = error; 576 plog(XLOG_ERROR, "Tree unmount of %s failed: %m", ml->mnt->mnt_dir); 577 } 578 } else { 579 (void) rmdirs(dir); 580 } 581 } 582 } 583 584 /* 585 * Throw away mount list 586 */ 587 discard_mntlist(mlist); 588 589 /* 590 * Try to remount, except when we are shutting down. 591 */ 592 if (xerror && amd_state != Finishing) { 593 xerror = amfs_host_fmount(mf); 594 if (!xerror) { 595 /* 596 * Don't log this - it's usually too verbose 597 plog(XLOG_INFO, "Remounted host %s", mf->mf_info); 598 */ 599 xerror = EBUSY; 600 } 601 } 602 return xerror; 603} 604 605 606/* 607 * Tell mountd we're done. 608 * This is not quite right, because we may still 609 * have other filesystems mounted, but the existing 610 * mountd protocol is badly broken anyway. 611 */ 612static void 613amfs_host_umounted(am_node *mp) 614{ 615 mntfs *mf = mp->am_mnt; 616 char *host; 617 CLIENT *client; 618 enum clnt_stat clnt_stat; 619 struct sockaddr_in sin; 620 int sock = RPC_ANYSOCK; 621 struct timeval tv; 622 u_long mnt_version; 623 624 if (mf->mf_error || mf->mf_refc > 1 || !mf->mf_server) 625 return; 626 627 /* 628 * Take a copy of the server hostname, address, and NFS version 629 * to mount version conversion. 630 */ 631 host = mf->mf_server->fs_host; 632 sin = *mf->mf_server->fs_ip; 633 plog(XLOG_INFO, "amfs_host_umounted: NFS version %d", mf->mf_server->fs_version); 634#ifdef HAVE_FS_NFS3 635 if (mf->mf_server->fs_version == NFS_VERSION3) 636 mnt_version = MOUNTVERS3; 637 else 638#endif /* HAVE_FS_NFS3 */ 639 mnt_version = MOUNTVERS; 640 641 /* 642 * Create a client attached to mountd 643 */ 644 tv.tv_sec = 10; 645 tv.tv_usec = 0; 646 client = get_mount_client(host, &sin, &tv, &sock, mnt_version); 647 if (client == NULL) { 648#ifdef HAVE_CLNT_SPCREATEERROR 649 plog(XLOG_ERROR, "get_mount_client failed for %s: %s", 650 host, clnt_spcreateerror("")); 651#else /* not HAVE_CLNT_SPCREATEERROR */ 652 plog(XLOG_ERROR, "get_mount_client failed for %s", host); 653#endif /* not HAVE_CLNT_SPCREATEERROR */ 654 goto out; 655 } 656 657 if (!nfs_auth) { 658 if (make_nfs_auth()) 659 goto out; 660 } 661 client->cl_auth = nfs_auth; 662 663#ifdef DEBUG 664 dlog("Unmounting all from %s", host); 665#endif /* DEBUG */ 666 667 clnt_stat = clnt_call(client, 668 MOUNTPROC_UMNTALL, 669 (XDRPROC_T_TYPE) xdr_void, 670 0, 671 (XDRPROC_T_TYPE) xdr_void, 672 0, 673 tv); 674 if (clnt_stat != RPC_SUCCESS && clnt_stat != RPC_SYSTEMERROR) { 675 /* RPC_SYSTEMERROR seems to be returned for no good reason ... */ 676 char *msg = clnt_sperrno(clnt_stat); 677 plog(XLOG_ERROR, "unmount all from %s rpc failed: %s", host, msg, clnt_stat); 678 goto out; 679 } 680 681out: 682 if (sock != RPC_ANYSOCK) 683 (void) amu_close(sock); 684 if (client) 685 clnt_destroy(client); 686} 687