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

« back to all changes in this revision

Viewing changes to misc-utils/lsblk.c

  • Committer: Package Import Robot
  • Author(s): LaMont Jones
  • Date: 2011-11-03 15:38:23 UTC
  • mto: (4.5.5 sid) (1.6.4)
  • mto: This revision was merged to the branch mainline in revision 85.
  • Revision ID: package-import@ubuntu.com-20111103153823-10sx16jprzxlhkqf
ImportĀ upstreamĀ versionĀ 2.20.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*
2
2
 * lsblk(8) - list block devices
3
3
 *
4
 
 * Copyright (C) 2010 Red Hat, Inc. All rights reserved.
 
4
 * Copyright (C) 2010,2011 Red Hat, Inc. All rights reserved.
5
5
 * Written by Milan Broz <mbroz@redhat.com>
6
6
 *            Karel Zak <kzak@redhat.com>
7
7
 *
31
31
#include <dirent.h>
32
32
#include <fcntl.h>
33
33
#include <string.h>
34
 
#include <err.h>
35
34
#include <sys/ioctl.h>
36
35
#include <inttypes.h>
37
36
#include <stdarg.h>
38
37
#include <locale.h>
39
38
#include <pwd.h>
40
39
#include <grp.h>
 
40
#include <ctype.h>
41
41
 
42
42
#include <blkid.h>
43
43
 
51
51
#include "tt.h"
52
52
#include "xalloc.h"
53
53
#include "strutils.h"
 
54
#include "c.h"
 
55
#include "sysfs.h"
54
56
 
55
57
/* column IDs */
56
58
enum {
65
67
        COL_RM,
66
68
        COL_MODEL,
67
69
        COL_SIZE,
 
70
        COL_STATE,
68
71
        COL_OWNER,
69
72
        COL_GROUP,
70
73
        COL_MODE,
75
78
        COL_LOGSEC,
76
79
        COL_ROTA,
77
80
        COL_SCHED,
 
81
        COL_RQ_SIZE,
 
82
        COL_TYPE,
 
83
        COL_DALIGN,
 
84
        COL_DGRAN,
 
85
        COL_DMAX,
 
86
        COL_DZERO,
78
87
 
79
88
        __NCOLUMNS
80
89
};
90
99
/* columns descriptions */
91
100
static struct colinfo infos[__NCOLUMNS] = {
92
101
        [COL_NAME]   = { "NAME",    0.25, TT_FL_TREE, N_("device name") },
93
 
        [COL_KNAME]  = { "KNAME",   0.3, 0, N_("internel kernel device name") },
 
102
        [COL_KNAME]  = { "KNAME",   0.3, 0, N_("internal kernel device name") },
94
103
        [COL_MAJMIN] = { "MAJ:MIN", 6, 0, N_("major:minor device number") },
95
104
        [COL_FSTYPE] = { "FSTYPE",  0.1, TT_FL_TRUNC, N_("filesystem type") },
96
105
        [COL_TARGET] = { "MOUNTPOINT", 0.10, TT_FL_TRUNC, N_("where the device is mounted") },
101
110
        [COL_ROTA]   = { "ROTA",    1, TT_FL_RIGHT, N_("rotational device") },
102
111
        [COL_MODEL]  = { "MODEL",   0.1, TT_FL_TRUNC, N_("device identifier") },
103
112
        [COL_SIZE]   = { "SIZE",    6, TT_FL_RIGHT, N_("size of the device") },
 
113
        [COL_STATE]  = { "STATE",   7, TT_FL_TRUNC, N_("state of the device") },
104
114
        [COL_OWNER]  = { "OWNER",   0.1, TT_FL_TRUNC, N_("user name"), },
105
115
        [COL_GROUP]  = { "GROUP",   0.1, TT_FL_TRUNC, N_("group name") },
106
116
        [COL_MODE]   = { "MODE",    10,   0, N_("device node permissions") },
109
119
        [COL_OPTIO]  = { "OPT-IO",  6, TT_FL_RIGHT, N_("optimal I/O size") },
110
120
        [COL_PHYSEC] = { "PHY-SEC", 7, TT_FL_RIGHT, N_("physical sector size") },
111
121
        [COL_LOGSEC] = { "LOG-SEC", 7, TT_FL_RIGHT, N_("logical sector size") },
112
 
        [COL_SCHED]  = { "SCHED",   0.1, 0, N_("I/O scheduler name") }
113
 
 
 
122
        [COL_SCHED]  = { "SCHED",   0.1, 0, N_("I/O scheduler name") },
 
123
        [COL_RQ_SIZE]= { "RQ-SIZE", 5, TT_FL_RIGHT, N_("request queue size") },
 
124
        [COL_TYPE]   = { "TYPE",    4, 0, N_("device type") },
 
125
        [COL_DALIGN] = { "DISC-ALN", 6, TT_FL_RIGHT, N_("discard alignment offset") },
 
126
        [COL_DGRAN]  = { "DISC-GRAN", 6, TT_FL_RIGHT, N_("discard granularity") },
 
127
        [COL_DMAX]   = { "DISC-MAX", 6, TT_FL_RIGHT, N_("discard max bytes") },
 
128
        [COL_DZERO]  = { "DISC-ZERO", 1, TT_FL_RIGHT, N_("discard zeroes data") },
114
129
};
115
130
 
