diff -urN atftp-0.7.dfsg/atftpd.8 atftp-0.7.dfsg.patched/atftpd.8
--- atftp-0.7.dfsg/atftpd.8	2004-02-13 05:03:12.000000000 +0100
+++ atftp-0.7.dfsg.patched/atftpd.8	2009-04-16 19:30:15.000000000 +0200
@@ -161,6 +161,15 @@
 printout the substitution.
 
 .TP
+.B \-\-content\-generator <path>
+Execute <path> to generate content for nonexisting files. If a
+requested file does not exist, the program will be called as <path> 
+--file <requested file>. The generated contents must be written to
+file descriptor 3,  which will be opened by atftpd using tmpfile(). 
+If the contents need to be stored as well, the program itself is 
+responsible for doing so, atftpd will not store the contents.
+
+.TP
 .B \-\-mtftp <file>
 This will start a mtftp server thread for each valid entry in the
 supplied file. See PXE specification for detail about mtftp. An
diff -urN atftp-0.7.dfsg/configure.ac atftp-0.7.dfsg.patched/configure.ac
--- atftp-0.7.dfsg/configure.ac	2004-03-16 02:51:40.000000000 +0100
+++ atftp-0.7.dfsg.patched/configure.ac	2009-04-13 22:36:36.000000000 +0200
@@ -45,6 +45,12 @@
 		yes) libpcre=true ;;
 		no) libpcre=flase ;;
 	  esac], [libpcre=true])
+AC_ARG_ENABLE(generated_content,
+        [  --enable-generated-content enable support for generated content in the server],
+	[ case "${enableval}" in
+		yes) generated_content=true ;;
+		no) generated_content=false ;;
+	  esac], [generated_content=false])
 
 AC_ARG_ENABLE(mtftp,
 	[  --enable-mtftp          enable mtftp support in server],
@@ -170,6 +176,10 @@
 		"Support for libpcre pattern subsitution")])
    AC_SUBST(LIBPCRE)
 fi
+if test x$generated_content = xtrue; then
+	AC_DEFINE([HAVE_GENERATED_CONTENT], 1,
+                   Support for generated content)
+fi
 
 dnl Checks for header files.
 AC_HEADER_STDC
diff -urN atftp-0.7.dfsg/debian/rules atftp-0.7.dfsg.patched/debian/rules
--- atftp-0.7.dfsg/debian/rules	2009-04-16 19:48:47.000000000 +0200
+++ atftp-0.7.dfsg.patched/debian/rules	2009-04-13 22:36:36.000000000 +0200
@@ -17,7 +17,7 @@
 configure-stamp:
 	dh_testdir
 	# Add here commands to configure the package.
-	./configure --prefix=/usr --mandir=/usr/share/man
+	./configure --prefix=/usr --mandir=/usr/share/man --enable-generated-content
 
 	touch configure-stamp
 
