]> git.ipfire.org Git - thirdparty/util-linux.git/blob - partx/partx.c
Imported from util-linux-2.13-pre6 tarball.
[thirdparty/util-linux.git] / partx / partx.c
1 /*
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.
5 *
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.]
9 *
10 * Call:
11 * partx [-{l|a|d}] [--type TYPE] [--nr M-N] [partition] wholedisk
12 * where TYPE is {dos|bsd|solaris|unixware|gpt}.
13 *
14 * Read wholedisk and add all partitions:
15 * partx -a wholedisk
16 *
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
22 *
23 * Delete all partitions from wholedisk:
24 * partx -d wholedisk
25 *
26 * Delete partitions M-N from wholedisk:
27 * partx -d --nr M-N wholedisk
28 *
29 * aeb, 2000-03-21 -- sah is 42 now
30 */
31
32 #include <stdio.h>
33 #include <fcntl.h>
34 #include <errno.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <getopt.h>
38 #include <unistd.h>
39 #include <sys/ioctl.h>
40 #include <linux/hdreg.h> /* HDIO_GETGEO */
41 #ifdef HAVE_LINUX_COMPILER_H
42 #include <linux/compiler.h>
43 #endif
44 #include <linux/blkpg.h>
45 #define BLKGETSIZE _IO(0x12,96) /* return device size */
46
47 #include "partx.h"
48 #include "crc32.h"
49 static void errmerge(int err, int m, char *msg1, char *msg2);
50
51 #define SIZE(a) (sizeof(a)/sizeof((a)[0]))
52
53 #define MAXTYPES 64
54 #define MAXSLICES 256
55
56 struct slice slices[MAXSLICES];
57
58 enum action { LIST, ADD, DELETE };
59
60 struct pt {
61 char *type;
62 ptreader *fn;
63 } pts[MAXTYPES];
64 int ptct;
65
66 static void
67 addpts(char *t, ptreader f)
68 {
69 if (ptct >= MAXTYPES) {
70 fprintf(stderr, "addpts: too many types\n");
71 exit(1);
72 }
73 pts[ptct].type = t;
74 pts[ptct].fn = f;
75 ptct++;
76 }
77
78 static void
79 initpts(void)
80 {
81 addpts("gpt", read_gpt_pt);
82 addpts("dos", read_dos_pt);
83 addpts("bsd", read_bsd_pt);
84 addpts("solaris", read_solaris_pt);
85 addpts("unixware", read_unixware_pt);
86 }
87
88 static char short_opts[] = "ladgvn:t:";
89 static const struct option long_opts[] = {
90 { "gpt", no_argument, NULL, 'g' },
91 { "type", required_argument, NULL, 't' },
92 { "nr", required_argument, NULL, 'n' },
93 { NULL, 0, NULL, 0 }
94 };
95
96 /* Used in gpt.c */
97 int force_gpt=0;
98
99 int
100 main(int argc, char **argv){
101 int fd, fd2, c, i, j, k, n;
102 long size;
103 struct hd_geometry g;
104 struct slice all;
105 struct blkpg_ioctl_arg a;
106 struct blkpg_partition pt;
107 struct pt *ptp;
108 enum action what = LIST;
109 char *p, *type, *diskdevice, *device;
110 int lower, upper;
111 int verbose = 0;
112 int ret = 0;
113
114 initpts();
115 init_crc32();
116
117 lower = upper = 0;
118 type = device = diskdevice = NULL;
119
120 while ((c = getopt_long (argc, argv, short_opts, long_opts, NULL))
121 != -1) switch(c) {
122 case 'l':
123 what = LIST; break;
124 case 'a':
125 what = ADD; break;
126 case 'd':
127 what = DELETE; break;
128 case 'g':
129 force_gpt = 1; break;
130 case 'n':
131 p = optarg;
132 lower = atoi(p);
133 p = index(p, '-');
134 if (p)
135 upper = atoi(p+1);
136 else
137 upper = lower;
138 break;
139 case 't':
140 type = optarg;
141 break;
142 case 'v':
143 verbose = 1;
144 break;
145 case '?':
146 default:
147 fprintf(stderr, "unknown option\n");
148 exit(1);
149 }
150
151 if (optind == argc-2) {
152 device = argv[optind];
153 diskdevice = argv[optind+1];
154 } else if (optind == argc-1) {
155 diskdevice = device = argv[optind];
156 } else {
157 fprintf(stderr, "call: partx -opts [device] wholedisk\n");
158 exit(1);
159 }
160
161 fd = open(diskdevice, O_RDONLY);
162 if (fd == -1) {
163 perror(diskdevice);
164 exit(1);
165 }
166
167 /* remove the indicated partitions from the kernel partition tables */
168 if (what == DELETE) {
169 if (device != diskdevice) {
170 fprintf(stderr,
171 "call: partx -d [--nr M-N] wholedisk\n");
172 exit(1);
173 }
174
175 if (!lower)
176 lower = 1;
177
178 while (upper == 0 || lower <= upper) {
179 int err;
180
181 pt.pno = lower;
182 pt.start = 0;
183 pt.length = 0;
184 pt.devname[0] = 0;
185 pt.volname[0] = 0;
186 a.op = BLKPG_DEL_PARTITION;
187 a.flags = 0;
188 a.datalen = sizeof(pt);
189 a.data = &pt;
190 if (ioctl(fd, BLKPG, &a) == -1)
191 err = errno;
192 else
193 err = 0;
194 errmerge(err, lower,
195 "error deleting partition %d: ",
196 "error deleting partitions %d-%d: ");
197 /* expected errors:
198 EBUSY: mounted or in use as swap
199 ENXIO: no such nonempty partition
200 EINVAL: not wholedisk, or bad pno
201 EACCES/EPERM: permission denied
202 */
203 if (err && err != EBUSY && err != ENXIO) {
204 ret = 1;
205 break;
206 }
207 if (err == 0 && verbose)
208 printf("deleted partition %d\n", lower);
209 lower++;
210 }
211 errmerge(0, 0,
212 "error deleting partition %d: ",
213 "error deleting partitions %d-%d: ");
214 return ret;
215 }
216
217 if (device != diskdevice) {
218 fd2 = open(device, O_RDONLY);
219 if (fd2 == -1) {
220 perror(device);
221 exit(1);
222 }
223 } else {
224 fd2 = fd;
225 }
226
227 if (ioctl(fd, HDIO_GETGEO, &g)) {
228 perror("HDIO_GETGEO");
229 exit(1);
230 }
231 if (g.start != 0) {
232 fprintf(stderr, "last arg is not the whole disk\n");
233 fprintf(stderr, "call: partx -opts device wholedisk\n");
234 exit(1);
235 }
236
237 if (ioctl(fd2, HDIO_GETGEO, &g)) {
238 perror("HDIO_GETGEO");
239 exit(1);
240 }
241 all.start = g.start;
242
243 if(ioctl(fd2, BLKGETSIZE, &size)) {
244 perror("BLKGETSIZE");
245 exit(1);
246 }
247 all.size = size;
248
249 if (verbose)
250 printf("device %s: start %d size %d\n",
251 device, all.start, all.size);
252
253 if (all.size == 0) {
254 fprintf(stderr, "That disk slice has size 0\n");
255 exit(0);
256 }
257 if (all.size == 2)
258 all.size = 0; /* probably extended partition */
259
260 /* add the indicated partitions to the kernel partition tables */
261 if (!lower)
262 lower = 1;
263 for (i = 0; i < ptct; i++) {
264 ptp = &pts[i];
265 if (!type || !strcmp(type, ptp->type)) {
266 n = ptp->fn(fd, all, slices, SIZE(slices));
267 if (n >= 0 && verbose)
268 printf("%s: %d slices\n", ptp->type, n);
269 if (n > 0 && (verbose || what == LIST)) {
270 for (j=0; j<n; j++)
271 printf("#%2d: %9d-%9d (%9d sectors, %6d MB)\n",
272 lower+j,
273 slices[j].start,
274 slices[j].start+slices[j].size-1,
275 slices[j].size,
276 (int)((512 * (long long) slices[j].size)
277 / 1000000));
278 }
279 if (n > 0 && what == ADD) {
280 /* test for overlap, as in the case of an
281 extended partition, and reduce size */
282 for (j=0; j<n; j++) {
283 for (k=j+1; k<n; k++) {
284 if (slices[k].start > slices[j].start &&
285 slices[k].start < slices[j].start +
286 slices[j].size) {
287 slices[j].size = slices[k].start -
288 slices[j].start;
289 if (verbose)
290 printf("reduced size of "
291 "partition #%d to %d\n",
292 lower+j,
293 slices[j].size);
294 }
295 }
296 }
297 for (j=0; j<n; j++) {
298 pt.pno = lower+j;
299 pt.start = 512 * (long long) slices[j].start;
300 pt.length = 512 * (long long) slices[j].size;
301 pt.devname[0] = 0;
302 pt.volname[0] = 0;
303 a.op = BLKPG_ADD_PARTITION;
304 a.flags = 0;
305 a.datalen = sizeof(pt);
306 a.data = &pt;
307 if (ioctl(fd, BLKPG, &a) == -1) {
308 perror("BLKPG");
309 fprintf(stderr,
310 "error adding partition %d\n",
311 lower+j);
312 } else if (verbose)
313 printf("added partition %d\n", lower+j);
314 }
315 }
316 }
317 }
318
319 return 0;
320 }
321
322 static void *
323 xmalloc (size_t size) {
324 void *t;
325
326 if (size == 0)
327 return NULL;
328 t = malloc (size);
329 if (t == NULL) {
330 fprintf(stderr, "Out of memory\n");
331 exit(1);
332 }
333 return t;
334 }
335
336 static int
337 sseek(int fd, unsigned int secnr) {
338 long long in, out;
339 in = ((long long) secnr << 9);
340 out = 1;
341
342 if ((out = lseek(fd, in, SEEK_SET)) != in)
343 {
344 fprintf(stderr, "lseek error\n");
345 return -1;
346 }
347 return 0;
348 }
349
350 static
351 struct block {
352 unsigned int secnr;
353 char *block;
354 struct block *next;
355 } *blockhead;
356
357 char *
358 getblock(int fd, unsigned int secnr) {
359 struct block *bp;
360
361 for (bp = blockhead; bp; bp = bp->next)
362 if (bp->secnr == secnr)
363 return bp->block;
364 if (sseek(fd, secnr))
365 return NULL;
366 bp = xmalloc(sizeof(struct block));
367 bp->secnr = secnr;
368 bp->next = blockhead;
369 blockhead = bp;
370 bp->block = (char *) xmalloc(1024);
371 if (read(fd, bp->block, 1024) != 1024) {
372 fprintf(stderr, "read error, sector %d\n", secnr);
373 bp->block = NULL;
374 }
375 return bp->block;
376 }
377
378 /* call with errno and integer m and error message */
379 /* merge to interval m-n */
380 static void
381 errmerge(int err, int m, char *msg1, char *msg2) {
382 static int preverr, firstm, prevm;
383
384 if (err != preverr) {
385 if (preverr) {
386 if (firstm == prevm)
387 fprintf(stderr, msg1, firstm);
388 else
389 fprintf(stderr, msg2, firstm, prevm);
390 errno = preverr;
391 perror("BLKPG");
392 }
393 preverr = err;
394 firstm = prevm = m;
395 } else
396 prevm = m;
397 }