(Warning: Off-topic). Exceedingly cool. I will install it ASAP. Now I can amaze my friends, and confuse my enemies. Thank you.
 
I don't know if it is supposed to work with fuse mounts

# /usr/local/bin/ntfs-3g -o ro /dev/ada0s2 /mnt/ntfs1
#/usr/local/bin/ntfs-3g -o ro /dev/ada0s4 /mnt/ntfs2

# mount
/dev/fuse on /mnt/ntfs1 (fusefs, local, read-only, synchronous)
/dev/fuse on /mnt/ntfs2 (fusefs, local, read-only, synchronous)

#./lsblk.sh
DEVICE MAJ:MIN SIZE TYPE LABEL MOUNT
ada0s2 0:83 176G ntfs ntfs/ntfsa -
ada0s4 0:8a 188G ntfs ntfs/ntfsb -

It returns no mountpoints

It looks like ntfs-3g does not keep record of the mounted block devices anywhere.
#mount only returns /dev/fuse
The only way to access it was this , I don't know if there is a a better way.
lsof | grep ntfs-3g | grep /dev/ada

Yep, I wrote about it in the UPDATE 2 - Code Reorganization and 75% Rewrite update, its just /dev/fuse after mount :(

... but after messing with it a little I added fuse(8) mounts support to lsblk.sh for NTFS and exFAT filesystems now.

Details are described in the UPDATE 4 – Added fuse(8) Support update:

Its like that now:

6937






[B][USER=30524]ralphbsz[/USER][/B] said:

Love the script.
But even better: How do you get the wild colors on your screen? I tried taking LSD, but it has side effects.

As @yuripv said its just games/rubygem-lolcat package, just pipe any output to lolcat. Thats it ;)
 
All mount points are missing except / and swap, for ntfs the mount options are listed,


#mount | egrep -ve "tmpfs|procfs|fdescfs|linsysfs|devfs"
/dev/ada2p2 on / (ufs, local, journaled soft-updates)
/dev/gpt/fbsd2 on /fbsd2 (ufs, local, journaled soft-updates)
/dev/ufs/dufs on /fdufs (ufs, local, journaled soft-updates)
/dev/fuse on /mnt/ntfs1 (fusefs, local, read-only, synchronous)
/dev/fuse on /mnt/ntfs2 (fusefs, local, read-only, synchronous)
/dev/gpt/sharfat on /mnt/sharfat (msdosfs, local)
/dev/gpt/sharext2 on /mnt/sharext2 (ext2fs, local)
/dev/gpt/6T on /mnt/6T (ufs, local, noatime, noexec, nosuid, nosymfollow, read-only)
/dev/gpt/5T on /mnt/5T (ufs, local, noatime, noexec, nosuid, nosymfollow, read-only)
/dev/gpt/odatswap on /mnt/odatswap (ufs, local, noatime, noexec, nosuid, nosymfollow, read-only)
/dev/fuse on /fbsd2/usr/home/x/.gvfs (fusefs, local, nosuid, synchronous, mounted by x)
/dev/fuse on /fbsd2/usr/home/x/.gvfs (fusefs, local, nosuid, synchronous, mounted by x)

#./lsblk.sh
DEVICE MAJ:MIN SIZE TYPE LABEL MOUNT
ada0 0:128 932G MBR -
<FREE> -:- 1.0G - - -
ada0s3 0:150 378G freebsd ufs/dufs
ada0s2 0:149 176G ntfs ntfs/ntfsa ro
<FREE> -:- 188G - - -
ada0s4 0:151 188G ntfs ntfs/ntfsb ro
<FREE> -:- 728K - - -
ada1 0:129 119G MBR -
<FREE> -:- 60G - - -
ada1s3 0:152 60G linux-data -
<FREE> -:- 344K - - -
ada2 0:130 466G GPT -
<FREE> -:- 3.0K - - -
ada2p1 0:153 236K freebsd-boot gpt/fboot1
<FREE> -:- 1.8M - - -
ada2p2 0:154 80G freebsd-ufs myfbsdx /
<FREE> -:- 256K - - -
ada2p3 0:155 17G freebsd-swap - SWAP
ada2p3.eli 0:135 17G freebsd-swap -
<FREE> -:- 768K - - -
ada2p4 0:156 1.0G efi gpt/efi1
ada2p5 0:157 110G freebsd-ufs gpt/fbsd2
ada2p7 0:158 2.0G linux-data gpt/sharext2
ada2p8 0:159 2.0G ms-basic-data gpt/sharfat
<FREE> -:- 100G - - -
ada2p10 0:160 110G openbsd-data gpt/odatswap
<FREE> -:- 44G - - -
diskinfo: cd0: ioctl(DIOCGMEDIASIZE) failed, probably not a disk.
cd0 0:127 - -
diskinfo: da0: ioctl(DIOCGMEDIASIZE) failed, probably not a disk.
da0 0:136 - -
da1 0:87 4.5T GPT -
da1p4 0:161 4.5T openbsd-data gpt/5T
<FREE> -:- 232K - - -
da2 0:88 5.5T GPT -
da2p1 0:162 5.5T freebsd-ufs gpt/fboot1
<FREE> -:- 3.5K -

==================================
Note, in redhat the columns are :
-NAME
-MAJ:MIN
-RM (removable)
-SIZE
-RO
-TYPE
-MOUNTPOINT
 
Hi, i've written a (ntfs-3g) lsblk , it's a bit shorter than a shell script but depends on ruby,
Code:
#!/usr/local/bin/ruby
glabeltxt=`glabel status | awk '{if (NR!=1) print $1,$3}'`
nam2dev=Hash.new
dev2nam=Hash.new

glabeltxt.each_line do |line|
    asplit=line.split
    n="/dev/"+asplit[0]
    d="/dev/"+asplit[1]
    nam2dev[n]=d
    dev2nam[d]=n
end

mounttxt=`mount | grep -e ^/dev/ `
dev2mount=Hash.new
dev2ro=Hash.new
mounttxt.each_line do |line|
    asplit=line.split
    w=asplit[0]
    if nam2dev[w] then
        w=nam2dev[w]
    end
    dev2mount[w]=asplit[2]
    dev2ro[w]="rw"
    if  line =~ /read-only/i then
        dev2ro[w]="ro"
        end
