int main(int argc, char **argv) { char *device; unsigned drive; unsigned type; unsigned media_size; unsigned drive_size; int verify= 0; struct stat st0, st; char special[PATH_MAX + 1], mounted_on[PATH_MAX + 1]; char version[MNTNAMELEN], rw_flag[MNTFLAGLEN]; /* Option -v. */ while (argc > 1 && argv[1][0] == '-') { char *p; for (p= argv[1]; *p == '-' || *p == 'v'; p++) { if (*p == 'v') verify= 1; } if (*p != 0) usage(); argc--; argv++; if (strcmp(argv[0], "--") == 0) break; } if (argc < 2 || argc > 4) usage(); /* Check if the caller has read-write permission. Use the access() * call to check with the real uid & gid. This program is usually * set-uid root. */ device= argv[1]; if (stat(device, &st0) < 0 || access(device, R_OK|W_OK) < 0 || stat(device, &st) < 0 || (errno= EACCES, 0) /* set errno for following tests */ || st.st_dev != st0.st_dev || st.st_ino != st0.st_ino ) { fatal(device); } if (!S_ISBLK(st.st_mode) || !isfloppy(st.st_rdev)) { fprintf(stderr, "format: %s: not a floppy device\n", device); exit(1); } drive= fl_drive(st.st_rdev); type= fl_type(st.st_rdev); /* The drive should not be mounted. */ if (load_mtab("mkfs") < 0) exit(1); while (get_mtab_entry(special, mounted_on, version, rw_flag) == 0) { if (stat(special, &st) >= 0 && isfloppy(st.st_rdev) && fl_drive(st.st_rdev) == drive) { fprintf(stderr, "format: %s is mounted on %s\n", device, mounted_on); exit(1); } } if (isflauto(type)) { /* Auto type 0 requires size(s). */ unsigned long lmedia, ldrive; char *end; if (argc < 3) { fprintf(stderr, "format: no size specified for auto floppy device %s\n", device); usage(); } lmedia= strtoul(argv[2], &end, 10); if (end == argv[2] || *end != 0 || lmedia > 20 * 1024) usage(); if (argc == 4) { ldrive= strtoul(argv[3], &end, 10); if (end == argv[3] || *end != 0 || ldrive > 20 * 1024) usage(); } else { ldrive= lmedia; } /* Silently correct wrong ordered sizes. */ if (lmedia > ldrive) { media_size= ldrive; drive_size= lmedia; } else { media_size= lmedia; drive_size= ldrive; } /* A 1.44M drive can do 720k diskettes with no extra tricks. * Diddle with the 720k params so it is found. */ if (media_size == 720 && drive_size == 1440) parameters[4 - 1].drive_size= 1440; /* Translate the auto type to a known type. */ for (type= 1; type <= NR_TYPES; type++) { if (parameters[type - 1].media_size == media_size && parameters[type - 1].drive_size == drive_size ) break; } if (!isfltyped(type)) { fprintf(stderr, "format: can't format a %uk floppy in a %uk drive\n", media_size, drive_size); exit(1); } } else if (isfltyped(type)) { /* No sizes needed for a non-auto type. */ if (argc > 2) { fprintf(stderr, "format: no sizes need to be specified for non-auto floppy device %s\n", device); usage(); } } else if (isflpart(type)) { fprintf(stderr, "format: floppy partition %s can't be formatted\n", device); exit(1); } else { fprintf(stderr, "format: %s: can't format strange type %d\n", device, type); } format_device(drive, type, verify); exit(0); }
/* * Check to see if the special file named 'device' is mounted. */ void check_mtab(const char *device) /* /dev/hd1 or whatever */ { #if defined(__minix) int n, r; struct stat sb; char dev[PATH_MAX], mount_point[PATH_MAX], type[MNTNAMELEN], flags[MNTFLAGLEN]; r= stat(device, &sb); if (r == -1) { if (errno == ENOENT) return; /* Does not exist, and therefore not mounted. */ err(1, "stat %s failed", device); } if (!S_ISBLK(sb.st_mode)) { /* Not a block device and therefore not mounted. */ return; } if (load_mtab(__UNCONST("mkfs")) < 0) return; while (1) { n = get_mtab_entry(dev, mount_point, type, flags); if (n < 0) return; if (strcmp(device, dev) == 0) { /* Can't mkfs on top of a mounted file system. */ errx(1, "%s is mounted on %s", device, mount_point); } } #elif defined(__linux__) /* XXX: this code is copyright Theodore T'so and distributed under the GPLv2. Rewrite. */ struct mntent *mnt; struct stat st_buf; dev_t file_dev=0, file_rdev=0; ino_t file_ino=0; FILE *f; int fd; char *mtab_file = "/proc/mounts"; if ((f = setmntent (mtab_file, "r")) == NULL) goto error; if (stat(device, &st_buf) == 0) { if (S_ISBLK(st_buf.st_mode)) { file_rdev = st_buf.st_rdev; } else { file_dev = st_buf.st_dev; file_ino = st_buf.st_ino; } } while ((mnt = getmntent (f)) != NULL) { if (strcmp(device, mnt->mnt_fsname) == 0) break; if (stat(mnt->mnt_fsname, &st_buf) == 0) { if (S_ISBLK(st_buf.st_mode)) { if (file_rdev && (file_rdev == st_buf.st_rdev)) break; } else { if (file_dev && ((file_dev == st_buf.st_dev) && (file_ino == st_buf.st_ino))) break; } } } if (mnt == NULL) { /* * Do an extra check to see if this is the root device. We * can't trust /etc/mtab, and /proc/mounts will only list * /dev/root for the root filesystem. Argh. Instead we * check if the given device has the same major/minor number * as the device that the root directory is on. */ if (file_rdev && stat("/", &st_buf) == 0) { if (st_buf.st_dev == file_rdev) { goto is_root; } } goto test_busy; } /* Validate the entry in case /etc/mtab is out of date */ /* * We need to be paranoid, because some broken distributions * (read: Slackware) don't initialize /etc/mtab before checking * all of the non-root filesystems on the disk. */ if (stat(mnt->mnt_dir, &st_buf) < 0) { if (errno == ENOENT) { goto test_busy; } goto error; } if (file_rdev && (st_buf.st_dev != file_rdev)) { goto error; } fprintf(stderr, "Device %s is mounted, exiting\n", device); exit(-1); /* * Check to see if we're referring to the root filesystem. * If so, do a manual check to see if we can open /etc/mtab * read/write, since if the root is mounted read/only, the * contents of /etc/mtab may not be accurate. */ if (!strcmp(mnt->mnt_dir, "/")) { is_root: fprintf(stderr, "Device %s is mounted as root file system!\n", device); exit(-1); } test_busy: endmntent (f); if ((stat(device, &st_buf) != 0) || !S_ISBLK(st_buf.st_mode)) return; fd = open(device, O_RDONLY | O_EXCL); if (fd < 0) { if (errno == EBUSY) { fprintf(stderr, "Device %s is used by the system\n", device); exit(-1); } } else close(fd); return; error: endmntent (f); fprintf(stderr, "Error while checking if device %s is mounted\n", device); exit(-1); #else (void) device; /* shut up warnings about unused variable... */ #endif }