"Fossies" - the Fresh Open Source Software Archive 
Member "dosfstools-4.2/src/device_info.c" (31 Jan 2021, 9495 Bytes) of package /linux/misc/dosfstools-4.2.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "device_info.c" see the
Fossies "Dox" file reference documentation and the latest
Fossies "Diffs" side-by-side code changes report:
4.1_vs_4.2.
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
68 int device_info_verbose;
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, §ors)
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
100 if (!blkdev_get_sector_size(fd, &size))
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 }