├── LICENSE ├── README.md ├── lsblk ├── lsblk.examples.png └── release ├── lsblk-1.0.tar.gz ├── lsblk-1.1.tar.gz ├── lsblk-3.4.tar.gz ├── lsblk-3.5.tar.gz ├── lsblk-3.6.tar.gz ├── lsblk-3.7.tar.gz ├── lsblk-3.8.tar.gz ├── lsblk-3.9.tar.gz └── lsblk-4.0.tar.gz /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 2-Clause License 2 | 3 | Copyright (c) 2020, vermaden 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 20 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # lsblk 2 | ___ ___ ___ __ _ _ _____ 3 | \ \ __\__\__\ \ \ __ / / / \ 4 | \ \/ __/ \ \ \/ // / / . \ 5 | \ \___ \ \ \ \_ \\ \ \ \ / 6 | \___\__/\____/\___\/\_\\_\_\____\/ 7 | 8 | List information about block devices in the FreeBSD system. 9 | 10 | I often need(ed) to work with Linux systems - and there is `lsblk(8)` command. 11 | 12 | Anything closest to it (but still far away) in FreeBSD land are: 13 | 14 | ``` 15 | # geom disk list 16 | # camcontrol devlist 17 | # gpart show 18 | # mount 19 | # zfs list 20 | ``` 21 | 22 | ... and none of these tools provide complete information like `lsblk(8)` does. 23 | 24 | So I wrote `lsblk(8)` in POSIX `/bin/sh` for FreeBSD. 25 | 26 | It only supports two modes. 27 | 28 | The default one w/o any arguments. 29 | 30 | Listing entire disks with `-d` option. 31 | 32 | Hope that helps. 33 | 34 | Below you will see examples of **lsblk(8)** usage. 35 | 36 | ![lsblk(8) Examples](https://github.com/vermaden/lsblk/raw/master/lsblk.examples.png) 37 | 38 | For comparison - this is how Linux version of `lsblk(8)` output looks like. 39 | 40 | ``` 41 | [root@rhidm ~]# lsblk 42 | NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT 43 | vda 252:0 0 20G 0 disk 44 | ├─vda1 252:1 0 600M 0 part /boot/efi 45 | ├─vda2 252:2 0 1G 0 part /boot 46 | └─vda3 252:3 0 18.4G 0 part 47 | ├─rhel-root 253:0 0 16.4G 0 lvm / 48 | └─rhel-swap 253:1 0 2G 0 lvm [SWAP] 49 | 50 | [root@rhidm ~]# lsblk -d 51 | NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT 52 | vda 252:0 0 20G 0 disk 53 | 54 | ``` 55 | 56 | ... and mine `lsblk(8)` on FreeBSD system. 57 | 58 | ``` 59 | FreeBSD # lsblk 60 | DEVICE MAJ:MIN SIZE TYPE LABEL MOUNT 61 | ada0 0:123 489G GPT - - 62 | ada0p1 0:128 260M efi gpt/efiboot0 /boot/efi 63 | ada0p2 0:129 512K freebsd-boot gpt/gptboot0 - 64 | -:- 492K - - - 65 | ada0p3 0:130 4.0G freebsd-swap gpt/freebsd-swap SWAP 66 | ada0p4 0:131 485G freebsd-zfs gpt/freebsd-zfs 67 | -:- 500K - - - 68 | nda0 0:107 477G GPT - - 69 | -:- 1.0M - - - 70 | nda0p1 0:109 100M efi gpt/EFI - 71 | nda0p2 0:111 16M ms-reserved gpt/MS/reserved - 72 | nda0p3 0:113 476G ms-basic-data gpt/MS/data/basic - 73 | -:- 698K - - - 74 | nda0p4 0:115 509M ms-recovery gpt/ms-recovery - 75 | -:- 1.3M - - - 76 | 77 | FreeBSD # lsblk -d 78 | DEVICE SIZE MODEL 79 | ada0 489G Crucial CT525MX300SSD1 80 | nda0 477G INTEL SSDPEKNW512GZL 81 | - 966G TOTAL SYSTEM STORAGE 82 | 83 | ``` 84 | -------------------------------------------------------------------------------- /lsblk: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | 3 | # Copyright (c) 2016-2025 Slawomir Wojciech Wojtczak (vermaden) 4 | # All rights reserved. 5 | # 6 | # THIS SOFTWARE USES FREEBSD LICENSE (ALSO KNOWN AS 2-CLAUSE BSD LICENSE) 7 | # https://www.freebsd.org/copyright/freebsd-license.html 8 | # 9 | # Redistribution and use in source and binary forms, with or without 10 | # modification, are permitted provided that following conditions are met: 11 | # 1. Redistributions of source code must retain the above copyright 12 | # notice, this list of conditions and the following disclaimer. 13 | # 2. Redistributions in binary form must reproduce the above copyright 14 | # notice, this list of conditions and the following disclaimer in the 15 | # documentation and/or other materials provided with the distribution. 16 | # 17 | # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS 'AS IS' AND ANY 18 | # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 | # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | # DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY 21 | # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 | # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 | # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 | # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | # 28 | # ------------------------------ 29 | # REPLACEMENT FOR LINUX lsblk(8) 30 | # ------------------------------ 31 | # vermaden [AT] interia [DOT] pl 32 | # https://vermaden.wordpress.com 33 | 34 | PATH=${PATH}:/bin:/usr/bin:/usr/local/bin:/sbin:/usr/sbin:/usr/local/sbin 35 | 36 | # DISPLAY VERSION 37 | if [ "${1}" = "--version" -o \ 38 | "${1}" = "-version" -o \ 39 | "${1}" = "version" ] 40 | then 41 | echo 42 | echo " ___ ___ ___ __ _ _ _____ " 43 | echo " \ \ __\__\__\ \ \ __ / / / \ " 44 | echo " \ \/ __/ \ \ \/ // / / . \ " 45 | echo " \ \___ \ \ \ \_ \\\ \ \ \ / " 46 | echo " \___\__/\____/\___\/\_\\\_\_\____\/ " 47 | echo 48 | echo "lsblk 4.1 2025/05/19" 49 | echo 50 | exit 0 51 | fi 52 | 53 | # DISPLAY HELP/USAGE/EXAMPLES 54 | __usage() { 55 | local NAME="${0##*/}" 56 | cat << __EOF 57 | usage: 58 | 59 | BASIC USAGE INFORMATION 60 | ======================= 61 | # ${NAME} [DISK] 62 | # ${NAME} --disks | -d 63 | # ${NAME} --version 64 | 65 | example(s): 66 | 67 | LIST ALL BLOCK DEVICES IN SYSTEM 68 | -------------------------------- 69 | # ${NAME} 70 | DEVICE MAJ:MIN SIZE TYPE LABEL MOUNT 71 | ada0 0:92 932G GPT - - 72 | ada0p1 0:100 200M efi efiboot0 - 73 | ada0p2 0:101 512K freebsd-boot gptboot0 - 74 | -:- 492K - - - 75 | ada0p3 0:102 931G freebsd-zfs zfs0 76 | ada0p3.eli 0:106 931G freebsd-zfs - 77 | 78 | LIST ONLY da1 BLOCK DEVICE 79 | -------------------------- 80 | # ${NAME} da1 81 | DEVICE MAJ:MIN SIZE TYPE LABEL MOUNT 82 | da1 0:80 2.0G MBR - - 83 | da1s1 0:80 2.0G freebsd - - 84 | da1s1a 0:81 1.0G freebsd-ufs root / 85 | da1s1b 0:82 1.0G freebsd-swap swap SWAP 86 | 87 | LIST ENTIRE DISKS 88 | ----------------- 89 | # ${NAME} -d 90 | DEVICE SIZE MODEL 91 | ada0 1.8T Samsung SSD 860 QVO 2TB 92 | ada1 119G SAMSUNG SSD PM830 mSATA 128GB 93 | - 2T TOTAL SYSTEM STORAGE 94 | 95 | hint(s): 96 | 97 | DISPLAY PHYSICAL DISKS 98 | ---------------------- 99 | # sysctl kern.disks 100 | kern.disks: ada0 da0 da1 101 | 102 | DISPLAY MEMORY BACKED DISKS 103 | --------------------------- 104 | # mdconfig -l 105 | md0 106 | 107 | __EOF 108 | exit 1 109 | } 110 | # __usage() ENDED 111 | 112 | # GET MAJOR/MINOR NUMBERS 113 | __major_minor() { # 1=DEV 114 | local DEV=$( echo "${1}" | sed s./dev/..g ) 115 | MAJ=$( stat -f "%Hr" /dev/${DEV} ) 116 | MIN=$( stat -f "%Lr" /dev/${DEV} ) 117 | } 118 | # __major_minor() ENDED 119 | 120 | # DETECT IF SWAP IS BEING USED 121 | __swap_mount() { # 1=DEV 122 | local DEV="${1}" 123 | SWAP_FOUND=0 124 | 125 | # DETECT SWAP BY RAW DEVICE 126 | if swapctl -l | grep -q -- ${DEV} 2> /dev/null 127 | then 128 | TYPE=freebsd-swap 129 | MOUNT=SWAP 130 | LABEL="-" 131 | SWAP_FOUND=1 132 | return 133 | fi 134 | 135 | # DETECT SWAP BY LABEL 136 | while read LABELER GARBAGE PROVIDER 137 | do 138 | if [ "${DEV}" = "${PROVIDER}" ] 139 | then 140 | if swapctl -l | grep -q -- ${LABELER} 2> /dev/null 141 | then 142 | TYPE=freebsd-swap 143 | LABEL=${LABELER} 144 | MOUNT=SWAP 145 | SWAP_FOUND=1 146 | break 147 | fi 148 | fi 149 | done << __EOF 150 | $( echo "${GLABEL}" ) 151 | __EOF 152 | } 153 | # __swap_mount() ENDED 154 | 155 | # DETECT TYPE WITH fstyp(8) TOOL 156 | __type() { # 1=DEV 157 | local DEV=${1} 158 | TYPE=$( fstyp -u /dev/${DEV} 2> /dev/null ) 159 | [ "${TYPE}" = "" ] && __swap_mount ${DEV} 160 | [ "${TYPE}" = "" ] && TYPE="-" 161 | } 162 | # __type() ENDED 163 | 164 | # DETECT MOUNT/LABEL IF POSSIBLE 165 | __mount_label() { # 1=TARGET 166 | local TARGET="${1}" 167 | local MOUNT_FOUND=0 168 | local LABEL_FOUND=0 169 | LABEL="-" 170 | if [ "${SWAP_FOUND}" = "1" ] 171 | then 172 | local MOUNT_FOUND=1 173 | else 174 | MOUNT="-" 175 | fi 176 | 177 | # CHECK IF DEVICE EXISTS - IT NOT THEN EXIT FUNCTION 178 | [ ! -e /dev/${TARGET} ] && return 179 | 180 | # TRY CLASSIC MOUNT POINT WITH DEVICE NAME 181 | if [ "${MOUNT_FOUND}" != "1" ] 182 | then 183 | MOUNT=$( mount | grep "/dev/${TARGET} " | awk 'END{print $3}' ) 184 | if [ "${MOUNT}" = "" ] 185 | then 186 | MOUNT="-" 187 | else 188 | local MOUNT_FOUND=1 189 | fi 190 | fi 191 | 192 | # GET LABEL/MOUNT FOR UFS/zfs(8)/msdosfs(8) FILESYSTEM 193 | case ${TYPE} in 194 | (freebsd-ufs) 195 | LABEL=$( tunefs -p /dev/${TARGET} 2>&1 | awk '/volume label/ {print $5}' ) 196 | if [ "${LABEL}" = "" ] 197 | then 198 | LABEL="-" 199 | else 200 | LABEL="ufs/${LABEL}" 201 | local LABEL_FOUND=1 202 | fi 203 | ;; 204 | (freebsd-zfs) 205 | # zfs(8) IS NEVER MOUNTED BY RAW DEVICE NAME 206 | # SO NO NEED TO CHECK IF MOUNT_FOUND = 1 HERE 207 | MOUNT="" 208 | local MOUNT_FOUND=1 209 | ;; 210 | (msdosfs) 211 | LABEL=$( file -s /dev/${DEV} | tr ',' '\n' | awk -F '"' '/label:/ {print $2}' ) 212 | if [ "${LABEL}" = "" ] 213 | then 214 | LABEL="-" 215 | else 216 | LABEL="msdosfs/${LABEL}" 217 | local LABEL_FOUND=1 218 | fi 219 | ;; 220 | (exfat) 221 | # IF exfatlabel(8) IS AVAIALBLE THEN READ exFAT LABEL 222 | if which exfatlabel 1> /dev/null 2> /dev/null 223 | then 224 | LABEL=$( exfatlabel /dev/${DEV} 2> /dev/null ) 225 | if [ "${LABEL}" = "" ] 226 | then 227 | LABEL="-" 228 | else 229 | LABEL="exfat/${LABEL}" 230 | local LABEL_FOUND=1 231 | fi 232 | fi 233 | ;; 234 | esac 235 | 236 | # GET LABEL USING glabel(8) 237 | if [ "${LABEL_FOUND}" != "1" ] 238 | then 239 | # TRY GLABEL MOUNTPOINT AS msdosfs MOUNT IS NOT POSSIBLE WITHOUT GPT/MBR 240 | local GLABEL_GREP=$( echo "${GLABEL}" | grep -v ufsid | grep " ${TARGET}\$" ) 241 | if [ "${GLABEL_GREP}" = "" ] 242 | then 243 | LABEL="-" 244 | else 245 | while read PROVIDER STATUS DEVICE 246 | do 247 | LABEL=$( echo "${GLABEL_GREP}" | grep -m 1 " ${TARGET}" | awk '{print $1}' | sed -e 's@%20@ @g' ) 248 | local LABEL_FOUND=1 249 | break 250 | done << ______EOF 251 | $( echo "${GLABEL_GREP}" ) 252 | ______EOF 253 | fi 254 | fi 255 | 256 | # GET MOUNT USING glabel(8) 257 | if [ "${MOUNT_FOUND}" != "1" ] 258 | then 259 | # TRY GLABEL MOUNTPOINT AS msdosfs MOUNT IS NOT POSSIBLE WITHOUT GPT/MBR 260 | local GLABEL_GREP=$( echo "${GLABEL}" | grep -v ufsid | grep " ${TARGET}\$" ) 261 | if [ "${GLABEL_GREP}" != "" ] 262 | then 263 | while read PROVIDER STATUS DEVICE 264 | do 265 | MOUNT=$( mount | grep "${PROVIDER}" | awk 'END{print $3}' ) 266 | if [ "${MOUNT}" = "" ] 267 | then 268 | MOUNT="-" 269 | else 270 | local MOUNT_FOUND=1 271 | fi 272 | break 273 | done << ______EOF 274 | $( echo "${GLABEL_GREP}" ) 275 | ______EOF 276 | fi 277 | fi 278 | 279 | # GET MOUNT FROM fuse(8) 280 | if [ "${MOUNT_FOUND}" != "1" ] 281 | then 282 | if [ -e /dev/fuse ] 283 | then 284 | local FUSE_PIDS=$( fstat /dev/fuse 2> /dev/null | awk 'NR > 1 {print $3}' | tr '\n' ',' | sed '$s/.$//' ) 285 | else 286 | local FUSE_PIDS=$( pgrep mount.exfat ntfs-3g 2> /dev/null | tr '\n' ',' | sed '$s/.$//' ) 287 | fi 288 | if [ "${FUSE_PIDS}" != "" ] 289 | then 290 | local FUSE_MOUNTS=$( ps -p "${FUSE_PIDS}" -o command | sed 1d | sort -u ) 291 | MOUNT=$( echo "${FUSE_MOUNTS}" | grep "/dev/${TARGET} " | sed 's|(mount.exfat-fuse)||g' | awk '{print $NF}' ) 292 | # TRY automount(8) STATE FILE IF EXISTS 293 | if [ "${MOUNT}" = "" ] 294 | then 295 | if [ -f /var/run/automount.state ] 296 | then 297 | MOUNT=$( grep "^/dev/${TARGET} " /var/run/automount.state | awk '{print $NF}' ) 298 | if ! mount -t fusefs | grep -q "${MOUNT}" 299 | then 300 | MOUNT="-" 301 | fi 302 | fi 303 | fi 304 | if [ "${MOUNT}" = "" ] 305 | then 306 | MOUNT="-" 307 | else 308 | local MOUNT_FOUND=1 309 | fi 310 | fi 311 | fi 312 | 313 | # GET LABEL FROM gpart(8) 314 | if [ "${LABEL_FOUND}" != "1" ] 315 | then 316 | LABEL=$( gpart show -p ${DEV} 2> /dev/null | sed 's|=>||g' | sed -E 's-\[.*\]--g' | grep "${TARGET} " | awk '{for (i=4; i<256; i++) if ($i) if($i != $NF) print $i}' ) 317 | if [ "${LABEL}" = "" -o "${LABEL}" = "(null)" ] 318 | then 319 | LABEL="-" 320 | else 321 | LABEL="gpt/${LABEL}" 322 | fi 323 | fi 324 | SWAP_FOUND=0 325 | } 326 | # __mount_label() ENDED 327 | 328 | # LIST BLOCK DEVICES 329 | __list_block_devices() { 330 | # FIRST 1000 DEVICES OF EACH CLASS SHOULD DO 331 | ( 332 | sysctl -n kern.disks | tr ' ' '\n' 333 | for I in ada da mmcsd md vtbd 334 | do 335 | ls -1 /dev/${I}[0-9] 2> /dev/null 336 | ls -1 /dev/${I}[0-9][0-9] 2> /dev/null 337 | ls -1 /dev/${I}[0-9][0-9][0-9] 2> /dev/null 338 | done 339 | ) \ 340 | | sed 's|/dev/||g' \ 341 | | sed -r "s/[[:cntrl:]]\[[0-9]{1,3}m//g" \ 342 | | sort -u \ 343 | | sed '/^s*$/d' 344 | } 345 | # __list_block_devices() ENDED 346 | 347 | # PRINT DEVICES AND PARTITIONS 348 | __print_parts() { # 1=NAME 2=TYPE 3=SIZE 4=SIZE_FREE 349 | local NAME=${1} 350 | local TYPE=${2} 351 | local SIZE=${3} 352 | local SIZE_FREE=${4} 353 | 354 | case ${TYPE} in 355 | (free) 356 | # REMOVE BRACKETS FROM SIZE 357 | local SIZE_FREE=$( echo ${SIZE_FREE} | tr -d '()' ) 358 | # FIRST 16 SECTORS ARE ALWAYS EMPTY ON bsdlabel(8) PARTITION SCHEMA 359 | [ "${SIZE_FREE}" = "8.0K" ] && return 360 | # OUTPUT 361 | printf "${FORMAT}" "" - - ${SIZE_FREE} "-" "${LABEL}" ${MOUNT} 362 | ;; 363 | (*) 364 | # NEEDED FOR bsdlabel(8) ON WHOLE DISK WITHOUT PARTITION 365 | # WORKAROUND FOR gpart(8) BUG 241004 366 | # https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=241004 367 | if [ "${TYPE}" = "!0" ] 368 | then 369 | local TYPE=freebsd-ufs 370 | fi 371 | 372 | # REMOVE BRACKETS FROM SIZE 373 | local SIZE=$( echo ${SIZE} | tr -d '()' ) 374 | [ "${LABEL}" = "" ] && local LABEL="-" 375 | [ "${MOUNT}" = "" ] && local MOUNT="-" 376 | __major_minor ${NAME} 377 | 378 | # REPLACE LONG Microsoft BULLSHIT NAMES WITH SOMETHING RELEVANT 379 | LABEL=$( echo "${LABEL}" \ 380 | | sed -e 's.EFI system partition.EFI.g' \ 381 | -e 's.Microsoft reserved partition.MS/reserved.g' \ 382 | -e 's.Main Data Partition.MS/data/main.g' \ 383 | -e 's.Basic data partition.MS/data/basic.g' 384 | ) 385 | 386 | # PRINT INFORMATION ON TERMINAL 387 | printf "${FORMAT}" ${NAME} ${MAJ} ${MIN} ${SIZE} ${TYPE} "${LABEL}" ${MOUNT} 388 | if [ -e /dev/${NAME}.eli ] 389 | then 390 | # GET GELI MOUNT/LABEL/MAJOR/MINOR 391 | __major_minor ${NAME}.eli 392 | __type ${NAME}.eli 393 | __mount_label ${NAME}.eli 394 | printf "${FORMAT}" ${NAME}.eli ${MAJ} ${MIN} ${SIZE} ${TYPE} "${LABEL}" ${MOUNT} 395 | MOUNT="-" 396 | fi 397 | ;; 398 | esac 399 | } 400 | # __print_parts() ENDED 401 | 402 | # WHEN GPART OUTPUT EXISTS (partition table / not entire device) 403 | __gpart_present() { # 1=DEV 404 | local DEV=${1} 405 | local TYPE="-" 406 | local LABEL="-" 407 | local MOUNT="-" 408 | local SIZE="-" 409 | local SIZE_FREE="-" 410 | # CHECK IF DEVICE EXISTS 411 | if [ ! -e ${DEV} ] 412 | then 413 | DEV=/dev/${DEV} 414 | [ ! -e ${DEV} ] && return 415 | fi 416 | # WORKAROUND FOR gpart(1) BUG 240998 417 | # https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=240998 418 | TYPE_EXFAT_HELPER_DEVICE=$( gpart show -p ${DEV} 2> /dev/null | head -1 | sed -E 's-\[.*\]--g' | awk '{print $5}' 2> /dev/null ) 419 | if [ "${TYPE_EXFAT_HELPER_DEVICE}" = "MBR" ] 420 | then 421 | TYPE_EXFAT_HELPER=$( fstyp -u /dev/${DEV} 2> /dev/null ) 422 | if [ "${TYPE_EXFAT_HELPER}" = "exfat" ] 423 | then 424 | TYPE=exfat 425 | case ${DEV} in 426 | (md*) SIZE=$( diskinfo -v ${DEV} 2> /dev/null | awk '/mediasize in bytes/ {print $NF}' | tr -d '()' ) ;; 427 | (*) SIZE=$( geom disk list ${DEV} 2> /dev/null | awk '/Mediasize:/ {print $NF}' | tr -d '()' ) ;; 428 | esac 429 | __mount_label ${DEV} 430 | # EXFAT FILESYSTEM ON WHOLE DEVICE IS INTERPETED AS MBR - FIX THAT 431 | if [ "${LABEL}" = "gpt/MBR" ] 432 | then 433 | 434 | # IF exfatlabel(8) IS AVAIALBLE THEN READ exFAT LABEL 435 | if which exfatlabel 1> /dev/null 2> /dev/null 436 | then 437 | LABEL=$( exfatlabel /dev/${DEV} 2> /dev/null ) 438 | if [ "${LABEL}" = "" ] 439 | then 440 | local LABEL="-" 441 | else 442 | local LABEL="exfat/${LABEL}" 443 | fi 444 | fi 445 | 446 | fi 447 | __print_parts ${DEV} ${TYPE} ${SIZE} ${MOUNT} 448 | continue 449 | fi 450 | fi 451 | 452 | # READ PARTITIONS OF PROVIDER 453 | local GPART=$( gpart show -p ${DEV} 2> /dev/null | sed -E 's-\[.*\]--g' | sed 's|=>||g' ) 454 | # PARSE gpart(8) OUTPUT 455 | echo "${GPART}" \ 456 | | while read BEG END NAME TYPE SIZE SIZE_FREE 457 | do 458 | # VISITED ONLY ONCE FOR WHOLE DEVICE 459 | if [ ${LEVEL_DEV} = "0" ] 460 | then 461 | # WHOLE DEVICE 462 | LEVEL_DEV=1 463 | FORMAT="${FORMAT_L0}" 464 | __print_parts ${NAME} ${TYPE} ${SIZE} ${SIZE_FREE} 465 | else 466 | # PARTITION 467 | FORMAT="${FORMAT_L1}" 468 | # READ PARTITIONS OF PROVIDER 469 | local GPART_PARTS=$( gpart show -p ${NAME} 2> /dev/null | sed -E 's-\[.*\]--g' | sed 's|=>||g' ) 470 | # PARSE gpart(8) OUTPUT 471 | if [ "${GPART_PARTS}" != "" ] 472 | then 473 | # PARTITION IN PARTITION 474 | [ ! -e /dev/${NAME} ] && return 475 | # PARSE DEVICE 476 | echo "${GPART_PARTS}" \ 477 | | while read BEG END NAMEONE TYPE SIZE SIZE_FREE 478 | do 479 | # VISITED ONLY ONCE FOR WHOLE DEVICE 480 | if [ ${LEVEL_PAR} = "0" ] 481 | then 482 | # WHOLE DEVICE 483 | LEVEL_PAR=1 484 | FORMAT="${FORMAT_L1}" 485 | else 486 | # PARTITION 487 | FORMAT="${FORMAT_L2}" 488 | fi 489 | # CHECK IF SWAP IS ENABLED FOR SWAP DEVICES 490 | [ "${TYPE}" = "freebsd-swap" ] && __swap_mount ${NAMEONE} 491 | __mount_label ${NAMEONE} 492 | __print_parts ${NAMEONE} ${TYPE} ${SIZE} ${SIZE_FREE} 493 | done 494 | else 495 | # FILESYSTEM 496 | [ "${TYPE}" = "freebsd-swap" ] && __swap_mount ${DEV} 497 | __mount_label ${NAME} 498 | __print_parts ${NAME} ${TYPE} ${SIZE} ${SIZE_FREE} 499 | fi 500 | fi 501 | done 502 | } 503 | # __gpart_present() ENDED 504 | 505 | # WHEN GPART OUTPUT DO NOT EXISTS (no partition table / entire device) 506 | __gpart_absent() { # 1=DEV 507 | local DEV=${1} 508 | # EXIT IF DEVICE DOES NOT EXISTS 509 | if [ ! -e ${DEV} ] 510 | then 511 | DEV=/dev/${DEV} 512 | [ ! -e ${DEV} ] && return 513 | fi 514 | local MOUNT="-" 515 | local DEV=$( echo "${DEV}" | sed s./dev/..g ) 516 | case ${DEV} in 517 | (md*) local SIZE=$( diskinfo -v ${DEV} 2> /dev/null | awk '/mediasize in bytes/ {print $NF}' | tr -d '()' ) ;; 518 | (*) local SIZE=$( geom disk list ${DEV} 2> /dev/null | awk '/Mediasize:/ {print $NF}' | tr -d '()' ) ;; 519 | esac 520 | # WHEN SIZE IS NOT AVAILABLE ITS PROBABLY EMPTY CARD READER 521 | if [ "${SIZE}" = "0B" ] 522 | then 523 | return 524 | fi 525 | local SIZE_FREE="-" 526 | __type ${DEV} 527 | __mount_label ${DEV} 528 | [ "${SIZE}" = "" ] && local SIZE="-" 529 | [ "${TYPE}" = "" ] && local TYPE="-" 530 | [ "${LABEL}" = "" ] && local LABEL="-" 531 | [ "${MOUNT}" = "" ] && local MOUNT="-" 532 | # REMOVE SPACE(S) 533 | LABEL=$( echo ${LABEL} ) 534 | __print_parts ${DEV} ${TYPE} ${SIZE} ${SIZE_FREE} 535 | } 536 | # __gpart_absent() ENDED 537 | 538 | # CHECK MAX UNIT 539 | __list_disks_max_unit() { # 1=UNIT_TO_CHECK_IN_NUMBER 540 | ORDER=${1} 541 | if [ ${1} -gt ${MAXUNIT} ] 542 | then 543 | MAXUNIT=${1} 544 | fi 545 | } 546 | # __list_disks_max_unit() ENDED 547 | 548 | # SET DIV/UNIT/MAXDIV VALUE 549 | __list_disks_max_div() { # 1=ORDER TO SET 550 | case ${1} in 551 | (0) DIV=1 ; UNIT=B ;; 552 | (1) DIV=$(( 1024 )) ; UNIT=K ;; 553 | (2) DIV=$(( 1024 * 1024 )) ; UNIT=M ;; 554 | (3) DIV=$(( 1024 * 1024 * 1024 )) ; UNIT=G ;; 555 | (4) DIV=$(( 1024 * 1024 * 1024 * 1024 )) ; UNIT=T ;; 556 | (5) DIV=$(( 1024 * 1024 * 1024 * 1024 * 1024 )) ; UNIT=E ;; 557 | (*) DIV=1 ; UNIT=B ;; 558 | esac 559 | if [ ${DIV} -gt ${MAXDIV} ] 560 | then 561 | MAXDIV=${DIV} 562 | fi 563 | } 564 | # __list_disks_max_div() ENDED 565 | 566 | # SET ENDUNIT FOR TOTALE STORAGE SUM PRINTING 567 | __list_disks_unit_set() { # 1=ORDER TO SET 568 | case ${1} in 569 | (0) ENDUNIT=B ;; 570 | (1) ENDUNIT=K ;; 571 | (2) ENDUNIT=M ;; 572 | (3) ENDUNIT=G ;; 573 | (4) ENDUNIT=T ;; 574 | (5) ENDUNIT=E ;; 575 | esac 576 | } 577 | # __list_disks_unit_set() ENDED 578 | 579 | # LIST ENTIRE DISKS ONLY 580 | __list_disks() { 581 | # GET WIDTH FOR ${DEVICE} COLUMN 582 | local DEVICE_WIDTH=$( 583 | echo -e "DEVICE\n${DISKS}" \ 584 | | while read I 585 | do 586 | echo ${I} | wc -c 587 | done \ 588 | | sort -u \ 589 | | tail -1 \ 590 | | tr -cd 0-9 ) 591 | 592 | # LOCAL VARIABLES 593 | local DEVICE_WIDTH=$(( ${DEVICE_WIDTH} - 1 )) 594 | 595 | # NOT LOCAL VARIABLES 596 | MAXUNIT=1 597 | MAXDIV=1024 598 | ENDUNIT=K 599 | SUM=0 600 | 601 | # SET FORMAT 602 | local FORMAT="%-${DEVICE_WIDTH}s %5s %s\n" 603 | 604 | # PRINT HEADER 605 | printf "${FORMAT}" DEVICE SIZE MODEL 606 | 607 | # DO THE JOB 608 | while read DEVICE 609 | do 610 | # GET PER DEVICE INFO 611 | case ${DEVICE} in 612 | (md*) 613 | local SIZE=$( diskinfo -v ${DEVICE} 2> /dev/null| awk '/mediasize in bytes/ {print $NF}' | tr -d '()' ) 614 | local MODEL="FreeBSD md(4) Memory Disk" 615 | ;; 616 | (*) 617 | local GEOM_DISK_LIST=$( geom disk list ${DEVICE} 2> /dev/null ) 618 | local SIZE=$( echo "${GEOM_DISK_LIST}" | awk '/Mediasize:/ {print $NF}' | tr -d '()' ) 619 | local MODEL=$( echo "${GEOM_DISK_LIST}" | awk -F ':' '/descr:/ {print $2}' | sed '$s/^.//' | tr -cd '0-9a-zA-Z -./\n' | tr -d '?' ) 620 | unset GEOM_DISK_LIST 621 | ;; 622 | esac 623 | 624 | # CALCULATE TOTAL STORAGE SUM 625 | case ${SIZE} in 626 | (*B|*b) MULT=1 ;; 627 | (*K|*k) MULT=$(( 1024 )) ; ORDER=1 ; __list_disks_max_unit ${ORDER} ;; 628 | (*M|*m) MULT=$(( 1024 * 1024 )) ; ORDER=2 ; __list_disks_max_unit ${ORDER} ;; 629 | (*G|*g) MULT=$(( 1024 * 1024 * 1024 )) ; ORDER=3 ; __list_disks_max_unit ${ORDER} ;; 630 | (*T|*t) MULT=$(( 1024 * 1024 * 1024 * 1024 )) ; ORDER=4 ; __list_disks_max_unit ${ORDER} ;; 631 | (*E|*e) MULT=$(( 1024 * 1024 * 1024 * 1024 * 1024 )) ; ORDER=5 ; __list_disks_max_unit ${ORDER} ;; 632 | (*) MULT=1 ; ;; 633 | esac 634 | BYTES=$( echo ${SIZE} | tr -c -d '0-9.,' ) 635 | BYTES=$( echo "${BYTES} * ${MULT}" | bc -l ) 636 | SUM=$( echo "${SUM} + ${BYTES}" | bc -l ) 637 | __list_disks_max_div ${ORDER} 638 | 639 | # BACK PER DEVICE LISTING 640 | [ "${SIZE}" = "" ] && local SIZE="-" 641 | [ "${MODEL}" = "" ] && local MODEL="-" 642 | printf "${FORMAT}" ${DEVICE} ${SIZE} "${MODEL}" 643 | unset SIZE MODEL 644 | done << EOF 645 | $( echo "${DISKS}" ) 646 | EOF 647 | 648 | # PRINT TOTAL STORAGE INFO 649 | __list_disks_unit_set ${MAXUNIT} 650 | SUM=$( echo "${SUM} / ${MAXDIV}" | bc -l ) 651 | SUM=$( printf "%3.0f" "${SUM}" ) 652 | printf "${FORMAT}" - "${SUM}${ENDUNIT}" "TOTAL SYSTEM STORAGE" 653 | unset MAXUNIT MAXDIV ENDUNIT SUM 654 | } 655 | # __list_disks() ENDED 656 | 657 | # PARSE ARGUMENTS IF THERE ARE ANY 658 | LEVEL_DEV=0 659 | LEVEL_PAR=0 660 | GLABEL=$( glabel status | sed 1d | grep -v gptid ) 661 | DISKS=$( __list_block_devices ) 662 | 663 | case ${#} in 664 | (0) 665 | # LIST ALL DISKS 666 | : 667 | ;; 668 | (1) 669 | # SINGLE ARGUMENT MEANS 'SINGLE DISK' OR 'ENTIRE DISKS ONLY' OR 'HELP' 670 | case ${1} in 671 | (-d|--disks) 672 | __list_disks 673 | exit 0 674 | ;; 675 | (h|-h|--h|help|-help|--help|*) 676 | __usage 677 | ;; 678 | esac 679 | # SINGLE DISK CHECK 680 | DISKCHECK="${1}" 681 | DISKCHECK=$( echo "${1}" | sed s./dev/..g ) 682 | if echo "${DISKS}" | grep -q -- "${DISKCHECK}" 683 | then 684 | DISKS="${DISKCHECK}" 685 | unset DISKCHECK 686 | else 687 | # SUPPORT DISPLAYING SINGLE PARTITIONS 688 | if [ /dev/${DISKCHECK} ] 689 | then 690 | PARTCHECK=$( echo "${DISKCHECK}" | grep -o -E '[a-zA-Z]+[0-9]+' | head -1 ) 691 | ${0} ${PARTCHECK} | grep --color=none -e '^DEVICE' -e "${DISKCHECK}" 692 | exit 0 693 | fi 694 | # DISK AND/OR PARTITION DOES NOT EXIST - DISPLAY ERROR AND EXIT 695 | echo "NOPE: disk '${DISKCHECK}' does not exist in the system" 696 | echo 697 | __usage 698 | fi 699 | ;; 700 | (*) 701 | # ONLY '0' and '1' ARGUMENTS ARE COVERED 702 | __usage 703 | ;; 704 | esac 705 | 706 | # SET OUTPUT FORMAT AND PRINT HEADER 707 | FORMAT_L0="%-14s %3s:%-3s %4s %-18s %26s %s\n" 708 | FORMAT_L1=" %-12s %3s:%-3s %4s %-18s %26s %s\n" 709 | FORMAT_L2=" %-10s %3s:%-3s %4s %-18s %26s %s\n" 710 | FORMAT="${FORMAT_L0}" 711 | printf "${FORMAT}" DEVICE MAJ MIN SIZE TYPE LABEL MOUNT 712 | 713 | # LIST ALL PARTITIONS OF ALL DISKS 714 | echo "${DISKS}" \ 715 | | while read DEVICE 716 | do 717 | if gpart show ${DEVICE} 1> /dev/null 2> /dev/null 718 | then 719 | __gpart_present ${DEVICE} 720 | else 721 | __gpart_absent ${DEVICE} 722 | fi 723 | done 724 | -------------------------------------------------------------------------------- /lsblk.examples.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vermaden/lsblk/d9b086eadaeb538d9235e08c0df2f4afa1cc9e0d/lsblk.examples.png -------------------------------------------------------------------------------- /release/lsblk-1.0.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vermaden/lsblk/d9b086eadaeb538d9235e08c0df2f4afa1cc9e0d/release/lsblk-1.0.tar.gz -------------------------------------------------------------------------------- /release/lsblk-1.1.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vermaden/lsblk/d9b086eadaeb538d9235e08c0df2f4afa1cc9e0d/release/lsblk-1.1.tar.gz -------------------------------------------------------------------------------- /release/lsblk-3.4.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vermaden/lsblk/d9b086eadaeb538d9235e08c0df2f4afa1cc9e0d/release/lsblk-3.4.tar.gz -------------------------------------------------------------------------------- /release/lsblk-3.5.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vermaden/lsblk/d9b086eadaeb538d9235e08c0df2f4afa1cc9e0d/release/lsblk-3.5.tar.gz -------------------------------------------------------------------------------- /release/lsblk-3.6.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vermaden/lsblk/d9b086eadaeb538d9235e08c0df2f4afa1cc9e0d/release/lsblk-3.6.tar.gz -------------------------------------------------------------------------------- /release/lsblk-3.7.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vermaden/lsblk/d9b086eadaeb538d9235e08c0df2f4afa1cc9e0d/release/lsblk-3.7.tar.gz -------------------------------------------------------------------------------- /release/lsblk-3.8.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vermaden/lsblk/d9b086eadaeb538d9235e08c0df2f4afa1cc9e0d/release/lsblk-3.8.tar.gz -------------------------------------------------------------------------------- /release/lsblk-3.9.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vermaden/lsblk/d9b086eadaeb538d9235e08c0df2f4afa1cc9e0d/release/lsblk-3.9.tar.gz -------------------------------------------------------------------------------- /release/lsblk-4.0.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vermaden/lsblk/d9b086eadaeb538d9235e08c0df2f4afa1cc9e0d/release/lsblk-4.0.tar.gz --------------------------------------------------------------------------------