end

#Vermadensline
ntfsids=`pgrep ntfs-3g`
ntfsids.each_line do |id|
    id=id.chop
    #Vermadensline
    todo="ps -p #{id} -o command | sed 1d | sort -u"
    output=`#{todo}`
    asplit=output.split
    d=asplit[3]
    m=asplit[4]
    puts d+" "+m
    dev2ro[d]="?"
    dev2mount[d]=m
end

gparttxt=`gpart  show -p ` 
gparttxt.each_line do | line|
    aline=line.split(' ')[0..-1].join(' ')
    if line[0]=="="
        puts "+++++++++++++++++"
        aline=aline.split(' ')[1..-1].join(' ')
    end
    if aline.length>1 then
        asplit=aline.split(' ')

        d="/dev/"+asplit[2]
        if asplit[2]=="-" then
            d="Free"
        end
        aname="Name:"+d

        amount="-"
        if dev2mount[d] then
            amount=dev2mount[d]
        end
        amount="Mount:"+amount
        
        atype=asplit[3]
        atype="Type:"+atype
        
        asize=aline[/\(.*\)/]
        asize="Size:"+asize
        
        ro="-"
        if dev2ro[d] then
            ro=dev2ro[d]
        end
        ro="Option:"+ro
        
        anamespace=" "*(19-aname.length)
        asizespace=" "*(13-asize.length)
        rospace   =" "*(11-ro.length)
        atypespace=" "*(20-atype.length)
        output=""
        output=output+aname+anamespace
        output=output+asize+asizespace
        output=output+ro+rospace
        output=output+atype+atypespace
        output=output+amount
        puts output
    end
end
 
It produces this output:
%./test.rb
Code:
+++++++++++++++++
Name:/dev/ada0     Size:(932G)  Option:-   Type:MBR            Mount:-
Name:Free          Size:(1.0G)  Option:-   Type:free           Mount:-
Name:/dev/ada0s3   Size:(378G)  Option:rw  Type:freebsd        Mount:/fdufs
Name:/dev/ada0s2   Size:(176G)  Option:?   Type:ntfs           Mount:/mnt/ntfs1
Name:Free          Size:(188G)  Option:-   Type:free           Mount:-
Name:/dev/ada0s4   Size:(188G)  Option:?   Type:ntfs           Mount:/mnt/ntfs2
Name:Free          Size:(728K)  Option:-   Type:free           Mount:-
+++++++++++++++++
Name:/dev/ada1     Size:(119G)  Option:-   Type:MBR            Mount:-
Name:Free          Size:(60G)   Option:-   Type:free           Mount:-
Name:/dev/ada1s3   Size:(60G)   Option:-   Type:linux-data     Mount:-
Name:Free          Size:(344K)  Option:-   Type:free           Mount:-
+++++++++++++++++
Name:/dev/ada2     Size:(466G)  Option:-   Type:GPT            Mount:-
Name:Free          Size:(3.0K)  Option:-   Type:free           Mount:-
Name:/dev/ada2p1   Size:(236K)  Option:-   Type:freebsd-boot   Mount:-
Name:Free          Size:(1.8M)  Option:-   Type:free           Mount:-
Name:/dev/ada2p2   Size:(80G)   Option:rw  Type:freebsd-ufs    Mount:/
Name:Free          Size:(256K)  Option:-   Type:free           Mount:-
Name:/dev/ada2p3   Size:(17G)   Option:-   Type:freebsd-swap   Mount:-
Name:Free          Size:(768K)  Option:-   Type:free           Mount:-
Name:/dev/ada2p4   Size:(1.0G)  Option:-   Type:efi            Mount:-
Name:/dev/ada2p5   Size:(110G)  Option:rw  Type:freebsd-ufs    Mount:/fbsd2
Name:/dev/ada2p7   Size:(2.0G)  Option:rw  Type:linux-data     Mount:/mnt/sharext2
Name:/dev/ada2p8   Size:(2.0G)  Option:rw  Type:ms-basic-data  Mount:/mnt/sharfat
Name:Free          Size:(100G)  Option:-   Type:free           Mount:-
Name:/dev/ada2p10  Size:(110G)  Option:ro  Type:openbsd-data   Mount:/mnt/odatswap
Name:Free          Size:(44G)   Option:-   Type:free           Mount:-
+++++++++++++++++
Name:/dev/da1      Size:(4.5T)  Option:-   Type:GPT            Mount:-
Name:/dev/da1p4    Size:(4.5T)  Option:ro  Type:openbsd-data   Mount:/mnt/5T
Name:Free          Size:(232K)  Option:-   Type:free           Mount:-
+++++++++++++++++
Name:/dev/da2      Size:(5.5T)  Option:-   Type:GPT            Mount:-
Name:/dev/da2p1    Size:(5.5T)  Option:ro  Type:freebsd-ufs    Mount:/mnt/6T
Name:Free          Size:(3.5K)  Option:-   Type:free           Mount:-
 
