summaryrefslogtreecommitdiff
path: root/lib/pttype.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/pttype.c')
-rw-r--r--lib/pttype.c292
1 files changed, 292 insertions, 0 deletions
diff --git a/lib/pttype.c b/lib/pttype.c
new file mode 100644
index 0000000..c2294f1
--- /dev/null
+++ b/lib/pttype.c
@@ -0,0 +1,292 @@
+/*
+ * Based on libdisk from xfsprogs and Linux fdisk.
+ *
+ * Copyright (c) 2000-2001 Silicon Graphics, Inc.
+ * Copyright (C) 2009 Karel Zak <kzak@redhat.com>
+ */
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <stdlib.h>
+
+#include "blkdev.h"
+
+/* we need to read two sectors, beacuse BSD label offset is 512 */
+#define PTTYPE_BUFSIZ (2 * DEFAULT_SECTOR_SIZE) /* 1024 */
+
+/*
+ * SGI
+ */
+struct sgi_device_parameter { /* 48 bytes */
+ unsigned char skew;
+ unsigned char gap1;
+ unsigned char gap2;
+ unsigned char sparecyl;
+ unsigned short pcylcount;
+ unsigned short head_vol0;
+ unsigned short ntrks; /* tracks in cyl 0 or vol 0 */
+ unsigned char cmd_tag_queue_depth;
+ unsigned char unused0;
+ unsigned short unused1;
+ unsigned short nsect; /* sectors/tracks in cyl 0 or vol 0 */
+ unsigned short bytes;
+ unsigned short ilfact;
+ unsigned int flags; /* controller flags */
+ unsigned int datarate;
+ unsigned int retries_on_error;
+ unsigned int ms_per_word;
+ unsigned short xylogics_gap1;
+ unsigned short xylogics_syncdelay;
+ unsigned short xylogics_readdelay;
+ unsigned short xylogics_gap2;
+ unsigned short xylogics_readgate;
+ unsigned short xylogics_writecont;
+};
+
+#define SGI_VOLHDR 0x00
+/* 1 and 2 were used for drive types no longer supported by SGI */
+#define SGI_SWAP 0x03
+/* 4 and 5 were for filesystem types SGI haven't ever supported on MIPS CPUs */
+#define SGI_VOLUME 0x06
+#define SGI_EFS 0x07
+#define SGI_LVOL 0x08
+#define SGI_RLVOL 0x09
+#define SGI_XFS 0x0a
+#define SGI_XFSLOG 0x0b
+#define SGI_XLV 0x0c
+#define SGI_XVM 0x0d
+#define ENTIRE_DISK SGI_VOLUME
+/*
+ * controller flags
+ */
+#define SECTOR_SLIP 0x01
+#define SECTOR_FWD 0x02
+#define TRACK_FWD 0x04
+#define TRACK_MULTIVOL 0x08
+#define IGNORE_ERRORS 0x10
+#define RESEEK 0x20
+#define CMDTAGQ_ENABLE 0x40
+
+struct sgi_volume_header {
+ unsigned int magic; /* expect SGI_LABEL_MAGIC */
+ unsigned short boot_part; /* active boot partition */
+ unsigned short swap_part; /* active swap partition */
+ unsigned char boot_file[16]; /* name of the bootfile */
+ struct sgi_device_parameter devparam; /* 1 * 48 bytes */
+ struct volume_directory { /* 15 * 16 bytes */
+ unsigned char vol_file_name[8]; /* a character array */
+ unsigned int vol_file_start; /* number of logical block */
+ unsigned int vol_file_size; /* number of bytes */
+ } directory[15];
+ struct sgi_partition { /* 16 * 12 bytes */
+ unsigned int num_sectors; /* number of blocks */
+ unsigned int start_sector; /* must be cylinder aligned */
+ unsigned int id;
+ } partitions[16];
+ unsigned int csum;
+ unsigned int fillbytes;
+};
+
+#define SGI_LABEL_MAGIC 0x0be5a941
+
+static uint32_t
+twos_complement_32bit_sum(u_int32_t *base, int size)
+{
+ int i;
+ u_int32_t sum = 0;
+
+ size = size / sizeof(u_int32_t);
+ for (i = 0; i < size; i++)
+ sum = sum - ntohl(base[i]);
+ return sum;
+}
+
+static int
+sgi_parttable(unsigned char *base)
+{
+ u_int32_t csum;
+ struct sgi_volume_header *vh = (struct sgi_volume_header *) base;
+
+ if (ntohl(vh->magic) != SGI_LABEL_MAGIC)
+ return 0;
+ csum = twos_complement_32bit_sum((uint32_t *)vh,
+ sizeof(struct sgi_volume_header));
+ return !csum;
+}
+
+/*
+ * DOS
+ */
+static int
+dos_parttable(unsigned char *base)
+{
+ return (base[510] == 0x55 && base[511] == 0xaa);
+}
+
+/*
+ * AIX
+ */
+typedef struct {
+ unsigned int magic; /* expect AIX_LABEL_MAGIC */
+ /* ... */
+} aix_partition;
+
+#define AIX_LABEL_MAGIC 0xc9c2d4c1
+#define AIX_LABEL_MAGIC_SWAPPED 0xc1d4c2c9
+#define aixlabel(x) ((aix_partition *)x)
+
+static int
+aix_parttable(unsigned char *base)
+{
+ return (aixlabel(base)->magic == AIX_LABEL_MAGIC ||
+ aixlabel(base)->magic == AIX_LABEL_MAGIC_SWAPPED);
+}
+
+/*
+ * SUN
+ */
+typedef struct {
+ unsigned char info[128]; /* Informative text string */
+ unsigned char spare0[14];
+ struct sun_info {
+ unsigned char spare1;
+ unsigned char id;
+ unsigned char spare2;
+ unsigned char flags;
+ } infos[8];
+ unsigned char spare1[246]; /* Boot information etc. */
+ unsigned short rspeed; /* Disk rotational speed */
+ unsigned short pcylcount; /* Physical cylinder count */
+ unsigned short sparecyl; /* extra sects per cylinder */
+ unsigned char spare2[4]; /* More magic... */
+ unsigned short ilfact; /* Interleave factor */
+ unsigned short ncyl; /* Data cylinder count */
+ unsigned short nacyl; /* Alt. cylinder count */
+ unsigned short ntrks; /* Tracks per cylinder */
+ unsigned short nsect; /* Sectors per track */
+ unsigned char spare3[4]; /* Even more magic... */
+ struct sun_partition {
+ u_int32_t start_cylinder;
+ u_int32_t num_sectors;
+ } partitions[8];
+ unsigned short magic; /* Magic number */
+ unsigned short csum; /* Label xor'd checksum */
+} sun_partition;
+
+#define SUN_LABEL_MAGIC 0xDABE
+#define SUN_LABEL_MAGIC_SWAPPED 0xBEDA
+#define sunlabel(x) ((sun_partition *)x)
+
+static int
+sun_parttable(unsigned char *base)
+{
+ unsigned short *ush;
+ int csum = 0;
+
+ if (sunlabel(base)->magic != SUN_LABEL_MAGIC &&
+ sunlabel(base)->magic != SUN_LABEL_MAGIC_SWAPPED)
+ return csum;
+ ush = ((unsigned short *) (sunlabel(base) + 1)) - 1;
+ while (ush >= (unsigned short *)sunlabel(base))
+ csum ^= *ush--;
+ return !csum;
+}
+
+/*
+ * MAC
+ */
+typedef struct {
+ unsigned short magic;
+ /* ... */
+} mac_partition;
+
+#define MAC_LABEL_MAGIC 0x4552
+#define MAC_PARTITION_MAGIC 0x504d
+#define MAC_OLD_PARTITION_MAGIC 0x5453
+#define maclabel(x) ((mac_partition *)x)
+
+static int
+mac_parttable(unsigned char *base)
+{
+ return (ntohs(maclabel(base)->magic) == MAC_LABEL_MAGIC ||
+ ntohs(maclabel(base)->magic) == MAC_PARTITION_MAGIC ||
+ ntohs(maclabel(base)->magic) == MAC_OLD_PARTITION_MAGIC);
+}
+
+/*
+ * BSD subpartitions listed in a disklabel, under a dos-like partition.
+ */
+#define BSD_DISKMAGIC 0x82564557UL /* The disk magic number */
+#define BSD_DISKMAGIC_SWAPED 0x57455682UL
+struct bsd_disklabel {
+ uint32_t magic; /* the magic number */
+ /* ... */
+};
+
+static int
+bsd_parttable(unsigned char *base)
+{
+ struct bsd_disklabel *l = (struct bsd_disklabel *)
+ (base + (DEFAULT_SECTOR_SIZE * 1));
+
+ return (l->magic == BSD_DISKMAGIC || l->magic == BSD_DISKMAGIC_SWAPED);
+}
+
+const char *
+get_pt_type_fd(int fd)
+{
+ char *type = NULL;
+ unsigned char buf[PTTYPE_BUFSIZ];
+
+ if (read(fd, buf, PTTYPE_BUFSIZ) != PTTYPE_BUFSIZ)
+ ;
+ else {
+ if (sgi_parttable(buf))
+ type = "SGI";
+ else if (sun_parttable(buf))
+ type = "Sun";
+ else if (aix_parttable(buf))
+ type = "AIX";
+ else if (dos_parttable(buf))
+ type = "DOS";
+ else if (mac_parttable(buf))
+ type = "Mac";
+ else if (bsd_parttable(buf))
+ type = "BSD";
+ }
+ return type;
+}
+
+const char *
+get_pt_type(const char *device)
+{
+ int fd;
+ const char *type;
+
+ fd = open(device, O_RDONLY);
+ if (fd == -1)
+ return NULL;
+ type = get_pt_type_fd(fd);
+ close(fd);
+ return type;
+}
+
+#ifdef TEST_PROGRAM
+int
+main(int argc, char **argv)
+{
+ const char *type;
+
+ if (argc < 2) {
+ fprintf(stderr, "usage: %s <device>\n", argv[0]);
+ exit(EXIT_FAILURE);
+ }
+
+ type = get_pt_type(argv[1]);
+ if (type)
+ printf("Partition type: %s\n", type);
+ exit(EXIT_SUCCESS);
+}
+#endif