116
131
struct lsblk {
117
 
        struct tt *tt;          /* output table */
118
 
        int all_devices:1;      /* print all devices */
119
 
        int bytes:1;            /* print SIZE in bytes */
120
 
        int nodeps:1;           /* don't print slaves/holders */
 
132
        struct tt *tt;                  /* output table */
 
133
        unsigned int all_devices:1;     /* print all devices */
 
134
        unsigned int bytes:1;           /* print SIZE in bytes */
 
135
        unsigned int nodeps:1;          /* don't print slaves/holders */
121
136
};
122
137
 
123
138
struct lsblk *lsblk;    /* global handler */
124
139
int columns[__NCOLUMNS];/* enabled columns */
125
140
int ncolumns;           /* number of enabled columns */
126
141
 
127
 
unsigned int excludes[256];
128
 
int nexcludes;
 
142
int excludes[256];
 
143
size_t nexcludes;
129
144
 
130
145
struct blkdev_cxt {
131
146
        struct blkdev_cxt *parent;
137
152
        char *dm_name;          /* DM name (dm/block) */
138
153
 
139
154
        char *filename;         /* path to device node */
140
 
        int sysfs_fd;           /* O_RDONLY file desciptor to /sys/block/<dev> */
 
155
 
 
156
        struct sysfs_cxt  sysfs;
141
157
 
142
158
        int partition;          /* is partition? TRUE/FALSE */
143
159
 
150
166
                                 * /sys/block/.../holders + number of partition */
151
167
        int nslaves;            /* # of devices this device maps to */
152
168
        int maj, min;           /* devno */
 
169
        int discard;            /* supports discard */
153
170
 
154
171
        uint64_t size;          /* device size */
155
172
};
156
173
 
157
174
static int is_maj_excluded(int maj)
158
175
{
159
 
        int i;
 
176
        size_t i;
160
177
 
161
178
        assert(ARRAY_SIZE(excludes) > nexcludes);
162
179
 
166
183
        return 0;
167
184
}
168
185
 
169
 
 
170
186
/* array with IDs of enabled columns */
171
187
static int get_column_id(int num)
172
188
{
181
197
        return &infos[ get_column_id(num) ];
182
198
}
183
199
 
184
 
 
185
200
static int column_name_to_id(const char *name, size_t namesz)
186
201
{
187
202
        int i;
207
222
        free(cxt->uuid);
208
223
        free(cxt->label);
209
224
 
210
 
        if (cxt->sysfs_fd >= 0)
211
 
                close(cxt->sysfs_fd);
 
225
        sysfs_deinit(&cxt->sysfs);
212
226
 
213
227
        memset(cxt, 0, sizeof(*cxt));
214
228
}
235
249
        return d;
236
250
}
237
251
 
238
 
 
239
 
static int is_partition_dirent(DIR *dir, struct dirent *d, const char *parent_name)
240
 
{
241
 
        char path[256];
242
 
 
243
 
        assert(dir);
244
 
        assert(d);
245
 
 
246
 
#ifdef _DIRENT_HAVE_D_TYPE
247
 
        if (d->d_type != DT_DIR)
248
 
                return 0;
249
 
#endif
250
 
        if (strncmp(parent_name, d->d_name, strlen(parent_name)))
251
 
                return 0;
252
 
 
253
 
        /* Cannot use /partition file, not supported on old sysfs */
254
 
        snprintf(path, sizeof(path), "%s/start", d->d_name);
255
 
 
256
 
        return faccessat(dirfd(dir), path, R_OK, 0) == 0;
257
 
}
258
 
 
259
252
static char *get_device_path(struct blkdev_cxt *cxt)
260
253
{
261
254
        char path[PATH_MAX];
270
263
        return xstrdup(path);
271
264
}
272
265
 
273
 
static char *get_sysfs_path(struct blkdev_cxt *cxt)
274
 
{
275
 
        char path[PATH_MAX];
276
 
 
277
 
        assert(cxt);
278
 
        assert(cxt->name);
279
 
 
280
 
        if (cxt->partition && cxt->parent)
281
 
                snprintf(path, sizeof(path), _PATH_SYS_BLOCK "/%s/%s",
282
 
                         cxt->parent->name, cxt->name);
283
 
        else
284
 
                snprintf(path, sizeof(path), _PATH_SYS_BLOCK "/%s", cxt->name);
285
 
 
286
 
        return xstrdup(path);
287
 
}
288
 
 
289
 
static int sysfs_open(struct blkdev_cxt *cxt, const char *attr)
290
 
