~ubuntu-branches/ubuntu/precise/util-linux/precise-proposed

« back to all changes in this revision

Viewing changes to partx/partx.c

  • Committer: Bazaar Package Importer
  • Author(s): Steve Langasek
  • Date: 2011-06-20 22:31:50 UTC
  • mfrom: (1.6.3 upstream) (4.5.1 sid)
  • Revision ID: james.westby@ubuntu.com-20110620223150-lz8wrv0946ihcz3z
Tags: 2.19.1-2ubuntu1
* Merge from Debian unstable, remaining changes:
  - Build for multiarch.
  - Add pre-depends on multiarch-support.
  - configure.ac: don't try to be clever about extracting a path name from
    $libdir to append to /usr in a way that's not overridable; instead,
    reuse the built-in configurable libexecdir.
  - Fix up the .pc.in files to know about libexecdir, so our substitutions
    don't leave us with unusable pkg-config files.
  - Install custom blkid.conf to use /dev/.blkid.tab since we don't
    expect device names to survive a reboot
  - Mention mountall(8) in fstab(5) manpages, along with its special
    options.
  - Since upstart is required in Ubuntu, the hwclock.sh init script is not
    called on startup and the hwclockfirst.sh init script is removed.
  - Drop depends on initscripts for the above.
  - Replace hwclock udev rule with an Upstart job.
  - For the case where mount is called with a directory to mount, look
    that directory up in mountall's /lib/init/fstab if we couldn't find
    it mentioned anywhere else.  This means "mount /proc", "mount /sys",
    etc. work.
  - mount.8 points to the cifs-utils package, not the obsolete smbfs one. 
* Dropped changes:
  - mount.preinst: lsb_release has been fixed in lucid and above to be
    usable without configuration, so we don't have to diverge from Debian
    here anymore.
* Changes merged upstream:
  - sfdisk support for '+' with '-N'
  - mount/umount.c: fix a segfault on umount with empty mtab entry
  - Fix arbitrary unmount with fuse security issue

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
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
 
 *
 
2
 * partx: tell the kernel about your disk's partitions
6
3
 * [This is not an fdisk - adding and removing partitions
7
4
 * is not a change of the disk, but just telling the kernel
8
5
 * about presence and numbering of on-disk partitions.]
9
6
 *
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
7
 * aeb, 2000-03-21 -- sah is 42 now
 
8
 *
 
9
 * Copyright (C) 2010 Davidlohr Bueso <dave@gnu.org>
 
10
 *      Rewritten to use libblkid for util-linux
 
11
 *      based on ideas from Karel Zak <kzak@redhat.com>
30
12
 */
31
13
 
32
14
#include <stdio.h>
33
15
#include <fcntl.h>
 
16
#include <err.h>
34
17
#include <errno.h>
35
18
#include <stdlib.h>
36
19
#include <string.h>
 
20
#include <ctype.h>
37
21
#include <getopt.h>
 
22
#include <sys/types.h>
 
23
#include <sys/stat.h>
38
24
#include <unistd.h>
 
25
#include <assert.h>
39
26
#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
27
#include <linux/blkpg.h>
 
28
#include <dirent.h>
 
29
 
 
30
#include <blkid.h>
45
31
 
46
32
#include "c.h"
 
33
#include "pathnames.h"
 
34
#include "nls.h"
 
35
#include "tt.h"
47
36
#include "blkdev.h"
48
 
 
 
37
#include "strutils.h"
 
38
#include "xalloc.h"
49
39
#include "partx.h"
50
 
#include "crc32.h"
51
 
static void errmerge(int err, int m, char *msg1, char *msg2);
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
 
        unsigned long 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 = strchr(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);
 
40
 
 
41
/* this is the default upper limit, could be modified by --nr */
 
42
#define SLICES_MAX      256
 
43
 
 
44
/* all the columns (-o option) */
 
45
enum {
 
46
        COL_PARTNO,
 
47
        COL_START,
 
48
        COL_END,
 
49
        COL_SECTORS,
 
50
        COL_SIZE,
 
51
        COL_NAME,
 
52
        COL_UUID,
 
53
        COL_TYPE,
 
54
        COL_FLAGS,
 
55
        COL_SCHEME,
 
56
        __NCOLUMNS
 
57
};
 
58
 
 
59
enum {
 
60
        ACT_LIST = 1,
 
61
        ACT_SHOW,
 
62
        ACT_ADD,
 
63
        ACT_DELETE
 
64
};
 
65
 
 
66
enum {
 
67
        FL_BYTES = (1 << 1)
 
68
};
 
69
 
 
70
/* column names */
 
