4 # Copyright (c) 2016-2019 Slawomir Wojciech Wojtczak (vermaden)
7 # THIS SOFTWARE USES FREEBSD LICENSE (ALSO KNOWN AS 2-CLAUSE BSD LICENSE)
8 # https://www.freebsd.org/copyright/freebsd-license.html
10 # Redistribution and use in source and binary forms, with or without
11 # modification, are permitted provided that following conditions are met:
12 # 1. Redistributions of source code must retain the above copyright
13 # notice, this list of conditions and the following disclaimer.
14 # 2. Redistributions in binary form must reproduce the above copyright
15 # notice, this list of conditions and the following disclaimer in the
16 # documentation and/or other materials provided with the distribution.
18 # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS 'AS IS' AND ANY
19 # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 # DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY
22 # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 # ------------------------------
30 # REPLACEMENT FOR LINUX lsblk(8)
31 # ------------------------------
32 # vermaden [AT] interia [DOT] pl
33 # https://vermaden.wordpress.com
35 # https://github.com/vermaden/scripts/blob/master/lsblk.sh
37 PATH
=${PATH}:/bin
:/usr
/bin
:/usr
/local
/bin
:/sbin
:/usr
/sbin
:/usr
/local
/sbin
39 # DISPLAY HELP/USAGE/EXAMPLES
45 BASIC USAGE INFORMATION
46 =======================
51 LIST ALL BLOCK DEVICES IN SYSTEM
52 --------------------------------
54 DEVICE MAJ:MIN SIZE TYPE LABEL MOUNT
55 ada0 0:92 932G GPT - -
56 ada0p1 0:100 200M efi efiboot0 -
57 ada0p2 0:101 512K freebsd-boot gptboot0 -
59 ada0p3 0:102 931G freebsd-zfs zfs0 <ZFS>
60 ada0p3.eli 0:106 931G freebsd-zfs - <ZFS>
63 LIST ONLY da1 BLOCK DEVICE
64 --------------------------
66 DEVICE MAJ:MIN SIZE TYPE LABEL MOUNT
68 da1s1 0:80 2.0G freebsd - -
69 da1s1a 0:81 1.0G freebsd-ufs root /
70 da1s1b 0:82 1.0G freebsd-swap swap SWAP
74 DISPLAY PHYSICAL DISKS
75 ----------------------
77 kern.disks: ada0 da0 da1
79 DISPLAY MEMORY BACKED DISKS
80 ---------------------------
88 # GET MAJOR/MINOR NUMBERS
89 __major_minor
() { # 1=DEV
91 MAJ
=$
( stat
-f "%Hr" /dev
/${DEV} )
92 MIN
=$
( stat
-f "%Lr" /dev
/${DEV} )
94 # __major_minor() ENDED
96 # DETECT IF SWAP IS BEING USED
97 __swap_mount
() { # 1=DEV
101 # DETECT SWAP BY RAW DEVICE
102 if swapctl
-l |
grep -q -- ${DEV} 2> /dev
/null
111 # DETECT SWAP BY LABEL
112 while read LABELER GARBAGE PROVIDER
114 if [ "${DEV}" = "${PROVIDER}" ]
116 if swapctl
-l |
grep -q -- ${LABELER} 2> /dev
/null
126 $( echo "${GLABEL}" )
129 # __swap_mount() ENDED
131 # DETECT TYPE WITH fstyp(8) TOOL
134 TYPE
=$
( fstyp
-u /dev
/${DEV} 2> /dev
/null
)
135 [ "${TYPE}" = "" ] && __swap_mount
${DEV}
136 [ "${TYPE}" = "" ] && TYPE
="-"
140 # DETECT MOUNT/LABEL IF POSSIBLE
141 __mount_label
() { # 1=TARGET
146 if [ "${SWAP_FOUND}" = "1" ]
153 # CHECK IF DEVICE EXISTS
154 [ ! -e /dev
/${TARGET} ] && return
156 # TRY CLASSIC MOUNT POINT WITH DEVICE NAME
157 if [ "${MOUNT_FOUND}" != "1" ]
159 MOUNT
=$
( mount |
grep "/dev/${TARGET} " |
awk 'END{print $3}' )
160 if [ "${MOUNT}" = "" ]
168 # GET LABEL/MOUNT FOR UFS/zfs(8)/msdosfs(8) FILESYSTEM
171 LABEL
=$
( tunefs
-p /dev
/${TARGET} 2>&1 |
awk '/volume label/ {print $5}' )
172 if [ "${LABEL}" = "" ]
181 # zfs(8) IS NEVER MOUNTED BY RAW DEVICE NAME
182 # SO NO NEED TO CHECK IF MOUNT_FOUND = 1 HERE
187 LABEL
=$
( file -s /dev
/${DEV} |
tr ',' '\n' |
awk -F '"' '/label:/ {print $2}' )
188 if [ "${LABEL}" = "" ]
192 LABEL
="msdosfs/${LABEL}"
197 if which exfatlabel
1> /dev
/null
2> /dev
/null
199 LABEL
=$
( exfatlabel
/dev
/${DEV} 2> /dev
/null
)
200 if [ "${LABEL}" = "" ]
204 LABEL
="exfat/${LABEL}"
211 # GET LABEL USING glabel(8)
212 if [ "${LABEL_FOUND}" != "1" ]
214 # TRY GLABEL MOUNTPOINT AS msdosfs MOUNT IS NOT POSSIBLE WITHOUT GPT/MBR
215 local GLABEL_GREP
=$
( echo "${GLABEL}" |
grep -v ufsid |
grep "${TARGET}\$" )
216 if [ "${GLABEL_GREP}" = "" ]
220 while read PROVIDER STATUS DEVICE
222 LABEL
=$
( echo "${GLABEL_GREP}" | grep -m 1 "${TARGET}" | awk '{print $1}' )
226 $( echo "${GLABEL_GREP}" )
231 # GET MOUNT USING glabel(8)
232 if [ "${MOUNT_FOUND}" != "1" ]
234 # TRY GLABEL MOUNTPOINT AS msdosfs MOUNT IS NOT POSSIBLE WITHOUT GPT/MBR
235 local GLABEL_GREP=$( echo "${GLABEL}" | grep -v ufsid | grep "${TARGET}\$
" )
236 if [ "${GLABEL_GREP}" != "" ]
238 while read PROVIDER STATUS DEVICE
240 MOUNT=$( mount | grep "${PROVIDER}" | awk 'END{print $3}' )
241 if [ "${MOUNT}" = "" ]
249 $( echo "${GLABEL_GREP}" )
254 # GET MOUNT FROM fuse(8)
255 if [ "${MOUNT_FOUND}" != "1" ]
257 local FUSE_PIDS=$( pgrep mount.exfat ntfs-3g | tr '\n' ',' | sed '$s/.$//' )
258 if [ "${FUSE_PIDS}" != "" ]
260 local FUSE_MOUNTS=$( ps -p "${FUSE_PIDS}" -o command | sed 1d | sort -u )
261 MOUNT=$( echo "${FUSE_MOUNTS}" | grep "/dev/${TARGET} " | awk '{print $3}' )
262 if [ "${MOUNT}" = "" ]
271 # GET LABEL FROM gpart(8)
272 if [ "${LABEL_FOUND}" != "1" ]
274 LABEL=$( gpart show -p -l ${DEV} 2> /dev/null | sed 's|=>||g' | sed 's-\[active\]--g' | grep "${TARGET} " | awk '{print $4}' )
275 if [ "${LABEL}" = "" -o "${LABEL}" = "(null)" ]
284 # __mount_label() ENDED
287 __list_block_devices
() {
288 # FIRST 1000 DEVICES OF EACH CLASS SHOULD DO
289 for I
in ada da mmcsd md
291 ls -1 /dev
/${I}[0-9] 2> /dev
/null
292 ls -1 /dev
/${I}[0-9][0-9] 2> /dev
/null
293 ls -1 /dev
/${I}[0-9][0-9][0-9] 2> /dev
/null
299 # __list_block_devices() ENDED
301 # PRINT DEVICES AND PARTITIONS
302 __print_parts
() { # 1=NAME 2=TYPE 3=SIZE 4=SIZE_FREE
310 # REMOVE BRACKETS FROM SIZE
311 local SIZE_FREE
=$
( echo ${SIZE_FREE} |
tr -d '()' )
312 # FIRST 16 SECTORS ARE ALWAYS EMPTY ON bsdlabel(8) PARTITION SCHEMA
313 [ "${SIZE_FREE}" = "8.0K" ] && return
315 printf "${FORMAT}" "<FREE>" - - ${SIZE_FREE} "-" ${LABEL} ${MOUNT}
318 # NEEDED FOR bsdlabel(8) ON WHOLE DISK WITHOUT PARTITION
319 # WORKAROUND FOR gpart(8) BUG 241004
320 # https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=241004
321 if [ "${TYPE}" = "!0" ]
323 local TYPE=freebsd-ufs
326 # REMOVE BRACKETS FROM SIZE
327 local SIZE=$( echo ${SIZE} | tr -d '()' )
328 [ "${LABEL}" = "" ] && local LABEL="-"
329 [ "${MOUNT}" = "" ] && local MOUNT="-"
330 __major_minor ${NAME}
331 printf "${FORMAT}" ${NAME} ${MAJ} ${MIN} ${SIZE} ${TYPE} ${LABEL} ${MOUNT}
332 if [ -e /dev
/${NAME}.eli
]
334 # GET GELI MOUNT/LABEL/MAJOR/MINOR
335 __major_minor
${NAME}.eli
337 __mount_label
${NAME}.eli
338 printf "${FORMAT}" ${NAME}.eli ${MAJ} ${MIN} ${SIZE} ${TYPE} ${LABEL} ${MOUNT}
344 # __print_parts() ENDED
346 # WHEN GPART OUTPUT EXISTS (partition table / not entire device)
347 __gpart_present() { # 1=DEV
352 # CHECK IF DEVICE EXISTS
353 [ ! -e /dev/${DEV} ] && return
355 # WORKAROUND FOR gpart(1) BUG 240998
356 # https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=240998
357 TYPE_EXFAT_HELPER_DEVICE=$( gpart show -p ${DEV} | head -1 | sed 's-\[active\]--g' | awk '{print $5}' 2> /dev/null )
358 if [ "${TYPE_EXFAT_HELPER_DEVICE}" = "MBR
" ]
360 TYPE_EXFAT_HELPER=$( fstyp -u /dev/${DEV} 2> /dev/null )
361 if [ "${TYPE_EXFAT_HELPER}" = "exfat
" ]
364 SIZE=$( diskinfo -v ${DEV} 2> /dev/null| awk '/mediasize in bytes/ {print $NF}' | tr -d '()' )
365 __print_parts ${DEV} ${TYPE} ${SIZE} -
370 # READ PARTITIONS OF PROVIDER
371 local GPART=$( gpart show -p ${DEV} 2> /dev/null | sed 's-\[active\]--g' | sed 's|=>||g' )
372 # PARSE gpart(8) OUTPUT
374 | while read BEG END NAME TYPE SIZE SIZE_FREE
376 # VISITED ONLY ONCE FOR WHOLE DEVICE
377 if [ ${LEVEL_DEV} = "0" ]
381 FORMAT="${FORMAT_L0}"
382 __print_parts ${NAME} ${TYPE} ${SIZE} ${SIZE_FREE}
385 FORMAT="${FORMAT_L1}"
386 # READ PARTITIONS OF PROVIDER
387 local GPART_PARTS=$( gpart show -p ${NAME} 2> /dev/null | sed 's-\[active\]--g' | sed 's|=>||g' )
388 # PARSE gpart(8) OUTPUT
389 if [ "${GPART_PARTS}" != "" ]
391 # PARTITION IN PARTITION
392 [ ! -e /dev/${NAME} ] && return
394 echo "${GPART_PARTS}" \
395 | while read BEG END NAMEONE TYPE SIZE SIZE_FREE
397 # VISITED ONLY ONCE FOR WHOLE DEVICE
398 if [ ${LEVEL_PAR} = "0" ]
402 FORMAT="${FORMAT_L1}"
405 FORMAT="${FORMAT_L2}"
407 # CHECK IF SWAP IS ENABLED FOR SWAP DEVICES
408 [ "${TYPE}" = "freebsd-swap
" ] && __swap_mount ${NAMEONE}
409 __mount_label ${NAMEONE}
410 __print_parts ${NAMEONE} ${TYPE} ${SIZE} ${SIZE_FREE}
414 [ "${TYPE}" = "freebsd-swap
" ] && __swap_mount ${DEV}
415 __mount_label ${NAME}
416 __print_parts ${NAME} ${TYPE} ${SIZE} ${SIZE_FREE}
421 # __gpart_present() ENDED
423 # WHEN GPART OUTPUT DO NOT EXISTS (no partition table / entire device)
424 __gpart_absent() { # 1=DEV
426 # EXIT IF DEVICE DOES NOT EXISTS
427 [ ! -e /dev/${DEV} ] && return
428 local SIZE=$( diskinfo -v ${DEV} 2> /dev/null | awk '/mediasize in bytes/ {print $NF}' | tr -d '()' )
432 [ "${SIZE}" = "" ] && local SIZE="-"
433 [ "${TYPE}" = "" ] && local TYPE="-"
434 [ "${LABEL}" = "" ] && local LABEL="-"
435 [ "${MOUNT}" = "" ] && local MOUNT="-"
436 __print_parts ${DEV} ${TYPE} ${SIZE} ${SIZE_FREE}
438 # __gpart_absent() ENDED
440 # PARSE ARGUMENTS IF THERE ARE ANY
443 GLABEL=$( glabel status | sed 1d )
444 DISKS=$( __list_block_devices )
451 # SINGLE ARGUMENT MEANS SINGLE DISK OR HELP
453 (h|-h|--h|help|-help|--help)
458 if echo "${DISKS}" | grep -q -- "${1}"
462 echo "NOPE
: disk
'${1}' does not exist
in the system
"
468 # ONLY '0' and '1' ARGUMENTS ARE COVERED
473 # SET OUTPUT FORMAT AND PRINT HEADER
474 FORMAT_L0="%-14s %3s
:%-3s %4s
%-14s %20s
%s
\n"
475 FORMAT_L1=" %-12s %3s
:%-3s %4s
%-14s %20s
%s
\n"
476 FORMAT_L2=" %-10s %3s
:%-3s %4s
%-14s %20s
%s
\n"
477 FORMAT="${FORMAT_L0}"
478 printf "${FORMAT}" DEVICE MAJ MIN SIZE TYPE LABEL MOUNT
484 if gpart show ${DEVICE} 1> /dev/null 2> /dev/null
486 __gpart_present ${DEVICE}
488 __gpart_absent ${DEVICE}