dosfstools  4.2
About: dosfstools are utilities to create, check and label (MS-DOS) FAT filesystems.
  Fossies Dox: dosfstools-4.2.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

device_info.c
Go to the documentation of this file.
1 /* device_info.c - Collect device information for mkfs.fat
2 
3  Copyright (C) 2015 Andreas Bombe <aeb@debian.org>
4  Copyright (C) 2018 Pali Roh├ír <pali.rohar@gmail.com>
5 
6  This program is free software: you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation, either version 3 of the License, or
9  (at your option) any later version.
10 
11  This program is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19 
20 
21 #include <limits.h>
22 #include <stdint.h>
23 #include <stdbool.h>
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <sys/ioctl.h>
27 #include <sys/sysmacros.h>
28 
29 #ifdef HAVE_LINUX_LOOP_H
30 #include <linux/loop.h>
31 #endif
32 
33 #if HAVE_DECL_GETMNTENT
34 #include <paths.h>
35 #include <mntent.h>
36 #endif
37 
38 #if HAVE_DECL_GETMNTINFO
39 #include <sys/param.h>
40 #include <sys/ucred.h>
41 #include <sys/mount.h>
42 #endif
43 
44 #include <unistd.h>
45 #include <dirent.h>
46 #include <stdio.h>
47 #include <string.h>
48 #include <stdlib.h>
49 #include <errno.h>
50 
51 #include "blkdev.h"
52 #include "device_info.h"
53 
54 
55 static const struct device_info device_info_clueless = {
56  .type = TYPE_UNKNOWN,
57  .partition = -1,
58  .has_children = -1,
59  .geom_heads = -1,
60  .geom_sectors = -1,
61  .geom_start = -1,
62  .geom_size = -1,
63  .sector_size = -1,
64  .size = -1,
65 };
66 
67 
69 
70 
71 static void get_block_device_size(struct device_info *info, int fd)
72 {
73  unsigned long long bytes;
74 
75  if (!blkdev_get_size(fd, &bytes) && bytes != 0)
76  info->size = bytes;
77 }
78 
79 
80 static void get_block_geometry(struct device_info *info, int fd, dev_t rdev)
81 {
82  unsigned int heads, sectors;
83  unsigned long long start;
84 
85  if (!blkdev_get_geometry(fd, &heads, &sectors)
86  && heads && sectors) {
87  info->geom_heads = heads;
88  info->geom_sectors = sectors;
89  }
90 
91  if (!blkdev_get_start(fd, rdev, &start))
92  info->geom_start = start;
93 }
94 
95 
96 static void get_sector_size(struct device_info *info, int fd)
97 {
98  int size;
99 
101  info->sector_size = size;
102 }
103 
104 
105 #ifdef __linux__
106 static void get_block_linux_info(struct device_info *info, int devfd, dev_t rdev)
107 {
108  struct stat st;
109  char path[PATH_MAX];
110  int fd;
111  int blockfd;
112  FILE *file;
113  DIR *dir;
114  struct dirent *d;
115  int maj;
116  int min;
117  long long start;
118  int removable;
119 
120 #ifdef HAVE_LINUX_LOOP_H
121  struct loop_info64 lo;
122 #endif
123 
124  maj = major(rdev);
125  min = minor(rdev);
126 
127  snprintf(path, sizeof(path), "/sys/dev/block/%d:%d", maj, min);
128  blockfd = open(path, O_RDONLY | O_DIRECTORY);
129  if (blockfd < 0)
130  return;
131 
132  /* Check if device is partition */
133  fd = openat(blockfd, "partition", O_RDONLY);
134  if (fd >= 0) {
135  file = fdopen(fd, "r");
136  if (file) {
137  if (fscanf(file, "%d", &info->partition) != 1 || info->partition == 0)
138  info->partition = -1;
139  fclose(file);
140  } else {
141  close(fd);
142  }
143  /* Read total number of sectors of the disk */
144  fd = openat(blockfd, "../size", O_RDONLY);
145  if (fd >= 0) {
146  file = fdopen(fd, "r");
147  if (file) {
148  if (fscanf(file, "%lld", &info->geom_size) != 1 || info->geom_size == 0)
149  info->geom_size = -1;
150  fclose(file);
151  } else {
152  close(fd);
153  }
154  }
155  } else if (errno == ENOENT && info->geom_start <= 0) {
156  info->partition = 0;
157  if (info->size > 0 && info->sector_size > 0)
158  info->geom_size = info->size / info->sector_size;
159  }
160 
161  /* Check if device has partition subdevice and therefore has children */
162  fd = dup(blockfd);
163  if (fd >= 0) {
164  dir = fdopendir(fd);
165  if (dir) {
166  info->has_children = 0;
167  errno = 0;
168  while ((d = readdir(dir))) {
169  if (strcmp(d->d_name, ".") == 0 || strcmp(d->d_name, "..") == 0)
170  continue;
171  if (d->d_type != DT_DIR && d->d_type != DT_UNKNOWN)
172  continue;
173  snprintf(path, sizeof(path), "%s/partition", d->d_name);
174  if (fstatat(blockfd, path, &st, 0) == 0) {
175  if (S_ISREG(st.st_mode)) {
176  start = -1;
177  snprintf(path, sizeof(path), "%s/start", d->d_name);
178  fd = openat(blockfd, path, O_RDONLY);
179  if (fd >= 0) {
180  file = fdopen(fd, "r");
181  if (file) {
182  if (fscanf(file, "%lld", &start) != 1)
183  start = -1;
184  fclose(file);
185  } else {
186  close(fd);
187  }
188  }
189  /* If subdevice starts at zero offset then it is whole device, so it is not a child */
190  if (start != 0) {
191  info->has_children = 1;
192  break;
193  }
194  }
195  } else if (errno != ENOENT) {
196  info->has_children = -1;
197  }
198  errno = 0;
199  }
200  if (errno != 0 && info->has_children == 0)
201  info->has_children = -1;
202  closedir(dir);
203  } else {
204  close(fd);
205  }
206  }
207 
208  /* Check if device has holders and therefore has children */
209  if (info->has_children <= 0) {
210  fd = openat(blockfd, "holders", O_RDONLY | O_DIRECTORY);
211  if (fd >= 0) {
212  dir = fdopendir(fd);
213  if (dir) {
214  while ((d = readdir(dir))) {
215  if (strcmp(d->d_name, ".") == 0 || strcmp(d->d_name, "..") == 0)
216  continue;
217  info->has_children = 1;
218  break;
219  }
220  closedir(dir);
221  } else {
222  close(fd);
223  }
224  }
225  }
226 
227  /* Check if device is slave of another device and therefore is virtual */
228  fd = openat(blockfd, "slaves", O_RDONLY | O_DIRECTORY);
229  if (fd >= 0) {
230  dir = fdopendir(fd);
231  if (dir) {
232  while ((d = readdir(dir))) {
233  if (strcmp(d->d_name, ".") == 0 || strcmp(d->d_name, "..") == 0)
234  continue;
235  info->type = TYPE_VIRTUAL;
236  break;
237  }
238  closedir(dir);
239  } else {
240  close(fd);
241  }
242  }
243 
244 #ifdef HAVE_LINUX_LOOP_H
245  /* Check if device is loop and detect if is based from regular file or is virtual */
246  if (info->type == TYPE_UNKNOWN && info->partition == 0 && ioctl(devfd, LOOP_GET_STATUS64, &lo) == 0) {
247  if (lo.lo_offset == 0 && lo.lo_sizelimit == 0 && lo.lo_encrypt_type == LO_CRYPT_NONE &&
248  stat((char *)lo.lo_file_name, &st) == 0 && S_ISREG(st.st_mode) &&
249  st.st_dev == lo.lo_device && st.st_ino == lo.lo_inode && st.st_size == info->size)
250  info->type = TYPE_FILE;
251  else
252  info->type = TYPE_VIRTUAL;
253  }
254 #endif
255 
256  /* Device is neither loop nor virtual, so is either removable or fixed */
257  if (info->type == TYPE_UNKNOWN) {
258  removable = 0;
259  fd = openat(blockfd, "removable", O_RDONLY);
260  if (fd >= 0) {
261  file = fdopen(fd, "r");
262  if (file) {
263  if (fscanf(file, "%d", &removable) != 1)
264  removable = 0;
265  fclose(file);
266  } else {
267  close(fd);
268  }
269  }
270 
271  if (removable)
272  info->type = TYPE_REMOVABLE;
273  else
274  info->type = TYPE_FIXED;
275  }
276 
277  close(blockfd);
278 }
279 #endif
280 
281 
282 int get_device_info(int fd, struct device_info *info)
283 {
284  struct stat stat;
285  int ret;
286 
287  *info = device_info_clueless;
288 
289  ret = fstat(fd, &stat);
290  if (ret < 0) {
291  perror("fstat on target failed");
292  return -1;
293  }
294 
295  if (S_ISREG(stat.st_mode)) {
296  /* there is nothing more to discover for an image file */
297  info->type = TYPE_FILE;
298  info->partition = 0;
299  info->size = stat.st_size;
300  return 0;
301  }
302 
303  if (!S_ISBLK(stat.st_mode)) {
304  /* neither regular file nor block device? not usable */
305  info->type = TYPE_BAD;
306  return 0;
307  }
308 
309  get_block_device_size(info, fd);
310  get_block_geometry(info, fd, stat.st_rdev);
311  get_sector_size(info, fd);
312 
313 #ifdef __linux__
314  get_block_linux_info(info, fd, stat.st_rdev);
315 #endif
316 
317  return 0;
318 }
319 
320 
321 int is_device_mounted(const char *path)
322 {
323 #if HAVE_DECL_GETMNTENT
324  FILE *f;
325  struct mntent *mnt;
326 
327  if ((f = setmntent(_PATH_MOUNTED, "r")) == NULL)
328  return 0;
329  while ((mnt = getmntent(f)) != NULL)
330  if (strcmp(path, mnt->mnt_fsname) == 0)
331  return 1;
332  endmntent(f);
333  return 0;
334 #endif
335 
336 #if HAVE_DECL_GETMNTINFO
337  struct statfs *stat;
338  int count, i;
339 
340  count = getmntinfo(&stat, 0);
341  for (i = 0; i < count; i++)
342  if (!strcmp(path, stat[i].f_mntfromname))
343  return 1;
344  return 0;
345 #endif
346 
347  (void)path; /* prevent unused parameter warning */
348  return 0;
349 }
int blkdev_get_size(int fd, unsigned long long *bytes)
Definition: blkdev.c:86
int blkdev_get_geometry(int fd, unsigned int *h, unsigned int *s)
Definition: blkdev.c:288
int blkdev_get_sector_size(int fd, int *sector_size)
Definition: blkdev.c:204
int blkdev_get_start(int fd, dev_t rdev, unsigned long long *s)
Definition: blkdev.c:323
int min(int a, int b)
Definition: common.c:113
static void get_block_device_size(struct device_info *info, int fd)
Definition: device_info.c:71
static void get_sector_size(struct device_info *info, int fd)
Definition: device_info.c:96
int device_info_verbose
Definition: device_info.c:68
int is_device_mounted(const char *path)
Definition: device_info.c:321
int get_device_info(int fd, struct device_info *info)
Definition: device_info.c:282
static const struct device_info device_info_clueless
Definition: device_info.c:55
static void get_block_geometry(struct device_info *info, int fd, dev_t rdev)
Definition: device_info.c:80
@ TYPE_REMOVABLE
Definition: device_info.h:9
@ TYPE_FILE
Definition: device_info.h:7
@ TYPE_BAD
Definition: device_info.h:6
@ TYPE_VIRTUAL
Definition: device_info.h:8
@ TYPE_UNKNOWN
Definition: device_info.h:5
@ TYPE_FIXED
Definition: device_info.h:10
static int fd
Definition: io.c:56
long long geom_start
Definition: device_info.h:37
enum device_type type
Definition: device_info.h:14
int geom_sectors
Definition: device_info.h:36
long long size
Definition: device_info.h:48
long long geom_size
Definition: device_info.h:38
int sector_size
Definition: device_info.h:43
int geom_heads
Definition: device_info.h:35
int has_children
Definition: device_info.h:30