diff -urN atftp-0.7.dfsg/README.GENERATED atftp-0.7.dfsg.patched/README.GENERATED
--- atftp-0.7.dfsg/README.GENERATED	1970-01-01 01:00:00.000000000 +0100
+++ atftp-0.7.dfsg.patched/README.GENERATED	2009-04-16 19:36:56.000000000 +0200
@@ -0,0 +1,61 @@
+Dynamically generating content with atftpd
+------------------------------------------
+
+When installing many machines via PXEboot kickstart/d-i installs, it is often
+useful to generate pxelinux.cfg files on demand with contents grabbed from a
+database. Or when you have an Asus Wl500g router, you have only tftp available
+to download data, being able to generate this data could be useful (eg. lists
+of macaddresses or iptables rules).
+
+These were my two use cases for implementing support for dynamic content in 
+atftpd. Here is how to use it:
+
+* Add the "--content-generator /path/to/executable" argument to the atftpd 
+  commandline (eg. in xinetd.conf or /etc/default/atftpd, depending on your
+  setup).
+* Whenever a requested file cannot be found, atftpd will open a temporary
+  file with tmpfile(3) and will execute your application, with the
+  requested name as arguments (example: 
+  /usr/local/bin/tftp-generator --file /var/lib/tftpboot/some_file)
+  The application must ignore unknown arguments, more arguments might be added
+  later.
+* Your application is now responsible for writing the content that atftpd
+  should send to the given fd (6 in the example). If the content needs to
+  be stored, your application also must do so itself.
+* If your application exists with a non-zero exitstatus or writes zero bytes,
+  atftpd will treat that as "file not found". If data is written and your
+  application exits with code 0, the written data is sent to the client.
+
+-- 
+Dennis Kaarsemaker
+<dennis@kaarsemaker.net>
+
+-------------------------------------------------------------------------------
+Example application for use case #2: Grabbing a list of mac addresses from a
+database. The database is maintained using the django framework.
+
+#!/usr/bin/python
+
+import os
+import sys
+from optparse import OptionParser
+
+parser = OptionParser()
+parser.add_option("--file", dest="filename", help="Requested file", metavar="FILE")
+options, args = parser.parse_args()
+
+if os.path.basename(options.filename) != 'maclist':
+    sys.exit(1)
+fd = os.fdopen(3, 'w')
+
+sys.path.insert(0,'/srv/www/intranet')
+os.environ['DJANGO_SETTINGS_MODULE'] = 'infra.settings'
+from infra.machine.models import Interface
+
+fd.write("""#!/bin/sh
+# Shellscript generated from infra database
+# Do not edit by hand
+
+wl mac none
+wl mac %s 00:00:00:00:00:00
+""" % ' '.join([x.mac for x in Interface.objects.filter(wireless=True)]))
diff -urN atftp-0.7.dfsg/redhat/atftp.spec.in atftp-0.7.dfsg.patched/redhat/atftp.spec.in
--- atftp-0.7.dfsg/redhat/atftp.spec.in	2003-04-29 02:36:58.000000000 +0200
+++ atftp-0.7.dfsg.patched/redhat/atftp.spec.in	2009-04-16 19:50:41.000000000 +0200
@@ -33,7 +33,7 @@
 
 
 %build
-%configure
+%configure --enable-generated-files
 make
 
 
diff -urN atftp-0.7.dfsg/tftpd.c atftp-0.7.dfsg.patched/tftpd.c
--- atftp-0.7.dfsg/tftpd.c	2009-04-16 19:48:47.000000000 +0200
+++ atftp-0.7.dfsg.patched/tftpd.c	2009-04-13 22:36:36.000000000 +0200
@@ -112,6 +112,10 @@
 char *pcre_file;
 #endif
 
+#ifdef HAVE_GENERATED_CONTENT
+char *content_generator = NULL;
+#endif
+
 #ifdef HAVE_MTFTP
 /* mtftp options */
 struct mtftp_data *mtftp_data = NULL;
@@ -839,6 +843,9 @@
           { "pcre", 1, NULL, OPT_PCRE },
           { "pcre-test", 1, NULL, OPT_PCRE_TEST },
 #endif
+#ifdef HAVE_GENERATED_CONTENT
+          { "content-generator", 1, NULL, 'g' },
+#endif
 #ifdef HAVE_MTFTP
           { "mtftp", 1, NULL, OPT_MTFTP },
           { "mtftp-port", 1, NULL, OPT_MTFTP_PORT },
@@ -968,6 +975,15 @@
                          printf("Substitution: \"%s\" -> \"%s\"\n", string, out);
                }
 #endif
+#ifdef HAVE_GENERATED_CONTENT
+          case 'g':
+               content_generator = strdup(optarg);
+               if(access(content_generator, X_OK)) {
+                   fprintf(stderr, "Cannot use %s as content generator: %s\n", content_generator, strerror(errno));
+                   content_generator = NULL;
+               }
+               break;
+#endif
           case OPT_PORT_CHECK:
                source_port_checking = 0;
                break;
@@ -1053,6 +1069,10 @@
      if (pcre_top)
           logger(LOG_INFO, "  PCRE: using file: %s", pcre_file);
 #endif
