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 */
60 static char *amfs_nfsl_match(am_opts *fo);
61 static int amfs_nfsl_init(mntfs *mf);
62 static int amfs_nfsl_mount(am_node *mp, mntfs *mf);
63 static int amfs_nfsl_umount(am_node *mp, mntfs *mf);
64 static void amfs_nfsl_umounted(mntfs *mf);
65 static fserver *amfs_nfsl_ffserver(mntfs *mf);
66
67 /*
68 * NFS-Link operations
69 */
70 am_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 */
96 static char *
amfs_nfsl_match(am_opts * fo)97 amfs_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 */
137 static int
amfs_nfsl_init(mntfs * mf)138 amfs_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 */
156 static int
amfs_nfsl_mount(am_node * mp,mntfs * mf)157 amfs_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 */
175 static int
amfs_nfsl_umount(am_node * mp,mntfs * mf)176 amfs_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 */
196 static void
amfs_nfsl_umounted(mntfs * mf)197 amfs_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 */
213 static fserver *
amfs_nfsl_ffserver(mntfs * mf)214 amfs_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