Hi Guys,

I'm new (& self-taught) to DTrace and needed to write a program to track a 
specified dir and find out who/when/how etc if it got removed/renamed etc.

As you can see from the below code, I've been caught by 1 or 2 gotchas during 
my testing. This is a serious prog, going into production asap, so any comments 
towards making it better/more robust would be appreciated.

Cheers
Chris
PS Sorry about the layout, can't see an option for code tags

# Desc    : Track dir deletions of specified dir in specified zone.
#           Attempts to handle path issues on cmd and/or dir/dir.
#           Tries to catch any form of removal eg shell cmds:
#           rm, rmdir, unlink, mv and 'internal' code cmds inside Perl, C etc.
#           Note that normally this prog is controlled by
#           dt_dir_removal_mgr.pl, which reads the stdout & stderr,
#           filters false positives etc & logs and emails any alerts.
#           We do not allow the path of the tgt dir to be used,
#           as this may not be specified by the offending user/app...
#           thus we may get some false positives eg a file of the same name.
#           Local zonename is avail from DTrace, but filesystem and inode
#           are not avail from psinfo struct.
#           Not matching on zone because tgt dir can be deleted from global,
#           although the users should not be able to get in there.
usage()
{
    echo "USAGE: dt_dir_removal.sh -d dirname -z zonename
 
            -d dirname      # dirname to track : must NOT inc path
        eg,
            dt_dir_removal.sh -d testdir
        "
    exit 1
}
 
# --- Process Arguments ---
#
 
# Arg supplied ?
if [[ $# -eq 0 ]]
then
    usage
fi
 
# Check switch value & arg value : see usage()
while getopts d: name
do
    case $name in
    d)  dirname=$(basename $OPTARG) ;;
    *)  usage ;;
    esac
done
 
 
#################################
# --- DTrace ---
#
# NB: seem to need the single quotes around the DTrace code ...
# This also means the even the contents of comment blocks CANNOT have single 
quotes
# in them eg don't, won't etc... (sigh...)
/usr/sbin/dtrace -n  '
 
 /* Params from shell input */
 inline string DIRNAME  = "'$dirname'";
 
 #pragma D option quiet
 #pragma D option switchrate=10hz
 
 /*
  * Print header
  */
 dtrace:::BEGIN
 {
    /* print main headers: We cannot line up final arg hdr exactly
     * because the cmd len varies
     */
    printf("%-20s %-12s %5s  %5s  %6s  %6s  %s -> %s\n",
           "TIME", "ZONE", "GID", "UID", "PID", "PPID", "CMD", "TARGET") ;
 }
 
 /*
  *  Check exec event type
  */
 
syscall::unlink:entry
{
    /* Grab the dirname in qn to test later: remove any preceding path */
    /* Experiment seems to indicate unlink will not have this value in the 
return state ;
     * contrast with rmdir below which may not have it in entry state
     */
    tgt = basename(copyinstr(arg0));
}
 
/* 
http://docs.sun.com/app/docs/doc/817-6223/6mlkidlrg?l=en&a=view#indexterm-458 :
 * Avoiding Errors
 * The copyin() and copyinstr() subroutines cannot read from user addresses 
which have not yet
 * been touched so even a valid address may cause an error if the page 
containing that address
 * has not yet been faulted in by being accessed.
 * To resolve this issue, wait for kernel or application to use the data before 
tracing it.
 * For example, you might wait until the system call returns to apply 
copyinstr()
 */
syscall::rmdir:entry, syscall::rename:entry
{
    /* Try saving a ptr to the relevant value for later, otherwise it gives 
invalid addr error
     * in return section below
     */
    self->file = arg0;
}
 
syscall::rmdir:return, syscall::rename:return
{
    /* Grab the dirname in qn to test later: remove any preceding path */
    tgt = basename(copyinstr(self->file));
}
 
/* Not matching on zone because tgt dir can be deleted from global,
 * although the users should not be able to get in there.
 */
syscall::rmdir:return, syscall::rename:return, syscall::unlink:return
/ DIRNAME == tgt / 
{
    /* Print the field values. The TARGET tends not to line up as we
       print the cmd and the target name for completeness. For a shell level 
cmd,
       we will get the target name in the CMD field as well. For an "internal" 
cmd,
       eg rmdir() from within perl, the CMD field does not contain the target 
value.
    */
    printf("%-20Y %-12s %5d  %5d  %6d  %6d  %s -> %s\n",
            walltimestamp, zonename, gid, uid, pid, ppid,
            curpsinfo->pr_psargs, tgt ) ;
 
    /* Clear the self->file ptr to avoid dynamic variable drop errors */
    self->file = 0;
}
 
'
-- 
This message posted from opensolaris.org
_______________________________________________
dtrace-discuss mailing list
dtrace-discuss@opensolaris.org

Reply via email to