{
291
 
        int fd;
292
 
 
293
 
        assert(cxt);
294
 
        assert(cxt->sysfs_fd >= 0);
295
 
 
296
 
        fd = openat(cxt->sysfs_fd, attr, O_RDONLY);
297
 
        if (fd == -1 && errno == ENOENT && !strncmp(attr, "queue/", 6) && cxt->parent) {
298
 
                fd = openat(cxt->parent->sysfs_fd, attr, O_RDONLY);
299
 
        }
300
 
        return fd;
301
 
}
302
 
 
303
 
static FILE *sysfs_fopen(struct blkdev_cxt *cxt, const char *attr)
304
 
{
305
 
        int fd = sysfs_open(cxt, attr);
306
 
 
307
 
        return fd < 0 ? NULL : fdopen(fd, "r");
308
 
}
309
 
 
310
 
static DIR *sysfs_opendir(struct blkdev_cxt *cxt, const char *attr)
311
 
{
312
 
        DIR *dir;
313
 
        int fd;
314
 
 
315
 
        if (attr)
316
 
                fd = sysfs_open(cxt, attr);
317
 
        else {
318
 
                /* request to open root of device in sysfs (/sys/block/<dev>)
319
 
                 * -- we cannot use cxt->sysfs_fd directly, because closedir()
320
 
                 * will close this our persistent file descriptor.
321
 
                 */
322
 
                assert(cxt);
323
 
                assert(cxt->sysfs_fd >= 0);
324
 
 
325
 
                fd = dup(cxt->sysfs_fd);
326
 
        }
327
 
 
328
 
        if (fd < 0)
329
 
                return NULL;
330
 
        dir = fdopendir(fd);
331
 
        if (!dir) {
332
 
                close(fd);
333
 
                return NULL;
334
 
        }
335
 
        if (!attr)
336
 
                 rewinddir(dir);
337
 
        return dir;
338
 
}
339
 
 
340
 
static __attribute__ ((format (scanf, 3, 4)))
341
 
int sysfs_scanf(struct blkdev_cxt *cxt,  const char *attr, const char *fmt, ...)
342
 
{
343
 
        FILE *f = sysfs_fopen(cxt, attr);
344
 
        va_list ap;
345
 
        int rc;
346
 
 
347
 
        if (!f)
348
 
                return -EINVAL;
349
 
        va_start(ap, fmt);
350
 
        rc = vfscanf(f, fmt, ap);
351
 
        va_end(ap);
352
 
 
353
 
        fclose(f);
354
 
        return rc;
355
 
}
356
 
 
357
 
static uint64_t sysfs_read_u64(struct blkdev_cxt *cxt, const char *attr)
358
 
{
359
 
        uint64_t x;
360
 
        return sysfs_scanf(cxt, attr, "%"SCNu64, &x) == 1 ? x : 0;
361
 
}
362
 
 
363
 
static char *sysfs_strdup(struct blkdev_cxt *cxt, const char *attr)
364
 
{
365
 
        char buf[1024];
366
 
        return sysfs_scanf(cxt, attr, "%1024[^\n]", buf) == 1 ?
367
 
                                                xstrdup(buf) : NULL;
368
 
}
369
 
 
370
 
static int sysfs_count_dirents(struct blkdev_cxt *cxt, const char *attr)
371
 
{
372
 
        DIR *dir;
373
 
        int r = 0;
374
 
 
375
 
        if (!(dir = sysfs_opendir(cxt, attr)))
376
 
                return 0;
377
 
 
378
 
        while (xreaddir(dir)) r++;
379
 
 
380
 
        closedir(dir);
381
 
        return r;
382
 
}
383
 
 
384
 
static int sysfs_count_partitions(struct blkdev_cxt *cxt)
385
 