It produces this output:
%./test.rb
+++++++++++++++++
Name:/dev/ada0 Size:(932G) Option:- Type:MBR Mount:None
Name:/dev/- Size:(1.0G) Option:- Type:free Mount:None
Name:/dev/ada0s3 Size:(378G) Option:rw Type:freebsd Mount:/fdufs
Name:/dev/ada0s2 Size:(176G) Option:- Type:ntfs Mount:None
Name:/dev/- Size:(188G) Option:- Type:free Mount:None
Name:/dev/ada0s4 Size:(188G) Option:- Type:ntfs Mount:None
Name:/dev/- Size:(728K) Option:- Type:free Mount:None
+++++++++++++++++
Name:/dev/ada1 Size:(119G) Option:- Type:MBR Mount:None
Name:/dev/- Size:(60G) Option:- Type:free Mount:None
Name:/dev/ada1s3 Size:(60G) Option:- Type:linux-data Mount:None
Name:/dev/- Size:(344K) Option:- Type:free Mount:None
+++++++++++++++++
Name:/dev/ada2 Size:(466G) Option:- Type:GPT Mount:None
Name:/dev/- Size:(3.0K) Option:- Type:free Mount:None
Name:/dev/ada2p1 Size:(236K) Option:- Type:freebsd-boot Mount:None
Name:/dev/- Size:(1.8M) Option:- Type:free Mount:None
Name:/dev/ada2p2 Size:(80G) Option:rw Type:freebsd-ufs Mount:/
Name:/dev/- Size:(256K) Option:- Type:free Mount:None
Name:/dev/ada2p3 Size:(17G) Option:- Type:freebsd-swap Mount:None
Name:/dev/- Size:(768K) Option:- Type:free Mount:None
Name:/dev/ada2p4 Size:(1.0G) Option:- Type:efi Mount:None
Name:/dev/ada2p5 Size:(110G) Option:rw Type:freebsd-ufs Mount:/fbsd2
Name:/dev/ada2p7 Size:(2.0G) Option:rw Type:linux-data Mount:/mnt/sharext2
Name:/dev/ada2p8 Size:(2.0G) Option:rw Type:ms-basic-data Mount:/mnt/sharfat
Name:/dev/- Size:(100G) Option:- Type:free Mount:None
Name:/dev/ada2p10 Size:(110G) Option:ro Type:eek:penbsd-data Mount:/mnt/odatswap
Name:/dev/- Size:(44G) Option:- Type:free Mount:None
+++++++++++++++++
Name:/dev/da1 Size:(4.5T) Option:- Type:GPT Mount:None
Name:/dev/da1p4 Size:(4.5T) Option:ro Type:eek:penbsd-data Mount:/mnt/5T
Name:/dev/- Size:(232K) Option:- Type:free Mount:None
+++++++++++++++++
Name:/dev/da2 Size:(5.5T) Option:- Type:GPT Mount:None
Name:/dev/da2p1 Size:(5.5T) Option:ro Type:freebsd-ufs Mount:/mnt/6T
Name:/dev/- Size:(3.5K) Option:- Type:free Mount:None
Please format the output using the code tags, otherwise it looks too unhappy :)
 
All mount points are missing except / and swap, for ntfs the mount options are listed,


#mount | egrep -ve "tmpfs|procfs|fdescfs|linsysfs|devfs"
/dev/ada2p2 on / (ufs, local, journaled soft-updates)
/dev/gpt/fbsd2 on /fbsd2 (ufs, local, journaled soft-updates)
/dev/ufs/dufs on /fdufs (ufs, local, journaled soft-updates)
/dev/fuse on /mnt/ntfs1 (fusefs, local, read-only, synchronous)
/dev/fuse on /mnt/ntfs2 (fusefs, local, read-only, synchronous)
/dev/gpt/sharfat on /mnt/sharfat (msdosfs, local)
/dev/gpt/sharext2 on /mnt/sharext2 (ext2fs, local)
/dev/gpt/6T on /mnt/6T (ufs, local, noatime, noexec, nosuid, nosymfollow, read-only)
/dev/gpt/5T on /mnt/5T (ufs, local, noatime, noexec, nosuid, nosymfollow, read-only)
/dev/gpt/odatswap on /mnt/odatswap (ufs, local, noatime, noexec, nosuid, nosymfollow, read-only)
/dev/fuse on /fbsd2/usr/home/x/.gvfs (fusefs, local, nosuid, synchronous, mounted by x)
/dev/fuse on /fbsd2/usr/home/x/.gvfs (fusefs, local, nosuid, synchronous, mounted by x)

Code:
#./lsblk.sh                                                                                           
DEVICE         MAJ:MIN SIZE TYPE                      LABEL MOUNT
ada0             0:128 932G MBR                           -
  <FREE>         -:-   1.0G -                             - -
  ada0s3         0:150 378G freebsd                ufs/dufs
  ada0s2         0:149 176G ntfs                 ntfs/ntfsa ro
  <FREE>         -:-   188G -                             - -
  ada0s4         0:151 188G ntfs                 ntfs/ntfsb ro
  <FREE>         -:-   728K -                             - -
ada1             0:129 119G MBR                           -
  <FREE>         -:-    60G -                             - -
  ada1s3         0:152  60G linux-data                    -
  <FREE>         -:-   344K -                             - -
ada2             0:130 466G GPT                           -
  <FREE>         -:-   3.0K -                             - -
  ada2p1         0:153 236K freebsd-boot         gpt/fboot1
  <FREE>         -:-   1.8M -                             - -
  ada2p2         0:154  80G freebsd-ufs             myfbsdx /
  <FREE>         -:-   256K -                             - -
  ada2p3         0:155  17G freebsd-swap                  - SWAP
  ada2p3.eli     0:135  17G freebsd-swap                  -
  <FREE>         -:-   768K -                             - -
  ada2p4         0:156 1.0G efi                    gpt/efi1
  ada2p5         0:157 110G freebsd-ufs           gpt/fbsd2
  ada2p7         0:158 2.0G linux-data         gpt/sharext2
  ada2p8         0:159 2.0G ms-basic-data       gpt/sharfat
  <FREE>         -:-   100G -                             - -
  ada2p10        0:160 110G openbsd-data       gpt/odatswap
  <FREE>         -:-    44G -                             - -
diskinfo: cd0: ioctl(DIOCGMEDIASIZE) failed, probably not a disk.
cd0              0:127    - -                           
diskinfo: da0: ioctl(DIOCGMEDIASIZE) failed, probably not a disk.
da0              0:136    - -                           
da1              0:87  4.5T GPT                           -
  da1p4          0:161 4.5T openbsd-data             gpt/5T
  <FREE>         -:-   232K -                             - -
da2              0:88  5.5T GPT                           -
  da2p1          0:162 5.5T freebsd-ufs          gpt/fboot1
  <FREE>         -:-   3.5K -
==================================
Note, in redhat the columns are :
-NAME
-MAJ:MIN
-RM (removable)
-SIZE
-RO
-TYPE
-MOUNTPOINT

Thank You, please use [ code ] and [ / code ] tags next time :)
 
# mount | egrep -ve "tmpfs|procfs|fdescfs|linsysfs|devfs"

You can achieve the same with single mount command like that:
# mount -t notmpfs,procfs,fdescfs,linsysfs,devfs

