Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/pkg
Path: blob/main/libpkg/backup_lib.c
2065 views
1
/*-
2
* Copyright (c) 2020 Baptiste Daroussin <[email protected]>
3
*
4
* Redistribution and use in source and binary forms, with or without
5
* modification, are permitted provided that the following conditions
6
* are met:
7
* 1. Redistributions of source code must retain the above copyright
8
* notice, this list of conditions and the following disclaimer
9
* in this position and unchanged.
10
* 2. Redistributions in binary form must reproduce the above copyright
11
* notice, this list of conditions and the following disclaimer in the
12
* documentation and/or other materials provided with the distribution.
13
*
14
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
15
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17
* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
18
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24
*/
25
26
#include <errno.h>
27
#include <fcntl.h>
28
#include <time.h>
29
30
#include "pkg.h"
31
#include "private/event.h"
32
#include "private/pkg.h"
33
34
static int
35
register_backup(struct pkgdb *db, int fd, const char *path)
36
{
37
struct pkgdb_it *it;
38
struct pkg *pkg = NULL;
39
time_t t;
40
char buf[BUFSIZ];
41
char *sum;
42
struct pkg_file *f;
43
char *lpath;
44
struct stat st;
45
pkghash_entry *e;
46
int retcode;
47
48
sum = pkg_checksum_generate_fileat(fd, RELATIVE_PATH(path), PKG_HASH_TYPE_SHA256_HEX);
49
50
it = pkgdb_query(db, "compat-libraries", MATCH_EXACT);
51
if (it != NULL) {
52
pkgdb_it_next(it, &pkg, PKG_LOAD_BASIC|PKG_LOAD_FILES);
53
pkgdb_it_free(it);
54
}
55
if (pkg == NULL) {
56
if (pkg_new(&pkg, PKG_FILE) != EPKG_OK) {
57
return (EPKG_FATAL);
58
}
59
pkg->name = xstrdup("compat-libraries");
60
pkg->origin = xstrdup("compat/libraries");
61
pkg->comment = xstrdup("Compatibility libraries saved during local packages upgrade\n");
62
pkg->desc = xstrdup("Compatibility libraries saved during local packages upgrade\n");
63
pkg->maintainer = xstrdup("root@localhost");
64
pkg->www = xstrdup("N/A");
65
pkg->prefix = xstrdup("/");
66
pkg->abi = "*";
67
}
68
free(pkg->version);
69
t = time(NULL);
70
strftime(buf, sizeof(buf), "%Y%m%d%H%M%S", localtime(&t));
71
if ((e = pkghash_get(pkg->filehash, path)) != NULL) {
72
DL_DELETE(pkg->files, (struct pkg_file *)e->value);
73
pkg_file_free(e->value);
74
pkghash_del(pkg->filehash, path);
75
}
76
xasprintf(&lpath, "%s/%s", ctx.backup_library_path, path);
77
pkg_addfile(pkg, lpath, sum, false);
78
free(lpath);
79
pkg->version = xstrdup(buf);
80
pkg_analyse_files(NULL, pkg, ctx.pkg_rootdir);
81
pkg_open_root_fd(pkg);
82
f = NULL;
83
while (pkg_files(pkg, &f) == EPKG_OK) {
84
if (fstatat(pkg->rootfd, RELATIVE_PATH(f->path), &st, AT_SYMLINK_NOFOLLOW) != -1)
85
pkg->flatsize += st.st_size;
86
}
87
retcode = pkgdb_register_pkg(db, pkg, 0, "backuplib");
88
if (retcode == EPKG_OK)
89
pkgdb_register_finale(db, EPKG_OK, "backuplib");
90
return (retcode);
91
}
92
93
static void
94
backup_library(struct pkgdb *db, struct pkg *p, const char *path)
95
{
96
const char *libname;
97
int from, to, backupdir;
98
99
if ((libname = strrchr(path, '/')) == NULL)
100
return;
101
/* skip the initial / */
102
libname++;
103
104
pkg_open_root_fd(p);
105
to = -1;
106
107
from = openat(p->rootfd, RELATIVE_PATH(path), O_RDONLY);
108
if (from == -1) {
109
pkg_debug(2, "unable to backup %s:%s", path, strerror(errno));
110
return;
111
}
112
113
if (mkdirat(p->rootfd, RELATIVE_PATH(ctx.backup_library_path), 0755) == -1) {
114
if (!mkdirat_p(p->rootfd, RELATIVE_PATH(ctx.backup_library_path))) {
115
pkg_emit_errno("Impossible to create the library backup "
116
"directory", ctx.backup_library_path);
117
close(from);
118
return;
119
}
120
}
121
backupdir = openat(p->rootfd, RELATIVE_PATH(ctx.backup_library_path),
122
O_DIRECTORY);
123
if (backupdir == -1) {
124
pkg_emit_error("Impossible to open the library backup "
125
"directory %s", ctx.backup_library_path);
126
goto out;
127
}
128
129
/*
130
* always overwrite the existing backup library, it might be older than
131
* this one
132
*/
133
/* first always unlink to ensure we are not truncating a used library */
134
unlinkat(backupdir, libname, 0);
135
to = openat(backupdir, libname, O_EXCL|O_CREAT|O_WRONLY, 0644);
136
if (to == -1) {
137
pkg_emit_errno("Impossible to create the backup library", libname);
138
goto out;
139
}
140
141
if (pkg_copy_file(from, to)) {
142
if (close(to) < 0) {
143
to = -1;
144
goto out;
145
}
146
close(from);
147
register_backup(db, backupdir, libname);
148
close(backupdir);
149
return;
150
}
151
152
out:
153
pkg_emit_errno("Fail to backup the library", libname);
154
if (backupdir >= 0)
155
close(backupdir);
156
if (from >= 0)
157
close(from);
158
if (to >= 0)
159
close(to);
160
}
161
162
/*
163
* We're about to remove an installed file as part of an upgrade. See if it's a
164
* library and whether the user asked us to back up libraries, and if so, back
165
* it up.
166
*/
167
void
168
pkg_maybe_backup_library(struct pkgdb *db, struct pkg *pkg, const char *path)
169
{
170
const char *libname;
171
172
if (!ctx.backup_libraries)
173
return;
174
175
libname = strrchr(path, '/');
176
if (libname != NULL &&
177
charv_search(&pkg->shlibs_provided, libname + 1) != NULL)
178
backup_library(db, pkg, path);
179
}
180
181