{
386
 
        DIR *dir;
387
 
        struct dirent *d;
388
 
        int r = 0;
389
 
 
390
 
        if (!(dir = sysfs_opendir(cxt, NULL)))
391
 
                return 0;
392
 
 
393
 
        while ((d = xreaddir(dir))) {
394
 
                if (is_partition_dirent(dir, d, cxt->name))
395
 
                        r++;
396
 
        }
397
 
 
398
 
        closedir(dir);
399
 
        return r;
400
 
}
401
 
 
402
266
static char *get_device_mountpoint(struct blkdev_cxt *cxt)
403
267
{
404
268
        int fl = 0;
405
269
        char mnt[PATH_MAX];
406
270
 
 
271
        assert(cxt);
 
272
        assert(cxt->filename);
 
273
 
407
274
        *mnt = '\0';
408
275
 
409
276
        /*
462
329
{
463
330
        int fd, ro = 0;
464
331
 
465
 
        if (sysfs_scanf(cxt, "ro", "%d", &ro) == 0)
 
332
        if (sysfs_scanf(&cxt->sysfs, "ro", "%d", &ro) == 0)
466
333
                return ro;
467
334
 
468
335
        /* fallback if "ro" attribute does not exist */
476
343
 
477
344
static char *get_scheduler(struct blkdev_cxt *cxt)
478
345
{
479
 
        char *str = sysfs_strdup(cxt, "queue/scheduler");
 
346
        char *str = sysfs_strdup(&cxt->sysfs, "queue/scheduler");
480
347
        char *p, *res = NULL;
481
348
 
482
349
        if (!str)
495
362
        return res;
496
363
}
497
364
 
 
365
static char *get_type(struct blkdev_cxt *cxt)
 
366
{
 
367
        char *res = NULL, *p;
 
368
 
 
369
        if (is_dm(cxt->name)) {
 
370
                char *dm_uuid = sysfs_strdup(&cxt->sysfs, "dm/uuid");
 
371
 
 
372
                /* The DM_UUID prefix should be set to subsystem owning
 
373
                 * the device - LVM, CRYPT, DMRAID, MPATH, PART */
 
374
                if (dm_uuid) {
 
375
                        char *tmp = dm_uuid;
 
376
                        char *dm_uuid_prefix = strsep(&tmp, "-");
 
377
 
 
378
                        if (dm_uuid_prefix) {
 
379
                                /* kpartx hack to remove partition number */
 
380
                                if (strncasecmp(dm_uuid_prefix, "part", 4) == 0)
 
381
                                        dm_uuid_prefix[4] = '\0';
 
382
 
 
383
                                res = xstrdup(dm_uuid_prefix);
 
384
                        }
 
385
                }
 
386
 
 
387
                free(dm_uuid);
 
388
                if (!res)
 
389
                        /* No UUID or no prefix - just mark it as DM device */
 
390
                        res = xstrdup("dm");
 
391
 
 
392
        } else if (!strncmp(cxt->name, "loop", 4)) {
 
393
                res = xstrdup("loop");
 
394
 
 
395
        } else if (!strncmp(cxt->name, "md", 2)) {
 
396
                char *md_level = sysfs_strdup(&cxt->sysfs, "md/level");
 
397
                res = md_level ? md_level : xstrdup("md");
 
398
 
 
399
        } else {
 
400
                const char *type = cxt->partition ? "part" : "disk";
 
401
                int x = 0;
 
402
 
 
403
                sysfs_read_int(&cxt->sysfs, "device/type", &x);
 
404
 
 
405
                switch (x) {
 
406
                        case 0x0c: /* TYPE_RAID */
 
407
                                type = "raid"; break;
 
408
                        case 0x01: /* TYPE_TAPE */
 
409
                                type = "raid"; break;
 
410
                        case 0x04: /* TYPE_WORM */
 
411
                        case 0x05: /* TYPE_ROM */
 
412
                                type = "rom"; break;
 
413
                        case 0x07: /* TYPE_MOD */
 
414
                                type = "mo-disk"; break;
 
415
                        case 0x0e: /* TYPE_RBC */
 
416
                                type = "rbc"; break;
 
417
                }
 
418
 
 
419
                res = xstrdup(type);
 
420
        }
 
421
 
 
422
        for (p = res; p && *p; p++)
 
423
                *p = tolower((unsigned char) *p);
 
424
        return res;
 
425
}
 
426
 
498
427
static void set_tt_data(struct blkdev_cxt *cxt, int col, int id, struct tt_line *ln)
499
428
{
500
429
        char buf[1024];
501
 
        char *p;
 
430
        char *p = NULL;
502
431
 
503
432
        if (!cxt->st.st_rdev && (id == COL_OWNER || id == COL_GROUP ||
504
433
                                 id == COL_MODE))
537
466
                break;
538
467
        }
539
468
        case COL_MAJMIN:
540
 
                if (lsblk->tt->flags & TT_FL_RAW)
 
469
                if ((lsblk->tt->flags & TT_FL_RAW) ||
 
470
                    (lsblk->tt->flags & TT_FL_EXPORT))
541
471
                        snprintf(buf, sizeof(buf), "%u:%u", cxt->maj, cxt->min);
542
472
                else
543
473
                        snprintf(buf, sizeof(buf), "%3u:%-3u", cxt->maj, cxt->min);
570
500
                                        xstrdup("1") : xstrdup("0"));
571
501
                break;
572
502
        case COL_RM:
573
 
                p = sysfs_strdup(cxt, "removable");
 
503
                p = sysfs_strdup(&cxt->sysfs, "removable");
574
504
                if (!p && cxt->parent)
575
 
                        p = sysfs_strdup(cxt->parent, "removable");
 
505
                        p = sysfs_strdup(&cxt->parent->sysfs, "removable");
576
506
                if (p)
577
507
                        tt_line_set_data(ln, col, p);
578
508
                break;
579
509
        case COL_ROTA:
580
 
                p = sysfs_strdup(cxt, "queue/rotational");
 
510
                p = sysfs_strdup(&cxt->sysfs, "queue/rotational");
581
511
                if (p)
582
512
                        tt_line_set_data(ln, col, p);
583
513
                break;