71
struct colinfo {
 
72
        const char      *name;  /* header */
 
73
        double          whint;  /* width hint (N < 1 is in percent of termwidth) */
 
74
        int             flags;  /* TT_FL_* */
 
75
        const char      *help;
 
76
};
 
77
 
 
78
/* columns descriptions */
 
79
struct colinfo infos[__NCOLUMNS] = {
 
80
        [COL_PARTNO]   = { "NR",    0.25, TT_FL_RIGHT, N_("partition number") },
 
81
        [COL_START]    = { "START",   0.30, TT_FL_RIGHT, N_("start of the partition in sectors") },
 
82
        [COL_END]      = { "END",     0.30, TT_FL_RIGHT, N_("end of the partition in sectors") },
 
83
        [COL_SECTORS]  = { "SECTORS", 0.30, TT_FL_RIGHT, N_("number of sectors") },
 
84
        [COL_SIZE]     = { "SIZE",    0.30, TT_FL_RIGHT, N_("human readable size") },
 
85
        [COL_NAME]     = { "NAME",    0.30, TT_FL_TRUNC, N_("partition name") },
 
86
        [COL_UUID]     = { "UUID",    36, 0, N_("partition UUID")},
 
87
        [COL_SCHEME]   = { "SCHEME",  0.1, TT_FL_TRUNC, N_("partition table type (dos, gpt, ...)")},
 
88
        [COL_FLAGS]    = { "FLAGS",   0.1, TT_FL_TRUNC, N_("partition flags")},
 
89
        [COL_TYPE]     = { "TYPE",    1, TT_FL_RIGHT, N_("partition type hex or uuid")},
 
90
};
 
91
/* array with IDs of enabled columns */
 
92
static int columns[__NCOLUMNS], ncolumns;
 
93
 
 
94
static int verbose;
 
95
static int partx_flags;
 
96
 
 
97
 
 
98
static inline int get_column_id(int num)
 
99
{
 
100
        assert(ARRAY_SIZE(columns) == __NCOLUMNS);
 
101
        assert(num < ncolumns);
 
102
        assert(columns[num] < __NCOLUMNS);
 
103
        return columns[num];
 
104
}
 
105
 
 
106
static inline struct colinfo *get_column_info(int num)
 
107
{
 
108
        return &infos[ get_column_id(num) ];
 
109
}
 
110
 
 
111
static int column_name_to_id(const char *name, size_t namesz)
 
112
{
 
113
        int i;
 
114
 
 
115
        assert(name);
 
116
 
 
117
        for (i = 0; i < __NCOLUMNS; i++) {
 
118
                const char *cn = infos[i].name;
 
119
 
 
120
                if (!strncasecmp(name, cn, namesz) && !*(cn + namesz))
 
121
                        return i;
 
122
        }
 
123
        warnx(_("unknown column: %s"), name);
 
124
        return -1;
 
125
}
 
126
 
 
127
/*
 
128
 * Given a partition return the corresponding partition number.
 
129
 *
 
130
 * Note that this function tries to use sysfs, otherwise it assumes that the
 
131
 * last characters are always numeric (sda1, sdc20, etc).
 
132
 *
 
133
 * Returns -1 on error.
 
134
 */
 
135
static int get_partno_from_device(char *partition, dev_t devno)
 
136
{
 
137
        int partno = 0;
 
138
        size_t sz;
 
139
        char *p, *end = NULL;
 
140
 
 
141
        assert(partition);
 
142
 
 
143
        if (devno) {
 
144
                /* the device exits, read the partition number from /sys
 
145
                 * TODO: move this to stuff to lib/sysfs.c */
 
146
                char path[PATH_MAX];
 
147
                FILE *f;
 
148
 
 
149
                snprintf(path, sizeof(path),
 
150
                                _PATH_SYS_DEVBLOCK "/%d:%d/partition",
 
151
                                major(devno), minor(devno));
 
152
                f = fopen(path, "r");
 
153
                if (f) {
 
154
                        if (fscanf(f, "%d", &partno) != 1)
 
155
                                partno = 0;
 
156
                        fclose(f);
173
157
                }
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;
 
158
                if (partno)
 
159
                        return partno;
 
160
        }
 
161
 
 
162
        sz = strlen(partition);
 
163
        p = partition + sz - 1;
 
164
 
 
165
        if (!isdigit((unsigned int) *p))
 
166
                goto err;
 
167
 
 
168
        while (isdigit((unsigned int) *(p - 1))) p--;
 
169
 
 
170
        errno = 0;
 
171
        partno = strtol(p, &end, 10);
 
172
        if (errno || !end || *end || p == end)
 
173
                goto err;
 
174
 
 
175
        return partno;
 
176
err:
 
177
        errx(EXIT_FAILURE, _("%s: failed to get partition number"), partition);
 
178
}
 
