/* * Given a block device and a partition table type, * try to parse the partition table, and list the * contents. Optionally add or remove partitions. * * [This is not an fdisk - adding and removing partitions * is not a change of the disk, but just telling the kernel * about presence and numbering of on-disk partitions.] * * Call: * partx [-{l|a|d}] [--type TYPE] [--nr M-N] [partition] wholedisk * where TYPE is {dos|bsd|solaris|unixware|gpt}. * * Read wholedisk and add all partitions: * partx -a wholedisk * * Subdivide a partition into slices (and delete or shrink the partition): * [Not easy: one needs the partition number of partition - * that is the last 4 or 6 bits of the minor; it can also be found * in /proc/partitions; but there is no good direct way.] * partx -a partition wholedisk * * Delete all partitions from wholedisk: * partx -d wholedisk * * Delete partitions M-N from wholedisk: * partx -d --nr M-N wholedisk * * aeb, 2000-03-21 -- sah is 42 now */ #include #include #include #include #include #include #include #include #include /* HDIO_GETGEO */ #ifdef HAVE_LINUX_COMPILER_H #include #endif #include #include "c.h" #include "blkdev.h" #include "partx.h" #include "crc32.h" static void errmerge(int err, int m, char *msg1, char *msg2); #define MAXTYPES 64 #define MAXSLICES 256 struct slice slices[MAXSLICES]; enum action { LIST, ADD, DELETE }; struct pt { char *type; ptreader *fn; } pts[MAXTYPES]; int ptct; static void addpts(char *t, ptreader f) { if (ptct >= MAXTYPES) { fprintf(stderr, "addpts: too many types\n"); exit(1); } pts[ptct].type = t; pts[ptct].fn = f; ptct++; } static void initpts(void) { addpts("gpt", read_gpt_pt); addpts("dos", read_dos_pt); addpts("bsd", read_bsd_pt); addpts("solaris", read_solaris_pt); addpts("unixware", read_unixware_pt); } static char short_opts[] = "ladgvn:t:"; static const struct option long_opts[] = { { "gpt", no_argument, NULL, 'g' }, { "type", required_argument, NULL, 't' }, { "nr", required_argument, NULL, 'n' }, { NULL, 0, NULL, 0 } }; /* Used in gpt.c */ int force_gpt=0; int main(int argc, char **argv){ int fd, fd2, c, i, j, k, n; unsigned long long size; struct hd_geometry g; struct slice all; struct blkpg_ioctl_arg a; struct blkpg_partition pt; struct pt *ptp; enum action what = LIST; char *p, *type, *diskdevice, *device; int lower, upper; int verbose = 0; int ret = 0; initpts(); init_crc32(); lower = upper = 0; type = device = diskdevice = NULL; while ((c = getopt_long (argc, argv, short_opts, long_opts, NULL)) != -1) switch(c) { case 'l': what = LIST; break; case 'a': what = ADD; break; case 'd': what = DELETE; break; case 'g': force_gpt = 1; break; case 'n': p = optarg; lower = atoi(p); p = strchr(p, '-'); if (p) upper = atoi(p+1); else upper = lower; break; case 't': type = optarg; break; case 'v': verbose = 1; break; case '?': default: fprintf(stderr, "unknown option\n"); exit(1); } if (optind == argc-2) { device = argv[optind]; diskdevice = argv[optind+1]; } else if (optind == argc-1) { diskdevice = device = argv[optind]; } else { fprintf(stderr, "call: partx -opts [device] wholedisk\n"); exit(1); } fd = open(diskdevice, O_RDONLY); if (fd == -1) { perror(diskdevice); exit(1); } /* remove the indicated partitions from the kernel partition tables */ if (what == DELETE) { if (device != diskdevice) { fprintf(stderr, "call: partx -d [--nr M-N] wholedisk\n"); exit(1); } if (!lower) lower = 1; while (upper == 0 || lower <= upper) { int err; pt.pno = lower; pt.start = 0; pt.length = 0; pt.devname[0] = 0; pt.volname[0] = 0; a.op = BLKPG_DEL_PARTITION; a.flags = 0; a.datalen = sizeof(pt); a.data = &pt; if (ioctl(fd, BLKPG, &a) == -1) err = errno; else err = 0; errmerge(err, lower, "error deleting partition %d: ", "error deleting partitions %d-%d: "); /* expected errors: EBUSY: mounted or in use as swap ENXIO: no such nonempty partition EINVAL: not wholedisk, or bad pno EACCES/EPERM: permission denied */ if (err && err != EBUSY && err != ENXIO) { ret = 1; break; } if (err == 0 && verbose) printf("deleted partition %d\n", lower); lower++; } errmerge(0, 0, "error deleting partition %d: ", "error deleting partitions %d-%d: "); return ret; } if (device != diskdevice) { fd2 = open(device, O_RDONLY); if (fd2 == -1) { perror(device); exit(1); } } else { fd2 = fd; } if (ioctl(fd, HDIO_GETGEO, &g)) { perror("HDIO_GETGEO"); exit(1); } if (g.start != 0) { fprintf(stderr, "last arg is not the whole disk\n"); fprintf(stderr, "call: partx -opts device wholedisk\n"); exit(1); } if (ioctl(fd2, HDIO_GETGEO, &g)) { perror("HDIO_GETGEO"); exit(1); } all.start = g.start; if (blkdev_get_sectors(fd2, &size) != 0) { perror("partx"); exit(1); } all.size = (unsigned int) size; if (verbose) printf("device %s: start %d size %d\n", device, all.start, all.size); if (all.size == 0) { fprintf(stderr, "That disk slice has size 0\n"); exit(0); } if (all.size == 2) all.size = 0; /* probably extended partition */ /* add the indicated partitions to the kernel partition tables */ if (!lower) lower = 1; for (i = 0; i < ptct; i++) { ptp = &pts[i]; if (!type || !strcmp(type, ptp->type)) { n = ptp->fn(fd, all, slices, ARRAY_SIZE(slices)); if (n >= 0 && verbose) printf("%s: %d slices\n", ptp->type, n); if (n > 0 && (verbose || what == LIST)) { for (j=0; j 0 && what == ADD) { /* test for overlap, as in the case of an extended partition, and reduce size */ for (j=0; j slices[j].start && slices[k].start < slices[j].start + slices[j].size) { slices[j].size = slices[k].start - slices[j].start; if (verbose) printf("reduced size of " "partition #%d to %d\n", lower+j, slices[j].size); } } } for (j=0; jnext) if (bp->secnr == secnr) return bp->block; if (sseek(fd, secnr)) return NULL; bp = xmalloc(sizeof(struct block)); bp->secnr = secnr; bp->next = blockhead; blockhead = bp; bp->block = (unsigned char *) xmalloc(1024); if (read(fd, bp->block, 1024) != 1024) { fprintf(stderr, "read error, sector %d\n", secnr); bp->block = NULL; } return bp->block; } /* call with errno and integer m and error message */ /* merge to interval m-n */ static void errmerge(int err, int m, char *msg1, char *msg2) { static int preverr, firstm, prevm; if (err != preverr) { if (preverr) { if (firstm == prevm) fprintf(stderr, msg1, firstm); else fprintf(stderr, msg2, firstm, prevm); errno = preverr; perror("BLKPG"); } preverr = err; firstm = prevm = m; } else prevm = m; }