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