commit e1ccb86fada2f6a5a50f86c33ea76dc9063bde85
parent 969db94dbd640891967a12b462f24b0b8d2c922b
Author: Nihal Jere <nihal@nihaljere.xyz>
Date: Mon, 22 Feb 2021 21:23:08 -0600
pkg.*: add pkg_remove
Diffstat:
M | pkg.c | | | 68 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
M | pkg.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 *);