1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
|
#!/usr/bin/tclsh
#
# This script scans a directory hierarchy looking for Fossil CGI files -
# the files that are used to launch Fossil as a CGI program. For each
# such file found, in prints the name of the file and also the file
# content, indented, if the --print option is used.
#
# tclsh find-fossil-cgis.tcl [OPTIONS] DIRECTORY
#
# The argument is the directory from which to begin the search.
#
# OPTIONS can be zero or more of the following:
#
# --has REGEXP Only show the CGI if the body matches REGEXP.
# May be repeated multiple times, in which case
# all must match.
#
# --hasnot REGEXP Only show the CGI if it does NOT match the
# REGEXP.
#
# --print Show the content of the CGI, indented by
# three spaces
#
# --symlink Process DIRECTORY arguments that are symlinks.
# Normally symlinks are silently ignored.
#
# -v Show progress information for debugging
#
# EXAMPLE USE CASES:
#
# Find all CGIs that do not have the "errorlog:" property set
#
# find-fossil-cgis.tcl *.website --has '\nrepository:' \
# --hasnot '\nerrorlog:'
#
# Add the errorlog: property to any CGI that does not have it:
#
# find-fossil-cgis.tcl *.website --has '\nrepository:' \
# --hasnot '\nerrorlog:' | while read x
# do
# echo 'errorlog: /logs/errors.txt' >>$x
# done
#
# Find and print all CGIs that do redirects
#
# find-fossil-cgis.tcl *.website --has '\nredirect:' --print
#
# Find the CGIs in directory $dir. Invoke recursively to
# scan subdirectories.
#
proc find_in_one_dir {dir} {
global HAS HASNOT PRINT V
if {$V>0} {
puts "# $dir"
}
foreach obj [lsort [glob -nocomplain -directory $dir *]] {
if {[file isdir $obj]} {
find_in_one_dir $obj
continue
}
if {![file isfile $obj]} continue
if {[file size $obj]>5000} continue
if {![file exec $obj]} continue
if {![file readable $obj]} continue
set fd [open $obj rb]
set txt [read $fd]
close $fd
if {![string match #!* $txt]} continue
if {![regexp {fossil} $txt]} continue
if {![regexp {\nrepository: } $txt] &&
![regexp {\ndirectory: } $txt] &&
![regexp {\nredirect: } $txt]} continue
set ok 1
foreach re $HAS {
if {![regexp $re $txt]} {set ok 0; break;}
}
if {!$ok} continue
foreach re $HASNOT {
if {[regexp $re $txt]} {set ok 0; break;}
}
if {!$ok} continue
#
# At this point assume we have found a CGI file.
#
puts $obj
if {$PRINT} {
regsub -all {\n} [string trim $txt] "\n " out
puts " $out"
}
}
}
set HAS [list]
set HASNOT [list]
set PRINT 0
set SYMLINK 0
set V 0
set N [llength $argv]
set DIRLIST [list]
# First pass: Gather all the command-line arguments but do no
# processing.
#
for {set i 0} {$i<$N} {incr i} {
set dir [lindex $argv $i]
if {($dir eq "-has" || $dir eq "--has") && $i<[expr {$N-1}]} {
incr i
lappend HAS [lindex $argv $i]
continue
}
if {($dir eq "-hasnot" || $dir eq "--hasnot") && $i<[expr {$N-1}]} {
incr i
lappend HASNOT [lindex $argv $i]
continue
}
if {$dir eq "-print" || $dir eq "--print"} {
set PRINT 1
continue
}
if {$dir eq "-symlink" || $dir eq "--symlink"} {
set SYMLINK 1
continue
}
if {$dir eq "-v"} {
set V 1
continue
}
if {[file type $dir]=="directory"} {
lappend DIRLIST $dir
}
}
# Second pass: Process the non-option arguments.
#
foreach dir $DIRLIST {
set type [file type $dir]
if {$type eq "directory" || ($SYMLINK && $type eq "link")} {
find_in_one_dir $dir
}
}
|