zfs_versions.tcl
#!/usr/bin/tclsh
#
# CDDL HEADER START
#
# The contents of this file are subject to the terms of the
# Common Development and Distribution License (the "License").
# You may not use this file except in compliance with the License.
#
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
# or http://www.opensolaris.org/os/licensing.
# See the License for the specific language governing permissions
# and limitations under the License.
#
# When distributing Covered Code, include this CDDL HEADER in each
# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
# If applicable, add the following below this CDDL HEADER, with the
# fields enclosed by brackets "[]" replaced with your own identifying
# information: Portions Copyright [yyyy] [name of copyright owner]
#
# CDDL HEADER END
#
# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
# needs tclsh8.4 to be large file aware so if you are looking for
# versions of large files don’t use this.
#
proc vputs {str verb} {
global options
if {[info exists options(verbose)] && $options(verbose) == 1 } {
puts "$str $verb"
} else {
puts $str
}
}
proc output { buf1 file } {
upvar buf $buf1
global options
if [ info exists options(forX) ] {
vputs "\"[clock format $buf(mtime)]\"\t$file" "[array get buf]"
} else {
vputs "[clock format $buf(mtime)]\t$file" "[array get buf]"
}
}
proc do_file { fs file } {
foreach snap [glob -nocomplain [file join $fs .zfs snapshot * $file] ] {
if {[ catch {file stat $snap buf} err ] } {
puts stderr "$snap $err"
puts stdout "$snap"
continue
}
lappend x [ list $buf(mtime)$buf(ctime) $buf(ino) $snap [array get buf]]
}
if { ! [info exists x]} {
if [ file exists [file join $fs $file]] {
puts [file join $fs $file]
}
return
}
set x [lsort $x]
set lctime 0
set lmtime 0
set lino 0
unset buf
foreach snapl $x {
set snap [lindex $snapl 2]
array set buf [lindex $snapl 3]
if { $lctime == $buf(ctime) && $lmtime == $buf(mtime) && $lino == $buf(ino) } {
unset buf
continue
}
set lctime $buf(ctime)
set lmtime $buf(mtime)
set lino $buf(ino)
output buf $snap
unset buf
}
if {[ catch {file stat [file join $fs $file] buf} x ] } {
return
}
if { $lctime == $buf(ctime) && $lmtime == $buf(mtime) && $lino == $buf(ino) } {
return
}
output buf [file join $fs $file]
}
proc absolute {path} {
set x [split $path]
if { [lindex $x 0] == "/" } {
return $path
} else {
return [file join [pwd] $path]
}
}
proc find_do_zfs {path} {
set path [absolute $path]
while { $path != "/" && ! [file exists $path/.zfs ] } {
set x [file split $path]
set path [file dirname $path]
if [info exists p] {
set p [file join [lindex $x end] $p]
} else {
set p [lindex $x end]
}
}
return [list $path $p]
}
proc doit {file} {
set f [find_do_zfs $file]
do_file [lindex $f 0] [lindex $f 1]
}
set options(verbose) 0
if {[lindex $argv 0] == "-X" } {
set options(forX) 1
set argv [lrange $argv 1 end]
}
foreach arg $argv {
doit $arg
}