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