set test "pr16719"

if {![installtest_p]} {
   untested "$test"
   return
}

# This test makes sure that stap doesn't keep unnecessary files open during
# pass-5 execution. For kernel probing, we check for vmlinux. For userspace
# probing, we check for the binary or the corresponding debug file.

# Run stap with probe and once we reach pass-5, check in /proc/$pid/[fd,maps]
# for any opened/mapped file with the given pattern.
proc run_stap { probe pattern } {
   global test subtest

   # Build the stap command
   set script "probe $probe { next }"

   # Spawn stap
   eval spawn stap -e {$script} --vp 00003
   set stap_id $spawn_id
   set failed 1
   expect {
      -timeout 30
      -re {systemtap_module_init\(\)\ returned\ 0} { set failed 0 }
      timeout { kill -INT -[exp_pid] 2 }
      eof { kill -INT -[exp_pid] 2 }
   }

   # Check if stap was able to start
   if {!$failed} {
      pass "$test ($subtest - started stap)"
   } else {
      fail "$test ($subtest - can't start stap)"
      kill -INT -[exp_pid] 2
      catch { close }; catch { wait }
      return
   }

   # Check /proc/$pid/fd
   foreach file [glob -nocomplain /proc/[exp_pid -i $stap_id]/fd/*] {
      # Make sure it's a symlink
      if {![catch {file readlink $file} link]} {
         # Check that it matches the pattern
         if {[string match $pattern $link]} {
            verbose -log "link $link matches pattern $pattern"
            set failed 1
         }
      }
   }

   if {!$failed} {
      pass "$test ($subtest - fd clean)"
   } else {
      fail "$test ($subtest - found target file in fd)"
      kill -INT -[exp_pid] 2
      catch { close -i $stap_id }; catch { wait -i $stap_id }
      return
   }

   # Check /proc/$pid/maps
   if {[catch {open /proc/[exp_pid -i $stap_id]/maps} chan]} {
      # Can't open maps file
      untested "$test ($subtest - can't open maps file)"
      kill -INT -[exp_pid] 2
      catch { close -i $stap_id }; catch { wait -i $stap_id }
      return
   }

   # Read in maps line by line
   while {[gets $chan line] >= 0} {
      set fields [lreplace "$line" 0 -1]
      set file [lindex $fields 5]
      if {[expr [string length $file] && \
             [file exists $file] && \
             [string match $pattern $file]]} {
         verbose -log "file $file matches pattern $pattern"
         set failed 1
      }

   }
   catch {close $chan}

   if {!$failed} {
      pass "$test ($subtest - maps clean)"
   } else {
      fail "$test ($subtest - found target file in maps)"
      kill -INT -[exp_pid] 2
      catch { close -i $stap_id }; catch { wait -i $stap_id }
      return
   }

   pass "$test ($subtest)"
   kill -INT -[exp_pid] 2
   catch { close -i $stap_id }; catch { wait -i $stap_id }
}

# Kernel check
# Bad stap would have open /usr/lib/debug/lib/modules/`uname -r`/vmlinux
set subtest "kernel"
run_stap {vfs.read} {*/vmlinux}

# Kernel tracepoint check
# Bad stap would have open /usr/lib/debug/lib/modules/`uname -r`/vmlinux
# (from getting s.kernel_source_tree in tracepoint_builder::init_dw().)
set subtest "tracepoint"
run_stap {kernel.trace("sched_switch")!,never} {*/vmlinux}

# User check
# Bad stap would have open /bin/ls or /usr/lib/debug/bin/ls.debug
set subtest "user"
if {! [uprobes_p]} { untested "$test ($subtest)"; return }
run_stap {process("/bin/ls").function("main")} {*/bin/ls}
