"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "src/device_info.c" between
dosfstools-4.1.tar.gz and dosfstools-4.2.tar.gz

About: dosfstools are utilities to create, check and label (MS-DOS) FAT filesystems.

device_info.c  (dosfstools-4.1):device_info.c  (dosfstools-4.2)
/* device_info.c - Collect device information for mkfs.fat /* device_info.c - Collect device information for mkfs.fat
Copyright (C) 2015 Andreas Bombe <aeb@debian.org> Copyright (C) 2015 Andreas Bombe <aeb@debian.org>
Copyright (C) 2018 Pali Rohár <pali.rohar@gmail.com>
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
skipping to change at line 25 skipping to change at line 26
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <limits.h> #include <limits.h>
#include <stdint.h> #include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <sys/sysmacros.h>
#ifdef HAVE_UDEV #ifdef HAVE_LINUX_LOOP_H
#include <libudev.h> #include <linux/loop.h>
#endif #endif
#if HAVE_DECL_GETMNTENT #if HAVE_DECL_GETMNTENT
#include <paths.h> #include <paths.h>
#include <mntent.h> #include <mntent.h>
#endif #endif
#if HAVE_DECL_GETMNTINFO #if HAVE_DECL_GETMNTINFO
#include <sys/param.h> #include <sys/param.h>
#include <sys/ucred.h> #include <sys/ucred.h>
#include <sys/mount.h> #include <sys/mount.h>
#endif #endif
#include <unistd.h> #include <unistd.h>
#include <dirent.h> #include <dirent.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
#include <errno.h>
#include "blkdev.h" #include "blkdev.h"
#include "device_info.h" #include "device_info.h"
static const struct device_info device_info_clueless = { static const struct device_info device_info_clueless = {
.type = TYPE_UNKNOWN, .type = TYPE_UNKNOWN,
.partition = -1, .partition = -1,
.has_children = -1, .has_children = -1,
.geom_heads = -1, .geom_heads = -1,
.geom_sectors = -1, .geom_sectors = -1,
.geom_start = -1, .geom_start = -1,
.geom_size = -1,
.sector_size = -1, .sector_size = -1,
.size = -1, .size = -1,
}; };
int device_info_verbose; int device_info_verbose;
static void get_block_device_size(struct device_info *info, int fd) static void get_block_device_size(struct device_info *info, int fd)
{ {
unsigned long long bytes; unsigned long long bytes;
if (!blkdev_get_size(fd, &bytes) && bytes != 0) if (!blkdev_get_size(fd, &bytes) && bytes != 0)
info->size = bytes; info->size = bytes;
} }
static void get_block_geometry(struct device_info *info, int fd) static void get_block_geometry(struct device_info *info, int fd, dev_t rdev)
{ {
unsigned int heads, sectors, start; unsigned int heads, sectors;
unsigned long long start;
if (!blkdev_get_geometry(fd, &heads, &sectors) if (!blkdev_get_geometry(fd, &heads, &sectors)
&& heads && sectors) { && heads && sectors) {
info->geom_heads = heads; info->geom_heads = heads;
info->geom_sectors = sectors; info->geom_sectors = sectors;
} }
if (!blkdev_get_start(fd, &start)) if (!blkdev_get_start(fd, rdev, &start))
info->geom_start = start; info->geom_start = start;
} }
static void get_sector_size(struct device_info *info, int fd) static void get_sector_size(struct device_info *info, int fd)
{ {
int size; int size;
if (!blkdev_get_sector_size(fd, &size)) if (!blkdev_get_sector_size(fd, &size))
info->sector_size = size; info->sector_size = size;
} }
static int udev_fill_info(struct device_info *info, struct stat *stat); #ifdef __linux__
static void get_block_linux_info(struct device_info *info, int devfd, dev_t rdev
#ifdef HAVE_UDEV )
static int udev_fill_info(struct device_info *info, struct stat *stat)
{ {
struct udev *ctx; struct stat st;
struct udev_device *dev, *parent; char path[PATH_MAX];
struct udev_enumerate *uenum; int fd;
const char *attr; int blockfd;
char holders_path[PATH_MAX + 1]; FILE *file;
DIR *holders_dir; DIR *dir;
struct dirent *dir_entry; struct dirent *d;
unsigned long number; int maj;
char *endptr; int min;
long long start;
if (device_info_verbose >= 3) int removable;
printf("udev_fill_info()\n");
ctx = udev_new();
if (!ctx) {
if (device_info_verbose)
printf("no udev library context\n");
return -1;
}
dev = udev_device_new_from_devnum(ctx, 'b', stat->st_rdev);
if (!dev) {
if (device_info_verbose)
printf("no udev context\n");
udev_unref(ctx);
return -1;
}
/* #ifdef HAVE_LINUX_LOOP_H
* first, look for for dependent devices (partitions or virtual mappings on struct loop_info64 lo;
* this device) #endif
*/
if (device_info_verbose >= 3)
printf("looking for dependent devices\n");
uenum = udev_enumerate_new(ctx);
if (uenum) {
struct udev_list_entry *entry;
if (udev_enumerate_add_match_parent(uenum, dev) >= 0 &&
udev_enumerate_scan_devices(uenum) >= 0) {
entry = udev_enumerate_get_list_entry(uenum);
if (entry) {
/*
* the list of children includes the parent device, so make
* sure that has_children is -1 to end up with the correct
* count
*/
info->has_children = -1;
while (entry) {
if (device_info_verbose >= 2)
printf("child-or-self: %s\n", udev_list_entry_get_name(en
try));
entry = udev_list_entry_get_next(entry);
info->has_children++;
}
} else
info->has_children = 0;
}
udev_enumerate_unref(uenum);
}
/* see if the holders directory in sysfs exists and has entries */ maj = major(rdev);
if (device_info_verbose >= 2) min = minor(rdev);
printf("syspath: %s\n", udev_device_get_syspath(dev));
if (info->has_children < 1 || device_info_verbose >= 3) {
snprintf(holders_path, PATH_MAX, "%s/holders",
udev_device_get_syspath(dev));
holders_path[PATH_MAX] = 0;
if (info->has_children < 0)
info->has_children = 0;
holders_dir = opendir(holders_path);
if (holders_dir) {
dir_entry = readdir(holders_dir);
while (dir_entry) {
if (dir_entry->d_reclen && dir_entry->d_name[0] != '.') {
if (device_info_verbose >= 2)
printf("holder: %s\n", dir_entry->d_name);
info->has_children++;
/* look up and print every holder when very verbose */
if (device_info_verbose < 3)
break;
}
dir_entry = readdir(holders_dir);
}
closedir(holders_dir); snprintf(path, sizeof(path), "/sys/dev/block/%d:%d", maj, min);
} blockfd = open(path, O_RDONLY | O_DIRECTORY);
} if (blockfd < 0)
return;
/*
* block devices on real hardware have either other block devices /* Check if device is partition */
* (in the case of partitions) or the actual hardware as parent fd = openat(blockfd, "partition", O_RDONLY);
*/ if (fd >= 0) {
parent = udev_device_get_parent(dev); file = fdopen(fd, "r");
if (file) {
if (!parent) { if (fscanf(file, "%d", &info->partition) != 1 || info->partition ==
if (device_info_verbose >= 3) 0)
printf("no parent found, therefore virtual device\n"); info->partition = -1;
info->type = TYPE_VIRTUAL; fclose(file);
info->partition = 0; } else {
udev_device_unref(dev); close(fd);
return 0; }
/* Read total number of sectors of the disk */
fd = openat(blockfd, "../size", O_RDONLY);
if (fd >= 0) {
file = fdopen(fd, "r");
if (file) {
if (fscanf(file, "%lld", &info->geom_size) != 1 || info->geom_si
ze == 0)
info->geom_size = -1;
fclose(file);
} else {
close(fd);
}
}
} else if (errno == ENOENT && info->geom_start <= 0) {
info->partition = 0;
if (info->size > 0 && info->sector_size > 0)
info->geom_size = info->size / info->sector_size;
}
/* Check if device has partition subdevice and therefore has children */
fd = dup(blockfd);
if (fd >= 0) {
dir = fdopendir(fd);
if (dir) {
info->has_children = 0;
errno = 0;
while ((d = readdir(dir))) {
if (strcmp(d->d_name, ".") == 0 || strcmp(d->d_name, "..") == 0)
continue;
if (d->d_type != DT_DIR && d->d_type != DT_UNKNOWN)
continue;
snprintf(path, sizeof(path), "%s/partition", d->d_name);
if (fstatat(blockfd, path, &st, 0) == 0) {
if (S_ISREG(st.st_mode)) {
start = -1;
snprintf(path, sizeof(path), "%s/start", d->d_name);
fd = openat(blockfd, path, O_RDONLY);
if (fd >= 0) {
file = fdopen(fd, "r");
if (file) {
if (fscanf(file, "%lld", &start) != 1)
start = -1;
fclose(file);
} else {
close(fd);
}
}
/* If subdevice starts at zero offset then it is whole d
evice, so it is not a child */
if (start != 0) {
info->has_children = 1;
break;
}
}
} else if (errno != ENOENT) {
info->has_children = -1;
}
errno = 0;
}
if (errno != 0 && info->has_children == 0)
info->has_children = -1;
closedir(dir);
} else {
close(fd);
}
}
/* Check if device has holders and therefore has children */
if (info->has_children <= 0) {
fd = openat(blockfd, "holders", O_RDONLY | O_DIRECTORY);
if (fd >= 0) {
dir = fdopendir(fd);
if (dir) {
while ((d = readdir(dir))) {
if (strcmp(d->d_name, ".") == 0 || strcmp(d->d_name, "..") =
= 0)
continue;
info->has_children = 1;
break;
}
closedir(dir);
} else {
close(fd);
}
}
}
/* Check if device is slave of another device and therefore is virtual */
fd = openat(blockfd, "slaves", O_RDONLY | O_DIRECTORY);
if (fd >= 0) {
dir = fdopendir(fd);
if (dir) {
while ((d = readdir(dir))) {
if (strcmp(d->d_name, ".") == 0 || strcmp(d->d_name, "..") == 0)
continue;
info->type = TYPE_VIRTUAL;
break;
}
closedir(dir);
} else {
close(fd);
}
}
#ifdef HAVE_LINUX_LOOP_H
/* Check if device is loop and detect if is based from regular file or is vi
rtual */
if (info->type == TYPE_UNKNOWN && info->partition == 0 && ioctl(devfd, LOOP_
GET_STATUS64, &lo) == 0) {
if (lo.lo_offset == 0 && lo.lo_sizelimit == 0 && lo.lo_encrypt_type == L
O_CRYPT_NONE &&
stat((char *)lo.lo_file_name, &st) == 0 && S_ISREG(st.st_mode) &&
st.st_dev == lo.lo_device && st.st_ino == lo.lo_inode && st.st_size
== info->size)
info->type = TYPE_FILE;
else
info->type = TYPE_VIRTUAL;
} }
#endif
attr = udev_device_get_sysattr_value(dev, "removable"); /* Device is neither loop nor virtual, so is either removable or fixed */
if (device_info_verbose >= 3) { if (info->type == TYPE_UNKNOWN) {
if (attr) removable = 0;
printf("attribute \"removable\" is \"%s\"\n", attr); fd = openat(blockfd, "removable", O_RDONLY);
else if (fd >= 0) {
printf("attribute \"removable\" not found\n"); file = fdopen(fd, "r");
} if (file) {
if (attr && !strcmp(attr, "1")) if (fscanf(file, "%d", &removable) != 1)
info->type = TYPE_REMOVABLE; removable = 0;
else fclose(file);
info->type = TYPE_FIXED; } else {
close(fd);
attr = udev_device_get_sysattr_value(dev, "partition"); }
if (attr) { }
if (device_info_verbose >= 3)
printf("attribute \"partition\" is \"%s\"\n", attr); if (removable)
info->type = TYPE_REMOVABLE;
number = strtoul(attr, &endptr, 10); else
if (!*endptr) info->type = TYPE_FIXED;
info->partition = number;
} else {
printf("attribute \"partition\" not found\n");
if (info->type != TYPE_VIRTUAL && parent) {
/* partitions have other block devices as parent */
attr = udev_device_get_subsystem(parent);
if (attr) {
if (device_info_verbose >= 3)
printf("parent subsystem is \"%s\"\n", attr);
if (!strcmp(attr, "block"))
/* we don't know the partition number, use 1 */
info->partition = 1;
else
info->partition = 0;
}
}
} }
udev_device_unref(dev); close(blockfd);
udev_unref(ctx);
return 0;
}
#else /* HAVE_UDEV */
static int udev_fill_info(struct device_info *info, struct stat *stat)
{
/* prevent "unused parameter" warning */
(void)stat;
(void)info;
return -1;
} }
#endif #endif
int get_device_info(int fd, struct device_info *info) int get_device_info(int fd, struct device_info *info)
{ {
struct stat stat; struct stat stat;
int ret; int ret;
*info = device_info_clueless; *info = device_info_clueless;
skipping to change at line 287 skipping to change at line 302
return 0; return 0;
} }
if (!S_ISBLK(stat.st_mode)) { if (!S_ISBLK(stat.st_mode)) {
/* neither regular file nor block device? not usable */ /* neither regular file nor block device? not usable */
info->type = TYPE_BAD; info->type = TYPE_BAD;
return 0; return 0;
} }
get_block_device_size(info, fd); get_block_device_size(info, fd);
get_block_geometry(info, fd); get_block_geometry(info, fd, stat.st_rdev);
get_sector_size(info, fd); get_sector_size(info, fd);
/* use udev information if available */ #ifdef __linux__
udev_fill_info(info, &stat); get_block_linux_info(info, fd, stat.st_rdev);
#endif
return 0; return 0;
} }
int is_device_mounted(const char *path) int is_device_mounted(const char *path)
{ {
#if HAVE_DECL_GETMNTENT #if HAVE_DECL_GETMNTENT
FILE *f; FILE *f;
struct mntent *mnt; struct mntent *mnt;
 End of changes. 18 change blocks. 
164 lines changed or deleted 188 lines changed or added

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)