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