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