The 'no' is only on the first place, like NOfsone,fstwo,fsthree and so on.
 
Just added 𝗨𝗣𝗗𝗔𝗧𝗘 𝟱 - 𝗔𝗻𝗼𝘁𝗵𝗲𝗿 𝟲𝟵% 𝗥𝗲𝘄𝗿𝗶𝘁𝗲 to the 𝗟𝗶𝘀𝘁 𝗕𝗹𝗼𝗰𝗸 𝗗𝗲𝘃𝗶𝗰𝗲𝘀 𝗼𝗻 𝗙𝗿𝗲𝗲𝗕𝗦𝗗 𝗹𝘀𝗯𝗹𝗸(𝟴) 𝗦𝘁𝘆𝗹𝗲 article.

The 𝚕𝚜𝚋𝚕𝚔(𝟾) is now 10% faster and 15% smaller with more features like exFAT labels.

Details are available on the blog of course:
https://vermaden.wordpress.com/2019/09/27/list-block-devices-on-freebsd-lsblk8-style/

Latest 𝚕𝚜𝚋𝚕𝚔(𝟾) is available at usual place:
https://raw.githubusercontent.com/vermaden/scripts/master/lsblk.sh

Preview:
6949
 
i migrated my lsblk.ruby to a scala program,an ocaml version might follow
Code:
#!/usr/bin/env scala
import scala.sys.process._
import scala.collection.mutable.HashMap
import scala.util.matching.Regex

val glabeltxt=("tcsh -c \"  glabel status | awk '{if (NR!=1) print $1,$3}' \" ").!!
val nam2dev: HashMap[String, String] = HashMap()
val dev2nam: HashMap[String, String] = HashMap()
val glabelarr=glabeltxt.split("\n")
for (line <- glabelarr) {
    val asplit=line.split(" ")
    val n="/dev/"+asplit(0)
    val d="/dev/"+asplit(1)
    nam2dev+=(n->d)
    dev2nam+=(d->n)
}

val mounttxt=("tcsh -c \" mount | grep -e ^/dev/ \" ").!!
val dev2mount: HashMap[String, String] = HashMap()
val dev2ro: HashMap[String, String] = HashMap()
val mountarr=mounttxt.split("\n")
for (line <-mountarr){
    val asplit=line.split(" ")
    var w=asplit(0) 
    if (nam2dev.contains(w)) {w=nam2dev(w)}
    dev2mount(w)=asplit(2)
     dev2ro(w)="rw"
     val pattern = "read-only".r
    if (pattern.findFirstMatchIn(line).isDefined) {dev2ro(w)="ro"}
}

//Vermadensline
val ntfsidsstr=("tcsh -c \" pgrep ntfs-3g \" ").!!
val ntfsidsarr=ntfsidsstr.split("\n")
for (cid <-ntfsidsarr){
    //Vermadensline
    val todo=" \" ps -p "+cid+" -o command | sed 1d | sort -u \" "
    val output=("tcsh -c "+todo).!!
    val asplit=output.split(" ")
    var d=asplit(3)
    var m=asplit(4)
    dev2ro(d)="?"
    dev2mount(d)=m
}


val gparttxt=("tcsh -c \" gpart  show -p \" ").!!
val gpartarr=gparttxt.split("\n")

for (line <-gpartarr){
    var aline=line.trim
    if(line.length>0){
        if (line.charAt(0)=='=')  {
            println("++++++++++++++++++++++++++")
            aline=aline.substring(2,line.length)
        }
        aline=aline.trim
        val asplit=aline.split(" +")
        var d="/dev/"+asplit(2)
        if (asplit(2)=="-") {d="Free"}
        var aname="Name:"+d
        var amount="-"
        if (dev2mount.contains(d)){amount=dev2mount(d)}
        amount="Mount:"+amount
        var atype=asplit(3)
        atype="Type:"+atype
        var ro="-"
        if (dev2ro.contains(d)){ro=dev2ro(d)}
        ro="Option:"+ro
        val reg="""(?<=\()[^)]+(?=\))""".r
        var asize="Size:("+reg.findFirstMatchIn(aline).getOrElse("unknown")+")"
        val anamespace=" "*(19-aname.length)
        val asizespace=" "*(13-asize.length)
        val rospace   =" "*(11-ro.length)
        val atypespace=" "*(20-atype.length)
        var output=""
        output=output+aname+anamespace
        output=output+asize+asizespace
        output=output+ro+rospace
        output=output+atype+atypespace
        output=output+amount
        println(output)
    }
}
 
And here an lsblk.ml in ocaml, to compile : ocamlc -o lsblk str.cma unix.cma lsblk.ml
Code:
let read_process_lines command =
  let lines = ref [] in
  let in_channel = Unix.open_process_in command in
  begin
    try
      while true do
        lines := input_line in_channel :: !lines
      done;
    with End_of_file ->
      ignore (Unix.close_process_in in_channel)
  end;
  List.rev !lines

(* implicit second parameter with case*)
let rec lookupkv ak = function
    | [] -> ""
    | (k,v)::t -> if k=ak then v 
                          else lookupkv ak t;;
let regexpos regex line=
    try Str.search_forward regex line 0
    with Not_found -> -1;;

let spacereg=Str.regexp " +";;

let nam2dev=ref [] ;;
let dev2nam=ref [] ;;
let glabelline line=
        let lst=Str.split spacereg line in
        let n="/dev/" ^(List.hd lst) in
        let d="/dev/" ^(List.hd (List.tl lst)) in
        nam2dev:= (n,d) :: !nam2dev;
        dev2nam:= (d,n) :: !dev2nam;;
let glabeltxt_to_kv lines=
        List.map glabelline lines;;
let glabeltxt = read_process_lines "glabel status | awk '{if (NR!=1) print $1,$3}'";;
glabeltxt_to_kv glabeltxt;;

let dev2mount=ref [] ;;
let dev2ro=ref [] ;;
let mountline line=
        let lst=Str.split spacereg line in
        let w=(List.hd lst) in
        let t=(List.hd (List.tl (List.tl lst))) in
        let v=lookupkv w !nam2dev in
        let w2= if  v<>"" then lookupkv w !nam2dev
                          else w in
        dev2mount:= (w2,t) :: !dev2mount ;
        let roreg=Str.regexp "read-only" in
        let pos=regexpos roreg line in
        if  pos <> -1 then dev2ro:=(w2,"ro") :: !dev2ro
                      else dev2ro:=(w2,"rw") :: !dev2ro ;;
