Implement support to "preserve" existent on-disk files.
See NEWS for more information. Fix #51
This commit is contained in:
parent
fa960c2425
commit
f8d8f91a08
15
NEWS
15
NEWS
@ -1,5 +1,20 @@
|
|||||||
xbps-0.38 (???):
|
xbps-0.38 (???):
|
||||||
|
|
||||||
|
* Implemented support to preserve existent on-disk files, by always ignoring
|
||||||
|
the pkg content if the file has been matched. Details here:
|
||||||
|
https://github.com/voidlinux/xbps/issues/51
|
||||||
|
|
||||||
|
The new "preserve" keyword can be used in the xbps configuration file, as well
|
||||||
|
as for the system and configuration directories:
|
||||||
|
|
||||||
|
- <rootdir>/usr/share/xbps/preserve.d
|
||||||
|
- <rootdir>/etc/xbps/preserve.d
|
||||||
|
|
||||||
|
Full path to a file or globbing can be used:
|
||||||
|
|
||||||
|
- preserve=/usr/bin/blah
|
||||||
|
- preserve=/etc/blah/*.conf
|
||||||
|
|
||||||
* Always preserve files that exist on disk, but are managed by a package.
|
* Always preserve files that exist on disk, but are managed by a package.
|
||||||
When such condition ocurrs install the pkg configuration file as `file.new-<version>`.
|
When such condition ocurrs install the pkg configuration file as `file.new-<version>`.
|
||||||
This fixes GH issue #50 https://github.com/voidlinux/xbps/issues/50.
|
This fixes GH issue #50 https://github.com/voidlinux/xbps/issues/50.
|
||||||
|
@ -208,7 +208,7 @@ rcv_init(rcv_t *rcv, const char *prog)
|
|||||||
rcv->have_vars = 0;
|
rcv->have_vars = 0;
|
||||||
rcv->ptr = rcv->input = NULL;
|
rcv->ptr = rcv->input = NULL;
|
||||||
if (rcv->xbps_conf != NULL)
|
if (rcv->xbps_conf != NULL)
|
||||||
rcv->xhp.conffile = rcv->xbps_conf;
|
strncpy(rcv->xhp.conffile, rcv->xbps_conf, sizeof(rcv->xhp.conffile));
|
||||||
if (rcv->rootdir != NULL)
|
if (rcv->rootdir != NULL)
|
||||||
strncpy(rcv->xhp.rootdir, rcv->rootdir, sizeof(rcv->xhp.rootdir));
|
strncpy(rcv->xhp.rootdir, rcv->rootdir, sizeof(rcv->xhp.rootdir));
|
||||||
xbps_init(&rcv->xhp);
|
xbps_init(&rcv->xhp);
|
||||||
|
@ -190,7 +190,8 @@ main(int argc, char **argv)
|
|||||||
strncpy(xh.rootdir, rootdir, sizeof(xh.rootdir));
|
strncpy(xh.rootdir, rootdir, sizeof(xh.rootdir));
|
||||||
if (cachedir)
|
if (cachedir)
|
||||||
strncpy(xh.cachedir, cachedir, sizeof(xh.cachedir));
|
strncpy(xh.cachedir, cachedir, sizeof(xh.cachedir));
|
||||||
xh.conffile = conffile;
|
if (conffile)
|
||||||
|
strncpy(xh.conffile, conffile, sizeof(xh.conffile));
|
||||||
xh.flags = flags;
|
xh.flags = flags;
|
||||||
if (flags & XBPS_FLAG_VERBOSE)
|
if (flags & XBPS_FLAG_VERBOSE)
|
||||||
xh.unpack_cb = unpack_progress_cb;
|
xh.unpack_cb = unpack_progress_cb;
|
||||||
|
@ -136,6 +136,9 @@ state_cb(struct xbps_state_cb_data *xscd, void *cbdata _unused)
|
|||||||
case XBPS_STATE_SHOW_INSTALL_MSG:
|
case XBPS_STATE_SHOW_INSTALL_MSG:
|
||||||
printf("%s: post-install message:\n%s", xscd->arg, xscd->desc);
|
printf("%s: post-install message:\n%s", xscd->arg, xscd->desc);
|
||||||
break;
|
break;
|
||||||
|
case XBPS_STATE_UNPACK_FILE_PRESERVED:
|
||||||
|
printf("%s\n", xscd->desc);
|
||||||
|
break;
|
||||||
/* errors */
|
/* errors */
|
||||||
case XBPS_STATE_UNPACK_FAIL:
|
case XBPS_STATE_UNPACK_FAIL:
|
||||||
case XBPS_STATE_UPDATE_FAIL:
|
case XBPS_STATE_UPDATE_FAIL:
|
||||||
|
@ -137,7 +137,8 @@ main(int argc, char **argv)
|
|||||||
memset(&xh, 0, sizeof(xh));
|
memset(&xh, 0, sizeof(xh));
|
||||||
if (rootdir)
|
if (rootdir)
|
||||||
strncpy(xh.rootdir, rootdir, sizeof(xh.rootdir));
|
strncpy(xh.rootdir, rootdir, sizeof(xh.rootdir));
|
||||||
xh.conffile = conffile;
|
if (conffile)
|
||||||
|
strncpy(xh.conffile, conffile, sizeof(xh.conffile));
|
||||||
xh.flags = flags;
|
xh.flags = flags;
|
||||||
|
|
||||||
if ((rv = xbps_init(&xh)) != 0) {
|
if ((rv = xbps_init(&xh)) != 0) {
|
||||||
|
@ -213,7 +213,9 @@ main(int argc, char **argv)
|
|||||||
strncpy(xh.rootdir, rootdir, sizeof(xh.rootdir));
|
strncpy(xh.rootdir, rootdir, sizeof(xh.rootdir));
|
||||||
if (cachedir)
|
if (cachedir)
|
||||||
strncpy(xh.cachedir, cachedir, sizeof(xh.cachedir));
|
strncpy(xh.cachedir, cachedir, sizeof(xh.cachedir));
|
||||||
xh.conffile = conffile;
|
if (conffile)
|
||||||
|
strncpy(xh.conffile, conffile, sizeof(xh.conffile));
|
||||||
|
|
||||||
xh.flags = flags;
|
xh.flags = flags;
|
||||||
|
|
||||||
if ((rv = xbps_init(&xh)) != 0) {
|
if ((rv = xbps_init(&xh)) != 0) {
|
||||||
|
@ -147,7 +147,9 @@ main(int argc, char **argv)
|
|||||||
xh.state_cb = state_cb;
|
xh.state_cb = state_cb;
|
||||||
if (rootdir)
|
if (rootdir)
|
||||||
strncpy(xh.rootdir, rootdir, sizeof(xh.rootdir));
|
strncpy(xh.rootdir, rootdir, sizeof(xh.rootdir));
|
||||||
xh.conffile = conffile;
|
if (conffile)
|
||||||
|
strncpy(xh.conffile, conffile, sizeof(xh.conffile));
|
||||||
|
|
||||||
xh.flags = flags;
|
xh.flags = flags;
|
||||||
|
|
||||||
if ((rv = xbps_init(&xh)) != 0) {
|
if ((rv = xbps_init(&xh)) != 0) {
|
||||||
|
@ -251,7 +251,9 @@ main(int argc, char **argv)
|
|||||||
strncpy(xh.rootdir, rootdir, sizeof(xh.rootdir));
|
strncpy(xh.rootdir, rootdir, sizeof(xh.rootdir));
|
||||||
if (cachedir)
|
if (cachedir)
|
||||||
strncpy(xh.cachedir, cachedir, sizeof(xh.cachedir));
|
strncpy(xh.cachedir, cachedir, sizeof(xh.cachedir));
|
||||||
xh.conffile = conffile;
|
if (conffile)
|
||||||
|
strncpy(xh.conffile, conffile, sizeof(xh.conffile));
|
||||||
|
|
||||||
xh.flags = flags;
|
xh.flags = flags;
|
||||||
|
|
||||||
if ((rv = xbps_init(&xh)) != 0) {
|
if ((rv = xbps_init(&xh)) != 0) {
|
||||||
|
@ -87,14 +87,14 @@ main(int argc, char **argv)
|
|||||||
xbps_dictionary_t dict;
|
xbps_dictionary_t dict;
|
||||||
struct xbps_handle xh;
|
struct xbps_handle xh;
|
||||||
struct xferstat xfer;
|
struct xferstat xfer;
|
||||||
const char *version, *rootdir = NULL, *confdir = NULL;
|
const char *version, *rootdir = NULL, *conffile = NULL;
|
||||||
char *pkgname, *hash, *sep;
|
char *pkgname, *hash, *sep;
|
||||||
int flags = 0, c, rv = 0;
|
int flags = 0, c, rv = 0;
|
||||||
|
|
||||||
while ((c = getopt(argc, argv, "C:dr:V")) != -1) {
|
while ((c = getopt(argc, argv, "C:dr:V")) != -1) {
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case 'C':
|
case 'C':
|
||||||
confdir = optarg;
|
conffile = optarg;
|
||||||
break;
|
break;
|
||||||
case 'r':
|
case 'r':
|
||||||
/* To specify the root directory */
|
/* To specify the root directory */
|
||||||
@ -131,7 +131,8 @@ main(int argc, char **argv)
|
|||||||
xh.fetch_cb_data = &xfer;
|
xh.fetch_cb_data = &xfer;
|
||||||
if (rootdir)
|
if (rootdir)
|
||||||
strncpy(xh.rootdir, rootdir, sizeof(xh.rootdir));
|
strncpy(xh.rootdir, rootdir, sizeof(xh.rootdir));
|
||||||
xh.conffile = confdir;
|
if (conffile)
|
||||||
|
strncpy(xh.conffile, conffile, sizeof(xh.conffile));
|
||||||
if ((rv = xbps_init(&xh)) != 0) {
|
if ((rv = xbps_init(&xh)) != 0) {
|
||||||
xbps_error_printf("xbps-uhelper: failed to "
|
xbps_error_printf("xbps-uhelper: failed to "
|
||||||
"initialize libxbps: %s.\n", strerror(rv));
|
"initialize libxbps: %s.\n", strerror(rv));
|
||||||
|
@ -48,7 +48,7 @@
|
|||||||
*
|
*
|
||||||
* This header documents the full API for the XBPS Library.
|
* This header documents the full API for the XBPS Library.
|
||||||
*/
|
*/
|
||||||
#define XBPS_API_VERSION "20140727"
|
#define XBPS_API_VERSION "20140801"
|
||||||
|
|
||||||
#ifndef XBPS_VERSION
|
#ifndef XBPS_VERSION
|
||||||
#define XBPS_VERSION "UNSET"
|
#define XBPS_VERSION "UNSET"
|
||||||
@ -112,6 +112,18 @@
|
|||||||
*/
|
*/
|
||||||
#define XBPS_SYS_REPOD_PATH XBPS_SYSDEFCONF_PATH "/repo.d"
|
#define XBPS_SYS_REPOD_PATH XBPS_SYSDEFCONF_PATH "/repo.d"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @def XBPS_PRESERVED_PATH
|
||||||
|
* Configuration directory to store preserve configuration files.
|
||||||
|
*/
|
||||||
|
#define XBPS_PRESERVED_PATH XBPS_SYSCONF_PATH "/preserve.d"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @def XBPS_SYS_PRESERVED_PATH
|
||||||
|
* System directory to store preserve configuration files.
|
||||||
|
*/
|
||||||
|
#define XBPS_SYS_PRESERVED_PATH XBPS_SYSDEFCONF_PATH "/preserve.d"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @def XBPS_PKGDB
|
* @def XBPS_PKGDB
|
||||||
* Filename for the package database.
|
* Filename for the package database.
|
||||||
@ -278,6 +290,7 @@ extern "C" {
|
|||||||
* - XBPS_STATE_INVALID_DEP: package has an invalid dependency.
|
* - XBPS_STATE_INVALID_DEP: package has an invalid dependency.
|
||||||
* - XBPS_STATE_SHOW_INSTALL_MSG: package must show a post-install message.
|
* - XBPS_STATE_SHOW_INSTALL_MSG: package must show a post-install message.
|
||||||
* - XBPS_STATE_SHOW_REMOVE_MSG: package must show a pre-remove message.
|
* - XBPS_STATE_SHOW_REMOVE_MSG: package must show a pre-remove message.
|
||||||
|
* - XBPS_STATE_UNPACK_FILE_PRESERVED: package unpack preserved a file.
|
||||||
*/
|
*/
|
||||||
typedef enum xbps_state {
|
typedef enum xbps_state {
|
||||||
XBPS_STATE_UNKNOWN = 0,
|
XBPS_STATE_UNKNOWN = 0,
|
||||||
@ -319,7 +332,8 @@ typedef enum xbps_state {
|
|||||||
XBPS_STATE_REPO_KEY_IMPORT,
|
XBPS_STATE_REPO_KEY_IMPORT,
|
||||||
XBPS_STATE_INVALID_DEP,
|
XBPS_STATE_INVALID_DEP,
|
||||||
XBPS_STATE_SHOW_INSTALL_MSG,
|
XBPS_STATE_SHOW_INSTALL_MSG,
|
||||||
XBPS_STATE_SHOW_REMOVE_MSG
|
XBPS_STATE_SHOW_REMOVE_MSG,
|
||||||
|
XBPS_STATE_UNPACK_FILE_PRESERVED
|
||||||
} xbps_state_t;
|
} xbps_state_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -492,6 +506,7 @@ struct xbps_handle {
|
|||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
|
xbps_array_t preserved_files;
|
||||||
xbps_dictionary_t pkg_metad;
|
xbps_dictionary_t pkg_metad;
|
||||||
xbps_dictionary_t pkgdb_revdeps;
|
xbps_dictionary_t pkgdb_revdeps;
|
||||||
xbps_dictionary_t vpkgd;
|
xbps_dictionary_t vpkgd;
|
||||||
@ -558,18 +573,18 @@ struct xbps_handle {
|
|||||||
* the \a xbps_fetch_cb function callback.
|
* the \a xbps_fetch_cb function callback.
|
||||||
*/
|
*/
|
||||||
void *fetch_cb_data;
|
void *fetch_cb_data;
|
||||||
/**
|
|
||||||
* @var conffile
|
|
||||||
*
|
|
||||||
* Full path to the xbps configuration file.
|
|
||||||
*/
|
|
||||||
const char *conffile;
|
|
||||||
/**
|
/**
|
||||||
* @var target_arch
|
* @var target_arch
|
||||||
*
|
*
|
||||||
* Target architecture, as set by XBPS_TARGET_ARCH from environment.
|
* Target architecture, as set by XBPS_TARGET_ARCH from environment.
|
||||||
*/
|
*/
|
||||||
const char *target_arch;
|
const char *target_arch;
|
||||||
|
/**
|
||||||
|
* @var conffile
|
||||||
|
*
|
||||||
|
* Full path to the xbps configuration file.
|
||||||
|
*/
|
||||||
|
char conffile[XBPS_MAXPATH-1];
|
||||||
/**
|
/**
|
||||||
* @var rootdir
|
* @var rootdir
|
||||||
*
|
*
|
||||||
|
150
lib/initend.c
150
lib/initend.c
@ -45,7 +45,7 @@
|
|||||||
#pragma clang diagnostic ignored "-Wformat-nonliteral"
|
#pragma clang diagnostic ignored "-Wformat-nonliteral"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static int parse_file(struct xbps_handle *, const char *, bool, bool);
|
static int parse_file(struct xbps_handle *, const char *, const char *, bool, bool);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @file lib/initend.c
|
* @file lib/initend.c
|
||||||
@ -89,25 +89,58 @@ store_vpkg(struct xbps_handle *xhp, const char *path, size_t line, char *vpkg_s)
|
|||||||
xbps_dbg_printf(xhp, "%s: added vpkg %s for %s\n", path, vpkg, rpkg);
|
xbps_dbg_printf(xhp, "%s: added vpkg %s for %s\n", path, vpkg, rpkg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
store_preserved_file(struct xbps_handle *xhp, const char *file)
|
||||||
|
{
|
||||||
|
glob_t globbuf;
|
||||||
|
char *p = NULL, *rfile = NULL;
|
||||||
|
size_t len;
|
||||||
|
int rv = 0;
|
||||||
|
|
||||||
|
if (xhp->preserved_files == NULL) {
|
||||||
|
xhp->preserved_files = xbps_array_create();
|
||||||
|
assert(xhp->preserved_files);
|
||||||
|
}
|
||||||
|
|
||||||
|
rfile = xbps_xasprintf("%s%s", xhp->rootdir, file);
|
||||||
|
|
||||||
|
rv = glob(rfile, 0, NULL, &globbuf);
|
||||||
|
if (rv == GLOB_NOMATCH) {
|
||||||
|
if (xbps_match_string_in_array(xhp->preserved_files, file))
|
||||||
|
goto out;
|
||||||
|
xbps_array_add_cstring(xhp->preserved_files, file);
|
||||||
|
xbps_dbg_printf(xhp, "Added preserved file: %s\n", file);
|
||||||
|
goto out;
|
||||||
|
} else if (rv != 0) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
for (size_t i = 0; i < globbuf.gl_pathc; i++) {
|
||||||
|
if (xbps_match_string_in_array(xhp->preserved_files, globbuf.gl_pathv[i]))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
len = strlen(globbuf.gl_pathv[i]) - strlen(xhp->rootdir) + 1;
|
||||||
|
p = malloc(len);
|
||||||
|
assert(len);
|
||||||
|
strlcpy(p, globbuf.gl_pathv[i] + strlen(xhp->rootdir), len);
|
||||||
|
xbps_array_add_cstring(xhp->preserved_files, p);
|
||||||
|
xbps_dbg_printf(xhp, "Added preserved file: %s (expanded from %s)\n", p, file);
|
||||||
|
free(p);
|
||||||
|
}
|
||||||
|
out:
|
||||||
|
globfree(&globbuf);
|
||||||
|
if (rfile)
|
||||||
|
free(rfile);
|
||||||
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
store_repo(struct xbps_handle *xhp, const char *repo)
|
store_repo(struct xbps_handle *xhp, const char *repo)
|
||||||
{
|
{
|
||||||
/*
|
|
||||||
* Append repositories to our proplib array.
|
|
||||||
*/
|
|
||||||
if (xhp->repositories == NULL)
|
if (xhp->repositories == NULL)
|
||||||
xhp->repositories = xbps_array_create();
|
xhp->repositories = xbps_array_create();
|
||||||
|
|
||||||
/*
|
if (xbps_match_string_in_array(xhp->repositories, repo))
|
||||||
* Do not add duplicates.
|
|
||||||
*/
|
|
||||||
for (unsigned int i = 0; i < xbps_array_count(xhp->repositories); i++) {
|
|
||||||
const char *srepo;
|
|
||||||
|
|
||||||
xbps_array_get_cstring_nocopy(xhp->repositories, i, &srepo);
|
|
||||||
if (strcmp(repo, srepo) == 0)
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
xbps_array_add_cstring(xhp->repositories, repo);
|
xbps_array_add_cstring(xhp->repositories, repo);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -123,7 +156,8 @@ parse_option(char *buf, char **k, char **v)
|
|||||||
"syslog",
|
"syslog",
|
||||||
"repository",
|
"repository",
|
||||||
"virtualpkg",
|
"virtualpkg",
|
||||||
"include"
|
"include",
|
||||||
|
"preserve"
|
||||||
};
|
};
|
||||||
bool found = false;
|
bool found = false;
|
||||||
|
|
||||||
@ -158,14 +192,14 @@ parse_option(char *buf, char **k, char **v)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
parse_files_glob(struct xbps_handle *xhp, const char *path, bool nested, bool vpkgconf)
|
parse_files_glob(struct xbps_handle *xhp, const char *cwd, const char *path, bool nested, bool vpkgconf)
|
||||||
{
|
{
|
||||||
glob_t globbuf;
|
glob_t globbuf;
|
||||||
int i, rv = 0;
|
int rv = 0;
|
||||||
|
|
||||||
glob(path, 0, NULL, &globbuf);
|
glob(path, 0, NULL, &globbuf);
|
||||||
for (i = 0; globbuf.gl_pathv; i++) {
|
for (size_t i = 0; i < globbuf.gl_pathc; i++) {
|
||||||
if ((rv = parse_file(xhp, globbuf.gl_pathv[i], nested, vpkgconf)) != 0)
|
if ((rv = parse_file(xhp, cwd, globbuf.gl_pathv[i], nested, vpkgconf)) != 0)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
globfree(&globbuf);
|
globfree(&globbuf);
|
||||||
@ -174,14 +208,13 @@ parse_files_glob(struct xbps_handle *xhp, const char *path, bool nested, bool vp
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
parse_file(struct xbps_handle *xhp, const char *path, bool nested, bool vpkgconf)
|
parse_file(struct xbps_handle *xhp, const char *cwd, const char *path, bool nested, bool vpkgconf)
|
||||||
{
|
{
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
|
char tmppath[XBPS_MAXPATH] = {0};
|
||||||
size_t len, nlines = 0;
|
size_t len, nlines = 0;
|
||||||
ssize_t read;
|
ssize_t read;
|
||||||
char *line = NULL;
|
char *cfcwd, *line = NULL;
|
||||||
char ocwd[XBPS_MAXPATH] = { 0 }, tmppath[XBPS_MAXPATH] = { 0 };
|
|
||||||
char *cwd;
|
|
||||||
int rv = 0;
|
int rv = 0;
|
||||||
|
|
||||||
if ((fp = fopen(path, "r")) == NULL) {
|
if ((fp = fopen(path, "r")) == NULL) {
|
||||||
@ -196,15 +229,10 @@ parse_file(struct xbps_handle *xhp, const char *path, bool nested, bool vpkgconf
|
|||||||
|
|
||||||
/* cwd to the dir containing the config file */
|
/* cwd to the dir containing the config file */
|
||||||
strlcpy(tmppath, path, sizeof(tmppath));
|
strlcpy(tmppath, path, sizeof(tmppath));
|
||||||
cwd = dirname(tmppath);
|
cfcwd = dirname(tmppath);
|
||||||
if (getcwd(ocwd, sizeof(ocwd)) == NULL) {
|
if (chdir(cfcwd) == -1) {
|
||||||
rv = errno;
|
rv = errno;
|
||||||
xbps_dbg_printf(xhp, "cannot get cwd: %s\n", strerror(rv));
|
xbps_dbg_printf(xhp, "cannot chdir to %s: %s\n", cfcwd, strerror(rv));
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
if (chdir(cwd)) {
|
|
||||||
rv = errno;
|
|
||||||
xbps_dbg_printf(xhp, "cannot chdir to %s: %s\n", cwd, strerror(rv));
|
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -245,6 +273,8 @@ parse_file(struct xbps_handle *xhp, const char *path, bool nested, bool vpkgconf
|
|||||||
xbps_dbg_printf(xhp, "%s: added repository %s\n", path, v);
|
xbps_dbg_printf(xhp, "%s: added repository %s\n", path, v);
|
||||||
} else if (strcmp(k, "virtualpkg") == 0) {
|
} else if (strcmp(k, "virtualpkg") == 0) {
|
||||||
store_vpkg(xhp, path, nlines, v);
|
store_vpkg(xhp, path, nlines, v);
|
||||||
|
} else if (strcmp(k, "preserve") == 0) {
|
||||||
|
store_preserved_file(xhp, v);
|
||||||
}
|
}
|
||||||
/* Avoid double-nested parsing, only allow it once */
|
/* Avoid double-nested parsing, only allow it once */
|
||||||
if (nested)
|
if (nested)
|
||||||
@ -253,25 +283,18 @@ parse_file(struct xbps_handle *xhp, const char *path, bool nested, bool vpkgconf
|
|||||||
if (strcmp(k, "include"))
|
if (strcmp(k, "include"))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if ((rv = parse_files_glob(xhp, v, true, false)) != 0)
|
if ((rv = parse_files_glob(xhp, cwd, v, true, false)) != 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
free(line);
|
free(line);
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
|
||||||
/* Going back to old working directory */
|
|
||||||
if (chdir(ocwd)) {
|
|
||||||
rv = errno;
|
|
||||||
xbps_dbg_printf(xhp, "cannot chdir to %s: %s\n", ocwd, strerror(rv));
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
parse_dir(struct xbps_handle *xhp, const char *dir, const char *confdir, bool vpkg)
|
parse_dir(struct xbps_handle *xhp, const char *cwd, const char *dir, const char *confdir, bool vpkg)
|
||||||
{
|
{
|
||||||
struct dirent **namelist;
|
struct dirent **namelist;
|
||||||
char *ext, ldir[PATH_MAX], conf[PATH_MAX];
|
char *ext, ldir[PATH_MAX], conf[PATH_MAX];
|
||||||
@ -313,7 +336,7 @@ parse_dir(struct xbps_handle *xhp, const char *dir, const char *confdir, bool vp
|
|||||||
}
|
}
|
||||||
/* parse conf file */
|
/* parse conf file */
|
||||||
snprintf(conf, sizeof(conf), "%s/%s", ldir, namelist[i]->d_name);
|
snprintf(conf, sizeof(conf), "%s/%s", ldir, namelist[i]->d_name);
|
||||||
if ((rv = parse_file(xhp, conf, false, vpkg)) != 0) {
|
if ((rv = parse_file(xhp, cwd, conf, false, vpkg)) != 0) {
|
||||||
free(namelist[i]);
|
free(namelist[i]);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -351,7 +374,7 @@ stage2:
|
|||||||
}
|
}
|
||||||
/* parse conf file */
|
/* parse conf file */
|
||||||
snprintf(conf, sizeof(conf), "%s/%s", ldir, namelist[i]->d_name);
|
snprintf(conf, sizeof(conf), "%s/%s", ldir, namelist[i]->d_name);
|
||||||
if ((rv = parse_file(xhp, conf, false, vpkg)) != 0) {
|
if ((rv = parse_file(xhp, cwd, conf, false, vpkg)) != 0) {
|
||||||
free(namelist[i]);
|
free(namelist[i]);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -365,37 +388,38 @@ int
|
|||||||
xbps_init(struct xbps_handle *xhp)
|
xbps_init(struct xbps_handle *xhp)
|
||||||
{
|
{
|
||||||
struct utsname un;
|
struct utsname un;
|
||||||
char *buf;
|
char cwd[PATH_MAX-1], *buf;
|
||||||
const char *repodir, *native_arch;
|
const char *repodir, *native_arch;
|
||||||
int rv;
|
int rv;
|
||||||
|
|
||||||
assert(xhp != NULL);
|
assert(xhp != NULL);
|
||||||
|
|
||||||
xbps_dbg_printf(xhp, "%s\n", XBPS_RELVER);
|
/* get cwd */
|
||||||
|
if (getcwd(cwd, sizeof(cwd)) == NULL)
|
||||||
|
return ENOTSUP;
|
||||||
|
|
||||||
if (xhp->conffile == NULL)
|
/* set conffile */
|
||||||
xhp->conffile = XBPS_CONF_DEF;
|
if (xhp->conffile[0] == '\0') {
|
||||||
|
snprintf(xhp->conffile, sizeof(xhp->conffile), XBPS_CONF_DEF);
|
||||||
/* parse configuration file */
|
} else {
|
||||||
if ((rv = parse_file(xhp, xhp->conffile, false, false)) != 0) {
|
buf = strdup(xhp->conffile);
|
||||||
xbps_dbg_printf(xhp, "Using built-in defaults\n");
|
snprintf(xhp->conffile, sizeof(xhp->conffile), "%s/%s", cwd, buf);
|
||||||
|
free(buf);
|
||||||
}
|
}
|
||||||
/* Set rootdir */
|
/* Set rootdir */
|
||||||
if (xhp->rootdir[0] == '\0') {
|
if (xhp->rootdir[0] == '\0') {
|
||||||
xhp->rootdir[0] = '/';
|
xhp->rootdir[0] = '/';
|
||||||
xhp->rootdir[1] = '\0';
|
xhp->rootdir[1] = '\0';
|
||||||
} else if (xhp->rootdir[0] != '/') {
|
} else if (xhp->rootdir[0] != '/') {
|
||||||
/* relative path */
|
|
||||||
char path[PATH_MAX-1];
|
|
||||||
|
|
||||||
if (getcwd(path, sizeof(path)) == NULL)
|
|
||||||
return ENOTSUP;
|
|
||||||
|
|
||||||
buf = strdup(xhp->rootdir);
|
buf = strdup(xhp->rootdir);
|
||||||
snprintf(xhp->rootdir, sizeof(xhp->rootdir),
|
snprintf(xhp->rootdir, sizeof(xhp->rootdir), "%s/%s", cwd, buf);
|
||||||
"%s/%s", path, buf);
|
|
||||||
free(buf);
|
free(buf);
|
||||||
}
|
}
|
||||||
|
/* parse configuration file */
|
||||||
|
xbps_dbg_printf(xhp, "%s\n", XBPS_RELVER);
|
||||||
|
if ((rv = parse_file(xhp, cwd, xhp->conffile, false, false)) != 0) {
|
||||||
|
xbps_dbg_printf(xhp, "Using built-in defaults\n");
|
||||||
|
}
|
||||||
/* Set cachedir */
|
/* Set cachedir */
|
||||||
if (xhp->cachedir[0] == '\0') {
|
if (xhp->cachedir[0] == '\0') {
|
||||||
snprintf(xhp->cachedir, sizeof(xhp->cachedir),
|
snprintf(xhp->cachedir, sizeof(xhp->cachedir),
|
||||||
@ -421,11 +445,15 @@ xbps_init(struct xbps_handle *xhp)
|
|||||||
free(buf);
|
free(buf);
|
||||||
}
|
}
|
||||||
/* process virtualpkg.d dirs */
|
/* process virtualpkg.d dirs */
|
||||||
if ((rv = parse_dir(xhp, XBPS_SYS_VPKG_PATH, XBPS_VPKG_PATH, true)) != 0)
|
if ((rv = parse_dir(xhp, cwd, XBPS_SYS_VPKG_PATH, XBPS_VPKG_PATH, true)) != 0)
|
||||||
return rv;
|
return rv;
|
||||||
|
|
||||||
/* process repo.d dirs */
|
/* process repo.d dirs */
|
||||||
if ((rv = parse_dir(xhp, XBPS_SYS_REPOD_PATH, XBPS_REPOD_PATH, false)) != 0)
|
if ((rv = parse_dir(xhp, cwd, XBPS_SYS_REPOD_PATH, XBPS_REPOD_PATH, false)) != 0)
|
||||||
|
return rv;
|
||||||
|
|
||||||
|
/* process preserve.d dirs */
|
||||||
|
if ((rv = parse_dir(xhp, cwd, XBPS_SYS_PRESERVED_PATH, XBPS_PRESERVED_PATH, false)) != 0)
|
||||||
return rv;
|
return rv;
|
||||||
|
|
||||||
xhp->target_arch = getenv("XBPS_TARGET_ARCH");
|
xhp->target_arch = getenv("XBPS_TARGET_ARCH");
|
||||||
@ -452,6 +480,10 @@ xbps_init(struct xbps_handle *xhp)
|
|||||||
xbps_dbg_printf(xhp, "Repository[%u]=%s\n", i, repodir);
|
xbps_dbg_printf(xhp, "Repository[%u]=%s\n", i, repodir);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/* Going back to old working directory */
|
||||||
|
if (chdir(cwd) == -1)
|
||||||
|
xbps_dbg_printf(xhp, "%s: cannot chdir to %s: %s\n", __func__, cwd, strerror(errno));
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -151,6 +151,24 @@ create_pkg_metaplist(struct xbps_handle *xhp, const char *pkgname, const char *p
|
|||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
match_preserved_file(struct xbps_handle *xhp, const char *entry)
|
||||||
|
{
|
||||||
|
char *file;
|
||||||
|
|
||||||
|
if (xhp->preserved_files == NULL)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (entry[0] == '.' && entry[1] != '\0') {
|
||||||
|
file = strchr(entry, '.') + 1;
|
||||||
|
assert(file);
|
||||||
|
} else {
|
||||||
|
file = __UNCONST(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
return xbps_match_string_in_array(xhp->preserved_files, file);
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
unpack_archive(struct xbps_handle *xhp,
|
unpack_archive(struct xbps_handle *xhp,
|
||||||
xbps_dictionary_t pkg_repod,
|
xbps_dictionary_t pkg_repod,
|
||||||
@ -353,6 +371,17 @@ unpack_archive(struct xbps_handle *xhp,
|
|||||||
conf_file = skip_extract = file_exists = false;
|
conf_file = skip_extract = file_exists = false;
|
||||||
if (lstat(entry_pname, &st) == 0)
|
if (lstat(entry_pname, &st) == 0)
|
||||||
file_exists = true;
|
file_exists = true;
|
||||||
|
/*
|
||||||
|
* Check if the file to be extracted must be preserved, if true,
|
||||||
|
* pass to the next file.
|
||||||
|
*/
|
||||||
|
if (file_exists && match_preserved_file(xhp, entry_pname)) {
|
||||||
|
archive_read_data_skip(ar);
|
||||||
|
xbps_dbg_printf(xhp, "[unpack] `%s' exists on disk and must be preserved, skipping.\n", xhp, entry_pname);
|
||||||
|
xbps_set_cb_state(xhp, XBPS_STATE_UNPACK_FILE_PRESERVED, 0, pkgver,
|
||||||
|
pkgver, "%s: file `%s' won't be extracted, it's preserved.\n", pkgver, entry_pname);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
* If file to be extracted does not match the file type of
|
* If file to be extracted does not match the file type of
|
||||||
* file currently stored on disk, remove file on disk.
|
* file currently stored on disk, remove file on disk.
|
||||||
|
@ -21,6 +21,7 @@ atf_test_program{name="scripts_test"}
|
|||||||
atf_test_program{name="incorrect_deps_test"}
|
atf_test_program{name="incorrect_deps_test"}
|
||||||
atf_test_program{name="vpkg_test"}
|
atf_test_program{name="vpkg_test"}
|
||||||
atf_test_program{name="install_test"}
|
atf_test_program{name="install_test"}
|
||||||
|
atf_test_program{name="preserve_files_test"}
|
||||||
|
|
||||||
include('config/Kyuafile')
|
include('config/Kyuafile')
|
||||||
include('find_pkg_orphans/Kyuafile')
|
include('find_pkg_orphans/Kyuafile')
|
||||||
|
@ -36,7 +36,6 @@ ATF_TC_BODY(config_include_test, tc)
|
|||||||
{
|
{
|
||||||
struct xbps_handle xh;
|
struct xbps_handle xh;
|
||||||
const char *tcsdir;
|
const char *tcsdir;
|
||||||
char conffile[XBPS_MAXPATH-1];
|
|
||||||
|
|
||||||
/* get test source dir */
|
/* get test source dir */
|
||||||
tcsdir = atf_tc_get_config_var(tc, "srcdir");
|
tcsdir = atf_tc_get_config_var(tc, "srcdir");
|
||||||
@ -46,9 +45,7 @@ ATF_TC_BODY(config_include_test, tc)
|
|||||||
memset(&xh, 0, sizeof(xh));
|
memset(&xh, 0, sizeof(xh));
|
||||||
strncpy(xh.rootdir, tcsdir, sizeof(xh.rootdir));
|
strncpy(xh.rootdir, tcsdir, sizeof(xh.rootdir));
|
||||||
strncpy(xh.metadir, tcsdir, sizeof(xh.metadir));
|
strncpy(xh.metadir, tcsdir, sizeof(xh.metadir));
|
||||||
strncpy(conffile, tcsdir, sizeof(conffile));
|
snprintf(xh.conffile, sizeof(xh.conffile), "%s/xbps.conf", tcsdir);
|
||||||
strncat(conffile, "/xbps.conf", sizeof(conffile)-1);
|
|
||||||
xh.conffile = conffile;
|
|
||||||
xh.flags = XBPS_FLAG_DEBUG;
|
xh.flags = XBPS_FLAG_DEBUG;
|
||||||
ATF_REQUIRE_EQ(xbps_init(&xh), 0);
|
ATF_REQUIRE_EQ(xbps_init(&xh), 0);
|
||||||
|
|
||||||
@ -67,7 +64,6 @@ ATF_TC_BODY(config_include_nomatch_test, tc)
|
|||||||
{
|
{
|
||||||
struct xbps_handle xh;
|
struct xbps_handle xh;
|
||||||
const char *tcsdir;
|
const char *tcsdir;
|
||||||
char conffile[XBPS_MAXPATH-1];
|
|
||||||
|
|
||||||
/* get test source dir */
|
/* get test source dir */
|
||||||
tcsdir = atf_tc_get_config_var(tc, "srcdir");
|
tcsdir = atf_tc_get_config_var(tc, "srcdir");
|
||||||
@ -77,9 +73,7 @@ ATF_TC_BODY(config_include_nomatch_test, tc)
|
|||||||
memset(&xh, 0, sizeof(xh));
|
memset(&xh, 0, sizeof(xh));
|
||||||
strncpy(xh.rootdir, tcsdir, sizeof(xh.rootdir));
|
strncpy(xh.rootdir, tcsdir, sizeof(xh.rootdir));
|
||||||
strncpy(xh.metadir, tcsdir, sizeof(xh.metadir));
|
strncpy(xh.metadir, tcsdir, sizeof(xh.metadir));
|
||||||
strncpy(conffile, tcsdir, sizeof(conffile));
|
strncpy(xh.conffile, "/xbps_nomatch.conf", sizeof(xh.conffile));
|
||||||
strncat(conffile, "/xbps_nomatch.conf", sizeof(conffile)-1);
|
|
||||||
xh.conffile = conffile;
|
|
||||||
xh.flags = XBPS_FLAG_DEBUG;
|
xh.flags = XBPS_FLAG_DEBUG;
|
||||||
ATF_REQUIRE_EQ(xbps_init(&xh), 0);
|
ATF_REQUIRE_EQ(xbps_init(&xh), 0);
|
||||||
|
|
||||||
|
@ -79,7 +79,7 @@ ATF_TC_BODY(find_pkg_obsoletes_test, tc)
|
|||||||
|
|
||||||
memset(&xh, 0, sizeof(xh));
|
memset(&xh, 0, sizeof(xh));
|
||||||
strncpy(xh.rootdir, tcsdir, sizeof(xh.rootdir));
|
strncpy(xh.rootdir, tcsdir, sizeof(xh.rootdir));
|
||||||
xh.conffile = "/tmp/unexistent.conf";
|
strncpy(xh.conffile, "/tmp/unexistent.conf", sizeof(xh.conffile));
|
||||||
ATF_REQUIRE_EQ(xbps_init(&xh), 0);
|
ATF_REQUIRE_EQ(xbps_init(&xh), 0);
|
||||||
|
|
||||||
d1 = create_dict("files", "/etc/foo.conf");
|
d1 = create_dict("files", "/etc/foo.conf");
|
||||||
|
@ -4,7 +4,7 @@ TOPDIR = ../../../..
|
|||||||
TESTSHELL = conf_files_test issue6_test issue18_test issue20_test remove_test
|
TESTSHELL = conf_files_test issue6_test issue18_test issue20_test remove_test
|
||||||
TESTSHELL+= replace_test installmode_test obsoletefiles_test
|
TESTSHELL+= replace_test installmode_test obsoletefiles_test
|
||||||
TESTSHELL+= issue31_test scripts_test incorrect_deps_test
|
TESTSHELL+= issue31_test scripts_test incorrect_deps_test
|
||||||
TESTSHELL+= vpkg_test install_test
|
TESTSHELL+= vpkg_test install_test preserve_files_test
|
||||||
|
|
||||||
include ../Makefile.inc
|
include ../Makefile.inc
|
||||||
include $(TOPDIR)/mk/test.mk
|
include $(TOPDIR)/mk/test.mk
|
||||||
|
83
tests/xbps/libxbps/shell/preserve_files_test.sh
Normal file
83
tests/xbps/libxbps/shell/preserve_files_test.sh
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
#!/usr/bin/env atf-sh
|
||||||
|
|
||||||
|
atf_test_case tc1
|
||||||
|
|
||||||
|
tc1_head() {
|
||||||
|
atf_set "descr" "Tests for pkg install/upgrade with preserved files: preserve on-disk files with globs"
|
||||||
|
}
|
||||||
|
|
||||||
|
tc1_body() {
|
||||||
|
mkdir some_repo
|
||||||
|
mkdir -p pkg_A/usr/bin
|
||||||
|
echo "blahblah" > pkg_A/usr/bin/blah
|
||||||
|
echo "foofoo" > pkg_A/usr/bin/foo
|
||||||
|
cd some_repo
|
||||||
|
xbps-create -A noarch -n A-1.0_1 -s "A pkg" ../pkg_A
|
||||||
|
atf_check_equal $? 0
|
||||||
|
xbps-rindex -a *.xbps
|
||||||
|
atf_check_equal $? 0
|
||||||
|
cd ..
|
||||||
|
|
||||||
|
mkdir -p root/usr/bin
|
||||||
|
echo "modified blahblah" > root/usr/bin/blah
|
||||||
|
echo "modified foofoo" > root/usr/bin/foo
|
||||||
|
|
||||||
|
echo "preserve=/usr/bin/*" > foo.conf
|
||||||
|
|
||||||
|
xbps-install -C foo.conf -r root --repository=$PWD/some_repo -yd A
|
||||||
|
atf_check_equal $? 0
|
||||||
|
|
||||||
|
rv=1
|
||||||
|
if [ "$(cat root/usr/bin/blah)" = "modified blahblah" -a "$(cat root/usr/bin/foo)" = "modified foofoo" ]; then
|
||||||
|
rv=0
|
||||||
|
fi
|
||||||
|
atf_check_equal $rv 0
|
||||||
|
}
|
||||||
|
|
||||||
|
atf_test_case tc2
|
||||||
|
|
||||||
|
tc2_head() {
|
||||||
|
atf_set "descr" "Tests for pkg install/upgrade with preserved files: preserve on-disk files without globs"
|
||||||
|
}
|
||||||
|
|
||||||
|
tc2_body() {
|
||||||
|
mkdir some_repo
|
||||||
|
mkdir -p pkg_A/usr/bin
|
||||||
|
echo "blahblah" > pkg_A/usr/bin/blah
|
||||||
|
echo "foofoo" > pkg_A/usr/bin/foo
|
||||||
|
cd some_repo
|
||||||
|
xbps-create -A noarch -n A-1.0_1 -s "A pkg" ../pkg_A
|
||||||
|
atf_check_equal $? 0
|
||||||
|
xbps-rindex -a *.xbps
|
||||||
|
atf_check_equal $? 0
|
||||||
|
cd ..
|
||||||
|
|
||||||
|
mkdir -p root/usr/bin
|
||||||
|
echo "modified blahblah" > root/usr/bin/blah
|
||||||
|
echo "modified foofoo" > root/usr/bin/foo
|
||||||
|
|
||||||
|
printf "preserve=/usr/bin/blah\npreserve=/usr/bin/foo\n" > foo.conf
|
||||||
|
|
||||||
|
echo "foo.conf" >&2
|
||||||
|
cat foo.conf >&2
|
||||||
|
|
||||||
|
xbps-install -C foo.conf -r root --repository=$PWD/some_repo -yd A
|
||||||
|
atf_check_equal $? 0
|
||||||
|
|
||||||
|
rv=1
|
||||||
|
if [ "$(cat root/usr/bin/blah)" = "modified blahblah" -a "$(cat root/usr/bin/foo)" = "modified foofoo" ]; then
|
||||||
|
rv=0
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "root/usr/bin/blah" >&2
|
||||||
|
cat root/usr/bin/blah >&2
|
||||||
|
echo "root/usr/bin/foo" >&2
|
||||||
|
cat root/usr/bin/foo >&2
|
||||||
|
|
||||||
|
atf_check_equal $rv 0
|
||||||
|
}
|
||||||
|
|
||||||
|
atf_init_test_cases() {
|
||||||
|
atf_add_test_case tc1
|
||||||
|
atf_add_test_case tc2
|
||||||
|
}
|
@ -41,7 +41,7 @@ script_nargs_body() {
|
|||||||
rval=0
|
rval=0
|
||||||
xbps-reconfigure -C empty.conf -r root -f A 2>out
|
xbps-reconfigure -C empty.conf -r root -f A 2>out
|
||||||
out="$(cat out)"
|
out="$(cat out)"
|
||||||
expected="post A 1.0_1 no empty.conf $(uname -m)"
|
expected="post A 1.0_1 no $(pwd)/empty.conf $(uname -m)"
|
||||||
if [ "$out" != "$expected" ]; then
|
if [ "$out" != "$expected" ]; then
|
||||||
echo "out: '$out'"
|
echo "out: '$out'"
|
||||||
echo "expected: '$expected'"
|
echo "expected: '$expected'"
|
||||||
@ -75,7 +75,7 @@ script_arch_body() {
|
|||||||
rval=0
|
rval=0
|
||||||
XBPS_ARCH=foo xbps-reconfigure -C empty.conf -r root -f A 2>out
|
XBPS_ARCH=foo xbps-reconfigure -C empty.conf -r root -f A 2>out
|
||||||
out="$(cat out)"
|
out="$(cat out)"
|
||||||
expected="post A 1.0_1 no empty.conf foo"
|
expected="post A 1.0_1 no $(pwd)/empty.conf foo"
|
||||||
if [ "$out" != "$expected" ]; then
|
if [ "$out" != "$expected" ]; then
|
||||||
echo "out: '$out'"
|
echo "out: '$out'"
|
||||||
echo "expected: '$expected'"
|
echo "expected: '$expected'"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user