]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
libblkid: Add support for DASD partition table
authorVojtech Trefny <vtrefny@redhat.com>
Wed, 25 Feb 2026 13:18:42 +0000 (14:18 +0100)
committerVojtech Trefny <vtrefny@redhat.com>
Tue, 10 Mar 2026 14:02:24 +0000 (15:02 +0100)
Signed-off-by: Vojtech Trefny <vtrefny@redhat.com>
13 files changed:
include/Makemodule.am
include/pt-dasd.h [new file with mode: 0644]
libblkid/meson.build
libblkid/src/Makemodule.am
libblkid/src/partitions/dasd.c [new file with mode: 0644]
libblkid/src/partitions/partitions.c
libblkid/src/partitions/partitions.h
tests/expected/blkid/lowprobe-pt-dasd-cdl [new file with mode: 0644]
tests/expected/blkid/lowprobe-pt-dasd-ldl [new file with mode: 0644]
tests/expected/partx/partx-image-dasd-cdl [new file with mode: 0644]
tests/expected/partx/partx-image-dasd-ldl [new file with mode: 0644]
tests/ts/blkid/images-pt/dasd-cdl.img.xz [new file with mode: 0644]
tests/ts/blkid/images-pt/dasd-ldl.img.xz [new file with mode: 0644]

index 143677c8b9fed68bc4577ab2fa471bb3ec2866c5..3bc77ad6e7aaf35d00c5c074ee0b8239acba0a80 100644 (file)
@@ -61,6 +61,7 @@ dist_noinst_HEADERS += \
        include/plymouth-ctrl.h \
        include/procfs.h \
        include/pt-bsd.h \
+       include/pt-dasd.h \
        include/pt-mbr.h \
        include/pt-mbr-partnames.h \
        include/pt-gpt-partnames.h \
