This post is obsolete

This blog post is quite old, and a lot has changed since then. Meanwhile, I have changed employer, blogging platform, software stack, infrastructure, interests, and more.
You will probably find more recent and relevant information about the topics discussed here elsewhere.
Still, this content is provided here for historical reasons, but please don’t expect it to be current or authoritative at this point.
Thanks for stopping by!


How to Automatically Update Your Home Media Server Library With DTrace

newmusicsmf.jpg

Before we continue with our Home Server Scripting Series, let’s throw in a simple but useful DTrace hack.

One of the most typical uses for a home server is to serve music or videos to home entertainment equipment. In my case, I’m using the Firefly Media Server (no link, fireflymediaserver.org no longer exists) to serve music to my Roku Soundbridge and Mediatomb (no link, page no longer exists) for videos.

The Media Server Update Problem

Whenever I upload new music or videos to my OpenSolaris home server (typically by rsync-ing my laptop home directory), both Firefly and Mediatomb need to be restarted so they detect that new files are sitting in their directories, waiting to be served.

The typical way to solve this in the Linux world is to use inotify, and it seems to work quite well. But inotify is a Linux-only API and it is therefore not portable.

The OpenSolaris way to detect changes in the file system is through file notification events. Darren Moffat has written a nice tutorial on how to use file notification events in your code (no link, sun.com no longer exists). But this code has not been adopted by neither Firefly nor Mediatomb (yet?).

A Simple Media Server Update Solution

There’s another way, more simple than coding file notification events and easy to use for any kind of media server software: DTrace.

In the following script, we’ll ask DTrace to watch for open(2) (no link, sun.com no longer exists) events and filter out those that match the directories where we store our media. Then, when new files come in or are changed we’ll send SIGHUP signals to our media server processes so they can re-scan their content directories.

Some Useful DTrace Principles

While putting together this DTrace script, the following things came up which are probably useful to know for a variety of similar D scripts:

  1. DTrace already knows about the standard libc and kernel functions, so, when watching out for writes, we can just specify the O_RDWRITE and O_WRONLY flags to open(2) verbatim without knowing their actual values.

  2. To match the media directory with the path given to open(2), we need to look at arg0, which is a pointer to the given file name. But the file name resides in user space while DTrace operates in kernel space. Therefore, we need to use the DTrace copyin function to copy the file name across memory spaces. This is a common DTrace technique described in the User Process Tracing chapter of the DTrace documentation (no link, sun.com no longer exists).

  3. Another common thing to keep in mind: At the moment of function entry, the file name may reside on a memory page that is not yet accessible, so we can’t necessarily read it yet. We therefore capture the value of arg0 at function entry time, wait until the function has completed, then read out the file name which will then be accessible for sure. Again, this is described in the same chapter of the DTrace docs (no link, sun.com no longer exists).

  4. When trying to match the arguments to open(2) with the media directory we want to watch, we need to test for two cases: 1) arg0 contains the full path, or 2) arg0 is relative to the current working directory. In the latter case, we need to construct the full path, then test against it.

  5. If we add half a dozen CDs and 100 songs to our media library, we don’t want to force a re-scan 100 times. We’ll therefore use a flag that indicates that we have detected some new files, then test against the flag periodically (say, every minute or so) and only then signal the media server process to re-scan.

  6. In order to make the burden on the system as light as possible, we’ll try to do as much of the testing as possible inside of DTrace predicates (no link, sun.com no longer exists) and only use action statements where necessary. Also, DTrace supports short-circuiting of logical AND tests, so we’ll place the most likely or common tests at the beginning of our predicates.

  7. We’ll use the DTrace system() action to signal our media server processes. This is a destructive action (well, not really, but in DTrace parlance…) which means we’ll need to use the -w flag to dtrace(1M) (no link, sun.com no longer exists) which enables destructive actions.

The Automatic Re-Scan DTrace Script

With that in mind, let’s look at the final DTrace script:

Usage and Testing