179
 
 
180
static int get_max_partno(const char *disk, dev_t devno)
 
181
{
 
182
        char path[PATH_MAX], *parent;
 
183
        struct stat st;
 
184
        DIR *dir;
 
185
        struct dirent *d;
 
186
        int partno = 0;
 
187
 
 
188
        if (!devno && !stat(disk, &st))
 
189
                devno = st.st_rdev;
 
190
        if (!devno)
 
191
                goto dflt;
 
192
        parent = strrchr(disk, '/');
 
193
        if (!parent)
 
194
                goto dflt;
 
195
        parent++;
 
196
 
 
197
        snprintf(path, sizeof(path), _PATH_SYS_DEVBLOCK "/%d:%d/",
 
198
                        major(devno), minor(devno));
 
199
 
 
200
        dir = opendir(path);
 
201
        if (!dir)
 
202
                goto dflt;
 
203
 
 
204
         while ((d = readdir(dir))) {
 
205
                int fd;
 
206
 
 
207
                if (!strcmp(d->d_name, ".") ||
 
208
                    !strcmp(d->d_name, ".."))
 
209
                        continue;
 
210
#ifdef _DIRENT_HAVE_D_TYPE
 
211
                if (d->d_type != DT_DIR)
 
212
                        continue;
 
213
#endif
 
214
                if (strncmp(parent, d->d_name, strlen(parent)))
 
215
                        continue;
 
216
                snprintf(path, sizeof(path), "%s/partition", d->d_name);
 
217
 
 
218
                fd = openat(dirfd(dir), path, O_RDONLY);
 
219
                if (fd) {
 
220
                        int x = 0;
 
221
                        FILE *f = fdopen(fd, "r");
 
222
                        if (f) {
 
223
                                if (fscanf(f, "%d", &x) == 1 && x > partno)
 
224
                                        partno = x;
 
225
                                fclose(f);
206
226
                        }
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 (blkdev_get_sectors(fd2, &size) != 0) {
244
 
                perror("partx");
245
 
                exit(1);
246
 
        }
247
 
        all.size = (unsigned int) 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 */
 
227
                }
 
228
        }
 
229
 
 
230
        closedir(dir);
 
231
        return partno;
 
232
dflt:
 
233
        return SLICES_MAX;
 
234
}
 
235
 
 
236
static void del_parts_warnx(const char *device, int first, int last)
 
237
{
 
238
        if (first == last)
 
239
                warnx(_("%s: error deleting partition %d"), device, first);
 
240
        else
 
241
                warnx(_("%s: error deleting partitions %d-%d"),
 
242
                                device, first, last);
 
243
}
 
244
 
 
245
static int del_parts(int fd, const char *device, dev_t devno,
 
246
                     int lower, int upper)
 
247
{
 
248
        int rc = 0, i, errfirst = 0, errlast = 0;
 
249
 
 
250
        assert(fd >= 0);
 
251
        assert(device);
 
252
 
261
253
        if (!lower)
262
254
                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, ARRAY_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
 
        unsigned char *block;
354
 
        struct block *next;
355
 
} *blockhead;
356
 
 
357
 
unsigned 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 = (unsigned 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;
 
255
        if (!upper || lower < 0 || upper < 0) {
 
256
                int n = get_max_partno(device, devno);
 
257
                if (!upper)
 
258
                        upper = n;
 
259
                else if (upper < 0)
 
260
                        upper = n + upper + 1;
 
261
                if (lower < 0)
 
262
                        lower = n + lower + 1;
 
263
        }
 
264
        if (lower > upper) {
 
265
                warnx(_("defined range <%d:%d> "
 
266
                        "does not make sense"), lower, upper);
 
267
                return -1;
 
268
        }
 
269
 
 
270
        for (i = lower; i <= upper; i++) {
 
271
                if (partx_del_partition(fd, i) == 0) {
 
272
                        if (verbose)
 
273
                                printf(_("%s: partition #%d removed\n"), device, i);
 
274
                        continue;
 
275
                }
 
276
                rc = -1;
 
277
                if (verbose)
 
278
                        warn(_("%s: delete partition #%d failed"), device, i);
 
279
                if (!errfirst)
 
280
                        errlast = errfirst = i;
 
281
                else if (errlast + 1 == i)
 
282
                        errlast++;
 
283
                else {
 
284
                        del_parts_warnx(device, errfirst, errlast);
 
285
                        errlast = errfirst = i;
 
286
                }
 
287
        }
 
288
 
 
289
        if (errfirst)
 
290
                del_parts_warnx(device, errfirst, errlast);
 
291
        return rc;
 
292
}
 
