paul@181 | 1 | /* |
paul@181 | 2 | * probe.c - identify a block device by its contents, and return a dev |
paul@181 | 3 | * struct with the details |
paul@181 | 4 | * |
paul@181 | 5 | * Copyright (C) 1999 by Andries Brouwer |
paul@181 | 6 | * Copyright (C) 1999, 2000, 2003 by Theodore Ts'o |
paul@181 | 7 | * Copyright (C) 2001 by Andreas Dilger |
paul@181 | 8 | * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org> |
paul@181 | 9 | * |
paul@181 | 10 | * %Begin-Header% |
paul@181 | 11 | * This file may be redistributed under the terms of the |
paul@181 | 12 | * GNU Lesser General Public License. |
paul@181 | 13 | * %End-Header% |
paul@181 | 14 | */ |
paul@181 | 15 | |
paul@181 | 16 | #include "config.h" |
paul@181 | 17 | #include <stdio.h> |
paul@181 | 18 | #include <string.h> |
paul@181 | 19 | #include <stdlib.h> |
paul@181 | 20 | #include <unistd.h> |
paul@181 | 21 | #include <fcntl.h> |
paul@181 | 22 | #include <ctype.h> |
paul@181 | 23 | #include <sys/types.h> |
paul@181 | 24 | #ifdef HAVE_SYS_STAT_H |
paul@181 | 25 | #include <sys/stat.h> |
paul@181 | 26 | #endif |
paul@181 | 27 | #ifdef HAVE_SYS_MKDEV_H |
paul@181 | 28 | #include <sys/mkdev.h> |
paul@181 | 29 | #endif |
paul@181 | 30 | #ifdef __linux__ |
paul@181 | 31 | #include <sys/utsname.h> |
paul@181 | 32 | #endif |
paul@181 | 33 | #ifdef HAVE_ERRNO_H |
paul@181 | 34 | #include <errno.h> |
paul@181 | 35 | #endif |
paul@181 | 36 | #include "blkidP.h" |
paul@181 | 37 | #include "uuid/uuid.h" |
paul@181 | 38 | #include "probe.h" |
paul@181 | 39 | |
paul@181 | 40 | static int figure_label_len(const unsigned char *label, int len) |
paul@181 | 41 | { |
paul@181 | 42 | const unsigned char *end = label + len - 1; |
paul@181 | 43 | |
paul@181 | 44 | while (end >= label && (*end == ' ' || *end == 0)) |
paul@181 | 45 | --end; |
paul@181 | 46 | if (end >= label) |
paul@181 | 47 | return end - label + 1; |
paul@181 | 48 | return 0; |
paul@181 | 49 | } |
paul@181 | 50 | |
paul@181 | 51 | static unsigned char *get_buffer(struct blkid_probe *pr, |
paul@181 | 52 | blkid_loff_t off, size_t len) |
paul@181 | 53 | { |
paul@181 | 54 | ssize_t ret_read; |
paul@181 | 55 | unsigned char *newbuf; |
paul@181 | 56 | |
paul@181 | 57 | if (off + len <= SB_BUFFER_SIZE) { |
paul@181 | 58 | if (!pr->sbbuf) { |
paul@181 | 59 | pr->sbbuf = malloc(SB_BUFFER_SIZE); |
paul@181 | 60 | if (!pr->sbbuf) |
paul@181 | 61 | return NULL; |
paul@181 | 62 | if (lseek(pr->fd, 0, SEEK_SET) < 0) |
paul@181 | 63 | return NULL; |
paul@181 | 64 | ret_read = read(pr->fd, pr->sbbuf, SB_BUFFER_SIZE); |
paul@181 | 65 | if (ret_read < 0) |
paul@181 | 66 | ret_read = 0; |
paul@181 | 67 | pr->sb_valid = ret_read; |
paul@181 | 68 | } |
paul@181 | 69 | if (off+len > pr->sb_valid) |
paul@181 | 70 | return NULL; |
paul@181 | 71 | return pr->sbbuf + off; |
paul@181 | 72 | } else { |
paul@181 | 73 | if (len > pr->buf_max) { |
paul@181 | 74 | newbuf = realloc(pr->buf, len); |
paul@181 | 75 | if (newbuf == NULL) |
paul@181 | 76 | return NULL; |
paul@181 | 77 | pr->buf = newbuf; |
paul@181 | 78 | pr->buf_max = len; |
paul@181 | 79 | } |
paul@181 | 80 | if (blkid_llseek(pr->fd, off, SEEK_SET) < 0) |
paul@181 | 81 | return NULL; |
paul@181 | 82 | ret_read = read(pr->fd, pr->buf, len); |
paul@181 | 83 | if (ret_read != (ssize_t) len) |
paul@181 | 84 | return NULL; |
paul@181 | 85 | return pr->buf; |
paul@181 | 86 | } |
paul@181 | 87 | } |
paul@181 | 88 | |
paul@181 | 89 | |
paul@181 | 90 | /* |
paul@181 | 91 | * This is a special case code to check for an MDRAID device. We do |
paul@181 | 92 | * this special since it requires checking for a superblock at the end |
paul@181 | 93 | * of the device. |
paul@181 | 94 | */ |
paul@181 | 95 | static int check_mdraid(int fd, unsigned char *ret_uuid) |
paul@181 | 96 | { |
paul@181 | 97 | struct mdp_superblock_s *md; |
paul@181 | 98 | blkid_loff_t offset; |
paul@181 | 99 | char buf[4096]; |
paul@181 | 100 | |
paul@181 | 101 | if (fd < 0) |
paul@181 | 102 | return -BLKID_ERR_PARAM; |
paul@181 | 103 | |
paul@181 | 104 | offset = (blkid_get_dev_size(fd) & ~((blkid_loff_t)65535)) - 65536; |
paul@181 | 105 | |
paul@181 | 106 | if (blkid_llseek(fd, offset, 0) < 0 || |
paul@181 | 107 | read(fd, buf, 4096) != 4096) |
paul@181 | 108 | return -BLKID_ERR_IO; |
paul@181 | 109 | /* Check for magic number */ |
paul@181 | 110 | if (memcmp("\251+N\374", buf, 4) && memcmp("\374N+\251", buf, 4)) |
paul@181 | 111 | return -BLKID_ERR_PARAM; |
paul@181 | 112 | |
paul@181 | 113 | if (!ret_uuid) |
paul@181 | 114 | return 0; |
paul@181 | 115 | *ret_uuid = 0; |
paul@181 | 116 | |
paul@181 | 117 | /* The MD UUID is not contiguous in the superblock, make it so */ |
paul@181 | 118 | md = (struct mdp_superblock_s *)buf; |
paul@181 | 119 | if (md->set_uuid0 || md->set_uuid1 || md->set_uuid2 || md->set_uuid3) { |
paul@181 | 120 | memcpy(ret_uuid, &md->set_uuid0, 4); |
paul@181 | 121 | memcpy(ret_uuid + 4, &md->set_uuid1, 12); |
paul@181 | 122 | } |
paul@181 | 123 | return 0; |
paul@181 | 124 | } |
paul@181 | 125 | |
paul@181 | 126 | static void set_uuid(blkid_dev dev, uuid_t uuid, const char *tag) |
paul@181 | 127 | { |
paul@181 | 128 | char str[37]; |
paul@181 | 129 | |
paul@181 | 130 | if (!uuid_is_null(uuid)) { |
paul@181 | 131 | uuid_unparse(uuid, str); |
paul@181 | 132 | blkid_set_tag(dev, tag ? tag : "UUID", str, sizeof(str)); |
paul@181 | 133 | } |
paul@181 | 134 | } |
paul@181 | 135 | |
paul@181 | 136 | static void get_ext2_info(blkid_dev dev, struct blkid_magic *id, |
paul@181 | 137 | unsigned char *buf) |
paul@181 | 138 | { |
paul@181 | 139 | struct ext2_super_block *es = (struct ext2_super_block *) buf; |
paul@181 | 140 | const char *label = 0; |
paul@181 | 141 | |
paul@181 | 142 | DBG(DEBUG_PROBE, printf("ext2_sb.compat = %08X:%08X:%08X\n", |
paul@181 | 143 | blkid_le32(es->s_feature_compat), |
paul@181 | 144 | blkid_le32(es->s_feature_incompat), |
paul@181 | 145 | blkid_le32(es->s_feature_ro_compat))); |
paul@181 | 146 | |
paul@212 | 147 | if (es->s_volume_name[0]) |
paul@181 | 148 | label = es->s_volume_name; |
paul@181 | 149 | blkid_set_tag(dev, "LABEL", label, sizeof(es->s_volume_name)); |
paul@181 | 150 | |
paul@181 | 151 | set_uuid(dev, es->s_uuid, 0); |
paul@181 | 152 | |
paul@181 | 153 | if ((es->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL) && |
paul@181 | 154 | !uuid_is_null(es->s_journal_uuid)) |
paul@181 | 155 | set_uuid(dev, es->s_journal_uuid, "EXT_JOURNAL"); |
paul@181 | 156 | |
paul@181 | 157 | if (strcmp(id->bim_type, "ext2") && |
paul@181 | 158 | ((blkid_le32(es->s_feature_incompat) & |
paul@181 | 159 | EXT2_FEATURE_INCOMPAT_UNSUPPORTED) == 0)) |
paul@181 | 160 | blkid_set_tag(dev, "SEC_TYPE", "ext2", sizeof("ext2")); |
paul@181 | 161 | } |
paul@181 | 162 | |
paul@181 | 163 | /* |
paul@181 | 164 | * Check to see if a filesystem is in /proc/filesystems. |
paul@181 | 165 | * Returns 1 if found, 0 if not |
paul@181 | 166 | */ |
paul@181 | 167 | static int fs_proc_check(const char *fs_name) |
paul@181 | 168 | { |
paul@181 | 169 | FILE *f; |
paul@181 | 170 | char buf[80], *cp, *t; |
paul@181 | 171 | |
paul@181 | 172 | f = fopen("/proc/filesystems", "r"); |
paul@181 | 173 | if (!f) |
paul@181 | 174 | return (0); |
paul@181 | 175 | while (!feof(f)) { |
paul@181 | 176 | if (!fgets(buf, sizeof(buf), f)) |
paul@181 | 177 | break; |
paul@181 | 178 | cp = buf; |
paul@181 | 179 | if (!isspace(*cp)) { |
paul@181 | 180 | while (*cp && !isspace(*cp)) |
paul@181 | 181 | cp++; |
paul@181 | 182 | } |
paul@181 | 183 | while (*cp && isspace(*cp)) |
paul@181 | 184 | cp++; |
paul@181 | 185 | if ((t = strchr(cp, '\n')) != NULL) |
paul@181 | 186 | *t = 0; |
paul@181 | 187 | if ((t = strchr(cp, '\t')) != NULL) |
paul@181 | 188 | *t = 0; |
paul@181 | 189 | if ((t = strchr(cp, ' ')) != NULL) |
paul@181 | 190 | *t = 0; |
paul@181 | 191 | if (!strcmp(fs_name, cp)) { |
paul@181 | 192 | fclose(f); |
paul@181 | 193 | return (1); |
paul@181 | 194 | } |
paul@181 | 195 | } |
paul@181 | 196 | fclose(f); |
paul@181 | 197 | return (0); |
paul@181 | 198 | } |
paul@181 | 199 | |
paul@181 | 200 | /* |
paul@181 | 201 | * Check to see if a filesystem is available as a module |
paul@181 | 202 | * Returns 1 if found, 0 if not |
paul@181 | 203 | */ |
paul@181 | 204 | static int check_for_modules(const char *fs_name) |
paul@181 | 205 | { |
paul@181 | 206 | #ifdef __linux__ |
paul@181 | 207 | struct utsname uts; |
paul@181 | 208 | FILE *f; |
paul@181 | 209 | char buf[1024], *cp; |
paul@181 | 210 | int namesz; |
paul@181 | 211 | |
paul@181 | 212 | if (uname(&uts)) |
paul@181 | 213 | return (0); |
paul@181 | 214 | snprintf(buf, sizeof(buf), "/lib/modules/%s/modules.dep", uts.release); |
paul@181 | 215 | |
paul@181 | 216 | f = fopen(buf, "r"); |
paul@181 | 217 | if (!f) |
paul@181 | 218 | return (0); |
paul@181 | 219 | |
paul@181 | 220 | namesz = strlen(fs_name); |
paul@181 | 221 | |
paul@181 | 222 | while (!feof(f)) { |
paul@181 | 223 | if (!fgets(buf, sizeof(buf), f)) |
paul@181 | 224 | break; |
paul@181 | 225 | if ((cp = strchr(buf, ':')) != NULL) |
paul@181 | 226 | *cp = 0; |
paul@181 | 227 | else |
paul@181 | 228 | continue; |
paul@181 | 229 | if ((cp = strrchr(buf, '/')) != NULL) |
paul@181 | 230 | cp++; |
paul@181 | 231 | else |
paul@181 | 232 | cp = buf; |
paul@181 | 233 | if (!strncmp(cp, fs_name, namesz) && |
paul@181 | 234 | (!strcmp(cp + namesz, ".ko") || |
paul@181 | 235 | !strcmp(cp + namesz, ".ko.gz"))) { |
paul@181 | 236 | fclose(f); |
paul@181 | 237 | return (1); |
paul@181 | 238 | } |
paul@181 | 239 | } |
paul@181 | 240 | fclose(f); |
paul@181 | 241 | #endif |
paul@181 | 242 | return (0); |
paul@181 | 243 | } |
paul@181 | 244 | |
paul@181 | 245 | static int linux_version_code(void) |
paul@181 | 246 | { |
paul@181 | 247 | #ifdef __linux__ |
paul@181 | 248 | struct utsname ut; |
paul@181 | 249 | static int version_code = -1; |
paul@181 | 250 | int major, minor, rev; |
paul@181 | 251 | char *endptr; |
paul@181 | 252 | const char *cp; |
paul@181 | 253 | |
paul@181 | 254 | if (version_code > 0) |
paul@181 | 255 | return version_code; |
paul@181 | 256 | |
paul@181 | 257 | if (uname(&ut)) |
paul@181 | 258 | return 0; |
paul@181 | 259 | cp = ut.release; |
paul@181 | 260 | |
paul@181 | 261 | major = strtol(cp, &endptr, 10); |
paul@181 | 262 | if (cp == endptr || *endptr != '.') |
paul@181 | 263 | return 0; |
paul@181 | 264 | cp = endptr + 1; |
paul@181 | 265 | minor = strtol(cp, &endptr, 10); |
paul@181 | 266 | if (cp == endptr || *endptr != '.') |
paul@181 | 267 | return 0; |
paul@181 | 268 | cp = endptr + 1; |
paul@181 | 269 | rev = strtol(cp, &endptr, 10); |
paul@181 | 270 | if (cp == endptr) |
paul@181 | 271 | return 0; |
paul@181 | 272 | version_code = (((major * 256) + minor) * 256) + rev; |
paul@181 | 273 | return version_code; |
paul@181 | 274 | #else |
paul@181 | 275 | return 0; |
paul@181 | 276 | #endif |
paul@181 | 277 | } |
paul@181 | 278 | |
paul@181 | 279 | #define EXT4_SUPPORTS_EXT2 (2 * 65536 + 6*256 + 29) |
paul@181 | 280 | |
paul@181 | 281 | static int system_supports_ext2(void) |
paul@181 | 282 | { |
paul@181 | 283 | static time_t last_check = 0; |
paul@181 | 284 | static int ret = -1; |
paul@181 | 285 | time_t now = time(0); |
paul@181 | 286 | |
paul@181 | 287 | if (ret != -1 || (now - last_check) < 5) |
paul@181 | 288 | return ret; |
paul@181 | 289 | last_check = now; |
paul@181 | 290 | ret = (fs_proc_check("ext2") || check_for_modules("ext2")); |
paul@181 | 291 | return ret; |
paul@181 | 292 | } |
paul@181 | 293 | |
paul@181 | 294 | static int system_supports_ext4(void) |
paul@181 | 295 | { |
paul@181 | 296 | static time_t last_check = 0; |
paul@181 | 297 | static int ret = -1; |
paul@181 | 298 | time_t now = time(0); |
paul@181 | 299 | |
paul@181 | 300 | if (ret != -1 || (now - last_check) < 5) |
paul@181 | 301 | return ret; |
paul@181 | 302 | last_check = now; |
paul@181 | 303 | ret = (fs_proc_check("ext4") || check_for_modules("ext4")); |
paul@181 | 304 | return ret; |
paul@181 | 305 | } |
paul@181 | 306 | |
paul@181 | 307 | static int system_supports_ext4dev(void) |
paul@181 | 308 | { |
paul@181 | 309 | static time_t last_check = 0; |
paul@181 | 310 | static int ret = -1; |
paul@181 | 311 | time_t now = time(0); |
paul@181 | 312 | |
paul@181 | 313 | if (ret != -1 || (now - last_check) < 5) |
paul@181 | 314 | return ret; |
paul@181 | 315 | last_check = now; |
paul@181 | 316 | ret = (fs_proc_check("ext4dev") || check_for_modules("ext4dev")); |
paul@181 | 317 | return ret; |
paul@181 | 318 | } |
paul@181 | 319 | |
paul@181 | 320 | static int probe_ext4dev(struct blkid_probe *probe, |
paul@181 | 321 | struct blkid_magic *id, |
paul@181 | 322 | unsigned char *buf) |
paul@181 | 323 | { |
paul@181 | 324 | struct ext2_super_block *es; |
paul@181 | 325 | es = (struct ext2_super_block *)buf; |
paul@181 | 326 | |
paul@181 | 327 | /* Distinguish from jbd */ |
paul@181 | 328 | if (blkid_le32(es->s_feature_incompat) & |
paul@181 | 329 | EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) |
paul@181 | 330 | return -BLKID_ERR_PARAM; |
paul@181 | 331 | |
paul@181 | 332 | /* |
paul@181 | 333 | * If the filesystem does not have a journal and ext2 and ext4 |
paul@181 | 334 | * is not present, then force this to be detected as an |
paul@181 | 335 | * ext4dev filesystem. |
paul@181 | 336 | */ |
paul@181 | 337 | if (!(blkid_le32(es->s_feature_compat) & |
paul@181 | 338 | EXT3_FEATURE_COMPAT_HAS_JOURNAL) && |
paul@181 | 339 | !system_supports_ext2() && !system_supports_ext4() && |
paul@181 | 340 | system_supports_ext4dev() && |
paul@181 | 341 | linux_version_code() >= EXT4_SUPPORTS_EXT2) |
paul@181 | 342 | goto force_ext4dev; |
paul@181 | 343 | |
paul@181 | 344 | /* |
paul@181 | 345 | * If the filesystem is marked as OK for use by in-development |
paul@181 | 346 | * filesystem code, but ext4dev is not supported, and ext4 is, |
paul@181 | 347 | * then don't call ourselves ext4dev, since we should be |
paul@181 | 348 | * detected as ext4 in that case. |
paul@181 | 349 | * |
paul@181 | 350 | * If the filesystem is marked as in use by production |
paul@181 | 351 | * filesystem, then it can only be used by ext4 and NOT by |
paul@181 | 352 | * ext4dev, so always disclaim we are ext4dev in that case. |
paul@181 | 353 | */ |
paul@181 | 354 | if (blkid_le32(es->s_flags) & EXT2_FLAGS_TEST_FILESYS) { |
paul@181 | 355 | if (!system_supports_ext4dev() && system_supports_ext4()) |
paul@181 | 356 | return -BLKID_ERR_PARAM; |
paul@181 | 357 | } else |
paul@181 | 358 | return -BLKID_ERR_PARAM; |
paul@181 | 359 | |
paul@181 | 360 | force_ext4dev: |
paul@181 | 361 | get_ext2_info(probe->dev, id, buf); |
paul@181 | 362 | return 0; |
paul@181 | 363 | } |
paul@181 | 364 | |
paul@181 | 365 | static int probe_ext4(struct blkid_probe *probe, struct blkid_magic *id, |
paul@181 | 366 | unsigned char *buf) |
paul@181 | 367 | { |
paul@181 | 368 | struct ext2_super_block *es; |
paul@181 | 369 | es = (struct ext2_super_block *)buf; |
paul@181 | 370 | |
paul@181 | 371 | /* Distinguish from jbd */ |
paul@181 | 372 | if (blkid_le32(es->s_feature_incompat) & |
paul@181 | 373 | EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) |
paul@181 | 374 | return -BLKID_ERR_PARAM; |
paul@181 | 375 | |
paul@181 | 376 | /* |
paul@181 | 377 | * If the filesystem does not have a journal and ext2 is not |
paul@181 | 378 | * present, then force this to be detected as an ext2 |
paul@181 | 379 | * filesystem. |
paul@181 | 380 | */ |
paul@181 | 381 | if (!(blkid_le32(es->s_feature_compat) & |
paul@181 | 382 | EXT3_FEATURE_COMPAT_HAS_JOURNAL) && |
paul@181 | 383 | !system_supports_ext2() && system_supports_ext4() && |
paul@181 | 384 | linux_version_code() >= EXT4_SUPPORTS_EXT2) |
paul@181 | 385 | goto force_ext4; |
paul@181 | 386 | |
paul@181 | 387 | /* Ext4 has at least one feature which ext3 doesn't understand */ |
paul@181 | 388 | if (!(blkid_le32(es->s_feature_ro_compat) & |
paul@181 | 389 | EXT3_FEATURE_RO_COMPAT_UNSUPPORTED) && |
paul@181 | 390 | !(blkid_le32(es->s_feature_incompat) & |
paul@181 | 391 | EXT3_FEATURE_INCOMPAT_UNSUPPORTED)) |
paul@181 | 392 | return -BLKID_ERR_PARAM; |
paul@181 | 393 | |
paul@181 | 394 | force_ext4: |
paul@181 | 395 | /* |
paul@181 | 396 | * If the filesystem is a OK for use by in-development |
paul@181 | 397 | * filesystem code, and ext4dev is supported or ext4 is not |
paul@181 | 398 | * supported, then don't call ourselves ext4, so we can redo |
paul@181 | 399 | * the detection and mark the filesystem as ext4dev. |
paul@181 | 400 | * |
paul@181 | 401 | * If the filesystem is marked as in use by production |
paul@181 | 402 | * filesystem, then it can only be used by ext4 and NOT by |
paul@181 | 403 | * ext4dev. |
paul@181 | 404 | */ |
paul@181 | 405 | if (blkid_le32(es->s_flags) & EXT2_FLAGS_TEST_FILESYS) { |
paul@181 | 406 | if (system_supports_ext4dev() || !system_supports_ext4()) |
paul@181 | 407 | return -BLKID_ERR_PARAM; |
paul@181 | 408 | } |
paul@181 | 409 | get_ext2_info(probe->dev, id, buf); |
paul@181 | 410 | return 0; |
paul@181 | 411 | } |
paul@181 | 412 | |
paul@181 | 413 | static int probe_ext3(struct blkid_probe *probe, struct blkid_magic *id, |
paul@181 | 414 | unsigned char *buf) |
paul@181 | 415 | { |
paul@181 | 416 | struct ext2_super_block *es; |
paul@181 | 417 | es = (struct ext2_super_block *)buf; |
paul@181 | 418 | |
paul@181 | 419 | /* ext3 requires journal */ |
paul@181 | 420 | if (!(blkid_le32(es->s_feature_compat) & |
paul@181 | 421 | EXT3_FEATURE_COMPAT_HAS_JOURNAL)) |
paul@181 | 422 | return -BLKID_ERR_PARAM; |
paul@181 | 423 | |
paul@181 | 424 | /* Any features which ext3 doesn't understand */ |
paul@181 | 425 | if ((blkid_le32(es->s_feature_ro_compat) & |
paul@181 | 426 | EXT3_FEATURE_RO_COMPAT_UNSUPPORTED) || |
paul@181 | 427 | (blkid_le32(es->s_feature_incompat) & |
paul@181 | 428 | EXT3_FEATURE_INCOMPAT_UNSUPPORTED)) |
paul@181 | 429 | return -BLKID_ERR_PARAM; |
paul@181 | 430 | |
paul@181 | 431 | get_ext2_info(probe->dev, id, buf); |
paul@181 | 432 | return 0; |
paul@181 | 433 | } |
paul@181 | 434 | |
paul@181 | 435 | static int probe_ext2(struct blkid_probe *probe, struct blkid_magic *id, |
paul@181 | 436 | unsigned char *buf) |
paul@181 | 437 | { |
paul@181 | 438 | struct ext2_super_block *es; |
paul@181 | 439 | |
paul@181 | 440 | es = (struct ext2_super_block *)buf; |
paul@181 | 441 | |
paul@181 | 442 | /* Distinguish between ext3 and ext2 */ |
paul@181 | 443 | if ((blkid_le32(es->s_feature_compat) & |
paul@181 | 444 | EXT3_FEATURE_COMPAT_HAS_JOURNAL)) |
paul@181 | 445 | return -BLKID_ERR_PARAM; |
paul@181 | 446 | |
paul@181 | 447 | /* Any features which ext2 doesn't understand */ |
paul@181 | 448 | if ((blkid_le32(es->s_feature_ro_compat) & |
paul@181 | 449 | EXT2_FEATURE_RO_COMPAT_UNSUPPORTED) || |
paul@181 | 450 | (blkid_le32(es->s_feature_incompat) & |
paul@181 | 451 | EXT2_FEATURE_INCOMPAT_UNSUPPORTED)) |
paul@181 | 452 | return -BLKID_ERR_PARAM; |
paul@181 | 453 | |
paul@181 | 454 | /* |
paul@181 | 455 | * If ext2 is not present, but ext4 or ext4dev are, then |
paul@181 | 456 | * disclaim we are ext2 |
paul@181 | 457 | */ |
paul@181 | 458 | if (!system_supports_ext2() && |
paul@181 | 459 | (system_supports_ext4() || system_supports_ext4dev()) && |
paul@181 | 460 | linux_version_code() >= EXT4_SUPPORTS_EXT2) |
paul@181 | 461 | return -BLKID_ERR_PARAM; |
paul@181 | 462 | |
paul@181 | 463 | get_ext2_info(probe->dev, id, buf); |
paul@181 | 464 | return 0; |
paul@181 | 465 | } |
paul@181 | 466 | |
paul@181 | 467 | static int probe_jbd(struct blkid_probe *probe, struct blkid_magic *id, |
paul@181 | 468 | unsigned char *buf) |
paul@181 | 469 | { |
paul@181 | 470 | struct ext2_super_block *es = (struct ext2_super_block *) buf; |
paul@181 | 471 | |
paul@181 | 472 | if (!(blkid_le32(es->s_feature_incompat) & |
paul@181 | 473 | EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)) |
paul@181 | 474 | return -BLKID_ERR_PARAM; |
paul@181 | 475 | |
paul@181 | 476 | get_ext2_info(probe->dev, id, buf); |
paul@181 | 477 | |
paul@181 | 478 | return 0; |
paul@181 | 479 | } |
paul@181 | 480 | |
paul@181 | 481 | #define FAT_ATTR_VOLUME_ID 0x08 |
paul@181 | 482 | #define FAT_ATTR_DIR 0x10 |
paul@181 | 483 | #define FAT_ATTR_LONG_NAME 0x0f |
paul@181 | 484 | #define FAT_ATTR_MASK 0x3f |
paul@181 | 485 | #define FAT_ENTRY_FREE 0xe5 |
paul@181 | 486 | |
paul@181 | 487 | static const char *no_name = "NO NAME "; |
paul@181 | 488 | |
paul@181 | 489 | static unsigned char *search_fat_label(struct vfat_dir_entry *dir, int count) |
paul@181 | 490 | { |
paul@181 | 491 | int i; |
paul@181 | 492 | |
paul@181 | 493 | for (i = 0; i < count; i++) { |
paul@181 | 494 | if (dir[i].name[0] == 0x00) |
paul@181 | 495 | break; |
paul@181 | 496 | |
paul@181 | 497 | if ((dir[i].name[0] == FAT_ENTRY_FREE) || |
paul@181 | 498 | (dir[i].cluster_high != 0 || dir[i].cluster_low != 0) || |
paul@181 | 499 | ((dir[i].attr & FAT_ATTR_MASK) == FAT_ATTR_LONG_NAME)) |
paul@181 | 500 | continue; |
paul@181 | 501 | |
paul@181 | 502 | if ((dir[i].attr & (FAT_ATTR_VOLUME_ID | FAT_ATTR_DIR)) == |
paul@181 | 503 | FAT_ATTR_VOLUME_ID) { |
paul@181 | 504 | return dir[i].name; |
paul@181 | 505 | } |
paul@181 | 506 | } |
paul@181 | 507 | return 0; |
paul@181 | 508 | } |
paul@181 | 509 | |
paul@181 | 510 | /* FAT label extraction from the root directory taken from Kay |
paul@181 | 511 | * Sievers's volume_id library */ |
paul@181 | 512 | static int probe_fat(struct blkid_probe *probe, |
paul@181 | 513 | struct blkid_magic *id __BLKID_ATTR((unused)), |
paul@181 | 514 | unsigned char *buf) |
paul@181 | 515 | { |
paul@181 | 516 | struct vfat_super_block *vs = (struct vfat_super_block *) buf; |
paul@181 | 517 | struct msdos_super_block *ms = (struct msdos_super_block *) buf; |
paul@181 | 518 | struct vfat_dir_entry *dir; |
paul@181 | 519 | char serno[10]; |
paul@181 | 520 | const unsigned char *label = 0, *vol_label = 0, *tmp; |
paul@181 | 521 | unsigned char *vol_serno; |
paul@181 | 522 | int label_len = 0, maxloop = 100; |
paul@181 | 523 | __u16 sector_size, dir_entries, reserved; |
paul@181 | 524 | __u32 sect_count, fat_size, dir_size, cluster_count, fat_length; |
paul@181 | 525 | __u32 buf_size, start_data_sect, next, root_start, root_dir_entries; |
paul@181 | 526 | |
paul@181 | 527 | /* sector size check */ |
paul@181 | 528 | tmp = (unsigned char *)&ms->ms_sector_size; |
paul@181 | 529 | sector_size = tmp[0] + (tmp[1] << 8); |
paul@181 | 530 | if (sector_size != 0x200 && sector_size != 0x400 && |
paul@181 | 531 | sector_size != 0x800 && sector_size != 0x1000) |
paul@181 | 532 | return 1; |
paul@181 | 533 | |
paul@181 | 534 | tmp = (unsigned char *)&ms->ms_dir_entries; |
paul@181 | 535 | dir_entries = tmp[0] + (tmp[1] << 8); |
paul@181 | 536 | reserved = blkid_le16(ms->ms_reserved); |
paul@181 | 537 | tmp = (unsigned char *)&ms->ms_sectors; |
paul@181 | 538 | sect_count = tmp[0] + (tmp[1] << 8); |
paul@181 | 539 | if (sect_count == 0) |
paul@181 | 540 | sect_count = blkid_le32(ms->ms_total_sect); |
paul@181 | 541 | |
paul@181 | 542 | fat_length = blkid_le16(ms->ms_fat_length); |
paul@181 | 543 | if (fat_length == 0) |
paul@181 | 544 | fat_length = blkid_le32(vs->vs_fat32_length); |
paul@181 | 545 | |
paul@181 | 546 | fat_size = fat_length * ms->ms_fats; |
paul@181 | 547 | dir_size = ((dir_entries * sizeof(struct vfat_dir_entry)) + |
paul@181 | 548 | (sector_size-1)) / sector_size; |
paul@181 | 549 | |
paul@181 | 550 | cluster_count = sect_count - (reserved + fat_size + dir_size); |
paul@181 | 551 | if (ms->ms_cluster_size == 0) |
paul@181 | 552 | return 1; |
paul@181 | 553 | cluster_count /= ms->ms_cluster_size; |
paul@181 | 554 | |
paul@181 | 555 | if (cluster_count > FAT32_MAX) |
paul@181 | 556 | return 1; |
paul@181 | 557 | |
paul@181 | 558 | if (ms->ms_fat_length) { |
paul@181 | 559 | /* the label may be an attribute in the root directory */ |
paul@181 | 560 | root_start = (reserved + fat_size) * sector_size; |
paul@181 | 561 | root_dir_entries = vs->vs_dir_entries[0] + |
paul@181 | 562 | (vs->vs_dir_entries[1] << 8); |
paul@181 | 563 | |
paul@181 | 564 | buf_size = root_dir_entries * sizeof(struct vfat_dir_entry); |
paul@181 | 565 | dir = (struct vfat_dir_entry *) get_buffer(probe, root_start, |
paul@181 | 566 | buf_size); |
paul@181 | 567 | if (dir) |
paul@181 | 568 | vol_label = search_fat_label(dir, root_dir_entries); |
paul@181 | 569 | |
paul@181 | 570 | if (!vol_label || !memcmp(vol_label, no_name, 11)) |
paul@181 | 571 | vol_label = ms->ms_label; |
paul@181 | 572 | vol_serno = ms->ms_serno; |
paul@181 | 573 | |
paul@181 | 574 | blkid_set_tag(probe->dev, "SEC_TYPE", "msdos", |
paul@181 | 575 | sizeof("msdos")); |
paul@181 | 576 | } else { |
paul@181 | 577 | /* Search the FAT32 root dir for the label attribute */ |
paul@181 | 578 | buf_size = vs->vs_cluster_size * sector_size; |
paul@181 | 579 | start_data_sect = reserved + fat_size; |
paul@181 | 580 | |
paul@181 | 581 | next = blkid_le32(vs->vs_root_cluster); |
paul@181 | 582 | while (next && --maxloop) { |
paul@181 | 583 | __u32 next_sect_off; |
paul@181 | 584 | __u64 next_off, fat_entry_off; |
paul@181 | 585 | int count; |
paul@181 | 586 | |
paul@181 | 587 | next_sect_off = (next - 2) * vs->vs_cluster_size; |
paul@181 | 588 | next_off = (__u64) (start_data_sect + next_sect_off) * |
paul@181 | 589 | sector_size; |
paul@181 | 590 | |
paul@181 | 591 | dir = (struct vfat_dir_entry *) |
paul@181 | 592 | get_buffer(probe, next_off, buf_size); |
paul@181 | 593 | if (dir == NULL) |
paul@181 | 594 | break; |
paul@181 | 595 | |
paul@181 | 596 | count = buf_size / sizeof(struct vfat_dir_entry); |
paul@181 | 597 | |
paul@181 | 598 | vol_label = search_fat_label(dir, count); |
paul@181 | 599 | if (vol_label) |
paul@181 | 600 | break; |
paul@181 | 601 | |
paul@181 | 602 | /* get FAT entry */ |
paul@181 | 603 | fat_entry_off = |
paul@181 | 604 | ((unsigned int) reserved * |
paul@181 | 605 | (unsigned int) sector_size) + |
paul@181 | 606 | (next * sizeof(__u32)); |
paul@181 | 607 | buf = get_buffer(probe, fat_entry_off, buf_size); |
paul@181 | 608 | if (buf == NULL) |
paul@181 | 609 | break; |
paul@181 | 610 | |
paul@181 | 611 | /* set next cluster */ |
paul@181 | 612 | next = blkid_le32(*((__u32 *) buf) & 0x0fffffff); |
paul@181 | 613 | } |
paul@181 | 614 | |
paul@181 | 615 | if (!vol_label || !memcmp(vol_label, no_name, 11)) |
paul@181 | 616 | vol_label = vs->vs_label; |
paul@181 | 617 | vol_serno = vs->vs_serno; |
paul@181 | 618 | } |
paul@181 | 619 | |
paul@181 | 620 | if (vol_label && memcmp(vol_label, no_name, 11)) { |
paul@181 | 621 | if ((label_len = figure_label_len(vol_label, 11))) |
paul@181 | 622 | label = vol_label; |
paul@181 | 623 | } |
paul@181 | 624 | |
paul@181 | 625 | /* We can't just print them as %04X, because they are unaligned */ |
paul@181 | 626 | sprintf(serno, "%02X%02X-%02X%02X", vol_serno[3], vol_serno[2], |
paul@181 | 627 | vol_serno[1], vol_serno[0]); |
paul@181 | 628 | |
paul@181 | 629 | blkid_set_tag(probe->dev, "LABEL", (const char *) label, label_len); |
paul@181 | 630 | blkid_set_tag(probe->dev, "UUID", serno, sizeof(serno)-1); |
paul@181 | 631 | |
paul@181 | 632 | return 0; |
paul@181 | 633 | } |
paul@181 | 634 | |
paul@181 | 635 | /* |
paul@181 | 636 | * The FAT filesystem could be without a magic string in superblock |
paul@181 | 637 | * (e.g. old floppies). This heuristic for FAT detection is inspired |
paul@181 | 638 | * by http://vrfy.org/projects/volume_id/ and Linux kernel. |
paul@181 | 639 | * [7-Jul-2005, Karel Zak <kzak@redhat.com>] |
paul@181 | 640 | */ |
paul@181 | 641 | static int probe_fat_nomagic(struct blkid_probe *probe, |
paul@181 | 642 | struct blkid_magic *id __BLKID_ATTR((unused)), |
paul@181 | 643 | unsigned char *buf) |
paul@181 | 644 | { |
paul@181 | 645 | struct msdos_super_block *ms; |
paul@181 | 646 | |
paul@181 | 647 | ms = (struct msdos_super_block *)buf; |
paul@181 | 648 | |
paul@181 | 649 | /* heads check */ |
paul@181 | 650 | if (ms->ms_heads == 0) |
paul@181 | 651 | return 1; |
paul@181 | 652 | |
paul@181 | 653 | /* cluster size check*/ |
paul@181 | 654 | if (ms->ms_cluster_size == 0 || |
paul@181 | 655 | (ms->ms_cluster_size & (ms->ms_cluster_size-1))) |
paul@181 | 656 | return 1; |
paul@181 | 657 | |
paul@181 | 658 | /* media check */ |
paul@181 | 659 | if (ms->ms_media < 0xf8 && ms->ms_media != 0xf0) |
paul@181 | 660 | return 1; |
paul@181 | 661 | |
paul@181 | 662 | /* fat counts(Linux kernel expects at least 1 FAT table) */ |
paul@181 | 663 | if (!ms->ms_fats) |
paul@181 | 664 | return 1; |
paul@181 | 665 | |
paul@181 | 666 | /* |
paul@181 | 667 | * OS/2 and apparently DFSee will place a FAT12/16-like |
paul@181 | 668 | * pseudo-superblock in the first 512 bytes of non-FAT |
paul@181 | 669 | * filesystems --- at least JFS and HPFS, and possibly others. |
paul@181 | 670 | * So we explicitly check for those filesystems at the |
paul@181 | 671 | * FAT12/16 filesystem magic field identifier, and if they are |
paul@181 | 672 | * present, we rule this out as a FAT filesystem, despite the |
paul@181 | 673 | * FAT-like pseudo-header. |
paul@181 | 674 | */ |
paul@181 | 675 | if ((memcmp(ms->ms_magic, "JFS ", 8) == 0) || |
paul@181 | 676 | (memcmp(ms->ms_magic, "HPFS ", 8) == 0)) |
paul@181 | 677 | return 1; |
paul@181 | 678 | |
paul@181 | 679 | return probe_fat(probe, id, buf); |
paul@181 | 680 | } |
paul@181 | 681 | |
paul@181 | 682 | static int probe_ntfs(struct blkid_probe *probe, |
paul@181 | 683 | struct blkid_magic *id __BLKID_ATTR((unused)), |
paul@181 | 684 | unsigned char *buf) |
paul@181 | 685 | { |
paul@181 | 686 | struct ntfs_super_block *ns; |
paul@181 | 687 | struct master_file_table_record *mft; |
paul@181 | 688 | struct file_attribute *attr; |
paul@181 | 689 | char uuid_str[17], label_str[129], *cp; |
paul@181 | 690 | int bytes_per_sector, sectors_per_cluster; |
paul@181 | 691 | int mft_record_size, attr_off, attr_len; |
paul@181 | 692 | unsigned int i, attr_type, val_len; |
paul@181 | 693 | int val_off; |
paul@181 | 694 | __u64 nr_clusters; |
paul@181 | 695 | blkid_loff_t off; |
paul@181 | 696 | unsigned char *buf_mft, *val; |
paul@181 | 697 | |
paul@181 | 698 | ns = (struct ntfs_super_block *) buf; |
paul@181 | 699 | |
paul@181 | 700 | bytes_per_sector = ns->bios_parameter_block[0] + |
paul@181 | 701 | (ns->bios_parameter_block[1] << 8); |
paul@181 | 702 | sectors_per_cluster = ns->bios_parameter_block[2]; |
paul@181 | 703 | |
paul@181 | 704 | if ((bytes_per_sector < 512) || (sectors_per_cluster == 0)) |
paul@181 | 705 | return 1; |
paul@181 | 706 | |
paul@181 | 707 | if (ns->cluster_per_mft_record < 0) |
paul@181 | 708 | mft_record_size = 1 << (0-ns->cluster_per_mft_record); |
paul@181 | 709 | else |
paul@181 | 710 | mft_record_size = ns->cluster_per_mft_record * |
paul@181 | 711 | sectors_per_cluster * bytes_per_sector; |
paul@181 | 712 | nr_clusters = blkid_le64(ns->number_of_sectors) / sectors_per_cluster; |
paul@181 | 713 | |
paul@181 | 714 | if ((blkid_le64(ns->mft_cluster_location) > nr_clusters) || |
paul@181 | 715 | (blkid_le64(ns->mft_mirror_cluster_location) > nr_clusters)) |
paul@181 | 716 | return 1; |
paul@181 | 717 | |
paul@181 | 718 | off = blkid_le64(ns->mft_mirror_cluster_location) * |
paul@181 | 719 | bytes_per_sector * sectors_per_cluster; |
paul@181 | 720 | |
paul@181 | 721 | buf_mft = get_buffer(probe, off, mft_record_size); |
paul@181 | 722 | if (!buf_mft) |
paul@181 | 723 | return 1; |
paul@181 | 724 | |
paul@181 | 725 | if (memcmp(buf_mft, "FILE", 4)) |
paul@181 | 726 | return 1; |
paul@181 | 727 | |
paul@181 | 728 | off = blkid_le64(ns->mft_cluster_location) * bytes_per_sector * |
paul@181 | 729 | sectors_per_cluster; |
paul@181 | 730 | |
paul@181 | 731 | buf_mft = get_buffer(probe, off, mft_record_size); |
paul@181 | 732 | if (!buf_mft) |
paul@181 | 733 | return 1; |
paul@181 | 734 | |
paul@181 | 735 | if (memcmp(buf_mft, "FILE", 4)) |
paul@181 | 736 | return 1; |
paul@181 | 737 | |
paul@181 | 738 | off += MFT_RECORD_VOLUME * mft_record_size; |
paul@181 | 739 | |
paul@181 | 740 | buf_mft = get_buffer(probe, off, mft_record_size); |
paul@181 | 741 | if (!buf_mft) |
paul@181 | 742 | return 1; |
paul@181 | 743 | |
paul@181 | 744 | if (memcmp(buf_mft, "FILE", 4)) |
paul@181 | 745 | return 1; |
paul@181 | 746 | |
paul@181 | 747 | mft = (struct master_file_table_record *) buf_mft; |
paul@181 | 748 | |
paul@181 | 749 | attr_off = blkid_le16(mft->attrs_offset); |
paul@181 | 750 | label_str[0] = 0; |
paul@181 | 751 | |
paul@181 | 752 | while (1) { |
paul@181 | 753 | attr = (struct file_attribute *) (buf_mft + attr_off); |
paul@181 | 754 | attr_len = blkid_le16(attr->len); |
paul@181 | 755 | attr_type = blkid_le32(attr->type); |
paul@181 | 756 | val_off = blkid_le16(attr->value_offset); |
paul@181 | 757 | val_len = blkid_le32(attr->value_len); |
paul@181 | 758 | |
paul@181 | 759 | attr_off += attr_len; |
paul@181 | 760 | |
paul@181 | 761 | if ((attr_off > mft_record_size) || |
paul@181 | 762 | (attr_len == 0)) |
paul@181 | 763 | break; |
paul@181 | 764 | |
paul@181 | 765 | if (attr_type == MFT_RECORD_ATTR_END) |
paul@181 | 766 | break; |
paul@181 | 767 | |
paul@181 | 768 | if (attr_type == MFT_RECORD_ATTR_VOLUME_NAME) { |
paul@181 | 769 | if (val_len > sizeof(label_str)) |
paul@181 | 770 | val_len = sizeof(label_str)-1; |
paul@181 | 771 | |
paul@181 | 772 | for (i=0, cp=label_str; i < val_len; i+=2,cp++) { |
paul@181 | 773 | val = ((__u8 *) attr) + val_off + i; |
paul@181 | 774 | *cp = val[0]; |
paul@181 | 775 | if (val[1]) |
paul@181 | 776 | *cp = '?'; |
paul@181 | 777 | } |
paul@181 | 778 | *cp = 0; |
paul@181 | 779 | } |
paul@181 | 780 | } |
paul@181 | 781 | |
paul@181 | 782 | sprintf(uuid_str, "%016llX", blkid_le64(ns->volume_serial)); |
paul@181 | 783 | blkid_set_tag(probe->dev, "UUID", uuid_str, 0); |
paul@181 | 784 | if (label_str[0]) |
paul@181 | 785 | blkid_set_tag(probe->dev, "LABEL", label_str, 0); |
paul@181 | 786 | return 0; |
paul@181 | 787 | } |
paul@181 | 788 | |
paul@181 | 789 | |
paul@181 | 790 | static int probe_xfs(struct blkid_probe *probe, |
paul@181 | 791 | struct blkid_magic *id __BLKID_ATTR((unused)), |
paul@181 | 792 | unsigned char *buf) |
paul@181 | 793 | { |
paul@181 | 794 | struct xfs_super_block *xs; |
paul@181 | 795 | const char *label = 0; |
paul@181 | 796 | |
paul@181 | 797 | xs = (struct xfs_super_block *)buf; |
paul@181 | 798 | |
paul@181 | 799 | if (strlen(xs->xs_fname)) |
paul@181 | 800 | label = xs->xs_fname; |
paul@181 | 801 | blkid_set_tag(probe->dev, "LABEL", label, sizeof(xs->xs_fname)); |
paul@181 | 802 | set_uuid(probe->dev, xs->xs_uuid, 0); |
paul@181 | 803 | return 0; |
paul@181 | 804 | } |
paul@181 | 805 | |
paul@181 | 806 | static int probe_reiserfs(struct blkid_probe *probe, |
paul@181 | 807 | struct blkid_magic *id, unsigned char *buf) |
paul@181 | 808 | { |
paul@181 | 809 | struct reiserfs_super_block *rs = (struct reiserfs_super_block *) buf; |
paul@181 | 810 | unsigned int blocksize; |
paul@181 | 811 | const char *label = 0; |
paul@181 | 812 | |
paul@181 | 813 | blocksize = blkid_le16(rs->rs_blocksize); |
paul@181 | 814 | |
paul@181 | 815 | /* The blocksize must be at least 1k */ |
paul@181 | 816 | if ((blocksize >> 10) == 0) |
paul@181 | 817 | return -BLKID_ERR_PARAM; |
paul@181 | 818 | |
paul@181 | 819 | /* If the superblock is inside the journal, we have the wrong one */ |
paul@181 | 820 | if (id->bim_kboff/(blocksize>>10) > blkid_le32(rs->rs_journal_block)) |
paul@181 | 821 | return -BLKID_ERR_BIG; |
paul@181 | 822 | |
paul@181 | 823 | /* LABEL/UUID are only valid for later versions of Reiserfs v3.6. */ |
paul@181 | 824 | if (id->bim_magic[6] == '2' || id->bim_magic[6] == '3') { |
paul@181 | 825 | if (strlen(rs->rs_label)) |
paul@181 | 826 | label = rs->rs_label; |
paul@181 | 827 | set_uuid(probe->dev, rs->rs_uuid, 0); |
paul@181 | 828 | } |
paul@181 | 829 | blkid_set_tag(probe->dev, "LABEL", label, sizeof(rs->rs_label)); |
paul@181 | 830 | |
paul@181 | 831 | return 0; |
paul@181 | 832 | } |
paul@181 | 833 | |
paul@181 | 834 | static int probe_reiserfs4(struct blkid_probe *probe, |
paul@181 | 835 | struct blkid_magic *id __BLKID_ATTR((unused)), |
paul@181 | 836 | unsigned char *buf) |
paul@181 | 837 | { |
paul@181 | 838 | struct reiser4_super_block *rs4 = (struct reiser4_super_block *) buf; |
paul@181 | 839 | const unsigned char *label = 0; |
paul@181 | 840 | |
paul@181 | 841 | if (strlen((char *) rs4->rs4_label)) |
paul@181 | 842 | label = rs4->rs4_label; |
paul@181 | 843 | set_uuid(probe->dev, rs4->rs4_uuid, 0); |
paul@181 | 844 | blkid_set_tag(probe->dev, "LABEL", (const char *) label, |
paul@181 | 845 | sizeof(rs4->rs4_label)); |
paul@181 | 846 | |
paul@181 | 847 | return 0; |
paul@181 | 848 | } |
paul@181 | 849 | |
paul@181 | 850 | static int probe_jfs(struct blkid_probe *probe, |
paul@181 | 851 | struct blkid_magic *id __BLKID_ATTR((unused)), |
paul@181 | 852 | unsigned char *buf) |
paul@181 | 853 | { |
paul@181 | 854 | struct jfs_super_block *js; |
paul@181 | 855 | const char *label = 0; |
paul@181 | 856 | |
paul@181 | 857 | js = (struct jfs_super_block *)buf; |
paul@181 | 858 | |
paul@181 | 859 | if (blkid_le32(js->js_bsize) != (1U << blkid_le16(js->js_l2bsize))) |
paul@181 | 860 | return 1; |
paul@181 | 861 | |
paul@181 | 862 | if (blkid_le32(js->js_pbsize) != (1U << blkid_le16(js->js_l2pbsize))) |
paul@181 | 863 | return 1; |
paul@181 | 864 | |
paul@181 | 865 | if ((blkid_le16(js->js_l2bsize) - blkid_le16(js->js_l2pbsize)) != |
paul@181 | 866 | blkid_le16(js->js_l2bfactor)) |
paul@181 | 867 | return 1; |
paul@181 | 868 | |
paul@181 | 869 | if (strlen((char *) js->js_label)) |
paul@181 | 870 | label = (char *) js->js_label; |
paul@181 | 871 | blkid_set_tag(probe->dev, "LABEL", label, sizeof(js->js_label)); |
paul@181 | 872 | set_uuid(probe->dev, js->js_uuid, 0); |
paul@181 | 873 | return 0; |
paul@181 | 874 | } |
paul@181 | 875 | |
paul@181 | 876 | static int probe_zfs(struct blkid_probe *probe __BLKID_ATTR((unused)), |
paul@181 | 877 | struct blkid_magic *id __BLKID_ATTR((unused)), |
paul@181 | 878 | unsigned char *buf __BLKID_ATTR((unused))) |
paul@181 | 879 | { |
paul@181 | 880 | #if 0 |
paul@181 | 881 | char *vdev_label; |
paul@181 | 882 | const char *pool_name = 0; |
paul@181 | 883 | |
paul@181 | 884 | /* read nvpair data for pool name, pool GUID (complex) */ |
paul@181 | 885 | blkid_set_tag(probe->dev, "LABEL", pool_name, sizeof(pool_name)); |
paul@181 | 886 | set_uuid(probe->dev, pool_guid, 0); |
paul@181 | 887 | #endif |
paul@181 | 888 | return 0; |
paul@181 | 889 | } |
paul@181 | 890 | |
paul@181 | 891 | static int probe_luks(struct blkid_probe *probe, |
paul@181 | 892 | struct blkid_magic *id __BLKID_ATTR((unused)), |
paul@181 | 893 | unsigned char *buf) |
paul@181 | 894 | { |
paul@212 | 895 | char uuid[41]; |
paul@181 | 896 | |
paul@181 | 897 | /* 168 is the offset to the 40 character uuid: |
paul@181 | 898 | * http://luks.endorphin.org/LUKS-on-disk-format.pdf */ |
paul@181 | 899 | strncpy(uuid, (char *) buf+168, 40); |
paul@212 | 900 | uuid[40] = 0; |
paul@212 | 901 | blkid_set_tag(probe->dev, "UUID", uuid, 40); |
paul@181 | 902 | return 0; |
paul@181 | 903 | } |
paul@181 | 904 | |
paul@181 | 905 | static int probe_romfs(struct blkid_probe *probe, |
paul@181 | 906 | struct blkid_magic *id __BLKID_ATTR((unused)), |
paul@181 | 907 | unsigned char *buf) |
paul@181 | 908 | { |
paul@181 | 909 | struct romfs_super_block *ros; |
paul@181 | 910 | const char *label = 0; |
paul@181 | 911 | |
paul@181 | 912 | ros = (struct romfs_super_block *)buf; |
paul@181 | 913 | |
paul@181 | 914 | if (strlen((char *) ros->ros_volume)) |
paul@181 | 915 | label = (char *) ros->ros_volume; |
paul@181 | 916 | blkid_set_tag(probe->dev, "LABEL", label, 0); |
paul@181 | 917 | return 0; |
paul@181 | 918 | } |
paul@181 | 919 | |
paul@181 | 920 | static int probe_cramfs(struct blkid_probe *probe, |
paul@181 | 921 | struct blkid_magic *id __BLKID_ATTR((unused)), |
paul@181 | 922 | unsigned char *buf) |
paul@181 | 923 | { |
paul@181 | 924 | struct cramfs_super_block *csb; |
paul@181 | 925 | const char *label = 0; |
paul@181 | 926 | |
paul@181 | 927 | csb = (struct cramfs_super_block *)buf; |
paul@181 | 928 | |
paul@181 | 929 | if (strlen((char *) csb->name)) |
paul@181 | 930 | label = (char *) csb->name; |
paul@181 | 931 | blkid_set_tag(probe->dev, "LABEL", label, 0); |
paul@181 | 932 | return 0; |
paul@181 | 933 | } |
paul@181 | 934 | |
paul@181 | 935 | static int probe_swap0(struct blkid_probe *probe, |
paul@181 | 936 | struct blkid_magic *id __BLKID_ATTR((unused)), |
paul@181 | 937 | unsigned char *buf __BLKID_ATTR((unused))) |
paul@181 | 938 | { |
paul@181 | 939 | blkid_set_tag(probe->dev, "UUID", 0, 0); |
paul@181 | 940 | blkid_set_tag(probe->dev, "LABEL", 0, 0); |
paul@181 | 941 | return 0; |
paul@181 | 942 | } |
paul@181 | 943 | |
paul@181 | 944 | static int probe_swap1(struct blkid_probe *probe, |
paul@181 | 945 | struct blkid_magic *id, |
paul@181 | 946 | unsigned char *buf __BLKID_ATTR((unused))) |
paul@181 | 947 | { |
paul@181 | 948 | struct swap_id_block *sws; |
paul@181 | 949 | |
paul@181 | 950 | probe_swap0(probe, id, buf); |
paul@181 | 951 | /* |
paul@181 | 952 | * Version 1 swap headers are always located at offset of 1024 |
paul@181 | 953 | * bytes, although the swap signature itself is located at the |
paul@181 | 954 | * end of the page (which may vary depending on hardware |
paul@181 | 955 | * pagesize). |
paul@181 | 956 | */ |
paul@181 | 957 | sws = (struct swap_id_block *) get_buffer(probe, 1024, 1024); |
paul@181 | 958 | if (!sws) |
paul@181 | 959 | return 1; |
paul@181 | 960 | |
paul@181 | 961 | /* check for wrong version or zeroed pagecount, for sanity */ |
paul@181 | 962 | if (!memcmp(id->bim_magic, "SWAPSPACE2", id->bim_len) && |
paul@181 | 963 | (sws->sws_version != 1 || sws->sws_lastpage == 0)) |
paul@181 | 964 | return 1; |
paul@181 | 965 | |
paul@181 | 966 | /* arbitrary sanity check.. is there any garbage down there? */ |
paul@181 | 967 | if (sws->sws_pad[32] == 0 && sws->sws_pad[33] == 0) { |
paul@181 | 968 | if (sws->sws_volume[0]) |
paul@181 | 969 | blkid_set_tag(probe->dev, "LABEL", sws->sws_volume, |
paul@181 | 970 | sizeof(sws->sws_volume)); |
paul@181 | 971 | if (sws->sws_uuid[0]) |
paul@181 | 972 | set_uuid(probe->dev, sws->sws_uuid, 0); |
paul@181 | 973 | } |
paul@181 | 974 | return 0; |
paul@181 | 975 | } |
paul@181 | 976 | |
paul@181 | 977 | static int probe_iso9660(struct blkid_probe *probe, |
paul@181 | 978 | struct blkid_magic *id __BLKID_ATTR((unused)), |
paul@181 | 979 | unsigned char *buf) |
paul@181 | 980 | { |
paul@181 | 981 | struct iso_volume_descriptor *iso; |
paul@181 | 982 | const unsigned char *label; |
paul@181 | 983 | |
paul@181 | 984 | iso = (struct iso_volume_descriptor *) buf; |
paul@181 | 985 | label = iso->volume_id; |
paul@181 | 986 | |
paul@181 | 987 | blkid_set_tag(probe->dev, "LABEL", (const char *) label, |
paul@181 | 988 | figure_label_len(label, 32)); |
paul@181 | 989 | return 0; |
paul@181 | 990 | } |
paul@181 | 991 | |
paul@181 | 992 | |
paul@181 | 993 | static const char |
paul@181 | 994 | *udf_magic[] = { "BEA01", "BOOT2", "CD001", "CDW02", "NSR02", |
paul@181 | 995 | "NSR03", "TEA01", 0 }; |
paul@181 | 996 | |
paul@181 | 997 | static int probe_udf(struct blkid_probe *probe, |
paul@181 | 998 | struct blkid_magic *id __BLKID_ATTR((unused)), |
paul@181 | 999 | unsigned char *buf __BLKID_ATTR((unused))) |
paul@181 | 1000 | { |
paul@181 | 1001 | int j, bs; |
paul@181 | 1002 | struct iso_volume_descriptor *isosb; |
paul@181 | 1003 | const char ** m; |
paul@181 | 1004 | |
paul@181 | 1005 | /* determine the block size by scanning in 2K increments |
paul@181 | 1006 | (block sizes larger than 2K will be null padded) */ |
paul@181 | 1007 | for (bs = 1; bs < 16; bs++) { |
paul@181 | 1008 | isosb = (struct iso_volume_descriptor *) |
paul@181 | 1009 | get_buffer(probe, (blkid_loff_t) bs*2048+32768, |
paul@181 | 1010 | sizeof(*isosb)); |
paul@181 | 1011 | if (!isosb) |
paul@181 | 1012 | return 1; |
paul@181 | 1013 | if (isosb->vd_id[0]) |
paul@181 | 1014 | break; |
paul@181 | 1015 | } |
paul@181 | 1016 | |
paul@181 | 1017 | /* Scan up to another 64 blocks looking for additional VSD's */ |
paul@181 | 1018 | for (j = 1; j < 64; j++) { |
paul@181 | 1019 | if (j > 1) { |
paul@181 | 1020 | isosb = (struct iso_volume_descriptor *) |
paul@181 | 1021 | get_buffer(probe, j*bs*2048+32768, |
paul@181 | 1022 | sizeof(*isosb)); |
paul@181 | 1023 | if (!isosb) |
paul@181 | 1024 | return 1; |
paul@181 | 1025 | } |
paul@181 | 1026 | /* If we find NSR0x then call it udf: |
paul@181 | 1027 | NSR01 for UDF 1.00 |
paul@181 | 1028 | NSR02 for UDF 1.50 |
paul@181 | 1029 | NSR03 for UDF 2.00 */ |
paul@181 | 1030 | if (!memcmp(isosb->vd_id, "NSR0", 4)) |
paul@181 | 1031 | return probe_iso9660(probe, id, buf); |
paul@181 | 1032 | for (m = udf_magic; *m; m++) |
paul@181 | 1033 | if (!memcmp(*m, isosb->vd_id, 5)) |
paul@181 | 1034 | break; |
paul@181 | 1035 | if (*m == 0) |
paul@181 | 1036 | return 1; |
paul@181 | 1037 | } |
paul@181 | 1038 | return 1; |
paul@181 | 1039 | } |
paul@181 | 1040 | |
paul@181 | 1041 | static int probe_ocfs(struct blkid_probe *probe, |
paul@181 | 1042 | struct blkid_magic *id __BLKID_ATTR((unused)), |
paul@181 | 1043 | unsigned char *buf) |
paul@181 | 1044 | { |
paul@181 | 1045 | struct ocfs_volume_header ovh; |
paul@181 | 1046 | struct ocfs_volume_label ovl; |
paul@181 | 1047 | __u32 major; |
paul@181 | 1048 | |
paul@181 | 1049 | memcpy(&ovh, buf, sizeof(ovh)); |
paul@181 | 1050 | memcpy(&ovl, buf+512, sizeof(ovl)); |
paul@181 | 1051 | |
paul@181 | 1052 | major = ocfsmajor(ovh); |
paul@181 | 1053 | if (major == 1) |
paul@181 | 1054 | blkid_set_tag(probe->dev,"SEC_TYPE","ocfs1",sizeof("ocfs1")); |
paul@181 | 1055 | else if (major >= 9) |
paul@181 | 1056 | blkid_set_tag(probe->dev,"SEC_TYPE","ntocfs",sizeof("ntocfs")); |
paul@181 | 1057 | |
paul@181 | 1058 | blkid_set_tag(probe->dev, "LABEL", ovl.label, ocfslabellen(ovl)); |
paul@181 | 1059 | blkid_set_tag(probe->dev, "MOUNT", ovh.mount, ocfsmountlen(ovh)); |
paul@181 | 1060 | set_uuid(probe->dev, ovl.vol_id, 0); |
paul@181 | 1061 | return 0; |
paul@181 | 1062 | } |
paul@181 | 1063 | |
paul@181 | 1064 | static int probe_ocfs2(struct blkid_probe *probe, |
paul@181 | 1065 | struct blkid_magic *id __BLKID_ATTR((unused)), |
paul@181 | 1066 | unsigned char *buf) |
paul@181 | 1067 | { |
paul@181 | 1068 | struct ocfs2_super_block *osb; |
paul@181 | 1069 | |
paul@181 | 1070 | osb = (struct ocfs2_super_block *)buf; |
paul@181 | 1071 | |
paul@181 | 1072 | blkid_set_tag(probe->dev, "LABEL", osb->s_label, sizeof(osb->s_label)); |
paul@181 | 1073 | set_uuid(probe->dev, osb->s_uuid, 0); |
paul@181 | 1074 | return 0; |
paul@181 | 1075 | } |
paul@181 | 1076 | |
paul@181 | 1077 | static int probe_oracleasm(struct blkid_probe *probe, |
paul@181 | 1078 | struct blkid_magic *id __BLKID_ATTR((unused)), |
paul@181 | 1079 | unsigned char *buf) |
paul@181 | 1080 | { |
paul@181 | 1081 | struct oracle_asm_disk_label *dl; |
paul@181 | 1082 | |
paul@181 | 1083 | dl = (struct oracle_asm_disk_label *)buf; |
paul@181 | 1084 | |
paul@181 | 1085 | blkid_set_tag(probe->dev, "LABEL", dl->dl_id, sizeof(dl->dl_id)); |
paul@181 | 1086 | return 0; |
paul@181 | 1087 | } |
paul@181 | 1088 | |
paul@181 | 1089 | static int probe_gfs(struct blkid_probe *probe, |
paul@181 | 1090 | struct blkid_magic *id __BLKID_ATTR((unused)), |
paul@181 | 1091 | unsigned char *buf) |
paul@181 | 1092 | { |
paul@181 | 1093 | struct gfs2_sb *sbd; |
paul@181 | 1094 | const char *label = 0; |
paul@181 | 1095 | |
paul@181 | 1096 | sbd = (struct gfs2_sb *)buf; |
paul@181 | 1097 | |
paul@181 | 1098 | if (blkid_be32(sbd->sb_fs_format) == GFS_FORMAT_FS && |
paul@181 | 1099 | blkid_be32(sbd->sb_multihost_format) == GFS_FORMAT_MULTI) |
paul@181 | 1100 | { |
paul@181 | 1101 | blkid_set_tag(probe->dev, "UUID", 0, 0); |
paul@181 | 1102 | |
paul@181 | 1103 | if (strlen(sbd->sb_locktable)) |
paul@181 | 1104 | label = sbd->sb_locktable; |
paul@181 | 1105 | blkid_set_tag(probe->dev, "LABEL", label, sizeof(sbd->sb_locktable)); |
paul@181 | 1106 | return 0; |
paul@181 | 1107 | } |
paul@181 | 1108 | return 1; |
paul@181 | 1109 | } |
paul@181 | 1110 | |
paul@181 | 1111 | static int probe_gfs2(struct blkid_probe *probe, |
paul@181 | 1112 | struct blkid_magic *id __BLKID_ATTR((unused)), |
paul@181 | 1113 | unsigned char *buf) |
paul@181 | 1114 | { |
paul@181 | 1115 | struct gfs2_sb *sbd; |
paul@181 | 1116 | const char *label = 0; |
paul@181 | 1117 | |
paul@181 | 1118 | sbd = (struct gfs2_sb *)buf; |
paul@181 | 1119 | |
paul@181 | 1120 | if (blkid_be32(sbd->sb_fs_format) == GFS2_FORMAT_FS && |
paul@181 | 1121 | blkid_be32(sbd->sb_multihost_format) == GFS2_FORMAT_MULTI) |
paul@181 | 1122 | { |
paul@181 | 1123 | blkid_set_tag(probe->dev, "UUID", 0, 0); |
paul@181 | 1124 | |
paul@181 | 1125 | if (strlen(sbd->sb_locktable)) |
paul@181 | 1126 | label = sbd->sb_locktable; |
paul@181 | 1127 | blkid_set_tag(probe->dev, "LABEL", label, sizeof(sbd->sb_locktable)); |
paul@181 | 1128 | return 0; |
paul@181 | 1129 | } |
paul@181 | 1130 | return 1; |
paul@181 | 1131 | } |
paul@181 | 1132 | |
paul@181 | 1133 | static void unicode_16be_to_utf8(unsigned char *str, int out_len, |
paul@181 | 1134 | const unsigned char *buf, int in_len) |
paul@181 | 1135 | { |
paul@181 | 1136 | int i, j; |
paul@181 | 1137 | unsigned int c; |
paul@181 | 1138 | |
paul@181 | 1139 | for (i = j = 0; i + 2 <= in_len; i += 2) { |
paul@181 | 1140 | c = (buf[i] << 8) | buf[i+1]; |
paul@181 | 1141 | if (c == 0) { |
paul@181 | 1142 | str[j] = '\0'; |
paul@181 | 1143 | break; |
paul@181 | 1144 | } else if (c < 0x80) { |
paul@181 | 1145 | if (j+1 >= out_len) |
paul@181 | 1146 | break; |
paul@181 | 1147 | str[j++] = (unsigned char) c; |
paul@181 | 1148 | } else if (c < 0x800) { |
paul@181 | 1149 | if (j+2 >= out_len) |
paul@181 | 1150 | break; |
paul@181 | 1151 | str[j++] = (unsigned char) (0xc0 | (c >> 6)); |
paul@181 | 1152 | str[j++] = (unsigned char) (0x80 | (c & 0x3f)); |
paul@181 | 1153 | } else { |
paul@181 | 1154 | if (j+3 >= out_len) |
paul@181 | 1155 | break; |
paul@181 | 1156 | str[j++] = (unsigned char) (0xe0 | (c >> 12)); |
paul@181 | 1157 | str[j++] = (unsigned char) (0x80 | ((c >> 6) & 0x3f)); |
paul@181 | 1158 | str[j++] = (unsigned char) (0x80 | (c & 0x3f)); |
paul@181 | 1159 | } |
paul@181 | 1160 | } |
paul@181 | 1161 | str[j] = '\0'; |
paul@181 | 1162 | } |
paul@181 | 1163 | |
paul@181 | 1164 | static void unicode_16le_to_utf8(unsigned char *str, int out_len, |
paul@181 | 1165 | const unsigned char *buf, int in_len) |
paul@181 | 1166 | { |
paul@181 | 1167 | int i, j; |
paul@181 | 1168 | unsigned int c; |
paul@181 | 1169 | |
paul@181 | 1170 | for (i = j = 0; i + 2 <= in_len; i += 2) { |
paul@181 | 1171 | c = (buf[i+1] << 8) | buf[i]; |
paul@181 | 1172 | if (c == 0) { |
paul@181 | 1173 | str[j] = '\0'; |
paul@181 | 1174 | break; |
paul@181 | 1175 | } else if (c < 0x80) { |
paul@181 | 1176 | if (j+1 >= out_len) |
paul@181 | 1177 | break; |
paul@181 | 1178 | str[j++] = (unsigned char) c; |
paul@181 | 1179 | } else if (c < 0x800) { |
paul@181 | 1180 | if (j+2 >= out_len) |
paul@181 | 1181 | break; |
paul@181 | 1182 | str[j++] = (unsigned char) (0xc0 | (c >> 6)); |
paul@181 | 1183 | str[j++] = (unsigned char) (0x80 | (c & 0x3f)); |
paul@181 | 1184 | } else { |
paul@181 | 1185 | if (j+3 >= out_len) |
paul@181 | 1186 | break; |
paul@181 | 1187 | str[j++] = (unsigned char) (0xe0 | (c >> 12)); |
paul@181 | 1188 | str[j++] = (unsigned char) (0x80 | ((c >> 6) & 0x3f)); |
paul@181 | 1189 | str[j++] = (unsigned char) (0x80 | (c & 0x3f)); |
paul@181 | 1190 | } |
paul@181 | 1191 | } |
paul@181 | 1192 | str[j] = '\0'; |
paul@181 | 1193 | } |
paul@181 | 1194 | |
paul@181 | 1195 | static int probe_hfs(struct blkid_probe *probe __BLKID_ATTR((unused)), |
paul@181 | 1196 | struct blkid_magic *id __BLKID_ATTR((unused)), |
paul@181 | 1197 | unsigned char *buf) |
paul@181 | 1198 | { |
paul@181 | 1199 | struct hfs_mdb *hfs = (struct hfs_mdb *)buf; |
paul@181 | 1200 | unsigned long long *uuid_ptr; |
paul@181 | 1201 | char uuid_str[17]; |
paul@181 | 1202 | __u64 uuid; |
paul@181 | 1203 | |
paul@181 | 1204 | if ((memcmp(hfs->embed_sig, "H+", 2) == 0) || |
paul@181 | 1205 | (memcmp(hfs->embed_sig, "HX", 2) == 0)) |
paul@181 | 1206 | return 1; /* Not hfs, but an embedded HFS+ */ |
paul@181 | 1207 | |
paul@181 | 1208 | uuid_ptr = (unsigned long long *)hfs->finder_info.id; |
paul@181 | 1209 | uuid = blkid_le64(*uuid_ptr); |
paul@181 | 1210 | if (uuid) { |
paul@181 | 1211 | sprintf(uuid_str, "%016llX", uuid); |
paul@181 | 1212 | blkid_set_tag(probe->dev, "UUID", uuid_str, 0); |
paul@181 | 1213 | } |
paul@181 | 1214 | blkid_set_tag(probe->dev, "LABEL", (char *)hfs->label, hfs->label_len); |
paul@181 | 1215 | return 0; |
paul@181 | 1216 | } |
paul@181 | 1217 | |
paul@181 | 1218 | |
paul@181 | 1219 | #define HFSPLUS_SECTOR_SIZE 512 |
paul@181 | 1220 | |
paul@181 | 1221 | static int probe_hfsplus(struct blkid_probe *probe, |
paul@181 | 1222 | struct blkid_magic *id, |
paul@181 | 1223 | unsigned char *buf) |
paul@181 | 1224 | { |
paul@181 | 1225 | struct hfsplus_extent extents[HFSPLUS_EXTENT_COUNT]; |
paul@181 | 1226 | struct hfsplus_bnode_descriptor *descr; |
paul@181 | 1227 | struct hfsplus_bheader_record *bnode; |
paul@181 | 1228 | struct hfsplus_catalog_key *key; |
paul@181 | 1229 | struct hfsplus_vol_header *hfsplus; |
paul@181 | 1230 | struct hfs_mdb *sbd = (struct hfs_mdb *) buf; |
paul@181 | 1231 | unsigned int alloc_block_size; |
paul@181 | 1232 | unsigned int alloc_first_block; |
paul@181 | 1233 | unsigned int embed_first_block; |
paul@181 | 1234 | unsigned int off = 0; |
paul@181 | 1235 | unsigned int blocksize; |
paul@181 | 1236 | unsigned int cat_block; |
paul@181 | 1237 | unsigned int ext_block_start; |
paul@181 | 1238 | unsigned int ext_block_count; |
paul@181 | 1239 | unsigned int record_count; |
paul@181 | 1240 | unsigned int leaf_node_head; |
paul@181 | 1241 | unsigned int leaf_node_count; |
paul@181 | 1242 | unsigned int leaf_node_size; |
paul@181 | 1243 | unsigned int leaf_block; |
paul@181 | 1244 | unsigned int label_len; |
paul@181 | 1245 | unsigned long long *uuid_ptr; |
paul@181 | 1246 | __u64 leaf_off, uuid; |
paul@181 | 1247 | char uuid_str[17], label[512]; |
paul@181 | 1248 | int ext; |
paul@181 | 1249 | |
paul@181 | 1250 | /* Check for a HFS+ volume embedded in a HFS volume */ |
paul@181 | 1251 | if (memcmp(sbd->signature, "BD", 2) == 0) { |
paul@181 | 1252 | if ((memcmp(sbd->embed_sig, "H+", 2) != 0) && |
paul@181 | 1253 | (memcmp(sbd->embed_sig, "HX", 2) != 0)) |
paul@181 | 1254 | /* This must be an HFS volume, so fail */ |
paul@181 | 1255 | return 1; |
paul@181 | 1256 | |
paul@181 | 1257 | alloc_block_size = blkid_be32(sbd->al_blk_size); |
paul@181 | 1258 | alloc_first_block = blkid_be16(sbd->al_bl_st); |
paul@181 | 1259 | embed_first_block = blkid_be16(sbd->embed_startblock); |
paul@181 | 1260 | off = (alloc_first_block * 512) + |
paul@181 | 1261 | (embed_first_block * alloc_block_size); |
paul@181 | 1262 | buf = get_buffer(probe, off + (id->bim_kboff * 1024), |
paul@181 | 1263 | sizeof(*sbd)); |
paul@181 | 1264 | if (!buf) |
paul@181 | 1265 | return 1; |
paul@181 | 1266 | |
paul@181 | 1267 | hfsplus = (struct hfsplus_vol_header *) buf; |
paul@181 | 1268 | } |
paul@181 | 1269 | |
paul@181 | 1270 | hfsplus = (struct hfsplus_vol_header *) buf; |
paul@181 | 1271 | |
paul@181 | 1272 | if ((memcmp(hfsplus->signature, "H+", 2) != 0) && |
paul@181 | 1273 | (memcmp(hfsplus->signature, "HX", 2) != 0)) |
paul@181 | 1274 | return 1; |
paul@181 | 1275 | |
paul@181 | 1276 | uuid_ptr = (unsigned long long *)hfsplus->finder_info.id; |
paul@181 | 1277 | uuid = blkid_le64(*uuid_ptr); |
paul@181 | 1278 | if (uuid) { |
paul@181 | 1279 | sprintf(uuid_str, "%016llX", uuid); |
paul@181 | 1280 | blkid_set_tag(probe->dev, "UUID", uuid_str, 0); |
paul@181 | 1281 | } |
paul@181 | 1282 | |
paul@181 | 1283 | blocksize = blkid_be32(hfsplus->blocksize); |
paul@181 | 1284 | if (blocksize < HFSPLUS_SECTOR_SIZE) |
paul@181 | 1285 | return 1; |
paul@181 | 1286 | |
paul@181 | 1287 | memcpy(extents, hfsplus->cat_file.extents, sizeof(extents)); |
paul@181 | 1288 | cat_block = blkid_be32(extents[0].start_block); |
paul@181 | 1289 | |
paul@181 | 1290 | buf = get_buffer(probe, off + ((__u64) cat_block * blocksize), 0x2000); |
paul@181 | 1291 | if (!buf) |
paul@181 | 1292 | return 0; |
paul@181 | 1293 | |
paul@181 | 1294 | bnode = (struct hfsplus_bheader_record *) |
paul@181 | 1295 | &buf[sizeof(struct hfsplus_bnode_descriptor)]; |
paul@181 | 1296 | |
paul@181 | 1297 | leaf_node_head = blkid_be32(bnode->leaf_head); |
paul@181 | 1298 | leaf_node_size = blkid_be16(bnode->node_size); |
paul@181 | 1299 | leaf_node_count = blkid_be32(bnode->leaf_count); |
paul@181 | 1300 | if (leaf_node_count == 0) |
paul@181 | 1301 | return 0; |
paul@181 | 1302 | |
paul@181 | 1303 | leaf_block = (leaf_node_head * leaf_node_size) / blocksize; |
paul@181 | 1304 | |
paul@181 | 1305 | /* get physical location */ |
paul@181 | 1306 | for (ext = 0; ext < HFSPLUS_EXTENT_COUNT; ext++) { |
paul@181 | 1307 | ext_block_start = blkid_be32(extents[ext].start_block); |
paul@181 | 1308 | ext_block_count = blkid_be32(extents[ext].block_count); |
paul@181 | 1309 | if (ext_block_count == 0) |
paul@181 | 1310 | return 0; |
paul@181 | 1311 | |
paul@181 | 1312 | /* this is our extent */ |
paul@181 | 1313 | if (leaf_block < ext_block_count) |
paul@181 | 1314 | break; |
paul@181 | 1315 | |
paul@181 | 1316 | leaf_block -= ext_block_count; |
paul@181 | 1317 | } |
paul@181 | 1318 | if (ext == HFSPLUS_EXTENT_COUNT) |
paul@181 | 1319 | return 0; |
paul@181 | 1320 | |
paul@181 | 1321 | leaf_off = (__u64) (ext_block_start + leaf_block) * blocksize; |
paul@181 | 1322 | |
paul@181 | 1323 | buf = get_buffer(probe, off + leaf_off, leaf_node_size); |
paul@181 | 1324 | if (!buf) |
paul@181 | 1325 | return 0; |
paul@181 | 1326 | |
paul@181 | 1327 | descr = (struct hfsplus_bnode_descriptor *) buf; |
paul@181 | 1328 | record_count = blkid_be16(descr->num_recs); |
paul@181 | 1329 | if (record_count == 0) |
paul@181 | 1330 | return 0; |
paul@181 | 1331 | |
paul@181 | 1332 | if (descr->type != HFS_NODE_LEAF) |
paul@181 | 1333 | return 0; |
paul@181 | 1334 | |
paul@181 | 1335 | key = (struct hfsplus_catalog_key *) |
paul@181 | 1336 | &buf[sizeof(struct hfsplus_bnode_descriptor)]; |
paul@181 | 1337 | |
paul@181 | 1338 | if (blkid_be32(key->parent_id) != HFSPLUS_POR_CNID) |
paul@181 | 1339 | return 0; |
paul@181 | 1340 | |
paul@181 | 1341 | label_len = blkid_be16(key->unicode_len) * 2; |
paul@181 | 1342 | unicode_16be_to_utf8((unsigned char *)label, sizeof(label), |
paul@181 | 1343 | key->unicode, label_len); |
paul@181 | 1344 | blkid_set_tag(probe->dev, "LABEL", label, 0); |
paul@181 | 1345 | return 0; |
paul@181 | 1346 | } |
paul@181 | 1347 | |
paul@181 | 1348 | #define LVM2_LABEL_SIZE 512 |
paul@181 | 1349 | static unsigned int lvm2_calc_crc(const void *buf, unsigned int size) |
paul@181 | 1350 | { |
paul@181 | 1351 | static const unsigned int crctab[] = { |
paul@181 | 1352 | 0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac, |
paul@181 | 1353 | 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c, |
paul@181 | 1354 | 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, |
paul@181 | 1355 | 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c |
paul@181 | 1356 | }; |
paul@181 | 1357 | unsigned int i, crc = 0xf597a6cf; |
paul@181 | 1358 | const __u8 *data = (const __u8 *) buf; |
paul@181 | 1359 | |
paul@181 | 1360 | for (i = 0; i < size; i++) { |
paul@181 | 1361 | crc ^= *data++; |
paul@181 | 1362 | crc = (crc >> 4) ^ crctab[crc & 0xf]; |
paul@181 | 1363 | crc = (crc >> 4) ^ crctab[crc & 0xf]; |
paul@181 | 1364 | } |
paul@181 | 1365 | return crc; |
paul@181 | 1366 | } |
paul@181 | 1367 | |
paul@181 | 1368 | static int probe_lvm2(struct blkid_probe *probe, |
paul@181 | 1369 | struct blkid_magic *id, |
paul@181 | 1370 | unsigned char *buf) |
paul@181 | 1371 | { |
paul@181 | 1372 | int sector = (id->bim_kboff) << 1; |
paul@181 | 1373 | struct lvm2_pv_label_header *label= (struct lvm2_pv_label_header *)buf; |
paul@181 | 1374 | char *p, *q, uuid[40]; |
paul@181 | 1375 | unsigned int i, b; |
paul@181 | 1376 | |
paul@181 | 1377 | /* buf is at 0k or 1k offset; find label inside */ |
paul@181 | 1378 | if (memcmp(buf, "LABELONE", 8) == 0) { |
paul@181 | 1379 | label = (struct lvm2_pv_label_header *)buf; |
paul@181 | 1380 | } else if (memcmp(buf + 512, "LABELONE", 8) == 0) { |
paul@181 | 1381 | label = (struct lvm2_pv_label_header *)(buf + 512); |
paul@181 | 1382 | sector++; |
paul@181 | 1383 | } else { |
paul@181 | 1384 | return 1; |
paul@181 | 1385 | } |
paul@181 | 1386 | |
paul@181 | 1387 | if (blkid_le64(label->sector_xl) != (unsigned) sector) { |
paul@181 | 1388 | DBG(DEBUG_PROBE, |
paul@181 | 1389 | printf("LVM2: label for sector %llu found at sector %d\n", |
paul@181 | 1390 | blkid_le64(label->sector_xl), sector)); |
paul@181 | 1391 | return 1; |
paul@181 | 1392 | } |
paul@181 | 1393 | |
paul@181 | 1394 | if (lvm2_calc_crc(&label->offset_xl, LVM2_LABEL_SIZE - |
paul@181 | 1395 | ((char *)&label->offset_xl - (char *)label)) != |
paul@181 | 1396 | blkid_le32(label->crc_xl)) { |
paul@181 | 1397 | DBG(DEBUG_PROBE, |
paul@181 | 1398 | printf("LVM2: label checksum incorrect at sector %d\n", |
paul@181 | 1399 | sector)); |
paul@181 | 1400 | return 1; |
paul@181 | 1401 | } |
paul@181 | 1402 | |
paul@181 | 1403 | for (i=0, b=1, p=uuid, q= (char *) label->pv_uuid; i < LVM2_ID_LEN; |
paul@181 | 1404 | i++, b <<= 1) { |
paul@181 | 1405 | if (b & 0x4444440) |
paul@181 | 1406 | *p++ = '-'; |
paul@181 | 1407 | *p++ = *q++; |
paul@181 | 1408 | } |
paul@181 | 1409 | |
paul@181 | 1410 | blkid_set_tag(probe->dev, "UUID", uuid, LVM2_ID_LEN+6); |
paul@181 | 1411 | |
paul@181 | 1412 | return 0; |
paul@181 | 1413 | } |
paul@181 | 1414 | |
paul@181 | 1415 | static int probe_btrfs(struct blkid_probe *probe, |
paul@181 | 1416 | struct blkid_magic *id __BLKID_ATTR((unused)), |
paul@181 | 1417 | unsigned char *buf) |
paul@181 | 1418 | { |
paul@181 | 1419 | struct btrfs_super_block *bs; |
paul@181 | 1420 | const char *label = 0; |
paul@181 | 1421 | |
paul@181 | 1422 | bs = (struct btrfs_super_block *)buf; |
paul@181 | 1423 | |
paul@181 | 1424 | if (strlen(bs->label)) |
paul@181 | 1425 | label = bs->label; |
paul@181 | 1426 | blkid_set_tag(probe->dev, "LABEL", label, sizeof(bs->label)); |
paul@181 | 1427 | set_uuid(probe->dev, bs->fsid, 0); |
paul@181 | 1428 | return 0; |
paul@181 | 1429 | } |
paul@181 | 1430 | |
paul@181 | 1431 | static int probe_f2fs(struct blkid_probe *probe, |
paul@181 | 1432 | struct blkid_magic *id __BLKID_ATTR((unused)), |
paul@181 | 1433 | unsigned char *buf) |
paul@181 | 1434 | { |
paul@181 | 1435 | struct f2fs_super_block *bs; |
paul@181 | 1436 | |
paul@181 | 1437 | bs = (struct f2fs_super_block *)buf; |
paul@181 | 1438 | set_uuid(probe->dev, bs->uuid, 0); |
paul@181 | 1439 | return 0; |
paul@181 | 1440 | } |
paul@181 | 1441 | |
paul@181 | 1442 | static uint64_t exfat_block_to_offset(const struct exfat_super_block *sb, |
paul@181 | 1443 | uint64_t block) |
paul@181 | 1444 | { |
paul@181 | 1445 | return block << sb->block_bits; |
paul@181 | 1446 | } |
paul@181 | 1447 | |
paul@181 | 1448 | static uint64_t exfat_cluster_to_block(const struct exfat_super_block *sb, |
paul@181 | 1449 | uint32_t cluster) |
paul@181 | 1450 | { |
paul@181 | 1451 | return sb->cluster_block_start + |
paul@181 | 1452 | ((uint64_t)(cluster - EXFAT_FIRST_DATA_CLUSTER) << sb->bpc_bits); |
paul@181 | 1453 | } |
paul@181 | 1454 | |
paul@181 | 1455 | static uint64_t exfat_cluster_to_offset(const struct exfat_super_block *sb, |
paul@181 | 1456 | uint32_t cluster) |
paul@181 | 1457 | { |
paul@181 | 1458 | return exfat_block_to_offset(sb, exfat_cluster_to_block(sb, cluster)); |
paul@181 | 1459 | } |
paul@181 | 1460 | |
paul@181 | 1461 | static uint32_t exfat_next_cluster(struct blkid_probe *probe, |
paul@181 | 1462 | const struct exfat_super_block *sb, |
paul@181 | 1463 | uint32_t cluster) |
paul@181 | 1464 | { |
paul@181 | 1465 | uint32_t *next; |
paul@181 | 1466 | uint64_t offset; |
paul@181 | 1467 | |
paul@181 | 1468 | offset = exfat_block_to_offset(sb, sb->fat_block_start) |
paul@181 | 1469 | + (uint64_t) cluster * sizeof (cluster); |
paul@181 | 1470 | next = (uint32_t *)get_buffer(probe, offset, sizeof (uint32_t)); |
paul@181 | 1471 | |
paul@181 | 1472 | return next ? *next : 0; |
paul@181 | 1473 | } |
paul@181 | 1474 | |
paul@181 | 1475 | static struct exfat_entry_label *find_exfat_entry_label( |
paul@181 | 1476 | struct blkid_probe *probe, const struct exfat_super_block *sb) |
paul@181 | 1477 | { |
paul@181 | 1478 | uint32_t cluster = sb->rootdir_cluster; |
paul@181 | 1479 | uint64_t offset = exfat_cluster_to_offset(sb, cluster); |
paul@181 | 1480 | uint8_t *entry; |
paul@181 | 1481 | const size_t max_iter = 10000; |
paul@181 | 1482 | size_t i = 0; |
paul@181 | 1483 | |
paul@181 | 1484 | for (; i < max_iter; ++i) { |
paul@181 | 1485 | entry = (uint8_t *)get_buffer(probe, offset, EXFAT_ENTRY_SIZE); |
paul@181 | 1486 | if (!entry) |
paul@181 | 1487 | return NULL; |
paul@181 | 1488 | if (entry[0] == EXFAT_ENTRY_EOD) |
paul@181 | 1489 | return NULL; |
paul@181 | 1490 | if (entry[0] == EXFAT_ENTRY_LABEL) |
paul@181 | 1491 | return (struct exfat_entry_label*) entry; |
paul@181 | 1492 | |
paul@181 | 1493 | offset += EXFAT_ENTRY_SIZE; |
paul@181 | 1494 | if (offset % CLUSTER_SIZE(sb) == 0) { |
paul@181 | 1495 | cluster = exfat_next_cluster(probe, sb, cluster); |
paul@181 | 1496 | if (cluster < EXFAT_FIRST_DATA_CLUSTER) |
paul@181 | 1497 | return NULL; |
paul@181 | 1498 | if (cluster > EXFAT_LAST_DATA_CLUSTER) |
paul@181 | 1499 | return NULL; |
paul@181 | 1500 | offset = exfat_cluster_to_offset(sb, cluster); |
paul@181 | 1501 | } |
paul@181 | 1502 | } |
paul@181 | 1503 | |
paul@181 | 1504 | return NULL; |
paul@181 | 1505 | } |
paul@181 | 1506 | |
paul@212 | 1507 | static int probe_exfat(struct blkid_probe *probe, |
paul@212 | 1508 | struct blkid_magic *id __BLKID_ATTR((unused)), |
paul@181 | 1509 | unsigned char *buf) |
paul@181 | 1510 | { |
paul@181 | 1511 | struct exfat_super_block *sb; |
paul@181 | 1512 | struct exfat_entry_label *label; |
paul@212 | 1513 | char uuid[40]; |
paul@181 | 1514 | |
paul@181 | 1515 | sb = (struct exfat_super_block *)buf; |
paul@212 | 1516 | if (!sb || CLUSTER_SIZE(sb) == 0) { |
paul@181 | 1517 | DBG(DEBUG_PROBE, printf("bad exfat superblock.\n")); |
paul@181 | 1518 | return errno ? - errno : 1; |
paul@181 | 1519 | } |
paul@181 | 1520 | |
paul@181 | 1521 | label = find_exfat_entry_label(probe, sb); |
paul@181 | 1522 | if (label) { |
paul@212 | 1523 | unsigned char utf8_label[128]; |
paul@181 | 1524 | unicode_16le_to_utf8(utf8_label, sizeof(utf8_label), label->name, label->length * 2); |
paul@212 | 1525 | blkid_set_tag(probe->dev, "LABEL", (char *) utf8_label, 0); |
paul@181 | 1526 | } else { |
paul@181 | 1527 | blkid_set_tag(probe->dev, "LABEL", "disk", 4); |
paul@181 | 1528 | } |
paul@181 | 1529 | |
paul@181 | 1530 | memset(uuid, 0, sizeof (uuid)); |
paul@181 | 1531 | snprintf(uuid, sizeof (uuid), "%02hhX%02hhX-%02hhX%02hhX", |
paul@181 | 1532 | sb->volume_serial[3], sb->volume_serial[2], |
paul@181 | 1533 | sb->volume_serial[1], sb->volume_serial[0]); |
paul@181 | 1534 | blkid_set_tag(probe->dev, "UUID", uuid, strlen(uuid)); |
paul@181 | 1535 | |
paul@181 | 1536 | return 0; |
paul@181 | 1537 | } |
paul@181 | 1538 | |
paul@181 | 1539 | /* |
paul@181 | 1540 | * Various filesystem magics that we can check for. Note that kboff and |
paul@181 | 1541 | * sboff are in kilobytes and bytes respectively. All magics are in |
paul@181 | 1542 | * byte strings so we don't worry about endian issues. |
paul@181 | 1543 | */ |
paul@181 | 1544 | static struct blkid_magic type_array[] = { |
paul@181 | 1545 | /* type kboff sboff len magic probe */ |
paul@181 | 1546 | { "oracleasm", 0, 32, 8, "ORCLDISK", probe_oracleasm }, |
paul@181 | 1547 | { "ntfs", 0, 3, 8, "NTFS ", probe_ntfs }, |
paul@181 | 1548 | { "jbd", 1, 0x38, 2, "\123\357", probe_jbd }, |
paul@181 | 1549 | { "ext4dev", 1, 0x38, 2, "\123\357", probe_ext4dev }, |
paul@181 | 1550 | { "ext4", 1, 0x38, 2, "\123\357", probe_ext4 }, |
paul@181 | 1551 | { "ext3", 1, 0x38, 2, "\123\357", probe_ext3 }, |
paul@181 | 1552 | { "ext2", 1, 0x38, 2, "\123\357", probe_ext2 }, |
paul@181 | 1553 | { "reiserfs", 8, 0x34, 8, "ReIsErFs", probe_reiserfs }, |
paul@181 | 1554 | { "reiserfs", 64, 0x34, 9, "ReIsEr2Fs", probe_reiserfs }, |
paul@181 | 1555 | { "reiserfs", 64, 0x34, 9, "ReIsEr3Fs", probe_reiserfs }, |
paul@181 | 1556 | { "reiserfs", 64, 0x34, 8, "ReIsErFs", probe_reiserfs }, |
paul@181 | 1557 | { "reiserfs", 8, 20, 8, "ReIsErFs", probe_reiserfs }, |
paul@181 | 1558 | { "reiser4", 64, 0, 7, "ReIsEr4", probe_reiserfs4 }, |
paul@181 | 1559 | { "gfs2", 64, 0, 4, "\x01\x16\x19\x70", probe_gfs2 }, |
paul@181 | 1560 | { "gfs", 64, 0, 4, "\x01\x16\x19\x70", probe_gfs }, |
paul@181 | 1561 | { "vfat", 0, 0x52, 5, "MSWIN", probe_fat }, |
paul@181 | 1562 | { "vfat", 0, 0x52, 8, "FAT32 ", probe_fat }, |
paul@181 | 1563 | { "vfat", 0, 0x36, 5, "MSDOS", probe_fat }, |
paul@181 | 1564 | { "vfat", 0, 0x36, 8, "FAT16 ", probe_fat }, |
paul@181 | 1565 | { "vfat", 0, 0x36, 8, "FAT12 ", probe_fat }, |
paul@181 | 1566 | { "vfat", 0, 0, 1, "\353", probe_fat_nomagic }, |
paul@181 | 1567 | { "vfat", 0, 0, 1, "\351", probe_fat_nomagic }, |
paul@181 | 1568 | { "vfat", 0, 0x1fe, 2, "\125\252", probe_fat_nomagic }, |
paul@181 | 1569 | { "minix", 1, 0x10, 2, "\177\023", 0 }, |
paul@181 | 1570 | { "minix", 1, 0x10, 2, "\217\023", 0 }, |
paul@181 | 1571 | { "minix", 1, 0x10, 2, "\150\044", 0 }, |
paul@181 | 1572 | { "minix", 1, 0x10, 2, "\170\044", 0 }, |
paul@181 | 1573 | { "vxfs", 1, 0, 4, "\365\374\001\245", 0 }, |
paul@181 | 1574 | { "xfs", 0, 0, 4, "XFSB", probe_xfs }, |
paul@181 | 1575 | { "romfs", 0, 0, 8, "-rom1fs-", probe_romfs }, |
paul@181 | 1576 | { "bfs", 0, 0, 4, "\316\372\173\033", 0 }, |
paul@181 | 1577 | { "cramfs", 0, 0, 4, "E=\315\050", probe_cramfs }, |
paul@181 | 1578 | { "qnx4", 0, 4, 6, "QNX4FS", 0 }, |
paul@181 | 1579 | { "udf", 32, 1, 5, "BEA01", probe_udf }, |
paul@181 | 1580 | { "udf", 32, 1, 5, "BOOT2", probe_udf }, |
paul@181 | 1581 | { "udf", 32, 1, 5, "CD001", probe_udf }, |
paul@181 | 1582 | { "udf", 32, 1, 5, "CDW02", probe_udf }, |
paul@181 | 1583 | { "udf", 32, 1, 5, "NSR02", probe_udf }, |
paul@181 | 1584 | { "udf", 32, 1, 5, "NSR03", probe_udf }, |
paul@181 | 1585 | { "udf", 32, 1, 5, "TEA01", probe_udf }, |
paul@181 | 1586 | { "iso9660", 32, 1, 5, "CD001", probe_iso9660 }, |
paul@181 | 1587 | { "iso9660", 32, 9, 5, "CDROM", probe_iso9660 }, |
paul@181 | 1588 | { "jfs", 32, 0, 4, "JFS1", probe_jfs }, |
paul@181 | 1589 | /* ZFS has 128 root blocks (#4 is the first used), check only 6 of them */ |
paul@181 | 1590 | { "zfs", 128, 0, 8, "\0\0\0\0\0\xba\xb1\x0c", probe_zfs }, |
paul@181 | 1591 | { "zfs", 128, 0, 8, "\x0c\xb1\xba\0\0\0\0\0", probe_zfs }, |
paul@181 | 1592 | { "zfs", 132, 0, 8, "\0\0\0\0\0\xba\xb1\x0c", probe_zfs }, |
paul@181 | 1593 | { "zfs", 132, 0, 8, "\x0c\xb1\xba\0\0\0\0\0", probe_zfs }, |
paul@181 | 1594 | { "zfs", 136, 0, 8, "\0\0\0\0\0\xba\xb1\x0c", probe_zfs }, |
paul@181 | 1595 | { "zfs", 136, 0, 8, "\x0c\xb1\xba\0\0\0\0\0", probe_zfs }, |
paul@181 | 1596 | { "zfs", 384, 0, 8, "\0\0\0\0\0\xba\xb1\x0c", probe_zfs }, |
paul@181 | 1597 | { "zfs", 384, 0, 8, "\x0c\xb1\xba\0\0\0\0\0", probe_zfs }, |
paul@181 | 1598 | { "zfs", 388, 0, 8, "\0\0\0\0\0\xba\xb1\x0c", probe_zfs }, |
paul@181 | 1599 | { "zfs", 388, 0, 8, "\x0c\xb1\xba\0\0\0\0\0", probe_zfs }, |
paul@181 | 1600 | { "zfs", 392, 0, 8, "\0\0\0\0\0\xba\xb1\x0c", probe_zfs }, |
paul@181 | 1601 | { "zfs", 392, 0, 8, "\x0c\xb1\xba\0\0\0\0\0", probe_zfs }, |
paul@181 | 1602 | { "hfsplus", 1, 0, 2, "BD", probe_hfsplus }, |
paul@181 | 1603 | { "hfsplus", 1, 0, 2, "H+", probe_hfsplus }, |
paul@181 | 1604 | { "hfsplus", 1, 0, 2, "HX", probe_hfsplus }, |
paul@181 | 1605 | { "hfs", 1, 0, 2, "BD", probe_hfs }, |
paul@181 | 1606 | { "ufs", 8, 0x55c, 4, "T\031\001\000", 0 }, |
paul@181 | 1607 | { "hpfs", 8, 0, 4, "I\350\225\371", 0 }, |
paul@181 | 1608 | { "sysv", 0, 0x3f8, 4, "\020~\030\375", 0 }, |
paul@181 | 1609 | { "swap", 0, 0xff6, 10, "SWAP-SPACE", probe_swap0 }, |
paul@181 | 1610 | { "swap", 0, 0xff6, 10, "SWAPSPACE2", probe_swap1 }, |
paul@181 | 1611 | { "swsuspend", 0, 0xff6, 9, "S1SUSPEND", probe_swap1 }, |
paul@181 | 1612 | { "swsuspend", 0, 0xff6, 9, "S2SUSPEND", probe_swap1 }, |
paul@181 | 1613 | { "swsuspend", 0, 0xff6, 9, "ULSUSPEND", probe_swap1 }, |
paul@181 | 1614 | { "swap", 0, 0x1ff6, 10, "SWAP-SPACE", probe_swap0 }, |
paul@181 | 1615 | { "swap", 0, 0x1ff6, 10, "SWAPSPACE2", probe_swap1 }, |
paul@181 | 1616 | { "swsuspend", 0, 0x1ff6, 9, "S1SUSPEND", probe_swap1 }, |
paul@181 | 1617 | { "swsuspend", 0, 0x1ff6, 9, "S2SUSPEND", probe_swap1 }, |
paul@181 | 1618 | { "swsuspend", 0, 0x1ff6, 9, "ULSUSPEND", probe_swap1 }, |
paul@181 | 1619 | { "swap", 0, 0x3ff6, 10, "SWAP-SPACE", probe_swap0 }, |
paul@181 | 1620 | { "swap", 0, 0x3ff6, 10, "SWAPSPACE2", probe_swap1 }, |
paul@181 | 1621 | { "swsuspend", 0, 0x3ff6, 9, "S1SUSPEND", probe_swap1 }, |
paul@181 | 1622 | { "swsuspend", 0, 0x3ff6, 9, "S2SUSPEND", probe_swap1 }, |
paul@181 | 1623 | { "swsuspend", 0, 0x3ff6, 9, "ULSUSPEND", probe_swap1 }, |
paul@181 | 1624 | { "swap", 0, 0x7ff6, 10, "SWAP-SPACE", probe_swap0 }, |
paul@181 | 1625 | { "swap", 0, 0x7ff6, 10, "SWAPSPACE2", probe_swap1 }, |
paul@181 | 1626 | { "swsuspend", 0, 0x7ff6, 9, "S1SUSPEND", probe_swap1 }, |
paul@181 | 1627 | { "swsuspend", 0, 0x7ff6, 9, "S2SUSPEND", probe_swap1 }, |
paul@181 | 1628 | { "swsuspend", 0, 0x7ff6, 9, "ULSUSPEND", probe_swap1 }, |
paul@181 | 1629 | { "swap", 0, 0xfff6, 10, "SWAP-SPACE", probe_swap0 }, |
paul@181 | 1630 | { "swap", 0, 0xfff6, 10, "SWAPSPACE2", probe_swap1 }, |
paul@181 | 1631 | { "swsuspend", 0, 0xfff6, 9, "S1SUSPEND", probe_swap1 }, |
paul@181 | 1632 | { "swsuspend", 0, 0xfff6, 9, "S2SUSPEND", probe_swap1 }, |
paul@181 | 1633 | { "swsuspend", 0, 0xfff6, 9, "ULSUSPEND", probe_swap1 }, |
paul@181 | 1634 | { "ocfs", 0, 8, 9, "OracleCFS", probe_ocfs }, |
paul@181 | 1635 | { "ocfs2", 1, 0, 6, "OCFSV2", probe_ocfs2 }, |
paul@181 | 1636 | { "ocfs2", 2, 0, 6, "OCFSV2", probe_ocfs2 }, |
paul@181 | 1637 | { "ocfs2", 4, 0, 6, "OCFSV2", probe_ocfs2 }, |
paul@181 | 1638 | { "ocfs2", 8, 0, 6, "OCFSV2", probe_ocfs2 }, |
paul@181 | 1639 | { "crypt_LUKS", 0, 0, 6, "LUKS\xba\xbe", probe_luks }, |
paul@181 | 1640 | { "squashfs", 0, 0, 4, "sqsh", 0 }, |
paul@181 | 1641 | { "squashfs", 0, 0, 4, "hsqs", 0 }, |
paul@181 | 1642 | { "lvm2pv", 0, 0x218, 8, "LVM2 001", probe_lvm2 }, |
paul@181 | 1643 | { "lvm2pv", 0, 0x018, 8, "LVM2 001", probe_lvm2 }, |
paul@181 | 1644 | { "lvm2pv", 1, 0x018, 8, "LVM2 001", probe_lvm2 }, |
paul@181 | 1645 | { "lvm2pv", 1, 0x218, 8, "LVM2 001", probe_lvm2 }, |
paul@181 | 1646 | { "btrfs", 64, 0x40, 8, "_BHRfS_M", probe_btrfs }, |
paul@181 | 1647 | { "f2fs", 1, 0, 4, "\x10\x20\xf5\xf2", probe_f2fs }, |
paul@181 | 1648 | { "exfat", 0, 3, 8, "EXFAT ", probe_exfat }, |
paul@181 | 1649 | { NULL, 0, 0, 0, NULL, NULL } |
paul@181 | 1650 | }; |
paul@181 | 1651 | |
paul@181 | 1652 | /* |
paul@181 | 1653 | * Verify that the data in dev is consistent with what is on the actual |
paul@181 | 1654 | * block device (using the devname field only). Normally this will be |
paul@181 | 1655 | * called when finding items in the cache, but for long running processes |
paul@181 | 1656 | * is also desirable to revalidate an item before use. |
paul@181 | 1657 | * |
paul@181 | 1658 | * If we are unable to revalidate the data, we return the old data and |
paul@181 | 1659 | * do not set the BLKID_BID_FL_VERIFIED flag on it. |
paul@181 | 1660 | */ |
paul@181 | 1661 | blkid_dev blkid_verify(blkid_cache cache, blkid_dev dev) |
paul@181 | 1662 | { |
paul@181 | 1663 | struct blkid_magic *id; |
paul@181 | 1664 | struct blkid_probe probe; |
paul@181 | 1665 | blkid_tag_iterate iter; |
paul@181 | 1666 | unsigned char *buf; |
paul@181 | 1667 | const char *type, *value; |
paul@181 | 1668 | struct stat st; |
paul@181 | 1669 | time_t now; |
paul@181 | 1670 | double diff; |
paul@181 | 1671 | int idx; |
paul@181 | 1672 | |
paul@181 | 1673 | if (!dev) |
paul@181 | 1674 | return NULL; |
paul@181 | 1675 | |
paul@181 | 1676 | now = time(0); |
paul@181 | 1677 | diff = difftime(now, dev->bid_time); |
paul@181 | 1678 | |
paul@181 | 1679 | if (stat(dev->bid_name, &st) < 0) { |
paul@181 | 1680 | DBG(DEBUG_PROBE, |
paul@181 | 1681 | printf("blkid_verify: error %s (%d) while " |
paul@181 | 1682 | "trying to stat %s\n", strerror(errno), errno, |
paul@181 | 1683 | dev->bid_name)); |
paul@181 | 1684 | open_err: |
paul@181 | 1685 | if ((errno == EPERM) || (errno == EACCES) || (errno == ENOENT)) { |
paul@181 | 1686 | /* We don't have read permission, just return cache data. */ |
paul@181 | 1687 | DBG(DEBUG_PROBE, printf("returning unverified data for %s\n", |
paul@181 | 1688 | dev->bid_name)); |
paul@181 | 1689 | return dev; |
paul@181 | 1690 | } |
paul@181 | 1691 | blkid_free_dev(dev); |
paul@181 | 1692 | return NULL; |
paul@181 | 1693 | } |
paul@181 | 1694 | |
paul@181 | 1695 | if ((now >= dev->bid_time) && |
paul@181 | 1696 | (st.st_mtime <= dev->bid_time) && |
paul@181 | 1697 | ((diff < BLKID_PROBE_MIN) || |
paul@181 | 1698 | (dev->bid_flags & BLKID_BID_FL_VERIFIED && |
paul@181 | 1699 | diff < BLKID_PROBE_INTERVAL))) |
paul@181 | 1700 | return dev; |
paul@181 | 1701 | |
paul@181 | 1702 | DBG(DEBUG_PROBE, |
paul@181 | 1703 | printf("need to revalidate %s (cache time %lu, stat time %lu,\n\t" |
paul@181 | 1704 | "time since last check %lu)\n", |
paul@181 | 1705 | dev->bid_name, (unsigned long)dev->bid_time, |
paul@181 | 1706 | (unsigned long)st.st_mtime, (unsigned long)diff)); |
paul@181 | 1707 | |
paul@181 | 1708 | if ((probe.fd = open(dev->bid_name, O_RDONLY)) < 0) { |
paul@181 | 1709 | DBG(DEBUG_PROBE, printf("blkid_verify: error %s (%d) while " |
paul@181 | 1710 | "opening %s\n", strerror(errno), errno, |
paul@181 | 1711 | dev->bid_name)); |
paul@181 | 1712 | goto open_err; |
paul@181 | 1713 | } |
paul@181 | 1714 | |
paul@181 | 1715 | probe.cache = cache; |
paul@181 | 1716 | probe.dev = dev; |
paul@181 | 1717 | probe.sbbuf = 0; |
paul@181 | 1718 | probe.buf = 0; |
paul@181 | 1719 | probe.buf_max = 0; |
paul@181 | 1720 | |
paul@181 | 1721 | /* |
paul@181 | 1722 | * Iterate over the type array. If we already know the type, |
paul@181 | 1723 | * then try that first. If it doesn't work, then blow away |
paul@181 | 1724 | * the type information, and try again. |
paul@181 | 1725 | * |
paul@181 | 1726 | */ |
paul@181 | 1727 | try_again: |
paul@181 | 1728 | type = 0; |
paul@181 | 1729 | if (!dev->bid_type || !strcmp(dev->bid_type, "mdraid")) { |
paul@181 | 1730 | uuid_t uuid; |
paul@181 | 1731 | |
paul@181 | 1732 | if (check_mdraid(probe.fd, uuid) == 0) { |
paul@181 | 1733 | set_uuid(dev, uuid, 0); |
paul@181 | 1734 | type = "mdraid"; |
paul@181 | 1735 | goto found_type; |
paul@181 | 1736 | } |
paul@181 | 1737 | } |
paul@181 | 1738 | for (id = type_array; id->bim_type; id++) { |
paul@181 | 1739 | if (dev->bid_type && |
paul@181 | 1740 | strcmp(id->bim_type, dev->bid_type)) |
paul@181 | 1741 | continue; |
paul@181 | 1742 | |
paul@181 | 1743 | idx = id->bim_kboff + (id->bim_sboff >> 10); |
paul@181 | 1744 | buf = get_buffer(&probe, (__u64) idx << 10, 1024); |
paul@181 | 1745 | if (!buf) |
paul@181 | 1746 | continue; |
paul@181 | 1747 | |
paul@181 | 1748 | if (memcmp(id->bim_magic, buf + (id->bim_sboff & 0x3ff), |
paul@181 | 1749 | id->bim_len)) |
paul@181 | 1750 | continue; |
paul@181 | 1751 | |
paul@181 | 1752 | if ((id->bim_probe == NULL) || |
paul@181 | 1753 | (id->bim_probe(&probe, id, buf) == 0)) { |
paul@181 | 1754 | type = id->bim_type; |
paul@181 | 1755 | goto found_type; |
paul@181 | 1756 | } |
paul@181 | 1757 | } |
paul@181 | 1758 | |
paul@181 | 1759 | if (!id->bim_type && dev->bid_type) { |
paul@181 | 1760 | /* |
paul@181 | 1761 | * Zap the device filesystem information and try again |
paul@181 | 1762 | */ |
paul@181 | 1763 | DBG(DEBUG_PROBE, |
paul@181 | 1764 | printf("previous fs type %s not valid, " |
paul@181 | 1765 | "trying full probe\n", dev->bid_type)); |
paul@181 | 1766 | iter = blkid_tag_iterate_begin(dev); |
paul@181 | 1767 | while (blkid_tag_next(iter, &type, &value) == 0) |
paul@181 | 1768 | blkid_set_tag(dev, type, 0, 0); |
paul@181 | 1769 | blkid_tag_iterate_end(iter); |
paul@181 | 1770 | goto try_again; |
paul@181 | 1771 | } |
paul@181 | 1772 | |
paul@181 | 1773 | if (!dev->bid_type) { |
paul@181 | 1774 | blkid_free_dev(dev); |
paul@181 | 1775 | dev = 0; |
paul@181 | 1776 | goto found_type; |
paul@181 | 1777 | } |
paul@181 | 1778 | |
paul@181 | 1779 | found_type: |
paul@181 | 1780 | if (dev && type) { |
paul@181 | 1781 | dev->bid_devno = st.st_rdev; |
paul@181 | 1782 | dev->bid_time = time(0); |
paul@181 | 1783 | dev->bid_flags |= BLKID_BID_FL_VERIFIED; |
paul@181 | 1784 | cache->bic_flags |= BLKID_BIC_FL_CHANGED; |
paul@181 | 1785 | |
paul@181 | 1786 | blkid_set_tag(dev, "TYPE", type, 0); |
paul@181 | 1787 | |
paul@181 | 1788 | DBG(DEBUG_PROBE, printf("%s: devno 0x%04llx, type %s\n", |
paul@181 | 1789 | dev->bid_name, (long long)st.st_rdev, type)); |
paul@181 | 1790 | } |
paul@181 | 1791 | |
paul@181 | 1792 | free(probe.sbbuf); |
paul@181 | 1793 | free(probe.buf); |
paul@181 | 1794 | if (probe.fd >= 0) |
paul@181 | 1795 | close(probe.fd); |
paul@181 | 1796 | |
paul@181 | 1797 | return dev; |
paul@181 | 1798 | } |
paul@181 | 1799 | |
paul@181 | 1800 | int blkid_known_fstype(const char *fstype) |
paul@181 | 1801 | { |
paul@181 | 1802 | struct blkid_magic *id; |
paul@181 | 1803 | |
paul@181 | 1804 | for (id = type_array; id->bim_type; id++) { |
paul@181 | 1805 | if (strcmp(fstype, id->bim_type) == 0) |
paul@181 | 1806 | return 1; |
paul@181 | 1807 | } |
paul@181 | 1808 | return 0; |
paul@181 | 1809 | } |
paul@181 | 1810 | |
paul@181 | 1811 | #ifdef TEST_PROGRAM |
paul@181 | 1812 | int main(int argc, char **argv) |
paul@181 | 1813 | { |
paul@181 | 1814 | blkid_dev dev; |
paul@181 | 1815 | blkid_cache cache; |
paul@181 | 1816 | int ret; |
paul@181 | 1817 | |
paul@181 | 1818 | if (argc != 2) { |
paul@181 | 1819 | fprintf(stderr, "Usage: %s device\n" |
paul@181 | 1820 | "Probe a single device to determine type\n", argv[0]); |
paul@181 | 1821 | exit(1); |
paul@181 | 1822 | } |
paul@181 | 1823 | if ((ret = blkid_get_cache(&cache, "/dev/null")) != 0) { |
paul@181 | 1824 | fprintf(stderr, "%s: error creating cache (%d)\n", |
paul@181 | 1825 | argv[0], ret); |
paul@181 | 1826 | exit(1); |
paul@181 | 1827 | } |
paul@181 | 1828 | dev = blkid_get_dev(cache, argv[1], BLKID_DEV_NORMAL); |
paul@181 | 1829 | if (!dev) { |
paul@181 | 1830 | printf("%s: %s has an unsupported type\n", argv[0], argv[1]); |
paul@181 | 1831 | return (1); |
paul@181 | 1832 | } |
paul@181 | 1833 | printf("TYPE='%s'\n", dev->bid_type ? dev->bid_type : "(null)"); |
paul@181 | 1834 | if (dev->bid_label) |
paul@181 | 1835 | printf("LABEL='%s'\n", dev->bid_label); |
paul@181 | 1836 | if (dev->bid_uuid) |
paul@181 | 1837 | printf("UUID='%s'\n", dev->bid_uuid); |
paul@181 | 1838 | |
paul@181 | 1839 | blkid_free_dev(dev); |
paul@181 | 1840 | return (0); |
paul@181 | 1841 | } |
paul@181 | 1842 | #endif |