pm

barely a pack manager
git clone git://z3bra.org/pm
Log | Files | Refs | README | LICENSE

commit 11ca8f6728acf195601b904ac0c90cbfff2f2f8f
parent 714472bbfbcc98d91cd52a7ebc7ca205a0601666
Author: z3bra <willyatmailoodotorg>
Date:   Wed Jun 22 09:54:01 +0200

Clean pack from syystem if update fails

Packs should not be left "half-installed". In case the update fails during
installation, the pack will simply be removed from the system.

This commit also fixes a few cases where mmap() would fail, and put metadata
removal in its own function, for easier use.

Diffstat:
pm.c | 116++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------
1 file changed, 82 insertions(+), 34 deletions(-)
diff --git a/pm.c b/pm.c @@ -68,6 +68,7 @@ int pack_extract(const char *rootfs, const char *datadir, struct pack *p); int pack_install(const char *rootfs, const char *datadir, struct pack *p); int pack_delete(const char *rootfs, const char *datadir, struct pack *p); +int inspect_installed(const char *datadir, const char *name); int inspect_version(const char *datadir, const char *name, char version[]); int inspect_collision(const char *rootfs, struct pack *p); int inspect_files(int fd, const char *datadir, const char *name); @@ -77,6 +78,7 @@ int write_metadata(const char *datadir, struct pack *pack); int write_entry(struct archive *a, struct archive *w); int delete_node(char *path); int delete_content(const char *rootfs, char *map, size_t size); +int delete_metadata(const char *datadir, char *name); /* action wrappers around CLI arguments */ int install(const char *rootfs, const char *datadir, char *path); @@ -236,13 +238,12 @@ pack_load_tarball(char *path) struct pack * pack_load_metadata(const char *datadir, char *name) { - struct stat st; struct pack *pack = NULL; char tmp[PATH_MAX] = ""; snprintf(tmp, PATH_MAX, "%s/%s", datadir, name); - if (stat(tmp, &st) < 0) { + if (inspect_installed(datadir, name)) { fprintf(stderr, "%s: No such pack installed\n", name); return NULL; } @@ -315,6 +316,7 @@ pack_extract(const char *rootfs, const char *datadir, struct pack *p) if ((r = archive_read_open_filename(a, p->path, 0)) != ARCHIVE_OK) { fprintf(stderr, "%s: %s\n", p->path, archive_error_string(a)); archive_read_free(a); + close(fd); return r; } @@ -347,6 +349,7 @@ pack_extract(const char *rootfs, const char *datadir, struct pack *p) dprintf(fd, "%s\n", archive_entry_pathname(e)); archive_write_finish_entry(w); } + close(fd); chdir(cwd); archive_write_free(w); @@ -399,14 +402,14 @@ pack_install(const char *rootfs, const char *datadir, struct pack *p) int pack_delete(const char *rootfs, const char *datadir, struct pack *p) { - int fd; + int fd, r = 0; char *addr = NULL; char tmp[PATH_MAX]; struct stat st; snprintf(tmp, PATH_MAX, "%s/%s/files", datadir, p->name); - if (stat(tmp, &st) < 0 && errno == ENOENT) { - fprintf(stderr, "%s: No installed files\n", p->name); + if (stat(tmp, &st) < 0) { + perror(tmp); return -1; } if ((fd = open(tmp, O_RDONLY)) < 0) { @@ -414,42 +417,46 @@ pack_delete(const char *rootfs, const char *datadir, struct pack *p) return ERR_DELETE; } - addr = mmap(0, st.st_size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0); - if (addr == MAP_FAILED) { - perror(tmp); - close(fd); - } - - log(LOG_VERBOSE, "deleting installed files\n"); - /* ignore errors so everything gets deleted */ - if (delete_content(rootfs, addr, st.st_size) < 0) { - fprintf(stderr, "%s: Pack removal failed\n", p->name); - close(fd); - return ERR_DELETE; + if (st.st_size > 0) { + addr = mmap(0, st.st_size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0); + if (addr == MAP_FAILED) { + perror("mmap"); + close(fd); + return ERR_DELETE; + } + + log(LOG_VERBOSE, "deleting installed files\n"); + /* ignore errors so everything gets deleted */ + if (delete_content(rootfs, addr, st.st_size) < 0) { + fprintf(stderr, "%s: Pack removal failed\n", p->name); + close(fd); + r = ERR_DELETE; + } + munmap(addr, st.st_size); } close(fd); log(LOG_VERBOSE, "cleaning metadata\n"); - log(LOG_DEBUG, "- %s\n", tmp); - if (unlink(tmp) < 0) { - perror(tmp); - return ERR_DELETE; + if (delete_metadata(datadir, p->name) < 0) { + fprintf(stderr, "%s: Metadata removal failed\n", p->name); + r = ERR_DELETE; } - snprintf(tmp, PATH_MAX, "%s/%s/version", datadir, p->name); + return r; +} - log(LOG_DEBUG, "- %s\n", tmp); - if (unlink(tmp) < 0) { - perror(tmp); - return ERR_DELETE; - } - /* remove metadata directory, no matter what */ - snprintf(tmp, PATH_MAX, "%s/%s", datadir, p->name); - log(LOG_DEBUG, "- %s\n", tmp); - rmdir(tmp); +/* + * Returns 0 if "name" is installed, non-zero otherwise + */ +int +inspect_installed(const char *datadir, const char *name) +{ + char tmp[PATH_MAX] = ""; + struct stat st; - return 0; + snprintf(tmp, PATH_MAX, "%s/%s", datadir, name); + return stat(tmp, &st) || S_ISDIR(st.st_mode); } @@ -507,7 +514,7 @@ inspect_collision(const char *rootfs, struct pack *p) while (archive_read_next_header(a, &e) == ARCHIVE_OK) { if (stat(archive_entry_pathname(e), &st) == 0 && !S_ISDIR(st.st_mode)) { fprintf(stderr, "%s: File exists\n", archive_entry_pathname(e)); - r = -1; + r++; break; } archive_read_data_skip(a); @@ -724,6 +731,32 @@ delete_content(const char *rootfs, char *map, size_t size) /* + * Delete the metadata stored for a given pack name + */ +int +delete_metadata(const char *datadir, char *name) +{ + int i; + char path[PATH_MAX] = ""; + char *meta[] = { "files", "version", NULL }; + + for (i = 0; meta[i] != NULL; i++) { + snprintf(path, PATH_MAX, "%s/%s/%s", datadir, name, meta[i]); + log(LOG_DEBUG, "- %s\n", path); + if (unlink(path) < 0) { + perror(path); + return ERR_DELETE; + } + } + + /* remove metadata directory, no matter what */ + snprintf(path, PATH_MAX, "%s/%s", datadir, name); + log(LOG_DEBUG, "- %s\n", path); + return rmdir(path); +} + + +/* * Install a pack from the given path. This wraps load/install of a pack */ int @@ -760,6 +793,12 @@ update(const char *rootfs, const char *datadir, char *path) if ((p = pack_load_tarball(path)) == NULL) return ERR_PACK_LOAD; + if (inspect_installed(datadir, p->name)) { + fprintf(stderr, "%s: No such pack installed\n", p->name); + pack_free(p); + return ERR_DELETE; + } + if (pack_delete(rootfs, datadir, p) != 0) return ERR_DELETE; @@ -767,8 +806,12 @@ update(const char *rootfs, const char *datadir, char *path) r += pack_install(rootfs, datadir, p); overwrite = tmp; - if (r == 0) + if (r == 0) { log(LOG_INFO, "updated %s to %s\n", p->name, p->version); + } else { + fprintf(stderr, "%s: Update failed. Cleaning filesystem\n", p->name); + pack_delete(rootfs, datadir, p); + } pack_free(p); @@ -785,6 +828,11 @@ delete(const char *rootfs, const char *datadir, char *name) int r = 0; struct pack *p = NULL; + if (inspect_installed(datadir, name)) { + fprintf(stderr, "%s: No such pack installed\n", name); + return ERR_DELETE; + } + if ((p = pack_load_metadata(datadir, name)) == NULL) return ERR_PACK_LOAD;