293
 
 
294
static void add_parts_warnx(const char *device, int first, int last)
 
295
{
 
296
        if (first == last)
 
297
                warnx(_("%s: error adding partition %d"), device, first);
 
298
        else
 
299
                warnx(_("%s: error adding partitions %d-%d"),
 
300
                                device, first, last);
 
301
}
 
302
 
 
303
static int add_parts(int fd, const char *device,
 
304
                        blkid_partlist ls, int lower, int upper)
 
305
{
 
306
        int i, nparts, rc = 0, errfirst = 0, errlast = 0;
 
307
 
 
308
        assert(fd >= 0);
 
309
        assert(device);
 
310
        assert(ls);
 
311
 
 
312
        nparts = blkid_partlist_numof_partitions(ls);
 
313
 
 
314
        for (i = 0; i < nparts; i++) {
 
315
                blkid_partition par = blkid_partlist_get_partition(ls, i);
 
316
                int n = blkid_partition_get_partno(par);
 
317
                uintmax_t start, size;
 
318
 
 
319
                if (lower && n < lower)
 
320
                        continue;
 
321
                if (upper && n > upper)
 
322
                        continue;
 
323
 
 
324
                start = blkid_partition_get_start(par);
 
325
                size =  blkid_partition_get_size(par);
 
326
 
 
327
                if (blkid_partition_is_extended(par))
 
328
                        /*
 
329
                         * Let's follow Linux kernel and reduce
 
330
                         * DOS extended partition to 1 or 2 sectors
 
331
                         */
 
332
                        size = min(size, (uintmax_t) 2);
 
333
 
 
334
                if (partx_add_partition(fd, n, start, size) == 0) {
 
335
                        if (verbose)
 
336
                                printf(_("%s: partition #%d added\n"), device, n);
 
337
                        continue;
 
338
                }
 
339
                rc = -1;
 
340
                if (verbose)
 
341
                        warn(_("%s: add partition #%d failed"), device, n);
 
342
                if (!errfirst)
 
343
                        errlast = errfirst = n;
 
344
                else if (errlast + 1 == n)
 
345
                        errlast++;
 
346
                else {
 
347
                        add_parts_warnx(device, errfirst, errlast);
 
348
                        errlast = errfirst = n;
 
349
                }
 
350
        }
 
351
 
 
352
        if (errfirst)
 
353
                add_parts_warnx(device, errfirst, errlast);
 
354
        return rc;
 
355
}
 
356
 
 
357
static int list_parts(blkid_partlist ls, int lower, int upper)
 
358
{
 
359
        int i, nparts;
 
360
 
 
361
        assert(ls);
 
362
 
 
363
        nparts = blkid_partlist_numof_partitions(ls);
 
364
 
 
365
        for (i = 0; i < nparts; i++) {
 
366
                blkid_partition par = blkid_partlist_get_partition(ls, i);
 
367
                int n = blkid_partition_get_partno(par);
 
368
                uintmax_t start, size;
 
369
 
 
370
                if (lower && n < lower)
 
371
                        continue;
 
372
                if (upper && n > upper)
 
373
                        continue;
 
374
 
 
375
                start = blkid_partition_get_start(par);
 
376
                size =  blkid_partition_get_size(par);
 
377
 
 
378
                printf("#%2d: %9ju-%9ju (%9ju sectors, %6ju MB)\n",
 
379
                       n, start, start + size -1,
 
380
                       size, (size << 9) / 1000000);
 
381
        }
 
382
        return 0;
 
383
}
 
384
 
 
385
static void add_tt_line(struct tt *tt, blkid_partition par)
 
