]> git.ipfire.org Git - thirdparty/util-linux.git/blame - lib/ismounted.c
lscpu: fix variable shadowing
[thirdparty/util-linux.git] / lib / ismounted.c
CommitLineData
607c2a72
KZ
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 * This file may be redistributed under the terms of the GNU Public
7 * License.
8 */
9#include <stdio.h>
10#include <unistd.h>
11#include <stdlib.h>
12#include <errno.h>
13#include <fcntl.h>
fbc333fe 14#ifdef HAVE_MNTENT_H
607c2a72 15#include <mntent.h>
9779651e 16#endif
607c2a72
KZ
17#include <string.h>
18#include <sys/stat.h>
19#include <ctype.h>
acf6ab6f 20#include <sys/param.h>
ac1c53e4
RM
21
22#ifndef __linux__
23# ifdef HAVE_SYS_UCRED_H
24# include <sys/ucred.h>
25# endif
26# ifdef HAVE_SYS_MOUNT_H
27# include <sys/mount.h>
28# endif
9779651e 29#endif
607c2a72 30
fb429f22 31#include "pathnames.h"
8ecc6ba8 32#include "strutils.h"
607c2a72 33#include "ismounted.h"
4951f9b3 34#include "c.h"
ca4f6229
KZ
35#ifdef __linux__
36# include "loopdev.h"
37#endif
38
39
607c2a72 40
acf6ab6f 41#ifdef HAVE_MNTENT_H
607c2a72
KZ
42/*
43 * Helper function which checks a file in /etc/mtab format to see if a
44 * filesystem is mounted. Returns an error if the file doesn't exist
45 * or can't be opened.
46 */
47static int check_mntent_file(const char *mtab_file, const char *file,
acf6ab6f 48 int *mount_flags, char *mtpt, int mtlen)
607c2a72 49{
acf6ab6f 50 struct mntent *mnt;
607c2a72
KZ
51 struct stat st_buf;
52 int retval = 0;
45ddc110 53 dev_t file_dev=0, file_rdev=0;
607c2a72 54 ino_t file_ino=0;
fb429f22 55 FILE *f;
acf6ab6f 56 int fd;
607c2a72
KZ
57
58 *mount_flags = 0;
607c2a72
KZ
59 if ((f = setmntent (mtab_file, "r")) == NULL)
60 return errno;
ca4f6229 61
607c2a72
KZ
62 if (stat(file, &st_buf) == 0) {
63 if (S_ISBLK(st_buf.st_mode)) {
64#ifndef __GNU__ /* The GNU hurd is broken with respect to stat devices */
65 file_rdev = st_buf.st_rdev;
66#endif /* __GNU__ */
67 } else {
68 file_dev = st_buf.st_dev;
69 file_ino = st_buf.st_ino;
70 }
71 }
ca4f6229 72
acf6ab6f
KZ
73 while ((mnt = getmntent (f)) != NULL) {
74 if (mnt->mnt_fsname[0] != '/')
607c2a72 75 continue;
acf6ab6f 76 if (strcmp(file, mnt->mnt_fsname) == 0)
607c2a72 77 break;
ca4f6229
KZ
78 if (stat(mnt->mnt_fsname, &st_buf) != 0)
79 continue;
80
81 if (S_ISBLK(st_buf.st_mode)) {
607c2a72 82#ifndef __GNU__
45ddc110
KZ
83 if (file_rdev && file_rdev == st_buf.st_rdev)
84 break;
85#ifdef __linux__
86 /* maybe the file is loopdev backing file */
87 if (file_dev
88 && major(st_buf.st_rdev) == LOOPDEV_MAJOR
74a4705a 89 && loopdev_is_used(mnt->mnt_fsname, file, 0, 0, 0))
ca4f6229 90 break;
45ddc110 91#endif /* __linux__ */
ca4f6229
KZ
92#endif /* __GNU__ */
93 } else {
94 if (file_dev && ((file_dev == st_buf.st_dev) &&
95 (file_ino == st_buf.st_ino)))
96 break;
607c2a72
KZ
97 }
98 }
99
f8bd089b 100 if (mnt == NULL) {
607c2a72
KZ
101#ifndef __GNU__ /* The GNU hurd is broken with respect to stat devices */
102 /*
103 * Do an extra check to see if this is the root device. We
104 * can't trust /etc/mtab, and /proc/mounts will only list
105 * /dev/root for the root filesystem. Argh. Instead we
106 * check if the given device has the same major/minor number
107 * as the device that the root directory is on.
108 */
acf6ab6f
KZ
109 if (file_rdev && stat("/", &st_buf) == 0 &&
110 st_buf.st_dev == file_rdev) {
607c2a72 111 *mount_flags = MF_MOUNTED;
acf6ab6f 112 if (mtpt)
8ecc6ba8 113 xstrncpy(mtpt, "/", mtlen);
acf6ab6f
KZ
114 goto is_root;
115 }
607c2a72
KZ
116#endif /* __GNU__ */
117 goto errout;
118 }
119#ifndef __GNU__ /* The GNU hurd is deficient; what else is new? */
120 /* Validate the entry in case /etc/mtab is out of date */
121 /*
122 * We need to be paranoid, because some broken distributions
123 * (read: Slackware) don't initialize /etc/mtab before checking
124 * all of the non-root filesystems on the disk.
125 */
acf6ab6f 126 if (stat(mnt->mnt_dir, &st_buf) < 0) {
607c2a72
KZ
127 retval = errno;
128 if (retval == ENOENT) {
129#ifdef DEBUG
130 printf("Bogus entry in %s! (%s does not exist)\n",
acf6ab6f 131 mtab_file, mnt->mnt_dir);
607c2a72
KZ
132#endif /* DEBUG */
133 retval = 0;
134 }
135 goto errout;
136 }
137 if (file_rdev && (st_buf.st_dev != file_rdev)) {
138#ifdef DEBUG
139 printf("Bogus entry in %s! (%s not mounted on %s)\n",
acf6ab6f 140 mtab_file, file, mnt->mnt_dir);
607c2a72
KZ
141#endif /* DEBUG */
142 goto errout;
143 }
144#endif /* __GNU__ */
145 *mount_flags = MF_MOUNTED;
146
acf6ab6f
KZ
147#ifdef MNTOPT_RO
148 /* Check to see if the ro option is set */
149 if (hasmntopt(mnt, MNTOPT_RO))
150 *mount_flags |= MF_READONLY;
151#endif
152
153 if (mtpt)
8ecc6ba8 154 xstrncpy(mtpt, mnt->mnt_dir, mtlen);
acf6ab6f
KZ
155 /*
156 * Check to see if we're referring to the root filesystem.
157 * If so, do a manual check to see if we can open /etc/mtab
158 * read/write, since if the root is mounted read/only, the
159 * contents of /etc/mtab may not be accurate.
160 */
161 if (!strcmp(mnt->mnt_dir, "/")) {
162is_root:
163#define TEST_FILE "/.ismount-test-file"
164 *mount_flags |= MF_ISROOT;
b1fa3e22 165 fd = open(TEST_FILE, O_RDWR|O_CREAT|O_CLOEXEC, 0600);
acf6ab6f
KZ
166 if (fd < 0) {
167 if (errno == EROFS)
168 *mount_flags |= MF_READONLY;
169 } else
170 close(fd);
171 (void) unlink(TEST_FILE);
172 }
607c2a72
KZ
173 retval = 0;
174errout:
175 endmntent (f);
176 return retval;
177}
178
acf6ab6f
KZ
179static int check_mntent(const char *file, int *mount_flags,
180 char *mtpt, int mtlen)
607c2a72
KZ
181{
182 int retval;
607c2a72 183
acf6ab6f
KZ
184#ifdef DEBUG
185 retval = check_mntent_file("/tmp/mtab", file, mount_flags,
186 mtpt, mtlen);
187 if (retval == 0)
188 return 0;
189#endif /* DEBUG */
607c2a72 190#ifdef __linux__
acf6ab6f
KZ
191 retval = check_mntent_file("/proc/mounts", file, mount_flags,
192 mtpt, mtlen);
193 if (retval == 0 && (*mount_flags != 0))
607c2a72 194 return 0;
8c9e72ce
KZ
195 if (access("/proc/mounts", R_OK) == 0) {
196 *mount_flags = 0;
197 return retval;
198 }
607c2a72 199#endif /* __linux__ */
acf6ab6f
KZ
200#if defined(MOUNTED) || defined(_PATH_MOUNTED)
201#ifndef MOUNTED
202#define MOUNTED _PATH_MOUNTED
203#endif /* MOUNTED */
204 retval = check_mntent_file(MOUNTED, file, mount_flags, mtpt, mtlen);
205 return retval;
206#else
207 *mount_flags = 0;
208 return 0;
209#endif /* defined(MOUNTED) || defined(_PATH_MOUNTED) */
210}
211
212#else
213#if defined(HAVE_GETMNTINFO)
214
215static int check_getmntinfo(const char *file, int *mount_flags,
216 char *mtpt, int mtlen)
217{
218 struct statfs *mp;
219 int len, n;
220 const char *s1;
221 char *s2;
222
223 n = getmntinfo(&mp, MNT_NOWAIT);
224 if (n == 0)
225 return errno;
226
227 len = sizeof(_PATH_DEV) - 1;
228 s1 = file;
229 if (strncmp(_PATH_DEV, s1, len) == 0)
230 s1 += len;
231
232 *mount_flags = 0;
233 while (--n >= 0) {
234 s2 = mp->f_mntfromname;
235 if (strncmp(_PATH_DEV, s2, len) == 0) {
236 s2 += len - 1;
237 *s2 = 'r';
238 }
239 if (strcmp(s1, s2) == 0 || strcmp(s1, &s2[1]) == 0) {
240 *mount_flags = MF_MOUNTED;
241 break;
242 }
243 ++mp;
244 }
245 if (mtpt)
8ecc6ba8 246 xstrncpy(mtpt, mp->f_mntonname, mtlen);
acf6ab6f
KZ
247 return 0;
248}
249#endif /* HAVE_GETMNTINFO */
250#endif /* HAVE_MNTENT_H */
251
252/*
253 * Check to see if we're dealing with the swap device.
254 */
255static int is_swap_device(const char *file)
256{
257 FILE *f;
258 char buf[1024], *cp;
259 dev_t file_dev;
260 struct stat st_buf;
261 int ret = 0;
262
263 file_dev = 0;
264#ifndef __GNU__ /* The GNU hurd is broken with respect to stat devices */
265 if ((stat(file, &st_buf) == 0) &&
266 S_ISBLK(st_buf.st_mode))
267 file_dev = st_buf.st_rdev;
268#endif /* __GNU__ */
269
b1fa3e22 270 if (!(f = fopen("/proc/swaps", "r" UL_CLOEXECSTR)))
acf6ab6f
KZ
271 return 0;
272 /* Skip the first line */
273 if (!fgets(buf, sizeof(buf), f))
274 goto leave;
ad296391 275 if (*buf && strncmp(buf, "Filename\t", 9) != 0)
acf6ab6f
KZ
276 /* Linux <=2.6.19 contained a bug in the /proc/swaps
277 * code where the header would not be displayed
278 */
279 goto valid_first_line;
280
281 while (fgets(buf, sizeof(buf), f)) {
282valid_first_line:
283 if ((cp = strchr(buf, ' ')) != NULL)
284 *cp = 0;
285 if ((cp = strchr(buf, '\t')) != NULL)
286 *cp = 0;
287 if (strcmp(buf, file) == 0) {
288 ret++;
289 break;
290 }
291#ifndef __GNU__
292 if (file_dev && (stat(buf, &st_buf) == 0) &&
293 S_ISBLK(st_buf.st_mode) &&
294 file_dev == st_buf.st_rdev) {
295 ret++;
296 break;
297 }
298#endif /* __GNU__ */
299 }
300
301leave:
302 fclose(f);
303 return ret;
304}
305
306
307/*
308 * check_mount_point() fills determines if the device is mounted or otherwise
309 * busy, and fills in mount_flags with one or more of the following flags:
310 * MF_MOUNTED, MF_ISROOT, MF_READONLY, MF_SWAP, and MF_BUSY. If mtpt is
311 * non-NULL, the directory where the device is mounted is copied to where mtpt
312 * is pointing, up to mtlen characters.
313 */
314#ifdef __TURBOC__
315 #pragma argsused
316#endif
317int check_mount_point(const char *device, int *mount_flags,
318 char *mtpt, int mtlen)
319{
acf6ab6f 320 int retval = 0;
acf6ab6f
KZ
321
322 if (is_swap_device(device)) {
323 *mount_flags = MF_MOUNTED | MF_SWAP;
f3135f93 324 if (mtpt && mtlen)
8ecc6ba8 325 xstrncpy(mtpt, "[SWAP]", mtlen);
acf6ab6f
KZ
326 } else {
327#ifdef HAVE_MNTENT_H
328 retval = check_mntent(device, mount_flags, mtpt, mtlen);
329#else
330#ifdef HAVE_GETMNTINFO
331 retval = check_getmntinfo(device, mount_flags, mtpt, mtlen);
332#else
333#ifdef __GNUC__
334 #warning "Can't use getmntent or getmntinfo to check for mounted filesystems!"
335#endif
336 *mount_flags = 0;
337#endif /* HAVE_GETMNTINFO */
338#endif /* HAVE_MNTENT_H */
339 }
340 if (retval)
341 return retval;
342
343#ifdef __linux__ /* This only works on Linux 2.6+ systems */
8b9cf26a
RM
344 {
345 struct stat st_buf;
346 int fd;
347 if ((stat(device, &st_buf) != 0) ||
348 !S_ISBLK(st_buf.st_mode))
349 return 0;
350 fd = open(device, O_RDONLY|O_EXCL|O_CLOEXEC);
351 if (fd < 0) {
352 if (errno == EBUSY)
353 *mount_flags |= MF_BUSY;
354 } else
355 close(fd);
356 }
acf6ab6f
KZ
357#endif
358
359 return 0;
360}
361
362int is_mounted(const char *file)
363{
364 int retval;
365 int mount_flags = 0;
366
367 retval = check_mount_point(file, &mount_flags, NULL, 0);
607c2a72
KZ
368 if (retval)
369 return 0;
acf6ab6f 370 return mount_flags & MF_MOUNTED;
607c2a72
KZ
371}
372
e8f7acb0 373#ifdef TEST_PROGRAM_ISMOUNTED
607c2a72
KZ
374int main(int argc, char **argv)
375{
acf6ab6f
KZ
376 int flags = 0;
377 char devname[PATH_MAX];
378
607c2a72
KZ
379 if (argc < 2) {
380 fprintf(stderr, "Usage: %s device\n", argv[0]);
355eceba 381 return EXIT_FAILURE;
607c2a72
KZ
382 }
383
acf6ab6f
KZ
384 if (check_mount_point(argv[1], &flags, devname, sizeof(devname)) == 0 &&
385 (flags & MF_MOUNTED)) {
386 if (flags & MF_SWAP)
387 printf("used swap device\n");
388 else
389 printf("mounted on %s\n", devname);
355eceba
KZ
390 return EXIT_SUCCESS;
391 }
acf6ab6f 392
355eceba
KZ
393 printf("not mounted\n");
394 return EXIT_FAILURE;
607c2a72
KZ
395}
396#endif /* DEBUG */