xref: /netbsd/external/bsd/am-utils/dist/amd/restart.c (revision 6550d01e)
1 /*	$NetBSD: restart.c,v 1.1.1.2 2009/03/20 20:26:50 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/restart.c
43  *
44  */
45 
46 #ifdef HAVE_CONFIG_H
47 # include <config.h>
48 #endif /* HAVE_CONFIG_H */
49 #include <am_defs.h>
50 #include <amd.h>
51 
52 
53 static void
54 restart_fake_mntfs(mntent_t *me, am_ops *fs_ops)
55 {
56   mntfs *mf;
57   am_opts mo;
58   char *cp;
59 
60   /*
61    * Partially fake up an opts structure
62    */
63   memset(&mo, 0, sizeof(mo));
64   mo.opt_rhost = NULL;
65   mo.opt_rfs = NULL;
66   cp = strchr(me->mnt_fsname, ':');
67   if (cp) {
68     *cp = '\0';
69     mo.opt_rhost = strdup(me->mnt_fsname);
70     mo.opt_rfs = strdup(cp + 1);
71     *cp = ':';
72   } else if (STREQ(me->mnt_type, MNTTAB_TYPE_NFS)) {
73     /*
74      * Hacky workaround for mnttab NFS entries that only list the server
75      */
76     plog(XLOG_WARNING, "NFS server entry assumed to be %s:/", me->mnt_fsname);
77     mo.opt_rhost = strdup(me->mnt_fsname);
78     mo.opt_rfs = strdup("/");
79     me->mnt_fsname = str3cat(me->mnt_fsname, mo.opt_rhost, ":", "/");
80   }
81   mo.opt_fs = me->mnt_dir;
82   mo.opt_opts = me->mnt_opts;
83 
84   /*
85    * Make a new mounted filesystem
86    */
87   mf = find_mntfs(fs_ops, &mo, me->mnt_dir,
88 		  me->mnt_fsname, "", me->mnt_opts, "");
89   if (mf->mf_refc == 1) {
90     mf->mf_flags |= MFF_RESTART | MFF_MOUNTED;
91     mf->mf_error = 0;		     /* Already mounted correctly */
92     mf->mf_fo = NULL;
93     /*
94      * Only timeout non-NFS entries
95      */
96     if (!STREQ(me->mnt_type, MNTTAB_TYPE_NFS))
97       mf->mf_flags |= MFF_RSTKEEP;
98     if (fs_ops->fs_init) {
99       /*
100        * Don't care whether this worked since
101        * it is checked again when the fs is
102        * inherited.
103        */
104       (void) (*fs_ops->fs_init) (mf);
105     }
106     plog(XLOG_INFO, "%s restarted fstype %s on %s, flags 0x%x",
107 	 me->mnt_fsname, fs_ops->fs_type, me->mnt_dir, mf->mf_flags);
108   } else {
109     /* Something strange happened - two mounts at the same place! */
110     free_mntfs(mf);
111   }
112   /*
113    * Clean up mo
114    */
115   if (mo.opt_rhost)
116     XFREE(mo.opt_rhost);
117   if (mo.opt_rfs)
118     XFREE(mo.opt_rfs);
119 }
120 
121 
122 /*
123  * Handle an amd restart.
124  *
125  * Scan through the mount list finding all "interesting" mount points.
126  * Next hack up partial data structures and add the mounted file
127  * system to the list of known filesystems.
128  *
129  * This module relies on internal details of other components.  If
130  * you change something else make *sure* restart() still works.
131  */
132 void
133 restart(void)
134 {
135   mntlist *ml, *mlp;
136 
137   /*
138    * Read the existing mount table.  For each entry, find nfs, ufs or auto
139    * mounts and create a partial am_node to represent it.
140    */
141   for (mlp = ml = read_mtab("restart", mnttab_file_name);
142        mlp;
143        mlp = mlp->mnext) {
144     mntent_t *me = mlp->mnt;
145     am_ops *fs_ops = NULL;
146 
147     if (STREQ(me->mnt_type, MNTTAB_TYPE_NFS)) {
148       /*
149        * NFS entry, or possibly an Amd entry...
150        * The mnt_fsname for daemon mount points is
151        * 	host:(pidXXX)
152        * or (seen on Solaris)
153        *        host:daemon(pidXXX)
154        */
155       char *colon = strchr(me->mnt_fsname, ':');
156       if (colon && strstr(colon, "(pid"))
157 	continue;
158     }
159 
160     /* Search for the correct filesystem ops */
161     fs_ops = ops_search(me->mnt_type);
162 
163     /*
164      * Catch everything else with symlinks to
165      * avoid recursive mounts.  This is debatable...
166      */
167     if (!fs_ops)
168       fs_ops = &amfs_link_ops;
169 
170     restart_fake_mntfs(me, fs_ops);
171   }
172 
173   /*
174    * Free the mount list
175    */
176   free_mntlist(ml);
177 }
178 
179 
180 /*
181  * Handle an amd restart for amd's own mount points.
182  *
183  * Scan through the mount list finding all daemon mount points
184  * (determined by the presence of a pid inside the mount info).
185  * Next hack up partial data structures and add the mounted file
186  * system to the list of known filesystems.
187  *
188  * This module relies on internal details of other components.  If
189  * you change something else make *sure* restart() still works.
190  */
191 void
192 restart_automounter_nodes(void)
193 {
194   mntlist *ml, *mlp;
195   /* reasonably sized list of restarted nfs ports */
196   u_short old_ports[256];
197 
198   memset((voidp) &old_ports, 0, sizeof(u_short) * 256);
199 
200   /*
201    * Read the existing mount table.  For each entry, find nfs, ufs or auto
202    * mounts and create a partial am_node to represent it.
203    */
204   for (mlp = ml = read_mtab("restart", mnttab_file_name);
205        mlp;
206        mlp = mlp->mnext) {
207     mntent_t *me = mlp->mnt;
208     am_ops *fs_ops = NULL;
209     char *colon;
210     long pid;
211     u_short port;
212     int err;
213 
214     if (!STREQ(me->mnt_type, MNTTAB_TYPE_NFS))
215       continue;			/* to next mlp */
216     /*
217      * NFS entry, or possibly an Amd entry...
218      * The mnt_fsname for daemon mount points is
219      *	   host:(pidXXX)
220      * or (seen on Solaris)
221      *     host:daemon(pidXXX)
222      */
223     colon = strchr(me->mnt_fsname, ':');
224     if (!colon || !strstr(colon, "(pid"))
225       continue;
226     /* if got here, then we matched an existing Amd mount point */
227     err = 1;
228 
229     plog(XLOG_WARNING, "%s is an existing automount point", me->mnt_dir);
230 
231     /* Is the old automounter still alive? */
232     if (sscanf(colon, "%*[^(](pid%ld%*[,)]", &pid) != 1) {
233       plog(XLOG_WARNING, "Can't parse pid in %s", me->mnt_fsname);
234       goto give_up;
235     }
236     if (kill(pid, 0) != -1 || errno != ESRCH) {
237       plog(XLOG_WARNING, "Automounter (pid: %ld) still alive", pid);
238       goto give_up;
239     }
240 
241     /*
242      * Do we have a map for this mount point?  Who cares, we'll restart
243      * anyway -- getting ESTALE is way better than hanging.
244      */
245 
246     /* Can we restart it? Only if it tells us what port it was using... */
247     if (sscanf(colon, "%*[^,],port%hu)", &port) != 1) {
248       plog(XLOG_WARNING, "No port specified for %s", me->mnt_fsname);
249       goto give_up;
250     }
251 
252     /* Maybe we already own that port... */
253     if (port != nfs_port) {
254       int i;
255       for (i = 0; i < 256; i++) {
256 	if (old_ports[i] == port ||
257 	    old_ports[i] == 0)
258 	  break;
259       }
260       if (i == 256) {
261 	plog(XLOG_WARNING, "Too many open ports (256)");
262 	goto give_up;
263       }
264 
265       if (old_ports[i] == 0) {
266 	int soNFS;
267 	SVCXPRT *nfsxprt;
268 	if (create_nfs_service(&soNFS, &port, &nfsxprt, nfs_program_2) != 0) {
269 	  plog(XLOG_WARNING, "Can't bind to port %u", port);
270 	  goto give_up;
271 	}
272 	old_ports[i] = nfs_port = port;
273       }
274     }
275     err = 0;
276 
277   give_up:
278     if (err) {
279       plog(XLOG_WARNING, "Can't restart %s, leaving it alone", me->mnt_dir);
280       fs_ops = &amfs_link_ops;
281     } else {
282       fs_ops = &amfs_toplvl_ops;
283     }
284 
285     restart_fake_mntfs(me, fs_ops);
286   } /* end of "for (mlp" */
287 
288   /* free the mount list */
289   free_mntlist(ml);
290 }
291