Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/pkg
Path: blob/main/libpkg/backup_lib.c
2648 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, struct pkg *orig, 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 *lpath, *name, *sum;
42
struct pkg_file *f;
43
struct stat st;
44
pkghash_entry *e;
45
int retcode;
46
47
sum = pkg_checksum_generate_fileat(fd, RELATIVE_PATH(path),
48
PKG_HASH_TYPE_SHA256_HEX);
49
50
(void)xasprintf(&name, "%s-backup-libraries", orig->name);
51
52
it = pkgdb_query(db, name, MATCH_EXACT);
53
if (it != NULL) {
54
pkgdb_it_next(it, &pkg, PKG_LOAD_BASIC|PKG_LOAD_FILES);
55
pkgdb_it_free(it);
56
}
57
if (pkg == NULL) {
58
char *origin;
59
60
if (pkg_new(&pkg, PKG_FILE) != EPKG_OK) {
61
return (EPKG_FATAL);
62
}
63
pkg->name = name;
64
(void)xasprintf(&origin, "%s-backup", orig->origin);
65
pkg->origin = origin;
66
pkg->comment = xstrdup(
67
"Compatibility libraries saved during package upgrade");
68
pkg->desc = xstrdup(
69
"Compatibility libraries saved during package upgrade\n");
70
pkg->maintainer = xstrdup("root@localhost");
71
pkg->www = xstrdup("N/A");
72
pkg->prefix = xstrdup("/");
73
pkg->abi = xstrdup(orig->abi);
74
vec_foreach(orig->shlibs_provided_ignore, i) {
75
pkg_addshlib_provided_ignore(pkg, orig->shlibs_provided_ignore.d[i]);
76
}
77
vec_foreach(orig->shlibs_required_ignore, i) {
78
pkg_addshlib_required_ignore(pkg, orig->shlibs_required_ignore.d[i]);
79
}
80
} else {
81
free(name);
82
name = NULL;
83
}
84
if ((e = pkghash_get(pkg->filehash, path)) != NULL) {
85
DL_DELETE(pkg->files, (struct pkg_file *)e->value);
86
pkg_file_free(e->value);
87
pkghash_del(pkg->filehash, path);
88
}
89
xasprintf(&lpath, "%s/%s", ctx.backup_library_path, path);
90
pkg_addfile(pkg, lpath, sum, false);
91
free(lpath);
92
93
t = time(NULL);
94
strftime(buf, sizeof(buf), "%Y%m%d%H%M%S", localtime(&t));
95
free(pkg->version);
96
pkg->version = xstrdup(buf);
97
98
pkg_analyse_files(NULL, pkg, ctx.pkg_rootdir);
99
pkg_open_root_fd(pkg);
100
f = NULL;
101
while (pkg_files(pkg, &f) == EPKG_OK) {
102
if (fstatat(pkg->rootfd, RELATIVE_PATH(f->path), &st,
103
AT_SYMLINK_NOFOLLOW) != -1)
104
pkg->flatsize += st.st_size;
105
}
106
retcode = pkgdb_register_pkg(db, pkg, 1, "backuplib");
107
if (retcode == EPKG_OK)
108
retcode = pkgdb_register_finale(db, EPKG_OK, "backuplib");
109
return (retcode);
110
}
111
112
static void
113
backup_library(struct pkgdb *db, struct pkg *p, const char *path)
114
{
115
const char *libname;
116
int from, to, backupdir;
117
118
if ((libname = strrchr(path, '/')) == NULL)
119
return;
120
/* skip the initial / */
121
libname++;
122
123
pkg_open_root_fd(p);
124
to = -1;
125
126
from = openat(p->rootfd, RELATIVE_PATH(path), O_RDONLY);
127
if (from == -1) {
128
pkg_debug(2, "unable to backup %s:%s", path, strerror(errno));
129
return;
130
}
131
132
if (mkdirat(p->rootfd, RELATIVE_PATH(ctx.backup_library_path), 0755) == -1) {
133
if (!mkdirat_p(p->rootfd, RELATIVE_PATH(ctx.backup_library_path))) {
134
pkg_emit_errno("Impossible to create the library backup "
135
"directory", ctx.backup_library_path);
136
close(from);
137
return;
138
}
139
}
140
backupdir = openat(p->rootfd, RELATIVE_PATH(ctx.backup_library_path),
141
O_DIRECTORY);
142
if (backupdir == -1) {
143
pkg_emit_error("Impossible to open the library backup "
144
"directory %s", ctx.backup_library_path);
145
goto out;
146
}
147
148
/*
149
* always overwrite the existing backup library, it might be older than
150
* this one
151
*/
152
/* first always unlink to ensure we are not truncating a used library */
153
unlinkat(backupdir, libname, 0);
154
to = openat(backupdir, libname, O_EXCL|O_CREAT|O_WRONLY, 0644);
155
if (to == -1) {
156
pkg_emit_errno("Impossible to create the backup library", libname);
157
goto out;
158
}
159
160
if (pkg_copy_file(from, to)) {
161
if (close(to) < 0) {
162
to = -1;
163
goto out;
164
}
165
close(from);
166
register_backup(db, p, backupdir, libname);
167
close(backupdir);
168
return;
169
}
170
171
out:
172
pkg_emit_errno("Fail to backup the library", libname);
173
if (backupdir >= 0)
174
close(backupdir);
175
if (from >= 0)
176
close(from);
177
if (to >= 0)
178
close(to);
179
}
180
181
/*
182
* We're about to remove an installed file as part of an upgrade. See if it's a
183
* library and whether the user asked us to back up libraries, and if so, back
184
* it up.
185
*/
186
void
187
pkg_maybe_backup_library(struct pkgdb *db, struct pkg *pkg, const char *path)
188
{
189
const char *libname;
190
191
if (!ctx.backup_libraries)
192
return;
193
194
libname = strrchr(path, '/');
195
if (libname != NULL &&
196
charv_search(&pkg->shlibs_provided, libname + 1) != NULL)
197
backup_library(db, pkg, path);
198
}
199
200