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