Question

I am using dtrace to record all files being deleted.

Is it possible to find out what the symlink target is (if it's a symlink)? I want to output the symlink filename and the target filename for logging in case I need to restore the link later.

One solution I came up with is to use the dtrace "system" function to call my own program that will print out the symlink target: system("myprogram %s") where %s is the full name of the symlink I want to print out the target for.

This works ok (it's a very short C program and does the job) - but is there a way to get the info directly through dtrace, seeing as we are handling the file anyway we should be able to look up the symlink target?

I had a look at the fileinfo_t struct but it doesn't have the symlink target: http://docs.oracle.com/cd/E18752_01/html/817-6223/chp-io-args.html#chp-io-fileinfo

This is my script so far: This is in Solaris 10. (This is probing for fop_remove rather than syscall::unlink and the reason for that is to be able to get the symlink directory in case the user doesn't specify the directory in the call to rm).

    #!/usr/sbin/dtrace -s

    #pragma D option quiet

    fbt::fop_remove:entry
    {
           self->dir = stringof(args[0]->v_path);
           self->file = stringof(args[1]);
    }

    fbt::fop_remove:return
    /self->file != NULL/
    {
           printf("%s/%s\n", self->dir, self->file);
           self->file = 0;
           self->dir = 0;
    }

thanks!

Was it helpful?

Solution

On Solaris VFS level (aka the vnode_t structure), the symlink target is not attached to the node for the symlink itself. It's a filesystem implementation detail.

For UFS filesystems, if the pathname of the link target is shorter than 48 Bytes (what UFS calls a 'fast symlink'), it's recorded inline with the inode_t struct, and you can print the value through DTrace via:

vnode = args[0];
inode = (inode_t*)vnode->v_data;

printf("symlink tgt: %47s\n",
    vnode->v_type != VLNK ||
    vnode->v_op != ufs_vnodeops ||
    inode->i_flags & I_FASTSYMLINK == 0 ?
        "[unresolved]" :
        (char *)inode->i_db);

For other filesystems / in the generic case, you'd have to use a fsinfo::readlink:return (or fop::fop_readlink:return) probe points to get the target - on access, that is, it won't (usually) be retrievable directly from the vnode_t.

OTHER TIPS

I have the following possible solution - on access like you said:

syscall::open:entry /strstr(stringof(copyinstr(arg0)), "mydirectory")!=NULL/ {
    self->file=copyinstr(arg0);
}

syscall::open:return /self->file != "" && strstr(stringof(fds[arg0].fi_pathname),   "mydirectory")!=NULL / {
    printf("%s %s\n", self-> file, fds[arg0].fi_pathname);
    self -> file=0;
}

syscall::open:return {
    self -> file=0;
}

(I'm restricting the tracing to mydirectory here).

So this takes advantage of the fact that on entry, the arg0 is the symlink name, and on return, the file descriptor is available to get the pathname which is the pathname of the actual file. So that would be the target of the symlink. It's not actually critical that the trace is done on deletion, just that the symlink -> target is recorded.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top