File: //usr/share/sysdig/chisels/spy_file.lua
--[[
Copyright (C) 2013-2018 Draios Inc dba Sysdig.
This file is part of sysdig.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
--]]
-- Chisel description
description = "This chisel intercepts all reads and writes to all files. Instead of all files, you can limit interception to one file."
short_description = "Echo any read/write made by any process to all files. Optionally, you can provide the name of one file to only intercept reads/writes to that file.";
category = "I/O";
-- Argument list
args =
{
{
name = "read_or_write",
description = "Specify 'R' to capture only read events; 'W' to capture only write events; 'RW' to capture read and write events. By default both read and write events are captured.",
argtype = "string",
optional = true
},
{
name = "spy_on_file_name",
description = "The name of the file which the chisel should spy on for all read and write activity.",
argtype = "string",
optional = true
}
}
-- Imports and globals
require "common"
local spy_file_name = nil
local read_or_write = nil
local verbose = false
-- Argument notification callback
function on_set_arg(name, val)
if name == "read_or_write" then
read_or_write = val
return true
elseif name == "spy_on_file_name" then
spy_file_name = val
return true
end
return false
end
-- Initialization callback
function on_init()
local filter
-- Request the fields that we need
fbuf = chisel.request_field("evt.buffer")
fdata = chisel.request_field("evt.arg.data")
ffdname = chisel.request_field("fd.name")
fisw = chisel.request_field("evt.is_io_write")
fpid = chisel.request_field("proc.pid")
fpname = chisel.request_field("proc.name")
fres = chisel.request_field("evt.rawarg.res")
ftid = chisel.request_field("thread.tid")
fts = chisel.request_field("evt.time")
-- increase the snaplen so we capture more of the conversation
sysdig.set_snaplen(2000)
-- set the output format to ascii
sysdig.set_output_format("ascii")
-- set the filter
if spy_file_name ~= nil and spy_file_name ~= "" then
filter = string.format("(fd.name=%s) and ", spy_file_name)
else
-- watching terminals risks looping in a live capture
filter = "(not fd.name contains /dev/pt and not fd.name contains /dev/tty) and "
end
if read_or_write == "R" or read_or_write == "r" then
filter = string.format("%s%s", filter, "evt.is_io_read=true and ")
elseif read_or_write == "W" or read_or_write == "w" then
filter = string.format("%s%s", filter, "evt.is_io_write=true and ")
else
filter = string.format("%s%s", filter, "evt.is_io=true and ")
end
filter = string.format("%s%s", filter, "fd.type=file and evt.dir=< and evt.failed=false")
if verbose then
print("filter=" .. filter)
end
chisel.set_filter(filter)
return true
end
-- Event parsing callback
function on_event()
-- Extract the event details
local data = evt.field(fdata)
local fdname = evt.field(ffdname)
local is_write = evt.field(fisw)
local pid = evt.field(fpid)
local pname = evt.field(fpname)
local res = evt.field(fres)
local ts = evt.field(fts)
local read_write
-- Render the message to screen
if is_write == true then
read_write = "W"
else
read_write = "R"
end
print(string.format("%s %s(%s) %s %s %s %s", ts, pname, pid, read_write, format_bytes(res), fdname, data))
return true
end