584
514
        case COL_MODEL:
585
515
                if (!cxt->partition && cxt->nslaves == 0) {
586
 
                        p = sysfs_strdup(cxt, "device/model");
 
516
                        p = sysfs_strdup(&cxt->sysfs, "device/model");
587
517
                        if (p)
588
518
                                tt_line_set_data(ln, col, p);
589
519
                }
594
524
                                if (asprintf(&p, "%jd", cxt->size) < 0)
595
525
                                        p = NULL;
596
526
                        } else
597
 
                                p = size_to_human_string(cxt->size);
 
527
                                p = size_to_human_string(SIZE_SUFFIX_1LETTER, cxt->size);
598
528
                        if (p)
599
529
                                tt_line_set_data(ln, col, p);
600
530
                }
601
531
                break;
 
532
        case COL_STATE:
 
533
                if (!cxt->partition && !cxt->dm_name) {
 
534
                        p = sysfs_strdup(&cxt->sysfs, "device/state");
 
535
                } else if (cxt->dm_name) {
 
536
                        int x = 0;
 
537
                        if (sysfs_read_int(&cxt->sysfs, "dm/suspended", &x) == 0)
 
538
                                p = x ? xstrdup("suspended") : xstrdup("running");
 
539
                }
 
540
                if (p)
 
541
                        tt_line_set_data(ln, col, p);
 
542
                break;
602
543
        case COL_ALIOFF:
603
 
                p = sysfs_strdup(cxt, "alignment_offset");
 
544
                p = sysfs_strdup(&cxt->sysfs, "alignment_offset");
604
545
                if (p)
605
546
                        tt_line_set_data(ln, col, p);
606
547
                break;
607
548
        case COL_MINIO:
608
 
                p = sysfs_strdup(cxt, "queue/minimum_io_size");
 
549
                p = sysfs_strdup(&cxt->sysfs, "queue/minimum_io_size");
609
550
                if (p)
610
551
                        tt_line_set_data(ln, col, p);
611
552
                break;
612
553
        case COL_OPTIO:
613
 
                p = sysfs_strdup(cxt, "queue/optimal_io_size");
 
554
                p = sysfs_strdup(&cxt->sysfs, "queue/optimal_io_size");
614
555
                if (p)
615
556
                        tt_line_set_data(ln, col, p);
616
557
                break;
617
558
        case COL_PHYSEC:
618
 
                p = sysfs_strdup(cxt, "queue/physical_block_size");
 
559
                p = sysfs_strdup(&cxt->sysfs, "queue/physical_block_size");
619
560
                if (p)
620
561
                        tt_line_set_data(ln, col, p);
621
562
                break;
622
563
        case COL_LOGSEC:
623
 
                p = sysfs_strdup(cxt, "queue/logical_block_size");
 
564
                p = sysfs_strdup(&cxt->sysfs, "queue/logical_block_size");
624
565
                if (p)
625
566
                        tt_line_set_data(ln, col, p);
626
567
                break;
629
570
                if (p)
630
571
                        tt_line_set_data(ln, col, p);
631
572
                break;
 
573
        case COL_RQ_SIZE:
 
574
                p = sysfs_strdup(&cxt->sysfs, "queue/nr_requests");
 
575
                if (p)
 
576
                        tt_line_set_data(ln, col, p);
 
577
                break;
 
578
        case COL_TYPE:
 
579
                p = get_type(cxt);
 
580
                if (p)
 
581
                        tt_line_set_data(ln, col, p);
 
582
                break;
 
583
        case COL_DALIGN:
 
584
                p = sysfs_strdup(&cxt->sysfs, "discard_alignment");
 
585
                if (cxt->discard && p)
 
586
                        tt_line_set_data(ln, col, p);
 
587
                else
 
588
                        tt_line_set_data(ln, col, "0");
 
589
                break;
 
590
        case COL_DGRAN:
 
591
                if (lsblk->bytes)
 
592
                        p = sysfs_strdup(&cxt->sysfs, "queue/discard_granularity");
 
593
                else {
 
594
                        uint64_t x;
 
595
 
 
596
                        if (sysfs_read_u64(&cxt->sysfs,
 
597
                                           "queue/discard_granularity", &x) == 0)
 
598
                                p = size_to_human_string(SIZE_SUFFIX_1LETTER, x);
 
599
                }
 
600
                if (p)
 
601
                        tt_line_set_data(ln, col, p);
 
602
                break;
 
603
        case COL_DMAX:
 
604
                if (lsblk->bytes)
 
605
                        p = sysfs_strdup(&cxt->sysfs, "queue/discard_max_bytes");
 
606
                else {
 
607
                        uint64_t x;
 
608
 
 
609
                        if (sysfs_read_u64(&cxt->sysfs,
 
610
                                           "queue/discard_max_bytes", &x) == 0)
 
611
                                p = size_to_human_string(SIZE_SUFFIX_1LETTER, x);
 
612
                }
 
613
                if (p)
 
