ismounted.c revision 07cefe7a7051e32f14b93d9003a6dbb308597bd3
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 Public 8 * License. 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_MNTENT_H 24#include <mntent.h> 25#endif 26#ifdef HAVE_GETMNTINFO 27#include <paths.h> 28#include <sys/param.h> 29#include <sys/mount.h> 30#endif /* HAVE_GETMNTINFO */ 31#include <string.h> 32#include <sys/stat.h> 33 34#include "ext2_fs.h" 35#include "ext2fs.h" 36 37#ifdef HAVE_MNTENT_H 38/* 39 * Helper function which checks a file in /etc/mtab format to see if a 40 * filesystem is mounted. Returns an error if the file doesn't exist 41 * or can't be opened. 42 */ 43static errcode_t check_mntent_file(const char *mtab_file, const char *file, 44 int *mount_flags, char *mtpt, int mtlen) 45{ 46 struct mntent *mnt; 47 struct stat st_buf; 48 errcode_t retval = 0; 49 dev_t file_dev; 50 FILE *f; 51 int fd; 52 53 *mount_flags = 0; 54 if ((f = setmntent (mtab_file, "r")) == NULL) 55 return errno; 56 file_dev = 0; 57#ifndef __GNU__ /* The GNU hurd is broken with respect to stat devices */ 58 if (stat(file, &st_buf) == 0) 59 file_dev = st_buf.st_rdev; 60#endif 61 while ((mnt = getmntent (f)) != NULL) { 62 if (strcmp(file, mnt->mnt_fsname) == 0) 63 break; 64#ifndef __GNU__ 65 if (file_dev && (stat(mnt->mnt_fsname, &st_buf) == 0) && 66 file_dev == st_buf.st_rdev) 67 break; 68#endif 69 } 70 71 if (mnt == 0) { 72#ifndef __GNU__ /* The GNU hurd is broken with respect to stat devices */ 73 /* 74 * Do an extra check to see if this is the root device. We 75 * can't trust /etc/mtab, and /proc/mounts will only list 76 * /dev/root for the root filesystem. Argh. Instead we 77 * check if the given device has the same major/minor number 78 * as the device that the root directory is on. 79 */ 80 if (file_dev && stat("/", &st_buf) == 0) { 81 if (st_buf.st_dev == file_dev) { 82 *mount_flags = EXT2_MF_MOUNTED; 83 if (mtpt) 84 strncpy(mtpt, "/", mtlen); 85 goto is_root; 86 } 87 } 88#endif 89 goto exit; 90 } 91#ifndef __GNU__ /* The GNU hurd is deficient; what else is new? */ 92 /* Validate the entry in case /etc/mtab is out of date */ 93 /* 94 * We need to be paranoid, because some broken distributions 95 * (read: Slackware) don't initialize /etc/mtab before checking 96 * all of the non-root filesystems on the disk. 97 */ 98 if (stat(mnt->mnt_dir, &st_buf) < 0) { 99 retval = errno; 100 if (retval == ENOENT) { 101#ifdef DEBUG 102 printf("Bogus entry in %s! (%s does not exist)\n", 103 mtab_file, mnt->mnt_dir); 104#endif 105 retval = 0; 106 } 107 goto exit; 108 } 109 if (file_dev && (st_buf.st_dev != file_dev)) { 110#ifdef DEBUG 111 printf("Bogus entry in %s! (%s not mounted on %s)\n", 112 mtab_file, file, mnt->mnt_dir); 113#endif 114 goto exit; 115 } 116#endif 117 *mount_flags = EXT2_MF_MOUNTED; 118 119 /* Check to see if the ro option is set */ 120 if (hasmntopt(mnt, MNTOPT_RO)) 121 *mount_flags |= EXT2_MF_READONLY; 122 123 if (mtpt) 124 strncpy(mtpt, mnt->mnt_dir, mtlen); 125 /* 126 * Check to see if we're referring to the root filesystem. 127 * If so, do a manual check to see if we can open /etc/mtab 128 * read/write, since if the root is mounted read/only, the 129 * contents of /etc/mtab may not be accurate. 130 */ 131 if (!strcmp(mnt->mnt_dir, "/")) { 132is_root: 133#define TEST_FILE "/.ismount-test-file" 134 *mount_flags |= EXT2_MF_ISROOT; 135 fd = open(TEST_FILE, O_RDWR|O_CREAT); 136 if (fd < 0) { 137 if (errno == EROFS) 138 *mount_flags |= EXT2_MF_READONLY; 139 } else 140 close(fd); 141 (void) unlink(TEST_FILE); 142 } 143 retval = 0; 144exit: 145 endmntent (f); 146 return retval; 147} 148 149/* 150 * Check to see if we're dealing with the swap device. 151 */ 152static int is_swap_device(const char *file) 153{ 154 FILE *f; 155 char buf[1024], *cp; 156 dev_t file_dev; 157 struct stat st_buf; 158 159 file_dev = 0; 160#ifndef __GNU__ /* The GNU hurd is broken with respect to stat devices */ 161 if (stat(file, &st_buf) == 0) 162 file_dev = st_buf.st_rdev; 163#endif 164 165 f = fopen("/proc/swaps", "r"); 166 if (!f) 167 return; 168 /* Skip the first line */ 169 fgets(buf, sizeof(buf), f); 170 while (!feof(f)) { 171 if (!fgets(buf, sizeof(buf), f)) 172 break; 173 if ((cp = strchr(buf, ' ')) != NULL) 174 *cp = 0; 175 if ((cp = strchr(buf, '\t')) != NULL) 176 *cp = 0; 177 if (strcmp(buf, file) == 0) 178 return 1; 179#ifndef __GNU__ 180 if (file_dev && (stat(buf, &st_buf) == 0) && 181 file_dev == st_buf.st_rdev) 182 return 1; 183#endif 184 } 185 return 0; 186} 187 188static errcode_t check_mntent(const char *file, int *mount_flags, 189 char *mtpt, int mtlen) 190{ 191 errcode_t retval; 192 193#ifdef DEBUG 194 retval = check_mntent_file("/tmp/mtab", file, mount_flags, 195 mtpt, mtlen); 196 if (retval == 0) 197 return 0; 198#endif 199#ifdef __linux__ 200 retval = check_mntent_file("/proc/mounts", file, mount_flags, 201 mtpt, mtlen); 202 if (retval == 0) 203 return 0; 204#endif 205 retval = check_mntent_file(MOUNTED, file, mount_flags, mtpt, mtlen); 206 return retval; 207} 208 209#elif defined(HAVE_GETMNTINFO) 210 211static errcode_t check_getmntinfo(const char *file, int *mount_flags, 212 char *mtpt, int mtlen) 213{ 214 struct statfs *mp; 215 int len, n; 216 const char *s1; 217 char *s2; 218 219 n = getmntinfo(&mp, MNT_NOWAIT); 220 if (n == 0) 221 return errno; 222 223 len = sizeof(_PATH_DEV) - 1; 224 s1 = file; 225 if (strncmp(_PATH_DEV, s1, len) == 0) 226 s1 += len; 227 228 *mount_flags = 0; 229 while (--n >= 0) { 230 s2 = mp->f_mntfromname; 231 if (strncmp(_PATH_DEV, s2, len) == 0) { 232 s2 += len - 1; 233 *s2 = 'r'; 234 } 235 if (strcmp(s1, s2) == 0 || strcmp(s1, &s2[1]) == 0) { 236 *mount_flags = EXT2_MF_MOUNTED; 237 break; 238 } 239 ++mp; 240 } 241 if (mtpt) 242 strncpy(mtpt, mp->f_mntonname, mtlen); 243 return 0; 244} 245#endif /* HAVE_GETMNTINFO */ 246 247/* 248 * ext2fs_check_mount_point() returns 1 if the device is mounted, 0 249 * otherwise. If mtpt is non-NULL, the directory where the device is 250 * mounted is copied to where mtpt is pointing, up to mtlen 251 * characters. 252 */ 253#ifdef __TURBOC__ 254 #pragma argsused 255#endif 256errcode_t ext2fs_check_mount_point(const char *device, int *mount_flags, 257 char *mtpt, int mtlen) 258{ 259 if (is_swap_device(device)) { 260 *mount_flags = EXT2_MF_MOUNTED | EXT2_MF_SWAP; 261 strncpy(mtpt, "<swap>", mtlen); 262 return 0; 263 } 264#ifdef HAVE_MNTENT_H 265 return check_mntent(device, mount_flags, mtpt, mtlen); 266#else 267#ifdef HAVE_GETMNTINFO 268 return check_getmntinfo(device, mount_flags, mtpt, mtlen); 269#else 270#warning "Can't use getmntent or getmntinfo to check for mounted filesystems!" 271 *mount_flags = 0; 272 return 0; 273#endif /* HAVE_GETMNTINFO */ 274#endif /* HAVE_MNTENT_H */ 275} 276 277/* 278 * ext2fs_check_if_mounted() sets the mount_flags EXT2_MF_MOUNTED, 279 * EXT2_MF_READONLY, and EXT2_MF_ROOT 280 * 281 */ 282errcode_t ext2fs_check_if_mounted(const char *file, int *mount_flags) 283{ 284 return ext2fs_check_mount_point(file, mount_flags, NULL, 0); 285} 286 287#ifdef DEBUG 288int main(int argc, char **argv) 289{ 290 int retval, mount_flags; 291 char mntpt[80]; 292 293 if (argc < 2) { 294 fprintf(stderr, "Usage: %s device\n", argv[0]); 295 exit(1); 296 } 297 298 mntpt[0] = 0; 299 retval = ext2fs_check_mount_point(argv[1], &mount_flags, 300 mntpt, sizeof(mntpt)); 301 if (retval) { 302 com_err(argv[0], retval, 303 "while calling ext2fs_check_if_mounted"); 304 exit(1); 305 } 306 printf("Device %s reports flags %02x\n", argv[1], mount_flags); 307 if (mount_flags & EXT2_MF_MOUNTED) 308 printf("\t%s is mounted.\n", argv[1]); 309 310 if (mount_flags & EXT2_MF_SWAP) 311 printf("\t%s is a swap device.\n", argv[1]); 312 313 if (mount_flags & EXT2_MF_READONLY) 314 printf("\t%s is read-only.\n", argv[1]); 315 316 if (mount_flags & EXT2_MF_ISROOT) 317 printf("\t%s is the root filesystem.\n", argv[1]); 318 if (mntpt[0]) 319 printf("\t%s is mounted on %s.\n", argv[1], mntpt); 320 321 exit(0); 322} 323#endif 324