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