diff --git a/src/bin/copy.c b/src/bin/copy.c
index f84b6b20..d542568b 100644
--- a/src/bin/copy.c
+++ b/src/bin/copy.c
@@ -158,6 +158,16 @@ static bool is_uri(const char *str)
return strstr(str, "://") != NULL;
}
+static bool is_stdout(const char *path)
+{
+ if (!path)
+ return 1;
+
+ return !strcmp(path, "-") ||
+ !strcmp(path, "/dev/stdout") ||
+ !strcmp(path, "/dev/fd/1");
+}
+
static char *mktmp(void)
{
mode_t oldmask;
@@ -413,6 +423,23 @@ static int curl_download(const char *uri, const char *dstpath)
return 0;
}
+static int cat(const char *srcpath)
+{
+ char *argv[] = { "cat", NULL, NULL };
+ int err;
+
+ argv[1] = strdup(srcpath);
+ if (!argv[1])
+ return 1;
+
+ err = subprocess(argv);
+ if (err)
+ warnx("failed writing to stdout, exit code %d", err);
+
+ free(argv[1]);
+ return err;
+}
+
static int cp(const char *srcpath, const char *dstpath)
{
char *argv[] = {
@@ -441,6 +468,8 @@ static int put(const char *srcpath, const char *dst,
if (ds)
err = sysrepo_import(ds, srcpath);
+ else if (is_stdout(dst))
+ err = cat(srcpath);
else if (is_uri(dst))
err = curl_upload(srcpath, dst);
@@ -494,6 +523,9 @@ static int resolve_src(const char **src, const struct infix_ds **ds, char **path
static int resolve_dst(const char **dst, const struct infix_ds **ds, char **path)
{
+ if (is_stdout(*dst) || is_uri(*dst))
+ return 0;
+
*dst = infix_ds(*dst, ds);
if (*ds) {
@@ -506,8 +538,6 @@ static int resolve_dst(const char **dst, const struct infix_ds **ds, char **path
return 0;
*path = strdup((*ds)->path);
- } else if (is_uri(*dst)) {
- return 0;
} else {
*path = cfg_adjust(*dst, NULL, sanitize);
}
@@ -536,7 +566,7 @@ static int copy(const char *src, const char *dst)
/* rw for user and group only */
oldmask = umask(0006);
- if (!strcmp(src, dst)) {
+ if (dst && !strcmp(src, dst)) {
warn("source and destination are the same, aborting.");
goto err;
}
@@ -562,7 +592,8 @@ err:
if (rmsrc)
rmtmp(srcpath);
- free(dstpath);
+ if (dstpath)
+ free(dstpath);
free(srcpath);
sync();
@@ -572,7 +603,7 @@ err:
static int usage(int rc)
{
- printf("Usage: %s [OPTIONS] SRC DST\n"
+ printf("Usage: %s [OPTIONS] SRC [DST]\n"
"\n"
"Options:\n"
" -h This help text\n"
@@ -584,7 +615,8 @@ static int usage(int rc)
"\n"
"Files:\n"
" SRC JSON configuration file, or a datastore\n"
- " DST A file or datastore, except factory-config\n"
+ " DST Optiional file or datastore, except factory-config,\n"
+ " when omitted output goes to stdout\n"
"\n"
"Datastores:\n"
" running-config The running datastore, current active config\n"
@@ -627,7 +659,7 @@ int main(int argc, char *argv[])
if (timeout < 0)
timeout = 120;
- if (argc - optind != 2)
+ if (argc - optind < 1)
return usage(1);
src = argv[optind++];
diff --git a/src/klish-plugin-infix/xml/infix.xml b/src/klish-plugin-infix/xml/infix.xml
index 38676fbc..75f1cc68 100644
--- a/src/klish-plugin-infix/xml/infix.xml
+++ b/src/klish-plugin-infix/xml/infix.xml
@@ -628,15 +628,15 @@
- jq -C . /etc/factory-config.cfg |pager
+ copy factory | jq -C . |pager
- sysrepocfg -X -f json | jq -C . |pager
+ copy running | jq -C . |pager
- jq -C . /cfg/startup-config.cfg |pager
+ copy startup | jq -C . |pager