1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright (c) 1996,1998 by Sun Microsystems, Inc. 24 * All rights reserved. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include "dump.h" 30 31 /* 32 * File system mount table input routines. We handle a 33 * a combination of BSD and SVR4 formats by coding functions 34 * to explicitly read the SVR4 vfstab file and using 35 * #define's to build a routine to read both BSD files 36 * (fstab and mtab) and SVR4's mnttab file. Internally 37 * we keep everything in the common (mtab/mnttab) format. 38 */ 39 static struct pmntent { 40 struct mntent *pm_mnt; 41 struct pmntent *pm_next; 42 } *mnttable; 43 44 /* Note that nothing is ever free()'d, so this is safe */ 45 #define mntstrdup(s) ((s) ? strdup((s)) : "") 46 47 #ifdef __STDC__ 48 static struct mntent *mygetmntent(FILE *, char *); 49 static struct pmntent *addmtab(char *, struct pmntent *); 50 static struct mntent *allocmntent(struct mntent *); 51 #else /* !__STDC__ */ 52 static struct pmntent *addmtab(); 53 static struct mntent *mygetmntent(); 54 static struct mntent *allocmntent(); 55 static int idatesort(); 56 #endif 57 58 static struct mntent * 59 mygetmntent(f, name) 60 FILE *f; 61 char *name; 62 { 63 static struct mntent mt; 64 int status; 65 66 if ((status = getmntent(f, &mt)) == 0) 67 return (&mt); 68 69 switch (status) { 70 case EOF: break; /* normal exit condition */ 71 case MNT_TOOLONG: 72 msg(gettext("%s has a line that is too long\n"), name); 73 break; 74 case MNT_TOOMANY: 75 msg(gettext("%s has a line with too many entries\n"), name); 76 break; 77 case MNT_TOOFEW: 78 msg(gettext("%s has a line with too few entries\n"), name); 79 break; 80 default: 81 msg(gettext( 82 "Unknown return code, %d, from getmntent() on %s\n"), 83 status, name); 84 break; 85 } 86 87 return (NULL); 88 } 89 90 /* 91 * Read in SVR4 vfstab-format table. 92 */ 93 static struct pmntent * 94 addvfstab(tablename, pm) 95 char *tablename; 96 struct pmntent *pm; 97 { 98 struct mnttab *mnt; 99 struct vfstab vfs; 100 FILE *tp; 101 int status; 102 103 assert(((mnttable == NULL) && (pm == NULL)) || (pm != NULL)); 104 105 /* 106 * No need to secure this, as tablename is hard-coded to VFSTAB, 107 * and that file is in /etc. If random people have write-permission 108 * there, then there are more problems than any degree of paranoia 109 * on our part can fix. 110 */ 111 tp = fopen(tablename, "r"); 112 if (tp == (FILE *)0) { 113 msg(gettext("Cannot open %s for dump table information.\n"), 114 tablename); 115 return ((struct pmntent *)0); 116 } 117 while ((status = getvfsent(tp, &vfs)) == 0) { 118 if (vfs.vfs_fstype == (char *)0 || 119 strcmp(vfs.vfs_fstype, MNTTYPE_42) != 0) 120 continue; 121 122 mnt = (struct mnttab *)xmalloc(sizeof (*mnt)); 123 mnt->mnt_fsname = mntstrdup(vfs.vfs_special); 124 mnt->mnt_dir = mntstrdup(vfs.vfs_mountp); 125 mnt->mnt_type = mntstrdup(vfs.vfs_fstype); 126 mnt->mnt_opts = mntstrdup(vfs.vfs_mntopts); 127 128 if (mnttable == (struct pmntent *)0) 129 /* 130 * Guaranteed by caller that pm will also be NULL, 131 * so no memory leak to worry about. 132 */ 133 mnttable = pm = (struct pmntent *)xmalloc(sizeof (*pm)); 134 else { 135 /* Guaranteed pm not NULL by caller and local logic */ 136 pm->pm_next = (struct pmntent *)xmalloc(sizeof (*pm)); 137 pm = pm->pm_next; 138 } 139 pm->pm_mnt = mnt; 140 pm->pm_next = (struct pmntent *)0; 141 } 142 143 switch (status) { 144 case EOF: break; /* normal exit condition */ 145 case VFS_TOOLONG: 146 msg(gettext("%s has a line that is too long\n"), tablename); 147 break; 148 case VFS_TOOMANY: 149 msg(gettext("%s has a line with too many entries\n"), 150 tablename); 151 break; 152 case VFS_TOOFEW: 153 msg(gettext("%s has a line with too few entries\n"), tablename); 154 break; 155 default: 156 msg(gettext( 157 "Unknown return code, %d, from getvfsent() on %s\n"), 158 status, tablename); 159 break; 160 } 161 (void) fclose(tp); 162 return (pm); 163 } 164 165 static struct mntent * 166 allocmntent(mnt) 167 struct mntent *mnt; 168 { 169 struct mntent *new; 170 171 new = (struct mntent *)xmalloc(sizeof (*mnt)); 172 new->mnt_fsname = mntstrdup(mnt->mnt_fsname); /* mnt_special */ 173 new->mnt_dir = mntstrdup(mnt->mnt_dir); /* mnt_mountp */ 174 new->mnt_type = mntstrdup(mnt->mnt_type); /* mnt_fstype */ 175 new->mnt_opts = mntstrdup(mnt->mnt_opts); /* mnt_mntopts */ 176 return (new); 177 } 178 179 void 180 mnttabread() 181 { 182 struct pmntent *pm = (struct pmntent *)0; 183 184 if (mnttable != (struct pmntent *)0) 185 return; 186 /* 187 * Read in the file system mount tables. Order 188 * is important as the first matched entry is used 189 * if the target device/filesystem is not mounted. 190 * We try fstab or vfstab first, then mtab or mnttab. 191 */ 192 pm = addvfstab(VFSTAB, pm); 193 (void) addmtab(MOUNTED, pm); 194 } 195 196 static struct pmntent * 197 addmtab(tablename, pm) 198 char *tablename; 199 struct pmntent *pm; 200 { 201 struct mntent *mnt; 202 FILE *tp; 203 204 tp = setmntent(tablename, "r"); 205 if (tp == (FILE *)0) { 206 msg(gettext("Cannot open %s for dump table information.\n"), 207 tablename); 208 return ((struct pmntent *)0); 209 } 210 while (mnt = mygetmntent(tp, tablename)) { 211 if (mnt->mnt_type == (char *)0 || 212 strcmp(mnt->mnt_type, MNTTYPE_42) != 0) 213 continue; 214 215 mnt = allocmntent(mnt); 216 if (mnttable == (struct pmntent *)0) 217 /* 218 * Guaranteed by caller that pm will also be NULL, 219 * so no memory leak to worry about. 220 */ 221 mnttable = pm = (struct pmntent *)xmalloc(sizeof (*pm)); 222 else { 223 /* Guaranteed pm not NULL by caller and local logic */ 224 pm->pm_next = (struct pmntent *)xmalloc(sizeof (*pm)); 225 pm = pm->pm_next; 226 } 227 pm->pm_mnt = mnt; 228 pm->pm_next = (struct pmntent *)0; 229 } 230 (void) endmntent(tp); 231 return (pm); 232 } 233 234 /* 235 * Search in fstab and potentially mtab for a file name. 236 * If "mounted" is non-zero, the target file system must 237 * be mounted in order for the search to succeed. 238 * This file name can be either the special or the path file name. 239 * 240 * The entries in either fstab or mtab are the BLOCK special names, 241 * not the character special names. 242 * The caller of mnttabsearch assures that the character device 243 * is dumped (that is much faster) 244 * 245 * The file name can omit the leading '/'. 246 */ 247 struct mntent * 248 mnttabsearch(key, mounted) 249 char *key; 250 int mounted; 251 { 252 struct pmntent *pm; 253 struct mntent *mnt; 254 struct mntent *first = (struct mntent *)0; 255 char *s; 256 char *gotreal; 257 char path[MAXPATHLEN]; 258 259 for (pm = mnttable; pm; pm = pm->pm_next) { 260 s = NULL; 261 mnt = pm->pm_mnt; 262 if (strcmp(mnt->mnt_dir, key) == 0) 263 goto found; 264 if (strcmp(mnt->mnt_fsname, key) == 0) 265 goto found; 266 if ((s = rawname(mnt->mnt_fsname)) != NULL && 267 strcmp(s, key) == 0) 268 goto found; 269 270 gotreal = realpath(mnt->mnt_dir, path); 271 if (gotreal && strcmp(path, key) == 0) 272 goto found; 273 if (key[0] != '/') { 274 if (*mnt->mnt_fsname == '/' && 275 strcmp(mnt->mnt_fsname + 1, key) == 0) 276 goto found; 277 if (*mnt->mnt_dir == '/' && 278 strcmp(mnt->mnt_dir + 1, key) == 0) 279 goto found; 280 if (gotreal && *path == '/' && 281 strcmp(path + 1, key) == 0) 282 goto found; 283 } 284 if (s != NULL && s != mnt->mnt_fsname) 285 free(s); 286 continue; 287 found: 288 /* Pointer comparison, not string comparison */ 289 if (s != NULL && s != mnt->mnt_fsname) 290 free(s); 291 /* 292 * Found a match; return immediately if 293 * it is mounted (valid), otherwise just 294 * record if it's the first matched entry. 295 */ 296 if (lf_ismounted(mnt->mnt_fsname, mnt->mnt_dir) > 0) 297 return (mnt); 298 else if (first == (struct mntent *)0) 299 first = mnt; 300 } 301 /* 302 * If we get here, there were either 303 * no matches, or no matched entries 304 * were mounted. Return failure if 305 * we were supposed to find a mounted 306 * entry, otherwise return the first 307 * matched entry (or null). 308 */ 309 if (mounted) 310 return ((struct mntent *)0); 311 return (first); 312 } 313 314 static struct pmntent *current; 315 static int set; 316 317 void 318 #ifdef __STDC__ 319 setmnttab(void) 320 #else 321 setmnttab() 322 #endif 323 { 324 current = mnttable; 325 set = 1; 326 } 327 328 struct mntent * 329 #ifdef __STDC__ 330 getmnttab(void) 331 #else 332 getmnttab() 333 #endif 334 { 335 struct pmntent *pm; 336 337 if (!set) 338 setmnttab(); 339 pm = current; 340 if (current) { 341 current = current->pm_next; 342 return (pm->pm_mnt); 343 } 344 return ((struct mntent *)0); 345 } 346