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