1*8bae5d40Schristos /* $NetBSD: autil.c,v 1.1.1.3 2015/01/17 16:34:15 christos Exp $ */
2a53f50b9Schristos
3a53f50b9Schristos /*
4*8bae5d40Schristos * Copyright (c) 1997-2014 Erez Zadok
5a53f50b9Schristos * Copyright (c) 1990 Jan-Simon Pendry
6a53f50b9Schristos * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
7a53f50b9Schristos * Copyright (c) 1990 The Regents of the University of California.
8a53f50b9Schristos * All rights reserved.
9a53f50b9Schristos *
10a53f50b9Schristos * This code is derived from software contributed to Berkeley by
11a53f50b9Schristos * Jan-Simon Pendry at Imperial College, London.
12a53f50b9Schristos *
13a53f50b9Schristos * Redistribution and use in source and binary forms, with or without
14a53f50b9Schristos * modification, are permitted provided that the following conditions
15a53f50b9Schristos * are met:
16a53f50b9Schristos * 1. Redistributions of source code must retain the above copyright
17a53f50b9Schristos * notice, this list of conditions and the following disclaimer.
18a53f50b9Schristos * 2. Redistributions in binary form must reproduce the above copyright
19a53f50b9Schristos * notice, this list of conditions and the following disclaimer in the
20a53f50b9Schristos * documentation and/or other materials provided with the distribution.
21*8bae5d40Schristos * 3. Neither the name of the University nor the names of its contributors
22a53f50b9Schristos * may be used to endorse or promote products derived from this software
23a53f50b9Schristos * without specific prior written permission.
24a53f50b9Schristos *
25a53f50b9Schristos * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26a53f50b9Schristos * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27a53f50b9Schristos * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28a53f50b9Schristos * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29a53f50b9Schristos * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30a53f50b9Schristos * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31a53f50b9Schristos * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32a53f50b9Schristos * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33a53f50b9Schristos * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34a53f50b9Schristos * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35a53f50b9Schristos * SUCH DAMAGE.
36a53f50b9Schristos *
37a53f50b9Schristos *
38a53f50b9Schristos * File: am-utils/amd/autil.c
39a53f50b9Schristos *
40a53f50b9Schristos */
41a53f50b9Schristos
42a53f50b9Schristos /*
43a53f50b9Schristos * utilities specified to amd, taken out of the older amd/util.c.
44a53f50b9Schristos */
45a53f50b9Schristos
46a53f50b9Schristos #ifdef HAVE_CONFIG_H
47a53f50b9Schristos # include <config.h>
48a53f50b9Schristos #endif /* HAVE_CONFIG_H */
49a53f50b9Schristos #include <am_defs.h>
50a53f50b9Schristos #include <amd.h>
51a53f50b9Schristos
52a53f50b9Schristos int NumChildren = 0; /* number of children of primary amd */
53a53f50b9Schristos static char invalid_keys[] = "\"'!;@ \t\n";
54a53f50b9Schristos
55a53f50b9Schristos /****************************************************************************
56a53f50b9Schristos *** MACROS ***
57a53f50b9Schristos ****************************************************************************/
58a53f50b9Schristos
59a53f50b9Schristos #ifdef HAVE_TRANSPORT_TYPE_TLI
60a53f50b9Schristos # define PARENT_USLEEP_TIME 100000 /* 0.1 seconds */
61a53f50b9Schristos #endif /* HAVE_TRANSPORT_TYPE_TLI */
62a53f50b9Schristos
63a53f50b9Schristos
64a53f50b9Schristos /****************************************************************************
65a53f50b9Schristos *** FORWARD DEFINITIONS ***
66a53f50b9Schristos ****************************************************************************/
67a53f50b9Schristos static void domain_strip(char *otherdom, char *localdom);
68a53f50b9Schristos static int dofork(void);
69a53f50b9Schristos
70a53f50b9Schristos
71a53f50b9Schristos /****************************************************************************
72a53f50b9Schristos *** FUNCTIONS ***
73a53f50b9Schristos ****************************************************************************/
74a53f50b9Schristos
75a53f50b9Schristos /*
76a53f50b9Schristos * Copy s into p, reallocating p if necessary
77a53f50b9Schristos */
78a53f50b9Schristos char *
strealloc(char * p,char * s)79a53f50b9Schristos strealloc(char *p, char *s)
80a53f50b9Schristos {
81a53f50b9Schristos size_t len = strlen(s) + 1;
82a53f50b9Schristos
83a53f50b9Schristos p = (char *) xrealloc((voidp) p, len);
84a53f50b9Schristos
85a53f50b9Schristos xstrlcpy(p, s, len);
86a53f50b9Schristos #ifdef DEBUG_MEM
87a53f50b9Schristos # if defined(HAVE_MALLINFO) && defined(HAVE_MALLOC_VERIFY)
88a53f50b9Schristos malloc_verify();
89a53f50b9Schristos # endif /* not defined(HAVE_MALLINFO) && defined(HAVE_MALLOC_VERIFY) */
90a53f50b9Schristos #endif /* DEBUG_MEM */
91a53f50b9Schristos return p;
92a53f50b9Schristos }
93a53f50b9Schristos
94a53f50b9Schristos
95a53f50b9Schristos /*
96a53f50b9Schristos * Strip off the trailing part of a domain
97a53f50b9Schristos * to produce a short-form domain relative
98a53f50b9Schristos * to the local host domain.
99a53f50b9Schristos * Note that this has no effect if the domain
100a53f50b9Schristos * names do not have the same number of
101a53f50b9Schristos * components. If that restriction proves
102a53f50b9Schristos * to be a problem then the loop needs recoding
103a53f50b9Schristos * to skip from right to left and do partial
104a53f50b9Schristos * matches along the way -- ie more expensive.
105a53f50b9Schristos */
106a53f50b9Schristos static void
domain_strip(char * otherdom,char * localdom)107a53f50b9Schristos domain_strip(char *otherdom, char *localdom)
108a53f50b9Schristos {
109a53f50b9Schristos char *p1, *p2;
110a53f50b9Schristos
111a53f50b9Schristos if ((p1 = strchr(otherdom, '.')) &&
112a53f50b9Schristos (p2 = strchr(localdom, '.')) &&
113a53f50b9Schristos STREQ(p1 + 1, p2 + 1))
114a53f50b9Schristos *p1 = '\0';
115a53f50b9Schristos }
116a53f50b9Schristos
117a53f50b9Schristos
118a53f50b9Schristos /*
119a53f50b9Schristos * Normalize a host name: replace cnames with real names, and decide if to
120a53f50b9Schristos * strip domain name or not.
121a53f50b9Schristos */
122a53f50b9Schristos void
host_normalize(char ** chp)123a53f50b9Schristos host_normalize(char **chp)
124a53f50b9Schristos {
125a53f50b9Schristos /*
126a53f50b9Schristos * Normalize hosts is used to resolve host name aliases
127a53f50b9Schristos * and replace them with the standard-form name.
128a53f50b9Schristos * Invoked with "-n" command line option.
129a53f50b9Schristos */
130a53f50b9Schristos if (gopt.flags & CFM_NORMALIZE_HOSTNAMES) {
131a53f50b9Schristos struct hostent *hp;
132a53f50b9Schristos hp = gethostbyname(*chp);
133a53f50b9Schristos if (hp && hp->h_addrtype == AF_INET) {
134a53f50b9Schristos dlog("Hostname %s normalized to %s", *chp, hp->h_name);
135a53f50b9Schristos *chp = strealloc(*chp, (char *) hp->h_name);
136a53f50b9Schristos }
137a53f50b9Schristos }
138a53f50b9Schristos if (gopt.flags & CFM_DOMAIN_STRIP) {
139a53f50b9Schristos domain_strip(*chp, hostd);
140a53f50b9Schristos }
141a53f50b9Schristos }
142a53f50b9Schristos
143a53f50b9Schristos
144a53f50b9Schristos /*
145a53f50b9Schristos * Keys are not allowed to contain " ' ! or ; to avoid
146a53f50b9Schristos * problems with macro expansions.
147a53f50b9Schristos */
148a53f50b9Schristos int
valid_key(char * key)149a53f50b9Schristos valid_key(char *key)
150a53f50b9Schristos {
151a53f50b9Schristos while (*key)
152a53f50b9Schristos if (strchr(invalid_keys, *key++))
153a53f50b9Schristos return FALSE;
154a53f50b9Schristos return TRUE;
155a53f50b9Schristos }
156a53f50b9Schristos
157a53f50b9Schristos
158a53f50b9Schristos void
forcibly_timeout_mp(am_node * mp)159a53f50b9Schristos forcibly_timeout_mp(am_node *mp)
160a53f50b9Schristos {
161*8bae5d40Schristos mntfs *mf = mp->am_al->al_mnt;
162a53f50b9Schristos /*
163a53f50b9Schristos * Arrange to timeout this node
164a53f50b9Schristos */
165a53f50b9Schristos if (mf && ((mp->am_flags & AMF_ROOT) ||
166a53f50b9Schristos (mf->mf_flags & (MFF_MOUNTING | MFF_UNMOUNTING)))) {
1674bcd344eSchristos /*
1684bcd344eSchristos * We aren't going to schedule a timeout, so we need to notify the
1694bcd344eSchristos * child here unless we are already unmounting, in which case that
1704bcd344eSchristos * process is responsible for notifying the child.
1714bcd344eSchristos */
172a53f50b9Schristos if (mf->mf_flags & MFF_UNMOUNTING)
173a53f50b9Schristos plog(XLOG_WARNING, "node %s is currently being unmounted, ignoring timeout request", mp->am_path);
1744bcd344eSchristos else {
175a53f50b9Schristos plog(XLOG_WARNING, "ignoring timeout request for active node %s", mp->am_path);
1764bcd344eSchristos notify_child(mp, AMQ_UMNT_FAILED, EBUSY, 0);
1774bcd344eSchristos }
178a53f50b9Schristos } else {
179a53f50b9Schristos plog(XLOG_INFO, "\"%s\" forcibly timed out", mp->am_path);
180a53f50b9Schristos mp->am_flags &= ~AMF_NOTIMEOUT;
181a53f50b9Schristos mp->am_ttl = clocktime(NULL);
182a53f50b9Schristos /*
183a53f50b9Schristos * Force mtime update of parent dir, to prevent DNLC/dcache from caching
184a53f50b9Schristos * the old entry, which could result in ESTALE errors, bad symlinks, and
185a53f50b9Schristos * more.
186a53f50b9Schristos */
187a53f50b9Schristos clocktime(&mp->am_parent->am_fattr.na_mtime);
188a53f50b9Schristos reschedule_timeout_mp();
189a53f50b9Schristos }
190a53f50b9Schristos }
191a53f50b9Schristos
192a53f50b9Schristos
193a53f50b9Schristos void
mf_mounted(mntfs * mf,bool_t call_free_opts)194a53f50b9Schristos mf_mounted(mntfs *mf, bool_t call_free_opts)
195a53f50b9Schristos {
196a53f50b9Schristos int quoted;
197a53f50b9Schristos int wasmounted = mf->mf_flags & MFF_MOUNTED;
198a53f50b9Schristos
199a53f50b9Schristos if (!wasmounted) {
200a53f50b9Schristos /*
201a53f50b9Schristos * If this is a freshly mounted
202a53f50b9Schristos * filesystem then update the
203a53f50b9Schristos * mntfs structure...
204a53f50b9Schristos */
205a53f50b9Schristos mf->mf_flags |= MFF_MOUNTED;
206a53f50b9Schristos mf->mf_error = 0;
207a53f50b9Schristos
208a53f50b9Schristos /*
209a53f50b9Schristos * Do mounted callback
210a53f50b9Schristos */
211a53f50b9Schristos if (mf->mf_ops->mounted)
212a53f50b9Schristos mf->mf_ops->mounted(mf);
213a53f50b9Schristos
214a53f50b9Schristos /*
215*8bae5d40Schristos * We used to free the mf_mo (options) here, however they're now stored
216*8bae5d40Schristos * and managed with the mntfs and do not need to be free'd here (this ensures
217*8bae5d40Schristos * that we use the same options to monitor/unmount the system as we used
218*8bae5d40Schristos * to mount it).
219a53f50b9Schristos */
220a53f50b9Schristos }
221a53f50b9Schristos
222a53f50b9Schristos if (mf->mf_flags & MFF_RESTART) {
223a53f50b9Schristos mf->mf_flags &= ~MFF_RESTART;
224a53f50b9Schristos dlog("Restarted filesystem %s, flags 0x%x", mf->mf_mount, mf->mf_flags);
225a53f50b9Schristos }
226a53f50b9Schristos
227a53f50b9Schristos /*
228a53f50b9Schristos * Log message
229a53f50b9Schristos */
230a53f50b9Schristos quoted = strchr(mf->mf_info, ' ') != 0;
231a53f50b9Schristos plog(XLOG_INFO, "%s%s%s %s fstype %s on %s",
232a53f50b9Schristos quoted ? "\"" : "",
233a53f50b9Schristos mf->mf_info,
234a53f50b9Schristos quoted ? "\"" : "",
235a53f50b9Schristos wasmounted ? "referenced" : "mounted",
236a53f50b9Schristos mf->mf_ops->fs_type, mf->mf_mount);
237a53f50b9Schristos }
238a53f50b9Schristos
239a53f50b9Schristos
240a53f50b9Schristos void
am_mounted(am_node * mp)241a53f50b9Schristos am_mounted(am_node *mp)
242a53f50b9Schristos {
243a53f50b9Schristos int notimeout = 0; /* assume normal timeouts initially */
244*8bae5d40Schristos mntfs *mf = mp->am_al->al_mnt;
245a53f50b9Schristos
246a53f50b9Schristos /*
247a53f50b9Schristos * This is the parent mntfs which does the mf->mf_fo (am_opts type), and
248a53f50b9Schristos * we're passing TRUE here to tell mf_mounted to actually free the
249a53f50b9Schristos * am_opts. See a related comment in mf_mounted().
250a53f50b9Schristos */
251a53f50b9Schristos mf_mounted(mf, TRUE);
252a53f50b9Schristos
253a53f50b9Schristos #ifdef HAVE_FS_AUTOFS
254a53f50b9Schristos if (mf->mf_flags & MFF_IS_AUTOFS)
255a53f50b9Schristos autofs_mounted(mp);
256a53f50b9Schristos #endif /* HAVE_FS_AUTOFS */
257a53f50b9Schristos
258a53f50b9Schristos /*
259a53f50b9Schristos * Patch up path for direct mounts
260a53f50b9Schristos */
261*8bae5d40Schristos if (mp->am_parent && mp->am_parent->am_al->al_mnt->mf_fsflags & FS_DIRECT)
262a53f50b9Schristos mp->am_path = str3cat(mp->am_path, mp->am_parent->am_path, "/", ".");
263a53f50b9Schristos
264a53f50b9Schristos /*
265a53f50b9Schristos * Check whether this mount should be cached permanently or not,
266a53f50b9Schristos * and handle user-requested timeouts.
267a53f50b9Schristos */
268a53f50b9Schristos /* first check if file system was set to never timeout */
269a53f50b9Schristos if (mf->mf_fsflags & FS_NOTIMEOUT)
270a53f50b9Schristos notimeout = 1;
271a53f50b9Schristos /* next, alter that decision by map flags */
272*8bae5d40Schristos
273a53f50b9Schristos if (mf->mf_mopts) {
274a53f50b9Schristos mntent_t mnt;
275a53f50b9Schristos mnt.mnt_opts = mf->mf_mopts;
276a53f50b9Schristos
277a53f50b9Schristos /* umount option: user wants to unmount this entry */
278a53f50b9Schristos if (amu_hasmntopt(&mnt, "unmount") || amu_hasmntopt(&mnt, "umount"))
279a53f50b9Schristos notimeout = 0;
280a53f50b9Schristos /* noumount option: user does NOT want to unmount this entry */
281a53f50b9Schristos if (amu_hasmntopt(&mnt, "nounmount") || amu_hasmntopt(&mnt, "noumount"))
282a53f50b9Schristos notimeout = 1;
283a53f50b9Schristos /* utimeout=N option: user wants to unmount this option AND set timeout */
284a53f50b9Schristos if ((mp->am_timeo = hasmntval(&mnt, "utimeout")) == 0)
285a53f50b9Schristos mp->am_timeo = gopt.am_timeo; /* otherwise use default timeout */
286a53f50b9Schristos else
287a53f50b9Schristos notimeout = 0;
288a53f50b9Schristos /* special case: don't try to unmount "/" (it can never succeed) */
289a53f50b9Schristos if (mf->mf_mount[0] == '/' && mf->mf_mount[1] == '\0')
290a53f50b9Schristos notimeout = 1;
291a53f50b9Schristos }
292a53f50b9Schristos /* finally set actual flags */
293a53f50b9Schristos if (notimeout) {
294a53f50b9Schristos mp->am_flags |= AMF_NOTIMEOUT;
295a53f50b9Schristos plog(XLOG_INFO, "%s set to never timeout", mp->am_path);
296a53f50b9Schristos } else {
297a53f50b9Schristos mp->am_flags &= ~AMF_NOTIMEOUT;
298a53f50b9Schristos plog(XLOG_INFO, "%s set to timeout in %d seconds", mp->am_path, mp->am_timeo);
299a53f50b9Schristos }
300a53f50b9Schristos
301a53f50b9Schristos /*
302a53f50b9Schristos * If this node is a symlink then
303a53f50b9Schristos * compute the length of the returned string.
304a53f50b9Schristos */
305a53f50b9Schristos if (mp->am_fattr.na_type == NFLNK)
306a53f50b9Schristos mp->am_fattr.na_size = strlen(mp->am_link ? mp->am_link : mf->mf_mount);
307a53f50b9Schristos
308a53f50b9Schristos /*
309a53f50b9Schristos * Record mount time, and update am_stats at the same time.
310a53f50b9Schristos */
311a53f50b9Schristos mp->am_stats.s_mtime = clocktime(&mp->am_fattr.na_mtime);
312a53f50b9Schristos new_ttl(mp);
313a53f50b9Schristos
314a53f50b9Schristos /*
315a53f50b9Schristos * Update mtime of parent node (copying "struct nfstime" in '=' below)
316a53f50b9Schristos */
317*8bae5d40Schristos if (mp->am_parent && mp->am_parent->am_al->al_mnt)
318a53f50b9Schristos mp->am_parent->am_fattr.na_mtime = mp->am_fattr.na_mtime;
319a53f50b9Schristos
320a53f50b9Schristos /*
321a53f50b9Schristos * This is ugly, but essentially unavoidable
322a53f50b9Schristos * Sublinks must be treated separately as type==link
323a53f50b9Schristos * when the base type is different.
324a53f50b9Schristos */
325a53f50b9Schristos if (mp->am_link && mf->mf_ops != &amfs_link_ops)
326a53f50b9Schristos amfs_link_ops.mount_fs(mp, mf);
327a53f50b9Schristos
328a53f50b9Schristos /*
329a53f50b9Schristos * Now, if we can, do a reply to our client here
330a53f50b9Schristos * to speed things up.
331a53f50b9Schristos */
332a53f50b9Schristos #ifdef HAVE_FS_AUTOFS
333a53f50b9Schristos if (mp->am_flags & AMF_AUTOFS)
334a53f50b9Schristos autofs_mount_succeeded(mp);
335a53f50b9Schristos else
336a53f50b9Schristos #endif /* HAVE_FS_AUTOFS */
337a53f50b9Schristos nfs_quick_reply(mp, 0);
338a53f50b9Schristos
339a53f50b9Schristos /*
340a53f50b9Schristos * Update stats
341a53f50b9Schristos */
342a53f50b9Schristos amd_stats.d_mok++;
343a53f50b9Schristos }
344a53f50b9Schristos
345a53f50b9Schristos
346a53f50b9Schristos /*
347a53f50b9Schristos * Replace mount point with a reference to an error filesystem.
348a53f50b9Schristos * The mount point (struct mntfs) is NOT discarded,
349a53f50b9Schristos * the caller must do it if it wants to _before_ calling this function.
350a53f50b9Schristos */
351a53f50b9Schristos void
assign_error_mntfs(am_node * mp)352a53f50b9Schristos assign_error_mntfs(am_node *mp)
353a53f50b9Schristos {
354a53f50b9Schristos int error;
355a53f50b9Schristos dlog("assign_error_mntfs");
356*8bae5d40Schristos
357*8bae5d40Schristos if (mp->am_al == NULL) {
358*8bae5d40Schristos plog(XLOG_ERROR, "%s: Can't assign error", __func__);
359*8bae5d40Schristos return;
360*8bae5d40Schristos }
361a53f50b9Schristos /*
362a53f50b9Schristos * Save the old error code
363a53f50b9Schristos */
364a53f50b9Schristos error = mp->am_error;
365a53f50b9Schristos if (error <= 0)
366*8bae5d40Schristos error = mp->am_al->al_mnt->mf_error;
367a53f50b9Schristos /*
368a53f50b9Schristos * Allocate a new error reference
369a53f50b9Schristos */
370*8bae5d40Schristos free_loc(mp->am_al);
371*8bae5d40Schristos mp->am_al = new_loc();
372a53f50b9Schristos /*
373a53f50b9Schristos * Put back the error code
374a53f50b9Schristos */
375*8bae5d40Schristos mp->am_al->al_mnt->mf_error = error;
376*8bae5d40Schristos mp->am_al->al_mnt->mf_flags |= MFF_ERROR;
377a53f50b9Schristos /*
378a53f50b9Schristos * Zero the error in the mount point
379a53f50b9Schristos */
380a53f50b9Schristos mp->am_error = 0;
381a53f50b9Schristos }
382a53f50b9Schristos
383a53f50b9Schristos
384a53f50b9Schristos /*
385a53f50b9Schristos * Build a new map cache for this node, or re-use
386a53f50b9Schristos * an existing cache for the same map.
387a53f50b9Schristos */
388a53f50b9Schristos void
amfs_mkcacheref(mntfs * mf)389a53f50b9Schristos amfs_mkcacheref(mntfs *mf)
390a53f50b9Schristos {
391a53f50b9Schristos char *cache;
392a53f50b9Schristos
393a53f50b9Schristos if (mf->mf_fo && mf->mf_fo->opt_cache)
394a53f50b9Schristos cache = mf->mf_fo->opt_cache;
395a53f50b9Schristos else
396a53f50b9Schristos cache = "none";
397a53f50b9Schristos mf->mf_private = (opaque_t) mapc_find(mf->mf_info,
398a53f50b9Schristos cache,
399a53f50b9Schristos (mf->mf_fo ? mf->mf_fo->opt_maptype : NULL),
400a53f50b9Schristos mf->mf_mount);
401a53f50b9Schristos mf->mf_prfree = mapc_free;
402a53f50b9Schristos }
403a53f50b9Schristos
404a53f50b9Schristos
405a53f50b9Schristos /*
406a53f50b9Schristos * Locate next node in sibling list which is mounted
407a53f50b9Schristos * and is not an error node.
408a53f50b9Schristos */
409a53f50b9Schristos am_node *
next_nonerror_node(am_node * xp)410a53f50b9Schristos next_nonerror_node(am_node *xp)
411a53f50b9Schristos {
412a53f50b9Schristos mntfs *mf;
413a53f50b9Schristos
414a53f50b9Schristos /*
415a53f50b9Schristos * Bug report (7/12/89) from Rein Tollevik <rein@ifi.uio.no>
416a53f50b9Schristos * Fixes a race condition when mounting direct automounts.
417a53f50b9Schristos * Also fixes a problem when doing a readdir on a directory
418a53f50b9Schristos * containing hung automounts.
419a53f50b9Schristos */
420a53f50b9Schristos while (xp &&
421*8bae5d40Schristos (!(mf = xp->am_al->al_mnt) || /* No mounted filesystem */
422a53f50b9Schristos mf->mf_error != 0 || /* There was a mntfs error */
423a53f50b9Schristos xp->am_error != 0 || /* There was a mount error */
424a53f50b9Schristos !(mf->mf_flags & MFF_MOUNTED) || /* The fs is not mounted */
425a53f50b9Schristos (mf->mf_server->fs_flags & FSF_DOWN)) /* The fs may be down */
426a53f50b9Schristos )
427a53f50b9Schristos xp = xp->am_osib;
428a53f50b9Schristos
429a53f50b9Schristos return xp;
430a53f50b9Schristos }
431a53f50b9Schristos
432a53f50b9Schristos
433a53f50b9Schristos /*
434a53f50b9Schristos * Mount an automounter directory.
435a53f50b9Schristos * The automounter is connected into the system
436a53f50b9Schristos * as a user-level NFS server. amfs_mount constructs
437a53f50b9Schristos * the necessary NFS parameters to be given to the
438a53f50b9Schristos * kernel so that it will talk back to us.
439a53f50b9Schristos *
440a53f50b9Schristos * NOTE: automounter mounts in themselves are using NFS Version 2 (UDP).
441a53f50b9Schristos *
442a53f50b9Schristos * NEW: on certain systems, mounting can be done using the
443a53f50b9Schristos * kernel-level automount (autofs) support. In that case,
444a53f50b9Schristos * we don't need NFS at all here.
445a53f50b9Schristos */
446a53f50b9Schristos int
amfs_mount(am_node * mp,mntfs * mf,char * opts)447a53f50b9Schristos amfs_mount(am_node *mp, mntfs *mf, char *opts)
448a53f50b9Schristos {
449a53f50b9Schristos char fs_hostname[MAXHOSTNAMELEN + MAXPATHLEN + 1];
450a53f50b9Schristos int retry, error = 0, genflags;
451a53f50b9Schristos int on_autofs = mf->mf_flags & MFF_ON_AUTOFS;
452a53f50b9Schristos char *dir = mf->mf_mount;
453a53f50b9Schristos mntent_t mnt;
454a53f50b9Schristos MTYPE_TYPE type;
455a53f50b9Schristos int forced_unmount = 0; /* are we using forced unmounts? */
456*8bae5d40Schristos u_long nfs_version = get_nfs_dispatcher_version(nfs_dispatcher);
457a53f50b9Schristos
458*8bae5d40Schristos memset(&mnt, 0, sizeof(mnt));
459a53f50b9Schristos mnt.mnt_dir = dir;
460a53f50b9Schristos mnt.mnt_fsname = pid_fsname;
461a53f50b9Schristos mnt.mnt_opts = opts;
462a53f50b9Schristos
463a53f50b9Schristos #ifdef HAVE_FS_AUTOFS
464a53f50b9Schristos if (mf->mf_flags & MFF_IS_AUTOFS) {
465a53f50b9Schristos type = MOUNT_TYPE_AUTOFS;
466a53f50b9Schristos /*
467a53f50b9Schristos * Make sure that amd's top-level autofs mounts are hidden by default
468a53f50b9Schristos * from df.
469a53f50b9Schristos * XXX: It works ok on Linux, might not work on other systems.
470a53f50b9Schristos */
471a53f50b9Schristos mnt.mnt_type = "autofs";
472a53f50b9Schristos } else
473a53f50b9Schristos #endif /* HAVE_FS_AUTOFS */
474a53f50b9Schristos {
475a53f50b9Schristos type = MOUNT_TYPE_NFS;
476a53f50b9Schristos /*
477a53f50b9Schristos * Make sure that amd's top-level NFS mounts are hidden by default
478a53f50b9Schristos * from df.
479a53f50b9Schristos * If they don't appear to support the either the "ignore" mnttab
480a53f50b9Schristos * option entry, or the "auto" one, set the mount type to "nfs".
481a53f50b9Schristos */
482a53f50b9Schristos mnt.mnt_type = HIDE_MOUNT_TYPE;
483a53f50b9Schristos }
484a53f50b9Schristos
485a53f50b9Schristos retry = hasmntval(&mnt, MNTTAB_OPT_RETRY);
486a53f50b9Schristos if (retry <= 0)
487a53f50b9Schristos retry = 2; /* XXX: default to 2 retries */
488a53f50b9Schristos
489a53f50b9Schristos /*
490a53f50b9Schristos * SET MOUNT ARGS
491a53f50b9Schristos */
492a53f50b9Schristos
493a53f50b9Schristos /*
494a53f50b9Schristos * Make a ``hostname'' string for the kernel
495a53f50b9Schristos */
496a53f50b9Schristos xsnprintf(fs_hostname, sizeof(fs_hostname), "pid%ld@%s:%s",
497a53f50b9Schristos get_server_pid(), am_get_hostname(), dir);
498a53f50b9Schristos /*
499a53f50b9Schristos * Most kernels have a name length restriction (64 bytes)...
500a53f50b9Schristos */
501a53f50b9Schristos if (strlen(fs_hostname) >= MAXHOSTNAMELEN)
502a53f50b9Schristos xstrlcpy(fs_hostname + MAXHOSTNAMELEN - 3, "..",
503a53f50b9Schristos sizeof(fs_hostname) - MAXHOSTNAMELEN + 3);
504a53f50b9Schristos #ifdef HOSTNAMESZ
505a53f50b9Schristos /*
506a53f50b9Schristos * ... and some of these restrictions are 32 bytes (HOSTNAMESZ)
507a53f50b9Schristos * If you need to get the definition for HOSTNAMESZ found, you may
508a53f50b9Schristos * add the proper header file to the conf/nfs_prot/nfs_prot_*.h file.
509a53f50b9Schristos */
510a53f50b9Schristos if (strlen(fs_hostname) >= HOSTNAMESZ)
511a53f50b9Schristos xstrlcpy(fs_hostname + HOSTNAMESZ - 3, "..",
512a53f50b9Schristos sizeof(fs_hostname) - HOSTNAMESZ + 3);
513a53f50b9Schristos #endif /* HOSTNAMESZ */
514a53f50b9Schristos
515a53f50b9Schristos /*
516a53f50b9Schristos * Finally we can compute the mount genflags set above,
517a53f50b9Schristos * and add any automounter specific flags.
518a53f50b9Schristos */
519a53f50b9Schristos genflags = compute_mount_flags(&mnt);
520a53f50b9Schristos #ifdef HAVE_FS_AUTOFS
521a53f50b9Schristos if (on_autofs)
522a53f50b9Schristos genflags |= autofs_compute_mount_flags(&mnt);
523a53f50b9Schristos #endif /* HAVE_FS_AUTOFS */
524a53f50b9Schristos genflags |= compute_automounter_mount_flags(&mnt);
525a53f50b9Schristos
526a53f50b9Schristos again:
527a53f50b9Schristos if (!(mf->mf_flags & MFF_IS_AUTOFS)) {
528a53f50b9Schristos nfs_args_t nfs_args;
529*8bae5d40Schristos am_nfs_handle_t *fhp, anh;
530a53f50b9Schristos #ifndef HAVE_TRANSPORT_TYPE_TLI
531a53f50b9Schristos u_short port;
532a53f50b9Schristos struct sockaddr_in sin;
533a53f50b9Schristos #endif /* not HAVE_TRANSPORT_TYPE_TLI */
534a53f50b9Schristos
535a53f50b9Schristos /*
536a53f50b9Schristos * get fhandle of remote path for automount point
537a53f50b9Schristos */
538*8bae5d40Schristos fhp = get_root_nfs_fh(dir, &anh);
539a53f50b9Schristos if (!fhp) {
540a53f50b9Schristos plog(XLOG_FATAL, "Can't find root file handle for %s", dir);
541a53f50b9Schristos return EINVAL;
542a53f50b9Schristos }
543a53f50b9Schristos
544a53f50b9Schristos #ifndef HAVE_TRANSPORT_TYPE_TLI
545a53f50b9Schristos /*
546a53f50b9Schristos * Create sockaddr to point to the local machine.
547a53f50b9Schristos */
548*8bae5d40Schristos memset(&sin, 0, sizeof(sin));
549a53f50b9Schristos /* as per POSIX, sin_len need not be set (used internally by kernel) */
550a53f50b9Schristos sin.sin_family = AF_INET;
551a53f50b9Schristos sin.sin_addr = myipaddr;
552a53f50b9Schristos port = hasmntval(&mnt, MNTTAB_OPT_PORT);
553a53f50b9Schristos if (port) {
554a53f50b9Schristos sin.sin_port = htons(port);
555a53f50b9Schristos } else {
556a53f50b9Schristos plog(XLOG_ERROR, "no port number specified for %s", dir);
557a53f50b9Schristos return EINVAL;
558a53f50b9Schristos }
559a53f50b9Schristos #endif /* not HAVE_TRANSPORT_TYPE_TLI */
560a53f50b9Schristos
561a53f50b9Schristos /* setup the many fields and flags within nfs_args */
562a53f50b9Schristos #ifdef HAVE_TRANSPORT_TYPE_TLI
563a53f50b9Schristos compute_nfs_args(&nfs_args,
564a53f50b9Schristos &mnt,
565a53f50b9Schristos genflags,
566a53f50b9Schristos nfsncp,
567a53f50b9Schristos NULL, /* remote host IP addr is set below */
568*8bae5d40Schristos nfs_version,
569a53f50b9Schristos "udp",
570*8bae5d40Schristos fhp,
571a53f50b9Schristos fs_hostname,
572a53f50b9Schristos pid_fsname);
573a53f50b9Schristos /*
574a53f50b9Schristos * IMPORTANT: set the correct IP address AFTERWARDS. It cannot
575a53f50b9Schristos * be done using the normal mechanism of compute_nfs_args(), because
576a53f50b9Schristos * that one will allocate a new address and use NFS_SA_DREF() to copy
577a53f50b9Schristos * parts to it, while assuming that the ip_addr passed is always
578a53f50b9Schristos * a "struct sockaddr_in". That assumption is incorrect on TLI systems,
579a53f50b9Schristos * because they define a special macro HOST_SELF which is DIFFERENT
580a53f50b9Schristos * than localhost (127.0.0.1)!
581a53f50b9Schristos */
582a53f50b9Schristos nfs_args.addr = &nfsxprt->xp_ltaddr;
583a53f50b9Schristos #else /* not HAVE_TRANSPORT_TYPE_TLI */
584a53f50b9Schristos compute_nfs_args(&nfs_args,
585a53f50b9Schristos &mnt,
586a53f50b9Schristos genflags,
587a53f50b9Schristos NULL,
588a53f50b9Schristos &sin,
589*8bae5d40Schristos nfs_version,
590a53f50b9Schristos "udp",
591*8bae5d40Schristos fhp,
592a53f50b9Schristos fs_hostname,
593a53f50b9Schristos pid_fsname);
594a53f50b9Schristos #endif /* not HAVE_TRANSPORT_TYPE_TLI */
595a53f50b9Schristos
596a53f50b9Schristos /*************************************************************************
597a53f50b9Schristos * NOTE: while compute_nfs_args() works ok for regular NFS mounts *
598a53f50b9Schristos * the toplvl one is not quite regular, and so some options must be *
599a53f50b9Schristos * corrected by hand more carefully, *after* compute_nfs_args() runs. *
600a53f50b9Schristos *************************************************************************/
601a53f50b9Schristos compute_automounter_nfs_args(&nfs_args, &mnt);
602a53f50b9Schristos
603a53f50b9Schristos if (amuDebug(D_TRACE)) {
604a53f50b9Schristos print_nfs_args(&nfs_args, 0);
605a53f50b9Schristos plog(XLOG_DEBUG, "Generic mount flags 0x%x", genflags);
606a53f50b9Schristos }
607a53f50b9Schristos
608a53f50b9Schristos /* This is it! Here we try to mount amd on its mount points */
609a53f50b9Schristos error = mount_fs(&mnt, genflags, (caddr_t) &nfs_args,
610a53f50b9Schristos retry, type, 0, NULL, mnttab_file_name, on_autofs);
611a53f50b9Schristos
612a53f50b9Schristos #ifdef HAVE_TRANSPORT_TYPE_TLI
613a53f50b9Schristos free_knetconfig(nfs_args.knconf);
614a53f50b9Schristos /*
615a53f50b9Schristos * local automounter mounts do not allocate a special address, so
616a53f50b9Schristos * no need to XFREE(nfs_args.addr) under TLI.
617a53f50b9Schristos */
618a53f50b9Schristos #endif /* HAVE_TRANSPORT_TYPE_TLI */
619a53f50b9Schristos
620a53f50b9Schristos #ifdef HAVE_FS_AUTOFS
621a53f50b9Schristos } else {
622a53f50b9Schristos /* This is it! Here we try to mount amd on its mount points */
623a53f50b9Schristos error = mount_fs(&mnt, genflags, (caddr_t) mp->am_autofs_fh,
624a53f50b9Schristos retry, type, 0, NULL, mnttab_file_name, on_autofs);
625a53f50b9Schristos #endif /* HAVE_FS_AUTOFS */
626a53f50b9Schristos }
627a53f50b9Schristos if (error == 0 || forced_unmount)
628a53f50b9Schristos return error;
629a53f50b9Schristos
630a53f50b9Schristos /*
631a53f50b9Schristos * If user wants forced/lazy unmount semantics, then try it iff the
632a53f50b9Schristos * current mount failed with EIO or ESTALE.
633a53f50b9Schristos */
634a53f50b9Schristos if (gopt.flags & CFM_FORCED_UNMOUNTS) {
635a53f50b9Schristos switch (errno) {
636a53f50b9Schristos case ESTALE:
637a53f50b9Schristos case EIO:
638a53f50b9Schristos forced_unmount = errno;
639a53f50b9Schristos plog(XLOG_WARNING, "Mount %s failed (%m); force unmount.", mp->am_path);
640a53f50b9Schristos if ((error = UMOUNT_FS(mp->am_path, mnttab_file_name,
641a53f50b9Schristos AMU_UMOUNT_FORCE | AMU_UMOUNT_DETACH)) < 0) {
642a53f50b9Schristos plog(XLOG_WARNING, "Forced umount %s failed: %m.", mp->am_path);
643a53f50b9Schristos errno = forced_unmount;
644a53f50b9Schristos } else
645a53f50b9Schristos goto again;
646a53f50b9Schristos default:
647a53f50b9Schristos break;
648a53f50b9Schristos }
649a53f50b9Schristos }
650a53f50b9Schristos
651a53f50b9Schristos return error;
652a53f50b9Schristos }
653a53f50b9Schristos
654a53f50b9Schristos
655a53f50b9Schristos void
am_unmounted(am_node * mp)656a53f50b9Schristos am_unmounted(am_node *mp)
657a53f50b9Schristos {
658*8bae5d40Schristos mntfs *mf = mp->am_al->al_mnt;
659a53f50b9Schristos
6604bcd344eSchristos if (!foreground) { /* firewall - should never happen */
6614bcd344eSchristos /*
6624bcd344eSchristos * This is a coding error. Make sure we hear about it!
6634bcd344eSchristos */
6644bcd344eSchristos plog(XLOG_FATAL, "am_unmounted: illegal use in background (%s)",
6654bcd344eSchristos mp->am_name);
6664bcd344eSchristos notify_child(mp, AMQ_UMNT_OK, 0, 0); /* XXX - be safe? */
667a53f50b9Schristos return;
6684bcd344eSchristos }
669a53f50b9Schristos
670a53f50b9Schristos /*
671a53f50b9Schristos * Do unmounted callback
672a53f50b9Schristos */
673a53f50b9Schristos if (mf->mf_ops->umounted)
674a53f50b9Schristos mf->mf_ops->umounted(mf);
675a53f50b9Schristos
676a53f50b9Schristos /*
677a53f50b9Schristos * This is ugly, but essentially unavoidable.
678a53f50b9Schristos * Sublinks must be treated separately as type==link
679a53f50b9Schristos * when the base type is different.
680a53f50b9Schristos */
681a53f50b9Schristos if (mp->am_link && mf->mf_ops != &amfs_link_ops)
682a53f50b9Schristos amfs_link_ops.umount_fs(mp, mf);
683a53f50b9Schristos
684a53f50b9Schristos #ifdef HAVE_FS_AUTOFS
685a53f50b9Schristos if (mf->mf_flags & MFF_IS_AUTOFS)
686a53f50b9Schristos autofs_release_fh(mp);
687a53f50b9Schristos if (mp->am_flags & AMF_AUTOFS)
688a53f50b9Schristos autofs_umount_succeeded(mp);
689a53f50b9Schristos #endif /* HAVE_FS_AUTOFS */
690a53f50b9Schristos
691a53f50b9Schristos /*
692a53f50b9Schristos * Clean up any directories that were made
693a53f50b9Schristos *
694a53f50b9Schristos * If we remove the mount point of a pending mount, any queued access
695a53f50b9Schristos * to it will fail. So don't do it in that case.
696a53f50b9Schristos * Also don't do it if the refcount is > 1.
697a53f50b9Schristos */
698a53f50b9Schristos if (mf->mf_flags & MFF_MKMNT &&
699a53f50b9Schristos mf->mf_refc == 1 &&
700a53f50b9Schristos !(mp->am_flags & AMF_REMOUNT)) {
701a53f50b9Schristos plog(XLOG_INFO, "removing mountpoint directory '%s'", mf->mf_mount);
702a53f50b9Schristos rmdirs(mf->mf_mount);
703a53f50b9Schristos mf->mf_flags &= ~MFF_MKMNT;
704a53f50b9Schristos }
705a53f50b9Schristos
706a53f50b9Schristos /*
707a53f50b9Schristos * If this is a pseudo-directory then adjust the link count
708a53f50b9Schristos * in the parent
709a53f50b9Schristos */
710a53f50b9Schristos if (mp->am_parent && mp->am_fattr.na_type == NFDIR)
711a53f50b9Schristos --mp->am_parent->am_fattr.na_nlink;
712a53f50b9Schristos
713a53f50b9Schristos /*
714a53f50b9Schristos * Update mtime of parent node
715a53f50b9Schristos */
716*8bae5d40Schristos if (mp->am_parent && mp->am_parent->am_al->al_mnt)
717a53f50b9Schristos clocktime(&mp->am_parent->am_fattr.na_mtime);
718a53f50b9Schristos
719a53f50b9Schristos if (mp->am_parent && (mp->am_flags & AMF_REMOUNT)) {
720*8bae5d40Schristos char *fname = xstrdup(mp->am_name);
721a53f50b9Schristos am_node *mp_parent = mp->am_parent;
722*8bae5d40Schristos mntfs *mf_parent = mp_parent->am_al->al_mnt;
7234bcd344eSchristos am_node fake_mp;
724a53f50b9Schristos int error = 0;
725a53f50b9Schristos
7264bcd344eSchristos /*
7274bcd344eSchristos * We need to use notify_child() after free_map(), so save enough
7284bcd344eSchristos * to do that in fake_mp.
7294bcd344eSchristos */
7304bcd344eSchristos fake_mp.am_fd[1] = mp->am_fd[1];
7314bcd344eSchristos mp->am_fd[1] = -1;
7324bcd344eSchristos
733a53f50b9Schristos free_map(mp);
734a53f50b9Schristos plog(XLOG_INFO, "am_unmounted: remounting %s", fname);
735a53f50b9Schristos mp = mf_parent->mf_ops->lookup_child(mp_parent, fname, &error, VLOOK_CREATE);
736a53f50b9Schristos if (mp && error < 0)
737*8bae5d40Schristos (void)mf_parent->mf_ops->mount_child(mp, &error);
738a53f50b9Schristos if (error > 0) {
739a53f50b9Schristos errno = error;
740a53f50b9Schristos plog(XLOG_ERROR, "am_unmounted: could not remount %s: %m", fname);
7414bcd344eSchristos notify_child(&fake_mp, AMQ_UMNT_OK, 0, 0);
7424bcd344eSchristos } else {
7434bcd344eSchristos notify_child(&fake_mp, AMQ_UMNT_FAILED, EBUSY, 0);
744a53f50b9Schristos }
745a53f50b9Schristos XFREE(fname);
7464bcd344eSchristos } else {
747a53f50b9Schristos /*
748a53f50b9Schristos * We have a race here.
749a53f50b9Schristos * If this node has a pending mount and amd is going down (unmounting
750a53f50b9Schristos * everything in the process), then we could potentially free it here
751a53f50b9Schristos * while a struct continuation still has a reference to it. So when
752a53f50b9Schristos * amfs_cont is called, it blows up.
753a53f50b9Schristos * We avoid the race by refusing to free any nodes that have
754*8bae5d40Schristos * pending mounts (defined as having a non-NULL am_alarray).
755a53f50b9Schristos */
7564bcd344eSchristos notify_child(mp, AMQ_UMNT_OK, 0, 0); /* do this regardless */
757*8bae5d40Schristos if (!mp->am_alarray)
758a53f50b9Schristos free_map(mp);
759a53f50b9Schristos }
7604bcd344eSchristos }
761a53f50b9Schristos
762a53f50b9Schristos
763a53f50b9Schristos /*
764a53f50b9Schristos * Fork the automounter
765a53f50b9Schristos *
766a53f50b9Schristos * TODO: Need a better strategy for handling errors
767a53f50b9Schristos */
768a53f50b9Schristos static int
dofork(void)769a53f50b9Schristos dofork(void)
770a53f50b9Schristos {
771a53f50b9Schristos int pid;
772a53f50b9Schristos
773a53f50b9Schristos top:
774a53f50b9Schristos pid = fork();
775a53f50b9Schristos
776a53f50b9Schristos if (pid < 0) { /* fork error, retry in 1 second */
777a53f50b9Schristos sleep(1);
778a53f50b9Schristos goto top;
779a53f50b9Schristos }
780a53f50b9Schristos if (pid == 0) { /* child process (foreground==false) */
781a53f50b9Schristos am_set_mypid();
782a53f50b9Schristos foreground = 0;
783a53f50b9Schristos } else { /* parent process, has one more child */
784a53f50b9Schristos NumChildren++;
785a53f50b9Schristos }
786a53f50b9Schristos
787a53f50b9Schristos return pid;
788a53f50b9Schristos }
789a53f50b9Schristos
790a53f50b9Schristos
791a53f50b9Schristos int
background(void)792a53f50b9Schristos background(void)
793a53f50b9Schristos {
794a53f50b9Schristos int pid = dofork();
795a53f50b9Schristos
796a53f50b9Schristos if (pid == 0) {
797a53f50b9Schristos dlog("backgrounded");
798a53f50b9Schristos foreground = 0;
799a53f50b9Schristos } else
800a53f50b9Schristos dlog("forked process %d", pid);
801a53f50b9Schristos return pid;
802a53f50b9Schristos }
803