The script accepts two arguments: A directory to watch and a command that is executed when a file is opened for writing inside the directory. A typical use of this script looks like this:

1
-bash-3.2$ pfexec ./dirtrap.d /home/constant/PowerBookHome/Music/iTunes "pkill -HUP mt-daapd"

And after having touched a file inside our directory with a simple:

1
-bash-3.2$ echo "test" >/home/constant/PowerBookHome/Music/iTunes/testfile

We see this after a couple of seconds in the mt-daapd log file:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
Apr 19 22:38:03 mt-daapd mt-daapd[7398]: [ID 702911 daemon.alert] Got HUP signal.
Apr 19 22:38:03 mt-daapd mt-daapd[7398]: [ID 702911 daemon.alert] Rotated logs
Apr 19 22:38:03 mt-daapd mt-daapd[7398]: [ID 702911 daemon.alert] Rescanning database
2010-04-19 22:38:03 (00000001): Rotated logs
2010-04-19 22:38:03 (00000001): Rescanning database
Apr 19 22:38:12 mt-daapd mt-daapd[7398]: [ID 702911 daemon.alert] Starting playlist scan
2010-04-19 22:38:12 (00000001): Starting playlist scan
Apr 19 22:38:22 mt-daapd mt-daapd[7398]: [ID 702911 daemon.alert] Updating playlists
2010-04-19 22:38:22 (00000001): Updating playlists
Apr 19 22:38:24 mt-daapd mt-daapd[7398]: [ID 702911 daemon.alert] Scanned 7175 songs (was 7175) in 21 seconds
2010-04-19 22:38:24 (00000001): Scanned 7175 songs (was 7175) in 21 seconds

Looks like this script is doing its thing. Now I’m waiting for my next load of CDs to arrive so I can rip and rsync them into my auto-updating OpenSolaris home media server!

Conclusion

DTrace can be an amazing help for any system administrator, even on a home server. In this case, we’ve fixed a common problem that other OSes would need a whole new API (like inotify) to address this problem with!

Learning DTrace isn’t that hard if you look at existing D scripts, check out the documentation (no link, sun.com no longer exists) and are not afraid to read the occasional line of OpenSolaris source code.

Other Useful DTrace Home Server Scripts

This is just the beginning. In fact, if you look around, there’s a wealth of opportunities to leverage DTrace in your day to day work, even in your home server. Here are a few famous examples:

Your Turn

But that’s not enough. Googling “DTrace home server” doesn’t reveal much at the moment. So now it’s your turn:

  • If you haven’t played with DTrace start exploring it now!

  • Did you write yourself some useful D scripts already? Blog them! Or share them in the comments below!

  • What other situations can you imagine where DTrace would be helpful to you home server?

As always, feel free to share your experiences and comments below.

Update

Thanks to this post (no link, sun.com no longer exists), I discovered that DTrace translators can help identify the file name no matter whether it was relative or not. That makes the predicate for syscall::open*:return much simpler:

1
2
3
4
5
/
  !flag &&          /* Exit if we've already found a hit. */
  self->file &&     /* Exit if we didn't take an arg0 note. */
  substr(fds[arg0].fi_pathname, 0, dirlen) == dir /* Check directory */
/

I need to look closer at those translators as they seem to be very useful.


Comments

Commenting is currently not available, because I’d like to avoid cookies on this site. I may or may not endeavor into building my own commenting system at some time, who knows?

Meanwhile, please use the Contact form to send me your comments.

Thank you!


Welcome

This is the blog of Constantin Gonzalez, a Solutions Architect at Amazon Web Services, with more than 25 years of IT experience.

The views expressed in this blog are my own and do not necessarily reflect the views of my current or previous employers.


Copyright © 2022 – Constantin Gonzalez – Some rights reserved.
By using this site you agree to not hold the author responsible for anything related to this site. See Site Info/Imprint for details and our information policy.

This site was built using Pelican, which is written in Python, using a homegrown theme that borrows heavily from Elegant. It is hosted on Amazon S3 and distributed through Amazon CloudFront.