diff --git a/include/pt-dasd.h b/include/pt-dasd.h
new file mode 100644 (file)
index 0000000..fa0f63b
--- /dev/null
@@ -0,0 +1,229 @@
+/*
+ * No copyright is claimed.  This code is in the public domain; do with
+ * it what you wish.
+ */
+#ifndef UTIL_LINUX_PT_DASD_H
+#define UTIL_LINUX_PT_DASD_H
+
+#include <stdint.h>
+#include "bitops.h"
+
+#define DASD_MAX_PARTITIONS    3
+
+#define DASD_VOL1_MAGIC                "\xe5\xd6\xd3\xf1"      /* "VOL1" in EBCDIC */
+#define DASD_LNX1_MAGIC                "\xd3\xd5\xe7\xf1"      /* "LNX1" in EBCDIC */
+#define DASD_CMS1_MAGIC                "\xc3\xd4\xe2\xf1"      /* "CMS1" in EBCDIC */
+
+#define DASD_FMT_ID_F1         0xf1
+#define DASD_FMT_ID_F4         0xf4
+#define DASD_FMT_ID_F5         0xf5
+#define DASD_FMT_ID_F7         0xf7
+#define DASD_FMT_ID_F8         0xf8
+#define DASD_FMT_ID_F9         0xf9
+
+/* Large volume compatibility cylinder threshold */
+#define DASD_LV_COMPAT_CYL     0xFFFE
+
+#define DASD_VOLSER_LENGTH     6
+
+/* Format 4 key field: 44 bytes of 0x04 */
+#define DASD_F4_KEYCD_BYTE     0x04
+#define DASD_F4_KEYCD_LENGTH   44
+
+struct dasd_cchhb {
+       uint16_t cc;
+       uint16_t hh;
+       uint8_t  b;
+} __attribute__ ((packed));
+
+struct dasd_cchh {
+       uint16_t cc;
+       uint16_t hh;
+} __attribute__ ((packed));
+
+struct dasd_extent {
+       uint8_t         typeind;
+       uint8_t         seqno;
+       struct dasd_cchh llimit;
+       struct dasd_cchh ulimit;
+} __attribute__ ((packed));
+
+/*
+ * CDL Volume Label.
+ */
+struct dasd_volume_label_cdl {
+       char            volkey[4];      /* record key*/
+       char            vollbl[4];      /* "VOL1" in EBCDIC */
+       char            volid[6];       /* volume identifier (VOLSER) */
+       uint8_t         security;
+       struct dasd_cchhb vtoc;         /* VTOC address */
+       char            res1[5];
+       char            cisize[4];
+       char            blkperci[4];
+       char            labperci[4];
+       char            res2[4];
+       char            lvtoc[14];
+       char            res3[29];
+} __attribute__ ((packed));
+
+/*
+ * LDL Volume Label.
+ */
+struct dasd_volume_label_ldl {
+       char            vollbl[4];      /* "LNX1" or "CMS1" in EBCDIC */
+       char            volid[6];       /* volume identifier (VOLSER) */
+       char            res1[69];
+       char            ldl_version;
+       uint64_t        formatted_blocks; /* for ldl_version 0xf2 */
+} __attribute__ ((packed));
+
+/*
+ * Format 1 / Format 8 DSCB (partition description)
+ */
+struct dasd_format1_label {
+       char            DS1DSNAM[44];   /* data set name (EBCDIC) */
+       uint8_t         DS1FMTID;       /* format identifier (0xf1 or 0xf8) */
+       unsigned char   DS1DSSN[6];
+       uint16_t        DS1VOLSQ;
+       uint8_t         DS1CREDT[3];
+       uint8_t         DS1EXPDT[3];
+       uint8_t         DS1NOEPV;
+       uint8_t         DS1NOBDB;
+       uint8_t         DS1FLAG1;
+       unsigned char   DS1SYSCD[13];
+       uint8_t         DS1REFD[3];
+       uint8_t         DS1SMSFG;
+       uint8_t         DS1SCXTF;
+       uint16_t        DS1SCXTV;
+       uint8_t         DS1DSRG1;
+       uint8_t         DS1DSRG2;
+       uint8_t         DS1RECFM;
+       uint8_t         DS1OPTCD;
+       uint16_t        DS1BLKL;
+       uint16_t        DS1LRECL;
+       uint8_t         DS1KEYL;
+       uint16_t        DS1RKP;
+       uint8_t         DS1DSIND;
+       uint8_t         DS1SCAL1;
+       char            DS1SCAL3[3];
+       uint8_t         DS1LSTAR[3];
+       uint16_t        DS1TRBAL;
+       uint16_t        res1;
+       struct dasd_extent DS1EXT1;
+       struct dasd_extent DS1EXT2;
+       struct dasd_extent DS1EXT3;
+       struct dasd_cchhb  DS1PTRDS;
+} __attribute__ ((packed));
+
+/*
+ * Format 4 DSCB (VTOC header with geometry information)
+ */
+struct dasd_format4_label {
+       char            DS4KEYCD[44];   /* key: 44 bytes of 0x04 */
+       uint8_t         DS4IDFMT;       /* format identifier (0xf4) */
+       struct dasd_cchhb DS4HPCHR;
+       uint16_t        DS4DSREC;
+       struct dasd_cchh  DS4HCCHH;
+       uint16_t        DS4NOATK;
+       uint8_t         DS4VTOCI;
+       uint8_t         DS4NOEXT;
+       uint8_t         DS4SMSFG;
+       uint8_t         DS4DEVAC;
+       uint16_t        DS4DSCYL;       /* number of logical cylinders */
+       uint16_t        DS4DSTRK;       /* number of tracks per cylinder */
+       uint16_t        DS4DEVTK;       /* device track length */
+       uint8_t         DS4DEVI;
+       uint8_t         DS4DEVL;
+       uint8_t         DS4DEVK;
+       uint8_t         DS4DEVFG;
+       uint16_t        DS4DEVTL;
+       uint8_t         DS4DEVDT;
+       uint8_t         DS4DEVDB;
+       char            DS4AMTIM[8];
+       char            DS4AMCAT[3];
+       char            DS4R2TIM[8];
+       char            res1[5];
+       char            DS4F6PTR[5];
+       struct dasd_extent DS4VTOCE;
+       char            res2[10];
+       uint8_t         DS4EFLVL;
+       struct dasd_cchhb  DS4EFPTR;
+       char            res3;
+       uint32_t        DS4DCYL;        /* number of logical cylinders (large volumes) */
+       char            res4[2];
+       uint8_t         DS4DEVF2;
+       char            res5;
+} __attribute__ ((packed));
+
+/*
+ * EBCDIC to ASCII conversion table.
+ */
+static const unsigned char dasd_ebcdic_to_ascii[256] __attribute__((unused)) =
+{
+/* 0x00  NUL   SOH   STX   ETX  *SEL    HT  *RNL   DEL */
+       0x00, 0x01, 0x02, 0x03, 0x07, 0x09, 0x07, 0x7F,
+/* 0x08  -GE  -SPS  -RPT    VT    FF    CR    SO    SI */
+       0x07, 0x07, 0x07, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+/* 0x10  DLE   DC1   DC2   DC3  -RES   -NL    BS  -POC */
+       0x10, 0x11, 0x12, 0x13, 0x07, 0x0A, 0x08, 0x07,
+/* 0x18  CAN    EM  -UBS  -CU1  -IFS  -IGS  -IRS  -ITB */
+       0x18, 0x19, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+/* 0x20  -DS  -SOS    FS  -WUS  -BYP    LF   ETB   ESC */
+       0x07, 0x07, 0x1C, 0x07, 0x07, 0x0A, 0x17, 0x1B,
+/* 0x28  -SA  -SFE   -SM  -CSP  -MFA   ENQ   ACK   BEL */
+       0x07, 0x07, 0x07, 0x07, 0x07, 0x05, 0x06, 0x07,
+/* 0x30 ----  ----   SYN   -IR   -PP  -TRN  -NBS   EOT */
+       0x07, 0x07, 0x16, 0x07, 0x07, 0x07, 0x07, 0x04,
+/* 0x38 -SBS   -IT  -RFF  -CU3   DC4   NAK  ----   SUB */
+       0x07, 0x07, 0x07, 0x07, 0x14, 0x15, 0x07, 0x1A,
+/* 0x40   SP   RSP */
+       0x20, 0xFF, 0x83, 0x84, 0x85, 0xA0, 0x07, 0x86,
+/* 0x48                      .     <     (     +     | */
+       0x87, 0xA4, 0x9B, 0x2E, 0x3C, 0x28, 0x2B, 0x7C,
+/* 0x50    & */
+       0x26, 0x82, 0x88, 0x89, 0x8A, 0xA1, 0x8C, 0x07,
+/* 0x58          ~     !     $     *     )     ; */
+       0x8D, 0xE1, 0x21, 0x24, 0x2A, 0x29, 0x3B, 0xAA,
+/* 0x60    -     / */
+       0x2D, 0x2F, 0x07, 0x8E, 0x07, 0x07, 0x07, 0x8F,
+/* 0x68             ----     ,     %     _     >     ? */
+       0x80, 0xA5, 0x07, 0x2C, 0x25, 0x5F, 0x3E, 0x3F,
+/* 0x70  --- */
+       0x07, 0x90, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+/* 0x78    *     `     :     #     @     '     =     " */
+       0x70, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22,
+/* 0x80    *     a     b     c     d     e     f     g */
+       0x07, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+/* 0x88    h     i */
+       0x68, 0x69, 0xAE, 0xAF, 0x07, 0x07, 0x07, 0xF1,
+/* 0x90          j     k     l     m     n     o     p */
+       0xF8, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70,
+/* 0x98    q     r */
+       0x71, 0x72, 0xA6, 0xA7, 0x91, 0x07, 0x92, 0x07,
+/* 0xA0          ~     s     t     u     v     w     x */
+       0xE6, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
+/* 0xA8    y     z */
+       0x79, 0x7A, 0xAD, 0xAB, 0x07, 0x07, 0x07, 0x07,
+/* 0xB0    ^ */
+       0x5E, 0x9C, 0x9D, 0xFA, 0x07, 0x07, 0x07, 0xAC,
+/* 0xB8       ----     [     ] */
+       0xAB, 0x07, 0x5B, 0x5D, 0x07, 0x07, 0x07, 0x07,
+/* 0xC0    {     A     B     C     D     E     F     G */
+       0x7B, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+/* 0xC8    H     I */
+       0x48, 0x49, 0x07, 0x93, 0x94, 0x95, 0xA2, 0x07,
+/* 0xD0    }     J     K     L     M     N     O     P */
+       0x7D, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50,
+/* 0xD8    Q     R */
+       0x51, 0x52, 0x07, 0x96, 0x81, 0x97, 0xA3, 0x98,
+/* 0xE0    \ */
+       0x5C, 0xF6, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
+/* 0xE8    Y     Z */
+       0x59, 0x5A, 0xFD, 0x07, 0x99, 0x07, 0x07, 0x07,
+/* 0xF0    0     1     2     3     4     5     6     7 */
+       0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+/* 0xF8    8     9 */
+       0x38, 0x39, 0x07, 0x07, 0x9A, 0x07, 0x07, 0x07
+};
+
+#endif /* UTIL_LINUX_PT_DASD_H */
index 2435692cd2d117cbe266e3227ca13c43b0a96abe..4c07b7a1e621e20535e3427148bdf9273e20f807 100644 (file)
@@ -40,6 +40,7 @@ lib_blkid_sources = '''
   src/partitions/aix.h
   src/partitions/atari.c
   src/partitions/bsd.c
+  src/partitions/dasd.c
   src/partitions/dos.c
   src/partitions/gpt.c
   src/partitions/mac.c
index ce65d502940402c6a9d2c5b935f5ca57d2211d73..5a8d1d702f44a0707be876bd5e81828e10ad7c34 100644 (file)
@@ -30,6 +30,7 @@ libblkid_la_SOURCES = \
        libblkid/src/partitions/aix.h \
        libblkid/src/partitions/atari.c \
        libblkid/src/partitions/bsd.c \
+       libblkid/src/partitions/dasd.c \
        libblkid/src/partitions/dos.c \
        libblkid/src/partitions/gpt.c \
        libblkid/src/partitions/mac.c \
diff --git a/libblkid/src/partitions/dasd.c b/libblkid/src/partitions/dasd.c
new file mode 100644 (file)
index 0000000..501a603
--- /dev/null
@@ -0,0 +1,385 @@
+/*
+ * DASD partition table probing
+ *
+ * Copyright (C) 2026 Red Hat, Inc.
+ *
+ * This file may be redistributed under the terms of the
+ * GNU Lesser General Public License.
+ *
+ * Inspired by fdasd (s390-tools), Linux kernel and libparted.
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stddef.h>
+#include <stdbool.h>
+#include <inttypes.h>
+
+#include "pt-dasd.h"
+#include "partitions.h"
+
+static void dasd_get_volser(const char *volid, char *volser)
+{
+       int i = 0;
+
+       for (i = 0; i < DASD_VOLSER_LENGTH; i++)
+               volser[i] = dasd_ebcdic_to_ascii[(unsigned char) volid[i]];
+       volser[DASD_VOLSER_LENGTH] = '\0';
+
+       /* trim trailing spaces */
+       for (i = DASD_VOLSER_LENGTH - 1; volser[i] == ' '; i--)
+               volser[i] = '\0';
+}
+
+static void dasd_get_dsnam(const struct dasd_format1_label *f1, char *dsnam)
+{
+       size_t i = 0;
+
+       for (i = 0; i < sizeof(f1->DS1DSNAM); i++)
+               dsnam[i] = dasd_ebcdic_to_ascii[(unsigned char) f1->DS1DSNAM[i]];
+       dsnam[sizeof(f1->DS1DSNAM)] = '\0';
+
+       /* trim trailing spaces */
+       for (i = sizeof(f1->DS1DSNAM) - 1; i != 0 && dsnam[i] == ' '; i--)
+               dsnam[i] = '\0';
+}
+
+/*
+ * CCHH for large volumes:
+ * - upper 12 bits of hh hold the upper cylinder bits
+ * - lower 4 bits of hh are the head number
+ */
+static uint32_t dasd_cchh_get_cc(const struct dasd_cchh *p)
+{
+       uint32_t cyl;
+
+       cyl = be16_to_cpu(p->hh) & 0xFFF0;
+       cyl <<= 12;
+       cyl |= be16_to_cpu(p->cc);
+       return cyl;
+}
+
+static uint16_t dasd_cchh_get_hh(const struct dasd_cchh *p)
+{
+       return be16_to_cpu(p->hh) & 0x000F;
+}
+
+static bool is_dasd_cdl_label(const unsigned char *buf)
+{
+       return memcmp(buf + 4, DASD_VOL1_MAGIC, 4) == 0;
+}
+
+static bool is_dasd_ldl_label(const unsigned char *buf)
+{
+       return memcmp(buf, DASD_LNX1_MAGIC, 4) == 0 ||
+              memcmp(buf, DASD_CMS1_MAGIC, 4) == 0;
+}
+
+/*
+ * Format 4: 44-byte key field filled with 0x04 + DS4IDFMT (0xf4)
+ */
+static bool is_dasd_f4_label(const unsigned char *buf)
+{
+       int i = 0;
+
+       for (i = 0; i < DASD_F4_KEYCD_LENGTH; i++) {
+               if (buf[i] != DASD_F4_KEYCD_BYTE)
+                       return false;
+       }
+       if (buf[DASD_F4_KEYCD_LENGTH] != DASD_FMT_ID_F4)
+               return false;
+
+       return true;
+}
+
+/*
+ * CDL -- up to three partitions defined by the F1/8 labels
+ */
+static int probe_dasd_pt_cdl(blkid_probe pr, blkid_partlist ls,
+                            blkid_parttable tab,
+                            unsigned int blocksize)
+{
+       const struct dasd_format4_label *f4;
+       const struct dasd_format1_label *f1;
+       const unsigned char *buf;
+       unsigned int blk_per_trk = 0;
+       uint16_t heads;
+       uint32_t cylinders;
+       unsigned int blk;
+       int partno = 0;
+
+       /*
+        * Looking for Format 4 label at blocks 3-20.
+        * On a real DASD, it is at CC=0 HH=1 R=1, which maps to
+        * linux block = blk_per_trk (one track after the start),
+        * but we don't know blk_per_trk yet.
+        */
+       for (blk = 3; blk <= 20; blk++) {
+               buf = blkid_probe_get_buffer(pr,
+                       (uint64_t) blk * blocksize,
+                       sizeof(struct dasd_format4_label));
+               if (!buf)
+                       return errno ? -errno : BLKID_PROBE_NONE;
+               if (is_dasd_f4_label(buf)) {
+                       blk_per_trk = blk;
+                       break;
+               }
+       }
+
+       if (!blk_per_trk) {
+               DBG(LOWPROBE, ul_debug("DASD: CDL detected but no F4 label found"));
+               return BLKID_PROBE_NONE;
+       }
+
+       f4 = (const struct dasd_format4_label *) buf;
+
+       heads = be16_to_cpu(f4->DS4DSTRK);
+       if (heads == 0)
+               return BLKID_PROBE_NONE;
+
+       cylinders = be16_to_cpu(f4->DS4DSCYL);
+
+       /* large volume -> use DS4DCYL */
+       if (cylinders == DASD_LV_COMPAT_CYL)
+               cylinders = be32_to_cpu(f4->DS4DCYL);
+
+       DBG(LOWPROBE, ul_debug("DASD CDL: blk_per_trk=%u heads=%u cylinders=%u blocksize=%u",
+                       blk_per_trk, heads, cylinders, blocksize));
+
+       /* scan for format 1 and format 8 labels describing the partitions */
+       for (blk = blk_per_trk + 1; blk < blk_per_trk + 20 && partno < DASD_MAX_PARTITIONS; blk++) {
+               char dsnam[sizeof(f1->DS1DSNAM) + 1];
+               char *last_dot;
+               size_t namelen;
+               uint32_t start_cc, end_cc;
+               uint16_t start_hh, end_hh;
+               uint64_t start_trk, end_trk;
+               uint64_t start_512, size_512;
+               blkid_partition par;
+
+               buf = blkid_probe_get_buffer(pr,
+                               (uint64_t) blk * blocksize,
+                               sizeof(struct dasd_format1_label));
+               if (!buf)
+                       return errno ? -errno : BLKID_PROBE_NONE;
+
+               f1 = (const struct dasd_format1_label *) buf;
+
+               /* only format 1 and 8 are valid partition descriptors */
+               if (f1->DS1FMTID != DASD_FMT_ID_F1 && f1->DS1FMTID != DASD_FMT_ID_F8)
+                       continue;
+
+               if (cylinders > DASD_LV_COMPAT_CYL) {
+                       /* large volume encoding */
+                       start_cc = dasd_cchh_get_cc(&f1->DS1EXT1.llimit);
+                       start_hh = dasd_cchh_get_hh(&f1->DS1EXT1.llimit);
+                       end_cc = dasd_cchh_get_cc(&f1->DS1EXT1.ulimit);
+                       end_hh = dasd_cchh_get_hh(&f1->DS1EXT1.ulimit);
+               } else {
+                       start_cc = be16_to_cpu(f1->DS1EXT1.llimit.cc);
+                       start_hh = be16_to_cpu(f1->DS1EXT1.llimit.hh);
+                       end_cc = be16_to_cpu(f1->DS1EXT1.ulimit.cc);
+                       end_hh = be16_to_cpu(f1->DS1EXT1.ulimit.hh);
+               }
+
+               start_trk = (uint64_t) start_cc * heads + start_hh;
+               end_trk = (uint64_t) end_cc * heads + end_hh;
+
+               if (end_trk <= start_trk)
+                       return BLKID_PROBE_NONE;
+
+               /* convert to 512 sectors */
+               start_512 = start_trk * blk_per_trk * blocksize / 512;
+               size_512 = (end_trk - start_trk + 1) * blk_per_trk * blocksize / 512;
+
+               DBG(LOWPROBE, ul_debug("DASD CDL part%d: CC=%u-%u HH=%u-%u "
+                               "trk=%"PRIu64"-%"PRIu64" start=%"PRIu64" size=%"PRIu64,
+                               partno + 1, start_cc, end_cc, start_hh, end_hh,
+                               start_trk, end_trk, start_512, size_512));
+
+               par = blkid_partlist_add_partition(ls, tab, start_512, size_512);
+               if (!par)
+                       return -ENOMEM;
+
+               dasd_get_dsnam(f1, dsnam);
+
+               /* split dsnam into name and type at the last '.' */
+               last_dot = strrchr(dsnam, '.');
+               if (last_dot) {
+                       namelen = min((size_t)(last_dot - dsnam), sizeof(dsnam) - 1);
+                       blkid_partition_set_name(par, (unsigned char *) dsnam, namelen);
+                       blkid_partition_set_type_string(par, (unsigned char *) last_dot + 1,
+                                                       strlen(last_dot + 1));
+               } else {
+                       blkid_partition_set_type_string(par, (unsigned char *) dsnam,
+                                                       strlen(dsnam));
+               }
+
+               partno++;
+       }
+
+       return BLKID_PROBE_OK;
+}
+
+/*
+ * LDL -- single implicit partition starting at block 3
+ */
+static int probe_dasd_pt_ldl(blkid_probe pr, blkid_partlist ls,
+                            blkid_parttable tab,
+                            const struct dasd_volume_label_ldl *vlabel,
+                            unsigned int blocksize)
+{
+       uint64_t start_512, size_512;
+       uint64_t blocks;
+       blkid_partition par;
+
+       start_512 = (uint64_t) 3 * blocksize / 512;
+
+       if ((unsigned char) vlabel->ldl_version >= 0xf2) {
+               blocks = be64_to_cpu(vlabel->formatted_blocks);
+               if (blocks <= 3) {
+                       DBG(LOWPROBE, ul_debug("DASD LDL: invalid formatted_blocks %"PRIu64, blocks));
+                       return BLKID_PROBE_NONE;
+               }
+               size_512 = (blocks - 3) * blocksize / 512;
+       } else {
+               size_512 = blkid_probe_get_size(pr) / 512 - start_512;
+       }
+
+       DBG(LOWPROBE, ul_debug("DASD LDL: start=%"PRIu64" size=%"PRIu64" blocksize=%u",
+                       start_512, size_512, blocksize));
+
+       par = blkid_partlist_add_partition(ls, tab, start_512, size_512);
+       if (!par)
+               return -ENOMEM;
+
+       return BLKID_PROBE_OK;
+}
+
+static const unsigned int dasd_blocksizes[] = { 4096, 2048, 1024, 512 };
+
+static int probe_dasd_pt(blkid_probe pr,
+               const struct blkid_idmag *mag __attribute__((__unused__)))
+{
+       const unsigned char *buf;
+       blkid_parttable tab = NULL;
+       blkid_partlist ls;
+       char volser[DASD_VOLSER_LENGTH + 1];
+       unsigned int blocksize;
+       bool is_cdl = false;
+       bool is_ldl = false;
+       const struct dasd_volume_label_cdl *cdl = NULL;
+       const struct dasd_volume_label_ldl *ldl = NULL;
+       const char *magic;
+       int rc;
+       size_t i = 0;
+
+       blocksize = blkid_probe_get_sectorsize(pr);
+       buf = blkid_probe_get_buffer(pr,
+                       (uint64_t) 2 * blocksize,
+                       sizeof(struct dasd_volume_label_ldl));
+       if (!buf)
+               return errno ? -errno : BLKID_PROBE_NONE;
+
+       /* CDL -- "VOL1" at byte 4 */
+       if (is_dasd_cdl_label(buf))
+               is_cdl = true;
+       /* LDL -- "LNX1" or "CMS1" at byte 0 */
+       else if (is_dasd_ldl_label(buf))
+               is_ldl = true;
+
+       /*
+        * check the other known DASD block sizes as well in case we are
+        * scanning e.g. 512 disk image
+        */
+       if (!is_cdl && !is_ldl) {
+               for (i = 0; i < ARRAY_SIZE(dasd_blocksizes); i++) {
+                       if (dasd_blocksizes[i] == blocksize)
+                               continue;
+
+                       buf = blkid_probe_get_buffer(pr,
+                                       (uint64_t) 2 * dasd_blocksizes[i],
+                                       sizeof(struct dasd_volume_label_ldl));
+                       if (!buf) {
+                               if (errno)
+                                       return -errno;
+                               continue;
+                       }
+
+                       if (is_dasd_cdl_label(buf)) {
+                               is_cdl = true;
+                               blocksize = dasd_blocksizes[i];
+                               break;
+                       }
+                       if (is_dasd_ldl_label(buf)) {
+                               is_ldl = true;
+                               blocksize = dasd_blocksizes[i];
+                               break;
+                       }
+               }
+       }
+
+       if (!is_cdl && !is_ldl)
+               return BLKID_PROBE_NONE;
+
+       DBG(LOWPROBE, ul_debug("DASD: %s label detected (blocksize=%u)",
+                       is_cdl ? "CDL" : "LDL", blocksize));
+
+       if (is_cdl) {
+               cdl = (const struct dasd_volume_label_cdl *) buf;
+
+               if (blkid_probe_set_magic(pr,
+                               (uint64_t) 2 * blocksize +
+                                       offsetof(struct dasd_volume_label_cdl, vollbl),
+                               4, (const unsigned char *) DASD_VOL1_MAGIC))
+                       return BLKID_PROBE_NONE;
+
+               dasd_get_volser(cdl->volid, volser);
+       } else {
+               ldl = (const struct dasd_volume_label_ldl *) buf;
+               magic = memcmp(buf, DASD_LNX1_MAGIC, 4) == 0 ? DASD_LNX1_MAGIC : DASD_CMS1_MAGIC;
+
+               if (blkid_probe_set_magic(pr,
+                               (uint64_t) 2 * blocksize +
+                                       offsetof(struct dasd_volume_label_ldl, vollbl),
+                               4, (const unsigned char *) magic))
+                       return BLKID_PROBE_NONE;
+
+               dasd_get_volser(ldl->volid, volser);
+       }
+
+       blkid_partitions_strcpy_ptuuid(pr, volser);
+
+       if (blkid_partitions_need_typeonly(pr))
+               return BLKID_PROBE_OK;
+
+       ls = blkid_probe_get_partlist(pr);
+       if (!ls)
+               return BLKID_PROBE_NONE;
+
+       tab = blkid_partlist_new_parttable(ls, "dasd", 0);
+       if (!tab)
+               return -ENOMEM;
+
+       blkid_parttable_set_id(tab, (unsigned char *) volser);
+
+       if (is_cdl)
+               rc = probe_dasd_pt_cdl(pr, ls, tab, blocksize);
+       else
+               rc = probe_dasd_pt_ldl(pr, ls, tab, ldl, blocksize);
+
+       return rc;
+}
+
+const struct blkid_idinfo dasd_pt_idinfo =
+{
+       .name           = "dasd",
+       .probefunc      = probe_dasd_pt,
+
+       /*
+        * magic location unfortunately depends on the device geometry and
+        * DASD version and format (CDL or LDL)
+        */
+       .magics         = BLKID_NONE_MAGIC
+};
index e838b3db1f7e4d6db5ab477165b085da5b937f1f..29897f17c125b4c8b4a5bb5ea723f5ae45f1bba2 100644 (file)
@@ -136,7 +136,8 @@ static const struct blkid_idinfo *idinfos[] =
        &unixware_pt_idinfo,
        &solaris_x86_pt_idinfo,
        &minix_pt_idinfo,
-       &atari_pt_idinfo
+       &atari_pt_idinfo,
+       &dasd_pt_idinfo,
 };
 
 /*
index 784e0c0e3349edd449b32bc2fbb3d619fe52ccd8..c6f881b6da7e9d54100300c5aba40c5336ff0a26 100644 (file)
@@ -70,5 +70,6 @@ extern const struct blkid_idinfo gpt_pt_idinfo;
 extern const struct blkid_idinfo pmbr_pt_idinfo;
 extern const struct blkid_idinfo ultrix_pt_idinfo;
 extern const struct blkid_idinfo atari_pt_idinfo;
+extern const struct blkid_idinfo dasd_pt_idinfo;
 
 #endif /* BLKID_PARTITIONS_H */
diff --git a/tests/expected/blkid/lowprobe-pt-dasd-cdl b/tests/expected/blkid/lowprobe-pt-dasd-cdl
new file mode 100644 (file)
index 0000000..02fa407
--- /dev/null
@@ -0,0 +1,4 @@
+size: 20971520, sector size: 512, PT: dasd, offset: 0, id=0X3726
+---
+#1:        192       4032  0x0 name='LINUX.V0X3726.PART0001' type='NATIVE'
+#2:       4224       4032  0x0 name='LINUX.V0X3726.PART0002' type='NATIVE'
diff --git a/tests/expected/blkid/lowprobe-pt-dasd-ldl b/tests/expected/blkid/lowprobe-pt-dasd-ldl
new file mode 100644 (file)
index 0000000..c534d24
--- /dev/null
@@ -0,0 +1,3 @@
+size: 20971520, sector size: 512, PT: dasd, offset: 0, id=0X3526
+---
+#1:         24   14424456  0x0
diff --git a/tests/expected/partx/partx-image-dasd-cdl b/tests/expected/partx/partx-image-dasd-cdl
new file mode 100644 (file)
index 0000000..efeec66
--- /dev/null
@@ -0,0 +1,3 @@
+NR START  END SECTORS SIZE NAME                   UUID
+ 1   192 4223    4032   2M LINUX.V0X3726.PART0001 
+ 2  4224 8255    4032   2M LINUX.V0X3726.PART0002 
diff --git a/tests/expected/partx/partx-image-dasd-ldl b/tests/expected/partx/partx-image-dasd-ldl
new file mode 100644 (file)
index 0000000..465c5f5
--- /dev/null
@@ -0,0 +1,2 @@
+NR START      END  SECTORS SIZE NAME UUID
+ 1    24 14424479 14424456 6.9G      
diff --git a/tests/ts/blkid/images-pt/dasd-cdl.img.xz b/tests/ts/blkid/images-pt/dasd-cdl.img.xz
new file mode 100644 (file)
index 0000000..8cb1152
Binary files /dev/null and b/tests/ts/blkid/images-pt/dasd-cdl.img.xz differ
diff --git a/tests/ts/blkid/images-pt/dasd-ldl.img.xz b/tests/ts/blkid/images-pt/dasd-ldl.img.xz
new file mode 100644 (file)
index 0000000..8fdcaab
Binary files /dev/null and b/tests/ts/blkid/images-pt/dasd-ldl.img.xz differ