pkgtools

morpheus pkg tools
git clone git://git.2f30.org/pkgtools.git
Log | Files | Refs | README | LICENSE

commit df9db5959ceb9e0208786f0801dbc707a45104d7
parent c4378623aaa08fb925173328365131f2a18875e0
Author: sin <sin@2f30.org>
Date:   Tue Jun 24 15:56:34 +0100

Factor pkg_*() routines into pkg.c

Diffstat:
Makefile | 1+
db.c | 327-------------------------------------------------------------------------------
pkg.c | 329+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
pkg.h | 15++++++++-------
4 files changed, 338 insertions(+), 334 deletions(-)
diff --git a/Makefile b/Makefile @@ -8,6 +8,7 @@ LIB = \ db.o \ ealloc.o \ eprintf.o \ + pkg.o \ reject.o \ strlcat.o \ strlcpy.o diff --git a/db.c b/db.c @@ -183,330 +183,3 @@ db_links(struct db *db, const char *path) links++; return links; } - -/* Create a package from the given db entry. e.g. /var/pkg/pkg#version */ -struct pkg * -pkg_load(struct db *db, const char *filename) -{ - char path[PATH_MAX], tmp[PATH_MAX], *p; - char *name, *version; - struct pkg *pkg; - struct pkgentry *pe; - FILE *fp; - char *buf = NULL; - size_t sz = 0; - ssize_t len; - - estrlcpy(tmp, filename, sizeof(tmp)); - p = strchr(tmp, '#'); - if (p) - *p = '\0'; - name = tmp; - version = p ? p + 1 : NULL; - - estrlcpy(path, db->path, sizeof(path)); - estrlcat(path, "/", sizeof(path)); - estrlcat(path, name, sizeof(path)); - if (version) { - estrlcat(path, "#", sizeof(path)); - estrlcat(path, version, sizeof(path)); - } - - pkg = pkg_new(path, name, version); - - if (!(fp = fopen(pkg->path, "r"))) { - weprintf("fopen %s:", pkg->path); - pkg_free(pkg); - return NULL; - } - - while ((len = getline(&buf, &sz, fp)) != -1) { - if (len > 0 && buf[len - 1] == '\n') - buf[len - 1] = '\0'; - - if (buf[0] == '\0') { - weprintf("%s: malformed pkg file\n", pkg->path); - free(buf); - fclose(fp); - pkg_free(pkg); - return NULL; - } - - pe = emalloc(sizeof(*pe)); - estrlcpy(path, db->prefix, sizeof(path)); - estrlcat(path, "/", sizeof(path)); - estrlcat(path, buf, sizeof(path)); - estrlcpy(pe->path, path, sizeof(pe->path)); - estrlcpy(pe->rpath, buf, sizeof(pe->rpath)); - TAILQ_INSERT_TAIL(&pkg->pe_head, pe, entry); - } - free(buf); - if (ferror(fp)) { - weprintf("%s: read error:", pkg->name); - fclose(fp); - pkg_free(pkg); - return NULL; - } - fclose(fp); - return pkg; -} - -/* Create a package from a file. e.g. /tmp/pkg#version.pkg.tgz */ -struct pkg * -pkg_load_file(struct db *db, const char *filename) -{ - char path[PATH_MAX]; - char *name, *version; - struct pkg *pkg; - struct pkgentry *pe; - struct archive *ar; - struct archive_entry *entry; - int r; - - if (!realpath(filename, path)) { - weprintf("realpath %s:", filename); - return NULL; - } - - parse_name(path, &name); - parse_version(path, &version); - pkg = pkg_new(path, name, version); - free(name); - free(version); - - ar = archive_read_new(); - - archive_read_support_filter_gzip(ar); - archive_read_support_filter_bzip2(ar); - archive_read_support_filter_xz(ar); - archive_read_support_format_tar(ar); - - if (archive_read_open_filename(ar, pkg->path, ARCHIVEBUFSIZ) < 0) { - weprintf("archive_read_open_filename %s: %s\n", pkg->path, - archive_error_string(ar)); - pkg_free(pkg); - return NULL; - } - - while (1) { - r = archive_read_next_header(ar, &entry); - if (r == ARCHIVE_EOF) - break; - if (r != ARCHIVE_OK) { - weprintf("archive_read_next_header: %s\n", - archive_error_string(ar)); - pkg_free(pkg); - return NULL; - } - pe = emalloc(sizeof(*pe)); - estrlcpy(path, db->prefix, sizeof(path)); - estrlcat(path, "/", sizeof(path)); - estrlcat(path, archive_entry_pathname(entry), - sizeof(path)); - estrlcpy(pe->path, path, sizeof(pe->path)); - estrlcpy(pe->rpath, archive_entry_pathname(entry), - sizeof(pe->rpath)); - TAILQ_INSERT_TAIL(&pkg->pe_head, pe, entry); - } - - archive_read_free(ar); - - return pkg; -} - -/* Install the given package */ -int -pkg_install(struct db *db, struct pkg *pkg) -{ - char cwd[PATH_MAX]; - struct archive *ar; - struct archive_entry *entry; - int flags, r; - - ar = archive_read_new(); - - archive_read_support_filter_gzip(ar); - archive_read_support_filter_bzip2(ar); - archive_read_support_filter_xz(ar); - archive_read_support_format_tar(ar); - - if (archive_read_open_filename(ar, pkg->path, ARCHIVEBUFSIZ) < 0) { - weprintf("archive_read_open_filename %s: %s\n", pkg->path, - archive_error_string(ar)); - return -1; - } - - if (!getcwd(cwd, sizeof(cwd))) { - weprintf("getcwd:"); - return -1; - } - if (chdir(db->prefix) < 0) { - weprintf("chdir %s:", db->prefix); - return -1; - } - - while (1) { - r = archive_read_next_header(ar, &entry); - if (r == ARCHIVE_EOF) - break; - if (r != ARCHIVE_OK) { - weprintf("archive_read_next_header %s: %s\n", - archive_entry_pathname(entry), archive_error_string(ar)); - if (chdir(cwd) < 0) - weprintf("chdir %s:", cwd); - return -1; - } - if (rej_match(db, archive_entry_pathname(entry)) > 0) { - weprintf("rejecting %s\n", archive_entry_pathname(entry)); - continue; - } - flags = ARCHIVE_EXTRACT_OWNER | ARCHIVE_EXTRACT_PERM | - ARCHIVE_EXTRACT_TIME | ARCHIVE_EXTRACT_SECURE_NODOTDOT; - if (fflag == 1) - flags |= ARCHIVE_EXTRACT_UNLINK; - r = archive_read_extract(ar, entry, flags); - if (r != ARCHIVE_OK && r != ARCHIVE_WARN) - weprintf("archive_read_extract %s: %s\n", - archive_entry_pathname(entry), archive_error_string(ar)); - } - - archive_read_free(ar); - - if (chdir(cwd) < 0) { - weprintf("chdir %s:", cwd); - return -1; - } - - return 0; -} - -static int -rm_empty_dir(const char *f, const struct stat *sb, int typeflag, - struct FTW *ftwbuf) -{ - (void) sb; - (void) ftwbuf; - - if (typeflag == FTW_DP) { - if (vflag == 1) - printf("removing %s\n", f); - rmdir(f); - } - return 0; -} - -/* Remove the package entries for the given package */ -int -pkg_remove(struct db *db, struct pkg *pkg) -{ - struct pkgentry *pe; - struct stat sb; - - TAILQ_FOREACH_REVERSE(pe, &pkg->pe_head, pe_head, entry) { - if (rej_match(db, pe->rpath) > 0) { - weprintf("rejecting %s\n", pe->rpath); - continue; - } - - if (lstat(pe->path, &sb) < 0) { - weprintf("lstat %s:", pe->path); - continue; - } - - if (S_ISDIR(sb.st_mode) == 1) { - if (fflag == 0) - printf("ignoring directory %s\n", pe->path); - /* We'll remove these further down in a separate pass */ - continue; - } - - if (S_ISLNK(sb.st_mode) == 1) { - if (fflag == 0) { - printf("ignoring link %s\n", pe->path); - continue; - } - } - - if (vflag == 1) - printf("removing %s\n", pe->path); - if (remove(pe->path) < 0) - weprintf("remove %s:", pe->path); - } - - if (fflag == 1) { - /* prune empty directories as well */ - TAILQ_FOREACH_REVERSE(pe, &pkg->pe_head, pe_head, entry) { - if (rej_match(db, pe->rpath) > 0) - continue; - if (db_links(db, pe->path) > 1) - continue; - nftw(pe->path, rm_empty_dir, 1, FTW_DEPTH); - } - } - - TAILQ_REMOVE(&db->pkg_head, pkg, entry); - TAILQ_INSERT_TAIL(&db->pkg_rm_head, pkg, entry); - - return 0; -} - -/* Check if the contents of the given package - * collide with corresponding entries in the filesystem */ -int -pkg_collisions(struct pkg *pkg) -{ - char resolvedpath[PATH_MAX]; - struct pkgentry *pe; - struct stat sb; - int ok = 0; - - TAILQ_FOREACH(pe, &pkg->pe_head, entry) { - if (access(pe->path, F_OK) == 0) { - if (stat(pe->path, &sb) < 0) { - weprintf("lstat %s:", pe->path); - return -1; - } - if (S_ISDIR(sb.st_mode) == 0) { - if (realpath(pe->path, resolvedpath)) - weprintf("%s exists\n", resolvedpath); - else - weprintf("%s exists\n", pe->path); - ok = -1; - } - } - } - - return ok; -} - -/* Create a new package instance */ -struct pkg * -pkg_new(const char *path, const char *name, const char *version) -{ - struct pkg *pkg; - - pkg = emalloc(sizeof(*pkg)); - pkg->name = estrdup(name); - if (version) - pkg->version = estrdup(version); - else - pkg->version = NULL; - estrlcpy(pkg->path, path, sizeof(pkg->path)); - TAILQ_INIT(&pkg->pe_head); - return pkg; -} - -/* Release package instance */ -void -pkg_free(struct pkg *pkg) -{ - struct pkgentry *pe, *tmp; - - for (pe = TAILQ_FIRST(&pkg->pe_head); pe; pe = tmp) { - tmp = TAILQ_NEXT(pe, entry); - free(pe); - } - free(pkg->name); - free(pkg->version); - free(pkg); -} diff --git a/pkg.c b/pkg.c @@ -0,0 +1,329 @@ +/* See LICENSE file for copyright and license details. */ +#include "pkg.h" + +/* Create a package from the given db entry. e.g. /var/pkg/pkg#version */ +struct pkg * +pkg_load(struct db *db, const char *filename) +{ + char path[PATH_MAX], tmp[PATH_MAX], *p; + char *name, *version; + struct pkg *pkg; + struct pkgentry *pe; + FILE *fp; + char *buf = NULL; + size_t sz = 0; + ssize_t len; + + estrlcpy(tmp, filename, sizeof(tmp)); + p = strchr(tmp, '#'); + if (p) + *p = '\0'; + name = tmp; + version = p ? p + 1 : NULL; + + estrlcpy(path, db->path, sizeof(path)); + estrlcat(path, "/", sizeof(path)); + estrlcat(path, name, sizeof(path)); + if (version) { + estrlcat(path, "#", sizeof(path)); + estrlcat(path, version, sizeof(path)); + } + + pkg = pkg_new(path, name, version); + + if (!(fp = fopen(pkg->path, "r"))) { + weprintf("fopen %s:", pkg->path); + pkg_free(pkg); + return NULL; + } + + while ((len = getline(&buf, &sz, fp)) != -1) { + if (len > 0 && buf[len - 1] == '\n') + buf[len - 1] = '\0'; + + if (buf[0] == '\0') { + weprintf("%s: malformed pkg file\n", pkg->path); + free(buf); + fclose(fp); + pkg_free(pkg); + return NULL; + } + + pe = emalloc(sizeof(*pe)); + estrlcpy(path, db->prefix, sizeof(path)); + estrlcat(path, "/", sizeof(path)); + estrlcat(path, buf, sizeof(path)); + estrlcpy(pe->path, path, sizeof(pe->path)); + estrlcpy(pe->rpath, buf, sizeof(pe->rpath)); + TAILQ_INSERT_TAIL(&pkg->pe_head, pe, entry); + } + free(buf); + if (ferror(fp)) { + weprintf("%s: read error:", pkg->name); + fclose(fp); + pkg_free(pkg); + return NULL; + } + fclose(fp); + return pkg; +} + +/* Create a package from a file. e.g. /tmp/pkg#version.pkg.tgz */ +struct pkg * +pkg_load_file(struct db *db, const char *filename) +{ + char path[PATH_MAX]; + char *name, *version; + struct pkg *pkg; + struct pkgentry *pe; + struct archive *ar; + struct archive_entry *entry; + int r; + + if (!realpath(filename, path)) { + weprintf("realpath %s:", filename); + return NULL; + } + + parse_name(path, &name); + parse_version(path, &version); + pkg = pkg_new(path, name, version); + free(name); + free(version); + + ar = archive_read_new(); + + archive_read_support_filter_gzip(ar); + archive_read_support_filter_bzip2(ar); + archive_read_support_filter_xz(ar); + archive_read_support_format_tar(ar); + + if (archive_read_open_filename(ar, pkg->path, ARCHIVEBUFSIZ) < 0) { + weprintf("archive_read_open_filename %s: %s\n", pkg->path, + archive_error_string(ar)); + pkg_free(pkg); + return NULL; + } + + while (1) { + r = archive_read_next_header(ar, &entry); + if (r == ARCHIVE_EOF) + break; + if (r != ARCHIVE_OK) { + weprintf("archive_read_next_header: %s\n", + archive_error_string(ar)); + pkg_free(pkg); + return NULL; + } + pe = emalloc(sizeof(*pe)); + estrlcpy(path, db->prefix, sizeof(path)); + estrlcat(path, "/", sizeof(path)); + estrlcat(path, archive_entry_pathname(entry), + sizeof(path)); + estrlcpy(pe->path, path, sizeof(pe->path)); + estrlcpy(pe->rpath, archive_entry_pathname(entry), + sizeof(pe->rpath)); + TAILQ_INSERT_TAIL(&pkg->pe_head, pe, entry); + } + + archive_read_free(ar); + + return pkg; +} + +/* Install the given package */ +int +pkg_install(struct db *db, struct pkg *pkg) +{ + char cwd[PATH_MAX]; + struct archive *ar; + struct archive_entry *entry; + int flags, r; + + ar = archive_read_new(); + + archive_read_support_filter_gzip(ar); + archive_read_support_filter_bzip2(ar); + archive_read_support_filter_xz(ar); + archive_read_support_format_tar(ar); + + if (archive_read_open_filename(ar, pkg->path, ARCHIVEBUFSIZ) < 0) { + weprintf("archive_read_open_filename %s: %s\n", pkg->path, + archive_error_string(ar)); + return -1; + } + + if (!getcwd(cwd, sizeof(cwd))) { + weprintf("getcwd:"); + return -1; + } + if (chdir(db->prefix) < 0) { + weprintf("chdir %s:", db->prefix); + return -1; + } + + while (1) { + r = archive_read_next_header(ar, &entry); + if (r == ARCHIVE_EOF) + break; + if (r != ARCHIVE_OK) { + weprintf("archive_read_next_header %s: %s\n", + archive_entry_pathname(entry), archive_error_string(ar)); + if (chdir(cwd) < 0) + weprintf("chdir %s:", cwd); + return -1; + } + if (rej_match(db, archive_entry_pathname(entry)) > 0) { + weprintf("rejecting %s\n", archive_entry_pathname(entry)); + continue; + } + flags = ARCHIVE_EXTRACT_OWNER | ARCHIVE_EXTRACT_PERM | + ARCHIVE_EXTRACT_TIME | ARCHIVE_EXTRACT_SECURE_NODOTDOT; + if (fflag == 1) + flags |= ARCHIVE_EXTRACT_UNLINK; + r = archive_read_extract(ar, entry, flags); + if (r != ARCHIVE_OK && r != ARCHIVE_WARN) + weprintf("archive_read_extract %s: %s\n", + archive_entry_pathname(entry), archive_error_string(ar)); + } + + archive_read_free(ar); + + if (chdir(cwd) < 0) { + weprintf("chdir %s:", cwd); + return -1; + } + + return 0; +} + +static int +rm_empty_dir(const char *f, const struct stat *sb, int typeflag, + struct FTW *ftwbuf) +{ + (void) sb; + (void) ftwbuf; + + if (typeflag == FTW_DP) { + if (vflag == 1) + printf("removing %s\n", f); + rmdir(f); + } + return 0; +} + +/* Remove the package entries for the given package */ +int +pkg_remove(struct db *db, struct pkg *pkg) +{ + struct pkgentry *pe; + struct stat sb; + + TAILQ_FOREACH_REVERSE(pe, &pkg->pe_head, pe_head, entry) { + if (rej_match(db, pe->rpath) > 0) { + weprintf("rejecting %s\n", pe->rpath); + continue; + } + + if (lstat(pe->path, &sb) < 0) { + weprintf("lstat %s:", pe->path); + continue; + } + + if (S_ISDIR(sb.st_mode) == 1) { + if (fflag == 0) + printf("ignoring directory %s\n", pe->path); + /* We'll remove these further down in a separate pass */ + continue; + } + + if (S_ISLNK(sb.st_mode) == 1) { + if (fflag == 0) { + printf("ignoring link %s\n", pe->path); + continue; + } + } + + if (vflag == 1) + printf("removing %s\n", pe->path); + if (remove(pe->path) < 0) + weprintf("remove %s:", pe->path); + } + + if (fflag == 1) { + /* prune empty directories as well */ + TAILQ_FOREACH_REVERSE(pe, &pkg->pe_head, pe_head, entry) { + if (rej_match(db, pe->rpath) > 0) + continue; + if (db_links(db, pe->path) > 1) + continue; + nftw(pe->path, rm_empty_dir, 1, FTW_DEPTH); + } + } + + TAILQ_REMOVE(&db->pkg_head, pkg, entry); + TAILQ_INSERT_TAIL(&db->pkg_rm_head, pkg, entry); + + return 0; +} + +/* Check if the contents of the given package + * collide with corresponding entries in the filesystem */ +int +pkg_collisions(struct pkg *pkg) +{ + char resolvedpath[PATH_MAX]; + struct pkgentry *pe; + struct stat sb; + int ok = 0; + + TAILQ_FOREACH(pe, &pkg->pe_head, entry) { + if (access(pe->path, F_OK) == 0) { + if (stat(pe->path, &sb) < 0) { + weprintf("lstat %s:", pe->path); + return -1; + } + if (S_ISDIR(sb.st_mode) == 0) { + if (realpath(pe->path, resolvedpath)) + weprintf("%s exists\n", resolvedpath); + else + weprintf("%s exists\n", pe->path); + ok = -1; + } + } + } + + return ok; +} + +/* Create a new package instance */ +struct pkg * +pkg_new(const char *path, const char *name, const char *version) +{ + struct pkg *pkg; + + pkg = emalloc(sizeof(*pkg)); + pkg->name = estrdup(name); + if (version) + pkg->version = estrdup(version); + else + pkg->version = NULL; + estrlcpy(pkg->path, path, sizeof(pkg->path)); + TAILQ_INIT(&pkg->pe_head); + return pkg; +} + +/* Release package instance */ +void +pkg_free(struct pkg *pkg) +{ + struct pkgentry *pe, *tmp; + + for (pe = TAILQ_FIRST(&pkg->pe_head); pe; pe = tmp) { + tmp = TAILQ_NEXT(pe, entry); + free(pe); + } + free(pkg->name); + free(pkg->version); + free(pkg); +} diff --git a/pkg.h b/pkg.h @@ -71,13 +71,6 @@ struct pkg *pkg_load_file(struct db *, const char *); int db_walk(struct db *, int (*)(struct db *, struct pkg *, void *), void *); int db_links(struct db *, const char *); -struct pkg *pkg_load(struct db *, const char *); -int pkg_install(struct db *, struct pkg *); -int pkg_remove(struct db *, struct pkg *); -int pkg_collisions(struct pkg *); -struct pkg *pkg_new(const char *, const char *, const char *); -void pkg_free(struct pkg *); - /* ealloc.c */ void *ecalloc(size_t, size_t); void *emalloc(size_t size); @@ -89,6 +82,14 @@ void enprintf(int, const char *, ...); void eprintf(const char *, ...); void weprintf(const char *, ...); +/* pkg.c */ +struct pkg *pkg_load(struct db *, const char *); +int pkg_install(struct db *, struct pkg *); +int pkg_remove(struct db *, struct pkg *); +int pkg_collisions(struct pkg *); +struct pkg *pkg_new(const char *, const char *, const char *); +void pkg_free(struct pkg *); + /* reject.c */ void rej_free(struct db *); int rej_load(struct db *);