386
{
 
387
        struct tt_line *line;
 
388
        int i;
 
389
 
 
390
        assert(tt);
 
391
        assert(par);
 
392
 
 
393
        line = tt_add_line(tt, NULL);
 
394
        if (!line) {
 
395
                warn(_("failed to add line to output"));
 
396
                return;
 
397
        }
 
398
 
 
399
        for (i = 0; i < ncolumns; i++) {
 
400
                char *str = NULL;
 
401
                int rc = 0;
 
402
 
 
403
                switch (get_column_id(i)) {
 
404
                case COL_PARTNO:
 
405
                        rc = asprintf(&str, "%d",
 
406
                                        blkid_partition_get_partno(par));
 
407
                        break;
 
408
                case COL_START:
 
409
                        rc = asprintf(&str, "%ju",
 
410
                                        blkid_partition_get_start(par));
 
411
                        break;
 
412
                case COL_END:
 
413
                        rc = asprintf(&str, "%ju",
 
414
                                        blkid_partition_get_start(par) +
 
415
                                        blkid_partition_get_size(par) - 1);
 
416
                        break;
 
417
                case COL_SECTORS:
 
418
                        rc = asprintf(&str, "%ju",
 
419
                                        blkid_partition_get_size(par));
 
420
                        break;
 
421
                case COL_SIZE:
 
422
                        if (partx_flags & FL_BYTES)
 
423
                                rc = asprintf(&str, "%ju", (uintmax_t)
 
424
                                        blkid_partition_get_size(par) << 9);
 
425
                        else
 
426
                                str = size_to_human_string(
 
427
                                        blkid_partition_get_size(par) << 9);
 
428
                        break;
 
429
                case COL_NAME:
 
430
                        str = (char *) blkid_partition_get_name(par);
 
431
                        if (str)
 
432
                                str = xstrdup(str);
 
433
                        break;
 
434
                case COL_UUID:
 
435
                        str = (char *) blkid_partition_get_uuid(par);
 
436
                        if (str)
 
437
                                str = xstrdup(str);
 
438
                        break;
 
439
                case COL_TYPE:
 
440
                        str = (char *) blkid_partition_get_type_string(par);
 
441
                        if (str)
 
442
                                str = xstrdup(str);
 
443
                        else
 
444
                                rc = asprintf(&str, "0x%x",
 
445
                                        blkid_partition_get_type(par));
 
446
                        break;
 
447
                case COL_FLAGS:
 
448
                        rc = asprintf(&str, "0x%llx", blkid_partition_get_flags(par));
 
449
                        break;
 
450
                case COL_SCHEME:
 
451
                {
 
452
                        blkid_parttable tab = blkid_partition_get_table(par);
 
453
                        if (tab) {
 
454
                                str = (char *) blkid_parttable_get_type(tab);
 
455
                                if (str)
 
456
                                        str = xstrdup(str);
 
457
                        }
 
458
                        break;
 
459
                }
 
460
                default:
 
461
                        break;
 
462
                }
 
463
 
 
464
                if (rc || str)
 
465
                        tt_line_set_data(line, i, str);
 
466
        }
 
467
}
 
468
 
 
469
static int show_parts(blkid_partlist ls, int tt_flags, int lower, int upper)
 
470
{
 
471
        int i, rc = -1;
 
472
        struct tt *tt;
 
473
        int nparts;
 
474
 
 
475
        assert(ls);
 
476
 
 
477
        nparts = blkid_partlist_numof_partitions(ls);
 
478
        if (!nparts)
 
479
                return 0;
 
480
 
 
481
        tt = tt_new_table(tt_flags);
 
482
        if (!tt) {
 
483
                warn(_("failed to initialize output table"));
 
484
                return -1;
 
485
        }
 
486
 
 
487
        for (i = 0; i < ncolumns; i++) {
 
488
                struct colinfo *col = get_column_info(i);
 
489
 
 
490
                if (!tt_define_column(tt, col->name, col->whint, col->flags)) {
 
491
                        warnx(_("failed to initialize output column"));
 
492
                        goto done;
 
493
                }
 
494
        }
 
495
 
 
496
        for (i = 0; i < nparts; i++) {
 
497
                blkid_partition par = blkid_partlist_get_partition(ls, i);
 
498
                int n = blkid_partition_get_partno(par);
 
499
 
 
500
                if (lower && n < lower)
 
501
                        continue;
 
502
                if (upper && n > upper)
 
503
                        continue;
 
504
 
 
505
                add_tt_line(tt, par);
 
506
        }
 
507
 
 
508
        rc = 0;
 
509
        tt_print_table(tt);
 
510
done:
 
511
        tt_free_table(tt);
 
512
        return rc;
 
513
}
 
514
 
 
515
static int parse_range(const char *str, int *lower, int *upper)
 