let mounttxt_to_kv lines= List.map mountline lines;;
let mounttxt = read_process_lines "mount | grep -e ^/dev/" ;;
mounttxt_to_kv mounttxt;;

let id_to_command cid="ps -p " ^ cid ^ " -o command | sed 1d | sort -u" ;;(*Vermaden*) 
let ntfsline line=
        let lst=Str.split spacereg line in
        let id=List.hd lst in
        let command= id_to_command id in
        let pstxt=read_process_lines command in
        let lst2=Str.split spacereg (List.hd pstxt) in
        let d=List.hd (List.tl (List.tl (List.tl lst2))) in
        let m=List.hd (List.tl (List.tl (List.tl (List.tl lst2)))) in
        dev2ro:=(d,"?") :: !dev2ro ;
        dev2mount:= (d,m) :: !dev2mount ;;
let ntfstxt_to_kv lines=
        List.map ntfsline lines;;
let ntfstxt = read_process_lines "pgrep ntfs-3g" ;; (*Vermaden*)
ntfstxt_to_kv ntfstxt;;

let eqline x line=
            let len=String.length line in
            if x then String.sub line 2 (len-2)
                 else line;;
let ismin x line=if x then "Free" else line ;;
let mountval x d=if x="" then "-" else lookupkv d !dev2mount;;
let roval x d   =if x="" then "-" else lookupkv d !dev2ro;;
let padme x s =let numspaces=x - (String.length s) in
               let spacesref=ref "" in
               for i=0 to numspaces do
                    spacesref:=" "^ (!spacesref)
               done;
               let sum=s^ (!spacesref) in
               sum ;;
let gpartline line=
        if (String.length line)>0 then
            let c=line.[0] in
            let qline=eqline (c='=') line in
            let asplit=Str.split spacereg qline in
            let el2=List.hd (List.tl (List.tl asplit)) in
            let el3=List.hd (List.tl (List.tl (List.tl asplit))) in
            let d="/dev/"^el2 in
            let aname= "Name:" ^(ismin (el2 = "-") d) in
            let amount="Mount:"^(mountval (lookupkv d !dev2mount) d) in
            let atype="Type:"^el3 in
            let ro="Option:"^(roval (lookupkv d !dev2ro) d) in
            let openreg=Str.regexp "(" in
            let closereg=Str.regexp ")" in
            let openpos=regexpos openreg qline in
            let closepos=regexpos closereg qline in
            if openpos<> -1 then
                if closepos <> -1 then
                    let asize=String.sub qline openpos (closepos-openpos+1) in
                    let output=(padme 19 aname)^(padme 13 asize)
                              ^(padme 11 ro)^(padme 20 atype)^amount^"\n" in
                    print_string output;;
let gparttxt_to_kv lines=
        List.map gpartline lines;;
let gparttxt = read_process_lines "gpart  show -p" ;;
gparttxt_to_kv gparttxt;;
 
And here an lsblk.ml in ocaml, to compile : ocamlc -o lsblk str.cma unix.cma lsblk.ml
Code:
let read_process_lines command =
  let lines = ref [] in
  let in_channel = Unix.open_process_in command in
  begin
    try
      while true do
        lines := input_line in_channel :: !lines
      done;
    with End_of_file ->
      ignore (Unix.close_process_in in_channel)
  end;
  List.rev !lines

(* implicit second parameter with case*)
let rec lookupkv ak = function
    | [] -> ""
    | (k,v)::t -> if k=ak then v
                          else lookupkv ak t;;
let regexpos regex line=
    try Str.search_forward regex line 0
    with Not_found -> -1;;

let spacereg=Str.regexp " +";;

let nam2dev=ref [] ;;
let dev2nam=ref [] ;;
let glabelline line=
        let lst=Str.split spacereg line in
        let n="/dev/" ^(List.hd lst) in
        let d="/dev/" ^(List.hd (List.tl lst)) in
        nam2dev:= (n,d) :: !nam2dev;
        dev2nam:= (d,n) :: !dev2nam;;
let glabeltxt_to_kv lines=
        List.map glabelline lines;;
let glabeltxt = read_process_lines "glabel status | awk '{if (NR!=1) print $1,$3}'";;
glabeltxt_to_kv glabeltxt;;

let dev2mount=ref [] ;;
let dev2ro=ref [] ;;
let mountline line=
        let lst=Str.split spacereg line in
        let w=(List.hd lst) in
        let t=(List.hd (List.tl (List.tl lst))) in
        let v=lookupkv w !nam2dev in
        let w2= if  v<>"" then lookupkv w !nam2dev
                          else w in
        dev2mount:= (w2,t) :: !dev2mount ;
        let roreg=Str.regexp "read-only" in
        let pos=regexpos roreg line in
        if  pos <> -1 then dev2ro:=(w2,"ro") :: !dev2ro
                      else dev2ro:=(w2,"rw") :: !dev2ro ;;
let mounttxt_to_kv lines= List.map mountline lines;;
let mounttxt = read_process_lines "mount | grep -e ^/dev/" ;;
mounttxt_to_kv mounttxt;;

let id_to_command cid="ps -p " ^ cid ^ " -o command | sed 1d | sort -u" ;;(*Vermaden*)
let ntfsline line=
        let lst=Str.split spacereg line in
        let id=List.hd lst in
        let command= id_to_command id in
        let pstxt=read_process_lines command in
        let lst2=Str.split spacereg (List.hd pstxt) in
        let d=List.hd (List.tl (List.tl (List.tl lst2))) in
        let m=List.hd (List.tl (List.tl (List.tl (List.tl lst2)))) in
        dev2ro:=(d,"?") :: !dev2ro ;
        dev2mount:= (d,m) :: !dev2mount ;;
let ntfstxt_to_kv lines=
        List.map ntfsline lines;;
let ntfstxt = read_process_lines "pgrep ntfs-3g" ;; (*Vermaden*)
ntfstxt_to_kv ntfstxt;;

