• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * ismounted.c --- Check to see if the filesystem was mounted
3  *
4  * Copyright (C) 1995,1996,1997,1998,1999,2000 Theodore Ts'o.
5  *
6  * %Begin-Header%
7  * This file may be redistributed under the terms of the GNU Library
8  * General Public License, version 2.
9  * %End-Header%
10  */
11 
12 #include <stdio.h>
13 #if HAVE_UNISTD_H
14 #include <unistd.h>
15 #endif
16 #if HAVE_ERRNO_H
17 #include <errno.h>
18 #endif
19 #include <fcntl.h>
20 #ifdef HAVE_LINUX_FD_H
21 #include <linux/fd.h>
22 #endif
23 #ifdef HAVE_LINUX_LOOP_H
24 #include <linux/loop.h>
25 #include <sys/ioctl.h>
26 #ifdef HAVE_LINUX_MAJOR_H
27 #include <linux/major.h>
28 #endif /* HAVE_LINUX_MAJOR_H */
29 #endif /* HAVE_LINUX_LOOP_H */
30 #ifdef HAVE_MNTENT_H
31 #include <mntent.h>
32 #endif
33 #ifdef HAVE_GETMNTINFO
34 #include <paths.h>
35 #include <sys/param.h>
36 #include <sys/mount.h>
37 #endif /* HAVE_GETMNTINFO */
38 #include <string.h>
39 #include <sys/stat.h>
40 
41 #include "ext2_fs.h"
42 #include "ext2fs.h"
43 
44 /*
45  * Check to see if a regular file is mounted.
46  * If /etc/mtab/ is a symlink of /proc/mounts, you will need the following check
47  * because the name in /proc/mounts is a loopback device not a regular file.
48  */
check_loop_mounted(const char * mnt_fsname,dev_t mnt_rdev,dev_t file_dev,ino_t file_ino)49 static int check_loop_mounted(const char *mnt_fsname, dev_t mnt_rdev,
50 				dev_t file_dev, ino_t file_ino)
51 {
52 #if defined(HAVE_LINUX_LOOP_H) && defined(HAVE_LINUX_MAJOR_H)
53 	struct loop_info64 loopinfo;
54 	int loop_fd, ret;
55 
56 	if (major(mnt_rdev) == LOOP_MAJOR) {
57 		loop_fd = open(mnt_fsname, O_RDONLY);
58 		if (loop_fd < 0)
59 			return -1;
60 
61 		ret = ioctl(loop_fd, LOOP_GET_STATUS64, &loopinfo);
62 		close(loop_fd);
63 		if (ret < 0)
64 			return -1;
65 
66 		if (file_dev == loopinfo.lo_device &&
67 				file_ino == loopinfo.lo_inode)
68 			return 1;
69 	}
70 #endif /* defined(HAVE_LINUX_LOOP_H) && defined(HAVE_LINUX_MAJOR_H) */
71 	return 0;
72 }
73 
74 #ifdef HAVE_SETMNTENT
75 /*
76  * Helper function which checks a file in /etc/mtab format to see if a
77  * filesystem is mounted.  Returns an error if the file doesn't exist
78  * or can't be opened.
79  */
check_mntent_file(const char * mtab_file,const char * file,int * mount_flags,char * mtpt,int mtlen)80 static errcode_t check_mntent_file(const char *mtab_file, const char *file,
81 				   int *mount_flags, char *mtpt, int mtlen)
82 {
83 	struct mntent 	*mnt;
84 	struct stat	st_buf;
85 	errcode_t	retval = 0;
86 	dev_t		file_dev=0, file_rdev=0;
87 	ino_t		file_ino=0;
88 	FILE 		*f;
89 	int		fd;
90 
91 	*mount_flags = 0;
92 	if ((f = setmntent (mtab_file, "r")) == NULL) {
93 		if (errno == ENOENT) {
94 			if (getenv("EXT2FS_NO_MTAB_OK"))
95 				return 0;
96 			else
97 				return EXT2_ET_NO_MTAB_FILE;
98 		}
99 		return errno;
100 	}
101 	if (stat(file, &st_buf) == 0) {
102 		if (S_ISBLK(st_buf.st_mode)) {
103 #ifndef __GNU__ /* The GNU hurd is broken with respect to stat devices */
104 			file_rdev = st_buf.st_rdev;
105 #endif	/* __GNU__ */
106 		} else {
107 			file_dev = st_buf.st_dev;
108 			file_ino = st_buf.st_ino;
109 		}
110 	}
111 	while ((mnt = getmntent (f)) != NULL) {
112 		if (mnt->mnt_fsname[0] != '/')
113 			continue;
114 		if (strcmp(file, mnt->mnt_fsname) == 0)
115 			break;
116 		if (stat(mnt->mnt_fsname, &st_buf) == 0) {
117 			if (S_ISBLK(st_buf.st_mode)) {
118 #ifndef __GNU__
119 				if (file_rdev && (file_rdev == st_buf.st_rdev))
120 					break;
121 				if (check_loop_mounted(mnt->mnt_fsname,
122 						st_buf.st_rdev, file_dev,
123 						file_ino) == 1)
124 					break;
125 #endif	/* __GNU__ */
126 			} else {
127 				if (file_dev && ((file_dev == st_buf.st_dev) &&
128 						 (file_ino == st_buf.st_ino)))
129 					break;
130 			}
131 		}
132 	}
133 
134 	if (mnt == 0) {
135 #ifndef __GNU__ /* The GNU hurd is broken with respect to stat devices */
136 		/*
137 		 * Do an extra check to see if this is the root device.  We
138 		 * can't trust /etc/mtab, and /proc/mounts will only list
139 		 * /dev/root for the root filesystem.  Argh.  Instead we
140 		 * check if the given device has the same major/minor number
141 		 * as the device that the root directory is on.
142 		 */
143 		if (file_rdev && stat("/", &st_buf) == 0) {
144 			if (st_buf.st_dev == file_rdev) {
145 				*mount_flags = EXT2_MF_MOUNTED;
146 				if (mtpt)
147 					strncpy(mtpt, "/", mtlen);
148 				goto is_root;
149 			}
150 		}
151 #endif	/* __GNU__ */
152 		goto errout;
153 	}
154 #ifndef __GNU__ /* The GNU hurd is deficient; what else is new? */
155 	/* Validate the entry in case /etc/mtab is out of date */
156 	/*
157 	 * We need to be paranoid, because some broken distributions
158 	 * (read: Slackware) don't initialize /etc/mtab before checking
159 	 * all of the non-root filesystems on the disk.
160 	 */
161 	if (stat(mnt->mnt_dir, &st_buf) < 0) {
162 		retval = errno;
163 		if (retval == ENOENT) {
164 #ifdef DEBUG
165 			printf("Bogus entry in %s!  (%s does not exist)\n",
166 			       mtab_file, mnt->mnt_dir);
167 #endif /* DEBUG */
168 			retval = 0;
169 		}
170 		goto errout;
171 	}
172 	if (file_rdev && (st_buf.st_dev != file_rdev)) {
173 #ifdef DEBUG
174 		printf("Bogus entry in %s!  (%s not mounted on %s)\n",
175 		       mtab_file, file, mnt->mnt_dir);
176 #endif /* DEBUG */
177 		goto errout;
178 	}
179 #endif /* __GNU__ */
180 	*mount_flags = EXT2_MF_MOUNTED;
181 
182 #ifdef MNTOPT_RO
183 	/* Check to see if the ro option is set */
184 	if (hasmntopt(mnt, MNTOPT_RO))
185 		*mount_flags |= EXT2_MF_READONLY;
186 #endif
187 
188 	if (mtpt)
189 		strncpy(mtpt, mnt->mnt_dir, mtlen);
190 	/*
191 	 * Check to see if we're referring to the root filesystem.
192 	 * If so, do a manual check to see if we can open /etc/mtab
193 	 * read/write, since if the root is mounted read/only, the
194 	 * contents of /etc/mtab may not be accurate.
195 	 */
196 	if (!strcmp(mnt->mnt_dir, "/")) {
197 is_root:
198 #define TEST_FILE "/.ismount-test-file"
199 		*mount_flags |= EXT2_MF_ISROOT;
200 		fd = open(TEST_FILE, O_RDWR|O_CREAT, 0600);
201 		if (fd < 0) {
202 			if (errno == EROFS)
203 				*mount_flags |= EXT2_MF_READONLY;
204 		} else
205 			close(fd);
206 		(void) unlink(TEST_FILE);
207 	}
208 	retval = 0;
209 errout:
210 	endmntent (f);
211 	return retval;
212 }
213 
check_mntent(const char * file,int * mount_flags,char * mtpt,int mtlen)214 static errcode_t check_mntent(const char *file, int *mount_flags,
215 			      char *mtpt, int mtlen)
216 {
217 	errcode_t	retval;
218 
219 #ifdef DEBUG
220 	retval = check_mntent_file("/tmp/mtab", file, mount_flags,
221 				   mtpt, mtlen);
222 	if (retval == 0)
223 		return 0;
224 #endif /* DEBUG */
225 #ifdef __linux__
226 	retval = check_mntent_file("/proc/mounts", file, mount_flags,
227 				   mtpt, mtlen);
228 	if (retval == 0 && (*mount_flags != 0))
229 		return 0;
230 #endif /* __linux__ */
231 #if defined(MOUNTED) || defined(_PATH_MOUNTED)
232 #ifndef MOUNTED
233 #define MOUNTED _PATH_MOUNTED
234 #endif /* MOUNTED */
235 	retval = check_mntent_file(MOUNTED, file, mount_flags, mtpt, mtlen);
236 	return retval;
237 #else
238 	*mount_flags = 0;
239 	return 0;
240 #endif /* defined(MOUNTED) || defined(_PATH_MOUNTED) */
241 }
242 
243 #else
244 #if defined(HAVE_GETMNTINFO)
245 
check_getmntinfo(const char * file,int * mount_flags,char * mtpt,int mtlen)246 static errcode_t check_getmntinfo(const char *file, int *mount_flags,
247 				  char *mtpt, int mtlen)
248 {
249 	struct statfs *mp;
250         int    len, n;
251         const  char   *s1;
252 	char	*s2;
253 
254         n = getmntinfo(&mp, MNT_NOWAIT);
255         if (n == 0)
256 		return errno;
257 
258         len = sizeof(_PATH_DEV) - 1;
259         s1 = file;
260         if (strncmp(_PATH_DEV, s1, len) == 0)
261                 s1 += len;
262 
263 	*mount_flags = 0;
264         while (--n >= 0) {
265                 s2 = mp->f_mntfromname;
266                 if (strncmp(_PATH_DEV, s2, len) == 0) {
267                         s2 += len - 1;
268                         *s2 = 'r';
269                 }
270                 if (strcmp(s1, s2) == 0 || strcmp(s1, &s2[1]) == 0) {
271 			*mount_flags = EXT2_MF_MOUNTED;
272 			break;
273 		}
274                 ++mp;
275 	}
276 	if (mtpt)
277 		strncpy(mtpt, mp->f_mntonname, mtlen);
278 	return 0;
279 }
280 #endif /* HAVE_GETMNTINFO */
281 #endif /* HAVE_SETMNTENT */
282 
283 /*
284  * Check to see if we're dealing with the swap device.
285  */
is_swap_device(const char * file)286 static int is_swap_device(const char *file)
287 {
288 	FILE		*f;
289 	char		buf[1024], *cp;
290 	dev_t		file_dev;
291 	struct stat	st_buf;
292 	int		ret = 0;
293 
294 	file_dev = 0;
295 #ifndef __GNU__ /* The GNU hurd is broken with respect to stat devices */
296 	if ((stat(file, &st_buf) == 0) &&
297 	    S_ISBLK(st_buf.st_mode))
298 		file_dev = st_buf.st_rdev;
299 #endif	/* __GNU__ */
300 
301 	if (!(f = fopen("/proc/swaps", "r")))
302 		return 0;
303 	/* Skip the first line */
304 	if (!fgets(buf, sizeof(buf), f))
305 		goto leave;
306 	if (*buf && strncmp(buf, "Filename\t", 9))
307 		/* Linux <=2.6.19 contained a bug in the /proc/swaps
308 		 * code where the header would not be displayed
309 		 */
310 		goto valid_first_line;
311 
312 	while (fgets(buf, sizeof(buf), f)) {
313 valid_first_line:
314 		if ((cp = strchr(buf, ' ')) != NULL)
315 			*cp = 0;
316 		if ((cp = strchr(buf, '\t')) != NULL)
317 			*cp = 0;
318 		if (strcmp(buf, file) == 0) {
319 			ret++;
320 			break;
321 		}
322 #ifndef __GNU__
323 		if (file_dev && (stat(buf, &st_buf) == 0) &&
324 		    S_ISBLK(st_buf.st_mode) &&
325 		    file_dev == st_buf.st_rdev) {
326 			ret++;
327 			break;
328 		}
329 #endif 	/* __GNU__ */
330 	}
331 
332 leave:
333 	fclose(f);
334 	return ret;
335 }
336 
337 
338 /*
339  * ext2fs_check_mount_point() fills determines if the device is
340  * mounted or otherwise busy, and fills in mount_flags with one or
341  * more of the following flags: EXT2_MF_MOUNTED, EXT2_MF_ISROOT,
342  * EXT2_MF_READONLY, EXT2_MF_SWAP, and EXT2_MF_BUSY.  If mtpt is
343  * non-NULL, the directory where the device is mounted is copied to
344  * where mtpt is pointing, up to mtlen characters.
345  */
346 #ifdef __TURBOC__
347  #pragma argsused
348 #endif
ext2fs_check_mount_point(const char * device,int * mount_flags,char * mtpt,int mtlen)349 errcode_t ext2fs_check_mount_point(const char *device, int *mount_flags,
350 				  char *mtpt, int mtlen)
351 {
352 	errcode_t	retval = 0;
353 
354 	if (is_swap_device(device)) {
355 		*mount_flags = EXT2_MF_MOUNTED | EXT2_MF_SWAP;
356 		strncpy(mtpt, "<swap>", mtlen);
357 	} else {
358 #ifdef HAVE_SETMNTENT
359 		retval = check_mntent(device, mount_flags, mtpt, mtlen);
360 #else
361 #ifdef HAVE_GETMNTINFO
362 		retval = check_getmntinfo(device, mount_flags, mtpt, mtlen);
363 #else
364 #ifdef __GNUC__
365  #warning "Can't use getmntent or getmntinfo to check for mounted filesystems!"
366 #endif
367 		*mount_flags = 0;
368 #endif /* HAVE_GETMNTINFO */
369 #endif /* HAVE_SETMNTENT */
370 	}
371 	if (retval)
372 		return retval;
373 
374 #ifdef __linux__ /* This only works on Linux 2.6+ systems */
375 	{
376 		struct stat st_buf;
377 
378 		if (stat(device, &st_buf) == 0 && S_ISBLK(st_buf.st_mode)) {
379 			int fd = open(device, O_RDONLY | O_EXCL);
380 
381 			if (fd >= 0)
382 				close(fd);
383 			else if (errno == EBUSY)
384 				*mount_flags |= EXT2_MF_BUSY;
385 		}
386 	}
387 #endif
388 
389 	return 0;
390 }
391 
392 /*
393  * ext2fs_check_if_mounted() sets the mount_flags EXT2_MF_MOUNTED,
394  * EXT2_MF_READONLY, and EXT2_MF_ROOT
395  *
396  */
ext2fs_check_if_mounted(const char * file,int * mount_flags)397 errcode_t ext2fs_check_if_mounted(const char *file, int *mount_flags)
398 {
399 	return ext2fs_check_mount_point(file, mount_flags, NULL, 0);
400 }
401 
402 #ifdef DEBUG
main(int argc,char ** argv)403 int main(int argc, char **argv)
404 {
405 	int	retval, mount_flags;
406 	char	mntpt[80];
407 
408 	if (argc < 2) {
409 		fprintf(stderr, "Usage: %s device\n", argv[0]);
410 		exit(1);
411 	}
412 
413 	add_error_table(&et_ext2_error_table);
414 	mntpt[0] = 0;
415 	retval = ext2fs_check_mount_point(argv[1], &mount_flags,
416 					  mntpt, sizeof(mntpt));
417 	if (retval) {
418 		com_err(argv[0], retval,
419 			"while calling ext2fs_check_if_mounted");
420 		exit(1);
421 	}
422 	printf("Device %s reports flags %02x\n", argv[1], mount_flags);
423 	if (mount_flags & EXT2_MF_BUSY)
424 		printf("\t%s is apparently in use.\n", argv[1]);
425 	if (mount_flags & EXT2_MF_MOUNTED)
426 		printf("\t%s is mounted.\n", argv[1]);
427 	if (mount_flags & EXT2_MF_SWAP)
428 		printf("\t%s is a swap device.\n", argv[1]);
429 	if (mount_flags & EXT2_MF_READONLY)
430 		printf("\t%s is read-only.\n", argv[1]);
431 	if (mount_flags & EXT2_MF_ISROOT)
432 		printf("\t%s is the root filesystem.\n", argv[1]);
433 	if (mntpt[0])
434 		printf("\t%s is mounted on %s.\n", argv[1], mntpt);
435 	exit(0);
436 }
437 #endif /* DEBUG */
438