xref: /netbsd/external/bsd/am-utils/dist/amd/restart.c (revision 31bdb48a)
1 /*	$NetBSD: restart.c,v 1.1.1.3 2015/01/17 16:34:15 christos Exp $	*/
2 
3 /*
4  * Copyright (c) 1997-2014 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. Neither the name of the University nor the names of its contributors
22  *    may be used to endorse or promote products derived from this software
23  *    without specific prior written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35  * SUCH DAMAGE.
36  *
37  *
38  * File: am-utils/amd/restart.c
39  *
40  */
41 
42 #ifdef HAVE_CONFIG_H
43 # include <config.h>
44 #endif /* HAVE_CONFIG_H */
45 #include <am_defs.h>
46 #include <amd.h>
47 
48 
49 static void
restart_fake_mntfs(mntent_t * me,am_ops * fs_ops)50 restart_fake_mntfs(mntent_t *me, am_ops *fs_ops)
51 {
52   mntfs *mf;
53   am_opts mo;
54   char *cp;
55 
56   /*
57    * Partially fake up an opts structure
58    */
59   memset(&mo, 0, sizeof(mo));
60   mo.opt_rhost = NULL;
61   mo.opt_rfs = NULL;
62   cp = strchr(me->mnt_fsname, ':');
63   if (cp) {
64     *cp = '\0';
65     mo.opt_rhost = xstrdup(me->mnt_fsname);
66     mo.opt_rfs = xstrdup(cp + 1);
67     *cp = ':';
68   } else if (STREQ(me->mnt_type, MNTTAB_TYPE_NFS)) {
69     /*
70      * Hacky workaround for mnttab NFS entries that only list the server
71      */
72     plog(XLOG_WARNING, "NFS server entry assumed to be %s:/", me->mnt_fsname);
73     mo.opt_rhost = xstrdup(me->mnt_fsname);
74     mo.opt_rfs = xstrdup("/");
75     me->mnt_fsname = str3cat(me->mnt_fsname, mo.opt_rhost, ":", "/");
76   }
77   mo.opt_fs = me->mnt_dir;
78   mo.opt_opts = me->mnt_opts;
79 
80   /*
81    * Make a new mounted filesystem
82    */
83   mf = find_mntfs(fs_ops, &mo, me->mnt_dir,
84 		  me->mnt_fsname, "", me->mnt_opts, "");
85   if (mf->mf_refc == 1) {
86     mf->mf_flags |= MFF_RESTART | MFF_MOUNTED;
87     mf->mf_error = 0;		     /* Already mounted correctly */
88     /*
89      * Only timeout non-NFS entries
90      */
91     if (!STREQ(me->mnt_type, MNTTAB_TYPE_NFS))
92       mf->mf_flags |= MFF_RSTKEEP;
93     if (fs_ops->fs_init) {
94       /*
95        * Don't care whether this worked since
96        * it is checked again when the fs is
97        * inherited.
98        */
99       (void) (*fs_ops->fs_init) (mf);
100     }
101     plog(XLOG_INFO, "%s restarted fstype %s on %s, flags 0x%x",
102 	 me->mnt_fsname, fs_ops->fs_type, me->mnt_dir, mf->mf_flags);
103   } else {
104     /* Something strange happened - two mounts at the same place! */
105     free_mntfs(mf);
106   }
107   /*
108    * Clean up mo
109    */
110   XFREE(mo.opt_rhost);
111   XFREE(mo.opt_rfs);
112 }
113 
114 
115 /*
116  * Handle an amd restart.
117  *
118  * Scan through the mount list finding all "interesting" mount points.
119  * Next hack up partial data structures and add the mounted file
120  * system to the list of known filesystems.
121  *
122  * This module relies on internal details of other components.  If
123  * you change something else make *sure* restart() still works.
124  */
125 void
restart(void)126 restart(void)
127 {
128   mntlist *ml, *mlp;
129 
130   /*
131    * Read the existing mount table.  For each entry, find nfs, ufs or auto
132    * mounts and create a partial am_node to represent it.
133    */
134   for (mlp = ml = read_mtab("restart", mnttab_file_name);
135        mlp;
136        mlp = mlp->mnext) {
137     mntent_t *me = mlp->mnt;
138     am_ops *fs_ops = NULL;
139 
140     if (STREQ(me->mnt_type, MNTTAB_TYPE_NFS)) {
141       /*
142        * NFS entry, or possibly an Amd entry...
143        * The mnt_fsname for daemon mount points is
144        * 	host:(pidXXX)
145        * or (seen on Solaris)
146        *        host:daemon(pidXXX)
147        */
148       char *colon = strchr(me->mnt_fsname, ':');
149       if (colon && strstr(colon, "(pid"))
150 	continue;
151     }
152 
153     /* Search for the correct filesystem ops */
154     fs_ops = ops_search(me->mnt_type);
155 
156     /*
157      * Catch everything else with symlinks to
158      * avoid recursive mounts.  This is debatable...
159      */
160     if (!fs_ops)
161       fs_ops = &amfs_link_ops;
162 
163     restart_fake_mntfs(me, fs_ops);
164   }
165 
166   /*
167    * Free the mount list
168    */
169   free_mntlist(ml);
170 }
171 
172 
173 /*
174  * Handle an amd restart for amd's own mount points.
175  *
176  * Scan through the mount list finding all daemon mount points
177  * (determined by the presence of a pid inside the mount info).
178  * Next hack up partial data structures and add the mounted file
179  * system to the list of known filesystems.
180  *
181  * This module relies on internal details of other components.  If
182  * you change something else make *sure* restart() still works.
183  */
184 void
restart_automounter_nodes(void)185 restart_automounter_nodes(void)
186 {
187   mntlist *ml, *mlp;
188   /* reasonably sized list of restarted nfs ports */
189   u_short old_ports[256];
190 
191   memset((voidp) &old_ports, 0, sizeof(u_short) * 256);
192 
193   /*
194    * Read the existing mount table.  For each entry, find nfs, ufs or auto
195    * mounts and create a partial am_node to represent it.
196    */
197   for (mlp = ml = read_mtab("restart", mnttab_file_name);
198        mlp;
199        mlp = mlp->mnext) {
200     mntent_t *me = mlp->mnt;
201     am_ops *fs_ops = NULL;
202     char *colon;
203     long pid;
204     u_short port;
205     int err;
206 
207     if (!STREQ(me->mnt_type, MNTTAB_TYPE_NFS))
208       continue;			/* to next mlp */
209     /*
210      * NFS entry, or possibly an Amd entry...
211      * The mnt_fsname for daemon mount points is
212      *	   host:(pidXXX)
213      * or (seen on Solaris)
214      *     host:daemon(pidXXX)
215      */
216     colon = strchr(me->mnt_fsname, ':');
217     if (!colon || !strstr(colon, "(pid"))
218       continue;
219     /* if got here, then we matched an existing Amd mount point */
220     err = 1;
221 
222     plog(XLOG_WARNING, "%s is an existing automount point", me->mnt_dir);
223 
224     /* Is the old automounter still alive? */
225     if (sscanf(colon, "%*[^(](pid%ld%*[,)]", &pid) != 1) {
226       plog(XLOG_WARNING, "Can't parse pid in %s", me->mnt_fsname);
227       goto give_up;
228     }
229     if (kill(pid, 0) != -1 || errno != ESRCH) {
230       plog(XLOG_WARNING, "Automounter (pid: %ld) still alive", pid);
231       goto give_up;
232     }
233 
234     /*
235      * Do we have a map for this mount point?  Who cares, we'll restart
236      * anyway -- getting ESTALE is way better than hanging.
237      */
238 
239     /* Can we restart it? Only if it tells us what port it was using... */
240     if (sscanf(colon, "%*[^,],port%hu)", &port) != 1) {
241       plog(XLOG_WARNING, "No port specified for %s", me->mnt_fsname);
242       goto give_up;
243     }
244 
245     /* Maybe we already own that port... */
246     if (port != nfs_port) {
247       int i;
248       for (i = 0; i < 256; i++) {
249 	if (old_ports[i] == port ||
250 	    old_ports[i] == 0)
251 	  break;
252       }
253       if (i == 256) {
254 	plog(XLOG_WARNING, "Too many open ports (256)");
255 	goto give_up;
256       }
257 
258       if (old_ports[i] == 0) {
259 	int soNFS;
260 	SVCXPRT *nfsxprt;
261 	if (create_nfs_service(&soNFS, &port, &nfsxprt, nfs_dispatcher,
262 	    get_nfs_dispatcher_version(nfs_dispatcher)) != 0) {
263 	  plog(XLOG_WARNING, "Can't bind to port %u", port);
264 	  goto give_up;
265 	}
266 	old_ports[i] = nfs_port = port;
267       }
268     }
269     err = 0;
270 
271   give_up:
272     if (err) {
273       plog(XLOG_WARNING, "Can't restart %s, leaving it alone", me->mnt_dir);
274       fs_ops = &amfs_link_ops;
275     } else {
276       fs_ops = &amfs_toplvl_ops;
277     }
278 
279     restart_fake_mntfs(me, fs_ops);
280   } /* end of "for (mlp" */
281 
282   /* free the mount list */
283   free_mntlist(ml);
284 }
285