let eqline x line=
            let len=String.length line in
            if x then String.sub line 2 (len-2)
                 else line;;
let ismin x line=if x then "Free" else line ;;
let mountval x d=if x="" then "-" else lookupkv d !dev2mount;;
let roval x d   =if x="" then "-" else lookupkv d !dev2ro;;
let padme x s =let numspaces=x - (String.length s) in
               let spacesref=ref "" in
               for i=0 to numspaces do
                    spacesref:=" "^ (!spacesref)
               done;
               let sum=s^ (!spacesref) in
               sum ;;
let gpartline line=
        if (String.length line)>0 then
            let c=line.[0] in
            let qline=eqline (c='=') line in
            let asplit=Str.split spacereg qline in
            let el2=List.hd (List.tl (List.tl asplit)) in
            let el3=List.hd (List.tl (List.tl (List.tl asplit))) in
            let d="/dev/"^el2 in
            let aname= "Name:" ^(ismin (el2 = "-") d) in
            let amount="Mount:"^(mountval (lookupkv d !dev2mount) d) in
            let atype="Type:"^el3 in
            let ro="Option:"^(roval (lookupkv d !dev2ro) d) in
            let openreg=Str.regexp "(" in
            let closereg=Str.regexp ")" in
            let openpos=regexpos openreg qline in
            let closepos=regexpos closereg qline in
            if openpos<> -1 then
                if closepos <> -1 then
                    let asize=String.sub qline openpos (closepos-openpos+1) in
                    let output=(padme 19 aname)^(padme 13 asize)
                              ^(padme 11 ro)^(padme 20 atype)^amount^"\n" in
                    print_string output;;
let gparttxt_to_kv lines=
        List.map gpartline lines;;
let gparttxt = read_process_lines "gpart  show -p" ;;
gparttxt_to_kv gparttxt;;

The output does not look super fancy in here :) :

Code:
Name:/dev/ada0      (112G)        Option:-    Type:GPT             Mount:-
Name:/dev/ada0p1    (512K)        Option:-    Type:freebsd-boot    Mount:-
Name:Free           (492K)        Option:-    Type:free            Mount:-
Name:/dev/ada0p2    (4.0G)        Option:-    Type:freebsd-swap    Mount:-
Name:/dev/ada0p3    (108G)        Option:-    Type:freebsd-zfs     Mount:-
Name:Free           (1.0M)        Option:-    Type:free            Mount:-
 
Good one, but ocaml was interesting. This simple problem is ideal to compare programming languages. Too bad, next version will not be ada but nim or crystal.
ada looks at first like typesafe pascal
 
With the danger of becoming boring here a nim-language version, to compile to binary executable : nim -c lsblk.nim
Code:
import osproc,strutils,tables,re

var nam2dev,dev2nam = initTable[string, string]()
let (glabeltxt, _) = execCmdEx("glabel status | awk '{if (NR!=1) print $1,$3}'")
for line in glabeltxt.strip().split("\n"):
    let asplit=line.strip().split(" ")
    let n="/dev/"&asplit[0]
    let d="/dev/"&asplit[1]
    nam2dev[n]=d
    dev2nam[d]=n

let (mounttxt, _) = execCmdEx("mount | grep -e ^/dev/ ")
var dev2mount,dev2ro = initTable[string, string]()
for line in mounttxt.strip().split("\n"):
    let asplit=line.strip().split(" ")
    var w=asplit[0]
    if nam2dev.hasKey(w):
            w=nam2dev[w]
    dev2mount[w]=asplit[2]
    dev2ro[w]="rw"
    let pattern=re(r"read-only")
    if line.contains(pattern):
        dev2ro[w]="ro"

echo ""   
#Vermadensline
let (ntfsidsstr, _) = execCmdEx("pgrep ntfs-3g")
let ntfsidstab=ntfsidsstr.strip().split("\n")
for cid in ntfsidstab:
    #Vermadensline
    let todo="ps -p " & cid & " -o command | sed 1d | sort -u"
    let (output, _) = execCmdEx(todo)
    let asplit=output.strip().split(" ")
    let d=asplit[3]
    let m=asplit[4]
    dev2ro[d]="?"
    dev2mount[d]=m

let (gparttxt, _) = execCmdEx("gpart show -p")
let gparttab=gparttxt.strip().split("\n")
for line in gparttab:
    var aline=line.strip()
    if aline.len()>0:
        if aline[0]=='=':
            echo "++++++++++++++++++++++++++"
            aline=aline[2..aline.len()-1]
        let asplit=aline.strip().splitWhitespace()
        var d="/dev/"&asplit[2]
        if asplit[2]=="-":
            d="Free"
        var aname="Name:"&d
        var amount="-"
        if dev2mount.haskey(d):
            amount=dev2mount[d]
        amount="Mount:"&amount
        var atype=asplit[3]
        atype="Type:"&atype
        var ro="-"
        if dev2ro.hasKey(d):
            ro=dev2ro[d]
        ro="Option:"&ro
        let rb=re(r"\(")
        let re=re(r"\)")
        let posb=aline.find(rb)
        let pose=aline.find(re)
        var asize=aline[posb..pose]
        aname=aname&" ".repeat(19-aname.len())
        asize=asize&" ".repeat(13-asize.len())
        ro=ro&" ".repeat(11-ro.len())
        atype=atype&" ".repeat(20-atype.len())
        let output=aname&asize&ro&atype&amount
        echo output

PS: Even though avionics like ada , at first glance this language pushes away, because as far as i understand you need to code all the small things explicitly.
 
Code:
--  USES ADA-UTIL , compiles like samples in ADA-UTIL
--  cfr samples.gpr in ADA-UTIL

with Ada.Containers.Indefinite_Hashed_Maps;
with Ada.Strings.Hash;
with Ada.Strings.Unbounded;  use Ada.Strings.Unbounded;
with Ada.Text_IO;            use Ada.Text_IO;
with Ada.Characters.Latin_1; use Ada.Characters;
with Util.Processes;
with Util.Streams.Pipes;
with Util.Streams.Buffered;
with GNAT.Regpat;
with GNAT.String_Split;      use GNAT.String_Split;
use Ada.Containers;
use GNAT;

