• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * probe disks for filesystems and partitions
3  *
4  * Copyright (C) 2011 Kay Sievers <kay@vrfy.org>
5  * Copyright (C) 2011 Karel Zak <kzak@redhat.com>
6  *
7  * This program is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation, either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
19  */
20 
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <stdarg.h>
24 #include <unistd.h>
25 #include <string.h>
26 #include <errno.h>
27 #include <fcntl.h>
28 #include <getopt.h>
29 #include <sys/stat.h>
30 #include <blkid/blkid.h>
31 
32 #include "udev.h"
33 
print_property(struct udev_device * dev,bool test,const char * name,const char * value)34 static void print_property(struct udev_device *dev, bool test, const char *name, const char *value) {
35         char s[256];
36 
37         s[0] = '\0';
38 
39         if (streq(name, "TYPE")) {
40                 udev_builtin_add_property(dev, test, "ID_FS_TYPE", value);
41 
42         } else if (streq(name, "USAGE")) {
43                 udev_builtin_add_property(dev, test, "ID_FS_USAGE", value);
44 
45         } else if (streq(name, "VERSION")) {
46                 udev_builtin_add_property(dev, test, "ID_FS_VERSION", value);
47 
48         } else if (streq(name, "UUID")) {
49                 blkid_safe_string(value, s, sizeof(s));
50                 udev_builtin_add_property(dev, test, "ID_FS_UUID", s);
51                 blkid_encode_string(value, s, sizeof(s));
52                 udev_builtin_add_property(dev, test, "ID_FS_UUID_ENC", s);
53 
54         } else if (streq(name, "UUID_SUB")) {
55                 blkid_safe_string(value, s, sizeof(s));
56                 udev_builtin_add_property(dev, test, "ID_FS_UUID_SUB", s);
57                 blkid_encode_string(value, s, sizeof(s));
58                 udev_builtin_add_property(dev, test, "ID_FS_UUID_SUB_ENC", s);
59 
60         } else if (streq(name, "LABEL")) {
61                 blkid_safe_string(value, s, sizeof(s));
62                 udev_builtin_add_property(dev, test, "ID_FS_LABEL", s);
63                 blkid_encode_string(value, s, sizeof(s));
64                 udev_builtin_add_property(dev, test, "ID_FS_LABEL_ENC", s);
65 
66         } else if (streq(name, "PTTYPE")) {
67                 udev_builtin_add_property(dev, test, "ID_PART_TABLE_TYPE", value);
68 
69         } else if (streq(name, "PTUUID")) {
70                 udev_builtin_add_property(dev, test, "ID_PART_TABLE_UUID", value);
71 
72         } else if (streq(name, "PART_ENTRY_NAME")) {
73                 blkid_encode_string(value, s, sizeof(s));
74                 udev_builtin_add_property(dev, test, "ID_PART_ENTRY_NAME", s);
75 
76         } else if (streq(name, "PART_ENTRY_TYPE")) {
77                 blkid_encode_string(value, s, sizeof(s));
78                 udev_builtin_add_property(dev, test, "ID_PART_ENTRY_TYPE", s);
79 
80         } else if (startswith(name, "PART_ENTRY_")) {
81                 strscpyl(s, sizeof(s), "ID_", name, NULL);
82                 udev_builtin_add_property(dev, test, s, value);
83 
84         } else if (streq(name, "SYSTEM_ID")) {
85                 blkid_encode_string(value, s, sizeof(s));
86                 udev_builtin_add_property(dev, test, "ID_FS_SYSTEM_ID", s);
87 
88         } else if (streq(name, "PUBLISHER_ID")) {
89                 blkid_encode_string(value, s, sizeof(s));
90                 udev_builtin_add_property(dev, test, "ID_FS_PUBLISHER_ID", s);
91 
92         } else if (streq(name, "APPLICATION_ID")) {
93                 blkid_encode_string(value, s, sizeof(s));
94                 udev_builtin_add_property(dev, test, "ID_FS_APPLICATION_ID", s);
95 
96         } else if (streq(name, "BOOT_SYSTEM_ID")) {
97                 blkid_encode_string(value, s, sizeof(s));
98                 udev_builtin_add_property(dev, test, "ID_FS_BOOT_SYSTEM_ID", s);
99         }
100 }
101 
probe_superblocks(blkid_probe pr)102 static int probe_superblocks(blkid_probe pr) {
103         struct stat st;
104         int rc;
105 
106         if (fstat(blkid_probe_get_fd(pr), &st))
107                 return -1;
108 
109         blkid_probe_enable_partitions(pr, 1);
110 
111         if (!S_ISCHR(st.st_mode) &&
112             blkid_probe_get_size(pr) <= 1024 * 1440 &&
113             blkid_probe_is_wholedisk(pr)) {
114                 /*
115                  * check if the small disk is partitioned, if yes then
116                  * don't probe for filesystems.
117                  */
118                 blkid_probe_enable_superblocks(pr, 0);
119 
120                 rc = blkid_do_fullprobe(pr);
121                 if (rc < 0)
122                         return rc;        /* -1 = error, 1 = nothing, 0 = success */
123 
124                 if (blkid_probe_lookup_value(pr, "PTTYPE", NULL, NULL) == 0)
125                         return 0;        /* partition table detected */
126         }
127 
128         blkid_probe_set_partitions_flags(pr, BLKID_PARTS_ENTRY_DETAILS);
129         blkid_probe_enable_superblocks(pr, 1);
130 
131         return blkid_do_safeprobe(pr);
132 }
133 
builtin_blkid(struct udev_device * dev,int argc,char * argv[],bool test)134 static int builtin_blkid(struct udev_device *dev, int argc, char *argv[], bool test) {
135         int64_t offset = 0;
136         bool noraid = false;
137         _cleanup_close_ int fd = -1;
138         blkid_probe pr;
139         const char *data;
140         const char *name;
141         const char *prtype = NULL;
142         int nvals;
143         int i;
144         int err = 0;
145 
146         static const struct option options[] = {
147                 { "offset", optional_argument, NULL, 'o' },
148                 { "noraid", no_argument, NULL, 'R' },
149                 {}
150         };
151 
152         for (;;) {
153                 int option;
154 
155                 option = getopt_long(argc, argv, "oR", options, NULL);
156                 if (option == -1)
157                         break;
158 
159                 switch (option) {
160                 case 'o':
161                         offset = strtoull(optarg, NULL, 0);
162                         break;
163                 case 'R':
164                         noraid = true;
165                         break;
166                 }
167         }
168 
169         pr = blkid_new_probe();
170         if (!pr)
171                 return EXIT_FAILURE;
172 
173         blkid_probe_set_superblocks_flags(pr,
174                 BLKID_SUBLKS_LABEL | BLKID_SUBLKS_UUID |
175                 BLKID_SUBLKS_TYPE | BLKID_SUBLKS_SECTYPE |
176                 BLKID_SUBLKS_USAGE | BLKID_SUBLKS_VERSION |
177                 BLKID_SUBLKS_BADCSUM);
178 
179         if (noraid)
180                 blkid_probe_filter_superblocks_usage(pr, BLKID_FLTR_NOTIN, BLKID_USAGE_RAID);
181 
182         fd = open(udev_device_get_devnode(dev), O_RDONLY|O_CLOEXEC);
183         if (fd < 0) {
184                 err = log_debug_errno(errno, "Failure opening block device %s: %m", udev_device_get_devnode(dev));
185                 goto out;
186         }
187 
188         err = blkid_probe_set_device(pr, fd, offset, 0);
189         if (err < 0)
190                 goto out;
191 
192         log_debug("probe %s %sraid offset=%"PRIi64,
193                   udev_device_get_devnode(dev),
194                   noraid ? "no" : "", offset);
195 
196         err = probe_superblocks(pr);
197         if (err < 0)
198                 goto out;
199         if (blkid_probe_has_value(pr, "SBBADCSUM")) {
200                 if (!blkid_probe_lookup_value(pr, "TYPE", &prtype, NULL))
201                         log_warning("incorrect %s checksum on %s",
202                                     prtype, udev_device_get_devnode(dev));
203                 else
204                         log_warning("incorrect checksum on %s",
205                                     udev_device_get_devnode(dev));
206                 goto out;
207         }
208 
209         nvals = blkid_probe_numof_values(pr);
210         for (i = 0; i < nvals; i++) {
211                 if (blkid_probe_get_value(pr, i, &name, &data, NULL))
212                         continue;
213 
214                 print_property(dev, test, name, data);
215         }
216 
217         blkid_free_probe(pr);
218 out:
219         if (err < 0)
220                 return EXIT_FAILURE;
221 
222         return EXIT_SUCCESS;
223 }
224 
225 const struct udev_builtin udev_builtin_blkid = {
226         .name = "blkid",
227         .cmd = builtin_blkid,
228         .help = "Filesystem and partition probing",
229         .run_once = true,
230 };
231