=item I<filename.xml>
-The name of the B<XML> file you want to restore.
+The name of the B<XML> file you want to restore. The special filename "-"
+(a single dash) is interpreted as standard input.
+
+In order to support the restore command in pipe mode (especially when
+using B<RRDtool> over a network connection), when using "-" as a filename
+the end of the file can be signalled either by closing the data
+channel after the file has transferred (as would be the case when
+using input redirection within a suitable shell) or by sending a
+crtl-Z / newline combination. This allows to send more commands to the
+B<RRDtool> server after a restore.
=item I<filename.rrd>
return (status);
} /* int parse_tag_rrd */
+/* helper type for stdioXmlInputReaderForPipeInterface */
+
+typedef struct stdioXmlReaderContext_t {
+ FILE *stream;
+ int freeOnClose;
+ int closed;
+ char eofchar;
+} stdioXmlReaderContext;
+
+/*
+ * this is a xmlInputReadCallback that is used for the pipe interface
+ * in case the passed filename is "-" (meaning standard input) to take
+ * care it will never actually close the stdio stream stdin. It will
+ * report eof once it reads the eof character (currently set to ctrl-Z
+ * (character code 26, hex 0x1A) in the calling code) anywhere on a line.
+ *
+ * Note that ctrl-Z is not an allowed character in XML 1.0 (which rrdtool
+ * uses).
+ *
+ */
+static int stdioXmlInputReadCallback(
+ void *context,
+ char *buffer,
+ int len)
+{
+ stdioXmlReaderContext *sctx = (stdioXmlReaderContext*) context;
+
+ if (sctx == NULL) return -1;
+ if (sctx->stream == NULL) return -1;
+ if (sctx->closed) return 0;
+
+ char *r = fgets(buffer, len, sctx->stream);
+ if (r == NULL) {
+ sctx->closed = 1;
+ return 0;
+ }
+
+ char *where = strchr(r, sctx->eofchar);
+ if (where != NULL) {
+ sctx->closed = 1;
+ *where = 0;
+ }
+
+ return strlen(r);
+}
+
+static int stdioXmlInputCloseCallback(void *context)
+{
+ stdioXmlReaderContext *sctx = (stdioXmlReaderContext*) context;
+
+ if (sctx == NULL) return 0;
+
+ if (sctx->freeOnClose) {
+ sctx->freeOnClose = 0;
+ free(sctx);
+ }
+ return 0; /* everything is OK */
+}
+
static rrd_t *parse_file(
const char *filename)
{
int status;
rrd_t *rrd;
-
- reader = xmlNewTextReaderFilename(filename);
+ stdioXmlReaderContext *sctx = NULL;
+
+ if (strcmp(filename, "-") == 0) {
+ sctx = malloc(sizeof(*sctx));
+ if (sctx == NULL) {
+ rrd_set_error("parse_file: malloc failed.");
+ return (NULL);
+ }
+ sctx->stream = stdin;
+ sctx->freeOnClose = 1;
+ sctx->closed = 0;
+ sctx->eofchar = 0x1A; /* ctrl-Z */
+
+ reader = xmlReaderForIO(stdioXmlInputReadCallback,
+ stdioXmlInputCloseCallback,
+ sctx,
+ filename,
+ NULL,
+ 0);
+ } else {
+ reader = xmlNewTextReaderFilename(filename);
+ }
if (reader == NULL) {
+ if (sctx != NULL) free(sctx);
+
rrd_set_error("Could not create xml reader for: %s",filename);
return (NULL);
}
+ /* NOTE: from now on, sctx will get free'd implicitly through
+ * xmlFreeTextReader and its call to
+ * stdioXmlInputCloseCallback. */
+
if (expect_element(reader,"rrd") != 0) {
xmlFreeTextReader(reader);
+
+ if (sctx != NULL) free(sctx);
return (NULL);
}