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