2 * Given a block device and a partition table type,
3 * try to parse the partition table, and list the
4 * contents. Optionally add or remove partitions.
6 * [This is not an fdisk - adding and removing partitions
7 * is not a change of the disk, but just telling the kernel
8 * about presence and numbering of on-disk partitions.]
11 * partx [-{l|a|d}] [--type TYPE] [--nr M-N] [partition] wholedisk
12 * where TYPE is {dos|bsd|solaris|unixware|gpt}.
14 * Read wholedisk and add all partitions:
17 * Subdivide a partition into slices (and delete or shrink the partition):
18 * [Not easy: one needs the partition number of partition -
19 * that is the last 4 or 6 bits of the minor; it can also be found
20 * in /proc/partitions; but there is no good direct way.]
21 * partx -a partition wholedisk
23 * Delete all partitions from wholedisk:
26 * Delete partitions M-N from wholedisk:
27 * partx -d --nr M-N wholedisk
29 * aeb, 2000-03-21 -- sah is 42 now
39 #include <sys/ioctl.h>
40 #include <linux/hdreg.h> /* HDIO_GETGEO */
41 #ifdef HAVE_LINUX_COMPILER_H
42 #include <linux/compiler.h>
44 #include <linux/blkpg.h>
50 static void errmerge(int err, int m, char *msg1, char *msg2);
52 #define SIZE(a) (sizeof(a)/sizeof((a)[0]))
57 struct slice slices[MAXSLICES];
59 enum action { LIST, ADD, DELETE };
68 addpts(char *t, ptreader f)
70 if (ptct >= MAXTYPES) {
71 fprintf(stderr, "addpts: too many types\n");
82 addpts("gpt", read_gpt_pt);
83 addpts("dos", read_dos_pt);
84 addpts("bsd", read_bsd_pt);
85 addpts("solaris", read_solaris_pt);
86 addpts("unixware", read_unixware_pt);
89 static char short_opts[] = "ladgvn:t:";
90 static const struct option long_opts[] = {
91 { "gpt", no_argument, NULL, 'g' },
92 { "type", required_argument, NULL, 't' },
93 { "nr", required_argument, NULL, 'n' },
101 main(int argc, char **argv){
102 int fd, fd2, c, i, j, k, n;
103 unsigned long long size;
104 struct hd_geometry g;
106 struct blkpg_ioctl_arg a;
107 struct blkpg_partition pt;
109 enum action what = LIST;
110 char *p, *type, *diskdevice, *device;
119 type = device = diskdevice = NULL;
121 while ((c = getopt_long (argc, argv, short_opts, long_opts, NULL))
128 what = DELETE; break;
130 force_gpt = 1; break;
148 fprintf(stderr, "unknown option\n");
152 if (optind == argc-2) {
153 device = argv[optind];
154 diskdevice = argv[optind+1];
155 } else if (optind == argc-1) {
156 diskdevice = device = argv[optind];
158 fprintf(stderr, "call: partx -opts [device] wholedisk\n");
162 fd = open(diskdevice, O_RDONLY);
168 /* remove the indicated partitions from the kernel partition tables */
169 if (what == DELETE) {
170 if (device != diskdevice) {
172 "call: partx -d [--nr M-N] wholedisk\n");
179 while (upper == 0 || lower <= upper) {
187 a.op = BLKPG_DEL_PARTITION;
189 a.datalen = sizeof(pt);
191 if (ioctl(fd, BLKPG, &a) == -1)
196 "error deleting partition %d: ",
197 "error deleting partitions %d-%d: ");
199 EBUSY: mounted or in use as swap
200 ENXIO: no such nonempty partition
201 EINVAL: not wholedisk, or bad pno
202 EACCES/EPERM: permission denied
204 if (err && err != EBUSY && err != ENXIO) {
208 if (err == 0 && verbose)
209 printf("deleted partition %d\n", lower);
213 "error deleting partition %d: ",
214 "error deleting partitions %d-%d: ");
218 if (device != diskdevice) {
219 fd2 = open(device, O_RDONLY);
228 if (ioctl(fd, HDIO_GETGEO, &g)) {
229 perror("HDIO_GETGEO");
233 fprintf(stderr, "last arg is not the whole disk\n");
234 fprintf(stderr, "call: partx -opts device wholedisk\n");
238 if (ioctl(fd2, HDIO_GETGEO, &g)) {
239 perror("HDIO_GETGEO");
244 if (blkdev_get_sectors(fd2, &size) != 0) {
248 all.size = (unsigned int) size;
251 printf("device %s: start %d size %d\n",
252 device, all.start, all.size);
255 fprintf(stderr, "That disk slice has size 0\n");
259 all.size = 0; /* probably extended partition */
261 /* add the indicated partitions to the kernel partition tables */
264 for (i = 0; i < ptct; i++) {
266 if (!type || !strcmp(type, ptp->type)) {
267 n = ptp->fn(fd, all, slices, SIZE(slices));
268 if (n >= 0 && verbose)
269 printf("%s: %d slices\n", ptp->type, n);
270 if (n > 0 && (verbose || what == LIST)) {
272 printf("#%2d: %9d-%9d (%9d sectors, %6d MB)\n",
275 slices[j].start+slices[j].size-1,
277 (int)((512 * (long long) slices[j].size)
280 if (n > 0 && what == ADD) {
281 /* test for overlap, as in the case of an
282 extended partition, and reduce size */
283 for (j=0; j<n; j++) {
284 for (k=j+1; k<n; k++) {
285 if (slices[k].start > slices[j].start &&
286 slices[k].start < slices[j].start +
288 slices[j].size = slices[k].start -
291 printf("reduced size of "
292 "partition #%d to %d\n",
298 for (j=0; j<n; j++) {
300 pt.start = 512 * (long long) slices[j].start;
301 pt.length = 512 * (long long) slices[j].size;
304 a.op = BLKPG_ADD_PARTITION;
306 a.datalen = sizeof(pt);
308 if (ioctl(fd, BLKPG, &a) == -1) {
311 "error adding partition %d\n",
314 printf("added partition %d\n", lower+j);
324 xmalloc (size_t size) {
331 fprintf(stderr, "Out of memory\n");
338 sseek(int fd, unsigned int secnr) {
340 in = ((long long) secnr << 9);
343 if ((out = lseek(fd, in, SEEK_SET)) != in)
345 fprintf(stderr, "lseek error\n");
354 unsigned char *block;
359 getblock(int fd, unsigned int secnr) {
362 for (bp = blockhead; bp; bp = bp->next)
363 if (bp->secnr == secnr)
365 if (sseek(fd, secnr))
367 bp = xmalloc(sizeof(struct block));
369 bp->next = blockhead;
371 bp->block = (unsigned char *) xmalloc(1024);
372 if (read(fd, bp->block, 1024) != 1024) {
373 fprintf(stderr, "read error, sector %d\n", secnr);
379 /* call with errno and integer m and error message */
380 /* merge to interval m-n */
382 errmerge(int err, int m, char *msg1, char *msg2) {
383 static int preverr, firstm, prevm;
385 if (err != preverr) {
388 fprintf(stderr, msg1, firstm);
390 fprintf(stderr, msg2, firstm, prevm);