mirror of
https://github.com/kernelkit/infix.git
synced 2026-07-22 01:13:00 +02:00
bin: factor out copy, erase, and files from klish-plugin-infix
Relocate C code from klish-plugin-infix to stand-alone binaries we can use also from Bash. Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
This commit is contained in:
@@ -1,4 +1,6 @@
|
||||
menu "Packages"
|
||||
|
||||
source "$BR2_EXTERNAL_INFIX_PATH/package/bin/Config.in"
|
||||
source "$BR2_EXTERNAL_INFIX_PATH/package/confd/Config.in"
|
||||
source "$BR2_EXTERNAL_INFIX_PATH/package/confd-test-mode/Config.in"
|
||||
source "$BR2_EXTERNAL_INFIX_PATH/package/curios-httpd/Config.in"
|
||||
@@ -34,4 +36,5 @@ source "$BR2_EXTERNAL_INFIX_PATH/package/sysrepo-cpp/Config.in"
|
||||
source "$BR2_EXTERNAL_INFIX_PATH/package/rousette/Config.in"
|
||||
source "$BR2_EXTERNAL_INFIX_PATH/package/nghttp2-asio/Config.in"
|
||||
source "$BR2_EXTERNAL_INFIX_PATH/package/date-cpp/Config.in"
|
||||
|
||||
endmenu
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
config BR2_PACKAGE_BIN
|
||||
bool "bin"
|
||||
select BR2_PACKAGE_SYSREPO
|
||||
select BR2_PACKAGE_LIBITE
|
||||
help
|
||||
Misc. tools for CLI and shell users.
|
||||
|
||||
https://github.com/kernelkit/infix
|
||||
@@ -0,0 +1 @@
|
||||
sha256 d2f96418893ac66156d0e691cda189b0d85ae1d814065d1d9aa1845383100f46 LICENSE
|
||||
@@ -0,0 +1,21 @@
|
||||
################################################################################
|
||||
#
|
||||
# bin
|
||||
#
|
||||
################################################################################
|
||||
|
||||
BIN_VERSION = 1.0
|
||||
BIN_SITE_METHOD = local
|
||||
BIN_SITE = $(BR2_EXTERNAL_INFIX_PATH)/src/bin
|
||||
BIN_LICENSE = BSD-3-Clause
|
||||
BIN_LICENSE_FILES = LICENSE
|
||||
BIN_REDISTRIBUTE = NO
|
||||
BIN_DEPENDENCIES = sysrepo libite
|
||||
BIN_CONF_OPTS = --prefix= --disable-silent-rules
|
||||
BIN_AUTORECONF = YES
|
||||
|
||||
define BIN_CONF_ENV
|
||||
CFLAGS="$(INFIX_CFLAGS)"
|
||||
endef
|
||||
|
||||
$(eval $(autotools-package))
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
# Host build of critical components, for Coverity Scan mostly
|
||||
APPS = confd execd factory keyack statd
|
||||
APPS = bin confd execd factory keyack statd
|
||||
|
||||
.PHONY: all
|
||||
all:
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
*~
|
||||
*.o
|
||||
copy
|
||||
erase
|
||||
files
|
||||
|
||||
/aclocal.m4
|
||||
/autom4te.cache/
|
||||
/aux
|
||||
/clixon.xml
|
||||
/compile
|
||||
/config.h
|
||||
/config.h.in
|
||||
/config.guess
|
||||
/config.log
|
||||
/config.status
|
||||
/config.sub
|
||||
/configure
|
||||
/depcomp
|
||||
/.deps/
|
||||
/install-sh
|
||||
/libtool
|
||||
/ltmain.sh
|
||||
/m4
|
||||
/missing
|
||||
|
||||
GPATH
|
||||
GRTAGS
|
||||
GTAGS
|
||||
Makefile
|
||||
Makefile.in
|
||||
@@ -0,0 +1,13 @@
|
||||
Copyright (c) 2024 The KernelKit Authors
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
@@ -0,0 +1,22 @@
|
||||
DISTCLEANFILES = *~ *.d
|
||||
ACLOCAL_AMFLAGS = -I m4
|
||||
|
||||
bin_PROGRAMS = copy erase files
|
||||
|
||||
copy_SOURCES = copy.c util.c util.h
|
||||
copy_CPPFLAGS = -D_DEFAULT_SOURCE -D_GNU_SOURCE
|
||||
copy_CFLAGS = -W -Wall -Wextra
|
||||
copy_CFLAGS += $(libite_CFLAGS) $(sysrepo_CFLAGS)
|
||||
copy_LDADD = $(libite_LIBS) $(sysrepo_LIBS)
|
||||
|
||||
erase_SOURCES = erase.c util.c util.h
|
||||
erase_CPPFLAGS = -D_DEFAULT_SOURCE -D_GNU_SOURCE
|
||||
erase_CFLAGS = -W -Wall -Wextra
|
||||
erase_CFLAGS += $(libite_CFLAGS) $(sysrepo_CFLAGS)
|
||||
erase_LDADD = $(libite_LIBS) $(sysrepo_LIBS)
|
||||
|
||||
files_SOURCES = files.c util.c util.h
|
||||
files_CPPFLAGS = -D_DEFAULT_SOURCE -D_GNU_SOURCE
|
||||
files_CFLAGS = -W -Wall -Wextra
|
||||
files_CFLAGS += $(libite_CFLAGS) $(sysrepo_CFLAGS)
|
||||
files_LDADD = $(libite_LIBS) $(sysrepo_LIBS)
|
||||
@@ -0,0 +1,2 @@
|
||||
* Add bash completion to 'copy' + 'erase', use 'files'
|
||||
* https://github.com/kernelkit/infix/issues/373
|
||||
Executable
+3
@@ -0,0 +1,3 @@
|
||||
#!/bin/sh
|
||||
|
||||
autoreconf -W portability -vifm
|
||||
@@ -0,0 +1,8 @@
|
||||
# Used by ../Makefile for 'make check' and Coverity Scan
|
||||
export PKG_CONFIG_PATH = $(CURDIR)/../staging/lib/pkgconfig
|
||||
|
||||
all:
|
||||
./autogen.sh
|
||||
./configure
|
||||
make V=1 all
|
||||
make distclean
|
||||
@@ -0,0 +1,70 @@
|
||||
AC_PREREQ(2.61)
|
||||
AC_INIT([bin], [1.0], [https://github.com/kernelkit/infix/issues])
|
||||
AM_INIT_AUTOMAKE(1.11 foreign subdir-objects)
|
||||
AM_SILENT_RULES(yes)
|
||||
|
||||
AC_CONFIG_HEADERS([config.h])
|
||||
AC_CONFIG_FILES([
|
||||
Makefile
|
||||
])
|
||||
|
||||
AC_PROG_CC
|
||||
AC_PROG_INSTALL
|
||||
|
||||
# Check for pkg-config first, warn if it's not installed
|
||||
PKG_PROG_PKG_CONFIG
|
||||
|
||||
PKG_CHECK_MODULES([libite], [libite >= 2.5.0])
|
||||
PKG_CHECK_MODULES([sysrepo], [sysrepo >= 2.2.36])
|
||||
|
||||
# Misc variable replacements for below Summary
|
||||
test "x$prefix" = xNONE && prefix=$ac_default_prefix
|
||||
test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
|
||||
|
||||
DATAROOTDIR=`eval echo $datarootdir`
|
||||
DATAROOTDIR=`eval echo $DATAROOTDIR`
|
||||
AC_SUBST(DATAROOTDIR)
|
||||
|
||||
LIBDIR=`eval echo $libdir`
|
||||
LIBDIR=`eval echo $LIBDIR`
|
||||
AC_SUBST(LIBDIR)
|
||||
|
||||
LOCALSTATEDIR=`eval echo $localstatedir`
|
||||
LOCALSTATEDIR=`eval echo $LOCALSTATEDIR`
|
||||
AC_SUBST(LOCALSTATEDIR)
|
||||
|
||||
RUNSTATEDIR=`eval echo $runstatedir`
|
||||
RUNSTATEDIR=`eval echo $RUNSTATEDIR`
|
||||
AC_SUBST(RUNSTATEDIR)
|
||||
|
||||
SYSCONFDIR=`eval echo $sysconfdir`
|
||||
SYSCONFDIR=`eval echo $SYSCONFDIR`
|
||||
AC_SUBST(SYSCONFDIR)
|
||||
|
||||
AC_OUTPUT
|
||||
|
||||
cat <<EOF
|
||||
|
||||
------------------ Summary ------------------
|
||||
$PACKAGE_NAME version $PACKAGE_VERSION
|
||||
Prefix................: $prefix
|
||||
Exec prefix...........: $eprefix
|
||||
Sysconfdir............: `eval echo $sysconfdir`
|
||||
Localstatedir.........: `eval echo $localstatedir`
|
||||
Default fstab.........: `eval echo $fstab`
|
||||
System environment....: ${sysconfig_path:-${sysconfig}}
|
||||
C Compiler............: $CC $CFLAGS $CPPFLAGS $LDFLAGS $LIBS
|
||||
Linker................: $LD $LLDP_LDFLAGS $LLDP_BIN_LDFLAGS $LDFLAGS $LIBS
|
||||
CFLAGS................: $libite_CFLAGS $sysrepo_CFLAGS
|
||||
LIBS..................: $libite_LIBS $sysrepo_LIBS
|
||||
|
||||
------------- Compiler version --------------
|
||||
$($CC --version || true)
|
||||
-------------- Linker version ---------------
|
||||
$($LD --version || true)
|
||||
---------------------------------------------
|
||||
|
||||
Check the above options and compile with:
|
||||
${MAKE-make}
|
||||
|
||||
EOF
|
||||
+347
@@ -0,0 +1,347 @@
|
||||
/* SPDX-License-Identifier: ISC */
|
||||
#include "config.h"
|
||||
|
||||
#include <getopt.h>
|
||||
#include <pwd.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <sysrepo.h>
|
||||
#include <sysrepo/netconf_acm.h>
|
||||
|
||||
#include "util.h"
|
||||
|
||||
struct infix_ds {
|
||||
char *name; /* startup-config, etc. */
|
||||
char *sysrepocfg; /* ds name in sysrepocfg */
|
||||
int datastore; /* sr_datastore_t and -1 */
|
||||
int rw; /* read-write:1 or not:0 */
|
||||
char *path; /* local path or NULL */
|
||||
};
|
||||
|
||||
struct infix_ds infix_config[] = {
|
||||
{ "startup-config", "startup", SR_DS_STARTUP, 1, "/cfg/startup-config.cfg" },
|
||||
{ "running-config", "running", SR_DS_RUNNING, 1, NULL },
|
||||
{ "candidate-config", "candidate", SR_DS_CANDIDATE, 1, NULL },
|
||||
{ "operational-config", "operational", SR_DS_OPERATIONAL, 1, NULL },
|
||||
{ "factory-config", "factory-default", SR_DS_FACTORY_DEFAULT, 0, NULL }
|
||||
};
|
||||
|
||||
static const char *prognm = "copy";
|
||||
|
||||
|
||||
/*
|
||||
* Print sysrepo session errors followed by an optional string.
|
||||
*/
|
||||
static void emsg(sr_session_ctx_t *sess, const char *fmt, ...)
|
||||
{
|
||||
const sr_error_info_t *err = NULL;
|
||||
va_list ap;
|
||||
size_t i;
|
||||
int rc;
|
||||
|
||||
if (!sess)
|
||||
goto end;
|
||||
|
||||
rc = sr_session_get_error(sess, &err);
|
||||
if ((rc != SR_ERR_OK) || !err)
|
||||
goto end;
|
||||
|
||||
// Show the first error only. Because probably next errors are
|
||||
// originated from internal sysrepo code but is not from subscribers.
|
||||
// for (i = 0; i < err->err_count; i++)
|
||||
for (i = 0; i < (err->err_count < 1 ? err->err_count : 1); i++)
|
||||
fprintf(stderr, ERRMSG "%s\n", err->err[i].message);
|
||||
end:
|
||||
if (fmt) {
|
||||
va_start(ap, fmt);
|
||||
vfprintf(stderr, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
}
|
||||
|
||||
static char *getuser(void)
|
||||
{
|
||||
const struct passwd *pw;
|
||||
uid_t uid;
|
||||
|
||||
uid = getuid();
|
||||
pw = getpwuid(uid);
|
||||
if (!pw) {
|
||||
perror("getpwuid");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return pw->pw_name;
|
||||
}
|
||||
|
||||
static void set_owner(const char *fn, const char *user)
|
||||
{
|
||||
struct passwd *pw;
|
||||
|
||||
pw = getpwnam(user);
|
||||
if (!pw) {
|
||||
fprintf(stderr, ERRMSG "setting owner %s on %s: %s\n", fn, user, strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
chmod(fn, 0660);
|
||||
chown(fn, pw->pw_uid, pw->pw_gid);
|
||||
}
|
||||
|
||||
static const char *infix_ds(const char *text, struct infix_ds **ds)
|
||||
{
|
||||
size_t i, len = strlen(text);
|
||||
|
||||
for (i = 0; i < NELEMS(infix_config); i++) {
|
||||
if (!strncmp(infix_config[i].name, text, len)) {
|
||||
*ds = &infix_config[i];
|
||||
return infix_config[i].name;
|
||||
}
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
|
||||
static int copy(const char *src, const char *dst, const char *user)
|
||||
{
|
||||
struct infix_ds *srcds = NULL, *dstds = NULL;
|
||||
char temp_file[20] = "/tmp/copy.XXXXXX";
|
||||
const char *tmpfn = NULL;
|
||||
sr_session_ctx_t *sess;
|
||||
const char *fn = NULL;
|
||||
const char *username;
|
||||
sr_conn_ctx_t *conn;
|
||||
char adjust[256];
|
||||
mode_t oldmask;
|
||||
int rc = 0;
|
||||
|
||||
oldmask = umask(0660);
|
||||
|
||||
src = infix_ds(src, &srcds);
|
||||
if (!src)
|
||||
goto err;
|
||||
dst = infix_ds(dst, &dstds);
|
||||
if (!dst)
|
||||
goto err;
|
||||
|
||||
if (!strcmp(src, dst)) {
|
||||
fprintf(stderr, ERRMSG "source and destination are the same, aborting.");
|
||||
goto err;
|
||||
}
|
||||
|
||||
username = getuser();
|
||||
|
||||
/* 1. Regular ds copy */
|
||||
if (srcds && dstds) {
|
||||
/* Ensure the dst ds is writable */
|
||||
if (!dstds->rw) {
|
||||
fprintf(stderr, ERRMSG "not possible to write to \"%s\", skipping.\n", dst);
|
||||
rc = 1;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (sr_connect(SR_CONN_DEFAULT, &conn)) {
|
||||
fprintf(stderr, ERRMSG "connection to datastore failed\n");
|
||||
rc = 1;
|
||||
goto err;
|
||||
}
|
||||
|
||||
sr_log_syslog("klishd", SR_LL_WRN);
|
||||
|
||||
if (sr_session_start(conn, dstds->datastore, &sess)) {
|
||||
fprintf(stderr, ERRMSG "unable to open transaction to %s\n", dst);
|
||||
} else {
|
||||
sr_nacm_set_user(sess, username);
|
||||
rc = sr_copy_config(sess, NULL, srcds->datastore, 0);
|
||||
if (rc)
|
||||
emsg(sess, ERRMSG "unable to copy configuration, err %d: %s\n",
|
||||
rc, sr_strerror(rc));
|
||||
else
|
||||
set_owner(dstds->path, username);
|
||||
}
|
||||
rc = sr_disconnect(conn);
|
||||
|
||||
if (!srcds->path || !dstds->path)
|
||||
goto err; /* done, not an error */
|
||||
|
||||
/* allow copy factory startup */
|
||||
}
|
||||
|
||||
if (srcds) {
|
||||
/* 2. Export from a datastore somewhere else */
|
||||
if (strstr(dst, "://")) {
|
||||
if (srcds->path)
|
||||
fn = srcds->path;
|
||||
else {
|
||||
snprintf(adjust, sizeof(adjust), "/tmp/%s.cfg", srcds->name);
|
||||
fn = tmpfn = adjust;
|
||||
rc = systemf("sysrepocfg -d %s -X%s -f json", srcds->sysrepocfg, fn);
|
||||
}
|
||||
|
||||
if (rc)
|
||||
fprintf(stderr, ERRMSG "failed exporting %s to %s\n", src, fn);
|
||||
else {
|
||||
rc = systemf("curl %s -LT %s %s", user, fn, dst);
|
||||
if (rc)
|
||||
fprintf(stderr, ERRMSG "failed uploading %s to %s\n", src, dst);
|
||||
else
|
||||
set_owner(dst, username);
|
||||
}
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (dstds && dstds->path)
|
||||
fn = dstds->path;
|
||||
else
|
||||
fn = cfg_adjust(dst, src, adjust, sizeof(adjust));
|
||||
|
||||
if (!fn) {
|
||||
fprintf(stderr, ERRMSG "invalid destination path.\n");
|
||||
rc = -1;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (!access(fn, F_OK) && !yorn("Overwrite existing file %s", fn)) {
|
||||
fprintf(stderr, "OK, aborting.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (srcds->path)
|
||||
rc = systemf("cp %s %s", srcds->path, fn);
|
||||
else
|
||||
rc = systemf("sysrepocfg -d %s -X%s -f json", srcds->sysrepocfg, fn);
|
||||
if (rc)
|
||||
fprintf(stderr, ERRMSG "failed copy %s to %s\n", src, fn);
|
||||
else
|
||||
set_owner(fn, username);
|
||||
} else if (dstds) {
|
||||
if (!dstds->sysrepocfg) {
|
||||
fprintf(stderr, ERRMSG "not possible to import to this datastore.\n");
|
||||
rc = 1;
|
||||
goto err;
|
||||
}
|
||||
if (!dstds->rw) {
|
||||
fprintf(stderr, ERRMSG "not possible to write to %s", dst);
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* 3. Import from somewhere to a datastore */
|
||||
if (strstr(src, "://")) {
|
||||
tmpfn = mktemp(temp_file);
|
||||
fn = tmpfn;
|
||||
} else {
|
||||
fn = cfg_adjust(src, NULL, adjust, sizeof(adjust));
|
||||
if (!fn) {
|
||||
fprintf(stderr, ERRMSG "invalid source file location.\n");
|
||||
rc = 1;
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
if (tmpfn)
|
||||
rc = systemf("curl %s -Lo %s %s", user, fn, src);
|
||||
if (rc) {
|
||||
fprintf(stderr, ERRMSG "failed downloading %s", src);
|
||||
} else {
|
||||
rc = systemf("sysrepocfg -d %s -I%s -f json", dstds->sysrepocfg, fn);
|
||||
if (rc)
|
||||
fprintf(stderr, ERRMSG "failed loading %s from %s", dst, src);
|
||||
}
|
||||
} else {
|
||||
if (strstr(src, "://") && strstr(dst, "://")) {
|
||||
fprintf(stderr, ERRMSG "copy from remote to remote is not supported.\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (strstr(src, "://")) {
|
||||
fn = cfg_adjust(dst, src, adjust, sizeof(adjust));
|
||||
if (!fn) {
|
||||
fprintf(stderr, ERRMSG "invalid destination file location.\n");
|
||||
rc = 1;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (!access(fn, F_OK)) {
|
||||
if (!yorn("Overwrite existing file %s", fn)) {
|
||||
fprintf(stderr, "OK, aborting.\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
rc = systemf("curl %s -Lo %s %s", user, fn, src);
|
||||
} else if (strstr(dst, "://")) {
|
||||
fn = cfg_adjust(src, NULL, adjust, sizeof(adjust));
|
||||
if (!fn) {
|
||||
fprintf(stderr, ERRMSG "invalid source file location.\n");
|
||||
rc = 1;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (access(fn, F_OK))
|
||||
fprintf(stderr, ERRMSG "no such file %s, aborting.", fn);
|
||||
else
|
||||
rc = systemf("curl %s -LT %s %s", user, fn, dst);
|
||||
} else {
|
||||
if (!access(dst, F_OK)) {
|
||||
if (!yorn("Overwrite existing file %s", dst)) {
|
||||
fprintf(stderr, "OK, aborting.\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
rc = systemf("cp %s %s", src, dst);
|
||||
}
|
||||
}
|
||||
|
||||
err:
|
||||
if (tmpfn)
|
||||
rc = remove(tmpfn);
|
||||
|
||||
sync(); /* ensure command is flushed to disk */
|
||||
umask(oldmask);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int usage(int rc)
|
||||
{
|
||||
printf("Usage: %s [OPTIONS] SRC DST\n"
|
||||
"\n"
|
||||
"Options:\n"
|
||||
" -h This help text\n"
|
||||
" -u USER Username for remote commands, like scp\n"
|
||||
" -v Show version\n", prognm);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
const char *user = NULL, *src = NULL, *dst = NULL;
|
||||
int c;
|
||||
|
||||
while ((c = getopt(argc, argv, "hu:v")) != EOF) {
|
||||
switch(c) {
|
||||
case 'h':
|
||||
return usage(0);
|
||||
case 'u':
|
||||
user = optarg;
|
||||
break;
|
||||
case 'v':
|
||||
puts(PACKAGE_VERSION);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (optind >= argc)
|
||||
return usage(1);
|
||||
|
||||
src = argv[optind++];
|
||||
dst = argv[optind++];
|
||||
|
||||
return copy(src, dst, user);
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
/* SPDX-License-Identifier: ISC */
|
||||
#include "config.h"
|
||||
|
||||
#include <alloca.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "util.h"
|
||||
|
||||
static const char *prognm = "erase";
|
||||
|
||||
|
||||
static int do_erase(const char *path)
|
||||
{
|
||||
char *fn;
|
||||
|
||||
if (access(path, F_OK)) {
|
||||
size_t len = strlen(path) + 10;
|
||||
|
||||
fn = alloca(len);
|
||||
if (!fn) {
|
||||
fprintf(stderr, ERRMSG "failed allocating memory.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
cfg_adjust(path, NULL, fn, len);
|
||||
if (access(fn, F_OK)) {
|
||||
fprintf(stderr, "No such file: %s\n", fn);
|
||||
return -1;
|
||||
}
|
||||
} else
|
||||
fn = (char *)path;
|
||||
|
||||
if (!yorn("Remove %s, are you sure", fn))
|
||||
return 0;
|
||||
|
||||
if (remove(fn)) {
|
||||
fprintf(stderr, ERRMSG "failed removing %s: %s\n", fn, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int usage(int rc)
|
||||
{
|
||||
printf("Usage: %s [OPTIONS] PATH\n"
|
||||
"\n"
|
||||
"Options:\n"
|
||||
" -h This help text\n"
|
||||
" -v Show version\n", prognm);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int c;
|
||||
|
||||
while ((c = getopt(argc, argv, "hv")) != EOF) {
|
||||
switch(c) {
|
||||
case 'h':
|
||||
return usage(0);
|
||||
case 'v':
|
||||
puts(PACKAGE_VERSION);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (optind >= argc)
|
||||
return usage(1);
|
||||
|
||||
return do_erase(argv[optind++]);
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
/* SPDX-License-Identifier: ISC */
|
||||
#include "config.h"
|
||||
|
||||
#include <dirent.h>
|
||||
#include <getopt.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "util.h"
|
||||
|
||||
static const char *prognm = "files";
|
||||
|
||||
|
||||
int files(const char *path, const char *stripext)
|
||||
{
|
||||
const struct dirent *d;
|
||||
DIR *dir;
|
||||
|
||||
dir = opendir(path);
|
||||
if (!dir) {
|
||||
fprintf(stderr, ERRMSG "%s", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
while ((d = readdir(dir))) {
|
||||
char name[sizeof(d->d_name) + 1];
|
||||
|
||||
/* only list regular files, skip dirs and dotfiles */
|
||||
if (d->d_type != DT_REG || d->d_name[0] == '.')
|
||||
continue;
|
||||
|
||||
strlcpy(name, d->d_name, sizeof(name));
|
||||
if (stripext) {
|
||||
size_t pos = has_ext(name, stripext);
|
||||
|
||||
if (pos)
|
||||
name[pos] = 0;
|
||||
}
|
||||
|
||||
printf("%s\n", name);
|
||||
}
|
||||
|
||||
return closedir(dir);
|
||||
}
|
||||
|
||||
|
||||
static int usage(int rc)
|
||||
{
|
||||
printf("Usage: %s [OPTIONS] PATH [EXT]\n"
|
||||
"\n"
|
||||
"Options:\n"
|
||||
" -h This help text\n"
|
||||
" -v Show version\n", prognm);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
const char *path = NULL, *ext = NULL;
|
||||
int c;
|
||||
|
||||
while ((c = getopt(argc, argv, "hv")) != EOF) {
|
||||
switch(c) {
|
||||
case 'h':
|
||||
return usage(0);
|
||||
case 'v':
|
||||
puts(PACKAGE_VERSION);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (optind >= argc)
|
||||
return usage(1);
|
||||
|
||||
path = argv[optind++];
|
||||
if (optind < argc)
|
||||
ext = argv[optind++];
|
||||
|
||||
return files(path, ext);
|
||||
}
|
||||
+115
@@ -0,0 +1,115 @@
|
||||
/* SPDX-License-Identifier: ISC */
|
||||
#include "config.h"
|
||||
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <termios.h>
|
||||
|
||||
#include "util.h"
|
||||
|
||||
|
||||
static char rawgetch(void)
|
||||
{
|
||||
struct termios saved, c;
|
||||
char key;
|
||||
|
||||
if (tcgetattr(fileno(stdin), &saved) < 0)
|
||||
return -1;
|
||||
|
||||
c = saved;
|
||||
c.c_lflag &= ~ICANON;
|
||||
c.c_lflag &= ~ECHO;
|
||||
c.c_cc[VMIN] = 1;
|
||||
c.c_cc[VTIME] = 0;
|
||||
|
||||
if (tcsetattr(fileno(stdin), TCSANOW, &c) < 0) {
|
||||
tcsetattr(fileno(stdin), TCSANOW, &saved);
|
||||
return -1;
|
||||
}
|
||||
|
||||
key = getchar();
|
||||
tcsetattr(fileno(stdin), TCSANOW, &saved);
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
int yorn(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
char ch;
|
||||
|
||||
va_start(ap, fmt);
|
||||
vfprintf(stderr, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
fprintf(stderr, " (y/N)? ");
|
||||
ch = rawgetch();
|
||||
fprintf(stderr, "%c\n", ch);
|
||||
if (ch != 'y' && ch != 'Y')
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int has_ext(const char *fn, const char *ext)
|
||||
{
|
||||
size_t pos = strlen(fn);
|
||||
size_t len = strlen(ext);
|
||||
|
||||
if (len < pos && !strcmp(&fn[pos - len], ext))
|
||||
return pos - len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char *basenm(const char *fn)
|
||||
{
|
||||
const char *ptr;
|
||||
|
||||
if (!fn)
|
||||
return "";
|
||||
|
||||
ptr = strrchr(fn, '/');
|
||||
if (!ptr)
|
||||
ptr = fn;
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
char *cfg_adjust(const char *fn, const char *tmpl, char *buf, size_t len)
|
||||
{
|
||||
if (strstr(fn, "../"))
|
||||
return NULL; /* relative paths not allowed */
|
||||
|
||||
if (fn[0] == '/') {
|
||||
strlcpy(buf, fn, len);
|
||||
return buf; /* allow absolute paths */
|
||||
}
|
||||
|
||||
/* Files in /cfg must end in .cfg */
|
||||
if (!strncmp(fn, "/cfg/", 5)) {
|
||||
strlcpy(buf, fn, len);
|
||||
if (!has_ext(fn, ".cfg"))
|
||||
strlcat(buf, ".cfg", len);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
/* Files ending with .cfg belong in /cfg */
|
||||
if (has_ext(fn, ".cfg")) {
|
||||
snprintf(buf, len, "/cfg/%s", fn);
|
||||
return buf;
|
||||
}
|
||||
|
||||
if (strlen(fn) > 0 && fn[0] == '.' && tmpl) {
|
||||
if (fn[1] == '/' && fn[2] != 0)
|
||||
strlcpy(buf, fn, len);
|
||||
else
|
||||
strlcpy(buf, basenm(tmpl), len);
|
||||
} else
|
||||
strlcpy(buf, fn, len);
|
||||
|
||||
return buf;
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
/* SPDX-License-Identifier: ISC */
|
||||
#ifndef BIN_UTIL_H_
|
||||
#define BIN_UTIL_H_
|
||||
#include <stdio.h>
|
||||
#include <libite/lite.h>
|
||||
|
||||
#define ERRMSG "Error: "
|
||||
#define INFMSG "Note: "
|
||||
|
||||
int yorn (const char *fmt, ...);
|
||||
|
||||
int files (const char *path, const char *stripext);
|
||||
|
||||
int has_ext (const char *fn, const char *ext);
|
||||
char *cfg_adjust (const char *fn, const char *tmpl, char *buf, size_t len);
|
||||
|
||||
#endif /* BIN_UTIL_H_ */
|
||||
@@ -1,12 +1,9 @@
|
||||
#include <assert.h>
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <pwd.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <termios.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
@@ -31,22 +28,6 @@
|
||||
const uint8_t kplugin_infix_major = 1;
|
||||
const uint8_t kplugin_infix_minor = 0;
|
||||
|
||||
struct infix_ds {
|
||||
char *name; /* startup-config, etc. */
|
||||
char *sysrepocfg; /* ds name in sysrepocfg */
|
||||
int datastore; /* sr_datastore_t and -1 */
|
||||
int rw; /* read-write:1 or not:0 */
|
||||
char *path; /* local path or NULL */
|
||||
};
|
||||
|
||||
struct infix_ds infix_config[] = {
|
||||
{ "startup-config", "startup", SR_DS_STARTUP, 1, "/cfg/startup-config.cfg" },
|
||||
{ "running-config", "running", SR_DS_RUNNING, 1, NULL },
|
||||
{ "candidate-config", "candidate", SR_DS_CANDIDATE, 1, NULL },
|
||||
{ "operational-config", "operational", SR_DS_OPERATIONAL, 1, NULL },
|
||||
{ "factory-config", "factory-default", SR_DS_FACTORY_DEFAULT, 0, NULL }
|
||||
};
|
||||
|
||||
static void cd_home(kcontext_t *ctx)
|
||||
{
|
||||
const char *user = "root";
|
||||
@@ -64,123 +45,6 @@ static void cd_home(kcontext_t *ctx)
|
||||
chdir(pw->pw_dir);
|
||||
}
|
||||
|
||||
static void set_owner(const char *fn, const char *user)
|
||||
{
|
||||
struct passwd *pw;
|
||||
|
||||
pw = getpwnam(user);
|
||||
if (!pw) {
|
||||
fprintf(stderr, ERRMSG "setting owner %s on %s: %s\n", fn, user, strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
chmod(fn, 0660);
|
||||
chown(fn, pw->pw_uid, pw->pw_gid);
|
||||
}
|
||||
|
||||
static int has_ext(const char *fn, const char *ext)
|
||||
{
|
||||
size_t pos = strlen(fn);
|
||||
size_t len = strlen(ext);
|
||||
|
||||
if (len < pos && !strcmp(&fn[pos - len], ext))
|
||||
return pos - len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char *basenm(const char *fn)
|
||||
{
|
||||
const char *ptr;
|
||||
|
||||
if (!fn)
|
||||
return "";
|
||||
|
||||
ptr = strrchr(fn, '/');
|
||||
if (!ptr)
|
||||
ptr = fn;
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
static char *cfg_adjust(const char *fn, const char *tmpl, char *buf, size_t len)
|
||||
{
|
||||
if (strstr(fn, "../"))
|
||||
return NULL; /* relative paths not allowed */
|
||||
|
||||
if (fn[0] == '/') {
|
||||
strncpy(buf, fn, len);
|
||||
return buf; /* allow absolute paths */
|
||||
}
|
||||
|
||||
/* Files in /cfg must end in .cfg */
|
||||
if (!strncmp(fn, "/cfg/", 5)) {
|
||||
snprintf(buf, len, "%s", fn);
|
||||
if (!has_ext(fn, ".cfg"))
|
||||
strcat(buf, ".cfg");
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
/* Files ending with .cfg belong in /cfg */
|
||||
if (has_ext(fn, ".cfg")) {
|
||||
snprintf(buf, len, "/cfg/%s", fn);
|
||||
return buf;
|
||||
}
|
||||
|
||||
if (strlen(fn) > 0 && fn[0] == '.' && tmpl) {
|
||||
if (fn[1] == '/' && fn[1] != 0)
|
||||
strncpy(buf, fn, len);
|
||||
else
|
||||
snprintf(buf, len, "%s", basenm(tmpl));
|
||||
} else
|
||||
strncpy(buf, fn, len);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
static char rawgetch(void)
|
||||
{
|
||||
struct termios saved, c;
|
||||
char key;
|
||||
|
||||
if (tcgetattr(fileno(stdin), &saved) < 0)
|
||||
return -1;
|
||||
|
||||
c = saved;
|
||||
c.c_lflag &= ~ICANON;
|
||||
c.c_lflag &= ~ECHO;
|
||||
c.c_cc[VMIN] = 1;
|
||||
c.c_cc[VTIME] = 0;
|
||||
|
||||
if (tcsetattr(fileno(stdin), TCSANOW, &c) < 0) {
|
||||
tcsetattr(fileno(stdin), TCSANOW, &saved);
|
||||
return -1;
|
||||
}
|
||||
|
||||
key = getchar();
|
||||
tcsetattr(fileno(stdin), TCSANOW, &saved);
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
static int yorn(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
char ch;
|
||||
|
||||
va_start(ap, fmt);
|
||||
vfprintf(stderr, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
fprintf(stderr, " (y/N)? ");
|
||||
ch = rawgetch();
|
||||
fprintf(stderr, "%c\n", ch);
|
||||
if (ch != 'y' && ch != 'Y')
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int systemf(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
@@ -219,68 +83,6 @@ static int systemf(const char *fmt, ...)
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* Print sysrepo session errors followed by an optional string.
|
||||
*/
|
||||
static void emsg(sr_session_ctx_t *sess, const char *fmt, ...)
|
||||
{
|
||||
const sr_error_info_t *err = NULL;
|
||||
va_list ap;
|
||||
size_t i;
|
||||
int rc;
|
||||
|
||||
if (!sess)
|
||||
goto end;
|
||||
|
||||
rc = sr_session_get_error(sess, &err);
|
||||
if ((rc != SR_ERR_OK) || !err)
|
||||
goto end;
|
||||
|
||||
// Show the first error only. Because probably next errors are
|
||||
// originated from internal sysrepo code but is not from subscribers.
|
||||
// for (i = 0; i < err->err_count; i++)
|
||||
for (i = 0; i < (err->err_count < 1 ? err->err_count : 1); i++)
|
||||
fprintf(stderr, ERRMSG "%s\n", err->err[i].message);
|
||||
end:
|
||||
if (fmt) {
|
||||
va_start(ap, fmt);
|
||||
vfprintf(stderr, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
}
|
||||
|
||||
static int files(const char *path, const char *stripext)
|
||||
{
|
||||
struct dirent *d;
|
||||
DIR *dir;
|
||||
|
||||
dir = opendir(path);
|
||||
if (!dir) {
|
||||
fprintf(stderr, ERRMSG "%s", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
while ((d = readdir(dir))) {
|
||||
char name[sizeof(d->d_name) + 1];
|
||||
|
||||
/* only list regular files, skip dirs and dotfiles */
|
||||
if (d->d_type != DT_REG || d->d_name[0] == '.')
|
||||
continue;
|
||||
|
||||
strncpy(name, d->d_name, sizeof(name));
|
||||
if (stripext) {
|
||||
size_t pos = has_ext(name, stripext);
|
||||
|
||||
if (pos)
|
||||
name[pos] = 0;
|
||||
}
|
||||
|
||||
printf("%s\n", name);
|
||||
}
|
||||
|
||||
return closedir(dir);
|
||||
}
|
||||
|
||||
int infix_datastore(kcontext_t *ctx)
|
||||
{
|
||||
const char *ds;
|
||||
@@ -300,14 +102,13 @@ int infix_datastore(kcontext_t *ctx)
|
||||
}
|
||||
|
||||
done:
|
||||
return files("/cfg", ".cfg");
|
||||
return systemf("files /cfg .cfg");
|
||||
}
|
||||
|
||||
int infix_erase(kcontext_t *ctx)
|
||||
{
|
||||
kpargv_t *pargv = kcontext_pargv(ctx);
|
||||
const char *path;
|
||||
char *fn;
|
||||
|
||||
path = kparg_value(kpargv_find(pargv, "file"));
|
||||
if (!path) {
|
||||
@@ -316,32 +117,8 @@ int infix_erase(kcontext_t *ctx)
|
||||
}
|
||||
|
||||
cd_home(ctx);
|
||||
if (access(path, F_OK)) {
|
||||
size_t len = strlen(path) + 10;
|
||||
|
||||
fn = alloca(len);
|
||||
if (!fn) {
|
||||
fprintf(stderr, ERRMSG "failed allocating memory.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
cfg_adjust(path, NULL, fn, len);
|
||||
if (access(fn, F_OK)) {
|
||||
fprintf(stderr, "No such file: %s\n", fn);
|
||||
return -1;
|
||||
}
|
||||
} else
|
||||
fn = (char *)path;
|
||||
|
||||
if (!yorn("Remove %s, are you sure", fn))
|
||||
return 0;
|
||||
|
||||
if (remove(fn)) {
|
||||
fprintf(stderr, ERRMSG "failed removing %s: %s\n", fn, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return systemf("erase %s", path);
|
||||
}
|
||||
|
||||
int infix_files(kcontext_t *ctx)
|
||||
@@ -355,7 +132,7 @@ int infix_files(kcontext_t *ctx)
|
||||
return -1;
|
||||
}
|
||||
|
||||
return files(path, NULL);
|
||||
return systemf("files %s", path);
|
||||
}
|
||||
|
||||
int infix_ifaces(kcontext_t *ctx)
|
||||
@@ -365,228 +142,27 @@ int infix_ifaces(kcontext_t *ctx)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char *infix_ds(const char *text, const char *type, struct infix_ds **ds)
|
||||
{
|
||||
size_t i, len = strlen(text);
|
||||
|
||||
for (i = 0; i < NELEMS(infix_config); i++) {
|
||||
if (!strncmp(infix_config[i].name, text, len)) {
|
||||
*ds = &infix_config[i];
|
||||
return infix_config[i].name;
|
||||
}
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
int infix_copy(kcontext_t *ctx)
|
||||
{
|
||||
struct infix_ds *srcds = NULL, *dstds = NULL;
|
||||
char temp_file[20] = "/tmp/copy.XXXXXX";
|
||||
kpargv_t *pargv = kcontext_pargv(ctx);
|
||||
const char *tmpfn = NULL;
|
||||
sr_session_ctx_t *sess;
|
||||
const char *fn = NULL;
|
||||
const char *src, *dst;
|
||||
const char *username;
|
||||
sr_conn_ctx_t *conn;
|
||||
char user[256] = "";
|
||||
char adjust[256];
|
||||
kparg_t *parg;
|
||||
int rc = 0;
|
||||
|
||||
src = kparg_value(kpargv_find(pargv, "src"));
|
||||
dst = kparg_value(kpargv_find(pargv, "dst"));
|
||||
if (!src || !dst)
|
||||
goto err;
|
||||
return -1;
|
||||
|
||||
parg = kpargv_find(pargv, "user");
|
||||
if (parg)
|
||||
snprintf(user, sizeof(user), "-u %s", kparg_value(parg));
|
||||
|
||||
src = infix_ds(src, "source", &srcds);
|
||||
if (!src)
|
||||
goto err;
|
||||
dst = infix_ds(dst, "destination", &dstds);
|
||||
if (!dst)
|
||||
goto err;
|
||||
|
||||
if (!strcmp(src, dst)) {
|
||||
fprintf(stderr, ERRMSG "source and destination are the same, aborting.");
|
||||
goto err;
|
||||
}
|
||||
|
||||
cd_home(ctx);
|
||||
username = ksession_user(kcontext_session(ctx));
|
||||
umask(0660);
|
||||
|
||||
/* 1. Regular ds copy */
|
||||
if (srcds && dstds) {
|
||||
/* Ensure the dst ds is writable */
|
||||
if (!dstds->rw) {
|
||||
fprintf(stderr, ERRMSG "not possible to write to \"%s\", skipping.\n", dst);
|
||||
rc = 1;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (sr_connect(SR_CONN_DEFAULT, &conn)) {
|
||||
fprintf(stderr, ERRMSG "connection to datastore failed\n");
|
||||
rc = 1;
|
||||
goto err;
|
||||
}
|
||||
|
||||
sr_log_syslog("klishd", SR_LL_WRN);
|
||||
|
||||
if (sr_session_start(conn, dstds->datastore, &sess)) {
|
||||
fprintf(stderr, ERRMSG "unable to open transaction to %s\n", dst);
|
||||
} else {
|
||||
sr_nacm_set_user(sess, username);
|
||||
rc = sr_copy_config(sess, NULL, srcds->datastore, 0);
|
||||
if (rc)
|
||||
emsg(sess, ERRMSG "unable to copy configuration, err %d: %s\n",
|
||||
rc, sr_strerror(rc));
|
||||
else
|
||||
set_owner(dstds->path, username);
|
||||
}
|
||||
rc = sr_disconnect(conn);
|
||||
|
||||
if (!srcds->path || !dstds->path)
|
||||
goto err; /* done, not an error */
|
||||
|
||||
/* allow copy factory startup */
|
||||
}
|
||||
|
||||
if (srcds) {
|
||||
/* 2. Export from a datastore somewhere else */
|
||||
if (strstr(dst, "://")) {
|
||||
if (srcds->path)
|
||||
fn = srcds->path;
|
||||
else {
|
||||
snprintf(adjust, sizeof(adjust), "/tmp/%s.cfg", srcds->name);
|
||||
fn = tmpfn = adjust;
|
||||
rc = systemf("sysrepocfg -d %s -X%s -f json", srcds->sysrepocfg, fn);
|
||||
}
|
||||
|
||||
if (rc)
|
||||
fprintf(stderr, ERRMSG "failed exporting %s to %s\n", src, fn);
|
||||
else {
|
||||
rc = systemf("curl %s -LT %s %s", user, fn, dst);
|
||||
if (rc)
|
||||
fprintf(stderr, ERRMSG "failed uploading %s to %s\n", src, dst);
|
||||
else
|
||||
set_owner(dst, username);
|
||||
}
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (dstds && dstds->path)
|
||||
fn = dstds->path;
|
||||
else
|
||||
fn = cfg_adjust(dst, src, adjust, sizeof(adjust));
|
||||
|
||||
if (!fn) {
|
||||
fprintf(stderr, ERRMSG "invalid destination path.\n");
|
||||
rc = -1;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (!access(fn, F_OK) && !yorn("Overwrite existing file %s", fn)) {
|
||||
fprintf(stderr, "OK, aborting.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (srcds->path)
|
||||
rc = systemf("cp %s %s", srcds->path, fn);
|
||||
else
|
||||
rc = systemf("sysrepocfg -d %s -X%s -f json", srcds->sysrepocfg, fn);
|
||||
if (rc)
|
||||
fprintf(stderr, ERRMSG "failed copy %s to %s\n", src, fn);
|
||||
else
|
||||
set_owner(fn, username);
|
||||
} else if (dstds) {
|
||||
if (!dstds->sysrepocfg) {
|
||||
fprintf(stderr, ERRMSG "not possible to import to this datastore.\n");
|
||||
rc = 1;
|
||||
goto err;
|
||||
}
|
||||
if (!dstds->rw) {
|
||||
fprintf(stderr, ERRMSG "not possible to write to %s", dst);
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* 3. Import from somewhere to a datastore */
|
||||
if (strstr(src, "://")) {
|
||||
tmpfn = mktemp(temp_file);
|
||||
fn = tmpfn;
|
||||
} else {
|
||||
fn = cfg_adjust(src, NULL, adjust, sizeof(adjust));
|
||||
if (!fn) {
|
||||
fprintf(stderr, ERRMSG "invalid source file location.\n");
|
||||
rc = 1;
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
if (tmpfn)
|
||||
rc = systemf("curl %s -Lo %s %s", user, fn, src);
|
||||
if (rc) {
|
||||
fprintf(stderr, ERRMSG "failed downloading %s", src);
|
||||
} else {
|
||||
rc = systemf("sysrepocfg -d %s -I%s -f json", dstds->sysrepocfg, fn);
|
||||
if (rc)
|
||||
fprintf(stderr, ERRMSG "failed loading %s from %s", dst, src);
|
||||
}
|
||||
} else {
|
||||
if (strstr(src, "://") && strstr(dst, "://")) {
|
||||
fprintf(stderr, ERRMSG "copy from remote to remote is not supported.\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (strstr(src, "://")) {
|
||||
fn = cfg_adjust(dst, src, adjust, sizeof(adjust));
|
||||
if (!fn) {
|
||||
fprintf(stderr, ERRMSG "invalid destination file location.\n");
|
||||
rc = 1;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (!access(fn, F_OK)) {
|
||||
if (!yorn("Overwrite existing file %s", fn)) {
|
||||
fprintf(stderr, "OK, aborting.\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
rc = systemf("curl %s -Lo %s %s", user, fn, src);
|
||||
} else if (strstr(dst, "://")) {
|
||||
fn = cfg_adjust(src, NULL, adjust, sizeof(adjust));
|
||||
if (!fn) {
|
||||
fprintf(stderr, ERRMSG "invalid source file location.\n");
|
||||
rc = 1;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (access(fn, F_OK))
|
||||
fprintf(stderr, ERRMSG "no such file %s, aborting.", fn);
|
||||
else
|
||||
rc = systemf("curl %s -LT %s %s", user, fn, dst);
|
||||
} else {
|
||||
if (!access(dst, F_OK)) {
|
||||
if (!yorn("Overwrite existing file %s", dst)) {
|
||||
fprintf(stderr, "OK, aborting.\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
rc = systemf("cp %s %s", src, dst);
|
||||
}
|
||||
}
|
||||
|
||||
err:
|
||||
if (tmpfn)
|
||||
rc = remove(tmpfn);
|
||||
sync(); /* ensure command is flushed to disk */
|
||||
|
||||
return rc;
|
||||
return systemf("sudo -u %s copy %s %s %s", username, user, src, dst);
|
||||
}
|
||||
|
||||
int infix_shell(kcontext_t *ctx)
|
||||
|
||||
Reference in New Issue
Block a user