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.
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
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
41 * $Id: amfs_toplvl.c,v 1.5 1999/02/04 07:24:14 ezk Exp $
46 * Top-level file system
51 #endif /* HAVE_CONFIG_H */
55 /****************************************************************************
56 *** FORWARD DEFINITIONS ***
57 ****************************************************************************/
60 /****************************************************************************
61 *** OPS STRUCTURES ***
62 ****************************************************************************/
63 am_ops amfs_toplvl_ops
=
67 0, /* amfs_auto_init */
73 amfs_auto_readdir
, /* browsable version of readdir() */
74 0, /* amfs_toplvl_readlink */
76 0, /* amfs_toplvl_umounted */
78 FS_MKMNT
| FS_NOTIMEOUT
| FS_BACKGROUND
| FS_AMQINFO
| FS_DIRECTORY
82 /****************************************************************************
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.
96 mount_amfs_toplvl(char *dir
, char *opts
)
98 char fs_hostname
[MAXHOSTNAMELEN
+ MAXPATHLEN
+ 1];
99 int retry
, error
, genflags
;
104 MTYPE_TYPE type
= MOUNT_TYPE_NFS
;
105 #ifndef HAVE_TRANSPORT_TYPE_TLI
107 struct sockaddr_in sin
;
108 #endif /* not HAVE_TRANSPORT_TYPE_TLI */
110 memset((voidp
) &mnt
, 0, sizeof(mnt
));
112 mnt
.mnt_fsname
= pid_fsname
;
116 * Make sure that amd's top-level NFS mounts are hidden by default
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
);
131 * get fhandle of remote path for automount point
135 plog(XLOG_FATAL
, "Can't find root file handle for %s", dir
);
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
);
150 sin
.sin_port
= htons(port
);
152 plog(XLOG_ERROR
, "no port number specified for %s", dir
);
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()),
165 * Most kernels have a name length restriction (64 bytes)...
167 if (strlen(fs_hostname
) >= MAXHOSTNAMELEN
)
168 strcpy(fs_hostname
+ MAXHOSTNAMELEN
- 3, "..");
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
,
193 NULL
, /* remote host IP addr is set below */
194 NFS_VERSION
, /* version 2 */
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
,
214 NFS_VERSION
, /* version 2 */
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 */
231 print_nfs_args(&nfs_args
, 0);
232 plog(XLOG_DEBUG
, "Generic mount flags 0x%x", genflags
);
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 */
251 * Mount the top-level
254 amfs_toplvl_mount(am_node
*mp
)
256 mntfs
*mf
= mp
->am_mnt
;
258 char opts
[256], preopts
[256];
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) {
270 } else if ((stb
.st_mode
& S_IFMT
) != S_IFDIR
) {
271 plog(XLOG_WARNING
, "%s is not a directory", mp
->am_path
);
274 if (mf
->mf_ops
== &amfs_toplvl_ops
)
275 mnttype
= "indirect";
276 else if (mf
->mf_ops
== &amfs_direct_ops
)
278 #ifdef HAVE_AM_FS_UNION
279 else if (mf
->mf_ops
== &amfs_union_ops
)
281 #endif /* HAVE_AM_FS_UNION */
286 * Construct some mount options:
288 * Tack on magic map=<mapname> option in mtab to emulate
289 * SunOS automounter behavior.
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",
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
);
312 plog(XLOG_FATAL
, "mount_amfs_toplvl: %m");
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
)
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) {
349 dlog("lstat(%s): %m", mp
->am_path
);
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
);