r270: Implement prerun and postrun options
authoryoe <yoe>
Thu, 26 Jul 2007 14:30:45 +0000 (14:30 +0000)
committeryoe <yoe>
Thu, 26 Jul 2007 14:30:45 +0000 (14:30 +0000)
nbd-server.5.sgml
nbd-server.c

index d44abd0..ba528b9 100644 (file)
@@ -320,7 +320,8 @@ manpage.1: manpage.sgml
            will use sparse files to implement the copy-on-write
            option; such files take up less space then they appear to,
            which allows <command>nbd-server</command> to handle the
            will use sparse files to implement the copy-on-write
            option; such files take up less space then they appear to,
            which allows <command>nbd-server</command> to handle the
-           file as if it was just as large as the block device it's for.
+           file as if it was just as large as the block device it's
+           for.
          </para>
          <para>
            If this option is disabled, <command>nbd-server</command>
          </para>
          <para>
            If this option is disabled, <command>nbd-server</command>
@@ -414,17 +415,64 @@ manpage.1: manpage.sgml
                  after it. <command>nbd-server</command> will use the
                  number as a network mask in CIDR style, and use that
                  as a hash cutoff point. In the above example, if
                  after it. <command>nbd-server</command> will use the
                  number as a network mask in CIDR style, and use that
                  as a hash cutoff point. In the above example, if
-                 <option>virtstyle</option> has been specified
-                 as <constant>cidrhash 16</constant>, then
+                 <option>virtstyle</option> has been specified as
+                 <constant>cidrhash 16</constant>, then
                  <command>nbd-server</command> will try to open
                  <command>nbd-server</command> will try to open
-                 <filename>/export/192.168.0.0/192.168.1.100</filename>; if
-                 <option>virtstyle</option> were specified as
+                 <filename>/export/192.168.0.0/192.168.1.100</filename>;
+                 if <option>virtstyle</option> were specified as
                  <constant>cidrhash 26</constant>, then
                  <command>nbd-server</command> will try to open
                  <filename>/export/192.168.1.64/192.168.1.100</filename>.
                </para>
              </listitem>
            </varlistentry>
                  <constant>cidrhash 26</constant>, then
                  <command>nbd-server</command> will try to open
                  <filename>/export/192.168.1.64/192.168.1.100</filename>.
                </para>
              </listitem>
            </varlistentry>
+           <varlistentry>
+             <term><option>prerun</option></term>
+             <listitem>
+               <para>Optional; string</para>
+               <para>
+                 If specified, then this command will be ran after a
+                 client has connected to the server (and has been
+                 accepted), but before the server starts serving. If
+                 the command contains the literal string '%s', then
+                 this string will be replaced by the filename of the
+                 file which nbd-server wants to export.
+               </para>
+               <para>
+                 This is useful to create export files on the fly, or
+                 to verify that a file can be used for export, to
+                 write something to a log file, or similar.
+               </para>
+               <para>
+                 If the command runs with a non-zero exit status,
+                 then nbd-server will assume the export will fail,
+                 and refuse to serve it.
+               </para>
+             </listitem>
+           </varlistentry>
+           <varlistentry>
+             <term><option>postrun</option></term>
+             <listitem>
+               <para>Optional; string</para>
+               <para>
+                 If specified, then it is assumed to be a command
+                 that will be ran when a client has
+                 disconnected. This can be useful to clean up
+                 whatever <option>prerun</option> has set up, to log
+                 something, or similar.
+               </para>
+               <para>
+                 If the literal string '%s' is present in the
+                 command, it will be replaced by the file name that
+                 has just been closed.
+               </para>
+               <para>
+                 In contrast to the <option>prerun</option> option,
+                 the exit state of <option>postrun</option> is
+                 <emphasis>ignored</emphasis>.
+               </para>
+             </listitem>
+           </varlistentry>
          </variablelist>
        </listitem>
       </varlistentry>
          </variablelist>
        </listitem>
       </varlistentry>
