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