516
{
 
517
        char *end = NULL;
 
518
 
 
519
        if (!str)
 
520
                return 0;
 
521
 
 
522
        *upper = *lower = 0;
 
523
        errno = 0;
 
524
 
 
525
        if (*str == ':') {                              /* <:N> */
 
526
                str++;
 
527
                *upper = strtol(str, &end, 10);
 
528
                if (errno || !end || *end || end == str)
 
529
                        return -1;
 
530
        } else {
 
531
                *upper = *lower = strtol(str, &end, 10);
 
532
                if (errno || !end || end == str)
 
533
                        return -1;
 
534
 
 
535
                if (*end == ':' && !*(end + 1))         /* <M:> */
 
536
                        *upper = 0;
 
537
                else if (*end == '-' || *end == ':') {  /* <M:N> <M-N> */
 
538
                        str = end + 1;
 
539
                        end = NULL;
 
540
                        errno = 0;
 
541
                        *upper = strtol(str, &end, 10);
 
542
 
 
543
                        if (errno || !end || *end || end == str)
 
544
                                return -1;
 
545
                }
 
546
        }
 
547
        return 0;
 
548
}
 
549
 
 
550
static blkid_partlist get_partlist(blkid_probe pr,
 
551
                        const char *device, char *type)
 
552
{
 
553
        blkid_partlist ls;
 
554
        blkid_parttable tab;
 
555
 
 
556
        assert(pr);
 
557
        assert(device);
 
558
 
 
559
        if (type) {
 
560
                char *name[] = { type, NULL };
 
561
 
 
562
                if (blkid_probe_filter_partitions_type(pr,
 
563
                                BLKID_FLTR_ONLYIN, name)) {
 
564
                        warnx(_("failed to initialize blkid "
 
565
                                        "filter for '%s'"), type);
 
566
                        return NULL;
 
567
                }
 
568
        }
 
569
 
 
570
        ls = blkid_probe_get_partitions(pr);
 
571
        if (!ls) {
 
572
                warnx(_("%s: failed to read partition table"), device);
 
573
                return NULL;
 
574
        }
 
575
 
 
576
        tab = blkid_partlist_get_table(ls);
 
577
        if (verbose && tab)
 
578
                printf(_("%s: partition table '%s' detected\n"),
 
579
                                device,
 
580
                                blkid_parttable_get_type(tab));
 
581
 
 
582
        if (!blkid_partlist_numof_partitions(ls)) {
 
583
                warnx(_("%s: %s partition table does not contains "
 
584
                        "usable partitions"), device,
 
585
                        blkid_parttable_get_type(tab));
 
586
                return NULL;
 
587
        }
 
588
        return ls;
 
589
}
 
590
 
 
591
static void __attribute__((__noreturn__)) usage(FILE *out)
 
592
{
 
593
        int i;
 
594
 
 
595
        fprintf(out, _(
 
596
                "\nUsage:\n"
 
597
                " %s [-a|-d|-s] [--nr <N:M> | <device>] <wholedisk>\n"),
 
598
                program_invocation_short_name);
 
599
 
 
600
        fprintf(out, _(
 
601
                "\nOptions:\n"
 
602
                " -a, --add            add specified partitions or all of them\n"
 
603
                " -d, --delete         delete specified partitions or all of them\n"
 
604
                " -l, --list           list partitions (DEPRECATED)\n"
 
605
                " -s, --show           list partitions\n\n"
 
606
 
 
607
                " -b, --bytes          print SIZE in bytes rather than in human readable format\n"
 
608
                " -g, --noheadings     don't print headings for --show\n"
 
609
                " -r, --raw            use raw format output\n"
 
610
                " -t, --type <TYPE>    specify the partition type (dos, bsd, solaris, etc.)\n"
 
611
                " -n, --nr <M:N>       specify the range of partitions (--nr 2:4)\n"
 
612
                " -o, --output <LIST>  output column\n"
 
613
                " -h, --help           print this help\n\n"));
 
614
 
 
615
        fprintf(out, _("\nAvailable columns (for --show):\n"));
 
616
 
 
617
        for (i = 0; i < __NCOLUMNS; i++)
 
618
                fprintf(out, " %10s  %s\n", infos[i].name, _(infos[i].help));
 
619
 
 
620
        fprintf(out, _("\nFor more information see partx(8).\n"));
 
621
 
 
622
        exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
 
623
}
 
624
 
 
625
static void __attribute__((__noreturn__))
 
626
errx_mutually_exclusive(const char *opts)
 
627
{
 
628
        errx(EXIT_FAILURE, "%s %s", opts, _("options are mutually exclusive"));
 
629
}
 
630
 
 
631
int main(int argc, char **argv)
 
