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>
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
- <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>
+ <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>
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;
/**
{ "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 },
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;
* 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;
}
/**
+ * 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;
setmysockopt(client->net);
- mainloop(client);
+ if(!do_run(client->server->prerun, client->exportname)) {
+ mainloop(client);
+ }
+ do_run(client->server->postrun, client->exportname);
}
/**
#endif // NOFORK
msg2(LOG_INFO,"Starting to serve");
serveconnection(client);
+ exit(EXIT_SUCCESS);
}
}
}