2 * lsblk(8) - list block devices
4 * Copyright (C) 2010 Red Hat, Inc. All rights reserved.
5 * Written by Milan Broz <mbroz@redhat.com>
6 * Karel Zak <kzak@redhat.com>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it would be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software Foundation,
20 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29 #include <sys/types.h>
34 #include <sys/ioctl.h>
45 #include "pathnames.h"
47 #include "canonicalize.h"
48 #include "ismounted.h"
84 const char *name
; /* header */
85 double whint
; /* width hint (N < 1 is in percent of termwidth) */
86 int flags
; /* TT_FL_* */
90 /* columns descriptions */
91 static struct colinfo infos
[__NCOLUMNS
] = {
92 [COL_NAME
] = { "NAME", 0.25, TT_FL_TREE
, N_("device name") },
93 [COL_KNAME
] = { "KNAME", 0.3, 0, N_("internel kernel device name") },
94 [COL_MAJMIN
] = { "MAJ:MIN", 6, 0, N_("major:minor device number") },
95 [COL_FSTYPE
] = { "FSTYPE", 0.1, TT_FL_TRUNC
, N_("filesystem type") },
96 [COL_TARGET
] = { "MOUNTPOINT", 0.10, TT_FL_TRUNC
, N_("where the device is mounted") },
97 [COL_LABEL
] = { "LABEL", 0.1, 0, N_("filesystem LABEL") },
98 [COL_UUID
] = { "UUID", 36, 0, N_("filesystem UUID") },
99 [COL_RO
] = { "RO", 1, TT_FL_RIGHT
, N_("read-only device") },
100 [COL_RM
] = { "RM", 1, TT_FL_RIGHT
, N_("removable device") },
101 [COL_ROTA
] = { "ROTA", 1, TT_FL_RIGHT
, N_("rotational device") },
102 [COL_MODEL
] = { "MODEL", 0.1, TT_FL_TRUNC
, N_("device identifier") },
103 [COL_SIZE
] = { "SIZE", 6, TT_FL_RIGHT
, N_("size of the device") },
104 [COL_OWNER
] = { "OWNER", 0.1, TT_FL_TRUNC
, N_("user name"), },
105 [COL_GROUP
] = { "GROUP", 0.1, TT_FL_TRUNC
, N_("group name") },
106 [COL_MODE
] = { "MODE", 10, 0, N_("device node permissions") },
107 [COL_ALIOFF
] = { "ALIGNMENT", 6, TT_FL_RIGHT
, N_("alignment offset") },
108 [COL_MINIO
] = { "MIN-IO", 6, TT_FL_RIGHT
, N_("minimum I/O size") },
109 [COL_OPTIO
] = { "OPT-IO", 6, TT_FL_RIGHT
, N_("optimal I/O size") },
110 [COL_PHYSEC
] = { "PHY-SEC", 7, TT_FL_RIGHT
, N_("physical sector size") },
111 [COL_LOGSEC
] = { "LOG-SEC", 7, TT_FL_RIGHT
, N_("logical sector size") },
112 [COL_SCHED
] = { "SCHED", 0.1, 0, N_("I/O scheduler name") }
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 */
123 struct lsblk
*lsblk
; /* global handler */
124 int columns
[__NCOLUMNS
];/* enabled columns */
125 int ncolumns
; /* number of enabled columns */
127 unsigned int excludes
[256];
131 struct blkdev_cxt
*parent
;
133 struct tt_line
*tt_line
;
136 char *name
; /* kernel name in /sys/block */
137 char *dm_name
; /* DM name (dm/block) */
139 char *filename
; /* path to device node */
140 int sysfs_fd
; /* O_RDONLY file desciptor to /sys/block/<dev> */
142 int partition
; /* is partition? TRUE/FALSE */
144 int probed
; /* already probed */
145 char *fstype
; /* detected fs, NULL or "?" if cannot detect */
146 char *uuid
; /* UUID of device / filesystem */
147 char *label
; /* FS label */
149 int nholders
; /* # of devices mapped directly to this device
150 * /sys/block/.../holders + number of partition */
151 int nslaves
; /* # of devices this device maps to */
152 int maj
, min
; /* devno */
154 uint64_t size
; /* device size */
157 static int is_maj_excluded(int maj
)
161 assert(ARRAY_SIZE(excludes
) > nexcludes
);
163 for (i
= 0; i
< nexcludes
; i
++)
164 if (excludes
[i
] == maj
)
170 /* array with IDs of enabled columns */
171 static int get_column_id(int num
)
173 assert(ARRAY_SIZE(columns
) == __NCOLUMNS
);
174 assert(num
< ncolumns
);
175 assert(columns
[num
] < __NCOLUMNS
);
179 static struct colinfo
*get_column_info(int num
)
181 return &infos
[ get_column_id(num
) ];
185 static int column_name_to_id(const char *name
, size_t namesz
)
189 for (i
= 0; i
< __NCOLUMNS
; i
++) {
190 const char *cn
= infos
[i
].name
;
192 if (!strncasecmp(name
, cn
, namesz
) && !*(cn
+ namesz
))
195 warnx(_("unknown column: %s"), name
);
199 static void reset_blkdev_cxt(struct blkdev_cxt
*cxt
)
210 if (cxt
->sysfs_fd
>= 0)
211 close(cxt
->sysfs_fd
);
213 memset(cxt
, 0, sizeof(*cxt
));
216 static int is_dm(const char *name
)
218 return strncmp(name
, "dm-", 3) ? 0 : 1;
221 static struct dirent
*xreaddir(DIR *dp
)
227 while ((d
= readdir(dp
))) {
228 if (!strcmp(d
->d_name
, ".") ||
229 !strcmp(d
->d_name
, ".."))
232 /* blacklist here? */
239 static int is_partition_dirent(DIR *dir
, struct dirent
*d
, const char *parent_name
)
246 #ifdef _DIRENT_HAVE_D_TYPE
247 if (d
->d_type
!= DT_DIR
)
250 if (strncmp(parent_name
, d
->d_name
, strlen(parent_name
)))
253 /* Cannot use /partition file, not supported on old sysfs */
254 snprintf(path
, sizeof(path
), "%s/start", d
->d_name
);
256 return faccessat(dirfd(dir
), path
, R_OK
, 0) == 0;
259 static char *get_device_path(struct blkdev_cxt
*cxt
)
266 if (is_dm(cxt
->name
))
267 return canonicalize_dm_name(cxt
->name
);
269 snprintf(path
, sizeof(path
), "/dev/%s", cxt
->name
);
270 return xstrdup(path
);
273 static char *get_sysfs_path(struct blkdev_cxt
*cxt
)
280 if (cxt
->partition
&& cxt
->parent
)
281 snprintf(path
, sizeof(path
), _PATH_SYS_BLOCK
"/%s/%s",
282 cxt
->parent
->name
, cxt
->name
);
284 snprintf(path
, sizeof(path
), _PATH_SYS_BLOCK
"/%s", cxt
->name
);
286 return xstrdup(path
);
289 static int sysfs_open(struct blkdev_cxt
*cxt
, const char *attr
)
294 assert(cxt
->sysfs_fd
>= 0);
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
);
303 static FILE *sysfs_fopen(struct blkdev_cxt
*cxt
, const char *attr
)
305 int fd
= sysfs_open(cxt
, attr
);
307 return fd
< 0 ? NULL
: fdopen(fd
, "r");
310 static DIR *sysfs_opendir(struct blkdev_cxt
*cxt
, const char *attr
)
316 fd
= sysfs_open(cxt
, attr
);
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.
323 assert(cxt
->sysfs_fd
>= 0);
325 fd
= dup(cxt
->sysfs_fd
);
340 static __attribute__ ((format (scanf
, 3, 4)))
341 int sysfs_scanf(struct blkdev_cxt
*cxt
, const char *attr
, const char *fmt
, ...)
343 FILE *f
= sysfs_fopen(cxt
, attr
);
350 rc
= vfscanf(f
, fmt
, ap
);
357 static uint64_t sysfs_read_u64(struct blkdev_cxt
*cxt
, const char *attr
)
360 return sysfs_scanf(cxt
, attr
, "%"SCNu64
, &x
) == 1 ? x
: 0;
363 static char *sysfs_strdup(struct blkdev_cxt
*cxt
, const char *attr
)
366 return sysfs_scanf(cxt
, attr
, "%1024[^\n]", buf
) == 1 ?
370 static int sysfs_count_dirents(struct blkdev_cxt
*cxt
, const char *attr
)
375 if (!(dir
= sysfs_opendir(cxt
, attr
)))
378 while (xreaddir(dir
)) r
++;
384 static int sysfs_count_partitions(struct blkdev_cxt
*cxt
)
390 if (!(dir
= sysfs_opendir(cxt
, NULL
)))
393 while ((d
= xreaddir(dir
))) {
394 if (is_partition_dirent(dir
, d
, cxt
->name
))
402 static char *get_device_mountpoint(struct blkdev_cxt
*cxt
)
410 * TODO: use libmount and parse /proc/mountinfo only once
412 if (check_mount_point(cxt
->filename
, &fl
, mnt
, sizeof(mnt
)) == 0 &&
415 strcpy(mnt
, "[SWAP]");
417 return strlen(mnt
) ? xstrdup(mnt
) : NULL
;
420 /* TODO: read info from udev db (if possible) for non-root users
422 static void probe_device(struct blkdev_cxt
*cxt
)
425 blkid_probe pr
= NULL
;
434 pr
= blkid_new_probe_from_filename(cxt
->filename
);
438 /* TODO: we have to enable partitions probing to avoid conflicts
439 * between raids and PT -- see blkid(8) code for more details
441 blkid_probe_enable_superblocks(pr
, 1);
442 blkid_probe_set_superblocks_flags(pr
, BLKID_SUBLKS_LABEL
|
445 if (!blkid_do_safeprobe(pr
)) {
446 const char *data
= NULL
;
448 if (!blkid_probe_lookup_value(pr
, "TYPE", &data
, NULL
))
449 cxt
->fstype
= xstrdup(data
);
450 if (!blkid_probe_lookup_value(pr
, "UUID", &data
, NULL
))
451 cxt
->uuid
= xstrdup(data
);
452 if (!blkid_probe_lookup_value(pr
, "LABEL", &data
, NULL
))
453 cxt
->label
= xstrdup(data
);
457 blkid_free_probe(pr
);
461 static int is_readonly_device(struct blkdev_cxt
*cxt
)
465 if (sysfs_scanf(cxt
, "ro", "%d", &ro
) == 0)
468 /* fallback if "ro" attribute does not exist */
469 fd
= open(cxt
->filename
, O_RDONLY
);
471 ioctl(fd
, BLKROGET
, &ro
);
477 static char *get_scheduler(struct blkdev_cxt
*cxt
)
479 char *str
= sysfs_strdup(cxt
, "queue/scheduler");
480 char *p
, *res
= NULL
;
484 p
= strchr(str
, '[');
487 p
= strchr(res
, ']');
498 static void set_tt_data(struct blkdev_cxt
*cxt
, int col
, int id
, struct tt_line
*ln
)
503 if (!cxt
->st
.st_rdev
&& (id
== COL_OWNER
|| id
== COL_GROUP
||
505 stat(cxt
->filename
, &cxt
->st
);
510 snprintf(buf
, sizeof(buf
), "%s (%s)",
511 cxt
->dm_name
, cxt
->name
);
512 tt_line_set_data(ln
, col
, xstrdup(buf
));
516 tt_line_set_data(ln
, col
, xstrdup(cxt
->name
));
520 struct passwd
*pw
= getpwuid(cxt
->st
.st_uid
);
522 tt_line_set_data(ln
, col
, xstrdup(pw
->pw_name
));
527 struct group
*gr
= getgrgid(cxt
->st
.st_gid
);
529 tt_line_set_data(ln
, col
, xstrdup(gr
->gr_name
));
535 strmode(cxt
->st
.st_mode
, md
);
536 tt_line_set_data(ln
, col
, xstrdup(md
));
540 if (lsblk
->tt
->flags
& TT_FL_RAW
)
541 snprintf(buf
, sizeof(buf
), "%u:%u", cxt
->maj
, cxt
->min
);
543 snprintf(buf
, sizeof(buf
), "%3u:%-3u", cxt
->maj
, cxt
->min
);
544 tt_line_set_data(ln
, col
, xstrdup(buf
));
549 tt_line_set_data(ln
, col
, xstrdup(cxt
->fstype
));
552 if (!cxt
->nholders
) {
553 p
= get_device_mountpoint(cxt
);
555 tt_line_set_data(ln
, col
, p
);
561 tt_line_set_data(ln
, col
, xstrdup(cxt
->label
));
566 tt_line_set_data(ln
, col
, xstrdup(cxt
->uuid
));
569 tt_line_set_data(ln
, col
, is_readonly_device(cxt
) ?
570 xstrdup("1") : xstrdup("0"));
573 p
= sysfs_strdup(cxt
, "removable");
574 if (!p
&& cxt
->parent
)
575 p
= sysfs_strdup(cxt
->parent
, "removable");
577 tt_line_set_data(ln
, col
, p
);
580 p
= sysfs_strdup(cxt
, "queue/rotational");
582 tt_line_set_data(ln
, col
, p
);
585 if (!cxt
->partition
&& cxt
->nslaves
== 0) {
586 p
= sysfs_strdup(cxt
, "device/model");
588 tt_line_set_data(ln
, col
, p
);
594 if (asprintf(&p
, "%jd", cxt
->size
) < 0)
597 p
= size_to_human_string(cxt
->size
);
599 tt_line_set_data(ln
, col
, p
);
603 p
= sysfs_strdup(cxt
, "alignment_offset");
605 tt_line_set_data(ln
, col
, p
);
608 p
= sysfs_strdup(cxt
, "queue/minimum_io_size");
610 tt_line_set_data(ln
, col
, p
);
613 p
= sysfs_strdup(cxt
, "queue/optimal_io_size");
615 tt_line_set_data(ln
, col
, p
);
618 p
= sysfs_strdup(cxt
, "queue/physical_block_size");
620 tt_line_set_data(ln
, col
, p
);
623 p
= sysfs_strdup(cxt
, "queue/logical_block_size");
625 tt_line_set_data(ln
, col
, p
);
628 p
= get_scheduler(cxt
);
630 tt_line_set_data(ln
, col
, p
);
635 static void print_device(struct blkdev_cxt
*cxt
, struct tt_line
*tt_parent
)
639 cxt
->tt_line
= tt_add_line(lsblk
->tt
, tt_parent
);
641 for (i
= 0; i
< ncolumns
; i
++)
642 set_tt_data(cxt
, i
, get_column_id(i
), cxt
->tt_line
);
645 static int set_cxt(struct blkdev_cxt
*cxt
,
646 struct blkdev_cxt
*parent
,
652 cxt
->parent
= parent
;
653 cxt
->name
= xstrdup(name
);
654 cxt
->partition
= partition
;
656 cxt
->filename
= get_device_path(cxt
);
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
);
665 if (sysfs_scanf(cxt
, "dev", "%u:%u", &cxt
->maj
, &cxt
->min
) != 2)
668 cxt
->size
= sysfs_read_u64(cxt
, "size") << 9;
670 /* Ignore devices of zero size */
671 if (!lsblk
->all_devices
&& cxt
->size
== 0)
675 cxt
->dm_name
= sysfs_strdup(cxt
, "dm/name");
677 cxt
->nholders
= sysfs_count_dirents(cxt
, "holders") +
678 sysfs_count_partitions(cxt
);
679 cxt
->nslaves
= sysfs_count_dirents(cxt
, "slaves");
685 * List devices (holders) mapped to device
687 static int list_holders(struct blkdev_cxt
*cxt
)
691 struct blkdev_cxt holder
= {};
694 assert(cxt
->sysfs_fd
>= 0);
703 dir
= sysfs_opendir(cxt
, NULL
);
705 err(EXIT_FAILURE
, _("failed to open device directory in sysfs"));
707 while ((d
= xreaddir(dir
))) {
708 if (!is_partition_dirent(dir
, d
, cxt
->name
))
711 set_cxt(&holder
, cxt
, d
->d_name
, 1);
712 print_device(&holder
, cxt
->tt_line
);
713 list_holders(&holder
);
714 reset_blkdev_cxt(&holder
);
719 dir
= sysfs_opendir(cxt
, "holders");
723 while ((d
= xreaddir(dir
))) {
724 set_cxt(&holder
, cxt
, d
->d_name
, 0);
725 print_device(&holder
, cxt
->tt_line
);
726 list_holders(&holder
);
727 reset_blkdev_cxt(&holder
);
734 /* Iterate top-level devices in sysfs */
735 static int iterate_block_devices(void)
739 struct blkdev_cxt cxt
= {};
741 if (!(dir
= opendir(_PATH_SYS_BLOCK
)))
744 while ((d
= xreaddir(dir
))) {
746 if (set_cxt(&cxt
, NULL
, d
->d_name
, 0))
749 /* Skip devices in the middle of dependence tree */
753 if (!lsblk
->all_devices
&& is_maj_excluded(cxt
.maj
))
756 print_device(&cxt
, NULL
);
759 reset_blkdev_cxt(&cxt
);
767 static int process_one_device(char *devname
)
769 struct blkdev_cxt parent
= {}, cxt
= {};
774 if (stat(devname
, &st
) || !S_ISBLK(st
.st_mode
)) {
775 warnx(_("%s: not a block device"), devname
);
778 if (blkid_devno_to_wholedisk(st
.st_rdev
, buf
, sizeof(buf
), &disk
)) {
779 warn(_("%s: failed to get whole-list devno"), devname
);
782 if (st
.st_rdev
== disk
)
784 * unpartitioned device
786 set_cxt(&cxt
, NULL
, buf
, 0);
789 * Parititioned, read sysfs name of the device
792 char path
[PATH_MAX
], *diskname
, *name
;
794 snprintf(path
, sizeof(path
), "/sys/dev/block/%d:%d",
795 major(st
.st_rdev
), minor(st
.st_rdev
));
796 diskname
= xstrdup(buf
);
798 len
= readlink(path
, buf
, sizeof(buf
));
800 warn(_("%s: failed to read link"), path
);
805 /* sysfs device name */
806 name
= strrchr(buf
, '/') + 1;
808 set_cxt(&parent
, NULL
, diskname
, 0);
809 set_cxt(&cxt
, &parent
, name
, 1);
814 print_device(&cxt
, NULL
);
816 reset_blkdev_cxt(&cxt
);
818 if (st
.st_rdev
!= disk
)
819 reset_blkdev_cxt(&parent
);
824 static void parse_excludes(const char *str
)
828 while (str
&& *str
) {
833 n
= strtoul(str
, &end
, 10);
835 if (end
== str
|| (errno
!= 0 && (n
== ULONG_MAX
|| n
== 0)))
836 err(EXIT_FAILURE
, _("failed to parse list '%s'"), str
);
837 excludes
[nexcludes
++] = n
;
839 if (nexcludes
== ARRAY_SIZE(excludes
))
840 errx(EXIT_FAILURE
, _("the list of excluded devices is "
841 "too large (limit is %d devices)"),
842 (int)ARRAY_SIZE(excludes
));
843 str
= end
&& *end
? end
+ 1 : NULL
;
847 static void __attribute__((__noreturn__
)) help(FILE *out
)
853 " %s [options] [<device> ...]\n"), program_invocation_short_name
);
857 " -a, --all print all devices\n"
858 " -b, --bytes print SIZE in bytes rather than in human readable format\n"
859 " -d, --nodeps don't print slaves or holders\n"
860 " -e, --exclude <list> exclude devices by major number (default: RAM disks)\n"
861 " -f, --fs output info about filesystems\n"
862 " -h, --help usage information (this)\n"
863 " -i, --ascii use ascii characters only\n"
864 " -m, --perms output info about permissions\n"
865 " -l, --list use list format ouput\n"
866 " -n, --noheadings don't print headings\n"
867 " -o, --output <list> output columns\n"
868 " -r, --raw use raw format output\n"
869 " -t, --topology output info about topology\n"));
871 fprintf(out
, _("\nAvailable columns:\n"));
873 for (i
= 0; i
< __NCOLUMNS
; i
++)
874 fprintf(out
, " %10s %s\n", infos
[i
].name
, _(infos
[i
].help
));
876 fprintf(out
, _("\nFor more information see lsblk(8).\n"));
878 exit(out
== stderr
? EXIT_FAILURE
: EXIT_SUCCESS
);
881 static void __attribute__((__noreturn__
))
882 errx_mutually_exclusive(const char *opts
)
884 errx(EXIT_FAILURE
, "%s %s", opts
, _("options are mutually exclusive"));
887 int main(int argc
, char *argv
[])
890 int tt_flags
= TT_FL_TREE
;
891 int i
, c
, status
= EXIT_FAILURE
;
893 struct option longopts
[] = {
894 { "all", 0, 0, 'a' },
895 { "bytes", 0, 0, 'b' },
896 { "nodeps", 0, 0, 'd' },
897 { "help", 0, 0, 'h' },
898 { "output", 1, 0, 'o' },
899 { "perms", 0, 0, 'm' },
900 { "noheadings", 0, 0, 'n' },
901 { "list", 0, 0, 'l' },
902 { "ascii", 0, 0, 'i' },
903 { "raw", 0, 0, 'r' },
905 { "exclude", 1, 0, 'e' },
906 { "topology", 0, 0, 't' },
910 setlocale(LC_ALL
, "");
911 bindtextdomain(PACKAGE
, LOCALEDIR
);
915 memset(lsblk
, 0, sizeof(*lsblk
));
917 while((c
= getopt_long(argc
, argv
, "abde:fhlnmo:irt", longopts
, NULL
)) != -1) {
920 lsblk
->all_devices
= 1;
929 parse_excludes(optarg
);
935 if (tt_flags
& TT_FL_RAW
)
936 errx_mutually_exclusive("--{raw,list}");
938 tt_flags
&= ~TT_FL_TREE
; /* disable the default */
941 tt_flags
|= TT_FL_NOHEADINGS
;
944 if (tt_parse_columns_list(optarg
, columns
, &ncolumns
,
949 tt_flags
= TT_FL_ASCII
;
952 tt_flags
&= ~TT_FL_TREE
; /* disable the default */
953 tt_flags
|= TT_FL_RAW
; /* enable raw */
956 columns
[ncolumns
++] = COL_NAME
;
957 columns
[ncolumns
++] = COL_FSTYPE
;
958 columns
[ncolumns
++] = COL_LABEL
;
959 columns
[ncolumns
++] = COL_TARGET
;
962 columns
[ncolumns
++] = COL_NAME
;
963 columns
[ncolumns
++] = COL_SIZE
;
964 columns
[ncolumns
++] = COL_OWNER
;
965 columns
[ncolumns
++] = COL_GROUP
;
966 columns
[ncolumns
++] = COL_MODE
;
969 columns
[ncolumns
++] = COL_NAME
;
970 columns
[ncolumns
++] = COL_ALIOFF
;
971 columns
[ncolumns
++] = COL_MINIO
;
972 columns
[ncolumns
++] = COL_OPTIO
;
973 columns
[ncolumns
++] = COL_PHYSEC
;
974 columns
[ncolumns
++] = COL_LOGSEC
;
975 columns
[ncolumns
++] = COL_ROTA
;
976 columns
[ncolumns
++] = COL_SCHED
;
984 columns
[ncolumns
++] = COL_NAME
;
985 columns
[ncolumns
++] = COL_MAJMIN
;
986 columns
[ncolumns
++] = COL_RM
;
987 columns
[ncolumns
++] = COL_SIZE
;
988 columns
[ncolumns
++] = COL_RO
;
989 columns
[ncolumns
++] = COL_TARGET
;
992 if (nexcludes
&& lsblk
->all_devices
)
993 errx_mutually_exclusive("--{all,exclude}");
995 excludes
[nexcludes
++] = 1; /* default: ignore RAM disks */
997 * initialize output columns
999 if (!(lsblk
->tt
= tt_new_table(tt_flags
)))
1000 errx(EXIT_FAILURE
, _("failed to initialize output table"));
1002 for (i
= 0; i
< ncolumns
; i
++) {
1003 struct colinfo
*ci
= get_column_info(i
);
1006 if (!(tt_flags
& TT_FL_TREE
) && get_column_id(i
) == COL_NAME
)
1009 if (!tt_define_column(lsblk
->tt
, ci
->name
, ci
->whint
, fl
)) {
1010 warn(_("failed to initialize output column"));
1016 status
= iterate_block_devices();
1017 else while (optind
< argc
)
1018 status
= process_one_device(argv
[optind
++]);
1020 tt_print_table(lsblk
->tt
);
1023 tt_free_table(lsblk
->tt
);