ismounted.c revision 2a6b60488feb819bae7e506281ebe37e6091b5d6
1/*
2 * ismounted.c --- Check to see if the filesystem was mounted
3 *
4 * Copyright (C) 1995,1996,1997,1998,1999,2000,2008 Theodore Ts'o.
5 *
6 * %Begin-Header%
7 * This file may be redistributed under the terms of the GNU Public
8 * License.
9 * %End-Header%
10 */
11
12#include <stdio.h>
13#if HAVE_UNISTD_H
14#include <unistd.h>
15#endif
16#ifdef HAVE_STDLIB_H
17#include <stdlib.h>
18#endif
19#if HAVE_ERRNO_H
20#include <errno.h>
21#endif
22#include <fcntl.h>
23#ifdef HAVE_LINUX_FD_H
24#include <linux/fd.h>
25#endif
26#ifdef HAVE_MNTENT_H
27#include <mntent.h>
28#endif
29#include <string.h>
30#include <sys/stat.h>
31
32/*
33 * ext2fs_check_if_mounted flags
34 */
35#define MF_MOUNTED		1
36
37#include "et/com_err.h"
38
39static char *skip_over_blank(char *cp)
40{
41	while (*cp && isspace(*cp))
42		cp++;
43	return cp;
44}
45
46static char *skip_over_word(char *cp)
47{
48	while (*cp && !isspace(*cp))
49		cp++;
50	return cp;
51}
52
53static char *parse_word(char **buf)
54{
55	char *word, *next;
56
57	word = *buf;
58	if (*word == 0)
59		return 0;
60
61	word = skip_over_blank(word);
62	next = skip_over_word(word);
63	if (*next)
64		*next++ = 0;
65	*buf = next;
66	return word;
67}
68
69/*
70 * Helper function which checks a file in /etc/mtab format to see if a
71 * filesystem is mounted.  Returns an error if the file doesn't exist
72 * or can't be opened.
73 */
74static errcode_t check_mntent_file(const char *mtab_file, const char *file,
75				   int *mount_flags)
76{
77#ifdef HAVE_MNTENT_H
78	struct stat	st_buf;
79	errcode_t	retval = 0;
80	dev_t		file_dev=0, file_rdev=0;
81	ino_t		file_ino=0;
82	FILE 		*f;
83	char		buf[1024], *device = 0, *mnt_dir = 0, *cp;
84	int		fd;
85
86	*mount_flags = 0;
87	if ((f = fopen(mtab_file, "r")) == NULL)
88		return errno;
89
90	if ((f = setmntent (mtab_file, "r")) == NULL)
91		return errno;
92	if (stat(file, &st_buf) == 0) {
93		if (S_ISBLK(st_buf.st_mode)) {
94#ifndef __GNU__ /* The GNU hurd is broken with respect to stat devices */
95			file_rdev = st_buf.st_rdev;
96#endif	/* __GNU__ */
97		} else {
98			file_dev = st_buf.st_dev;
99			file_ino = st_buf.st_ino;
100		}
101	}
102	while (1) {
103		if (!fgets(buf, sizeof(buf), f)) {
104			device = mnt_dir = 0;
105			break;
106		}
107		buf[sizeof(buf)-1] = 0;
108
109		cp = buf;
110		device = parse_word(&cp);
111		if (!device || *device == '#')
112			return 0;	/* Ignore blank lines and comments */
113		mnt_dir = parse_word(&cp);
114
115		if (device[0] != '/')
116			continue;
117
118		if (strcmp(file, device) == 0)
119			break;
120		if (stat(device, &st_buf) == 0) {
121			if (S_ISBLK(st_buf.st_mode)) {
122#ifndef __GNU__
123				if (file_rdev && (file_rdev == st_buf.st_rdev))
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_dir == 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		    (st_buf.st_dev == file_rdev))
145			*mount_flags = MF_MOUNTED;
146#endif	/* __GNU__ */
147		goto errout;
148	}
149#ifndef __GNU__ /* The GNU hurd is deficient; what else is new? */
150	/* Validate the entry in case /etc/mtab is out of date */
151	/*
152	 * We need to be paranoid, because some broken distributions
153	 * (read: Slackware) don't initialize /etc/mtab before checking
154	 * all of the non-root filesystems on the disk.
155	 */
156	if (stat(mnt_dir, &st_buf) < 0) {
157		retval = errno;
158		if (retval == ENOENT) {
159#ifdef DEBUG
160			printf("Bogus entry in %s!  (%s does not exist)\n",
161			       mtab_file, mnt_dir);
162#endif /* DEBUG */
163			retval = 0;
164		}
165		goto errout;
166	}
167	if (file_rdev && (st_buf.st_dev != file_rdev)) {
168#ifdef DEBUG
169		printf("Bogus entry in %s!  (%s not mounted on %s)\n",
170		       mtab_file, file, mnt_dir);
171#endif /* DEBUG */
172		goto errout;
173	}
174#endif /* __GNU__ */
175	*mount_flags = MF_MOUNTED;
176
177	retval = 0;
178errout:
179	endmntent (f);
180	return retval;
181#else /* !HAVE_MNTENT_H */
182	return 0;
183#endif /* HAVE_MNTENT_H */
184}
185
186int is_mounted(const char *file)
187{
188	errcode_t	retval;
189	int		mount_flags = 0;
190
191#ifdef __linux__
192	retval = check_mntent_file("/proc/mounts", file, &mount_flags);
193	if (retval)
194		return 0;
195	if (mount_flags)
196		return 1;
197#endif /* __linux__ */
198	retval = check_mntent_file("/etc/mtab", file, &mount_flags);
199	if (retval)
200		return 0;
201	return (mount_flags);
202}
203
204#ifdef DEBUG
205int main(int argc, char **argv)
206{
207	if (argc < 2) {
208		fprintf(stderr, "Usage: %s device\n", argv[0]);
209		exit(1);
210	}
211
212	if (is_mounted(argv[1]))
213		printf("\t%s is mounted.\n", argv[1]);
214	exit(0);
215}
216#endif /* DEBUG */
217