procedure lsblk is

   package Pat renames GNAT.Regpat;

   function TUS (myin : String) return Unbounded_String is
   begin return To_Unbounded_String (myin); end TUS;

   function TS (myin : Unbounded_String) return String is
   begin return To_String (myin); end TS;

   procedure Put_Line (myin : Unbounded_String) is
   begin Put_Line (TS (myin)); end Put_Line;

   function Padme (astring : in Unbounded_String; myin : Integer)
     return Unbounded_String is
   begin
      return ("|" & astring & ((myin - Length (astring)) * " "));
   end Padme;

   package SS_Hashed_Maps is new
     Ada.Containers.Indefinite_Hashed_Maps
       (Key_Type        => String,
        Element_Type    => String,
        Hash            => Ada.Strings.Hash,
        Equivalent_Keys => "=");
   use SS_Hashed_Maps;

   procedure addhashkey (amap   : in out SS_Hashed_Maps.Map;
                         akey   : in Unbounded_String;
                         avalue : in Unbounded_String) is
   begin
      --  Looks good
      amap.Include (TS (akey), TS (avalue));
   end addhashkey;

   function runcommand (Command_Unbound : in Unbounded_String)
     return Unbounded_String is
      Command  : constant String := TS (Command_Unbound);
      Pipe    : aliased Util.Streams.Pipes.Pipe_Stream;
      Buffer  : Util.Streams.Buffered.Input_Buffer_Stream;
      Content : Unbounded_String;
   begin
      Pipe.Open (Command, Util.Processes.READ);
      Buffer.Initialize (Pipe'Access, 1024);
      Buffer.Read (Content);
      Pipe.Close;
      if Pipe.Get_Exit_Status /= 0 then
         Put_Line (Command & " exited with status " & Integer'Image (Pipe.Get_Exit_Status));
         return (TUS (""));
      end if;
      return (Content);
   end runcommand;

   function runcommand (Command : in String) return Unbounded_String is
   begin return runcommand (TUS (Command)); end runcommand;

   procedure S_splitcreate (Sliceset : in out Slice_Set;
                            From : in String;
                            Separators : in String) is
   begin
      String_Split.Create (S          => Sliceset,
                           From       => From,
                           Separators => Separators,
                           Mode       => String_Split.Multiple);
   end S_splitcreate;

begin
   declare
      star_string : constant String := TS (65 * "*");
      plus_string : constant String := TS (65 * "+");
      head_string : constant String
        := "|    NAME      | SIZE  | RO  |      TYPE     |    MOUNTPOINT     |";
      Glabel_Output : Unbounded_String;
      Mount_Output : Unbounded_String;
      Pgrep_Output : Unbounded_String;
      Gpart_Output : Unbounded_String;
      nam2dev   : SS_Hashed_Maps.Map;
      dev2nam   : SS_Hashed_Maps.Map;
      dev2mount : SS_Hashed_Maps.Map;
      dev2ro    : SS_Hashed_Maps.Map;
      Lines : String_Split.Slice_Set;
      MYLF : constant String := "" & Latin_1.LF;
      J : String_Split.Slice_Number := 0;
   begin

      --  EXECUTE_GLABEL
      Glabel_Output := runcommand ("glabel status | awk '{if (NR!=1) print $1,$3}'");
      --  GLABELOUTPUT_SPLIT
      S_splitcreate (Sliceset => Lines,
                     From     => TS (Glabel_Output),
                     Separators => MYLF & Latin_1.HT);
      J := String_Split.Slice_Count (Lines) - 1;
      for I in 1 .. J loop
         declare
            Line : constant String := String_Split.Slice (Lines, I);
            Words : String_Split.Slice_Set;
            Devname : Unbounded_String;
            Partname : Unbounded_String;
         begin
            S_splitcreate (Sliceset   => Words,
                           From       => Line,
                           Separators => " " & Latin_1.HT);
            Partname := "/dev/" & TUS (String_Split.Slice (Words, 1));
            Devname := "/dev/" & TUS (String_Split.Slice (Words, 2));
            addhashkey (dev2nam, Devname, Partname);
            addhashkey (nam2dev, Partname, Devname);
         end;
      end loop;

      --  EXECUTE_MOUNT
      Mount_Output := runcommand ("mount | grep -e ^/dev/ ");
      --  MOUNTOUTPUT_SPLIT
      S_splitcreate (Sliceset   => Lines,
                     From       => TS (Mount_Output),
                     Separators => MYLF & Latin_1.HT);
      J := String_Split.Slice_Count (Lines) - 1;
      for I in 1 .. J loop
         declare
            Line   : constant String := String_Split.Slice (Lines, I);
            Words  : String_Split.Slice_Set;
            Device : Unbounded_String;
            Path   : Unbounded_String;
            Compiled_Expression : constant Pat.Pattern_Matcher := Pat.Compile ("read-only");
            Option : Unbounded_String;
         begin
            S_splitcreate (Sliceset   => Words,
                           From       => Line,
                           Separators => " " & Latin_1.HT);
            Device := TUS (String_Split.Slice (Words, 1));
            if nam2dev.Contains (TS (Device)) then
               Device := TUS (nam2dev (TS (Device)));
            end if;
            Path := TUS (String_Split.Slice (Words, 3));
            addhashkey (dev2mount, Device, Path);
            if Pat.Match (Compiled_Expression, Line) then
               Option := TUS ("ro");
            else
               Option := TUS ("rw");
            end if;
            addhashkey (dev2ro, Device, Option);
         end;
      end loop;

      --  EXECUTE_PGREP
      --  Vermadensline
      Pgrep_Output := runcommand ("pgrep ntfs-3g");
      --  PGREPOUTPUT_SPLIT
      S_splitcreate (Sliceset   => Lines,
                     From       => TS (Pgrep_Output),
                     Separators => MYLF & Latin_1.HT);
      J := String_Split.Slice_Count (Lines) - 1;
      for I in 1 .. J loop
         declare
            Line   : constant String := String_Split.Slice (Lines, I);
            Words  : String_Split.Slice_Set;
            Ps_Command : Unbounded_String;
            Ps_Output : Unbounded_String;
            Device : Unbounded_String;
            Mount : Unbounded_String;
            Mylen   : Integer;
         begin
            --  Vermadensline
            Ps_Command := TUS ("ps -p " & Line & " -o command | sed 1d | sort -u");
            Ps_Output := runcommand (Ps_Command);
            S_splitcreate (Sliceset   => Words,
                           From       => TS (Ps_Output),
                           Separators => " " & Latin_1.HT);
            Device := TUS (String_Split.Slice (Words, 4));
            Mount := TUS (String_Split.Slice (Words, 5));
            Mylen := Ada.Strings.Unbounded.Length (Mount);
            Mount := Ada.Strings.Unbounded.Delete (Mount, Mylen, Mylen);
            addhashkey (dev2mount, Device, Mount);
            addhashkey (dev2ro, Device, TUS ("?"));
         end;
      end loop;

      --  EXECUTE_GPART
      Gpart_Output := runcommand
        (TUS ("gpart show -p"));
      --  GPART_SPLIT
      S_splitcreate (Sliceset   => Lines,
                     From       => TS (Gpart_Output),
                     Separators => MYLF & Latin_1.HT);
      J := String_Split.Slice_Count (Lines) - 1;
      Put_Line (head_string);
      for I in 1 .. J loop
         declare
            Line   : constant String := String_Split.Slice (Lines, I);
            ULine  : Unbounded_String;
            Words  : String_Split.Slice_Set;
            Mychar : Character;
            dtemp  : Unbounded_String;
            aname  : Unbounded_String;
            amount : Unbounded_String;
            atype  : Unbounded_String;
            ro     : Unbounded_String;
            asize  : Unbounded_String;
            output : Unbounded_String;
            posb : Integer;
            pose : Integer;
         begin
            Mychar := Ada.Strings.Unbounded.Element (TUS (Line), 1);
            ULine := TUS (Line);
            if Mychar = '=' then
               Put_Line (star_string);
               ULine := Ada.Strings.Unbounded.Delete (ULine, 1, 2);
            end if;
            S_splitcreate (Sliceset   => Words,
                           From       => Line,
                           Separators => " " & Latin_1.HT);
            dtemp := TUS (String_Split.Slice (Words, 4));
            if dtemp = "-" then
               aname := TUS ("-");
            else
               aname := "/dev/" & dtemp;
            end if;
            amount := TUS ("-");
            if dev2mount.Contains (TS (aname)) then
               amount := TUS (dev2mount (TS (aname)));
            end if;
            atype := TUS (String_Split.Slice (Words, 5));
            if dev2ro.Contains (TS (aname)) then
               ro := TUS (dev2ro (TS (aname)));
            else
               ro := TUS ("-");
            end if;
            posb := Pat.Match ("\(", TS (ULine));
            pose := Pat.Match ("\)", TS (ULine));
            asize := TUS (Ada.Strings.Unbounded.Slice (ULine, posb + 1, pose - 1));
            aname :=  Padme (aname, 14);
            asize :=  Padme (asize, 6);
            ro    :=  Padme (ro, 4);
            atype :=  Padme (atype, 15);
            amount := Padme (amount, 20);
            output := aname & asize & ro & atype & amount & "|";
            Put_Line (output);
            if Mychar = '=' then
               Put_Line (plus_string);
            end if;
         end;
      end loop;
   end;
end lsblk;

Output , well in mono font ,
Code:
|    NAME      | SIZE  | RO  |      TYPE     |    MOUNTPOINT      |
*******************************************************************
|/dev/ada0     |(932G) |-    |MBR            |-                   |
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|-             |(1.0G) |-    |free           |-                   |
|/dev/ada0s3   |(378G) |rw   |freebsd        |/fdufs              |
|/dev/ada0s2   |(176G) |?    |ntfs           |/mnt/ntfs1          |
|-             |(188G) |-    |free           |-                   |
|/dev/ada0s4   |(188G) |?    |ntfs           |/mnt/ntfs2          |
|-             |(728K) |-    |free           |-                   |
*******************************************************************
|/dev/ada1     |(119G) |-    |MBR            |-                   |
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|-             |(60G)  |-    |free           |-                   |
|/dev/ada1s3   |(60G)  |-    |linux-data     |-                   |
|-             |(344K) |-    |free           |-                   |
*******************************************************************
|/dev/ada2     |(466G) |-    |GPT            |-                   |
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|-             |(3.0K) |-    |free           |-                   |
|/dev/ada2p1   |(236K) |-    |freebsd-boot   |-                   |
|-             |(1.8M) |-    |free           |-                   |
|/dev/ada2p2   |(80G)  |rw   |freebsd-ufs    |/                   |
|-             |(256K) |-    |free           |-                   |
|/dev/ada2p3   |(17G)  |-    |freebsd-swap   |-                   |
|-             |(768K) |-    |free           |-                   |
|/dev/ada2p4   |(1.0G) |-    |efi            |-                   |
|/dev/ada2p5   |(110G) |rw   |freebsd-ufs    |/fbsd2              |
|/dev/ada2p7   |(2.0G) |rw   |linux-data     |/mnt/sharext2       |
|/dev/ada2p8   |(2.0G) |rw   |ms-basic-data  |/mnt/sharfat        |
|-             |(100G) |-    |free           |-                   |
|/dev/ada2p10  |(110G) |ro   |openbsd-data   |/mnt/odatswap       |
|/dev/ada2p6   |(19G)  |-    |freebsd-zfs    |-                   |
|/dev/ada2p9   |(19G)  |-    |freebsd-zfs    |-                   |
|-             |(5.7G) |-    |free           |-                   |
*******************************************************************
|/dev/da1      |(4.5T) |-    |GPT            |-                   |
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|/dev/da1p4    |(4.5T) |ro   |openbsd-data   |/mnt/5T             |
|-             |(232K) |-    |free           |-                   |
*******************************************************************
|/dev/da2      |(5.5T) |-    |GPT            |-                   |
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|/dev/da2p1    |(5.5T) |ro   |freebsd-ufs    |/mnt/6T             |
|-             |(3.5K) |-    |free           |-                   |
 
Last edited:
Back
Top