1/* 2 * Copyright (c) 1997-2006 Erez Zadok 3 * Copyright (c) 1990 Jan-Simon Pendry 4 * Copyright (c) 1990 Imperial College of Science, Technology & Medicine 5 * Copyright (c) 1990 The Regents of the University of California. 6 * All rights reserved. 7 * 8 * This code is derived from software contributed to Berkeley by 9 * Jan-Simon Pendry at Imperial College, London. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. All advertising materials mentioning features or use of this software 20 * must display the following acknowledgment: 21 * This product includes software developed by the University of 22 * California, Berkeley and its contributors. 23 * 4. Neither the name of the University nor the names of its contributors 24 * may be used to endorse or promote products derived from this software 25 * without specific prior written permission. 26 * 27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 30 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 37 * SUCH DAMAGE. 38 * 39 * 40 * File: am-utils/amd/amfs_nfsl.c 41 * 42 */ 43 44/* 45 * NFSL: Network file system with local existence check. If the local 46 * path denoted by $rfs exists, it behaves as type:=link. 47 * 48 * Example: 49 * pkg type:=nfsl;rhost:=jonny;rfs:=/n/johnny/src/pkg;fs:=${rfs} 50 */ 51 52#ifdef HAVE_CONFIG_H 53# include <config.h> 54#endif /* HAVE_CONFIG_H */ 55#include <am_defs.h> 56#include <amd.h> 57 58 59/* forward declarations */ 60static char *amfs_nfsl_match(am_opts *fo); 61static int amfs_nfsl_init(mntfs *mf); 62static int amfs_nfsl_mount(am_node *mp, mntfs *mf); 63static int amfs_nfsl_umount(am_node *mp, mntfs *mf); 64static void amfs_nfsl_umounted(mntfs *mf); 65static fserver *amfs_nfsl_ffserver(mntfs *mf); 66 67/* 68 * NFS-Link operations 69 */ 70am_ops amfs_nfsl_ops = 71{ 72 "nfsl", 73 amfs_nfsl_match, 74 amfs_nfsl_init, 75 amfs_nfsl_mount, 76 amfs_nfsl_umount, 77 amfs_error_lookup_child, 78 amfs_error_mount_child, 79 amfs_error_readdir, 80 0, /* amfs_nfsl_readlink */ 81 0, /* amfs_nfsl_mounted */ 82 amfs_nfsl_umounted, 83 amfs_nfsl_ffserver, 84 0, /* amfs_nfsl_get_wchan */ 85 FS_MKMNT | FS_BACKGROUND | FS_AMQINFO, /* nfs_fs_flags */ 86#ifdef HAVE_FS_AUTOFS 87 AUTOFS_NFSL_FS_FLAGS, 88#endif /* HAVE_FS_AUTOFS */ 89}; 90 91 92/* 93 * Check that f/s has all needed fields. 94 * Returns: matched string if found, NULL otherwise. 95 */ 96static char * 97amfs_nfsl_match(am_opts *fo) 98{ 99 char *cp; 100 char *ho = fo->opt_rhost; 101 char *retval; 102 struct stat stb; 103 104 if (fo->opt_sublink) 105 cp = fo->opt_sublink; 106 else 107 cp = fo->opt_fs; 108 109 if (!cp || !ho) { 110 plog(XLOG_USER, "amfs_nfsl: host $fs and $rhost must be specified"); 111 return NULL; 112 } 113 114 /* 115 * If this host is not the same as $rhost, or if link does not exist, 116 * call nfs_ops.fs_match(). 117 * If link value exists (or same host), call amfs_link_ops.fs_match(). 118 */ 119 if (!STRCEQ(ho, am_get_hostname())) { 120 plog(XLOG_INFO, "amfs_nfsl: \"%s\" is not local host, using type:=nfs", ho); 121 retval = nfs_ops.fs_match(fo); 122 } else if (lstat(cp, &stb) < 0) { 123 plog(XLOG_INFO, "amfs_nfsl: \"%s\" does not exist, using type:=nfs", cp); 124 retval = nfs_ops.fs_match(fo); 125 } else { 126 plog(XLOG_INFO, "amfs_nfsl: \"%s\" exists, using type:=link", cp); 127 retval = amfs_link_ops.fs_match(fo); 128 } 129 return retval; 130} 131 132 133/* 134 * Initialize. 135 * Returns: 0 if OK, non-zero (errno) if failed. 136 */ 137static int 138amfs_nfsl_init(mntfs *mf) 139{ 140 int ret = 0; 141 if (mf->mf_flags & MFF_NFSLINK) { 142 if (amfs_link_ops.fs_init) 143 ret = amfs_link_ops.fs_init(mf); 144 } else { 145 if (nfs_ops.fs_init) 146 ret = nfs_ops.fs_init(mf); 147 } 148 return ret; 149} 150 151 152/* 153 * Mount vfs. 154 * Returns: 0 if OK, non-zero (errno) if failed. 155 */ 156static int 157amfs_nfsl_mount(am_node *mp, mntfs *mf) 158{ 159 int ret = 0; 160 if (mf->mf_flags & MFF_NFSLINK) { 161 if (amfs_link_ops.mount_fs) 162 ret = amfs_link_ops.mount_fs(mp, mf); 163 } else { 164 if (nfs_ops.mount_fs) 165 ret = nfs_ops.mount_fs(mp, mf); 166 } 167 return ret; 168} 169 170 171/* 172 * Unmount VFS. 173 * Returns: 0 if OK, non-zero (errno) if failed. 174 */ 175static int 176amfs_nfsl_umount(am_node *mp, mntfs *mf) 177{ 178 int ret = 0; 179 if (mf->mf_flags & MFF_NFSLINK) { 180 if (amfs_link_ops.umount_fs) 181 ret = amfs_link_ops.umount_fs(mp, mf); 182 } else { 183 if (nfs_ops.umount_fs) 184 ret = nfs_ops.umount_fs(mp, mf); 185 } 186 return ret; 187} 188 189 190/* 191 * Async unmount callback function. 192 * After the base umount() succeeds, we may want to take extra actions, 193 * such as informing remote mount daemons that we've unmounted them. 194 * See amfs_auto_umounted(), host_umounted(), nfs_umounted(). 195 */ 196static void 197amfs_nfsl_umounted(mntfs *mf) 198{ 199 if (mf->mf_flags & MFF_NFSLINK) { 200 if (amfs_link_ops.umounted) 201 amfs_link_ops.umounted(mf); 202 } else { 203 if (nfs_ops.umounted) 204 nfs_ops.umounted(mf); 205 } 206} 207 208 209/* 210 * Find a file server. 211 * Returns: fserver of found server, or NULL if not found. 212 */ 213static fserver * 214amfs_nfsl_ffserver(mntfs *mf) 215{ 216 char *cp; 217 char *ho = mf->mf_fo->opt_rhost; 218 struct stat stb; 219 220 if (mf->mf_fo->opt_sublink) 221 cp = mf->mf_fo->opt_sublink; 222 else 223 cp = mf->mf_fo->opt_fs; 224 225 /* 226 * If this host is not the same as $rhost, or if link does not exist, 227 * call amfs_link_ops.ffserver(). 228 * If link value exists (or same host), then call ops_nfs.ffserver(). 229 */ 230 if (!STRCEQ(ho, am_get_hostname()) || lstat(cp, &stb) < 0) { 231 return nfs_ops.ffserver(mf); 232 } else { 233 mf->mf_flags |= MFF_NFSLINK; 234 /* remove the FS_MKMNT flag, we don't want amd touching the mountpoint */ 235 mf->mf_fsflags &= ~FS_MKMNT; 236 return amfs_link_ops.ffserver(mf); 237 } 238} 239