614
                        tt_line_set_data(ln, col, p);
 
615
                break;
 
616
        case COL_DZERO:
 
617
                p = sysfs_strdup(&cxt->sysfs, "queue/discard_zeroes_data");
 
618
                if (cxt->discard && p)
 
619
                        tt_line_set_data(ln, col, p);
 
620
                else
 
621
                        tt_line_set_data(ln, col, "0");
 
622
                break;
632
623
        };
633
624
}
634
625
 
647
638
                    const char *name,
648
639
                    int partition)
649
640
{
650
 
        char *p;
 
641
        dev_t devno;
651
642
 
652
643
        cxt->parent = parent;
653
644
        cxt->name = xstrdup(name);
654
645
        cxt->partition = partition;
655
646
 
656
647
        cxt->filename = get_device_path(cxt);
657
 
 
658
 
        /* open /sys/block/<name> */
659
 
        p = get_sysfs_path(cxt);
660
 
        cxt->sysfs_fd = open(p, O_RDONLY);
661
 
        if (cxt->sysfs_fd < 0)
662
 
                err(EXIT_FAILURE, _("%s: open failed"), p);
663
 
        free(p);
664
 
 
665
 
        if (sysfs_scanf(cxt, "dev", "%u:%u", &cxt->maj, &cxt->min) != 2)
666
 
                return -1;
667
 
 
668
 
        cxt->size = sysfs_read_u64(cxt, "size") << 9;
 
648
        if (!cxt->filename) {
 
649
                warnx(_("%s: failed to get device path"), name);
 
650
                return -1;
 
651
        }
 
652
 
 
653
        devno = sysfs_devname_to_devno(name,
 
654
                        partition && parent ? parent->name : NULL);
 
655
        if (!devno) {
 
656
                warnx(_("%s: unknown device name"), name);
 
657
                return -1;
 
658
        }
 
659
 
 
660
        if (sysfs_init(&cxt->sysfs, devno, parent ? &parent->sysfs : NULL)) {
 
661
                warnx(_("%s: failed to initialize sysfs handler"), name);
 
662
                return -1;
 
663
        }
 
664
 
 
665
        cxt->maj = major(devno);
 
666
        cxt->min = minor(devno);
 
667
 
 
668
        sysfs_read_u64(&cxt->sysfs, "size", &cxt->size);        /* in sectors */
 
669
        cxt->size <<= 9;                                        /* in bytes */
 
670
 
 
671
        sysfs_read_int(&cxt->sysfs, "queue/discard_granularity", &cxt->discard);
669
672
 
670
673
        /* Ignore devices of zero size */
671
674
        if (!lsblk->all_devices && cxt->size == 0)
672
675
                return -1;
673
676
 
674
 
        if (is_dm(name))
675
 
                cxt->dm_name = sysfs_strdup(cxt, "dm/name");
 
677
        if (is_dm(name)) {
 
678
                cxt->dm_name = sysfs_strdup(&cxt->sysfs, "dm/name");
 
679
                if (!cxt->dm_name) {
 
680
                        warnx(_("%s: failed to get dm name"), name);
 
681
                        return -1;
 
682
                }
 
683
        }
 
684
        cxt->nholders = sysfs_count_dirents(&cxt->sysfs, "holders") +
 
685
                        sysfs_count_partitions(&cxt->sysfs, name);
676
686
 
677
 
        cxt->nholders = sysfs_count_dirents(cxt, "holders") +
678
 
                        sysfs_count_partitions(cxt);
679
 
        cxt->nslaves = sysfs_count_dirents(cxt, "slaves");
 
687
        cxt->nslaves = sysfs_count_dirents(&cxt->sysfs, "slaves");
680
688
 
681
689
        return 0;
682
690
}
691
699
        struct blkdev_cxt holder = {};
692
700
 
693
701
        assert(cxt);
694
 
        assert(cxt->sysfs_fd >= 0);
695
702
 
696
703
        if (lsblk->nodeps)
697
704
                return 0;
700
707
                return 0;
701
708
 
702
709
        /* Partitions */
703
 
        dir = sysfs_opendir(cxt, NULL);
 
710
        dir = sysfs_opendir(&cxt->sysfs, NULL);
704
711
        if (!dir)
705
712
                err(EXIT_FAILURE, _("failed to open device directory in sysfs"));
706
713
 
