zipl: refactor zipl_helper.device-mapper

This is used by the next patches in the series to support mirror
setups not including boot sectors (e.g. mirrors over partitions).

. Rework the core procedure of device resolution (by walking along
  the device-mapper tree during logical device resolution) to be an
  explicit sequence of pairs (level-lookup, goto-parent-level);
. Add an "extended" device to keep a track of file system offset
  while ascending the device tree;
. Identify all possible results of a single level lookup;
. Rename target_entry to dmpath_entry;
. Make the main() function to look like a call of a handler
  identified by a pair (driver-id, util-id) and found by the name
  of the executable.

Signed-off-by: Eduard Shishkin <edward6@linux.ibm.com>
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
This commit is contained in:
Eduard Shishkin
2023-09-20 17:03:54 +02:00
committed by Steffen Eiden
parent 9cfaac58ea
commit 670bf3e870

View File

@@ -49,6 +49,7 @@
#include <sys/sysmacros.h>
#include <sys/types.h>
#include <unistd.h>
#include <assert.h>
#include "lib/dasd_base.h"
#include "lib/util_base.h"
@@ -84,16 +85,16 @@ struct target {
struct util_list_node list;
};
struct target_entry {
dev_t device;
struct target *target;
struct util_list_node list;
/* "extended" device */
struct ext_dev {
dev_t dev;
unsigned long fs_off; /* file system start */
};
struct physical_device {
dev_t device;
unsigned long offset;
struct util_list *target_list;
struct dmpath_entry {
struct ext_dev dev;
struct target *target;
struct util_list_node list;
};
struct device_characteristics {
@@ -104,6 +105,31 @@ struct device_characteristics {
struct hd_geometry geo;
};
struct physical_device {
unsigned long offset;
struct util_list *dmpath;
struct device_characteristics dc;
};
enum driver_id {
DM_DRIVER_ID,
LAST_DRIVER_ID
};
enum util_id {
ZIPL_UTIL_ID,
CHREIPL_UTIL_ID,
LAST_UTIL_ID
};
struct helper {
int util_id;
int driver_id;
const char *name;
int (*check_usage)(int argc, char *argv[]);
int (*print_params)(char *argv[], struct helper *h);
};
/* From include/linux/fs.h */
#define BDEVNAME_SIZE 32
@@ -112,8 +138,6 @@ struct device_characteristics {
#define DASD_PARTN_MASK 0x03
#define SCSI_PARTN_MASK 0x0f
#define CHREIPL_HELPER "chreipl_helper.device-mapper"
/* Internal constants */
enum dev_type {
DEV_TYPE_CDL = 0,
@@ -128,6 +152,14 @@ enum target_type {
TARGET_TYPE_MULTIPATH
};
enum lookup_result {
DM_LOOKUP_ERROR,
DM_EMPTY_TABLE,
DM_NO_TARGET,
DM_SINGLE_TARGET,
DM_MULTIPLE_TARGETS
};
static void get_type_name(char *name, unsigned short type)
{
switch (type) {
@@ -217,40 +249,52 @@ static unsigned long target_get_start(struct target *target)
{
struct target_data *td = util_list_start(target->data);
return td->start;
return target->start + td->start;
}
static void target_get_major_minor(struct target *target, unsigned int *major,
unsigned int *minor)
/*
* Return the first device from those that constitute the logical TARGET
*/
static dev_t first_device_by_target_data(struct target *target)
{
struct target_data *td = util_list_start(target->data);
*major = major(td->device);
*minor = minor(td->device);
return td->device;
}
static struct target_entry *target_entry_new(dev_t dev, struct target *target)
static struct dmpath_entry *dmpath_entry_new(struct ext_dev *dev,
struct target *target)
{
struct target_entry *te = util_malloc(sizeof(struct target_entry));
struct dmpath_entry *de = util_malloc(sizeof(struct dmpath_entry));
te->device = dev;
te->target = target;
return te;
de->dev = *dev;
de->target = target;
return de;
}
static void target_entry_free(struct target_entry *entry)
static void dmpath_entry_free(struct dmpath_entry *entry)
{
target_free(entry->target);
free(entry);
}
static struct target_entry *target_list_get_first_by_type(struct util_list *target_list,
unsigned short type)
static void dmpath_free(struct util_list *dmpath)
{
struct target_entry *te;
struct dmpath_entry *de, *n;
util_list_iterate(target_list, te) {
util_list_iterate_safe(dmpath, de, n) {
util_list_remove(dmpath, de);
dmpath_entry_free(de);
}
util_list_free(dmpath);
}
static struct dmpath_entry *dmpath_get_first_by_type(struct util_list *dmpath,
unsigned short type)
{
struct dmpath_entry *te;
util_list_iterate(dmpath, te) {
if (te->target->type == type)
return te;
}
@@ -258,17 +302,6 @@ static struct target_entry *target_list_get_first_by_type(struct util_list *targ
return NULL;
}
static void target_list_free(struct util_list *target_list)
{
struct target_entry *te, *n;
util_list_iterate_safe(target_list, te, n) {
util_list_remove(target_list, te);
target_entry_free(te);
}
util_list_free(target_list);
}
static void get_device_name(char *devname, dev_t dev)
{
struct util_proc_part_entry entry;
@@ -454,11 +487,10 @@ static struct util_list *get_mirror_data(const char *devname, char *args)
long nlogs, ndevs, nfeats, base_offset = -1;
SKIP_TOKEN_OR_GOTO(args, out); /* log_type */
NEXT_INT_TOKEN_OR_GOTO(nlogs, out); /* #log_args */
SKIP_NEXT_TOKENS_OR_GOTO(nlogs, out); /* log_args* */
NEXT_INT_TOKEN_OR_GOTO(ndevs, out);
for (; ndevs > 0; ndevs--) {
unsigned int major, minor;
long offset;
@@ -690,6 +722,8 @@ static void table_free(struct util_list *table)
{
struct target *target, *n;
if (!table)
return;
util_list_iterate_safe(table, target, n) {
util_list_remove(table, target);
target_free(target);
@@ -697,6 +731,10 @@ static void table_free(struct util_list *table)
util_list_free(table);
}
/**
* Remove all targets which don't maintain bytes in the interval
* [start,start+length-1] from the TABLE
*/
static void filter_table(struct util_list *table, unsigned int start,
unsigned int length)
{
@@ -711,23 +749,22 @@ static void filter_table(struct util_list *table, unsigned int start,
}
}
/*
/**
* Return list of target devices
*/
static struct util_list *get_table(dev_t dev)
static int get_table(dev_t dev, struct util_list **table)
{
char devname[BDEVNAME_SIZE];
struct util_list *table;
char *line = NULL;
size_t n = 0;
FILE *fp;
table = util_list_new(struct target, list);
*table = util_list_new(struct target, list);
fp = exec_cmd_and_get_out_stream("dmsetup table -j %u -m %u 2>/dev/null",
major(dev), minor(dev));
if (fp == NULL)
return table;
return 0;
get_device_name(devname, dev);
while (getline(&line, &n, fp) != -1) {
@@ -742,7 +779,6 @@ static struct util_list *get_table(dev_t dev)
devname);
goto out;
}
if (strcmp(type, "linear") == 0) {
data = get_linear_data(devname, args);
ttype = TARGET_TYPE_LINEAR;
@@ -761,20 +797,17 @@ static struct util_list *get_table(dev_t dev)
free(args);
if (data == NULL)
goto out;
util_list_add_tail(table, target_new(start, length, ttype, data));
util_list_add_tail(*table, target_new(start, length, ttype, data));
}
free(line);
pclose(fp);
return table;
return 0;
out:
free(line);
pclose(fp);
table_free(table);
return NULL;
table_free(*table);
*table = NULL;
return -1;
}
static bool is_dasd(unsigned short type)
@@ -783,88 +816,137 @@ static bool is_dasd(unsigned short type)
(type == DEV_TYPE_FBA);
}
static int get_physical_device(struct physical_device *pd, dev_t dev,
const char *directory)
/**
* Remove TARGET from TABLE and add it to DMPATH
*/
static void target_move(struct target *target, struct ext_dev *dev,
struct util_list **table,
struct util_list *dmpath)
{
struct util_list *target_list = NULL;
struct util_list *table = NULL;
unsigned int start, length;
struct target *target;
table = get_table(dev);
if (table == NULL || util_list_is_empty(table)) {
char devname[BDEVNAME_SIZE];
get_device_name(devname, dev);
ERR("Could not retrieve device-mapper information for device "
"'%s'\n", devname);
if (table != NULL)
table_free(table);
return -1;
}
target = util_list_start(table);
/* Filesystem must be on a single dm target */
if (util_list_next(table, target) != NULL) {
ERR("Unsupported setup: Directory '%s' is located on a "
"multi-target device-mapper device\n", directory);
table_free(table);
return -1;
}
util_list_remove(table, target);
table_free(table);
target_list = util_list_new(struct target_entry, list);
util_list_add_head(target_list, target_entry_new(dev, target));
start = target->start;
length = target->length;
while (true) {
unsigned int major, minor;
/* Convert fs_start to offset on parent dm device */
start += target_get_start(target);
target_get_major_minor(target, &major, &minor);
table = get_table(makedev(major, minor));
/* Found non-dm device */
if (table == NULL || util_list_is_empty(table)) {
pd->device = makedev(major, minor);
pd->offset = start;
pd->target_list = target_list;
if (table != NULL)
table_free(table);
return 0;
}
/* Get target in parent table which contains filesystem.
* We are interested only in targets between
* [start,start+length-1].
*/
filter_table(table, start, length);
target = util_list_start(table);
if (target == NULL || util_list_next(table, target) != NULL) {
ERR("Unsupported setup: Could not map directory '%s' "
"to a single physical device\n", directory);
table_free(table);
target_list_free(target_list);
return -1;
}
util_list_remove(table, target);
util_list_add_head(target_list,
target_entry_new(makedev(major, minor), target));
table_free(table);
/* Convert fs_start to offset on parent target */
start += target->start;
}
util_list_remove(*table, target);
table_free(*table);
*table = NULL;
util_list_add_head(dmpath, dmpath_entry_new(dev, target));
}
static int get_major_minor(dev_t *dev, const char *filename)
/**
* Look for a TARGET in a device-mapper's TABLE on the parent level by DEVICE
*/
static int lookup_parent(dev_t device, struct util_list **table,
struct target **target,
void (*filter_table_fn)(struct util_list *table,
unsigned int start,
unsigned int len),
unsigned int start, unsigned int len)
{
if (get_table(device, table))
return DM_LOOKUP_ERROR;
if (*table == NULL || util_list_is_empty(*table))
return DM_EMPTY_TABLE;
/* optionally apply filter to the table */
if (filter_table_fn)
filter_table_fn(*table, start, len);
*target = util_list_start(*table);
if (*target == NULL)
return DM_NO_TARGET;
if (util_list_next(*table, *target) != NULL)
return DM_MULTIPLE_TARGETS;
return DM_SINGLE_TARGET;
}
/**
* Starting from DEVICE go upward the device tree and find the topmost
* device, which is not a logical device managed by device-mapper driver.
*
* On success: return the whole path traveled. Data of the topmost target
* in that path consists of non-dm devices.
* FS_START contains file system offset on the topmost dm-device.
*
* BOTTOM: the logical device at the lowest level from which the ascent
* begins.
*/
static struct util_list *dmpath_walk(struct ext_dev *bottom, const char *dir,
unsigned long *fs_start)
{
struct util_list *dmpath = util_list_new(struct dmpath_entry, list);
struct util_list *table = NULL;
struct ext_dev top = *bottom;
char devname[BDEVNAME_SIZE];
struct target *target;
unsigned int length;
int ret;
ret = lookup_parent(top.dev, &table, &target, NULL, 0, 0);
switch (ret) {
case DM_LOOKUP_ERROR:
goto error;
case DM_EMPTY_TABLE:
get_device_name(devname, top.dev);
ERR("Could not retrieve device-mapper information for device "
"'%s'\n", devname);
goto error;
case DM_NO_TARGET:
/* impossible: table is not empty and no filter was applied */
assert(0);
goto error;
case DM_MULTIPLE_TARGETS:
ERR("Unsupported setup: Directory '%s' is located on a "
"multi-target device-mapper device\n", dir);
goto error;
case DM_SINGLE_TARGET:
break;
}
length = target->length;
while (true) {
target_move(target, &top, &table, dmpath);
/*
* Go to the upper level.
* First, select the first device from those that constitute
* the logical target (which is the "point of branching" in
* the device tree).
*/
top.dev = first_device_by_target_data(target);
top.fs_off += target_get_start(target);
/*
* look for a target maintaining bytes in the interval
* [fs_off, fs_off+length - 1] on the parent level
*/
ret = lookup_parent(top.dev, &table, &target,
filter_table, top.fs_off, length);
switch (ret) {
case DM_LOOKUP_ERROR:
goto error;
case DM_EMPTY_TABLE:
/* Found non-dm device */
table_free(table);
*fs_start = top.fs_off;
return dmpath;
case DM_NO_TARGET:
/* break through */
case DM_MULTIPLE_TARGETS:
ERR("Unsupported setup: Could not map directory '%s' "
"to a single physical device\n", dir);
goto error;
case DM_SINGLE_TARGET:
break;
}
}
error:
table_free(table);
dmpath_free(dmpath);
return NULL;
}
static int get_physical_device(struct physical_device *pd, struct ext_dev *dev,
const char *dir)
{
pd->dmpath = dmpath_walk(dev, dir, &pd->offset);
return pd->dmpath == NULL ? -1 : 0;
}
static int device_by_filename(dev_t *dev, const char *filename)
{
struct stat buf;
@@ -873,51 +955,43 @@ static int get_major_minor(dev_t *dev, const char *filename)
return -1;
}
*dev = buf.st_dev;
return 0;
}
static int get_physical_device_dir(struct physical_device *pd,
const char *directory)
static struct dmpath_entry *get_top_entry(struct physical_device *pd)
{
dev_t dev;
if (get_major_minor(&dev, directory) != 0)
return -1;
return get_physical_device(pd, dev, directory);
return util_list_start(pd->dmpath);
}
static int get_target_base(dev_t *base, dev_t bottom, unsigned int length,
struct util_list *target_list)
/**
* Find the topmost entry in the DMPATH, which provides access to
* the boot sectors
*/
static struct dmpath_entry *find_base_entry(struct util_list *dmpath,
unsigned int nr_boot_sectors)
{
struct target_entry *te, *tm;
dev_t top = bottom;
struct dmpath_entry *te, *tm, *top;
util_list_iterate(target_list, te) {
if ((te->target->start != 0) ||
(target_get_start(te->target) != 0) ||
(te->target->length < length)) {
top = util_list_start(dmpath);
util_list_iterate(dmpath, te) {
if (target_get_start(te->target) != 0 ||
te->target->length < nr_boot_sectors)
break;
}
top = te->device;
top = te;
}
/* Check for mirroring between base device and fs device */
for (tm = te; tm != NULL; tm = util_list_next(target_list, tm)) {
for (tm = te; tm != NULL; tm = util_list_next(dmpath, tm)) {
if (tm->target->type == TARGET_TYPE_MIRROR) {
char name[BDEVNAME_SIZE];
get_device_name(name, tm->device);
get_device_name(name, tm->dev.dev);
ERR("Unsupported setup: Block 0 is not mirrored in "
"device '%s'\n", name);
return -1;
return NULL;
}
}
*base = top;
return 0;
return top;
}
static inline dev_t get_partition_base(unsigned short type, dev_t dev)
@@ -929,138 +1003,252 @@ static inline dev_t get_partition_base(unsigned short type, dev_t dev)
static int extract_major_minor_from_cmdline(char *argv[], unsigned int *major,
unsigned int *minor)
{
if (sscanf(argv[1], "%u:%u", major, minor) != 2) {
if (sscanf(argv[1], "%u:%u", major, minor) != 2)
return -1;
}
return 0;
}
static bool toolname_is_chreipl_helper(const char *toolname)
static bool toolname_is(const char *toolname, const char *what)
{
int clen = strlen(CHREIPL_HELPER);
int wlen = strlen(what);
int tlen = strlen(toolname);
if (tlen < clen)
if (tlen < wlen)
return false;
return strcmp(toolname + tlen - clen, CHREIPL_HELPER) == 0;
return strcmp(toolname + tlen - wlen, what) == 0;
}
static void print_usage(const char *toolname)
static void print_usage_zipl_helper(const char *toolname)
{
fprintf(stderr, "%s <major:minor of target device>", toolname);
if (!toolname_is_chreipl_helper(toolname))
fprintf(stderr, " or <target directory>");
fprintf(stderr, "\n");
fprintf(stderr, " or <target directory>\n");
}
static void print_usage_chreipl_helper(const char *toolname)
{
fprintf(stderr, "%s <major:minor of target device>\n", toolname);
}
/**
* Complete the PD structure and assign the base device
*/
static int complete_physical_device(struct physical_device *pd, dev_t *base_dev)
{
struct device_characteristics *dc = &pd->dc;
struct dmpath_entry *top_entry, *base_entry;
dev_t top_dev;
top_entry = get_top_entry(pd);
top_dev = first_device_by_target_data(top_entry->target);
/* Retrieve parameters of the topmost device */
if (get_dev_characteristics(dc, top_dev) != 0)
return -1;
if (dc->partstart > 0) {
/*
* The topmost found device is a partition.
* Since just a part of the physical device is mapped, only
* the physical device can provide access to the boot record
*/
struct device_characteristics ndc = {0};
struct dmpath_entry *mirror;
/* Check for mirror */
mirror = dmpath_get_first_by_type(pd->dmpath,
TARGET_TYPE_MIRROR);
if (mirror != NULL) {
char name[BDEVNAME_SIZE];
get_device_name(name, mirror->dev.dev);
/* IPL records are not mirrored */
ERR("Unsupported setup: Block 0 is not mirrored in "
"device '%s'\n", name);
return -1;
}
base_entry = top_entry;
*base_dev = get_partition_base(dc->type, top_dev);
/* Complete the filesystem offset */
pd->offset += (dc->partstart * (dc->blocksize / SECTOR_SIZE));
dc->partstart = 0;
/* Update device geometry */
get_dev_characteristics(&ndc, *base_dev);
dc->geo = ndc.geo;
} else {
/*
* All of the device is mapped, so the base device is the
* top most dm device which provides access to boot sectors
*/
base_entry = find_base_entry(pd->dmpath, dc->bootsectors);
if (!base_entry)
return -1;
*base_dev = base_entry->dev.dev;
}
/* Check for valid offset of filesystem */
if ((pd->offset % (dc->blocksize / SECTOR_SIZE)) != 0) {
ERR("File system not aligned on physical block size\n");
return -1;
}
return 0;
}
/**
* Print a set of zipl parameters for a base device.
*
* BASE: physical or logical device, which provides access to boot sectors
* FS_START: offset (in sectors) of the first block managed by the file system
*/
static void base_dev_to_params(dev_t base, struct device_characteristics *dc,
unsigned long fs_start)
{
char type_name[8];
printf("targetbase=%u:%u\n", major(base), minor(base));
get_type_name(type_name, dc->type);
printf("targettype=%s\n", type_name);
if (dc->geo.cylinders != 0 &&
dc->geo.heads != 0 &&
dc->geo.sectors != 0) {
printf("targetgeometry=%d,%d,%d\n",
dc->geo.cylinders,
dc->geo.heads,
dc->geo.sectors);
}
printf("targetblocksize=%d\n", dc->blocksize);
printf("targetoffset=%lu\n",
fs_start / (dc->blocksize / SECTOR_SIZE));
}
/**
* Print parameters for logical device DEV required by zipl
* tool to install IPL records on its's physical components.
*
* DEV: a logical device managed by device-mapper driver
*/
static int dm_dev_to_zipl_params(struct ext_dev *dev, char *dir)
{
struct physical_device pd = {0};
dev_t base_dev;
if (get_physical_device(&pd, dev, dir))
return -1;
if (complete_physical_device(&pd, &base_dev))
goto error;
base_dev_to_params(base_dev, &pd.dc, pd.offset);
dmpath_free(pd.dmpath);
return 0;
error:
dmpath_free(pd.dmpath);
return -1;
}
static int dm_dev_to_chreipl_params(dev_t dev, char *dir)
{
struct physical_device pd = {0};
struct ext_dev xdev = {dev, 0};
dev_t top_dev;
if (get_physical_device(&pd, &xdev, dir))
return -1;
top_dev = get_top_entry(&pd)->dev.dev;
printf("%u:%u\n", major(top_dev), minor(top_dev));
dmpath_free(pd.dmpath);
return 0;
}
static int handle_device_mapper(dev_t dev, int util_id, char *name)
{
struct ext_dev xdev = {dev, 0};
switch (util_id) {
case CHREIPL_UTIL_ID:
return dm_dev_to_chreipl_params(dev, name);
case ZIPL_UTIL_ID:
return dm_dev_to_zipl_params(&xdev, name);
default:
ERR("Unsupported utility %d\n", util_id);
return -1;
}
}
static int print_params_device_mapper(char *argv[], struct helper *h)
{
unsigned int major, minor;
char *name = argv[1];
dev_t dev;
if (extract_major_minor_from_cmdline(argv, &major, &minor) == 0)
dev = makedev(major, minor);
else if (device_by_filename(&dev, name))
return -1;
return handle_device_mapper(dev, h->util_id, name);
}
static int check_usage_zipl_helper(int argc, char *argv[])
{
if (argc <= 1) {
print_usage_zipl_helper(argv[0]);
return -1;
}
return 0;
}
static int check_usage_chreipl_helper(int argc, char *argv[])
{
unsigned int major, minor;
if (argc <= 1 ||
extract_major_minor_from_cmdline(argv, &major, &minor)) {
print_usage_chreipl_helper(argv[0]);
return -1;
}
return 0;
}
static struct helper helpers[LAST_DRIVER_ID][LAST_UTIL_ID] = {
[DM_DRIVER_ID][ZIPL_UTIL_ID] = {
. util_id = ZIPL_UTIL_ID,
. driver_id = DM_DRIVER_ID,
. name = "zipl_helper.device-mapper",
. check_usage = check_usage_zipl_helper,
. print_params = print_params_device_mapper
},
[DM_DRIVER_ID][CHREIPL_UTIL_ID] = {
. util_id = CHREIPL_UTIL_ID,
. driver_id = DM_DRIVER_ID,
. name = "chreipl_helper.device-mapper",
. check_usage = check_usage_chreipl_helper,
. print_params = print_params_device_mapper
},
};
static struct helper *helper_by_toolname(const char *toolname)
{
int i, j;
for (i = 0; i < LAST_DRIVER_ID; i++)
for (j = 0; j < LAST_UTIL_ID; j++)
if (toolname_is(toolname, helpers[i][j].name))
return &helpers[i][j];
return NULL;
}
int main(int argc, char *argv[])
{
struct device_characteristics dc = {0};
const char *toolname = argv[0];
struct physical_device pd;
unsigned int major, minor;
char *directory = NULL;
char type_name[8];
dev_t base;
int res;
struct helper *h;
if (argc <= 1)
goto usage;
h = helper_by_toolname(argv[0]);
assert(h != NULL);
if (h->check_usage(argc, argv))
exit(EXIT_FAILURE);
if (setlocale(LC_ALL, "C") == NULL) {
ERR("Could not use standard locale\n");
exit(EXIT_FAILURE);
}
if (toolname_is_chreipl_helper(toolname)) {
if (extract_major_minor_from_cmdline(argv, &major, &minor) != 0)
goto usage;
if (get_physical_device(&pd, makedev(major, minor), argv[1]) != 0)
exit(EXIT_FAILURE);
printf("%u:%u\n", major(pd.device), minor(pd.device));
target_list_free(pd.target_list);
exit(EXIT_SUCCESS);
}
directory = argv[1];
if (extract_major_minor_from_cmdline(argv, &major, &minor) == 0)
res = get_physical_device(&pd, makedev(major, minor), directory);
else
res = get_physical_device_dir(&pd, directory);
if (res != 0)
if (h->print_params(argv, h))
exit(EXIT_FAILURE);
if (get_dev_characteristics(&dc, pd.device) != 0)
goto error;
/* Handle partitions */
if (dc.partstart > 0) {
struct device_characteristics ndc = {0};
struct target_entry *mirror;
/* Only the partition of the physical device is mapped so only
* the physical device can provide access to the boot record
*/
base = get_partition_base(dc.type, pd.device);
/* Check for mirror */
mirror = target_list_get_first_by_type(pd.target_list,
TARGET_TYPE_MIRROR);
if (mirror != NULL) {
char name[BDEVNAME_SIZE];
get_device_name(name, mirror->device);
/* IPL records are not mirrored */
ERR("Unsupported setup: Block 0 is not mirrored in "
"device '%s'\n", name);
goto error;
}
/* Adjust filesystem offset */
pd.offset += (dc.partstart * (dc.blocksize / SECTOR_SIZE));
dc.partstart = 0;
/* Update device geometry */
get_dev_characteristics(&ndc, base);
dc.geo = ndc.geo;
} else {
/* All of the device is mapped, so the base device is the
* top most dm device which provides access to boot sectors
*/
if (get_target_base(&base, pd.device, dc.bootsectors,
pd.target_list) != 0)
goto error;
}
/* Check for valid offset of filesystem */
if ((pd.offset % (dc.blocksize / SECTOR_SIZE)) != 0) {
ERR("File system not aligned on physical block size\n");
goto error;
}
target_list_free(pd.target_list);
/* Print resulting information */
printf("targetbase=%u:%u\n", major(base), minor(base));
get_type_name(type_name, dc.type);
printf("targettype=%s\n", type_name);
if (dc.geo.cylinders != 0 && dc.geo.heads != 0 && dc.geo.sectors != 0) {
printf("targetgeometry=%d,%d,%d\n",
dc.geo.cylinders, dc.geo.heads, dc.geo.sectors);
}
printf("targetblocksize=%d\n", dc.blocksize);
printf("targetoffset=%lu\n", (pd.offset / (dc.blocksize / SECTOR_SIZE)));
exit(EXIT_SUCCESS);
error:
if (pd.target_list != NULL)
target_list_free(pd.target_list);
exit(EXIT_FAILURE);
usage:
print_usage(toolname);
exit(EXIT_FAILURE);
}