index a7f759f..26c8f59 100644 (file)
@@ -179,6 +179,10 @@ typedef struct {
        VIRT_STYLE virtstyle;/**< The style of virtualization, if any */
        uint8_t cidrlen;     /**< The length of the mask when we use
                                  CIDR-style virtualization */
        VIRT_STYLE virtstyle;/**< The style of virtualization, if any */
        uint8_t cidrlen;     /**< The length of the mask when we use
                                  CIDR-style virtualization */
+       gchar* prerun;       /**< command to be ran after connecting a client,
+                                 but before starting to serve */
+       gchar* postrun;      /**< command that will be ran after the client
+                                 disconnects */
 } SERVER;
 
 /**
 } SERVER;
 
 /**
@@ -530,6 +534,8 @@ GArray* parse_cfile(gchar* f, GError** e) {
                { "timeout",    FALSE,  PARAM_INT,      NULL, 0 },
                { "filesize",   FALSE,  PARAM_INT,      NULL, 0 },
                { "virtstyle",  FALSE,  PARAM_STRING,   NULL, 0 },
                { "timeout",    FALSE,  PARAM_INT,      NULL, 0 },
                { "filesize",   FALSE,  PARAM_INT,      NULL, 0 },
                { "virtstyle",  FALSE,  PARAM_STRING,   NULL, 0 },
+               { "prerun",     FALSE,  PARAM_STRING,   NULL, 0 },
+               { "postrun",    FALSE,  PARAM_STRING,   NULL, 0 },
                { "readonly",   FALSE,  PARAM_BOOL,     NULL, F_READONLY },
                { "multifile",  FALSE,  PARAM_BOOL,     NULL, F_MULTIFILE },
                { "copyonwrite", FALSE, PARAM_BOOL,     NULL, F_COPYONWRITE },
                { "readonly",   FALSE,  PARAM_BOOL,     NULL, F_READONLY },
                { "multifile",  FALSE,  PARAM_BOOL,     NULL, F_MULTIFILE },
                { "copyonwrite", FALSE, PARAM_BOOL,     NULL, F_COPYONWRITE },
@@ -576,8 +582,11 @@ GArray* parse_cfile(gchar* f, GError** e) {
                lp[3].target=&(s.timeout);
                lp[4].target=&(s.expected_size);
                lp[5].target=&(virtstyle);
                lp[3].target=&(s.timeout);
                lp[4].target=&(s.expected_size);
                lp[5].target=&(virtstyle);
-               lp[6].target=lp[7].target=lp[8].target=
-                               lp[9].target=lp[10].target=&(s.flags);
+               lp[6].target=&(s.prerun);
+               lp[7].target=&(s.postrun);
+               lp[8].target=lp[9].target=lp[10].target=
+                               lp[11].target=lp[12].target=&(s.flags);
+               
                /* After the [generic] group, start parsing exports */
                if(i==1) {
                        p=lp;
                /* After the [generic] group, start parsing exports */
                if(i==1) {
                        p=lp;
@@ -1045,7 +1054,7 @@ void negotiate(CLIENT *client) {
  * pieces. Preferably with a chainsaw.
  *
  * @param client The client we're going to serve to.
  * pieces. Preferably with a chainsaw.
  *
  * @param client The client we're going to serve to.
- * @return never
+ * @return when the client disconnects
  **/
 int mainloop(CLIENT *client) {
        struct nbd_request request;
  **/
 int mainloop(CLIENT *client) {
        struct nbd_request request;
@@ -1233,6 +1242,25 @@ int copyonwrite_prepare(CLIENT* client) {
 }
 
 /**
 }
 
 /**
+ * Run a command. This is used for the ``prerun'' and ``postrun'' config file
+ * options
+ *
+ * @param command the command to be ran. Read from the config file
+ * @param file the file name we're about to export
+ **/
+int do_run(gchar* command, gchar* file) {
+       gchar* cmd;
+       int retval=0;
+
+       if(*command) {
+               cmd = g_strdup_printf(command, file);
+               retval=system(cmd);
+               g_free(cmd);
+       }
+       return retval;
+}
+
+/**
  * Serve a connection. 
  *
  * @todo allow for multithreading, perhaps use libevent. Not just yet, though;
  * Serve a connection. 
  *
  * @todo allow for multithreading, perhaps use libevent. Not just yet, though;
@@ -1249,7 +1277,10 @@ void serveconnection(CLIENT *client) {
 
        setmysockopt(client->net);
 
 
        setmysockopt(client->net);
 
-       mainloop(client);
+       if(!do_run(client->server->prerun, client->exportname)) {
+               mainloop(client);
+       }
+       do_run(client->server->postrun, client->exportname);
 }
 
 /**
 }
 
 /**
@@ -1499,6 +1530,7 @@ int serveloop(GArray* servers) {
 #endif // NOFORK
                                        msg2(LOG_INFO,"Starting to serve");
                                        serveconnection(client);
 #endif // NOFORK
                                        msg2(LOG_INFO,"Starting to serve");
                                        serveconnection(client);
+                                       exit(EXIT_SUCCESS);
                                }
                        }
                }
                                }
                        }
                }