From 3b7491d29b85fac57e473ccb1c952fdac815d1d8 Mon Sep 17 00:00:00 2001 From: Juan RP Date: Sat, 24 Dec 2011 01:05:26 +0100 Subject: [PATCH] Merged purge code in remove, configurable transaction regpkgdb flushing. See the NEWS file for info. --- NEWS | 23 ++- bin/xbps-bin/check_pkg_requiredby.c | 65 +++----- bin/xbps-bin/defs.h | 4 +- bin/xbps-bin/main.c | 48 ++---- bin/xbps-bin/state_cb.c | 12 -- bin/xbps-bin/transaction.c | 8 +- bin/xbps-bin/xbps-bin.8 | 62 ++------ bin/xbps-dgraph/main.c | 1 + bin/xbps-uhelper/main.c | 3 + doc/xbps_regpkgdb_dictionary.dot | 6 +- etc/.xbps.conf.swp | Bin 0 -> 12288 bytes etc/xbps.conf | 18 ++- include/xbps_api.h | 92 ++++++----- include/xbps_api_impl.h | 2 +- lib/Makefile | 2 +- lib/initend.c | 31 ++-- lib/package_configure.c | 3 +- lib/package_orphans.c | 5 +- lib/package_purge.c | 233 ---------------------------- lib/package_register.c | 178 ++++++++++----------- lib/package_remove.c | 229 ++++++++++++++++++--------- lib/package_requiredby.c | 46 +----- lib/package_state.c | 119 +++++--------- lib/package_unpack.c | 11 +- lib/plist.c | 2 +- lib/plist_find.c | 6 +- lib/plist_remove.c | 21 ++- lib/regpkgdb_dictionary.c | 131 +++++++++++----- lib/transaction_commit.c | 41 +++-- lib/transaction_dictionary.c | 2 + lib/transaction_ops.c | 22 +-- lib/transaction_package_replace.c | 5 +- 32 files changed, 613 insertions(+), 818 deletions(-) create mode 100644 etc/.xbps.conf.swp delete mode 100644 lib/package_purge.c diff --git a/NEWS b/NEWS index 6281f767..995da8a1 100644 --- a/NEWS +++ b/NEWS @@ -1,4 +1,25 @@ -xbps-0.11.1 (???): +xbps-0.12.0 (???): + + * Renamed some options in xbps.conf to not have dashes, such as: + fetch-timeout-connection -> FetchTimeoutConnection + fetch-cache-connections-host -> FetchCacheConnections + fetch-cache-connections-per-host -> FetchCacheConnectionsPerHost + + * Implemented memory caching for regpkgdb and configurarable transaction + flushing. Can be changed in xbps.conf with "TransactionFrequencyFlusing". + By default set to 5. That means that every 5 packages processed in + a transaction there will be a regpkgdb plist flush to disk. + + Setting it to 0 enables automatic mode which will only flush in + two required points. Setting it to 1 makes the behaviour used in XBPS<=0.11, + which flushed it on every package. + + That feature provides a 25% (and in some cases even more!) of performance + when executing a transaction. + + * Merged purge code into remove. It wasn't necessary to have this splitted, + so it now has been merged into xbps_remove_pkg(). That also means that + '-p' flag in xbps-bin(8) and xbps-repo(8) doesn't exist anymore. * xbps-repo(8): the 'find-files' target accepts multiple patterns, such as: $ xbps-repo find-files /bin/cat '/bin/f*' ... diff --git a/bin/xbps-bin/check_pkg_requiredby.c b/bin/xbps-bin/check_pkg_requiredby.c index 367264eb..3f0a7f1c 100644 --- a/bin/xbps-bin/check_pkg_requiredby.c +++ b/bin/xbps-bin/check_pkg_requiredby.c @@ -35,44 +35,6 @@ #include #include "defs.h" -static int -write_pkgd_to_regpkgdb(prop_dictionary_t pkgd, - prop_array_t regpkgs, - const char *pkgn) -{ - struct xbps_handle *xhp = xbps_handle_get(); - char *path; - int rv; - - rv = xbps_array_replace_dict_by_name(regpkgs, pkgd, pkgn); - if (rv != 0) { - xbps_error_printf("%s: failed to replace pkgd: %s\n", - pkgn, strerror(rv)); - return -1; - } - if (!prop_dictionary_set(xhp->regpkgdb_dictionary, - "packages", regpkgs)) { - xbps_error_printf("%s: failed to set new regpkgdb " - "packages array: %s", pkgn, strerror(errno)); - return -1; - } - path = xbps_xasprintf("%s/%s/%s", xhp->rootdir, - XBPS_META_PATH, XBPS_REGPKGDB); - if (path == NULL) - return -1; - - if (!prop_dictionary_externalize_to_zfile( - xhp->regpkgdb_dictionary, path)) { - xbps_error_printf("%s: failed to write regpkgdb plist:" - " %s\n", pkgn, strerror(errno)); - free(path); - return -1; - } - free(path); - - return 0; -} - /* * Checks package integrity of an installed package. * The following task is accomplished in this file: @@ -94,6 +56,8 @@ check_pkg_requiredby(prop_dictionary_t pkgd_regpkgdb, struct xbps_handle *xhp = xbps_handle_get(); const char *curpkgn, *pkgname, *pkgver; size_t i; + int rv; + bool pkg_fixed = false; (void)pkg_propsd; (void)pkg_filesd; @@ -101,7 +65,7 @@ check_pkg_requiredby(prop_dictionary_t pkgd_regpkgdb, prop_dictionary_get_cstring_nocopy(pkgd_regpkgdb, "pkgname", &pkgname); prop_dictionary_get_cstring_nocopy(pkgd_regpkgdb, "pkgver", &pkgver); - regpkgs = prop_dictionary_get(xhp->regpkgdb_dictionary, "packages"); + regpkgs = prop_dictionary_get(xhp->regpkgdb, "packages"); for (i = 0; i < prop_array_count(regpkgs); i++) { obj = prop_array_get(regpkgs, i); @@ -181,13 +145,30 @@ check_pkg_requiredby(prop_dictionary_t pkgd_regpkgdb, */ prop_array_add(reqby, curpkgver); prop_dictionary_set(pkgd_regpkgdb, "requiredby", reqby); - if (write_pkgd_to_regpkgdb(pkgd_regpkgdb, regpkgs, pkgname) != 0) + rv = xbps_array_replace_dict_by_name(regpkgs, obj, curpkgn); + if (rv != 0) { + xbps_error_printf("%s: failed to replace pkgd: %s\n", + curpkgn, strerror(rv)); return -1; - + } + if (!prop_dictionary_set(xhp->regpkgdb, "packages", regpkgs)) { + xbps_error_printf("%s: failed to set new regpkgdb " + "packages array: %s", curpkgn, strerror(errno)); + return -1; + } + pkg_fixed = true; printf("%s: added requiredby entry for %s.\n", pkgver, prop_string_cstring_nocopy(curpkgver)); prop_object_release(curpkg_propsd); } + if (pkg_fixed == false) + return rv; - return 0; + if ((rv = xbps_regpkgdb_update(xhp, true)) != 0) { + xbps_error_printf("failed to write regpkgdb plist: " + " %s\n", strerror(rv)); + return rv; + } + + return rv; } diff --git a/bin/xbps-bin/defs.h b/bin/xbps-bin/defs.h index 59b1d310..bd689e8a 100644 --- a/bin/xbps-bin/defs.h +++ b/bin/xbps-bin/defs.h @@ -47,9 +47,9 @@ struct list_pkgver_cb { /* from transaction.c */ int install_new_pkg(const char *, bool); int update_pkg(const char *); -int remove_pkg(const char *, bool, bool); +int remove_pkg(const char *, bool); int autoupdate_pkgs(bool, bool); -int autoremove_pkgs(bool, bool); +int autoremove_pkgs(bool); int exec_transaction(bool, bool); /* from remove.c */ diff --git a/bin/xbps-bin/main.c b/bin/xbps-bin/main.c index f99c72d5..b83fd0c4 100644 --- a/bin/xbps-bin/main.c +++ b/bin/xbps-bin/main.c @@ -68,17 +68,17 @@ main(int argc, char **argv) struct sigaction sa; const char *rootdir, *cachedir, *conffile, *option; int i, c, flags, rv; - bool yes, purge, debug, reqby_force, force_rm_with_deps, recursive_rm; + bool yes, debug, reqby_force, force_rm_with_deps, recursive_rm; bool install_auto, install_manual, show_download_pkglist_url; bool reinstall; rootdir = cachedir = conffile = option = NULL; flags = rv = 0; - reqby_force = yes = purge = force_rm_with_deps = false; + reqby_force = yes = force_rm_with_deps = false; recursive_rm = debug = reinstall = false; install_auto = install_manual = show_download_pkglist_url = false; - while ((c = getopt(argc, argv, "AC:c:dDFfMo:pRr:Vvy")) != -1) { + while ((c = getopt(argc, argv, "AC:c:dDFfMo:Rr:Vvy")) != -1) { switch (c) { case 'A': install_auto = true; @@ -109,9 +109,6 @@ main(int argc, char **argv) case 'o': option = optarg; break; - case 'p': - purge = true; - break; case 'R': recursive_rm = true; break; @@ -147,15 +144,6 @@ main(int argc, char **argv) exit(EXIT_FAILURE); } - /* - * Register a signal handler to clean up resources used by libxbps. - */ - memset(&sa, 0, sizeof(sa)); - sa.sa_handler = cleanup; - sigaction(SIGINT, &sa, NULL); - sigaction(SIGTERM, &sa, NULL); - sigaction(SIGQUIT, &sa, NULL); - /* * Initialize libxbps. */ @@ -185,6 +173,14 @@ main(int argc, char **argv) exit(EXIT_FAILURE); } + /* + * Register a signal handler to clean up resources used by libxbps. + */ + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = cleanup; + sigaction(SIGINT, &sa, NULL); + sigaction(SIGTERM, &sa, NULL); + if (strcasecmp(argv[0], "list") == 0) { /* Lists packages currently registered in database. */ if (argc < 1 || argc > 2) @@ -199,12 +195,12 @@ main(int argc, char **argv) lpc.state = XBPS_PKG_STATE_HALF_UNPACKED; else if (strcmp(argv[1], "unpacked") == 0) lpc.state = XBPS_PKG_STATE_UNPACKED; - else if (strcmp(argv[1], "config-files") == 0) - lpc.state = XBPS_PKG_STATE_CONFIG_FILES; + else if (strcmp(argv[1], "half-removed") == 0) + lpc.state = XBPS_PKG_STATE_HALF_REMOVED; else { fprintf(stderr, "E: invalid state `%s'. Accepted values: " - "config-files, unpacked, " + "half-removed, unpacked, half-unpacked, " "installed [default]\n", argv[1]); rv = -1; goto out; @@ -249,7 +245,7 @@ main(int argc, char **argv) usage(xhp); for (i = 1; i < argc; i++) { - rv = remove_pkg(argv[i], purge, recursive_rm); + rv = remove_pkg(argv[i], recursive_rm); if (rv == 0) continue; else if (rv != EEXIST) @@ -323,19 +319,7 @@ main(int argc, char **argv) if (argc != 1) usage(xhp); - rv = autoremove_pkgs(yes, purge); - - } else if (strcasecmp(argv[0], "purge") == 0) { - /* - * Purge a package completely. - */ - if (argc != 2) - usage(xhp); - - if (strcasecmp(argv[1], "all") == 0) - rv = xbps_purge_packages(); - else - rv = xbps_purge_pkg(argv[1], true); + rv = autoremove_pkgs(yes); } else if (strcasecmp(argv[0], "reconfigure") == 0) { /* diff --git a/bin/xbps-bin/state_cb.c b/bin/xbps-bin/state_cb.c index 10f92fb8..fa4c93eb 100644 --- a/bin/xbps-bin/state_cb.c +++ b/bin/xbps-bin/state_cb.c @@ -66,9 +66,6 @@ state_cb(const struct xbps_state_cb_data *xscd, void *cbdata) case XBPS_STATE_REMOVE: printf("Removing `%s-%s' ...\n", xscd->pkgname, xscd->version); break; - case XBPS_STATE_PURGE: - printf("Purging `%s-%s' ...\n", xscd->pkgname, xscd->version); - break; case XBPS_STATE_CONFIGURE: printf("Configuring `%s-%s' ...\n", xscd->pkgname, xscd->version); @@ -125,21 +122,12 @@ state_cb(const struct xbps_state_cb_data *xscd, void *cbdata) "(rootdir: %s).", xscd->pkgname, xscd->version, xhp->rootdir); break; - case XBPS_STATE_PURGE_DONE: - printf("Purged `%s-%s' successfully.\n", - xscd->pkgname, xscd->version); - if (xhp->syslog_enabled) - syslog(LOG_NOTICE, "Purged `%s-%s' successfully " - "(rootdir: %s).", xscd->pkgname, xscd->version, - xhp->rootdir); - break; /* errors */ case XBPS_STATE_UNPACK_FAIL: case XBPS_STATE_UPDATE_FAIL: case XBPS_STATE_CONFIGURE_FAIL: case XBPS_STATE_REGISTER_FAIL: case XBPS_STATE_UNREGISTER_FAIL: - case XBPS_STATE_PURGE_FAIL: case XBPS_STATE_REMOVE_FAIL: case XBPS_STATE_VERIFY_FAIL: case XBPS_STATE_DOWNLOAD_FAIL: diff --git a/bin/xbps-bin/transaction.c b/bin/xbps-bin/transaction.c index 5baa0782..a9395a99 100644 --- a/bin/xbps-bin/transaction.c +++ b/bin/xbps-bin/transaction.c @@ -222,11 +222,11 @@ autoupdate_pkgs(bool yes, bool show_download_pkglist_url) } int -autoremove_pkgs(bool yes, bool purge) +autoremove_pkgs(bool yes) { int rv = 0; - if ((rv = xbps_transaction_autoremove_pkgs(purge)) != 0) { + if ((rv = xbps_transaction_autoremove_pkgs()) != 0) { if (rv == ENOENT) { printf("No package orphans were found.\n"); return 0; @@ -328,7 +328,7 @@ update_pkg(const char *pkgname) } int -remove_pkg(const char *pkgname, bool purge, bool recursive) +remove_pkg(const char *pkgname, bool recursive) { prop_dictionary_t pkgd; prop_array_t reqby; @@ -336,7 +336,7 @@ remove_pkg(const char *pkgname, bool purge, bool recursive) size_t x; int rv; - rv = xbps_transaction_remove_pkg(pkgname, purge, recursive); + rv = xbps_transaction_remove_pkg(pkgname, recursive); if (rv == EEXIST) { /* pkg has revdeps */ pkgd = xbps_find_pkg_dict_installed(pkgname, false); diff --git a/bin/xbps-bin/xbps-bin.8 b/bin/xbps-bin/xbps-bin.8 index eba07240..4353e3c1 100644 --- a/bin/xbps-bin/xbps-bin.8 +++ b/bin/xbps-bin/xbps-bin.8 @@ -1,4 +1,4 @@ -.Dd December 22, 2011 +.Dd December 23, 2011 .Os Void GNU/Linux .Dt xbps-bin 8 .Sh NAME @@ -60,7 +60,6 @@ depending on it, i.e package is a dependency of any other installed package. .It Fl f Used currently in the .Em install , -.Em purge , .Em reconfigure and .Em remove @@ -69,10 +68,8 @@ targets. If set, package(s) will be reconfigured regardless of its state in target, or to .Em force removal of package files even if its hash does not match in the -.Em purge -and .Em remove -targets. If set, package(s) will be reinstalled even if its state is +target. If set, package(s) will be reinstalled even if its state is .Em installed when used with the .Em install @@ -95,13 +92,6 @@ Used currently in the target. Prints the value of specified key(s) from package's properties dictionary. Multiple keys can be specified delimited by the comma character. -.It Fl p -Used currently in the -.Em remove -and -.Em autoremove -targets. If enabled, after removing -a package it is also purged. .It Fl R Used currently in the .Em remove @@ -175,28 +165,14 @@ to list only packages with the specified By default only packages fully installed will be listed if .Em state has not been specified. Accepted states are: -.Em config-files , +.Em half-removed , .Em half-unpacked , -.Em unpacked , +.Em installed and -.Em installed . +.Em unpacked . .It Sy list-manual Lists packages that were installed manually by the user, i.e not as dependencies of any other package. -.It Sy purge Ar pkgname | Ar all -Purge an installed package: -.Em pkgname -or -.Em all -packages. The purge stage runs the post-remove action set in the REMOVE script -in its metadata directory -.Pa (/var/db/xbps/metadata/pkgname) -and will remove configuration (if they were not modified by the user) and -metadata files. The package will be fully removed from the system once it -has been purged. If -.Ql -f -option is used, configuration files that have been -.Em modified WILL BE REMOVED. BEWARE WITH THIS! .It Sy reconfigure Ar pkgname | Ar all Reconfigure an unpacked package. Packages in this state are not fully installed, because they were not configured for whatever reason. The configure stage will @@ -209,16 +185,7 @@ option is used, the package will be reconfigured even if its state is already in .It Sy remove Ar pkgname(s) Removes the installed package .Em pkgname(s) . -Its files will be removed and its state will be changed to -.Em config-files -in the package database. Configuration files, its metadata directory/files and its -information in the package database are preserved. To fully remove a package in -.Em config-files -state, it must be purged with the -.Em purge -command or alternatively use the -.Ql -p -flag. If +Files not matching the original SHA256 hash will be preserved. If .Ql -f option is used, package files will be .Em removed even if its SHA256 hash don't match . @@ -257,10 +224,9 @@ target that will update all currently installed packages. A package can be in a different state while it is being .Em installed , .Em removed , -.Em unpacked , -.Em configured +.Em unpacked or -.Em purged . +.Em configured . The following states are available: .Bl -tag -width ident .It Sy installed @@ -271,11 +237,13 @@ The package was being unpacked but didn't finish properly for unknown reasons. The package has been unpacked in destination root directory, but it is not fully installed because it was not yet configured. Please note that some packages will do not work if they are only unpacked. -.It Sy config-files -The package has been removed but configuration files and its metadata directory -are still available (and it is still registered in the package database). -You can purge safely packages that are in this state, modified configuration -files will be preserved. +.It Sy half-remove +The package removal did not finish for unknown reasons (power outage, process killed, etc). +The +.Em purge +action in its metadata REMOVE script has not been yet executed. The package +metadata directory is still available and it is registered in package database. +Packages in this state can be still removed. .Sh FILES .Bl -tag -width /var/db/xbps/metadata//props.plist -compact .It Pa /etc/xbps/xbps.conf diff --git a/bin/xbps-dgraph/main.c b/bin/xbps-dgraph/main.c index 200d6d49..ec2436b0 100644 --- a/bin/xbps-dgraph/main.c +++ b/bin/xbps-dgraph/main.c @@ -94,6 +94,7 @@ die(const char *fmt, ...) vfprintf(stderr, fmt, ap); fprintf(stderr, " (%s)\n", strerror(save_errno)); va_end(ap); + xbps_end(xbps_handle_get()); exit(EXIT_FAILURE); } diff --git a/bin/xbps-uhelper/main.c b/bin/xbps-uhelper/main.c index ab6a0fa7..d061bdf5 100644 --- a/bin/xbps-uhelper/main.c +++ b/bin/xbps-uhelper/main.c @@ -215,6 +215,9 @@ main(int argc, char **argv) in_chroot ? "[chroot] " : "" , argv[1], argv[2], strerror(rv), MSG_RESET); } else { + if ((rv = xbps_regpkgdb_update(xhp, true)) != 0) + exit(EXIT_FAILURE); + printf("%s%s=> %s-%s registered successfully.%s\n", MSG_NORMAL, in_chroot ? "[chroot] " : "", argv[1], argv[2], MSG_RESET); diff --git a/doc/xbps_regpkgdb_dictionary.dot b/doc/xbps_regpkgdb_dictionary.dot index 0701c6c3..b16e2368 100644 --- a/doc/xbps_regpkgdb_dictionary.dot +++ b/doc/xbps_regpkgdb_dictionary.dot @@ -17,11 +17,13 @@ digraph regpkgdb_dictionary { pkgdict -> pkgver [label="string"]; pkgdict -> state [label="string"]; state -> state_inst [label="value"]; - state -> state_cffiles [label="value"]; + state -> state_hfuned [label="value"]; state -> state_unpack [label="value"]; + state -> state_hfrmed [label="value"]; state_inst [style=filled,fillcolor="yellowgreen",label="installed"]; - state_cffiles [style=filled,fillcolor="yellowgreen",label="config-files"]; + state_hfuned [style=filled,fillcolor="yellowgreen",label="half-unpacked"]; state_unpack [style=filled,fillcolor="yellowgreen",label="unpacked"]; + state_hfrmed [style=filled,fillcolor="yellowgreen",label="half-removed"]; pkgdict -> automatic [label="bool"]; automatic [label="automatic-install"]; pkgdict -> short_desc [label="string"] diff --git a/etc/.xbps.conf.swp b/etc/.xbps.conf.swp new file mode 100644 index 0000000000000000000000000000000000000000..a70288a33106c8347fff3a0488905f8b07d5b8e2 GIT binary patch literal 12288 zcmeHNO^g&p6fQKvq9XpBJn>{n7UIs#^5eP^-~j6e5=DfSD8^__clC6!HC1g@_0Eon zUJZ%ypeH#PZ^nZM@I>3IT34;k72s&z53o)-+LWG zcjwNZdY+zcA7uDE%-G}G{yKf(nJKn&iLr|{*WvQ5KH6lyw%Xik-8&&+r?Tdv$h_;U zbt~5qK8t^8XGRydN|5d+1(E`Hpui4x@WB4LkYIZE6ZF`lFWo_|6q*!B3M2)R0!e|S zKvEznkQ7J?+-(Z@Y72W8r0;2nFE-y>uKR9&rmv(xQXnai6i5mr1(E_ufuulEASsX( zND3qc?m`84&e+zij2+kp^7#M%@xT9n-^tiD;9KAe;8Wlepah--{&CK*b4lxgR!rGFM$f+z#G6W;I{`E`v&+LxC(p>Tmjw#o&z2Metdwjj{prQU@veV za4&G}e#SlrJ_B-K7x43T#(n}m0Nw}Q23`dA0Dn#)2KW$o4R{r}04xEEz#iaNXz&Yg z70`eJ4go=%{XqI81(E_ufuz9yS%GObP1{$c^)*+mif1dlC#W!nE|KT9C%mJh)K$D} z&CODmzt!45OYL@>F0&BnDv`-Tikze-UkaLOf@a86UK&lV&Pw9$FczOGh|_orS67v> z$lkA&mz5IKkQlFUA)gbJaZOzjcl!s=BUW%#t@JeSi({J@A8E2RH(RU1I?y>5c+)b7 z7Dg#Ekh({1s6AgJ>8N%h2T`mzKN4iZrOnu7w!QSeI@}q(;HOQMnOwAu?RBiEjO%2z zwL<%j#;bo;h|b!={Oj|FZa<3Ktem~w<)h@+E$F?BRE&+}N4u@rnu1E~}o9^HpxqdSewg$-JvS~p8v=OYfLYW0I=6BXAR z3XHK>$JAq|qL16kWLzCym|K{O#%+bdvC9jwJ-LF=oM72WMJJb+&roR15n1I-Ah+J= z>kW-8L2xYw0+gB#o0OB4#yFuvMFmQ&tDO6wF18w!G7JTjz3CLjLMUTaFi|+Hp&`{| z4q?QEmuy?G_1=YjQIz;QB*BGQY>h(;l*C#lVtt67Y%#AR$D9cl1c1z(;Px@u*lbqzdcvZLb3><050t&FF_r0A z&AVtaH@e(M3Oqodg#&|d6sug-=nq2$S7;PCAu`IP3vsB4O)ufC>2g{21zPQd(Hbos zo*YN%;2btsY&y-47LbyCR2D3SlWf*vKd^QJSMs1!lk)`6O0k~tjIbv|^C0ntyp^!6 zIEO}wp-dLS@{Q@kc+pe@p25OltlWGX%@D?bTJkFOZr&AqO?f4%55hSi(QQL z2I|^@gr<;V>|l=vq6c^G;2wpBTaDU>gRsW<)?{D?GvRscybT3)MK5$j?4K}cZ=A8H z(XnAL<Kcqe;GS!g0z{j_Ill&%pwX$}yYAPKyU~7Bof`b&w_eT2B%e(9wVSgpKid WmA%@cIG7|(_+W;YkDoc$W`6?!cSIxr literal 0 HcmV?d00001 diff --git a/etc/xbps.conf b/etc/xbps.conf index 30341630..b85638f1 100644 --- a/etc/xbps.conf +++ b/etc/xbps.conf @@ -2,24 +2,30 @@ # ============================ # # Root directory. -#rootdir = / +#RootDir = / # # Cache directory to store downloaded binary packages. # If string begins with '/' it will be treated as full path, # otherwise it will be treated as relative to the root-directory. -#cachedir = var/cache/xbps +#CacheDir = var/cache/xbps # # Default global limit of cached connections when fetching files. -#fetch-cache-connections = 10 +#FetchCacheConnection = 10 # # Default per-host limit of cached connections when fetching files. -#fetch-cache-connections-per-host = 3 +#FetchCacheConnectionPerHost = 3 # # Default timeout limit for connections, in seconds. -#fetch-timeout-connection = 30 +#FetchTimeoutConnection = 30 # # Enable syslog messages, set the value to false or 0 to disable. -#syslog = true +#Syslog = true + +# Number of packages to be processed in a transaction to trigger +# a flush to the master package database. Set it to 0 to make it +# only flush at required points. +# +#TransactionFrequencyFlush = 25 # Repositories. # diff --git a/include/xbps_api.h b/include/xbps_api.h index f58d7a22..4f8686d3 100644 --- a/include/xbps_api.h +++ b/include/xbps_api.h @@ -56,7 +56,7 @@ */ #define XBPS_PKGINDEX_VERSION "1.3" -#define XBPS_API_VERSION "20111223" +#define XBPS_API_VERSION "20111224" #define XBPS_VERSION "0.12" /** @@ -159,6 +159,13 @@ */ #define XBPS_FETCH_TIMEOUT 30 +/** + * @def XBPS_TRANS_FLUSH + * Default number of packages to be processed in a transaction to + * trigger a flush to the master package database XBPS_REGPKGDB. + */ +#define XBPS_TRANS_FLUSH 5 + __BEGIN_DECLS void xbps_dbg_printf(const char *, ...); @@ -187,8 +194,6 @@ void xbps_warn_printf(const char *, ...); * XBPS_STATE_REMOVE_DONE: a package has been removed successfully. * XBPS_STATE_REMOVE_FILE: a package file is being removed. * XBPS_STATE_REMOVE_OBSOLETE: an obsolete package file is being removed. - * XBPS_STATE_PURGE: a package is being purged. - * XBPS_STATE_PURGE_DONE: a package has been purged successfully. * XBPS_STATE_REPLACE: a package is being replaced. * XBPS_STATE_INSTALL: a package is being installed. * XBPS_STATE_INSTALL_DONE: a package has been installed successfully. @@ -209,7 +214,6 @@ void xbps_warn_printf(const char *, ...); * its hash has failed. * XBPS_STATE_REMOVE_FILE_OBSOLETE_FAIL: an obsolete package file * removal has failed. - * XBPS_STATE_PURGE_FAIL: package purge has failed. * XBPS_STATE_CONFIGURE_FAIL: package configure has failed. * XBPS_STATE_CONFIG_FILE_FAIL: package configuration file operation * has failed. @@ -419,12 +423,12 @@ struct xbps_handle { */ cfg_t *cfg; /** - * @private regpkgdb_dictionary. + * @private regpkgdb. * * Internalized proplib dictionary with the registed package database * stored in XBPS_META_PATH/XBPS_REGPKGDB. */ - prop_dictionary_t regpkgdb_dictionary; + prop_dictionary_t regpkgdb; /** * @private * @@ -498,13 +502,20 @@ struct xbps_handle { */ const char *conffile; /** - * @private fetch_timeout + * @var fetch_timeout * * Unsigned integer to specify libfetch's timeout limit. * If not set, it defaults to 30 (in seconds). This is set internally * by the API from a setting in configuration file. */ uint16_t fetch_timeout; + /** + * @var transaction_frequency_flush + * + * Number of packages to be processed in a transaction to + * trigger a flush to the master databases. + */ + uint16_t transaction_frequency_flush; /** * @var flags * @@ -554,8 +565,8 @@ struct xbps_handle { * - Set default cache connections for libfetch. * - Parse configuration file. * - * @param[in] xhp Pointer to an xbps_handle structure, as returned by - * \a xbps_handle_alloc(). + * @param[in] xhp The xbps_handle structure previously allocated + * by \a xbps_handle_alloc(). * @note It's assumed that \a xhp is a valid pointer. * * @return 0 on success, an errno value otherwise. @@ -797,6 +808,32 @@ int xbps_regpkgdb_foreach_reverse_pkg_cb( int (*fn)(prop_object_t, void *, bool *), void *arg); +/** + * Returns a package dictionary from regpkgdb plist, matching pkgname or + * pkgver specified in \a pkg. + * + * @param[in] pkg Package name or name-version tuple to match. + * @param[in] bypattern If false \a pkg must be a pkgname, otherwise a pkgver. + * + * @return The matching proplib package dictionary from regpkgdb copied + * with \a prop_dictionary_copy() so it must be released when not required + * anymore with prop_object_release(). + */ +prop_dictionary_t xbps_regpkgdb_get_pkgd(const char *pkg, bool bypattern); + +/** + * Updates the regpkgdb plist with new contents from disk to the cached copy + * in memory. + * + * @param[in] xhp Pointer to our xbps_handle struct, as returned by + * \a xbps_handle_get() or xbps_handle_alloc(). + * @param[in] flush If true the regpkgdb plist contents in memory will + * be flushed atomically to disk. + * + * @return 0 on success, otherwise an errno value. + */ +int xbps_regpkgdb_update(struct xbps_handle *xhp, bool flush); + /** * Finds the proplib's dictionary associated with a package, by looking * it via its name in a proplib dictionary. @@ -1097,30 +1134,6 @@ int xbps_array_replace_dict_by_name(prop_array_t array, /*@}*/ -/** @addtogroup purge */ -/*@{*/ - -/** - * Purge an installed package. - * - * @param[in] pkgname Package name to match. - * @param[in] check_state Set it to true to check that package - * is in XBPS_PKG_STATE_CONFIG_FILES state. - * - * @return 0 on success, otherwise an errno value. - */ -int xbps_purge_pkg(const char *pkgname, bool check_state); - -/** - * Purge all installed packages. Packages that aren't in - * XBPS_PKG_STATE_CONFIG_FILES state will be ignored. - * - * @return 0 on success, otherwise an errno value. - */ -int xbps_purge_packages(void); - -/*@}*/ - /** @addtogroup pkg_register */ /*@{*/ @@ -1220,7 +1233,6 @@ int xbps_transaction_update_packages(void); * be added into the transaction dictionary. * * @param[in] pkgname Package name to be removed. - * @param[in] purge If true package will also be purged. * @param[in] recursive If true, all packages that are currently depending * on the package to be removed, and if they are orphans, will be added. * @@ -1229,19 +1241,16 @@ int xbps_transaction_update_packages(void); * process. */ int xbps_transaction_remove_pkg(const char *pkgname, - bool purge, bool recursive); /** * Finds all package orphans currently installed and adds them into * the transaction dictionary. * - * @param[in] purge If true packages will also be purged. - * * @return 0 on succcess, ENOENT if no package orphans were found, ENXIO * or EINVAL if a problem ocurred in the process. */ -int xbps_transaction_autoremove_pkgs(bool purge); +int xbps_transaction_autoremove_pkgs(void); /** * Returns the transaction dictionary, as shown above in the image. @@ -1452,8 +1461,9 @@ int xbps_repository_sync_pkg_index(const char *uri); * * XBPS_PKG_STATE_BROKEN: not yet used. * - * XBPS_PKG_STATE_CONFIG_FILES: Package has been removed but not - * yet purged. + * XBPS_PKG_STATE_HALF_REMOVED: Package has been removed but not + * completely: the purge action in REMOVE script wasn't executed, pkg + * metadata directory still exists and is registered in package database. * * XBPS_PKG_STATE_NOT_INSTALLED: Package going to be installed in * a transaction dictionary but that has not been yet unpacked. @@ -1462,7 +1472,7 @@ typedef enum pkg_state { XBPS_PKG_STATE_UNPACKED = 1, XBPS_PKG_STATE_INSTALLED, XBPS_PKG_STATE_BROKEN, - XBPS_PKG_STATE_CONFIG_FILES, + XBPS_PKG_STATE_HALF_REMOVED, XBPS_PKG_STATE_NOT_INSTALLED, XBPS_PKG_STATE_HALF_UNPACKED } pkg_state_t; diff --git a/include/xbps_api_impl.h b/include/xbps_api_impl.h index 2891eb5c..ac0b15eb 100644 --- a/include/xbps_api_impl.h +++ b/include/xbps_api_impl.h @@ -128,7 +128,7 @@ int HIDDEN xbps_repository_find_pkg_deps(prop_dictionary_t, * @private * From lib/package_requiredby.c */ -int HIDDEN xbps_requiredby_pkg_add(prop_array_t, prop_dictionary_t); +int HIDDEN xbps_requiredby_pkg_add(struct xbps_handle *, prop_dictionary_t); int HIDDEN xbps_requiredby_pkg_remove(const char *); /** diff --git a/lib/Makefile b/lib/Makefile index e63e9c7b..2ed3145f 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -44,7 +44,7 @@ EXTOBJS += external/match.o external/mkpath.o OBJS = package_configure.o package_config_files.o package_orphans.o OBJS += package_remove.o package_remove_obsoletes.o package_state.o OBJS += package_unpack.o package_requiredby.o package_register.o -OBJS += package_purge.o transaction_commit.o transaction_package_replace.o +OBJS += transaction_commit.o transaction_package_replace.o OBJS += transaction_dictionary.o transaction_sortdeps.o transaction_ops.o OBJS += download.o initend.o OBJS += plist.o plist_archive_entry.o plist_find.o plist_match.o diff --git a/lib/initend.c b/lib/initend.c index 92e1c1b7..c4258696 100644 --- a/lib/initend.c +++ b/lib/initend.c @@ -88,12 +88,14 @@ xbps_init(struct xbps_handle *xh) CFG_STR(__UNCONST("rootdir"), __UNCONST("/"), CFGF_NONE), CFG_STR(__UNCONST("cachedir"), __UNCONST(XBPS_CACHE_PATH), CFGF_NONE), - CFG_INT(__UNCONST("fetch-cache-connections"), + CFG_INT(__UNCONST("FetchCacheConnections"), XBPS_FETCH_CACHECONN, CFGF_NONE), - CFG_INT(__UNCONST("fetch-cache-connections-per-host"), + CFG_INT(__UNCONST("FetchCacheConnectionsPerHost"), XBPS_FETCH_CACHECONN_HOST, CFGF_NONE), - CFG_INT(__UNCONST("fetch-timeout-connection"), + CFG_INT(__UNCONST("FetchTimeoutConnection"), XBPS_FETCH_TIMEOUT, CFGF_NONE), + CFG_INT(__UNCONST("TransactionFrequencyFlush"), + XBPS_TRANS_FLUSH, CFGF_NONE), CFG_BOOL(__UNCONST("syslog"), true, CFGF_NONE), CFG_STR_LIST(__UNCONST("repositories"), NULL, CFGF_MULTI), CFG_SEC(__UNCONST("virtual-package"), @@ -161,22 +163,27 @@ xbps_init(struct xbps_handle *xh) if (xhp->cfg == NULL) { xhp->syslog_enabled = true; xhp->fetch_timeout = XBPS_FETCH_TIMEOUT; + xhp->transaction_frequency_flush = XBPS_TRANS_FLUSH; cc = XBPS_FETCH_CACHECONN; cch = XBPS_FETCH_CACHECONN_HOST; } else { xhp->syslog_enabled = cfg_getbool(xhp->cfg, "syslog"); - xhp->fetch_timeout = cfg_getint(xhp->cfg, "fetch-timeout-connection"); - cc = cfg_getint(xhp->cfg, "fetch-cache-connections"); - cch = cfg_getint(xhp->cfg, "fetch-cache-connections-per-host"); + xhp->fetch_timeout = cfg_getint(xhp->cfg, "FetchTimeoutConnection"); + cc = cfg_getint(xhp->cfg, "FetchCacheConnections"); + cch = cfg_getint(xhp->cfg, "FetchCacheConnectionsPerHost"); + xhp->transaction_frequency_flush = + cfg_getint(xhp->cfg, "TransactionFrequencyFlush"); } xbps_fetch_set_cache_connection(cc, cch); - xbps_dbg_printf("rootdir=%s\n", xhp->rootdir); - xbps_dbg_printf("cachedir=%s\n", xhp->cachedir); - xbps_dbg_printf("fetch-timeout=%u\n", xhp->fetch_timeout); - xbps_dbg_printf("fetch-cacheconn=%u\n", cc); - xbps_dbg_printf("fetch-cacheconn-host=%u\n", cch); - xbps_dbg_printf("syslog=%u\n", xhp->syslog_enabled); + xbps_dbg_printf("Rootdir=%s\n", xhp->rootdir); + xbps_dbg_printf("Cachedir=%s\n", xhp->cachedir); + xbps_dbg_printf("FetchTimeout=%u\n", xhp->fetch_timeout); + xbps_dbg_printf("FetchCacheconn=%u\n", cc); + xbps_dbg_printf("FetchCacheconnHost=%u\n", cch); + xbps_dbg_printf("Syslog=%u\n", xhp->syslog_enabled); + xbps_dbg_printf("TransactionFrequencyFlush=%u\n", + xhp->transaction_frequency_flush); return 0; } diff --git a/lib/package_configure.c b/lib/package_configure.c index ebafc0a0..244aa46c 100644 --- a/lib/package_configure.c +++ b/lib/package_configure.c @@ -86,8 +86,7 @@ xbps_configure_pkg(const char *pkgname, rv = xbps_pkg_state_installed(pkgname, &state); if (rv == ENOENT) { /* - * package not installed or has been removed - * (must be purged) so ignore it. + * package not installed or has been removed. */ return 0; } else if (rv != 0) { diff --git a/lib/package_orphans.c b/lib/package_orphans.c index 0f31a055..9805f260 100644 --- a/lib/package_orphans.c +++ b/lib/package_orphans.c @@ -90,9 +90,10 @@ find_orphan_pkg(prop_object_t obj, void *arg, bool *loop_done) if ((rv = xbps_pkg_state_dictionary(obj, &state)) != 0) return rv; /* - * Skip packages that aren't fully installed. + * Skip packages that aren't fully installed or half removed. */ - if (state != XBPS_PKG_STATE_INSTALLED) + if (state != XBPS_PKG_STATE_INSTALLED && + state != XBPS_PKG_STATE_HALF_REMOVED) return 0; reqby = prop_dictionary_get(obj, "requiredby"); diff --git a/lib/package_purge.c b/lib/package_purge.c deleted file mode 100644 index 78d447d6..00000000 --- a/lib/package_purge.c +++ /dev/null @@ -1,233 +0,0 @@ -/*- - * Copyright (c) 2009-2011 Juan Romero Pardines. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include -#include -#include -#include -#include - -#include "xbps_api_impl.h" - -/** - * @file lib/package_purge.c - * @brief Package purging routines - * @defgroup purge Package purging functions - * - * These functions will purge an specified package or all packages. - * Only packages in XBPS_PKG_STATE_CONFIG_FILES state will be processed - * (unless overriden). Package purging steps: - * - * - Unmodified configuration files will be removed. - * - The purge action in the REMOVE script will be executed (if found). - * - Metadata files will be removed and package will be unregistered - * with xbps_unregister_pkg(). - */ - -static int -remove_pkg_metadata(const char *pkgname, - const char *version, - const char *pkgver, - const char *rootdir) -{ - struct dirent *dp; - DIR *dirp; - char *metadir, *path; - int rv = 0; - - assert(pkgname != NULL); - assert(rootdir != NULL); - - metadir = xbps_xasprintf("%s/%s/metadata/%s", rootdir, - XBPS_META_PATH, pkgname); - if (metadir == NULL) - return ENOMEM; - - dirp = opendir(metadir); - if (dirp == NULL) { - free(metadir); - return errno; - } - - while ((dp = readdir(dirp)) != NULL) { - if ((strcmp(dp->d_name, ".") == 0) || - (strcmp(dp->d_name, "..") == 0)) - continue; - - path = xbps_xasprintf("%s/%s", metadir, dp->d_name); - if (path == NULL) { - (void)closedir(dirp); - free(metadir); - return ENOMEM; - } - - if (unlink(path) == -1) { - xbps_set_cb_state(XBPS_STATE_PURGE_FAIL, - errno, pkgname, version, - "%s: [purge] failed to remove metafile `%s': %s", - pkgver, path, strerror(errno)); - } - free(path); - } - (void)closedir(dirp); - rv = rmdir(metadir); - free(metadir); - - return rv; -} - -static int -purge_pkgs_cb(prop_object_t obj, void *arg, bool *done) -{ - const char *pkgname; - - (void)arg; - (void)done; - - prop_dictionary_get_cstring_nocopy(obj, "pkgname", &pkgname); - return xbps_purge_pkg(pkgname, true); -} -int -xbps_purge_packages(void) -{ - return xbps_regpkgdb_foreach_pkg_cb(purge_pkgs_cb, NULL); -} - -int -xbps_purge_pkg(const char *pkgname, bool check_state) -{ - struct xbps_handle *xhp; - prop_dictionary_t dict, pkgd; - const char *version, *pkgver; - char *buf; - int rv = 0; - pkg_state_t state; - - assert(pkgname != NULL); - xhp = xbps_handle_get(); - - /* - * Firstly let's get the pkg dictionary from regpkgdb. - */ - pkgd = xbps_find_pkg_in_dict_by_name(xhp->regpkgdb_dictionary, - "packages", pkgname); - if (pkgd == NULL) { - xbps_dbg_printf("[purge] %s: missing pkg dictionary (%s)\n", - pkgname, strerror(errno)); - return errno; - } - prop_dictionary_get_cstring_nocopy(pkgd, "pkgver", &pkgver); - prop_dictionary_get_cstring_nocopy(pkgd, "version", &version); - xbps_set_cb_state(XBPS_STATE_PURGE, 0, pkgname, version, NULL); - - if (check_state) { - /* - * Skip packages that aren't in "config-files" state. - */ - if ((rv = xbps_pkg_state_dictionary(pkgd, &state)) != 0) - return rv; - if (state != XBPS_PKG_STATE_CONFIG_FILES) { - xbps_dbg_printf("[purge] %s not in config-files " - "state.\n", pkgname); - return rv; - } - } - /* - * Remove unmodified configuration files. - */ - dict = xbps_dictionary_from_metadata_plist(pkgname, XBPS_PKGFILES); - if (dict == NULL) { - xbps_set_cb_state(XBPS_STATE_PURGE_FAIL, - errno, pkgname, version, - "%s: [purge] failed to read metafile `%s': %s", - pkgver, XBPS_PKGFILES, strerror(errno)); - if (errno != ENOENT) - return errno; - } else { - if (prop_dictionary_get(dict, "conf_files")) { - rv = xbps_remove_pkg_files(dict, "conf_files", pkgver); - if (rv != 0) { - prop_object_release(dict); - xbps_set_cb_state(XBPS_STATE_PURGE_FAIL, - rv, pkgname, version, - "%s: [purge] failed to remove " - "configuration files: %s", - pkgver, strerror(rv)); - return rv; - } - } - prop_object_release(dict); - } - /* - * Execute the purge action in REMOVE script (if found). - */ - if (chdir(xhp->rootdir) == -1) { - rv = errno; - xbps_set_cb_state(XBPS_STATE_PURGE_FAIL, - rv, pkgname, version, - "%s: [purge] failed to chdir to rootdir `%s': %s", - pkgver, xhp->rootdir, strerror(rv)); - return rv; - } - buf = xbps_xasprintf("%s/metadata/%s/REMOVE", XBPS_META_PATH, pkgname); - if (buf == NULL) { - rv = ENOMEM; - return rv; - } - if (access(buf, X_OK) == 0) { - rv = xbps_file_exec(buf, "purge", pkgname, version, - "no", xhp->conffile, NULL); - if (rv != 0) { - free(buf); - if (errno && errno != ENOENT) { - xbps_set_cb_state(XBPS_STATE_PURGE_FAIL, - errno, pkgname, version, - "%s: [purge] REMOVE script failed to " - "execute purge ACTION: %s", - pkgver, strerror(errno)); - return rv; - } - } - } - free(buf); - /* - * Remove metadata dir and unregister package. - */ - if ((rv = remove_pkg_metadata(pkgname, version, pkgver, - xhp->rootdir)) != 0) { - xbps_set_cb_state(XBPS_STATE_PURGE_FAIL, - rv, pkgname, version, - "%s: [purge] failed to remove metadata files: %s", - pkgver, strerror(rv)); - if (rv != ENOENT) - return rv; - } - if ((rv = xbps_unregister_pkg(pkgname, version)) != 0) - return rv; - - xbps_set_cb_state(XBPS_STATE_PURGE_DONE, 0, pkgname, version, NULL); - - return rv; -} diff --git a/lib/package_register.c b/lib/package_register.c index 35f54dfd..1ef02f6d 100644 --- a/lib/package_register.c +++ b/lib/package_register.c @@ -43,20 +43,15 @@ int xbps_register_pkg(prop_dictionary_t pkgrd) { struct xbps_handle *xhp; - prop_dictionary_t dict, pkgd; - prop_array_t array, provides = NULL, reqby; + prop_dictionary_t pkgd; + prop_array_t provides, reqby, array; const char *pkgname, *version, *desc, *pkgver; - char *plist; int rv = 0; bool autoinst = false; assert(prop_object_type(pkgrd) == PROP_TYPE_DICTIONARY); xhp = xbps_handle_get(); - plist = xbps_xasprintf("%s/%s/%s", xhp->rootdir, - XBPS_META_PATH, XBPS_REGPKGDB); - if (plist == NULL) - return ENOMEM; prop_dictionary_get_cstring_nocopy(pkgrd, "pkgname", &pkgname); prop_dictionary_get_cstring_nocopy(pkgrd, "version", &version); @@ -72,80 +67,72 @@ xbps_register_pkg(prop_dictionary_t pkgrd) assert(version != NULL); assert(desc != NULL); assert(pkgver != NULL); + assert(xhp->regpkgdb != NULL); - if ((dict = prop_dictionary_internalize_from_zfile(plist)) != NULL) { - pkgd = xbps_find_pkg_in_dict_by_name(dict, - "packages", pkgname); - if (pkgd == NULL) { - rv = errno; - goto out; - } - if (!prop_dictionary_set_cstring_nocopy(pkgd, - "version", version)) { - prop_object_release(pkgd); - rv = EINVAL; - goto out; - } - if (!prop_dictionary_set_cstring_nocopy(pkgd, - "pkgver", pkgver)) { - prop_object_release(pkgd); - rv = EINVAL; - goto out; - } - if (!prop_dictionary_set_cstring_nocopy(pkgd, - "short_desc", desc)) { - prop_object_release(pkgd); - rv = EINVAL; - goto out; - } - if (reqby && !prop_dictionary_set(pkgd, "requiredby", reqby)) { - prop_object_release(pkgd); - rv = EINVAL; - goto out; - } - prop_dictionary_get_bool(pkgd, "automatic-install", &autoinst); - if (xhp->install_reason_auto) - autoinst = true; - else if (xhp->install_reason_manual) - autoinst = false; - - if (!prop_dictionary_set_bool(pkgd, - "automatic-install", autoinst)) { - prop_object_release(pkgd); - rv = EINVAL; - goto out; - } - if (provides) { - if (!prop_dictionary_set(pkgd, "provides", provides)) { - prop_object_release(pkgd); - rv = EINVAL; - goto out; - } - } - /* - * Add the requiredby objects for dependent packages. - */ - if (pkgrd && xbps_pkg_has_rundeps(pkgrd)) { - array = prop_dictionary_get(dict, "packages"); - if (array == NULL) { - prop_object_release(pkgd); - rv = EINVAL; - goto out; - } - if ((rv = xbps_requiredby_pkg_add(array, pkgrd)) != 0) - goto out; - } - /* - * Write plist file to storage. - */ - if (!prop_dictionary_externalize_to_zfile(dict, plist)) { - rv = errno; - goto out; - } - } else { - free(plist); - return ENOENT; + pkgd = xbps_regpkgdb_get_pkgd(pkgname, false); + if (pkgd == NULL) { + rv = ENOENT; + goto out; } + if (!prop_dictionary_set_cstring_nocopy(pkgd, + "version", version)) { + prop_object_release(pkgd); + rv = EINVAL; + goto out; + } + if (!prop_dictionary_set_cstring_nocopy(pkgd, + "pkgver", pkgver)) { + prop_object_release(pkgd); + rv = EINVAL; + goto out; + } + if (!prop_dictionary_set_cstring_nocopy(pkgd, + "short_desc", desc)) { + prop_object_release(pkgd); + rv = EINVAL; + goto out; + } + if (reqby && !prop_dictionary_set(pkgd, "requiredby", reqby)) { + prop_object_release(pkgd); + rv = EINVAL; + goto out; + } + prop_dictionary_get_bool(pkgd, "automatic-install", &autoinst); + if (xhp->install_reason_auto) + autoinst = true; + else if (xhp->install_reason_manual) + autoinst = false; + + if (!prop_dictionary_set_bool(pkgd, + "automatic-install", autoinst)) { + prop_object_release(pkgd); + rv = EINVAL; + goto out; + } + if (provides) { + if (!prop_dictionary_set(pkgd, "provides", provides)) { + prop_object_release(pkgd); + rv = EINVAL; + goto out; + } + } + array = prop_dictionary_get(xhp->regpkgdb, "packages"); + rv = xbps_array_replace_dict_by_name(array, pkgd, pkgname); + if (rv != 0) { + prop_object_release(pkgd); + goto out; + } + /* + * Add the requiredby objects for dependent packages. + */ + if (pkgrd && xbps_pkg_has_rundeps(pkgrd)) { + if ((rv = xbps_requiredby_pkg_add(xhp, pkgrd)) != 0) { + prop_object_release(pkgd); + goto out; + } + } + prop_object_release(pkgd); + out: if (rv != 0) { xbps_set_cb_state(XBPS_STATE_REGISTER_FAIL, @@ -153,8 +140,6 @@ out: "%s: failed to register package: %s", pkgver, strerror(rv)); } - prop_object_release(dict); - free(plist); return rv; } @@ -163,31 +148,24 @@ int xbps_unregister_pkg(const char *pkgname, const char *version) { struct xbps_handle *xhp; - char *plist; - int rv = 0; + int rv; assert(pkgname != NULL); + xhp = xbps_handle_get(); + if ((rv = xbps_regpkgdb_dictionary_init(xhp)) != 0) + return rv; + xbps_set_cb_state(XBPS_STATE_UNREGISTER, 0, pkgname, version, NULL); - xhp = xbps_handle_get(); - plist = xbps_xasprintf("%s/%s/%s", xhp->rootdir, - XBPS_META_PATH, XBPS_REGPKGDB); - if (plist == NULL) { - rv = ENOMEM; - goto out; - } - if (!xbps_remove_pkg_dict_from_plist_by_name(pkgname, plist)) { - rv = errno; - goto out; - } -out: - if (rv != 0) { + if (!xbps_remove_pkg_from_dict_by_name(xhp->regpkgdb, + "packages", pkgname)) { xbps_set_cb_state(XBPS_STATE_UNREGISTER_FAIL, - rv, pkgname, version, + errno, pkgname, version, "%s: failed to unregister package: %s", - pkgname, strerror(rv)); + pkgname, strerror(errno)); + return errno; } - free(plist); - return rv; + + return 0; } diff --git a/lib/package_remove.c b/lib/package_remove.c index 2ad4e070..e95eb616 100644 --- a/lib/package_remove.c +++ b/lib/package_remove.c @@ -42,14 +42,18 @@ * files. Package removal steps: * -# Its pre-remove target specified in the REMOVE script * will be executed. - * -# Its files, dirs and links will be removed. Modified files (not - * matching its sha256 hash) are preserved, unless + * -# Its links, files, conf_files and dirs will be removed. + * Modified files (not matchings its sha256 hash) are preserved, unless * XBPS_FLAG_FORCE_REMOVE_FILES flag is set via xbps_init::flags member. * -# Its post-remove target specified in the REMOVE script * will be executed. * -# Its requiredby objects will be removed from the installed packages * database. - * -# Its state will be changed to XBPS_PKG_STATE_CONFIG_FILES. + * -# Its state will be changed to XBPS_PKG_STATE_HALF_UNPACKED. + * -# Its purge-remove target specified in the REMOVE script + * will be executed. + * -# Its package metadata directory will be removed. + * -# Package will be unregistered from package database. * * @note * -# If a package is going to be updated, only steps 1 and 4 @@ -69,6 +73,58 @@ * Text inside of white boxes are the key associated with the object, its * data type is specified on its edge, i.e string, array, integer, dictionary. */ +static int +remove_pkg_metadata(const char *pkgname, + const char *version, + const char *pkgver, + const char *rootdir) +{ + struct dirent *dp; + DIR *dirp; + char *metadir, *path; + int rv = 0; + + assert(pkgname != NULL); + assert(rootdir != NULL); + + metadir = xbps_xasprintf("%s/%s/metadata/%s", rootdir, + XBPS_META_PATH, pkgname); + if (metadir == NULL) + return ENOMEM; + + dirp = opendir(metadir); + if (dirp == NULL) { + free(metadir); + return errno; + } + + while ((dp = readdir(dirp)) != NULL) { + if ((strcmp(dp->d_name, ".") == 0) || + (strcmp(dp->d_name, "..") == 0)) + continue; + + path = xbps_xasprintf("%s/%s", metadir, dp->d_name); + if (path == NULL) { + (void)closedir(dirp); + free(metadir); + return ENOMEM; + } + + if (unlink(path) == -1) { + xbps_set_cb_state(XBPS_STATE_PURGE_FAIL, + errno, pkgname, version, + "%s: [purge] failed to remove metafile `%s': %s", + pkgver, path, strerror(errno)); + } + free(path); + } + (void)closedir(dirp); + rv = rmdir(metadir); + free(metadir); + + return rv; +} + int xbps_remove_pkg_files(prop_dictionary_t dict, const char *key, @@ -87,9 +143,8 @@ xbps_remove_pkg_files(prop_dictionary_t dict, xhp = xbps_handle_get(); array = prop_dictionary_get(dict, key); - if (array == NULL) - return EINVAL; - else if (prop_array_count(array) == 0) + if ((prop_object_type(array) != PROP_TYPE_ARRAY) || + prop_array_count(array) == 0) return 0; iter = xbps_array_iter_from_dict(dict, key); @@ -174,6 +229,7 @@ xbps_remove_pkg_files(prop_dictionary_t dict, errno, pkgname, version, "%s: failed to remove %s `%s': %s", pkgver, curobj, file, strerror(errno)); + errno = 0; } else { /* success */ xbps_set_cb_state(XBPS_STATE_REMOVE_FILE, @@ -193,47 +249,47 @@ int xbps_remove_pkg(const char *pkgname, const char *version, bool update) { struct xbps_handle *xhp; - prop_dictionary_t dict; - char *buf, *pkgver; + prop_dictionary_t pkgd = NULL; + char *buf = NULL, *pkgver = NULL; int rv = 0; bool rmfile_exists = false; + pkg_state_t state = 0; assert(pkgname != NULL); assert(version != NULL); xhp = xbps_handle_get(); - /* - * Check if pkg is installed before anything else. - */ - if (!xbps_check_is_installed_pkg_by_name(pkgname)) - return ENOENT; - - pkgver = xbps_xasprintf("%s-%s", pkgname, version); - if (pkgver == NULL) - return ENOMEM; - - if (!update) - xbps_set_cb_state(XBPS_STATE_REMOVE, 0, pkgname, version, NULL); buf = xbps_xasprintf("%s/metadata/%s/REMOVE", XBPS_META_PATH, pkgname); if (buf == NULL) { rv = ENOMEM; - free(pkgver); - return rv; + goto out; } + pkgver = xbps_xasprintf("%s-%s", pkgname, version); + if (pkgver == NULL) { + rv = ENOMEM; + goto out; + } + + if ((rv = xbps_pkg_state_installed(pkgname, &state)) != 0) + goto out; + + if (!update) + xbps_set_cb_state(XBPS_STATE_REMOVE, 0, pkgname, version, NULL); + if (chdir(xhp->rootdir) == -1) { rv = errno; xbps_set_cb_state(XBPS_STATE_REMOVE_FAIL, rv, pkgname, version, "%s: [remove] failed to chdir to rootdir `%s': %s", pkgver, xhp->rootdir, strerror(rv)); - free(buf); - free(pkgver); - return rv; + goto out; } - + /* If package was "half-removed", remove it fully. */ + if (state == XBPS_PKG_STATE_HALF_REMOVED) + goto purge; /* * Run the pre remove action. */ @@ -246,18 +302,15 @@ xbps_remove_pkg(const char *pkgname, const char *version, bool update) "%s: [remove] REMOVE script failed to " "execute pre ACTION: %s", pkgver, strerror(errno)); - free(pkgver); - free(buf); - return errno; + rv = errno; + goto out; } } else { if (errno != ENOENT) { - free(pkgver); - free(buf); - return errno; + rv = errno; + goto out; } } - /* * If updating a package, we just need to execute the current * pre-remove action target, unregister its requiredby entries and @@ -269,38 +322,26 @@ xbps_remove_pkg(const char *pkgname, const char *version, bool update) return xbps_requiredby_pkg_remove(pkgname); } - /* - * Remove links, files and dirs. - */ - dict = xbps_dictionary_from_metadata_plist(pkgname, XBPS_PKGFILES); - if (dict == NULL) { - free(pkgver); - free(buf); - return errno; + pkgd = xbps_dictionary_from_metadata_plist(pkgname, XBPS_PKGFILES); + if (pkgd == NULL) { + rv = errno; + goto out; } - /* Remove links */ - if ((rv = xbps_remove_pkg_files(dict, "links", pkgver)) != 0) { - prop_object_release(dict); - free(buf); - free(pkgver); - return rv; - } + if ((rv = xbps_remove_pkg_files(pkgd, "links", pkgver)) != 0) + goto out; + /* Remove regular files */ - if ((rv = xbps_remove_pkg_files(dict, "files", pkgver)) != 0) { - prop_object_release(dict); - free(buf); - free(pkgver); - return rv; - } + if ((rv = xbps_remove_pkg_files(pkgd, "files", pkgver)) != 0) + goto out; + + /* Remove configuration files */ + if ((rv = xbps_remove_pkg_files(pkgd, "conf_files", pkgver)) != 0) + goto out; + /* Remove dirs */ - if ((rv = xbps_remove_pkg_files(dict, "dirs", pkgver)) != 0) { - prop_object_release(dict); - free(buf); - free(pkgver); - return rv; - } - prop_object_release(dict); + if ((rv = xbps_remove_pkg_files(pkgd, "dirs", pkgver)) != 0) + goto out; /* * Execute the post REMOVE action if file exists and we aren't @@ -313,12 +354,9 @@ xbps_remove_pkg(const char *pkgname, const char *version, bool update) errno, pkgname, version, "%s: [remove] REMOVE script failed to execute " "post ACTION: %s", pkgver, strerror(errno)); - free(buf); - free(pkgver); - return errno; + rv = errno; + goto out; } - free(buf); - /* * Update the requiredby array of all required dependencies. */ @@ -327,25 +365,64 @@ xbps_remove_pkg(const char *pkgname, const char *version, bool update) rv, pkgname, version, "%s: [remove] failed to remove requiredby entries: %s", pkgver, strerror(rv)); - free(pkgver); - return rv; + goto out; } - /* - * Set package state to "config-files". + * Set package state to "half-removed". */ rv = xbps_set_pkg_state_installed(pkgname, version, pkgver, - XBPS_PKG_STATE_CONFIG_FILES); + XBPS_PKG_STATE_HALF_REMOVED); if (rv != 0) { xbps_set_cb_state(XBPS_STATE_REMOVE_FAIL, rv, pkgname, version, - "%s: [remove] failed to set state to config-files: %s", + "%s: [remove] failed to set state to half-removed: %s", pkgver, strerror(rv)); - } else { - xbps_set_cb_state(XBPS_STATE_REMOVE_DONE, - 0, pkgname, version, NULL); + goto out; } - free(pkgver); + +purge: + /* + * Execute the purge REMOVE action if file exists. + */ + if (access(buf, X_OK) == 0) { + if (xbps_file_exec(buf, "purge", pkgname, version, "no", + xhp->conffile, NULL) != 0) { + rv = errno; + xbps_set_cb_state(XBPS_STATE_REMOVE_FAIL, + errno, pkgname, version, + "%s: REMOVE script failed to execute " + "purge ACTION: %s", pkgver, strerror(errno)); + goto out; + } + } + /* + * Remove package metadata directory. + */ + rv = remove_pkg_metadata(pkgname, version, pkgver, xhp->rootdir); + if (rv != 0) { + xbps_set_cb_state(XBPS_STATE_REMOVE_FAIL, + rv, pkgname, version, + "%s: failed to remove metadata files: %s", + pkgver, strerror(rv)); + if (rv != ENOENT) + goto out; + } + /* + * Unregister package from regpkgdb. + */ + if ((rv = xbps_unregister_pkg(pkgname, version)) != 0) + goto out; + + xbps_set_cb_state(XBPS_STATE_REMOVE_DONE, + 0, pkgname, version, NULL); + +out: + if (buf != NULL) + free(buf); + if (pkgver != NULL) + free(pkgver); + if (pkgd != NULL) + prop_object_release(pkgd); return rv; } diff --git a/lib/package_requiredby.c b/lib/package_requiredby.c index 7c5f3bc5..aa8cb0cb 100644 --- a/lib/package_requiredby.c +++ b/lib/package_requiredby.c @@ -91,9 +91,10 @@ remove_pkg_from_reqby(prop_object_t obj, void *arg, bool *loop_done) if (reqby == NULL || prop_array_count(reqby) == 0) return 0; - if (xbps_match_pkgname_in_array(reqby, pkgname)) + if (xbps_match_pkgname_in_array(reqby, pkgname)) { if (!xbps_remove_pkgname_from_array(reqby, pkgname)) return EINVAL; + } return 0; } @@ -101,46 +102,12 @@ remove_pkg_from_reqby(prop_object_t obj, void *arg, bool *loop_done) int HIDDEN xbps_requiredby_pkg_remove(const char *pkgname) { - struct xbps_handle *xhp; - prop_dictionary_t dict; - char *plist; - int rv = 0; - assert(pkgname != NULL); - - xhp = xbps_handle_get(); - plist = xbps_xasprintf("%s/%s/%s", xhp->rootdir, - XBPS_META_PATH, XBPS_REGPKGDB); - if (plist == NULL) - return ENOMEM; - - if ((dict = prop_dictionary_internalize_from_zfile(plist)) == NULL) { - free(plist); - xbps_dbg_printf("[reqby-rm] cannot internalize " - "regpkgdb plist for '%s': %s\n", pkgname, strerror(errno)); - return errno; - } - - rv = xbps_callback_array_iter_in_dict(dict, "packages", - remove_pkg_from_reqby, __UNCONST(pkgname)); - if (rv != 0) - goto out; - - if (!prop_dictionary_externalize_to_zfile(dict, plist)) { - xbps_dbg_printf("[reqby-rm] cannot externalize plist for " - "'%s': %s\n", pkgname, strerror(errno)); - rv = errno; - } - -out: - prop_object_release(dict); - free(plist); - - return rv; + return xbps_regpkgdb_foreach_pkg_cb(remove_pkg_from_reqby, __UNCONST(pkgname)); } int HIDDEN -xbps_requiredby_pkg_add(prop_array_t pkgs_array, prop_dictionary_t pkgd) +xbps_requiredby_pkg_add(struct xbps_handle *xhp, prop_dictionary_t pkgd) { prop_array_t pkg_rdeps; prop_object_t obj, pkgd_regpkgdb; @@ -148,7 +115,6 @@ xbps_requiredby_pkg_add(prop_array_t pkgs_array, prop_dictionary_t pkgd) const char *pkgver, *str; int rv = 0; - assert(prop_object_type(pkgs_array) == PROP_TYPE_ARRAY); assert(prop_object_type(pkgd) == PROP_TYPE_DICTIONARY); prop_dictionary_get_cstring_nocopy(pkgd, "pkgver", &pkgver); @@ -166,8 +132,8 @@ xbps_requiredby_pkg_add(prop_array_t pkgs_array, prop_dictionary_t pkgd) rv = EINVAL; break; } - pkgd_regpkgdb = - xbps_find_virtualpkg_in_array_by_pattern(pkgs_array, str); + pkgd_regpkgdb = xbps_find_virtualpkg_in_dict_by_pattern( + xhp->regpkgdb, "packages", str); if (pkgd_regpkgdb == NULL) return EINVAL; diff --git a/lib/package_state.c b/lib/package_state.c index fd64c814..34d80c45 100644 --- a/lib/package_state.c +++ b/lib/package_state.c @@ -40,7 +40,7 @@ static const struct state states[] = { { "unpacked", XBPS_PKG_STATE_UNPACKED }, { "installed", XBPS_PKG_STATE_INSTALLED }, { "broken", XBPS_PKG_STATE_BROKEN }, - { "config-files", XBPS_PKG_STATE_CONFIG_FILES }, + { "half-removed", XBPS_PKG_STATE_HALF_REMOVED }, { "not-installed", XBPS_PKG_STATE_NOT_INSTALLED }, { "half-unpacked", XBPS_PKG_STATE_HALF_UNPACKED }, { NULL, 0 } @@ -68,7 +68,7 @@ set_new_state(prop_dictionary_t dict, pkg_state_t state) break; if (stp->string == NULL) - return -1; + return EINVAL; if (!prop_dictionary_set_cstring_nocopy(dict, "state", stp->string)) return EINVAL; @@ -110,7 +110,7 @@ xbps_pkg_state_installed(const char *pkgname, pkg_state_t *state) assert(pkgname != NULL); assert(state != NULL); - pkgd = xbps_find_pkg_dict_installed(pkgname, false); + pkgd = xbps_regpkgdb_get_pkgd(pkgname, false); if (pkgd == NULL) return ENOENT; @@ -170,127 +170,80 @@ xbps_set_pkg_state_installed(const char *pkgname, pkg_state_t state) { struct xbps_handle *xhp; - prop_dictionary_t dict = NULL, pkgd; + prop_dictionary_t pkgd; prop_array_t array; - char *metadir, *plist; - int rv = 0; bool newpkg = false; + int rv; assert(pkgname != NULL); xhp = xbps_handle_get(); - metadir = xbps_xasprintf("%s/%s", xhp->rootdir, XBPS_META_PATH); - if (metadir == NULL) - return ENOMEM; - plist = xbps_xasprintf("%s/%s", metadir, XBPS_REGPKGDB); - if (plist == NULL) { - free(metadir); - return ENOMEM; - } - if ((dict = prop_dictionary_internalize_from_zfile(plist)) == NULL) { - dict = prop_dictionary_create(); - if (dict == NULL) { - rv = ENOMEM; - goto out; - } + if (xhp->regpkgdb == NULL) { + xhp->regpkgdb = prop_dictionary_create(); + if (xhp->regpkgdb == NULL) + return ENOMEM; + array = prop_array_create(); - if (array == NULL) { - rv = ENOMEM; - goto out; - } + if (array == NULL) + return ENOMEM; + pkgd = prop_dictionary_create(); if (pkgd == NULL) { - rv = ENOMEM; prop_object_release(array); - goto out; + return ENOMEM; } if ((rv = set_pkg_objs(pkgd, pkgname, version, pkgver)) != 0) { prop_object_release(array); prop_object_release(pkgd); - goto out; + return rv; } if ((rv = set_new_state(pkgd, state)) != 0) { prop_object_release(array); prop_object_release(pkgd); - goto out; + return rv; } if (!xbps_add_obj_to_array(array, pkgd)) { - rv = EINVAL; prop_object_release(array); prop_object_release(pkgd); - goto out; + return EINVAL; } - if (!xbps_add_obj_to_dict(dict, array, "packages")) { - rv = EINVAL; + if (!xbps_add_obj_to_dict(xhp->regpkgdb, array, "packages")) { prop_object_release(array); - goto out; + return EINVAL; } } else { - pkgd = xbps_find_pkg_in_dict_by_name(dict, - "packages", pkgname); + pkgd = xbps_regpkgdb_get_pkgd(pkgname, false); if (pkgd == NULL) { - if (errno && errno != ENOENT) { - rv = errno; - goto out; - } - newpkg = true; pkgd = prop_dictionary_create(); if ((rv = set_pkg_objs(pkgd, pkgname, version, pkgver)) != 0) { prop_object_release(pkgd); - goto out; - } - } - array = prop_dictionary_get(dict, "packages"); - if (array == NULL) { - array = prop_array_create(); - if (!prop_dictionary_set(dict, "packages", array)) { - rv = EINVAL; - if (newpkg) - prop_object_release(pkgd); - goto out; + return rv; } } if ((rv = set_new_state(pkgd, state)) != 0) { if (newpkg) prop_object_release(pkgd); - goto out; + return rv; } - if (newpkg && !xbps_add_obj_to_array(array, pkgd)) { - rv = EINVAL; - prop_object_release(pkgd); - goto out; - } - } - - /* Create metadir if doesn't exist */ - if (access(metadir, X_OK) == -1) { - if (errno == ENOENT) { - if (xbps_mkpath(metadir, 0755) != 0) { - xbps_dbg_printf("[pkgstate] failed to create " - "metadir %s: %s\n", metadir, - strerror(errno)); - rv = errno; - goto out; + array = prop_dictionary_get(xhp->regpkgdb, "packages"); + if (newpkg) { + if (!xbps_add_obj_to_array(array, pkgd)) { + prop_object_release(pkgd); + return EINVAL; } - } - } - /* Externalize regpkgdb plist file */ - if (!prop_dictionary_externalize_to_zfile(dict, plist)) { - rv = errno; - xbps_dbg_printf("[pkgstate] cannot write plist '%s': %s\n", - plist, strerror(errno)); - } + } else { + if ((rv = xbps_array_replace_dict_by_name(array, + pkgd, pkgname)) != 0) + return rv; -out: - if (prop_object_type(dict) == PROP_TYPE_DICTIONARY) - prop_object_release(dict); - if (metadir) - free(metadir); - if (plist) - free(plist); + prop_object_release(pkgd); + } + if (!prop_dictionary_set(xhp->regpkgdb, "packages", array)) + return EINVAL; + } return rv; } diff --git a/lib/package_unpack.c b/lib/package_unpack.c index e2ce8654..0ceadf2f 100644 --- a/lib/package_unpack.c +++ b/lib/package_unpack.c @@ -192,7 +192,16 @@ unpack_archive(prop_dictionary_t pkg_repod, struct archive *ar) xucd->entry_extract_count = 0; xucd->entry_total_count = 0; } - + if (access(xhp->rootdir, R_OK) == -1) { + if (errno != ENOENT) { + rv = errno; + goto out; + } + if (xbps_mkpath(xhp->rootdir, 0750) == -1) { + rv = errno; + goto out; + } + } if (chdir(xhp->rootdir) == -1) { xbps_set_cb_state(XBPS_STATE_UNPACK_FAIL, errno, pkgname, version, diff --git a/lib/plist.c b/lib/plist.c index bf198d60..33f1be23 100644 --- a/lib/plist.c +++ b/lib/plist.c @@ -231,7 +231,7 @@ xbps_dictionary_from_metadata_plist(const char *pkgname, if (access(plistf, R_OK) == -1) { pkgd = xbps_find_virtualpkg_dict_installed(pkgname, false); - if (pkgd) { + if (prop_object_type(pkgd) == PROP_TYPE_DICTIONARY) { free(plistf); prop_dictionary_get_cstring_nocopy(pkgd, "pkgname", &savedpkgname); diff --git a/lib/plist_find.c b/lib/plist_find.c index 1e22e6e5..b049e5c4 100644 --- a/lib/plist_find.c +++ b/lib/plist_find.c @@ -336,15 +336,15 @@ find_pkgd_installed(const char *str, bool bypattern, bool virtual) /* try normal pkg */ if (virtual == false) { - pkgd = find_pkg_in_dict(xhp->regpkgdb_dictionary, + pkgd = find_pkg_in_dict(xhp->regpkgdb, "packages", str, bypattern, false); } else { /* virtual pkg set by user in conf */ - pkgd = find_virtualpkg_user_in_dict(xhp->regpkgdb_dictionary, + pkgd = find_virtualpkg_user_in_dict(xhp->regpkgdb, "packages", str, bypattern); if (pkgd == NULL) { /* any virtual pkg in dictionary matching pattern */ - pkgd = find_pkg_in_dict(xhp->regpkgdb_dictionary, + pkgd = find_pkg_in_dict(xhp->regpkgdb, "packages", str, bypattern, true); } } diff --git a/lib/plist_remove.c b/lib/plist_remove.c index be2f310c..48758ff3 100644 --- a/lib/plist_remove.c +++ b/lib/plist_remove.c @@ -42,16 +42,20 @@ static bool remove_string_from_array(prop_array_t array, const char *str, int mode) { + prop_object_iterator_t iter; prop_object_t obj; const char *curname, *pkgdep; char *curpkgname; - size_t i, idx = 0; + size_t idx = 0; bool found = false; assert(prop_object_type(array) == PROP_TYPE_ARRAY); - for (i = 0; i < prop_array_count(array); i++) { - obj = prop_array_get(array, i); + iter = prop_array_iterator(array); + if (iter == NULL) + return false; + + while ((obj = prop_object_iterator_next(iter))) { if (mode == 0) { /* exact match, obj is a string */ if (prop_string_equals_cstring(obj, str)) { @@ -81,8 +85,12 @@ remove_string_from_array(prop_array_t array, const char *str, int mode) } idx++; } - if (!found) + prop_object_iterator_release(iter); + + if (!found) { + errno = ENOENT; return false; + } prop_array_remove(array, idx); return true; @@ -121,7 +129,10 @@ xbps_remove_pkg_from_dict_by_name(prop_dictionary_t dict, if (array == NULL) return false; - return xbps_remove_pkg_from_array_by_name(array, pkgname); + if (!xbps_remove_pkg_from_array_by_name(array, pkgname)) + return false; + + return prop_dictionary_set(dict, key, array); } bool diff --git a/lib/regpkgdb_dictionary.c b/lib/regpkgdb_dictionary.c index a1b46ed4..1d4351d2 100644 --- a/lib/regpkgdb_dictionary.c +++ b/lib/regpkgdb_dictionary.c @@ -56,45 +56,94 @@ * dictionary. */ -static bool regpkgdb_initialized; - int HIDDEN xbps_regpkgdb_dictionary_init(struct xbps_handle *xhp) { - char *plist; + int rv; - if (regpkgdb_initialized) + assert(xhp != NULL); + + if (xhp->regpkgdb != NULL) return 0; + rv = xbps_regpkgdb_update(xhp, false); + if (rv != 0) { + if (rv != ENOENT) + xbps_dbg_printf("[regpkgdb] cannot internalize " + "regpkgdb dictionary: %s\n", strerror(rv)); + + return rv; + } + xbps_dbg_printf("[regpkgdb] initialized ok.\n"); + + return 0; +} + +int +xbps_regpkgdb_update(struct xbps_handle *xhp, bool flush) +{ + char *plist, *metadir; + int rv = 0; + plist = xbps_xasprintf("%s/%s/%s", xhp->rootdir, XBPS_META_PATH, XBPS_REGPKGDB); if (plist == NULL) return ENOMEM; - xhp->regpkgdb_dictionary = - prop_dictionary_internalize_from_zfile(plist); - if (xhp->regpkgdb_dictionary == NULL) { - free(plist); - if (errno != ENOENT) - xbps_dbg_printf("[regpkgdb] cannot internalize " - "regpkgdb dictionary: %s\n", strerror(errno)); - return errno; + if (xhp->regpkgdb != NULL && flush) { + metadir = xbps_xasprintf("%s/%s", xhp->rootdir, + XBPS_META_PATH); + if (metadir == NULL) { + free(plist); + return ENOMEM; + } + /* Create metadir if doesn't exist */ + if (access(metadir, X_OK) == -1) { + if (errno == ENOENT) { + if (xbps_mkpath(metadir, 0755) != 0) { + xbps_dbg_printf("[regpkgdb] failed to " + "create metadir %s: %s\n", metadir, + strerror(errno)); + rv = errno; + free(metadir); + free(plist); + return rv; + } + } else { + free(plist); + return errno; + } + } + free(metadir); + /* flush dictionary to storage */ + if (!prop_dictionary_externalize_to_zfile(xhp->regpkgdb, + plist)) { + free(plist); + return errno; + } + prop_object_release(xhp->regpkgdb); + xhp->regpkgdb = NULL; } - free(plist); - regpkgdb_initialized = true; - xbps_dbg_printf("[regpkgdb] initialized ok.\n"); + /* update copy in memory */ + xhp->regpkgdb = prop_dictionary_internalize_from_zfile(plist); + if (xhp->regpkgdb == NULL) + rv = errno; - return 0; + free(plist); + + return rv; } void HIDDEN xbps_regpkgdb_dictionary_release(struct xbps_handle *xhp) { - if (!regpkgdb_initialized) + assert(xhp != NULL); + + if (xhp->regpkgdb == NULL) return; - prop_object_release(xhp->regpkgdb_dictionary); - regpkgdb_initialized = false; + prop_object_release(xhp->regpkgdb); + xhp->regpkgdb = NULL; xbps_dbg_printf("[regpkgdb] released ok.\n"); } @@ -103,36 +152,19 @@ foreach_pkg_cb(int (*fn)(prop_object_t, void *, bool *), void *arg, bool reverse) { - prop_array_t array; - prop_object_t obj; struct xbps_handle *xhp = xbps_handle_get(); - size_t i, cnt; int rv; - bool done = false; /* initialize regpkgdb */ if ((rv = xbps_regpkgdb_dictionary_init(xhp)) != 0) return rv; - array = prop_dictionary_get(xhp->regpkgdb_dictionary, "packages"); - if (prop_object_type(array) != PROP_TYPE_ARRAY) - return EINVAL; - - cnt = prop_array_count(array); if (reverse) { - while (cnt--) { - obj = prop_array_get(array, cnt); - rv = (*fn)(obj, arg, &done); - if (rv != 0 || done) - break; - } + rv = xbps_callback_array_iter_reverse_in_dict( + xhp->regpkgdb, "packages", fn, arg); } else { - for (i = 0; i < cnt; i++) { - obj = prop_array_get(array, i); - rv = (*fn)(obj, arg, &done); - if (rv != 0 || done) - break; - } + rv = xbps_callback_array_iter_in_dict( + xhp->regpkgdb, "packages", fn, arg); } return rv; } @@ -150,3 +182,22 @@ xbps_regpkgdb_foreach_pkg_cb(int (*fn)(prop_object_t, void *, bool *), { return foreach_pkg_cb(fn, arg, false); } + +prop_dictionary_t +xbps_regpkgdb_get_pkgd(const char *pkg, bool bypattern) +{ + struct xbps_handle *xhp = xbps_handle_get(); + prop_dictionary_t pkgd = NULL; + + if (xbps_regpkgdb_dictionary_init(xhp) != 0) + return NULL; + + if (bypattern) + pkgd = xbps_find_pkg_in_dict_by_pattern(xhp->regpkgdb, + "packages", pkg); + else + pkgd = xbps_find_pkg_in_dict_by_name(xhp->regpkgdb, + "packages", pkg); + + return prop_dictionary_copy(pkgd); +} diff --git a/lib/transaction_commit.c b/lib/transaction_commit.c index 4ae8bb81..3398f6bb 100644 --- a/lib/transaction_commit.c +++ b/lib/transaction_commit.c @@ -164,13 +164,14 @@ xbps_transaction_commit(prop_dictionary_t transd) struct xbps_handle *xhp; prop_object_t obj; prop_object_iterator_t iter; + size_t i; const char *pkgname, *version, *pkgver, *tract; int rv = 0; - bool update, install, purge; + bool update, install; assert(prop_object_type(transd) == PROP_TYPE_DICTIONARY); - update = install = purge = false; + update = install = false; xhp = xbps_handle_get(); iter = xbps_array_iter_from_dict(transd, "packages"); if (iter == NULL) @@ -193,7 +194,16 @@ xbps_transaction_commit(prop_dictionary_t transd) */ xbps_set_cb_state(XBPS_STATE_TRANS_RUN, 0, NULL, NULL, NULL); + i = 0; while ((obj = prop_object_iterator_next(iter)) != NULL) { + if ((xhp->transaction_frequency_flush > 0) && + (++i >= xhp->transaction_frequency_flush)) { + rv = xbps_regpkgdb_update(xhp, true); + if (rv != 0 && rv != ENOENT) + goto out; + + i = 0; + } update = false; prop_dictionary_get_cstring_nocopy(obj, "transaction", &tract); prop_dictionary_get_cstring_nocopy(obj, "pkgname", &pkgname); @@ -201,22 +211,15 @@ xbps_transaction_commit(prop_dictionary_t transd) prop_dictionary_get_cstring_nocopy(obj, "pkgver", &pkgver); if (strcmp(tract, "remove") == 0) { - purge = update = false; + update = false; /* - * Remove and optionally also purge package. + * Remove package. */ prop_dictionary_get_bool(obj, "remove-and-update", &update); - prop_dictionary_get_bool(obj, "remove-and-purge", - &purge); rv = xbps_remove_pkg(pkgname, version, update); if (rv != 0) goto out; - if (update || !purge) - continue; - - if ((rv = xbps_purge_pkg(pkgname, false)) != 0) - goto out; } else if (strcmp(tract, "configure") == 0) { /* * Reconfigure pending package. @@ -269,6 +272,10 @@ xbps_transaction_commit(prop_dictionary_t transd) } prop_object_iterator_reset(iter); + /* force a flush now packages were removed/unpacked */ + if ((rv = xbps_regpkgdb_update(xhp, true)) != 0) + goto out; + /* if there are no packages to install or update we are done */ if (!update && !install) goto out; @@ -277,11 +284,21 @@ xbps_transaction_commit(prop_dictionary_t transd) */ xbps_set_cb_state(XBPS_STATE_TRANS_CONFIGURE, 0, NULL, NULL, NULL); + i = 0; while ((obj = prop_object_iterator_next(iter)) != NULL) { + if (xhp->transaction_frequency_flush > 0 && + ++i >= xhp->transaction_frequency_flush) { + if ((rv = xbps_regpkgdb_update(xhp, true)) != 0) + goto out; + + i = 0; + } + prop_dictionary_get_cstring_nocopy(obj, "transaction", &tract); if ((strcmp(tract, "remove") == 0) || (strcmp(tract, "configure") == 0)) continue; + prop_dictionary_get_cstring_nocopy(obj, "pkgname", &pkgname); prop_dictionary_get_cstring_nocopy(obj, "version", &version); update = false; @@ -304,6 +321,8 @@ xbps_transaction_commit(prop_dictionary_t transd) } } + /* Force a flush now that packages are configured */ + rv = xbps_regpkgdb_update(xhp, true); out: prop_object_iterator_release(iter); diff --git a/lib/transaction_dictionary.c b/lib/transaction_dictionary.c index 2480326d..a6614888 100644 --- a/lib/transaction_dictionary.c +++ b/lib/transaction_dictionary.c @@ -178,6 +178,8 @@ compute_transaction_stats(void) pkg_metad = xbps_dictionary_from_metadata_plist(pkgname, XBPS_PKGPROPS); + if (pkg_metad == NULL) + continue; prop_dictionary_get_uint64(pkg_metad, "installed_size", &tsize); prop_object_release(pkg_metad); diff --git a/lib/transaction_ops.c b/lib/transaction_ops.c index dbc6804e..0642a3c5 100644 --- a/lib/transaction_ops.c +++ b/lib/transaction_ops.c @@ -227,7 +227,7 @@ xbps_transaction_install_pkg(const char *pkgpattern) } int -xbps_transaction_remove_pkg(const char *pkgname, bool purge, bool recursive) +xbps_transaction_remove_pkg(const char *pkgname, bool recursive) { prop_dictionary_t transd, pkgd; prop_array_t mdeps, orphans, orphans_pkg, unsorted, reqby; @@ -238,11 +238,9 @@ xbps_transaction_remove_pkg(const char *pkgname, bool purge, bool recursive) assert(pkgname != NULL); - pkgd = xbps_find_pkg_dict_installed(pkgname, false); - if (prop_object_type(pkgd) != PROP_TYPE_DICTIONARY) { + if ((pkgd = xbps_regpkgdb_get_pkgd(pkgname, false)) == NULL) { /* pkg not installed */ - rv = ENOENT; - goto out; + return ENOENT; } /* * Prepare transaction dictionary and missing deps array. @@ -267,6 +265,7 @@ xbps_transaction_remove_pkg(const char *pkgname, bool purge, bool recursive) rv = ENOMEM; goto out; } + prop_array_set_cstring_nocopy(orphans_pkg, 0, pkgname); orphans = xbps_find_pkg_orphans(orphans_pkg); prop_object_release(orphans_pkg); @@ -274,13 +273,12 @@ xbps_transaction_remove_pkg(const char *pkgname, bool purge, bool recursive) rv = EINVAL; goto out; } + count = prop_array_count(orphans); while (count--) { obj = prop_array_get(orphans, count); prop_dictionary_get_cstring_nocopy(obj, "pkgver", &pkgver); prop_dictionary_set_cstring_nocopy(obj, "transaction", "remove"); - if (purge) - prop_dictionary_set_bool(obj, "remove-and-purge", true); prop_array_add(unsorted, obj); xbps_dbg_printf("%s: added into transaction (remove).\n", pkgver); } @@ -291,8 +289,6 @@ rmpkg: */ prop_dictionary_get_cstring_nocopy(pkgd, "pkgver", &pkgver); prop_dictionary_set_cstring_nocopy(pkgd, "transaction", "remove"); - if (purge) - prop_dictionary_set_bool(pkgd, "remove-and-purge", true); prop_array_add(unsorted, pkgd); xbps_dbg_printf("%s: added into transaction (remove).\n", pkgver); reqby = prop_dictionary_get(pkgd, "requiredby"); @@ -303,15 +299,15 @@ rmpkg: if ((prop_object_type(reqby) == PROP_TYPE_ARRAY) && (prop_array_count(reqby) > 0)) rv = EEXIST; + out: - if (prop_object_type(pkgd) == PROP_TYPE_DICTIONARY) - prop_object_release(pkgd); + prop_object_release(pkgd); return rv; } int -xbps_transaction_autoremove_pkgs(bool purge) +xbps_transaction_autoremove_pkgs(void) { prop_dictionary_t transd; prop_array_t orphans, mdeps, unsorted; @@ -350,8 +346,6 @@ xbps_transaction_autoremove_pkgs(bool purge) prop_dictionary_get_cstring_nocopy(obj, "pkgver", &pkgver); prop_dictionary_set_cstring_nocopy(obj, "transaction", "remove"); - if (purge) - prop_dictionary_set_bool(obj, "remove-and-purge", true); prop_array_add(unsorted, obj); xbps_dbg_printf("%s: added into transaction (remove).\n", pkgver); diff --git a/lib/transaction_package_replace.c b/lib/transaction_package_replace.c index 71e445a7..d74d1b04 100644 --- a/lib/transaction_package_replace.c +++ b/lib/transaction_package_replace.c @@ -121,8 +121,7 @@ xbps_transaction_package_replace(prop_dictionary_t transd) * If new package is providing a virtual package to the * package that we want to replace we should respect * its requiredby and automatic-install objects, so copy - * them to the pkg's dictionary in transaction. Also - * make sure that replaced package is also purged. + * them to the pkg's dictionary in transaction. */ if (xbps_match_virtual_pkg_in_dict(pkg_repod, pattern, true) || @@ -135,8 +134,6 @@ xbps_transaction_package_replace(prop_dictionary_t transd) } prop_dictionary_set_bool(pkg_repod, "automatic-install", instd_auto); - prop_dictionary_set_bool(instd, - "remove-and-purge", true); } /* * Add package dictionary into the transaction and mark