xref: /illumos-gate/usr/src/cmd/backup/dump/dumpfstab.c (revision fc910014e8a32a65612105835a10995f2c13d942)
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