707
714
        while ((d = xreaddir(dir))) {
708
 
                if (!is_partition_dirent(dir, d, cxt->name))
 
715
                if (!sysfs_is_partition_dirent(dir, d, cxt->name))
709
716
                        continue;
710
717
 
711
 
                set_cxt(&holder, cxt, d->d_name, 1);
 
718
                if (set_cxt(&holder, cxt, d->d_name, 1)) {
 
719
                        reset_blkdev_cxt(&holder);
 
720
                        continue;
 
721
                }
712
722
                print_device(&holder, cxt->tt_line);
713
723
                list_holders(&holder);
714
724
                reset_blkdev_cxt(&holder);
716
726
        closedir(dir);
717
727
 
718
728
        /* Holders */
719
 
        dir = sysfs_opendir(cxt, "holders");
 
729
        dir = sysfs_opendir(&cxt->sysfs, "holders");
720
730
        if (!dir)
721
731
                return 0;
722
732
 
723
733
        while ((d = xreaddir(dir))) {
724
 
                set_cxt(&holder, cxt, d->d_name, 0);
 
734
                if (set_cxt(&holder, cxt, d->d_name, 0)) {
 
735
                        reset_blkdev_cxt(&holder);
 
736
                        continue;
 
737
                }
725
738
                print_device(&holder, cxt->tt_line);
726
739
                list_holders(&holder);
727
740
                reset_blkdev_cxt(&holder);
742
755
                return EXIT_FAILURE;
743
756
 
744
757
        while ((d = xreaddir(dir))) {
745
 
 
746
758
                if (set_cxt(&cxt, NULL, d->d_name, 0))
747
759
                        goto next;
748
760
 
768
780
{
769
781
        struct blkdev_cxt parent = {}, cxt = {};
770
782
        struct stat st;
771
 
        char buf[PATH_MAX + 1];
 
783
        char buf[PATH_MAX + 1], *diskname = NULL;
772
784
        dev_t disk = 0;
 
785
        int status = EXIT_FAILURE;
773
786
 
774
787
        if (stat(devname, &st) || !S_ISBLK(st.st_mode)) {
775
788
                warnx(_("%s: not a block device"), devname);
776
789
                return EXIT_FAILURE;
777
790
        }
778
791
        if (blkid_devno_to_wholedisk(st.st_rdev, buf, sizeof(buf), &disk)) {
779
 
                warn(_("%s: failed to get whole-list devno"), devname);
 
792
                warn(_("%s: failed to get whole-disk device number"), devname);
780
793
                return EXIT_FAILURE;
781
794
        }
782
 
        if (st.st_rdev == disk)
 
795
        if (st.st_rdev == disk) {
783
796
                /*
784
797
                 * unpartitioned device
785
798
                 */
786
 
                set_cxt(&cxt, NULL, buf, 0);
787
 
        else {
 
799
                if (set_cxt(&cxt, NULL, buf, 0))
 
800
                        goto leave;
 
801
        } else {
788
802
                /*
789
803
                 * Parititioned, read sysfs name of the device
790
804
                 */
791
805
                ssize_t len;
792
 
                char path[PATH_MAX], *diskname, *name;
793
 
 
794
 
                snprintf(path, sizeof(path), "/sys/dev/block/%d:%d",
795
 
                                    major(st.st_rdev), minor(st.st_rdev));
 
806
                char path[PATH_MAX], *name;
 
807
 
 
808
                if (!sysfs_devno_path(st.st_rdev, path, sizeof(path))) {
 
809
                        warn(_("failed to compose sysfs path for %s"), devname);
 
810
                        goto leave;
 
811
                }
 
812
 
796
813
                diskname = xstrdup(buf);
797
 
 
798
814
                len = readlink(path, buf, PATH_MAX);
799
815
                if (len < 0) {
800
816
                        warn(_("%s: failed to read link"), path);
801
 
                        return EXIT_FAILURE;
 
817
                        goto leave;
802
818
                }
803
819
                buf[len] = '\0';
804
820
 
805
821
                /* sysfs device name */
806
822
                name = strrchr(buf, '/') + 1;
807
823
 
808
 
                set_cxt(&parent, NULL, diskname, 0);
809
 
                set_cxt(&cxt, &parent, name, 1);
810
 
 
811
 
                free(diskname);
 
824
                if (set_cxt(&parent, NULL, diskname, 0))
 
825
                        goto leave;
 
826
                if (set_cxt(&cxt, &parent, name, 1))
 
827
                        goto leave;
812
828
        }
813
829
 
814
830
        print_device(&cxt, NULL);
815
831
        list_holders(&cxt);
 
832
        status = EXIT_SUCCESS;
 
833
leave:
 
834
        free(diskname);
816
835
        reset_blkdev_cxt(&cxt);
817
836
 
818
837
        if (st.st_rdev != disk)
819
838
                reset_blkdev_cxt(&parent);
820
839
 
821
 
        return EXIT_SUCCESS;
 
840
        return status;
822
841
}
823
842
 
824
843
static void parse_excludes(const char *str)
837
856
                excludes[nexcludes++] = n;
838
857
 
839
858
                if (nexcludes == ARRAY_SIZE(excludes))
 
859
                        /* TRANSLATORS: The standard value for %d is 256. */
840
860
                        errx(EXIT_FAILURE, _("the list of excluded devices is "
841
861
                                        "too large (limit is %d devices)"),
842
862
                                        (int)ARRAY_SIZE(excludes));
857
877
                " -a, --all            print all devices\n"
858
878
                " -b, --bytes          print SIZE in bytes rather than in human readable format\n"
859
879
                " -d, --nodeps         don't print slaves or holders\n"
 
880
                " -D, --discard        print discard capabilities\n"
860
881
                " -e, --exclude <list> exclude devices by major number (default: RAM disks)\n"
861
882
                " -f, --fs             output info about filesystems\n"
862
883
                " -h, --help           usage information (this)\n"
865
886
                " -l, --list           use list format ouput\n"
866
887
                " -n, --noheadings     don't print headings\n"
867
888
                " -o, --output <list>  output columns\n"
868
 
                " -r, --raw            use raw format output\n"
 
889
                " -P, --pairs          use key=\"value\" output format\n"
 
890
                " -r, --raw            use raw output format\n"
869
891
                " -t, --topology       output info about topology\n"));
870
892
 
871
893
        fprintf(out, _("\nAvailable columns:\n"));
890
912
        int tt_flags = TT_FL_TREE;
891
913
        int i, c, status = EXIT_FAILURE;
892
914
 
893
 
        struct option longopts[] = {
 
915
        static const struct option longopts[] = {
894
916
                { "all",        0, 0, 'a' },
895
917
                { "bytes",      0, 0, 'b' },
896
918
                { "nodeps",     0, 0, 'd' },
 
919
                { "discard",    0, 0, 'D' },
897
920
                { "help",       0, 0, 'h' },
898
921
                { "output",     1, 0, 'o' },
899
922
                { "perms",      0, 0, 'm' },
904
927
                { "fs",         0, 0, 'f' },
905
928
                { "exclude",    1, 0, 'e' },
906
929
                { "topology",   0, 0, 't' },
 
930
                { "pairs",      0, 0, 'P' },
907
931
                { NULL, 0, 0, 0 },
908
932
        };
909
933
 
914
938
        lsblk = &_ls;
915
939
        memset(lsblk, 0, sizeof(*lsblk));
916
940
 
917
 
        while((c = getopt_long(argc, argv, "abde:fhlnmo:irt", longopts, NULL)) != -1) {
 
941
        while((c = getopt_long(argc, argv, "abdDe:fhlnmo:Pirt", longopts, NULL)) != -1) {
918
942
                switch(c) {
919
943
                case 'a':
920
944
                        lsblk->all_devices = 1;
925
949
                case 'd':
926
950
                        lsblk->nodeps = 1;
927
951
                        break;
 
952
                case 'D':
 
953
                        columns[ncolumns++] = COL_NAME;
 
954
                        columns[ncolumns++] = COL_DALIGN;
 
955
                        columns[ncolumns++] = COL_DGRAN;
 
956
                        columns[ncolumns++] = COL_DMAX;
 
957
                        columns[ncolumns++] = COL_DZERO;
 
958
                        break;
928
959
                case 'e':
929
960
                        parse_excludes(optarg);
930
961
                        break;
932
963
                        help(stdout);
933
964
                        break;
934
965
                case 'l':
935
 
                        if (tt_flags & TT_FL_RAW)
936
 
                                errx_mutually_exclusive("--{raw,list}");
 
966
                        if ((tt_flags & TT_FL_RAW)|| (tt_flags & TT_FL_EXPORT))
 
967
                                errx_mutually_exclusive("--{raw,list,export}");
937
968
 
938
969
                        tt_flags &= ~TT_FL_TREE; /* disable the default */
939
970
                        break;
941
972
                        tt_flags |= TT_FL_NOHEADINGS;
942
973
                        break;
943
974
                case 'o':
944
 
                        if (tt_parse_columns_list(optarg, columns, &ncolumns,
945
 
                                                column_name_to_id))
 
975
                        ncolumns = string_to_idarray(optarg,
 
976
                                                columns, ARRAY_SIZE(columns),
 
977
                                                column_name_to_id);
 
978
                        if (ncolumns < 0)
946
979
                                return EXIT_FAILURE;
947
980
                        break;
 
981
                case 'P':
 
982
                        tt_flags |= TT_FL_EXPORT;
 
983
                        tt_flags &= ~TT_FL_TREE;        /* disable the default */
 
984
                        break;
948
985
                case 'i':
949
986
                        tt_flags |= TT_FL_ASCII;
950
987
                        break;
974
1011
                        columns[ncolumns++] = COL_LOGSEC;
975
1012
                        columns[ncolumns++] = COL_ROTA;
976
1013
                        columns[ncolumns++] = COL_SCHED;
 
1014
                        columns[ncolumns++] = COL_RQ_SIZE;
977
1015
                        break;
978
1016
                default:
979
1017
                        help(stderr);
986
1024
                columns[ncolumns++] = COL_RM;
987
1025
                columns[ncolumns++] = COL_SIZE;
988
1026
                columns[ncolumns++] = COL_RO;
 
1027
                columns[ncolumns++] = COL_TYPE;
989
1028
                columns[ncolumns++] = COL_TARGET;
990
1029
        }
991
1030