pkg.c (7332B)
1 /* See LICENSE file for copyright and license details. */ 2 #include "pkg.h" 3 4 /* Create a package from the db entry. e.g. /var/pkg/pkg#version */ 5 struct pkg * 6 pkg_load(struct db *db, const char *file) 7 { 8 struct pkg *pkg; 9 struct pkgentry *pe; 10 FILE *fp; 11 char path[PATH_MAX]; 12 char *name, *version; 13 char *buf = NULL; 14 size_t sz = 0; 15 ssize_t len; 16 17 parse_db_name(file, &name); 18 parse_db_version(file, &version); 19 estrlcpy(path, db->path, sizeof(path)); 20 estrlcat(path, "/", sizeof(path)); 21 estrlcat(path, name, sizeof(path)); 22 if (version) { 23 estrlcat(path, "#", sizeof(path)); 24 estrlcat(path, version, sizeof(path)); 25 } 26 pkg = pkg_new(path, name, version); 27 free(name); 28 free(version); 29 30 if (!(fp = fopen(pkg->path, "r"))) { 31 weprintf("fopen %s:", pkg->path); 32 pkg_free(pkg); 33 return NULL; 34 } 35 36 while ((len = getline(&buf, &sz, fp)) != -1) { 37 if (len > 0 && buf[len - 1] == '\n') 38 buf[len - 1] = '\0'; 39 40 if (buf[0] == '\0') { 41 weprintf("%s: malformed pkg file\n", pkg->path); 42 free(buf); 43 fclose(fp); 44 pkg_free(pkg); 45 return NULL; 46 } 47 48 pe = pkgentry_new(db, buf); 49 TAILQ_INSERT_TAIL(&pkg->pe_head, pe, entry); 50 } 51 52 if (ferror(fp)) { 53 weprintf("%s: read error:", pkg->name); 54 free(buf); 55 fclose(fp); 56 pkg_free(pkg); 57 return NULL; 58 } 59 60 free(buf); 61 fclose(fp); 62 63 return pkg; 64 } 65 66 /* Create a package from a file. e.g. /tmp/pkg#version.pkg.tgz */ 67 struct pkg * 68 pkg_load_file(struct db *db, const char *file) 69 { 70 struct pkg *pkg; 71 struct pkgentry *pe; 72 struct archive *ar; 73 struct archive_entry *entry; 74 char path[PATH_MAX]; 75 const char *tmp; 76 char *name, *version; 77 int r; 78 79 if (!realpath(file, path)) { 80 weprintf("realpath %s:", file); 81 return NULL; 82 } 83 84 parse_name(path, &name); 85 parse_version(path, &version); 86 pkg = pkg_new(path, name, version); 87 free(name); 88 free(version); 89 90 ar = archive_read_new(); 91 92 archive_read_support_filter_gzip(ar); 93 archive_read_support_filter_bzip2(ar); 94 archive_read_support_filter_xz(ar); 95 archive_read_support_format_tar(ar); 96 97 if (archive_read_open_filename(ar, pkg->path, ARCHIVEBUFSIZ) < 0) { 98 weprintf("archive_read_open_filename %s: %s\n", pkg->path, 99 archive_error_string(ar)); 100 archive_read_free(ar); 101 pkg_free(pkg); 102 return NULL; 103 } 104 105 while (1) { 106 r = archive_read_next_header(ar, &entry); 107 if (r == ARCHIVE_EOF) 108 break; 109 if (r != ARCHIVE_OK) { 110 weprintf("archive_read_next_header: %s\n", 111 archive_error_string(ar)); 112 archive_read_free(ar); 113 pkg_free(pkg); 114 return NULL; 115 } 116 117 tmp = archive_entry_pathname(entry); 118 if (strncmp(tmp, "./", 2) == 0) 119 tmp += 2; 120 121 if (tmp[0] == '\0') 122 continue; 123 124 pe = pkgentry_new(db, tmp); 125 TAILQ_INSERT_TAIL(&pkg->pe_head, pe, entry); 126 } 127 128 archive_read_free(ar); 129 130 return pkg; 131 } 132 133 int 134 pkg_install(struct db *db, struct pkg *pkg) 135 { 136 struct archive *ar; 137 struct archive_entry *entry; 138 char cwd[PATH_MAX]; 139 int flags, r; 140 141 ar = archive_read_new(); 142 143 archive_read_support_filter_gzip(ar); 144 archive_read_support_filter_bzip2(ar); 145 archive_read_support_filter_xz(ar); 146 archive_read_support_format_tar(ar); 147 148 if (archive_read_open_filename(ar, pkg->path, ARCHIVEBUFSIZ) < 0) { 149 weprintf("archive_read_open_filename %s: %s\n", pkg->path, 150 archive_error_string(ar)); 151 archive_read_free(ar); 152 return -1; 153 } 154 155 if (!getcwd(cwd, sizeof(cwd))) { 156 weprintf("getcwd:"); 157 archive_read_free(ar); 158 return -1; 159 } 160 if (chdir(db->root) < 0) { 161 weprintf("chdir %s:", db->root); 162 archive_read_free(ar); 163 return -1; 164 } 165 166 while (1) { 167 r = archive_read_next_header(ar, &entry); 168 if (r == ARCHIVE_EOF) 169 break; 170 if (r != ARCHIVE_OK) { 171 weprintf("archive_read_next_header %s: %s\n", 172 archive_entry_pathname(entry), archive_error_string(ar)); 173 if (chdir(cwd) < 0) 174 weprintf("chdir %s:", cwd); 175 archive_read_free(ar); 176 return -1; 177 } 178 if (rej_match(db, archive_entry_pathname(entry)) > 0) { 179 weprintf("rejecting %s\n", archive_entry_pathname(entry)); 180 continue; 181 } 182 flags = ARCHIVE_EXTRACT_OWNER | ARCHIVE_EXTRACT_PERM | 183 ARCHIVE_EXTRACT_TIME | ARCHIVE_EXTRACT_SECURE_NODOTDOT; 184 if (fflag == 1) 185 flags |= ARCHIVE_EXTRACT_UNLINK; 186 r = archive_read_extract(ar, entry, flags); 187 if (r != ARCHIVE_OK && r != ARCHIVE_WARN) 188 weprintf("archive_read_extract %s: %s\n", 189 archive_entry_pathname(entry), archive_error_string(ar)); 190 } 191 192 archive_read_free(ar); 193 194 if (chdir(cwd) < 0) { 195 weprintf("chdir %s:", cwd); 196 return -1; 197 } 198 199 return 0; 200 } 201 202 static int 203 rm_empty_dir(const char *f, const struct stat *sb, int typeflag, 204 struct FTW *ftwbuf) 205 { 206 (void) sb; 207 (void) ftwbuf; 208 209 if (typeflag == FTW_DP) { 210 if (vflag == 1) 211 printf("removing %s\n", f); 212 rmdir(f); 213 } 214 return 0; 215 } 216 217 int 218 pkg_remove(struct db *db, struct pkg *pkg) 219 { 220 struct pkgentry *pe; 221 struct stat sb; 222 223 TAILQ_FOREACH_REVERSE(pe, &pkg->pe_head, pe_head, entry) { 224 if (rej_match(db, pe->rpath) > 0) { 225 weprintf("rejecting %s\n", pe->rpath); 226 continue; 227 } 228 229 if (lstat(pe->path, &sb) < 0) { 230 weprintf("lstat %s:", pe->path); 231 continue; 232 } 233 234 if (S_ISDIR(sb.st_mode) == 1) { 235 if (fflag == 0) 236 printf("ignoring directory %s\n", pe->path); 237 /* We'll remove these further down in a separate pass */ 238 continue; 239 } 240 241 if (S_ISLNK(sb.st_mode) == 1) { 242 if (fflag == 0) { 243 printf("ignoring link %s\n", pe->path); 244 continue; 245 } 246 } 247 248 if (vflag == 1) 249 printf("removing %s\n", pe->path); 250 if (remove(pe->path) < 0) 251 weprintf("remove %s:", pe->path); 252 } 253 254 if (fflag == 1) { 255 /* prune empty directories as well */ 256 TAILQ_FOREACH_REVERSE(pe, &pkg->pe_head, pe_head, entry) { 257 if (rej_match(db, pe->rpath) > 0) 258 continue; 259 if (db_links(db, pe->path) > 1) 260 continue; 261 nftw(pe->path, rm_empty_dir, 1, FTW_DEPTH); 262 } 263 } 264 265 TAILQ_REMOVE(&db->pkg_head, pkg, entry); 266 TAILQ_INSERT_TAIL(&db->pkg_rm_head, pkg, entry); 267 268 return 0; 269 } 270 271 /* Check if the file entries of the package 272 * collide with corresponding entries in the filesystem */ 273 int 274 pkg_collisions(struct pkg *pkg) 275 { 276 struct pkgentry *pe; 277 struct stat sb; 278 char resolvedpath[PATH_MAX]; 279 int r = 0; 280 281 TAILQ_FOREACH(pe, &pkg->pe_head, entry) { 282 if (access(pe->path, F_OK) == 0) { 283 if (stat(pe->path, &sb) < 0) { 284 weprintf("lstat %s:", pe->path); 285 return -1; 286 } 287 if (S_ISDIR(sb.st_mode) == 0) { 288 if (realpath(pe->path, resolvedpath)) 289 weprintf("%s exists\n", resolvedpath); 290 else 291 weprintf("%s exists\n", pe->path); 292 r = -1; 293 } 294 } 295 } 296 297 return r; 298 } 299 300 struct pkg * 301 pkg_new(const char *path, const char *name, const char *version) 302 { 303 struct pkg *pkg; 304 305 pkg = emalloc(sizeof(*pkg)); 306 pkg->name = estrdup(name); 307 if (version) 308 pkg->version = estrdup(version); 309 else 310 pkg->version = NULL; 311 estrlcpy(pkg->path, path, sizeof(pkg->path)); 312 TAILQ_INIT(&pkg->pe_head); 313 return pkg; 314 } 315 316 void 317 pkg_free(struct pkg *pkg) 318 { 319 struct pkgentry *pe, *tmp; 320 321 for (pe = TAILQ_FIRST(&pkg->pe_head); pe; pe = tmp) { 322 tmp = TAILQ_NEXT(pe, entry); 323 TAILQ_REMOVE(&pkg->pe_head, pe, entry); 324 pkgentry_free(pe); 325 } 326 free(pkg->name); 327 free(pkg->version); 328 free(pkg); 329 } 330 331 struct pkgentry * 332 pkgentry_new(struct db *db, const char *file) 333 { 334 struct pkgentry *pe; 335 336 pe = emalloc(sizeof(*pe)); 337 estrlcpy(pe->path, db->root, sizeof(pe->path)); 338 estrlcat(pe->path, "/", sizeof(pe->path)); 339 estrlcat(pe->path, file, sizeof(pe->path)); 340 estrlcpy(pe->rpath, file, sizeof(pe->rpath)); 341 return pe; 342 } 343 344 void 345 pkgentry_free(struct pkgentry *pe) 346 { 347 free(pe); 348 }