+#ifdef HAVE_GENERATED_CONTENT
+     if(content_generator)
+        logger(LOG_INFO, "  content generator: %s", content_generator);
+#endif
 #ifdef HAVE_MTFTP
      if (strcmp(mtftp_file, "") != 0)
      {
@@ -1142,6 +1162,9 @@
             "  --pcre <file>              : use this file for pattern replacement\n"
             "  --pcre-test <file>         : just test pattern file, not starting server\n"
 #endif
+#ifdef HAVE_GENERATED_CONTENT
+            "  --content-generator <path>         : use <path> to generate content\n"
+#endif
 #ifdef HAVE_MTFTP
             "  --mtftp <file>             : mtftp configuration file\n"
             "  --mtftp-port <port>        : port mtftp will listen\n"
diff -urN atftp-0.7.dfsg/tftpd_file.c atftp-0.7.dfsg.patched/tftpd_file.c
--- atftp-0.7.dfsg/tftpd_file.c	2004-02-18 03:21:47.000000000 +0100
+++ atftp-0.7.dfsg.patched/tftpd_file.c	2009-04-16 19:14:25.000000000 +0200
@@ -36,6 +36,10 @@
 #ifdef HAVE_PCRE
 #include "tftpd_pcre.h"
 #endif
+#ifdef HAVE_GENERATED_CONTENT
+#include <sys/types.h>
+#include <sys/wait.h>
+#endif
 
 #define S_BEGIN         0
 #define S_SEND_REQ      1
@@ -60,6 +64,9 @@
 extern tftpd_pcre_self_t *pcre_top;
 #endif
 
+#ifdef HAVE_GENERATED_CONTENT
+extern char* content_generator;
+#endif
 
 /*
  * Rules for filenames. This is common to both tftpd_recieve_file
@@ -428,6 +435,10 @@
      int prev_block_number = 0; /* needed to support netascii convertion */
      int prev_file_pos = 0;
      int temp = 0;
+#ifdef HAVE_GENERATED_CONTENT
+     pid_t generator_pid = 0;
+     int generator_status;
+#endif
 
      /* look for mode option */
      if (strcasecmp(data->tftp_options[OPT_MODE].value, "netascii") == 0)
@@ -485,6 +496,56 @@
           }
      }
 #endif
+#ifdef HAVE_GENERATED_CONTENT
+     if (fp == NULL)
+     {
+          if (content_generator)
+          {
+               logger(LOG_DEBUG, "Trying to generate contents for %s", filename);
+               fp = tmpfile();
+               generator_pid = fork();
+               switch(generator_pid) {
+                   case 0:
+                       /* In the child */
+                       close(3);
+                       dup2(fileno(fp), 3);
+                       for(temp=4; temp < 1024; temp++)
+                           close(temp);
+                       execl(content_generator, content_generator, "--file", filename, (char *)NULL);
+                       /* Exec failed, make sure the parent notices */
+                       exit(66);
+                       ;;
+                   case -1:
+                       logger(LOG_WARNING, "fork() failed: %s", strerror(errno));
+                       fclose(fp);
+                       fp = NULL;
+                   default:
+                       /* In the parent */
+                       while(1) {
+                            errno = 0;
+                            temp = waitpid(generator_pid, &generator_status, 0);
+                            if(temp == -1 && errno == EINTR)
+                                continue;
+                            break;
+                       }
+                       if(!WIFEXITED(generator_status) || (WEXITSTATUS(generator_status) != 0)) {
+                            logger(LOG_WARNING, "generating content failed: %d %d", generator_status, WEXITSTATUS(generator_status));
+                            fclose(fp);
+                            fp = NULL;
+                       }
+                       else {
+                            fstat(fileno(fp), &file_stat);
+                            if(file_stat.st_size == 0) {
+                                 logger(LOG_WARNING, "content generator wrote 0 bytes");
+                                 fclose(fp);
+                                 fp = NULL;
+                            }
+                       }
+                       break;
+               }
+          }
+     }
+#endif 
      if (fp == NULL)
      {
           tftp_send_error(sockfd, sa, ENOTFOUND, data->data_buffer, data->data_buffer_size);