632
{
 
633
        int fd, c, what = 0, lower = 0, upper = 0, rc = 0;
 
634
        int tt_flags = 0;
 
635
        char *type = NULL;
 
636
        char *device = NULL; /* pointer to atgv[], ie: /dev/sda1 */
 
637
        char *wholedisk = NULL; /* allocated, ie: /dev/sda */
 
638
        dev_t disk_devno = 0, part_devno = 0;
 
639
 
 
640
        static const struct option long_opts[] = {
 
641
                { "bytes",      no_argument,       NULL, 'b' },
 
642
                { "noheadings", no_argument,       NULL, 'g' },
 
643
                { "raw",        no_argument,       NULL, 'r' },
 
644
                { "list",       no_argument,       NULL, 'l' },
 
645
                { "show",       no_argument,       NULL, 's' },
 
646
                { "add",        no_argument,       NULL, 'a' },
 
647
                { "delete",     no_argument,       NULL, 'd' },
 
648
                { "type",       required_argument, NULL, 't' },
 
649
                { "nr",         required_argument, NULL, 'n' },
 
650
                { "output",     required_argument, NULL, 'o' },
 
651
                { "help",       no_argument,       NULL, 'h' },
 
652
                { NULL, 0, NULL, 0 }
 
653
        };
 
654
 
 
655
        while ((c = getopt_long(argc, argv, "abdglrsvn:t:o:h", long_opts, NULL)) != -1) {
 
656
                switch(c) {
 
657
                case 'a':
 
658
                        if (what)
 
659
                                errx_mutually_exclusive("--{add,delete,show,list,raw}");
 
660
                        what = ACT_ADD;
 
661
                        break;
 
662
                case 'b':
 
663
                        partx_flags |= FL_BYTES;
 
664
                        break;
 
665
                case 'd':
 
666
                        if (what)
 
667
                                errx_mutually_exclusive("--{add,delete,show,list,raw}");
 
668
                        what = ACT_DELETE;
 
669
                        break;
 
670
                case 'g':
 
671
                        tt_flags |= TT_FL_NOHEADINGS;
 
672
                        break;
 
673
                case 'l':
 
674
                        if (what)
 
675
                                errx_mutually_exclusive("--{add,delete,show,list,raw}");
 
676
                        what = ACT_LIST;
 
677
                        break;
 
678
                case 'n':
 
679
                        if (parse_range(optarg, &lower, &upper))
 
680
                                errx(EXIT_FAILURE, _("failed to parse --nr <M-N> range"));
 
681
                        break;
 
682
 
 
683
                case 'o':
 
684
                        if (tt_parse_columns_list(optarg, columns, &ncolumns,
 
685
                                                column_name_to_id))
 
686
                                return EXIT_FAILURE;
 
687
                        break;
 
688
                case 'r':
 
689
                        tt_flags |= TT_FL_RAW;
 
690
                        if (what)
 
691
                                errx_mutually_exclusive("--{add,delete,show,list,raw}");
 
692
                        what = ACT_SHOW;
 
693
                        break;
 
694
 
 
695
                case 's':
 
696
                        if (what)
 
697
                                errx_mutually_exclusive("--{add,delete,show,list,raw}");
 
698
                        what = ACT_SHOW;
 
699
                        break;
 
700
                case 't':
 
701
                        type = optarg;
 
702
                        break;
 
703
                case 'v':
 
704
                        verbose = 1;
 
705
                        break;
 
706
                case 'h':
 
707
                        usage(stdout);
 
708
                case '?':
 
709
                default:
 
710
                        usage(stderr);
 
711
                }
 
712
        }
 
713
 
 
714
        /* -o <list> enables --show mode by default */
 
715
        if (ncolumns && !what)
 
716
                what = ACT_SHOW;
 
717
 
 
718
        /* backwardly compatible default */
 
719
        if (!what)
 
720
                what = ACT_LIST;
 
721
 
 
722
        /* --show default, could by modified by -o  */
 
723
        if (what == ACT_SHOW && !ncolumns) {
 
724
                columns[ncolumns++] = COL_PARTNO;
 
725
                columns[ncolumns++] = COL_START;
 
726
                columns[ncolumns++] = COL_END;
 
727
                columns[ncolumns++] = COL_SECTORS;
 
728
                columns[ncolumns++] = COL_SIZE;
 
729
                columns[ncolumns++] = COL_NAME;
 
730
                columns[ncolumns++] = COL_UUID;
 
731
        }
 
732
 
 
733
        /*
 
734
         * Note that 'partx /dev/sda1' == 'partx /dev/sda1 /dev/sda'
 
735
         * so assume that the device and/or disk are always the last
 
736
         * arguments to be passed to partx.
 
737
         */
 
738
        if (optind == argc - 2) {
 
739
                /* passed 2 arguments:
 
740
                 *   /dev/sda1 /dev/sda  : partition + whole-disk
 
741
                 *   -- /dev/sda1        : partition that should be used as a whole-disk
 
742
                 */
 
743
                device = argv[optind];
 
744
 
 
745
                if (strcmp(device, "-") == 0) {
 
746
                        device = NULL;
 
747
                        wholedisk = xstrdup(argv[optind + 1]);
 
748
                } else {
 
749
                        device = argv[optind];
 
750
                        wholedisk = xstrdup(argv[optind + 1]);
 
751
                }
 
752
        } else if (optind == argc - 1) {
 
753
                /* passed only one arg (ie: /dev/sda3 or /dev/sda) */
 
754
                struct stat sb;
 
755
 
 
756
                device = argv[optind];
 
757
 
 
758
                if (stat(device, &sb))
 
759
                        err(EXIT_FAILURE, _("%s: stat failed"), device);
 
760
 
 
761
                part_devno = sb.st_rdev;
 
762
 
 
763
                if (blkid_devno_to_wholedisk(part_devno,
 
764
                                             NULL, 0, &disk_devno) == 0 &&
 
765
                    part_devno != disk_devno)
 
766
                        wholedisk = blkid_devno_to_devname(disk_devno);
 
767
 
 
768
                if (!wholedisk) {
 
769
                        wholedisk = xstrdup(device);
 
770
                        disk_devno = part_devno;
 
771
                        device = NULL;
 
772
                        part_devno = 0;
 
773
                }
395
774
        } else
396
 
                prevm = m;
 
775
                usage(stderr);
 
776
 
 
777
        if (device && (upper || lower))
 
778
                errx(EXIT_FAILURE, _("--nr and <partition> are mutually exclusive}"));
 
779
 
 
780
        assert(wholedisk);
 
781
 
 
782
        if (device) {
 
783
                /* use partno from given partition instead of --nr range, e.g:
 
784
                 *   partx -d /dev/sda3
 
785
                 * is the same like:
 
786
                 *   partx -d --nr 3 /dev/sda
 
787
                 */
 
788
                struct stat sb;
 
789
 
 
790
                if (!part_devno && !stat(device, &sb))
 
791
                        part_devno = sb.st_rdev;
 
792
 
 
793
                lower = upper = get_partno_from_device(device, part_devno);
 
794
        }
 
795
 
 
796
        if (verbose)
 
797
                printf("device: %s, whole-disk: %s, lower: %d, upper: %d\n",
 
798
                                device, wholedisk, lower, upper);
 
799
 
 
800
        if (what == ACT_ADD || what == ACT_DELETE) {
 
801
                struct stat x;
 
802
 
 
803
                if (stat(wholedisk, &x) || !S_ISBLK(x.st_mode))
 
804
                        errx(EXIT_FAILURE, _("%s: not a block device"), wholedisk);
 
805
        }
 
806
        if ((fd = open(wholedisk, O_RDONLY)) == -1)
 
807
                err(EXIT_FAILURE, _("%s: open failed"), wholedisk);
 
808
 
 
809
        if (what == ACT_DELETE)
 
810
                rc = del_parts(fd, wholedisk, disk_devno, lower, upper);
 
811
        else {
 
812
                blkid_probe pr = blkid_new_probe();
 
813
                blkid_partlist ls = NULL;
 
814
 
 
815
                if (!pr || blkid_probe_set_device(pr, fd, 0, 0))
 
816
                        warnx(_("%s: failed to initialize blkid prober"),
 
817
                                        wholedisk);
 
818
                else
 
819
                        ls = get_partlist(pr, wholedisk, type);
 
820
 
 
821
                if (ls) {
 
822
                        int n = blkid_partlist_numof_partitions(ls);
 
823
 
 
824
                        if (lower < 0)
 
825
                                lower = n + lower + 1;
 
826
                        if (upper < 0)
 
827
                                upper = n + upper + 1;
 
828
                        if (lower > upper) {
 
829
                                warnx(_("defined range <%d:%d> "
 
830
                                        "does not make sense"), lower, upper);
 
831
                                rc = -1, what = 0;
 
832
                        }
 
833
 
 
834
                        switch (what) {
 
835
                        case ACT_SHOW:
 
836
                                rc = show_parts(ls, tt_flags, lower, upper);
 
837
                                break;
 
838
                        case ACT_LIST:
 
839
                                rc = list_parts(ls, lower, upper);
 
840
                                break;
 
841
                        case ACT_ADD:
 
842
                                rc = add_parts(fd, wholedisk, ls, lower, upper);
 
843
                                break;
 
844
                        }
 
845
                }
 
846
                blkid_free_probe(pr);
 
847
        }
 
848
 
 
849
        close(fd);
 
850
        return rc ? EXIT_FAILURE : EXIT_SUCCESS;
397
851
}
 
852