Merge branch 'vendor/OPENSSL'
[dragonfly.git] / contrib / amd / amd / amfs_toplvl.c
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.
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  *      %W% (Berkeley) %G%
40  *
41  * $Id: amfs_toplvl.c,v 1.5 1999/02/04 07:24:14 ezk Exp $
42  *
43  */
44
45 /*
46  * Top-level file system
47  */
48
49 #ifdef HAVE_CONFIG_H
50 # include <config.h>
51 #endif /* HAVE_CONFIG_H */
52 #include <am_defs.h>
53 #include <amd.h>
54
55 /****************************************************************************
56  *** FORWARD DEFINITIONS                                                  ***
57  ****************************************************************************/
58
59
60 /****************************************************************************
61  *** OPS STRUCTURES                                                       ***
62  ****************************************************************************/
63 am_ops amfs_toplvl_ops =
64 {
65   "toplvl",
66   amfs_auto_match,
67   0,                            /* amfs_auto_init */
68   amfs_toplvl_mount,
69   0,
70   amfs_toplvl_umount,
71   0,
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
79 };
80
81
82 /****************************************************************************
83  *** FUNCTIONS                                                             ***
84  ****************************************************************************/
85
86 /*
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.
92  *
93  * NOTE: automounter mounts in themselves are using NFS Version 2.
94  */
95 static int
96 mount_amfs_toplvl(char *dir, char *opts)
97 {
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 */
109
110   memset((voidp) &mnt, 0, sizeof(mnt));
111   mnt.mnt_dir = dir;
112   mnt.mnt_fsname = pid_fsname;
113   mnt.mnt_opts = opts;
114
115   /*
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".
120    */
121   mnt.mnt_type = HIDE_MOUNT_TYPE;
122
123   retry = hasmntval(&mnt, MNTTAB_OPT_RETRY);
124   if (retry <= 0)
125     retry = 2;                  /* XXX */
126
127   /*
128    * SET MOUNT ARGS
129    */
130   /*
131    * get fhandle of remote path for automount point
132    */
133   fhp = root_fh(dir);
134   if (!fhp) {
135     plog(XLOG_FATAL, "Can't find root file handle for %s", dir);
136     return EINVAL;
137   }
138
139 #ifndef HAVE_TRANSPORT_TYPE_TLI
140   /*
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.
144    */
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;
154   }
155 #endif /* not HAVE_TRANSPORT_TYPE_TLI */
156
157   /*
158    * Make a ``hostname'' string for the kernel
159    */
160   sprintf(fs_hostname, "pid%ld@%s:%s",
161           (long) (foreground ? am_mypid : getppid()),
162           am_get_hostname(),
163           dir);
164   /*
165    * Most kernels have a name length restriction (64 bytes)...
166    */
167   if (strlen(fs_hostname) >= MAXHOSTNAMELEN)
168     strcpy(fs_hostname + MAXHOSTNAMELEN - 3, "..");
169 #ifdef HOSTNAMESZ
170   /*
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.
174    */
175   if (strlen(fs_hostname) >= HOSTNAMESZ)
176     strcpy(fs_hostname + HOSTNAMESZ - 3, "..");
177 #endif /* HOSTNAMESZ */
178
179   /*
180    * Finally we can compute the mount genflags set above,
181    * and add any automounter specific flags.
182    */
183   genflags = compute_mount_flags(&mnt);
184   genflags |= compute_automounter_mount_flags(&mnt);
185
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);
199   /*
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)!
207    */
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 */
220
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);
227
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);
233   }
234 #endif /* DEBUG */
235   error = mount_fs(&mnt, genflags, (caddr_t) &nfs_args, retry, type,
236                    0, NULL, mnttab_file_name);
237
238 #ifdef HAVE_TRANSPORT_TYPE_TLI
239   free_knetconfig(nfs_args.knconf);
240   /*
241    * local automounter mounts do not allocate a special address, so
242    * no need to XFREE(nfs_args.addr) under TLI.
243    */
244 #endif /* HAVE_TRANSPORT_TYPE_TLI */
245
246   return error;
247 }
248
249
250 /*
251  * Mount the top-level
252  */
253 int
254 amfs_toplvl_mount(am_node *mp)
255 {
256   mntfs *mf = mp->am_mnt;
257   struct stat stb;
258   char opts[256], preopts[256];
259   int error;
260   char *mnttype;
261
262   /*
263    * Mounting the automounter.
264    * Make sure the mount directory exists, construct
265    * the mount options and call the mount_amfs_toplvl routine.
266    */
267
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;
273   }
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";
284
285   /*
286    * Construct some mount options:
287    *
288    * Tack on magic map=<mapname> option in mtab to emulate
289    * SunOS automounter behavior.
290    */
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);
307
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;
314   }
315   return 0;
316 }
317
318
319 void
320 amfs_toplvl_mounted(mntfs *mf)
321 {
322   amfs_auto_mkcacheref(mf);
323 }
324
325
326 /*
327  * Unmount a top-level automount node
328  */
329 int
330 amfs_toplvl_umount(am_node *mp)
331 {
332   int error;
333   struct stat stb;
334
335 again:
336   /*
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.
346    */
347   if (lstat(mp->am_path, &stb) < 0) {
348 #ifdef DEBUG
349     dlog("lstat(%s): %m", mp->am_path);
350 #endif /* DEBUG */
351   }
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;
357   }
358   return error;
359 }