busybox/e2fsprogs/old_e2fsprogs/blkid/probe.c
<<
>>
Prefs
   1/* vi: set sw=4 ts=4: */
   2/*
   3 * probe.c - identify a block device by its contents, and return a dev
   4 *           struct with the details
   5 *
   6 * Copyright (C) 1999 by Andries Brouwer
   7 * Copyright (C) 1999, 2000, 2003 by Theodore Ts'o
   8 * Copyright (C) 2001 by Andreas Dilger
   9 *
  10 * %Begin-Header%
  11 * This file may be redistributed under the terms of the
  12 * GNU Lesser General Public License.
  13 * %End-Header%
  14 */
  15
  16#include <stdio.h>
  17#include <string.h>
  18#include <stdlib.h>
  19#include <unistd.h>
  20#include <fcntl.h>
  21#include <sys/types.h>
  22#ifdef HAVE_SYS_STAT_H
  23#include <sys/stat.h>
  24#endif
  25#ifdef HAVE_SYS_MKDEV_H
  26#include <sys/mkdev.h>
  27#endif
  28#ifdef HAVE_ERRNO_H
  29#include <errno.h>
  30#endif
  31#include "blkidP.h"
  32#include "../uuid/uuid.h"
  33#include "probe.h"
  34
  35/*
  36 * This is a special case code to check for an MDRAID device.  We do
  37 * this special since it requires checking for a superblock at the end
  38 * of the device.
  39 */
  40static int check_mdraid(int fd, unsigned char *ret_uuid)
  41{
  42        struct mdp_superblock_s *md;
  43        blkid_loff_t            offset;
  44        char                    buf[4096];
  45
  46        if (fd < 0)
  47                return -BLKID_ERR_PARAM;
  48
  49        offset = (blkid_get_dev_size(fd) & ~((blkid_loff_t)65535)) - 65536;
  50
  51        if (blkid_llseek(fd, offset, 0) < 0 ||
  52            read(fd, buf, 4096) != 4096)
  53                return -BLKID_ERR_IO;
  54
  55        /* Check for magic number */
  56        if (memcmp("\251+N\374", buf, 4))
  57                return -BLKID_ERR_PARAM;
  58
  59        if (!ret_uuid)
  60                return 0;
  61        *ret_uuid = 0;
  62
  63        /* The MD UUID is not contiguous in the superblock, make it so */
  64        md = (struct mdp_superblock_s *)buf;
  65        if (md->set_uuid0 || md->set_uuid1 || md->set_uuid2 || md->set_uuid3) {
  66                memcpy(ret_uuid, &md->set_uuid0, 4);
  67                memcpy(ret_uuid, &md->set_uuid1, 12);
  68        }
  69        return 0;
  70}
  71
  72static void set_uuid(blkid_dev dev, uuid_t uuid)
  73{
  74        char    str[37];
  75
  76        if (!uuid_is_null(uuid)) {
  77                uuid_unparse(uuid, str);
  78                blkid_set_tag(dev, "UUID", str, sizeof(str));
  79        }
  80}
  81
  82static void get_ext2_info(blkid_dev dev, unsigned char *buf)
  83{
  84        struct ext2_super_block *es = (struct ext2_super_block *) buf;
  85        const char *label = 0;
  86
  87        DBG(DEBUG_PROBE, printf("ext2_sb.compat = %08X:%08X:%08X\n",
  88                   blkid_le32(es->s_feature_compat),
  89                   blkid_le32(es->s_feature_incompat),
  90                   blkid_le32(es->s_feature_ro_compat)));
  91
  92        if (strlen(es->s_volume_name))
  93                label = es->s_volume_name;
  94        blkid_set_tag(dev, "LABEL", label, sizeof(es->s_volume_name));
  95
  96        set_uuid(dev, es->s_uuid);
  97}
  98
  99static int probe_ext3(int fd __BLKID_ATTR((unused)),
 100                      blkid_cache cache __BLKID_ATTR((unused)),
 101                      blkid_dev dev,
 102                      const struct blkid_magic *id __BLKID_ATTR((unused)),
 103                      unsigned char *buf)
 104{
 105        struct ext2_super_block *es;
 106
 107        es = (struct ext2_super_block *)buf;
 108
 109        /* Distinguish between jbd and ext2/3 fs */
 110        if (blkid_le32(es->s_feature_incompat) &
 111            EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)
 112                return -BLKID_ERR_PARAM;
 113
 114        /* Distinguish between ext3 and ext2 */
 115        if (!(blkid_le32(es->s_feature_compat) &
 116              EXT3_FEATURE_COMPAT_HAS_JOURNAL))
 117                return -BLKID_ERR_PARAM;
 118
 119        get_ext2_info(dev, buf);
 120
 121        blkid_set_tag(dev, "SEC_TYPE", "ext2", sizeof("ext2"));
 122
 123        return 0;
 124}
 125
 126static int probe_ext2(int fd __BLKID_ATTR((unused)),
 127                      blkid_cache cache __BLKID_ATTR((unused)),
 128                      blkid_dev dev,
 129                      const struct blkid_magic *id __BLKID_ATTR((unused)),
 130                      unsigned char *buf)
 131{
 132        struct ext2_super_block *es;
 133
 134        es = (struct ext2_super_block *)buf;
 135
 136        /* Distinguish between jbd and ext2/3 fs */
 137        if (blkid_le32(es->s_feature_incompat) &
 138            EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)
 139                return -BLKID_ERR_PARAM;
 140
 141        get_ext2_info(dev, buf);
 142
 143        return 0;
 144}
 145
 146static int probe_jbd(int fd __BLKID_ATTR((unused)),
 147                     blkid_cache cache __BLKID_ATTR((unused)),
 148                     blkid_dev dev,
 149                     const struct blkid_magic *id __BLKID_ATTR((unused)),
 150                     unsigned char *buf)
 151{
 152        struct ext2_super_block *es = (struct ext2_super_block *) buf;
 153
 154        if (!(blkid_le32(es->s_feature_incompat) &
 155              EXT3_FEATURE_INCOMPAT_JOURNAL_DEV))
 156                return -BLKID_ERR_PARAM;
 157
 158        get_ext2_info(dev, buf);
 159
 160        return 0;
 161}
 162
 163static int probe_vfat(int fd __BLKID_ATTR((unused)),
 164                      blkid_cache cache __BLKID_ATTR((unused)),
 165                      blkid_dev dev,
 166                      const struct blkid_magic *id __BLKID_ATTR((unused)),
 167                      unsigned char *buf)
 168{
 169        struct vfat_super_block *vs;
 170        char serno[10];
 171        const char *label = 0;
 172        int label_len = 0;
 173
 174        vs = (struct vfat_super_block *)buf;
 175
 176        if (strncmp(vs->vs_label, "NO NAME", 7)) {
 177                char *end = vs->vs_label + sizeof(vs->vs_label) - 1;
 178
 179                while (*end == ' ' && end >= vs->vs_label)
 180                        --end;
 181                if (end >= vs->vs_label) {
 182                        label = vs->vs_label;
 183                        label_len = end - vs->vs_label + 1;
 184                }
 185        }
 186
 187        /* We can't just print them as %04X, because they are unaligned */
 188        sprintf(serno, "%02X%02X-%02X%02X", vs->vs_serno[3], vs->vs_serno[2],
 189                vs->vs_serno[1], vs->vs_serno[0]);
 190        blkid_set_tag(dev, "LABEL", label, label_len);
 191        blkid_set_tag(dev, "UUID", serno, sizeof(serno));
 192
 193        return 0;
 194}
 195
 196static int probe_msdos(int fd __BLKID_ATTR((unused)),
 197                       blkid_cache cache __BLKID_ATTR((unused)),
 198                       blkid_dev dev,
 199                       const struct blkid_magic *id __BLKID_ATTR((unused)),
 200                       unsigned char *buf)
 201{
 202        struct msdos_super_block *ms = (struct msdos_super_block *) buf;
 203        char serno[10];
 204        const char *label = 0;
 205        int label_len = 0;
 206
 207        if (strncmp(ms->ms_label, "NO NAME", 7)) {
 208                char *end = ms->ms_label + sizeof(ms->ms_label) - 1;
 209
 210                while (*end == ' ' && end >= ms->ms_label)
 211                        --end;
 212                if (end >= ms->ms_label) {
 213                        label = ms->ms_label;
 214                        label_len = end - ms->ms_label + 1;
 215                }
 216        }
 217
 218        /* We can't just print them as %04X, because they are unaligned */
 219        sprintf(serno, "%02X%02X-%02X%02X", ms->ms_serno[3], ms->ms_serno[2],
 220                ms->ms_serno[1], ms->ms_serno[0]);
 221        blkid_set_tag(dev, "UUID", serno, 0);
 222        blkid_set_tag(dev, "LABEL", label, label_len);
 223        blkid_set_tag(dev, "SEC_TYPE", "msdos", sizeof("msdos"));
 224
 225        return 0;
 226}
 227
 228static int probe_xfs(int fd __BLKID_ATTR((unused)),
 229                     blkid_cache cache __BLKID_ATTR((unused)),
 230                     blkid_dev dev,
 231                     const struct blkid_magic *id __BLKID_ATTR((unused)),
 232                     unsigned char *buf)
 233{
 234        struct xfs_super_block *xs;
 235        const char *label = 0;
 236
 237        xs = (struct xfs_super_block *)buf;
 238
 239        if (strlen(xs->xs_fname))
 240                label = xs->xs_fname;
 241        blkid_set_tag(dev, "LABEL", label, sizeof(xs->xs_fname));
 242        set_uuid(dev, xs->xs_uuid);
 243        return 0;
 244}
 245
 246static int probe_reiserfs(int fd __BLKID_ATTR((unused)),
 247                          blkid_cache cache __BLKID_ATTR((unused)),
 248                          blkid_dev dev,
 249                          const struct blkid_magic *id, unsigned char *buf)
 250{
 251        struct reiserfs_super_block *rs = (struct reiserfs_super_block *) buf;
 252        unsigned int blocksize;
 253        const char *label = 0;
 254
 255        blocksize = blkid_le16(rs->rs_blocksize);
 256
 257        /* If the superblock is inside the journal, we have the wrong one */
 258        if (id->bim_kboff/(blocksize>>10) > blkid_le32(rs->rs_journal_block))
 259                return -BLKID_ERR_BIG;
 260
 261        /* LABEL/UUID are only valid for later versions of Reiserfs v3.6. */
 262        if (!strcmp(id->bim_magic, "ReIsEr2Fs") ||
 263            !strcmp(id->bim_magic, "ReIsEr3Fs")) {
 264                if (strlen(rs->rs_label))
 265                        label = rs->rs_label;
 266                set_uuid(dev, rs->rs_uuid);
 267        }
 268        blkid_set_tag(dev, "LABEL", label, sizeof(rs->rs_label));
 269
 270        return 0;
 271}
 272
 273static int probe_jfs(int fd __BLKID_ATTR((unused)),
 274                     blkid_cache cache __BLKID_ATTR((unused)),
 275                     blkid_dev dev,
 276                     const struct blkid_magic *id __BLKID_ATTR((unused)),
 277                     unsigned char *buf)
 278{
 279        struct jfs_super_block *js;
 280        const char *label = 0;
 281
 282        js = (struct jfs_super_block *)buf;
 283
 284        if (strlen((char *) js->js_label))
 285                label = (char *) js->js_label;
 286        blkid_set_tag(dev, "LABEL", label, sizeof(js->js_label));
 287        set_uuid(dev, js->js_uuid);
 288        return 0;
 289}
 290
 291static int probe_romfs(int fd __BLKID_ATTR((unused)),
 292                       blkid_cache cache __BLKID_ATTR((unused)),
 293                       blkid_dev dev,
 294                       const struct blkid_magic *id __BLKID_ATTR((unused)),
 295                       unsigned char *buf)
 296{
 297        struct romfs_super_block *ros;
 298        const char *label = 0;
 299
 300        ros = (struct romfs_super_block *)buf;
 301
 302        if (strlen((char *) ros->ros_volume))
 303                label = (char *) ros->ros_volume;
 304        blkid_set_tag(dev, "LABEL", label, 0);
 305        return 0;
 306}
 307
 308static int probe_cramfs(int fd __BLKID_ATTR((unused)),
 309                       blkid_cache cache __BLKID_ATTR((unused)),
 310                       blkid_dev dev,
 311                       const struct blkid_magic *id __BLKID_ATTR((unused)),
 312                       unsigned char *buf)
 313{
 314        struct cramfs_super_block *csb;
 315        const char *label = 0;
 316
 317        csb = (struct cramfs_super_block *)buf;
 318
 319        if (strlen((char *) csb->name))
 320                label = (char *) csb->name;
 321        blkid_set_tag(dev, "LABEL", label, 0);
 322        return 0;
 323}
 324
 325static int probe_swap0(int fd __BLKID_ATTR((unused)),
 326                       blkid_cache cache __BLKID_ATTR((unused)),
 327                       blkid_dev dev,
 328                       const struct blkid_magic *id __BLKID_ATTR((unused)),
 329                       unsigned char *buf __BLKID_ATTR((unused)))
 330{
 331        blkid_set_tag(dev, "UUID", 0, 0);
 332        blkid_set_tag(dev, "LABEL", 0, 0);
 333        return 0;
 334}
 335
 336static int probe_swap1(int fd,
 337                       blkid_cache cache __BLKID_ATTR((unused)),
 338                       blkid_dev dev,
 339                       const struct blkid_magic *id __BLKID_ATTR((unused)),
 340                       unsigned char *buf __BLKID_ATTR((unused)))
 341{
 342        struct swap_id_block *sws;
 343
 344        probe_swap0(fd, cache, dev, id, buf);
 345        /*
 346         * Version 1 swap headers are always located at offset of 1024
 347         * bytes, although the swap signature itself is located at the
 348         * end of the page (which may vary depending on hardware
 349         * pagesize).
 350         */
 351        if (lseek(fd, 1024, SEEK_SET) < 0) return 1;
 352        sws = xmalloc(1024);
 353        if (read(fd, sws, 1024) != 1024) {
 354                free(sws);
 355                return 1;
 356        }
 357
 358        /* arbitrary sanity check.. is there any garbage down there? */
 359        if (sws->sws_pad[32] == 0 && sws->sws_pad[33] == 0)  {
 360                if (sws->sws_volume[0])
 361                        blkid_set_tag(dev, "LABEL", (const char*)sws->sws_volume,
 362                                      sizeof(sws->sws_volume));
 363                if (sws->sws_uuid[0])
 364                        set_uuid(dev, sws->sws_uuid);
 365        }
 366        free(sws);
 367
 368        return 0;
 369}
 370
 371static const char
 372* const udf_magic[] = { "BEA01", "BOOT2", "CD001", "CDW02", "NSR02",
 373                 "NSR03", "TEA01", 0 };
 374
 375static int probe_udf(int fd, blkid_cache cache __BLKID_ATTR((unused)),
 376                     blkid_dev dev __BLKID_ATTR((unused)),
 377                     const struct blkid_magic *id __BLKID_ATTR((unused)),
 378                     unsigned char *buf __BLKID_ATTR((unused)))
 379{
 380        int j, bs;
 381        struct iso_volume_descriptor isosb;
 382        const char *const *m;
 383
 384        /* determine the block size by scanning in 2K increments
 385           (block sizes larger than 2K will be null padded) */
 386        for (bs = 1; bs < 16; bs++) {
 387                lseek(fd, bs*2048+32768, SEEK_SET);
 388                if (read(fd, (char *)&isosb, sizeof(isosb)) != sizeof(isosb))
 389                        return 1;
 390                if (isosb.id[0])
 391                        break;
 392        }
 393
 394        /* Scan up to another 64 blocks looking for additional VSD's */
 395        for (j = 1; j < 64; j++) {
 396                if (j > 1) {
 397                        lseek(fd, j*bs*2048+32768, SEEK_SET);
 398                        if (read(fd, (char *)&isosb, sizeof(isosb))
 399                            != sizeof(isosb))
 400                                return 1;
 401                }
 402                /* If we find NSR0x then call it udf:
 403                   NSR01 for UDF 1.00
 404                   NSR02 for UDF 1.50
 405                   NSR03 for UDF 2.00 */
 406                if (!strncmp(isosb.id, "NSR0", 4))
 407                        return 0;
 408                for (m = udf_magic; *m; m++)
 409                        if (!strncmp(*m, isosb.id, 5))
 410                                break;
 411                if (*m == 0)
 412                        return 1;
 413        }
 414        return 1;
 415}
 416
 417static int probe_ocfs(int fd __BLKID_ATTR((unused)),
 418                      blkid_cache cache __BLKID_ATTR((unused)),
 419                      blkid_dev dev,
 420                      const struct blkid_magic *id __BLKID_ATTR((unused)),
 421                      unsigned char *buf)
 422{
 423        struct ocfs_volume_header ovh;
 424        struct ocfs_volume_label ovl;
 425        __u32 major;
 426
 427        memcpy(&ovh, buf, sizeof(ovh));
 428        memcpy(&ovl, buf+512, sizeof(ovl));
 429
 430        major = ocfsmajor(ovh);
 431        if (major == 1)
 432                blkid_set_tag(dev, "SEC_TYPE", "ocfs1", sizeof("ocfs1"));
 433        else if (major >= 9)
 434                blkid_set_tag(dev, "SEC_TYPE", "ntocfs", sizeof("ntocfs"));
 435
 436        blkid_set_tag(dev, "LABEL", (const char*)ovl.label, ocfslabellen(ovl));
 437        blkid_set_tag(dev, "MOUNT", (const char*)ovh.mount, ocfsmountlen(ovh));
 438        set_uuid(dev, ovl.vol_id);
 439        return 0;
 440}
 441
 442static int probe_ocfs2(int fd __BLKID_ATTR((unused)),
 443                       blkid_cache cache __BLKID_ATTR((unused)),
 444                       blkid_dev dev,
 445                       const struct blkid_magic *id __BLKID_ATTR((unused)),
 446                       unsigned char *buf)
 447{
 448        struct ocfs2_super_block *osb;
 449
 450        osb = (struct ocfs2_super_block *)buf;
 451
 452        blkid_set_tag(dev, "LABEL", (const char*)osb->s_label, sizeof(osb->s_label));
 453        set_uuid(dev, osb->s_uuid);
 454        return 0;
 455}
 456
 457static int probe_oracleasm(int fd __BLKID_ATTR((unused)),
 458                           blkid_cache cache __BLKID_ATTR((unused)),
 459                           blkid_dev dev,
 460                           const struct blkid_magic *id __BLKID_ATTR((unused)),
 461                           unsigned char *buf)
 462{
 463        struct oracle_asm_disk_label *dl;
 464
 465        dl = (struct oracle_asm_disk_label *)buf;
 466
 467        blkid_set_tag(dev, "LABEL", dl->dl_id, sizeof(dl->dl_id));
 468        return 0;
 469}
 470
 471/*
 472 * BLKID_BLK_OFFS is at least as large as the highest bim_kboff defined
 473 * in the type_array table below + bim_kbalign.
 474 *
 475 * When probing for a lot of magics, we handle everything in 1kB buffers so
 476 * that we don't have to worry about reading each combination of block sizes.
 477 */
 478#define BLKID_BLK_OFFS  64      /* currently reiserfs */
 479
 480/*
 481 * Various filesystem magics that we can check for.  Note that kboff and
 482 * sboff are in kilobytes and bytes respectively.  All magics are in
 483 * byte strings so we don't worry about endian issues.
 484 */
 485static const struct blkid_magic type_array[] = {
 486/*  type     kboff   sboff len  magic                   probe */
 487  { "oracleasm", 0,     32,  8, "ORCLDISK",             probe_oracleasm },
 488  { "ntfs",      0,      3,  8, "NTFS    ",             0 },
 489  { "jbd",       1,   0x38,  2, "\123\357",             probe_jbd },
 490  { "ext3",      1,   0x38,  2, "\123\357",             probe_ext3 },
 491  { "ext2",      1,   0x38,  2, "\123\357",             probe_ext2 },
 492  { "reiserfs",  8,   0x34,  8, "ReIsErFs",             probe_reiserfs },
 493  { "reiserfs", 64,   0x34,  9, "ReIsEr2Fs",            probe_reiserfs },
 494  { "reiserfs", 64,   0x34,  9, "ReIsEr3Fs",            probe_reiserfs },
 495  { "reiserfs", 64,   0x34,  8, "ReIsErFs",             probe_reiserfs },
 496  { "reiserfs",  8,     20,  8, "ReIsErFs",             probe_reiserfs },
 497  { "vfat",      0,   0x52,  5, "MSWIN",                probe_vfat },
 498  { "vfat",      0,   0x52,  8, "FAT32   ",             probe_vfat },
 499  { "vfat",      0,   0x36,  5, "MSDOS",                probe_msdos },
 500  { "vfat",      0,   0x36,  8, "FAT16   ",             probe_msdos },
 501  { "vfat",      0,   0x36,  8, "FAT12   ",             probe_msdos },
 502  { "minix",     1,   0x10,  2, "\177\023",             0 },
 503  { "minix",     1,   0x10,  2, "\217\023",             0 },
 504  { "minix",     1,   0x10,  2, "\150\044",             0 },
 505  { "minix",     1,   0x10,  2, "\170\044",             0 },
 506  { "vxfs",      1,      0,  4, "\365\374\001\245",     0 },
 507  { "xfs",       0,      0,  4, "XFSB",                 probe_xfs },
 508  { "romfs",     0,      0,  8, "-rom1fs-",             probe_romfs },
 509  { "bfs",       0,      0,  4, "\316\372\173\033",     0 },
 510  { "cramfs",    0,      0,  4, "E=\315\050",           probe_cramfs },
 511  { "qnx4",      0,      4,  6, "QNX4FS",               0 },
 512  { "udf",      32,      1,  5, "BEA01",                probe_udf },
 513  { "udf",      32,      1,  5, "BOOT2",                probe_udf },
 514  { "udf",      32,      1,  5, "CD001",                probe_udf },
 515  { "udf",      32,      1,  5, "CDW02",                probe_udf },
 516  { "udf",      32,      1,  5, "NSR02",                probe_udf },
 517  { "udf",      32,      1,  5, "NSR03",                probe_udf },
 518  { "udf",      32,      1,  5, "TEA01",                probe_udf },
 519  { "iso9660",  32,      1,  5, "CD001",                0 },
 520  { "iso9660",  32,      9,  5, "CDROM",                0 },
 521  { "jfs",      32,      0,  4, "JFS1",                 probe_jfs },
 522  { "hfs",       1,      0,  2, "BD",                   0 },
 523  { "ufs",       8,  0x55c,  4, "T\031\001\000",        0 },
 524  { "hpfs",      8,      0,  4, "I\350\225\371",        0 },
 525  { "sysv",      0,  0x3f8,  4, "\020~\030\375",        0 },
 526  { "swap",      0,  0xff6, 10, "SWAP-SPACE",           probe_swap0 },
 527  { "swap",      0,  0xff6, 10, "SWAPSPACE2",           probe_swap1 },
 528  { "swap",      0, 0x1ff6, 10, "SWAP-SPACE",           probe_swap0 },
 529  { "swap",      0, 0x1ff6, 10, "SWAPSPACE2",           probe_swap1 },
 530  { "swap",      0, 0x3ff6, 10, "SWAP-SPACE",           probe_swap0 },
 531  { "swap",      0, 0x3ff6, 10, "SWAPSPACE2",           probe_swap1 },
 532  { "swap",      0, 0x7ff6, 10, "SWAP-SPACE",           probe_swap0 },
 533  { "swap",      0, 0x7ff6, 10, "SWAPSPACE2",           probe_swap1 },
 534  { "swap",      0, 0xfff6, 10, "SWAP-SPACE",           probe_swap0 },
 535  { "swap",      0, 0xfff6, 10, "SWAPSPACE2",           probe_swap1 },
 536  { "ocfs",      0,      8,  9, "OracleCFS",            probe_ocfs },
 537  { "ocfs2",     1,      0,  6, "OCFSV2",               probe_ocfs2 },
 538  { "ocfs2",     2,      0,  6, "OCFSV2",               probe_ocfs2 },
 539  { "ocfs2",     4,      0,  6, "OCFSV2",               probe_ocfs2 },
 540  { "ocfs2",     8,      0,  6, "OCFSV2",               probe_ocfs2 },
 541  {   NULL,      0,      0,  0, NULL,                   NULL }
 542};
 543
 544/*
 545 * Verify that the data in dev is consistent with what is on the actual
 546 * block device (using the devname field only).  Normally this will be
 547 * called when finding items in the cache, but for long running processes
 548 * is also desirable to revalidate an item before use.
 549 *
 550 * If we are unable to revalidate the data, we return the old data and
 551 * do not set the BLKID_BID_FL_VERIFIED flag on it.
 552 */
 553blkid_dev blkid_verify(blkid_cache cache, blkid_dev dev)
 554{
 555        const struct blkid_magic *id;
 556        unsigned char *bufs[BLKID_BLK_OFFS + 1], *buf;
 557        const char *type;
 558        struct stat st;
 559        time_t diff, now;
 560        int fd, idx;
 561
 562        if (!dev)
 563                return NULL;
 564
 565        now = time(0);
 566        diff = now - dev->bid_time;
 567
 568        if ((now < dev->bid_time) ||
 569            (diff < BLKID_PROBE_MIN) ||
 570            (dev->bid_flags & BLKID_BID_FL_VERIFIED &&
 571             diff < BLKID_PROBE_INTERVAL))
 572                return dev;
 573
 574        DBG(DEBUG_PROBE,
 575            printf("need to revalidate %s (time since last check %lu)\n",
 576                   dev->bid_name, diff));
 577
 578        if (((fd = open(dev->bid_name, O_RDONLY)) < 0) ||
 579            (fstat(fd, &st) < 0)) {
 580                if (errno == ENXIO || errno == ENODEV || errno == ENOENT) {
 581                        blkid_free_dev(dev);
 582                        return NULL;
 583                }
 584                /* We don't have read permission, just return cache data. */
 585                DBG(DEBUG_PROBE,
 586                    printf("returning unverified data for %s\n",
 587                           dev->bid_name));
 588                return dev;
 589        }
 590
 591        memset(bufs, 0, sizeof(bufs));
 592
 593        /*
 594         * Iterate over the type array.  If we already know the type,
 595         * then try that first.  If it doesn't work, then blow away
 596         * the type information, and try again.
 597         *
 598         */
 599try_again:
 600        type = 0;
 601        if (!dev->bid_type || !strcmp(dev->bid_type, "mdraid")) {
 602                uuid_t  uuid;
 603
 604                if (check_mdraid(fd, uuid) == 0) {
 605                        set_uuid(dev, uuid);
 606                        type = "mdraid";
 607                        goto found_type;
 608                }
 609        }
 610        for (id = type_array; id->bim_type; id++) {
 611                if (dev->bid_type &&
 612                    strcmp(id->bim_type, dev->bid_type))
 613                        continue;
 614
 615                idx = id->bim_kboff + (id->bim_sboff >> 10);
 616                if (idx > BLKID_BLK_OFFS || idx < 0)
 617                        continue;
 618                buf = bufs[idx];
 619                if (!buf) {
 620                        if (lseek(fd, idx << 10, SEEK_SET) < 0)
 621                                continue;
 622
 623                        buf = xmalloc(1024);
 624
 625                        if (read(fd, buf, 1024) != 1024) {
 626                                free(buf);
 627                                continue;
 628                        }
 629                        bufs[idx] = buf;
 630                }
 631
 632                if (memcmp(id->bim_magic, buf + (id->bim_sboff&0x3ff),
 633                           id->bim_len))
 634                        continue;
 635
 636                if ((id->bim_probe == NULL) ||
 637                    (id->bim_probe(fd, cache, dev, id, buf) == 0)) {
 638                        type = id->bim_type;
 639                        goto found_type;
 640                }
 641        }
 642
 643        if (!id->bim_type && dev->bid_type) {
 644                /*
 645                 * Zap the device filesystem type and try again
 646                 */
 647                blkid_set_tag(dev, "TYPE", 0, 0);
 648                blkid_set_tag(dev, "SEC_TYPE", 0, 0);
 649                blkid_set_tag(dev, "LABEL", 0, 0);
 650                blkid_set_tag(dev, "UUID", 0, 0);
 651                goto try_again;
 652        }
 653
 654        if (!dev->bid_type) {
 655                blkid_free_dev(dev);
 656                return NULL;
 657        }
 658
 659found_type:
 660        if (dev && type) {
 661                dev->bid_devno = st.st_rdev;
 662                dev->bid_time = time(0);
 663                dev->bid_flags |= BLKID_BID_FL_VERIFIED;
 664                cache->bic_flags |= BLKID_BIC_FL_CHANGED;
 665
 666                blkid_set_tag(dev, "TYPE", type, 0);
 667
 668                DBG(DEBUG_PROBE, printf("%s: devno 0x%04llx, type %s\n",
 669                           dev->bid_name, st.st_rdev, type));
 670        }
 671
 672        close(fd);
 673
 674        return dev;
 675}
 676
 677int blkid_known_fstype(const char *fstype)
 678{
 679        const struct blkid_magic *id;
 680
 681        for (id = type_array; id->bim_type; id++) {
 682                if (strcmp(fstype, id->bim_type) == 0)
 683                        return 1;
 684        }
 685        return 0;
 686}
 687
 688#ifdef TEST_PROGRAM
 689int main(int argc, char **argv)
 690{
 691        blkid_dev dev;
 692        blkid_cache cache;
 693        int ret;
 694
 695        blkid_debug_mask = DEBUG_ALL;
 696        if (argc != 2) {
 697                fprintf(stderr, "Usage: %s device\n"
 698                        "Probe a single device to determine type\n", argv[0]);
 699                exit(1);
 700        }
 701        if ((ret = blkid_get_cache(&cache, bb_dev_null)) != 0) {
 702                fprintf(stderr, "%s: error creating cache (%d)\n",
 703                        argv[0], ret);
 704                exit(1);
 705        }
 706        dev = blkid_get_dev(cache, argv[1], BLKID_DEV_NORMAL);
 707        if (!dev) {
 708                printf("%s: %s has an unsupported type\n", argv[0], argv[1]);
 709                return 1;
 710        }
 711        printf("%s is type %s\n", argv[1], dev->bid_type ?
 712                dev->bid_type : "(null)");
 713        if (dev->bid_label)
 714                printf("\tlabel is '%s'\n", dev->bid_label);
 715        if (dev->bid_uuid)
 716                printf("\tuuid is %s\n", dev->bid_uuid);
 717
 718        blkid_free_dev(dev);
 719        return 0;
 720}
 721#endif
 722