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 *
mygetmntent(f,name)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 *
addvfstab(tablename,pm)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 *
allocmntent(mnt)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
mnttabread()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 *
addmtab(tablename,pm)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 *
mnttabsearch(key,mounted)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__
setmnttab(void)317 setmnttab(void)
318 #else
319 setmnttab()
320 #endif
321 {
322 current = mnttable;
323 set = 1;
324 }
325
326 struct mntent *
327 #ifdef __STDC__
getmnttab(void)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