2
* Source: copy of util-linux' partx partx.c
4
* Copyrights of the original file applies
5
* Copyright (c) 2004, 2005 Christophe Varoqui
6
* Copyright (c) 2005 Kiyoshi Ueda
7
* Copyright (c) 2005 Lars Soltau
11
* Given a block device and a partition table type,
12
* try to parse the partition table, and list the
13
* contents. Optionally add or remove partitions.
15
* Read wholedisk and add all partitions:
16
* kpartx [-a|-d|-l] [-v] wholedisk
30
#include <sys/types.h>
32
#include <libdevmapper.h>
34
#include "devmapper.h"
39
#define SIZE(a) (sizeof(a)/sizeof((a)[0]))
41
#define READ_SIZE 1024
44
#define DM_TARGET "linear"
45
#define LO_NAME_SIZE 64
46
#define PARTNAME_SIZE 128
49
struct slice slices[MAXSLICES];
51
enum action { LIST, ADD, DELETE };
61
addpts(char *t, ptreader f)
63
if (ptct >= MAXTYPES) {
64
fprintf(stderr, "addpts: too many types\n");
75
addpts("gpt", read_gpt_pt);
76
addpts("dos", read_dos_pt);
77
addpts("bsd", read_bsd_pt);
78
addpts("solaris", read_solaris_pt);
79
addpts("unixware", read_unixware_pt);
80
addpts("dasd", read_dasd_pt);
81
addpts("mac", read_mac_pt);
82
addpts("sun", read_sun_pt);
85
static char short_opts[] = "rladgvp:t:s";
92
printf("usage : kpartx [-a|-d|-l] [-v] wholedisk\n");
93
printf("\t-a add partition devmappings\n");
94
printf("\t-r devmappings will be readonly\n");
95
printf("\t-d del partition devmappings\n");
96
printf("\t-l list partitions devmappings that would be added by -a\n");
97
printf("\t-p set device name-partition number delimiter\n");
98
printf("\t-g force GUID partition table (GPT)\n");
99
printf("\t-v verbose\n");
100
printf("\t-s sync mode. Don't return until the partitions are created\n");
105
set_delimiter (char * device, char * delimiter)
109
while (*(p++) != 0x0)
112
if (isdigit(*(p - 2)))
117
strip_slash (char * device)
121
while (*(p++) != 0x0) {
129
find_devname_offset (char * device)
139
return (int)(q - device) + 1;
143
get_hotplug_device(void)
145
unsigned int major, minor, off, len;
147
char *devname = NULL;
152
var = getenv("ACTION");
154
if (!var || strcmp(var, "add"))
157
/* Get dm mapname for hotpluged device. */
158
if (!(devname = getenv("DEVNAME")))
161
if (stat(devname, &buf))
164
major = (unsigned int)MAJOR(buf.st_rdev);
165
minor = (unsigned int)MINOR(buf.st_rdev);
167
if (!(mapname = dm_mapname(major, minor))) /* Not dm device. */
170
off = find_devname_offset(devname);
171
len = strlen(mapname);
173
/* Dirname + mapname + \0 */
174
if (!(device = (char *)malloc(sizeof(char) * (off + len + 1))))
177
/* Create new device name. */
178
snprintf(device, off + 1, "%s", devname);
179
snprintf(device + off, len + 1, "%s", mapname);
181
if (strlen(device) != (off + len))
188
main(int argc, char **argv){
189
int fd, i, j, m, n, op, off, arg, c, d, ro=0;
192
enum action what = LIST;
193
char *type, *diskdevice, *device, *progname;
195
char partname[PARTNAME_SIZE], params[PARTNAME_SIZE + 16];
196
char * loopdev = NULL;
199
char *mapname = NULL;
210
type = device = diskdevice = NULL;
211
memset(&all, 0, sizeof(all));
212
memset(&partname, 0, sizeof(partname));
214
/* Check whether hotplug mode. */
215
progname = strrchr(argv[0], '/');
222
if (!strcmp(progname, "kpartx.dev")) { /* Hotplug mode */
225
/* Setup for original kpartx variables */
226
if (!(device = get_hotplug_device()))
231
} else if (argc < 2) {
236
while ((arg = getopt(argc, argv, short_opts)) != EOF) switch(arg) {
270
dm_udev_set_sync_support(0);
272
if (dm_prereq(DM_TARGET, 0, 0, 0) && (what == ADD || what == DELETE)) {
273
fprintf(stderr, "device mapper prerequisites not met\n");
278
/* already got [disk]device */
279
} else if (optind == argc-2) {
280
device = argv[optind];
281
diskdevice = argv[optind+1];
282
} else if (optind == argc-1) {
283
diskdevice = device = argv[optind];
289
if (stat(device, &buf)) {
290
printf("failed to stat() %s\n", device);
294
if (S_ISREG (buf.st_mode)) {
295
/* already looped file ? */
296
loopdev = find_loop_by_file(device);
298
if (!loopdev && what == DELETE)
302
loopdev = find_unused_loop_device();
304
if (set_loop(loopdev, device, 0, &loopro)) {
305
fprintf(stderr, "can't set up loop\n");
314
delim = malloc(DELIM_SIZE);
315
memset(delim, 0, DELIM_SIZE);
316
set_delimiter(device, delim);
319
off = find_devname_offset(device);
322
uuid = dm_mapuuid((unsigned int)MAJOR(buf.st_rdev),
323
(unsigned int)MINOR(buf.st_rdev));
324
mapname = dm_mapname((unsigned int)MAJOR(buf.st_rdev),
325
(unsigned int)MINOR(buf.st_rdev));
332
mapname = device + off;
334
fd = open(device, O_RDONLY);
341
/* add/remove partitions to the kernel devmapper tables */
343
for (i = 0; i < ptct; i++) {
346
if (type && strcmp(type, ptp->type))
349
/* here we get partitions */
350
n = ptp->fn(fd, all, slices, SIZE(slices));
354
printf("%s: %d slices\n", ptp->type, n);
364
for (j = 0, c = 0, m = 0; j < n; j++) {
365
if (slices[j].size == 0)
367
if (slices[j].container > 0) {
372
slices[j].minor = m++;
374
printf("%s%s%d : 0 %" PRIu64 " %s %" PRIu64"\n",
376
slices[j].size, device,
379
/* Loop to resolve contained slices */
382
for (j = 0; j < n; j++) {
384
int k = slices[j].container - 1;
386
if (slices[j].size == 0)
388
if (slices[j].minor > 0)
390
if (slices[j].container == 0)
392
slices[j].minor = m++;
394
start = slices[j].start - slices[k].start;
395
printf("%s%s%d : 0 %" PRIu64 " /dev/dm-%d %" PRIu64 "\n",
398
slices[k].minor, start);
401
/* Terminate loop if nothing more to resolve */
406
if (loopcreated && S_ISREG (buf.st_mode)) {
407
if (del_loop(device)) {
409
printf("can't del loop : %s\n",
413
printf("loop deleted : %s\n", device);
418
for (j = n-1; j >= 0; j--) {
419
if (safe_sprintf(partname, "%s%s%d",
420
mapname, delim, j+1)) {
421
fprintf(stderr, "partname too small\n");
424
strip_slash(partname);
426
if (!slices[j].size || !dm_map_present(partname))
429
if (!dm_simplecmd(DM_DEVICE_REMOVE, partname,
435
printf("del devmap : %s\n", partname);
438
if (S_ISREG (buf.st_mode)) {
439
if (del_loop(device)) {
441
printf("can't del loop : %s\n",
445
printf("loop deleted : %s\n", device);
450
for (j = 0, c = 0; j < n; j++) {
451
if (slices[j].size == 0)
454
/* Skip all contained slices */
455
if (slices[j].container > 0) {
460
if (safe_sprintf(partname, "%s%s%d",
461
mapname, delim, j+1)) {
462
fprintf(stderr, "partname too small\n");
465
strip_slash(partname);
467
if (safe_sprintf(params, "%s %" PRIu64 ,
468
device, slices[j].start)) {
469
fprintf(stderr, "params too small\n");
473
op = (dm_map_present(partname) ?
474
DM_DEVICE_RELOAD : DM_DEVICE_CREATE);
476
if (!dm_addmap(op, partname, DM_TARGET, params,
477
slices[j].size, ro, uuid, j+1,
478
buf.st_mode & 0777, buf.st_uid,
479
buf.st_gid, &cookie)) {
480
fprintf(stderr, "create/reload failed on %s\n",
484
if (op == DM_DEVICE_RELOAD &&
485
!dm_simplecmd(DM_DEVICE_RESUME, partname,
487
fprintf(stderr, "resume failed on %s\n",
491
dm_devn(partname, &slices[j].major,
495
printf("add map %s (%d:%d): 0 %" PRIu64 " %s %s\n",
496
partname, slices[j].major,
497
slices[j].minor, slices[j].size,
500
/* Loop to resolve contained slices */
503
for (j = 0; j < n; j++) {
505
int k = slices[j].container - 1;
507
if (slices[j].size == 0)
510
/* Skip all existing slices */
511
if (slices[j].minor > 0)
514
/* Skip all simple slices */
515
if (slices[j].container == 0)
518
/* Check container slice */
519
if (slices[k].size == 0)
520
fprintf(stderr, "Invalid slice %d\n",
523
if (safe_sprintf(partname, "%s%s%d",
524
mapname, delim, j+1)) {
525
fprintf(stderr, "partname too small\n");
528
strip_slash(partname);
530
start = slices[j].start - slices[k].start;
531
if (safe_sprintf(params, "%d:%d %" PRIu64,
535
fprintf(stderr, "params too small\n");
539
op = (dm_map_present(partname) ?
540
DM_DEVICE_RELOAD : DM_DEVICE_CREATE);
542
dm_addmap(op, partname, DM_TARGET, params,
543
slices[j].size, ro, uuid, j+1,
545
buf.st_uid, buf.st_gid,
548
if (op == DM_DEVICE_RELOAD)
549
dm_simplecmd(DM_DEVICE_RESUME,
553
dm_devn(partname, &slices[j].major,
557
printf("add map %s : 0 %" PRIu64 " %s %s\n",
558
partname, slices[j].size,
575
dm_udev_wait(cookie);
583
xmalloc (size_t size) {
592
fprintf(stderr, "Out of memory\n");
600
* sseek: seek to specified sector
604
sseek(int fd, unsigned int secnr) {
606
in = ((off64_t) secnr << 9);
609
if ((out = lseek64(fd, in, SEEK_SET)) != in)
611
fprintf(stderr, "llseek error\n");
625
getblock (int fd, unsigned int secnr) {
628
for (bp = blockhead; bp; bp = bp->next)
630
if (bp->secnr == secnr)
633
if (sseek(fd, secnr))
636
bp = xmalloc(sizeof(struct block));
638
bp->next = blockhead;
640
bp->block = (char *) xmalloc(READ_SIZE);
642
if (read(fd, bp->block, READ_SIZE) != READ_SIZE) {
643
fprintf(stderr, "read error, sector %d\n", secnr);