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