MFC r1.27:
[dragonfly.git] / contrib / amd / amd / amfs_toplvl.c
blob5d07f62d90f26150364f81a0498bb0c3838e9490
1 /*
2 * Copyright (c) 1997-1999 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.
8 * This code is derived from software contributed to Berkeley by
9 * Jan-Simon Pendry at Imperial College, London.
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.
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.
39 * %W% (Berkeley) %G%
41 * $Id: amfs_toplvl.c,v 1.5 1999/02/04 07:24:14 ezk Exp $
46 * Top-level file system
49 #ifdef HAVE_CONFIG_H
50 # include <config.h>
51 #endif /* HAVE_CONFIG_H */
52 #include <am_defs.h>
53 #include <amd.h>
55 /****************************************************************************
56 *** FORWARD DEFINITIONS ***
57 ****************************************************************************/
60 /****************************************************************************
61 *** OPS STRUCTURES ***
62 ****************************************************************************/
63 am_ops amfs_toplvl_ops =
65 "toplvl",
66 amfs_auto_match,
67 0, /* amfs_auto_init */
68 amfs_toplvl_mount,
70 amfs_toplvl_umount,
72 amfs_auto_lookuppn,
73 amfs_auto_readdir, /* browsable version of readdir() */
74 0, /* amfs_toplvl_readlink */
75 amfs_toplvl_mounted,
76 0, /* amfs_toplvl_umounted */
77 find_amfs_auto_srvr,
78 FS_MKMNT | FS_NOTIMEOUT | FS_BACKGROUND | FS_AMQINFO | FS_DIRECTORY
82 /****************************************************************************
83 *** FUNCTIONS ***
84 ****************************************************************************/
87 * Mount an automounter directory.
88 * The automounter is connected into the system
89 * as a user-level NFS server. mount_amfs_toplvl constructs
90 * the necessary NFS parameters to be given to the
91 * kernel so that it will talk back to us.
93 * NOTE: automounter mounts in themselves are using NFS Version 2.
95 static int
96 mount_amfs_toplvl(char *dir, char *opts)
98 char fs_hostname[MAXHOSTNAMELEN + MAXPATHLEN + 1];
99 int retry, error, genflags;
100 mntent_t mnt;
101 nfs_args_t nfs_args;
102 am_nfs_fh *fhp;
103 am_nfs_handle_t anh;
104 MTYPE_TYPE type = MOUNT_TYPE_NFS;
105 #ifndef HAVE_TRANSPORT_TYPE_TLI
106 u_short port;
107 struct sockaddr_in sin;
108 #endif /* not HAVE_TRANSPORT_TYPE_TLI */
110 memset((voidp) &mnt, 0, sizeof(mnt));
111 mnt.mnt_dir = dir;
112 mnt.mnt_fsname = pid_fsname;
113 mnt.mnt_opts = opts;
116 * Make sure that amd's top-level NFS mounts are hidden by default
117 * from df.
118 * If they don't appear to support the either the "ignore" mnttab
119 * option entry, or the "auto" one, set the mount type to "nfs".
121 mnt.mnt_type = HIDE_MOUNT_TYPE;
123 retry = hasmntval(&mnt, MNTTAB_OPT_RETRY);
124 if (retry <= 0)
125 retry = 2; /* XXX */
128 * SET MOUNT ARGS
131 * get fhandle of remote path for automount point
133 fhp = root_fh(dir);
134 if (!fhp) {
135 plog(XLOG_FATAL, "Can't find root file handle for %s", dir);
136 return EINVAL;
139 #ifndef HAVE_TRANSPORT_TYPE_TLI
141 * Create sockaddr to point to the local machine. 127.0.0.1
142 * is not used since that will not work in HP-UX clusters and
143 * this is no more expensive.
145 memset((voidp) &sin, 0, sizeof(sin));
146 sin.sin_family = AF_INET;
147 sin.sin_addr = myipaddr;
148 port = hasmntval(&mnt, MNTTAB_OPT_PORT);
149 if (port) {
150 sin.sin_port = htons(port);
151 } else {
152 plog(XLOG_ERROR, "no port number specified for %s", dir);
153 return EINVAL;
155 #endif /* not HAVE_TRANSPORT_TYPE_TLI */
158 * Make a ``hostname'' string for the kernel
160 sprintf(fs_hostname, "pid%ld@%s:%s",
161 (long) (foreground ? am_mypid : getppid()),
162 am_get_hostname(),
163 dir);
165 * Most kernels have a name length restriction (64 bytes)...
167 if (strlen(fs_hostname) >= MAXHOSTNAMELEN)
168 strcpy(fs_hostname + MAXHOSTNAMELEN - 3, "..");
169 #ifdef HOSTNAMESZ
171 * ... and some of these restrictions are 32 bytes (HOSTNAMESZ)
172 * If you need to get the definition for HOSTNAMESZ found, you may
173 * add the proper header file to the conf/nfs_prot/nfs_prot_*.h file.
175 if (strlen(fs_hostname) >= HOSTNAMESZ)
176 strcpy(fs_hostname + HOSTNAMESZ - 3, "..");
177 #endif /* HOSTNAMESZ */
180 * Finally we can compute the mount genflags set above,
181 * and add any automounter specific flags.
183 genflags = compute_mount_flags(&mnt);
184 genflags |= compute_automounter_mount_flags(&mnt);
186 /* setup the many fields and flags within nfs_args */
187 memmove(&anh.v2.fhs_fh, fhp, sizeof(*fhp));
188 #ifdef HAVE_TRANSPORT_TYPE_TLI
189 compute_nfs_args(&nfs_args,
190 &mnt,
191 genflags,
192 nfsncp,
193 NULL, /* remote host IP addr is set below */
194 NFS_VERSION, /* version 2 */
195 "udp",
196 &anh,
197 fs_hostname,
198 pid_fsname);
200 * IMPORTANT: set the correct IP address AFTERWARDS. It cannot
201 * be done using the normal mechanism of compute_nfs_args(), because
202 * that one will allocate a new address and use NFS_SA_DREF() to copy
203 * parts to it, while assuming that the ip_addr passed is always
204 * a "struct sockaddr_in". That assumption is incorrect on TLI systems,
205 * because they define a special macro HOST_SELF which is DIFFERENT
206 * than localhost (127.0.0.1)!
208 nfs_args.addr = &nfsxprt->xp_ltaddr;
209 #else /* not HAVE_TRANSPORT_TYPE_TLI */
210 compute_nfs_args(&nfs_args,
211 &mnt,
212 genflags,
213 &sin,
214 NFS_VERSION, /* version 2 */
215 "udp",
216 &anh,
217 fs_hostname,
218 pid_fsname);
219 #endif /* not HAVE_TRANSPORT_TYPE_TLI */
221 /*************************************************************************
222 * NOTE: while compute_nfs_args() works ok for regular NFS mounts *
223 * the toplvl one is not, and so some options must be corrected by hand *
224 * more carefully, *after* compute_nfs_args() runs. *
225 *************************************************************************/
226 compute_automounter_nfs_args(&nfs_args, &mnt);
228 /* This is it! Here we try to mount amd on its mount points */
229 #ifdef DEBUG
230 amuDebug(D_TRACE) {
231 print_nfs_args(&nfs_args, 0);
232 plog(XLOG_DEBUG, "Generic mount flags 0x%x", genflags);
234 #endif /* DEBUG */
235 error = mount_fs(&mnt, genflags, (caddr_t) &nfs_args, retry, type,
236 0, NULL, mnttab_file_name);
238 #ifdef HAVE_TRANSPORT_TYPE_TLI
239 free_knetconfig(nfs_args.knconf);
241 * local automounter mounts do not allocate a special address, so
242 * no need to XFREE(nfs_args.addr) under TLI.
244 #endif /* HAVE_TRANSPORT_TYPE_TLI */
246 return error;
251 * Mount the top-level
254 amfs_toplvl_mount(am_node *mp)
256 mntfs *mf = mp->am_mnt;
257 struct stat stb;
258 char opts[256], preopts[256];
259 int error;
260 char *mnttype;
263 * Mounting the automounter.
264 * Make sure the mount directory exists, construct
265 * the mount options and call the mount_amfs_toplvl routine.
268 if (stat(mp->am_path, &stb) < 0) {
269 return errno;
270 } else if ((stb.st_mode & S_IFMT) != S_IFDIR) {
271 plog(XLOG_WARNING, "%s is not a directory", mp->am_path);
272 return ENOTDIR;
274 if (mf->mf_ops == &amfs_toplvl_ops)
275 mnttype = "indirect";
276 else if (mf->mf_ops == &amfs_direct_ops)
277 mnttype = "direct";
278 #ifdef HAVE_AM_FS_UNION
279 else if (mf->mf_ops == &amfs_union_ops)
280 mnttype = "union";
281 #endif /* HAVE_AM_FS_UNION */
282 else
283 mnttype = "auto";
286 * Construct some mount options:
288 * Tack on magic map=<mapname> option in mtab to emulate
289 * SunOS automounter behavior.
291 preopts[0] = '\0';
292 #ifdef MNTTAB_OPT_INTR
293 strcat(preopts, MNTTAB_OPT_INTR);
294 strcat(preopts, ",");
295 #endif /* MNTTAB_OPT_INTR */
296 #ifdef MNTTAB_OPT_IGNORE
297 strcat(preopts, MNTTAB_OPT_IGNORE);
298 strcat(preopts, ",");
299 #endif /* MNTTAB_OPT_IGNORE */
300 sprintf(opts, "%s%s,%s=%d,%s=%d,%s=%d,%s,map=%s",
301 preopts,
302 MNTTAB_OPT_RW,
303 MNTTAB_OPT_PORT, nfs_port,
304 MNTTAB_OPT_TIMEO, gopt.amfs_auto_timeo,
305 MNTTAB_OPT_RETRANS, gopt.amfs_auto_retrans,
306 mnttype, mf->mf_info);
308 /* now do the mount */
309 error = mount_amfs_toplvl(mf->mf_mount, opts);
310 if (error) {
311 errno = error;
312 plog(XLOG_FATAL, "mount_amfs_toplvl: %m");
313 return error;
315 return 0;
319 void
320 amfs_toplvl_mounted(mntfs *mf)
322 amfs_auto_mkcacheref(mf);
327 * Unmount a top-level automount node
330 amfs_toplvl_umount(am_node *mp)
332 int error;
333 struct stat stb;
335 again:
337 * The lstat is needed if this mount is type=direct.
338 * When that happens, the kernel cache gets confused
339 * between the underlying type (dir) and the mounted
340 * type (link) and so needs to be re-synced before
341 * the unmount. This is all because the unmount system
342 * call follows links and so can't actually unmount
343 * a link (stupid!). It was noted that doing an ls -ld
344 * of the mount point to see why things were not working
345 * actually fixed the problem - so simulate an ls -ld here.
347 if (lstat(mp->am_path, &stb) < 0) {
348 #ifdef DEBUG
349 dlog("lstat(%s): %m", mp->am_path);
350 #endif /* DEBUG */
352 error = UMOUNT_FS(mp->am_path, mnttab_file_name);
353 if (error == EBUSY) {
354 plog(XLOG_WARNING, "amfs_toplvl_unmount retrying %s in 1s", mp->am_path);
355 sleep(1); /* XXX */
356 goto again;
358 return error;