Branch data Line data Source code
1 : : /*-
2 : : * Copyright (c) 2020 Baptiste Daroussin <bapt@FreeBSD.org>
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 : 8 : register_backup(struct pkgdb *db, int fd, const char *path)
36 : : {
37 : : struct pkgdb_it *it;
38 : 8 : 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 : :
47 : 8 : sum = pkg_checksum_generate_fileat(fd, RELATIVE_PATH(path), PKG_HASH_TYPE_SHA256_HEX);
48 : :
49 : 8 : it = pkgdb_query(db, "compat-libraries", MATCH_EXACT);
50 [ + - ]: 8 : if (it != NULL) {
51 : 8 : pkgdb_it_next(it, &pkg, PKG_LOAD_BASIC|PKG_LOAD_FILES);
52 : 8 : pkgdb_it_free(it);
53 : 8 : }
54 [ + + ]: 8 : if (pkg == NULL) {
55 [ - + ]: 4 : if (pkg_new(&pkg, PKG_FILE) != EPKG_OK) {
56 : 0 : return (EPKG_FATAL);
57 : : }
58 : 4 : pkg->name = xstrdup("compat-libraries");
59 : 4 : pkg->origin = xstrdup("compat/libraries");
60 : 4 : pkg->comment = xstrdup("Compatibility libraries saved during local packages upgrade\n");
61 : 4 : pkg->desc = xstrdup("Compatibility libraries saved during local packages upgrade\n");
62 : 4 : pkg->maintainer = xstrdup("root@localhost");
63 : 4 : pkg->www = xstrdup("N/A");
64 : 4 : pkg->prefix = xstrdup("/");
65 : 4 : pkg->abi = "*";
66 : 4 : }
67 : 8 : free(pkg->version);
68 : 8 : t = time(NULL);
69 : 8 : strftime(buf, sizeof(buf), "%Y%m%d%H%M%S", localtime(&t));
70 [ + - ]: 8 : if ((e = pkghash_get(pkg->filehash, path)) != NULL) {
71 [ # # # # : 0 : DL_DELETE(pkg->files, (struct pkg_file *)e->value);
# # # # ]
72 : 0 : pkg_file_free(e->value);
73 : 0 : pkghash_del(pkg->filehash, path);
74 : 0 : }
75 : 8 : xasprintf(&lpath, "%s/%s", ctx.backup_library_path, path);
76 : 8 : pkg_addfile(pkg, lpath, sum, false);
77 : 8 : free(lpath);
78 : 8 : pkg->version = xstrdup(buf);
79 : 8 : pkg_analyse_files(NULL, pkg, ctx.pkg_rootdir);
80 : 8 : pkg_open_root_fd(pkg);
81 : 8 : f = NULL;
82 [ + + ]: 20 : while (pkg_files(pkg, &f) == EPKG_OK) {
83 [ + - ]: 12 : if (fstatat(pkg->rootfd, RELATIVE_PATH(f->path), &st, AT_SYMLINK_NOFOLLOW) != -1)
84 : 12 : pkg->flatsize += st.st_size;
85 : : }
86 : 8 : pkgdb_register_finale(db, pkgdb_register_pkg(db, pkg, 0, "backuplib"), "backuplib");
87 : 8 : return (EPKG_OK);
88 : 8 : }
89 : :
90 : : void
91 : 8 : backup_library(struct pkgdb *db, struct pkg *p, const char *path)
92 : : {
93 : 8 : const char *libname = strrchr(path, '/');
94 : : char buf[BUFSIZ];
95 : : char *outbuf;
96 : : int from, to, backupdir;
97 : : ssize_t nread, nwritten;
98 : :
99 : 8 : pkg_open_root_fd(p);
100 : 8 : to = -1;
101 : :
102 [ + - ]: 8 : if (libname == NULL)
103 : 0 : return;
104 : : /* skip the initial / */
105 : 8 : libname++;
106 : :
107 : 8 : from = openat(p->rootfd, RELATIVE_PATH(path), O_RDONLY);
108 [ + - ]: 8 : if (from == -1) {
109 : 0 : pkg_debug(2, "unable to backup %s:%s", path, strerror(errno));
110 : 0 : return;
111 : : }
112 : :
113 [ + + ]: 8 : if (mkdirat(p->rootfd, RELATIVE_PATH(ctx.backup_library_path), 0755) == -1) {
114 [ + - ]: 4 : if (!mkdirat_p(p->rootfd, RELATIVE_PATH(ctx.backup_library_path))) {
115 : 0 : pkg_emit_errno("Impossible to create the library backup "
116 : 0 : "directory", ctx.backup_library_path);
117 : 0 : close(from);
118 : 0 : return;
119 : : }
120 : 4 : }
121 : 8 : backupdir = openat(p->rootfd, RELATIVE_PATH(ctx.backup_library_path),
122 : : O_DIRECTORY);
123 [ + - ]: 8 : if (backupdir == -1) {
124 : 0 : pkg_emit_error("Impossible to open the library backup "
125 : 0 : "directory %s", ctx.backup_library_path);
126 : 0 : 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 : 8 : unlinkat(backupdir, libname, 0);
135 : 8 : to = openat(backupdir, libname, O_EXCL|O_CREAT|O_WRONLY, 0644);
136 [ + - ]: 8 : if (to == -1) {
137 : 0 : pkg_emit_errno("Impossible to create the backup library", libname);
138 : 0 : goto out;
139 : : }
140 : :
141 [ + + ]: 72 : while (nread = read(from, buf, sizeof(buf)), nread > 0) {
142 : 64 : outbuf = buf;
143 : 64 : do {
144 : 64 : nwritten = write(to, outbuf, nread);
145 [ + - ]: 64 : if (nwritten >= 0) {
146 : 64 : nread -= nwritten;
147 : 64 : outbuf += nwritten;
148 [ # # ]: 64 : } else if (errno != EINTR) {
149 : 0 : goto out;
150 : : }
151 [ - + ]: 64 : } while (nread > 0);
152 : : }
153 : :
154 [ - + ]: 8 : if (nread == 0) {
155 [ - + ]: 8 : if (close(to) < 0) {
156 : 0 : to = -1;
157 : 0 : goto out;
158 : : }
159 : 8 : close(from);
160 : 8 : register_backup(db, backupdir, libname);
161 : 8 : close(backupdir);
162 : 8 : return;
163 : : }
164 : :
165 : :
166 : : out:
167 : 0 : pkg_emit_errno("Fail to backup the library", libname);
168 [ # # ]: 0 : if (backupdir >= 0)
169 : 0 : close(backupdir);
170 [ # # ]: 0 : if (from >= 0)
171 : 0 : close(from);
172 [ # # ]: 0 : if (to >= 0)
173 : 0 : close(to);
174 : :
175 : 0 : return;
176 : 8 : }
|