[feat] posix scripts, vim, mutt, gpg, font
[dotfiles_afify.git] / .scripts / lsblk.sh
blob1e44382c3305455deca3ac3647714751698a6cd0
1 #!/usr/bin/env bash
2 #! /bin/sh
4 # Copyright (c) 2016-2019 Slawomir Wojciech Wojtczak (vermaden)
5 # All rights reserved.
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
40 __usage() {
41 local NAME="${0##*/}"
42 cat << __EOF
43 usage:
45 BASIC USAGE INFORMATION
46 =======================
47 # ${NAME} [DISK]
49 example(s):
51 LIST ALL BLOCK DEVICES IN SYSTEM
52 --------------------------------
53 # ${NAME}
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 -
58 <FREE> -:- 492K - - -
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 --------------------------
65 # ${NAME} da1
66 DEVICE MAJ:MIN SIZE TYPE LABEL MOUNT
67 da1 0:80 2.0G MBR - -
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
72 hint(s):
74 DISPLAY PHYSICAL DISKS
75 ----------------------
76 # sysctl kern.disks
77 kern.disks: ada0 da0 da1
79 DISPLAY MEMORY BACKED DISKS
80 ---------------------------
81 # mdconfig -l
83 __EOF
84 exit 1
86 # __usage() ENDED
88 # GET MAJOR/MINOR NUMBERS
89 __major_minor() { # 1=DEV
90 local DEV=${1}
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
98 local DEV="${1}"
99 SWAP_FOUND=0
101 # DETECT SWAP BY RAW DEVICE
102 if swapctl -l | grep -q -- ${DEV} 2> /dev/null
103 then
104 TYPE=freebsd-swap
105 MOUNT=SWAP
106 LABEL="-"
107 SWAP_FOUND=1
108 return
111 # DETECT SWAP BY LABEL
112 while read LABELER GARBAGE PROVIDER
114 if [ "${DEV}" = "${PROVIDER}" ]
115 then
116 if swapctl -l | grep -q -- ${LABELER} 2> /dev/null
117 then
118 TYPE=freebsd-swap
119 LABEL=${LABELER}
120 MOUNT=SWAP
121 SWAP_FOUND=1
122 break
125 done << __EOF
126 $( echo "${GLABEL}" )
127 __EOF
129 # __swap_mount() ENDED
131 # DETECT TYPE WITH fstyp(8) TOOL
132 __type() { # 1=DEV
133 local DEV=${1}
134 TYPE=$( fstyp -u /dev/${DEV} 2> /dev/null )
135 [ "${TYPE}" = "" ] && __swap_mount ${DEV}
136 [ "${TYPE}" = "" ] && TYPE="-"
138 # __type() ENDED
140 # DETECT MOUNT/LABEL IF POSSIBLE
141 __mount_label() { # 1=TARGET
142 local TARGET="${1}"
143 local MOUNT_FOUND=0
144 local LABEL_FOUND=0
145 LABEL="-"
146 if [ "${SWAP_FOUND}" = "1" ]
147 then
148 local MOUNT_FOUND=1
149 else
150 MOUNT="-"
153 # CHECK IF DEVICE EXISTS
154 [ ! -e /dev/${TARGET} ] && return
156 # TRY CLASSIC MOUNT POINT WITH DEVICE NAME
157 if [ "${MOUNT_FOUND}" != "1" ]
158 then
159 MOUNT=$( mount | grep "/dev/${TARGET} " | awk 'END{print $3}' )
160 if [ "${MOUNT}" = "" ]
161 then
162 MOUNT="-"
163 else
164 local MOUNT_FOUND=1
168 # GET LABEL/MOUNT FOR UFS/zfs(8)/msdosfs(8) FILESYSTEM
169 case ${TYPE} in
170 (freebsd-ufs)
171 LABEL=$( tunefs -p /dev/${TARGET} 2>&1 | awk '/volume label/ {print $5}' )
172 if [ "${LABEL}" = "" ]
173 then
174 LABEL="-"
175 else
176 LABEL="ufs/${LABEL}"
177 local LABEL_FOUND=1
180 (freebsd-zfs)
181 # zfs(8) IS NEVER MOUNTED BY RAW DEVICE NAME
182 # SO NO NEED TO CHECK IF MOUNT_FOUND = 1 HERE
183 MOUNT="<ZFS>"
184 local MOUNT_FOUND=1
186 (msdosfs)
187 LABEL=$( file -s /dev/${DEV} | tr ',' '\n' | awk -F '"' '/label:/ {print $2}' )
188 if [ "${LABEL}" = "" ]
189 then
190 LABEL="-"
191 else
192 LABEL="msdosfs/${LABEL}"
193 local LABEL_FOUND=1
196 (exfat)
197 if which exfatlabel 1> /dev/null 2> /dev/null
198 then
199 LABEL=$( exfatlabel /dev/${DEV} 2> /dev/null )
200 if [ "${LABEL}" = "" ]
201 then
202 LABEL="-"
203 else
204 LABEL="exfat/${LABEL}"
205 local LABEL_FOUND=1
209 esac
211 # GET LABEL USING glabel(8)
212 if [ "${LABEL_FOUND}" != "1" ]
213 then
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}" = "" ]
217 then
218 LABEL="-"
219 else
220 while read PROVIDER STATUS DEVICE
222 LABEL=$( echo "${GLABEL_GREP}" | grep -m 1 "${TARGET}" | awk '{print $1}' )
223 local LABEL_FOUND=1
224 break
225 done << ______EOF
226 $( echo "${GLABEL_GREP}" )
227 ______EOF
231 # GET MOUNT USING glabel(8)
232 if [ "${MOUNT_FOUND}" != "1" ]
233 then
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}" != "" ]
237 then
238 while read PROVIDER STATUS DEVICE
240 MOUNT=$( mount | grep "${PROVIDER}" | awk 'END{print $3}' )
241 if [ "${MOUNT}" = "" ]
242 then
243 MOUNT="-"
244 else
245 local MOUNT_FOUND=1
247 break
248 done << ______EOF
249 $( echo "${GLABEL_GREP}" )
250 ______EOF
254 # GET MOUNT FROM fuse(8)
255 if [ "${MOUNT_FOUND}" != "1" ]
256 then
257 local FUSE_PIDS=$( pgrep mount.exfat ntfs-3g | tr '\n' ',' | sed '$s/.$//' )
258 if [ "${FUSE_PIDS}" != "" ]
259 then
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}" = "" ]
263 then
264 MOUNT="-"
265 else
266 local MOUNT_FOUND=1
271 # GET LABEL FROM gpart(8)
272 if [ "${LABEL_FOUND}" != "1" ]
273 then
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)" ]
276 then
277 LABEL="-"
278 else
279 LABEL="gpt/${LABEL}"
282 SWAP_FOUND=0
284 # __mount_label() ENDED
286 # LIST BLOCK DEVICES
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
294 done \
295 | sed 's|/dev/||g' \
296 | sort -u \
297 | sed '/^s*$/d'
299 # __list_block_devices() ENDED
301 # PRINT DEVICES AND PARTITIONS
302 __print_parts() { # 1=NAME 2=TYPE 3=SIZE 4=SIZE_FREE
303 local NAME=${1}
304 local TYPE=${2}
305 local SIZE=${3}
306 local SIZE_FREE=${4}
308 case ${TYPE} in
309 (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
314 # OUTPUT
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" ]
322 then
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 ]
333 then
334 # GET GELI MOUNT/LABEL/MAJOR/MINOR
335 __major_minor ${NAME}.eli
336 __type ${NAME}.eli
337 __mount_label ${NAME}.eli
338 printf "${FORMAT}" ${NAME}.eli ${MAJ} ${MIN} ${SIZE} ${TYPE} ${LABEL} ${MOUNT}
339 MOUNT="-"
342 esac
344 # __print_parts() ENDED
346 # WHEN GPART OUTPUT EXISTS (partition table / not entire device)
347 __gpart_present() { # 1=DEV
348 local DEV=${1}
349 local TYPE="-"
350 local SIZE="-"
351 local SIZE_FREE="-"
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" ]
359 then
360 TYPE_EXFAT_HELPER=$( fstyp -u /dev/${DEV} 2> /dev/null )
361 if [ "${TYPE_EXFAT_HELPER}" = "exfat" ]
362 then
363 TYPE=exfat
364 SIZE=$( diskinfo -v ${DEV} 2> /dev/null| awk '/mediasize in bytes/ {print $NF}' | tr -d '()' )
365 __print_parts ${DEV} ${TYPE} ${SIZE} -
366 continue
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
373 echo "${GPART}" \
374 | while read BEG END NAME TYPE SIZE SIZE_FREE
376 # VISITED ONLY ONCE FOR WHOLE DEVICE
377 if [ ${LEVEL_DEV} = "0" ]
378 then
379 # WHOLE DEVICE
380 LEVEL_DEV=1
381 FORMAT="${FORMAT_L0}"
382 __print_parts ${NAME} ${TYPE} ${SIZE} ${SIZE_FREE}
383 else
384 # PARTITION
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}" != "" ]
390 then
391 # PARTITION IN PARTITION
392 [ ! -e /dev/${NAME} ] && return
393 # PARSE DEVICE
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" ]
399 then
400 # WHOLE DEVICE
401 LEVEL_PAR=1
402 FORMAT="${FORMAT_L1}"
403 else
404 # PARTITION
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}
411 done
412 else
413 # FILESYSTEM
414 [ "${TYPE}" = "freebsd-swap" ] && __swap_mount ${DEV}
415 __mount_label ${NAME}
416 __print_parts ${NAME} ${TYPE} ${SIZE} ${SIZE_FREE}
419 done
421 # __gpart_present() ENDED
423 # WHEN GPART OUTPUT DO NOT EXISTS (no partition table / entire device)
424 __gpart_absent() { # 1=DEV
425 local DEV=${1}
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 '()' )
429 local SIZE_FREE="-"
430 __type ${DEV}
431 __mount_label ${DEV}
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
441 LEVEL_DEV=0
442 LEVEL_PAR=0
443 GLABEL=$( glabel status | sed 1d )
444 DISKS=$( __list_block_devices )
445 case ${#} in
447 # LIST ALL DISKS
451 # SINGLE ARGUMENT MEANS SINGLE DISK OR HELP
452 case ${1} in
453 (h|-h|--h|help|-help|--help)
454 __usage
456 esac
457 # SINGLE DISK CHECK
458 if echo "${DISKS}" | grep -q -- "${1}"
459 then
460 DISKS="${1}"
461 else
462 echo "NOPE: disk '${1}' does not exist in the system"
463 echo
464 __usage
468 # ONLY '0' and '1' ARGUMENTS ARE COVERED
469 __usage
471 esac
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
480 # DO THE JOB
481 echo "${DISKS}" \
482 | while read DEVICE
484 if gpart show ${DEVICE} 1> /dev/null 2> /dev/null
485 then
486 __gpart_present ${DEVICE}
487 else
488 __gpart_absent ${DEVICE}
490 done