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