pkg_delete.c
1 /*- 2 * Copyright (c) 2011-2026 Baptiste Daroussin <bapt@FreeBSD.org> 3 * Copyright (c) 2011-2012 Julien Laffaye <jlaffaye@FreeBSD.org> 4 * Copyright (c) 2011 Will Andrews <will@FreeBSD.org> 5 * Copyright (c) 2011 Philippe Pepiot <phil@philpep.org> 6 * Copyright (c) 2014 Vsevolod Stakhov <vsevolod@FreeBSD.org> 7 * Copyright (c) 2023 Serenity Cyber Security, LLC 8 * Author: Gleb Popov <arrowd@FreeBSD.org> 9 * All rights reserved. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer 16 * in this position and unchanged. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 #ifdef HAVE_CONFIG_H 34 #include "pkg_config.h" 35 #endif 36 37 #include <assert.h> 38 #include <errno.h> 39 #include <string.h> 40 #include <unistd.h> 41 #include <stdlib.h> 42 #include <fcntl.h> 43 44 #include <bsd_compat.h> 45 46 #include "pkg.h" 47 #include "private/event.h" 48 #include "private/pkg.h" 49 #include "private/pkgdb.h" 50 #include "private/utils.h" 51 52 #if defined(UF_NOUNLINK) 53 #define NOCHANGESFLAGS (UF_IMMUTABLE | UF_APPEND | UF_NOUNLINK | SF_IMMUTABLE | SF_APPEND | SF_NOUNLINK) 54 #else 55 #define NOCHANGESFLAGS (UF_IMMUTABLE | UF_APPEND | SF_IMMUTABLE | SF_APPEND) 56 #endif 57 58 int 59 pkg_delete(struct pkg *pkg, struct pkg *rpkg, struct pkgdb *db, int flags, 60 struct triggers *t) 61 { 62 xstring *message = NULL; 63 int ret, cancel = 0; 64 bool handle_rc = false; 65 const unsigned load_flags = PKG_LOAD_RDEPS|PKG_LOAD_FILES|PKG_LOAD_DIRS| 66 PKG_LOAD_SCRIPTS|PKG_LOAD_ANNOTATIONS|PKG_LOAD_LUA_SCRIPTS; 67 68 assert(pkg != NULL); 69 assert(db != NULL); 70 71 if (pkgdb_ensure_loaded(db, pkg, load_flags) != EPKG_OK) 72 return (EPKG_FATAL); 73 if (rpkg != NULL && pkgdb_ensure_loaded(db, rpkg, load_flags) != EPKG_OK) 74 return (EPKG_FATAL); 75 76 pkg_emit_deinstall_begin(pkg); 77 78 /* If the package is locked */ 79 if (pkg->locked) { 80 pkg_emit_locked(pkg); 81 return (EPKG_LOCKED); 82 } 83 84 /* 85 * stop the different related services if the users do want that 86 * and that the service is running 87 */ 88 handle_rc = pkg_object_bool(pkg_config_get("HANDLE_RC_SCRIPTS")); 89 if (handle_rc) 90 pkg_start_stop_rc_scripts(pkg, PKG_RC_STOP); 91 92 if ((flags & PKG_DELETE_NOSCRIPT) == 0) { 93 bool noexec = ((flags & PKG_DELETE_NOEXEC) == PKG_DELETE_NOEXEC); 94 pkg_open_root_fd(pkg); 95 ret = pkg_lua_script_run(pkg, PKG_LUA_PRE_DEINSTALL, false); 96 if (ret != EPKG_OK && ctx.developer_mode) 97 return (ret); 98 ret = pkg_script_run(pkg, PKG_SCRIPT_PRE_DEINSTALL, false, noexec); 99 if (ret != EPKG_OK && (ctx.developer_mode || noexec)) 100 return (ret); 101 } 102 103 /* 104 * Execute per-package pre-deinstall triggers 105 */ 106 if (t != NULL) 107 triggers_execute_perpackage(t, pkg, TRIGGER_PHASE_PRE_DEINSTALL, 108 (flags & PKG_DELETE_UPGRADE) != 0); 109 110 if ((flags & PKG_DELETE_KEEPFILES) == 0) { 111 ret = pkg_delete_files(db, pkg, rpkg, flags, t); 112 if (ret == EPKG_CANCEL) 113 cancel = 1; 114 else if (ret != EPKG_OK) 115 return (ret); 116 } 117 118 if ((flags & PKG_DELETE_NOSCRIPT) == 0) { 119 bool noexec = ((flags & PKG_DELETE_NOEXEC) == PKG_DELETE_NOEXEC); 120 pkg_lua_script_run(pkg, PKG_LUA_POST_DEINSTALL, false); 121 ret = pkg_script_run(pkg, PKG_SCRIPT_POST_DEINSTALL, false, noexec); 122 if (ret != EPKG_OK && (ctx.developer_mode || noexec)) 123 return (ret); 124 } 125 126 /* 127 * Execute per-package post-deinstall triggers 128 */ 129 if (t != NULL) 130 triggers_execute_perpackage(t, pkg, TRIGGER_PHASE_POST_DEINSTALL, 131 (flags & PKG_DELETE_UPGRADE) != 0); 132 133 if ((flags & PKG_DELETE_KEEPFILES) == 0) { 134 ret = pkg_delete_dirs(db, pkg, NULL); 135 if (ret != EPKG_OK) 136 return (ret); 137 } 138 139 pkg_emit_deinstall_finished(pkg); 140 vec_foreach(pkg->message, i) { 141 if (pkg->message.d[i]->type == PKG_MESSAGE_REMOVE) { 142 if (message == NULL) { 143 message = xstring_new(); 144 pkg_fprintf(message->fp, "Message from " 145 "%n-%v:\n", pkg, pkg); 146 } 147 fprintf(message->fp, "%s\n", pkg->message.d[i]->str); 148 } 149 } 150 if (pkg_has_message(pkg) && message != NULL) { 151 fflush(message->fp); 152 pkg_emit_message(message->buf); 153 xstring_free(message); 154 } 155 156 ret = pkgdb_unregister_pkg(db, pkg->id); 157 if (ret != EPKG_OK) 158 return ret; 159 160 return (cancel ? EPKG_CANCEL : ret); 161 } 162 163 void 164 pkg_add_dir_to_del(struct pkg *pkg, const char *file, const char *dir) 165 { 166 char path[MAXPATHLEN]; 167 char *tmp; 168 size_t len, len2; 169 170 strlcpy(path, file != NULL ? file : dir, MAXPATHLEN); 171 172 if (file != NULL) { 173 tmp = strrchr(path, '/'); 174 tmp[1] = '\0'; 175 } 176 177 len = strlen(path); 178 179 /* make sure to finish by a / */ 180 if (len > 0 && path[len - 1] != '/' && len < MAXPATHLEN) { 181 path[len] = '/'; 182 len++; 183 path[len] = '\0'; 184 } 185 186 vec_foreach(pkg->dir_to_del, i) { 187 len2 = strlen(pkg->dir_to_del.d[i]); 188 if (len2 >= len && strncmp(path, pkg->dir_to_del.d[i], len) == 0) 189 return; 190 191 if (strncmp(path, pkg->dir_to_del.d[i], len2) == 0) { 192 pkg_debug(1, "Replacing in deletion %s with %s", 193 pkg->dir_to_del.d[i], path); 194 free(pkg->dir_to_del.d[i]); 195 pkg->dir_to_del.d[i] = xstrdup(path); 196 return; 197 } 198 } 199 200 pkg_debug(1, "Adding to deletion %s", path); 201 vec_push(&pkg->dir_to_del, xstrdup(path)); 202 } 203 204 static void 205 rmdir_p(struct pkgdb *db, struct pkg *pkg, char *dir, const char *prefix_r) 206 { 207 char *tmp; 208 int64_t cnt; 209 char fullpath[MAXPATHLEN]; 210 size_t len; 211 #ifdef HAVE_STRUCT_STAT_ST_FLAGS 212 struct stat st; 213 #if !defined(HAVE_CHFLAGSAT) 214 int fd; 215 #endif 216 #endif 217 218 len = snprintf(fullpath, sizeof(fullpath), "/%s", dir); 219 while (fullpath[len -1] == '/') { 220 fullpath[len - 1] = '\0'; 221 len--; 222 } 223 if (pkgdb_is_dir_used(db, pkg, fullpath, &cnt) != EPKG_OK) 224 return; 225 226 pkg_debug(1, "Number of packages owning the directory '%s': %d", 227 fullpath, (int)cnt); 228 /* 229 * At this moment the package we are removing have already been removed 230 * from the local database so if anything else is owning the directory 231 * that is another package meaning only remove the diretory is cnt == 0 232 */ 233 if (cnt > 0) 234 return; 235 236 if (STREQ(prefix_r, fullpath + 1)) 237 return; 238 239 pkg_debug(1, "removing directory %s", fullpath); 240 #ifdef HAVE_STRUCT_STAT_ST_FLAGS 241 if (fstatat(pkg->rootfd, dir, &st, AT_SYMLINK_NOFOLLOW) != -1) { 242 if (st.st_flags & NOCHANGESFLAGS) { 243 #ifdef HAVE_CHFLAGSAT 244 /* Disable all flags*/ 245 chflagsat(pkg->rootfd, dir, 0, AT_SYMLINK_NOFOLLOW); 246 #else 247 fd = openat(pkg->rootfd, dir, O_NOFOLLOW); 248 if (fd > 0) { 249 fchflags(fd, 0); 250 close(fd); 251 } 252 #endif 253 } 254 } 255 #endif 256 257 if (unlinkat(pkg->rootfd, dir, AT_REMOVEDIR) == -1) { 258 if (errno != ENOTEMPTY && errno != EBUSY) 259 pkg_emit_errno("unlinkat", dir); 260 /* If the directory was already removed by a bogus script, continue removing parents */ 261 if (errno != ENOENT) 262 return; 263 } 264 265 /* No recursivity for packages out of the prefix */ 266 if (strncmp(prefix_r, dir, strlen(prefix_r)) != 0) 267 return; 268 269 /* remove the trailing '/' */ 270 tmp = strrchr(dir, '/'); 271 if (tmp == NULL) 272 return; 273 if (tmp == dir) 274 return; 275 276 tmp[0] = '\0'; 277 tmp = strrchr(dir, '/'); 278 if (tmp == NULL) 279 return; 280 281 tmp[1] = '\0'; 282 283 rmdir_p(db, pkg, dir, prefix_r); 284 } 285 286 static void 287 pkg_effective_rmdir(struct pkgdb *db, struct pkg *pkg) 288 { 289 char prefix_r[MAXPATHLEN]; 290 291 snprintf(prefix_r, sizeof(prefix_r), "%s", pkg->prefix[0] ? pkg->prefix + 1 : ""); 292 vec_foreach(pkg->dir_to_del, i) { 293 rmdir_p(db, pkg, pkg->dir_to_del.d[i], prefix_r); 294 } 295 } 296 297 void 298 pkg_delete_file(struct pkg *pkg, struct pkg_file *file) 299 { 300 const char *path; 301 const char *prefix_rel; 302 size_t len; 303 #ifdef HAVE_STRUCT_STAT_ST_FLAGS 304 struct stat st; 305 #if !defined(HAVE_CHFLAGSAT) 306 int fd; 307 #endif 308 #endif 309 pkg_open_root_fd(pkg); 310 311 path = file->path; 312 path++; 313 314 prefix_rel = pkg->prefix; 315 prefix_rel++; 316 len = strlen(prefix_rel); 317 while (len > 0 && prefix_rel[len - 1] == '/') 318 len--; 319 320 #ifdef HAVE_STRUCT_STAT_ST_FLAGS 321 if (fstatat(pkg->rootfd, path, &st, AT_SYMLINK_NOFOLLOW) != -1) { 322 if (st.st_flags & NOCHANGESFLAGS) { 323 #ifdef HAVE_CHFLAGSAT 324 chflagsat(pkg->rootfd, path, 325 st.st_flags & ~NOCHANGESFLAGS, 326 AT_SYMLINK_NOFOLLOW); 327 #else 328 fd = openat(pkg->rootfd, path, O_NOFOLLOW); 329 if (fd > 0) { 330 fchflags(fd, st.st_flags & ~NOCHANGESFLAGS); 331 close(fd); 332 } 333 #endif 334 } 335 } 336 #endif 337 pkg_debug(1, "Deleting file: '%s'", path); 338 if (unlinkat(pkg->rootfd, path, 0) == -1) { 339 if (errno == ENOENT) 340 pkg_emit_file_missing(pkg, file); 341 else 342 pkg_emit_errno("unlinkat", path); 343 return; 344 } 345 346 /* do not bother about directories not in prefix */ 347 if ((strncmp(prefix_rel, path, len) == 0) && path[len] == '/') 348 pkg_add_dir_to_del(pkg, path, NULL); 349 } 350 351 /* 352 * Handle a special case: the package is to be upgraded but is being deleted 353 * temporarily to handle a file path conflict. In this situation we shouldn't 354 * remove configuration files. For now, keep them if the replacement package 355 * contains a configuration file at the same path. 356 * 357 * Note, this currently doesn't handle the case where a configuration file 358 * participates in the conflict, i.e., it moves from one package to another. 359 */ 360 static bool 361 pkg_delete_skip_config(struct pkg *pkg, struct pkg *rpkg, struct pkg_file *file, 362 int flags) 363 { 364 if ((flags & PKG_DELETE_UPGRADE) == 0) 365 return (false); 366 if (pkghash_get(pkg->config_files_hash, file->path) == NULL) 367 return (false); 368 if (pkghash_get(rpkg->config_files_hash, file->path) == NULL) 369 return (false); 370 return (true); 371 } 372 373 int 374 pkg_delete_files(struct pkgdb *db, struct pkg *pkg, struct pkg *rpkg, int flags, 375 struct triggers *t) 376 { 377 struct pkg_file *file = NULL; 378 int nfiles, cur_file = 0; 379 int retcode = EPKG_OK; 380 381 nfiles = pkghash_count(pkg->filehash); 382 if (nfiles == 0) 383 return (EPKG_OK); 384 385 pkg_emit_delete_files_begin(pkg); 386 pkg_emit_progress_start(NULL); 387 388 while (pkg_files(pkg, &file) == EPKG_OK) { 389 if (pkg_delete_skip_config(pkg, rpkg, file, flags)) 390 continue; 391 if ((flags & PKG_DELETE_UPGRADE) != 0) 392 pkg_maybe_backup_library(db, pkg, file->path); 393 append_touched_file(file->path); 394 if (pkg_emit_progress_tick(cur_file++, nfiles)) 395 retcode = EPKG_CANCEL; 396 trigger_is_it_a_cleanup(t, file->path); 397 pkg_delete_file(pkg, file); 398 } 399 400 pkg_emit_progress_tick(nfiles, nfiles); 401 pkg_emit_delete_files_finished(pkg); 402 403 return (retcode); 404 } 405 406 void 407 pkg_delete_dir(struct pkg *pkg, struct pkg_dir *dir) 408 { 409 const char *path; 410 const char *prefix_rel; 411 size_t len; 412 413 pkg_open_root_fd(pkg); 414 415 path = dir->path; 416 /* remove the first / */ 417 path++; 418 419 prefix_rel = pkg->prefix; 420 prefix_rel++; 421 len = strlen(prefix_rel); 422 while (len > 0 && prefix_rel[len - 1] == '/') 423 len--; 424 425 if ((strncmp(prefix_rel, path, len) == 0) && path[len] == '/') { 426 pkg_add_dir_to_del(pkg, NULL, path); 427 } else { 428 vec_push(&pkg->dir_to_del, xstrdup(path)); 429 } 430 } 431 432 int 433 pkg_delete_dirs(__unused struct pkgdb *db, struct pkg *pkg, struct pkg *new) 434 { 435 struct pkg_dir *dir = NULL; 436 437 while (pkg_dirs(pkg, &dir) == EPKG_OK) { 438 if (new != NULL && pkg_has_dir(new, dir->path)) 439 continue; 440 pkg_delete_dir(pkg, dir); 441 } 442 443 pkg_effective_rmdir(db, pkg); 444 445 return (EPKG_OK); 446 }