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