nkiss

WIP
git clone git://git.nihaljere.xyz/nkiss
Log | Files | Refs

commit e1ccb86fada2f6a5a50f86c33ea76dc9063bde85
parent 969db94dbd640891967a12b462f24b0b8d2c922b
Author: Nihal Jere <nihal@nihaljere.xyz>
Date:   Mon, 22 Feb 2021 21:23:08 -0600

pkg.*: add pkg_remove

Diffstat:
Mpkg.c | 68++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mpkg.h | 1+
2 files changed, 69 insertions(+), 0 deletions(-)

diff --git a/pkg.c b/pkg.c @@ -14,6 +14,74 @@ #include "util.h" void +pkg_remove(char *name) +{ + char manifestpath[PATH_LEN], etcsumspath[PATH_LEN], line[PATH_LEN], + etcsumstr[1024], etcsumhash[HASH_LEN], filehash[HASH_LEN]; + FILE *manifest, *etcsums = NULL; + char *p; + + if (snprintf(manifestpath, PATH_LEN, "%s/%s/manifest", + KISS_INSTALLED, name) >= PATH_LEN) { + die("%s: manifest path too long for %s", __func__, name); + } + + /* no length check needed: "etcsums" is shorter than "manifest" */ + snprintf(etcsumspath, PATH_LEN, "%s/%s/etcsums", KISS_INSTALLED, name); + + if ((manifest = fopen(manifestpath, "r")) == NULL) { + die("%s: failed to open manifest for %s", __func__, name); + } + + if (access(etcsumspath, F_OK) == 0 && !(etcsums = fopen(etcsumspath, "r"))) { + fclose(manifest); + die("%s: failed to open etcsums for %s", name); + } + + while(fgets(line, PATH_LEN, manifest)) { + if ((p = strchr(line, '\n')) == NULL) { + fclose(manifest); + if (etcsums) + fclose(etcsums); + die("%s: path too long in manifest for %s", __func__, name); + } + *p = '\0'; + + /* /etc files are dealt with specially */ + if (strncmp(line, "/etc/", sizeof("/etc/") - 1) == 0 && etcsums) { + if (!fgets(etcsumstr, 1024, etcsums)) { + fclose(manifest); + fclose(etcsums); + die("%s: bad etcsums for %s", __func__, name); + } + + if (sha256_file(line, filehash) == -1) + die("%s: failed to hash %s", __func__, line); + + sha256_fromstr(etcsumhash, etcsumstr); + + /* if the file in /etc has been modified, don't remove it */ + if (memcmp(etcsumhash, filehash, HASH_LEN) != 0) + continue; + } + + /* we do rmdir first, as unlink won't tell us whether a file cannot be + * removed because it's a directory. */ + if (rmdir(line) == -1) { + if (errno == ENOTEMPTY) + continue; + + if (errno == ENOTDIR && unlink(line) == -1) + warn("%s: failed to remove %s:", __func__, line); + } + } + + fclose(manifest); + if (etcsums) + fclose(etcsums); +} + +void pkg_retrieve(struct source_t *sources) { for (int i = 0; sources[i].path[0] != '\0'; i++) { diff --git a/pkg.h b/pkg.h @@ -17,6 +17,7 @@ struct source_t { char checksum[HASH_LEN]; }; +void pkg_remove(char *name); void pkg_retrieve(struct source_t *sources); int pkg_sources(char *repo, char *name, struct source_t *); void pkg_checksums_load(char *repo, char *name, struct source_t *);