commit 155d25f88664709355a98723d96aa886180ed9d9
parent 945efae19305d4416f44b666b37340901d5055ce
Author: sin <sin@2f30.org>
Date: Mon, 16 Jun 2014 00:14:59 +0100
Add db interface
Diffstat:
M | Makefile | | | 2 | +- |
A | db.c | | | 571 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | db.h | | | 28 | ++++++++++++++++++++++++++++ |
M | infopkg.c | | | 109 | +++++++++++++++++++------------------------------------------------------------ |
M | installpkg.c | | | 304 | ++++++------------------------------------------------------------------------- |
D | lock.c | | | 32 | -------------------------------- |
M | removepkg.c | | | 262 | +++++++------------------------------------------------------------------------ |
M | strlcat.c | | | 17 | ++++++++++++++++- |
M | strlcpy.c | | | 17 | ++++++++++++++++- |
M | util.h | | | 2 | ++ |
10 files changed, 704 insertions(+), 640 deletions(-)
diff --git a/Makefile b/Makefile
@@ -4,7 +4,7 @@ include config.mk
.SUFFIXES: .c .o
LIB = \
- lock.o \
+ db.o \
strlcat.o \
strlcpy.o
diff --git a/db.c b/db.c
@@ -0,0 +1,571 @@
+/* See LICENSE file for copyright and license details. */
+#define _XOPEN_SOURCE 500
+#include <archive.h>
+#include <archive_entry.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <ftw.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/file.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include "db.h"
+#include "util.h"
+
+int fflag = 0;
+int vflag = 0;
+
+struct dbentry {
+ struct pkg *pkg;
+ int deleted;
+ struct dbentry *next;
+};
+
+struct db {
+ DIR *pkgdir;
+ char prefix[PATH_MAX];
+ char path[PATH_MAX];
+ struct dbentry *head;
+};
+
+struct db *
+dbinit(const char *prefix)
+{
+ struct db *db;
+ struct sigaction sa;
+
+ db = malloc(sizeof(*db));
+ if (!db) {
+ fprintf(stderr, "out of memory\n");
+ return NULL;
+ }
+ db->head = NULL;
+
+ realpath(prefix, db->prefix);
+
+ estrlcpy(db->path, db->prefix, sizeof(db->path));
+ estrlcat(db->path, "/var/pkg", sizeof(db->path));
+
+ db->pkgdir = opendir(db->path);
+ if (!db->pkgdir) {
+ fprintf(stderr, "opendir %s: %s\n", db->path,
+ strerror(errno));
+ return NULL;
+ }
+
+ if (flock(dirfd(db->pkgdir), LOCK_EX | LOCK_NB) < 0) {
+ if (errno == EWOULDBLOCK)
+ fprintf(stderr, "package db already locked\n");
+ else
+ fprintf(stderr, "flock %s: %s\n", db->path,
+ strerror(errno));
+ return NULL;
+ }
+
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = SIG_IGN;
+ sigaction(SIGHUP, &sa, 0);
+ sigaction(SIGINT, &sa, 0);
+ sigaction(SIGQUIT, &sa, 0);
+ sigaction(SIGTERM, &sa, 0);
+
+ return db;
+}
+
+int
+dbload(struct db *db)
+{
+ struct dbentry *de;
+ struct dirent *dp;
+
+ while ((dp = readdir(db->pkgdir))) {
+ if (strcmp(dp->d_name, ".") == 0 ||
+ strcmp(dp->d_name, "..") == 0)
+ continue;
+ de = malloc(sizeof(*de));
+ if (!de) {
+ fprintf(stderr, "out of memory\n");
+ return -1;
+ }
+ de->pkg = pkgnew(dp->d_name);
+ if (!de->pkg)
+ return -1;
+ if (dbpkgload(db, de->pkg) < 0)
+ return -1;
+ de->next = db->head;
+ db->head = de;
+ }
+
+ return 0;
+}
+
+struct pkg *
+dbfind(struct db *db, const char *name)
+{
+ struct dbentry *de;
+
+ for (de = db->head; de; de = de->next)
+ if (de->deleted == 0 && strcmp(de->pkg->name, name) == 0)
+ break;
+ if (!de)
+ return NULL;
+ return de->pkg;
+}
+
+int
+dbcollide(struct db *db, const char *name)
+{
+ char pkgpath[PATH_MAX];
+ char path[PATH_MAX];
+ struct archive *ar;
+ struct archive_entry *entry;
+ struct stat sb;
+ int ok = 0;
+ int r;
+
+ realpath(name, pkgpath);
+
+ ar = archive_read_new();
+
+ archive_read_support_filter_gzip(ar);
+ archive_read_support_format_tar(ar);
+
+ r = archive_read_open_filename(ar, pkgpath, 10240);
+ if (r < 0) {
+ fprintf(stderr, "%s\n", archive_error_string(ar));
+ return -1;
+ }
+
+ while (1) {
+ r = archive_read_next_header(ar, &entry);
+ if (r == ARCHIVE_EOF)
+ break;
+ if (r != ARCHIVE_OK) {
+ fprintf(stderr, "%s\n", archive_error_string(ar));
+ return -1;
+ }
+ estrlcpy(path, db->prefix, sizeof(path));
+ estrlcat(path, "/", sizeof(path));
+ estrlcat(path, archive_entry_pathname(entry), sizeof(path));
+ if (access(path, F_OK) == 0) {
+ r = stat(path, &sb);
+ if (r < 0) {
+ fprintf(stderr, "lstat %s: %s\n",
+ archive_entry_pathname(entry),
+ strerror(errno));
+ return -1;
+ }
+ if (S_ISDIR(sb.st_mode) == 0) {
+ fprintf(stderr, "%s exists\n", path);
+ ok = -1;
+ }
+ }
+ }
+
+ archive_read_free(ar);
+
+ return ok;
+}
+
+int
+dbadd(struct db *db, const char *name)
+{
+ char pkgpath[PATH_MAX], tmppath[PATH_MAX];
+ char path[PATH_MAX];
+ FILE *fp;
+ struct archive *ar;
+ struct archive_entry *entry;
+ int r;
+
+ realpath(name, pkgpath);
+
+ estrlcpy(tmppath, pkgpath, sizeof(tmppath));
+ estrlcpy(path, db->path, sizeof(path));
+ estrlcat(path, "/", sizeof(path));
+ estrlcat(path, basename(tmppath), sizeof(path));
+
+ ar = archive_read_new();
+
+ archive_read_support_filter_gzip(ar);
+ archive_read_support_format_tar(ar);
+
+ r = archive_read_open_filename(ar, pkgpath, 10240);
+ if (r < 0) {
+ fprintf(stderr, "%s\n", archive_error_string(ar));
+ return -1;
+ }
+
+ fp = fopen(path, "w");
+ if (!fp) {
+ fprintf(stderr, "fopen %s: %s\n", path,
+ strerror(errno));
+ return -1;
+ }
+
+ while (1) {
+ r = archive_read_next_header(ar, &entry);
+ if (r == ARCHIVE_EOF)
+ break;
+ if (r != ARCHIVE_OK) {
+ fprintf(stderr, "%s\n", archive_error_string(ar));
+ return -1;
+ }
+ estrlcpy(tmppath, db->prefix, sizeof(tmppath));
+ estrlcat(tmppath, "/", sizeof(tmppath));
+ estrlcat(tmppath, archive_entry_pathname(entry), sizeof(tmppath));
+ if (vflag == 1)
+ printf("installed %s\n", tmppath);
+ fputs(archive_entry_pathname(entry), fp);
+ fputc('\n', fp);
+ }
+
+ if (vflag == 1)
+ printf("updating %s\n", path);
+ fflush(fp);
+ r = fsync(fileno(fp));
+ if (r < 0)
+ fprintf(stderr, "fsync: %s\n", strerror(errno));
+ fclose(fp);
+
+ archive_read_free(ar);
+
+ return 0;
+}
+
+int
+dbwalk(struct db *db, int (*cb)(struct db *, struct pkg *, void *), void *data)
+{
+ struct dbentry *de;
+ int r;
+
+ for (de = db->head; de; de = de->next) {
+ if (de->deleted == 1)
+ continue;
+ r = cb(db, de->pkg, data);
+ if (r < 0)
+ return -1;
+ /* terminate traversal */
+ if (r > 0)
+ return 1;
+ }
+ return 0;
+}
+
+int
+dblinks(struct db *db, const char *path)
+{
+ struct dbentry *de;
+ struct pkgentry *pe;
+ int links = 0;
+
+ for (de = db->head; de; de = de->next) {
+ if (de->deleted == 1)
+ continue;
+ for (pe = de->pkg->head; pe; pe = pe->next)
+ if (strcmp(pe->path, path) == 0)
+ links++;
+ }
+ return links;
+}
+
+int
+dbfree(struct db *db)
+{
+ struct dbentry *de, *tmp;
+
+ de = db->head;
+ while (de) {
+ tmp = de->next;
+ pkgfree(de->pkg);
+ free(de);
+ de = tmp;
+ }
+ if (flock(dirfd(db->pkgdir), LOCK_UN) < 0) {
+ fprintf(stderr, "flock %s: %s\n", db->path,
+ strerror(errno));
+ return -1;
+ }
+ closedir(db->pkgdir);
+ free(db);
+ return 0;
+}
+
+void
+dbdump(struct db *db)
+{
+ struct dbentry *de;
+
+ for (de = db->head; de; de = de->next) {
+ if (de->deleted == 1)
+ continue;
+ puts(de->pkg->name);
+ }
+}
+
+int
+dbpkgload(struct db *db, struct pkg *pkg)
+{
+ struct pkgentry *pe;
+ FILE *fp;
+ char path[PATH_MAX];
+ char *buf = NULL, *p;
+ size_t sz = 0;
+
+ if (pkg->head)
+ return 0;
+
+ estrlcpy(path, db->path, sizeof(path));
+ estrlcat(path, "/", sizeof(path));
+ estrlcat(path, pkg->name, sizeof(path));
+
+ fp = fopen(path, "r");
+ if (!fp) {
+ fprintf(stderr, "fopen %s: %s\n", pkg->name,
+ strerror(errno));
+ return -1;
+ }
+
+ while (getline(&buf, &sz, fp) != -1) {
+ p = strrchr(buf, '\n');
+ if (p)
+ *p = '\0';
+
+ if (buf[0] == '\0') {
+ fprintf(stderr, "malformed pkg file: %s\n",
+ path);
+ return -1;
+ }
+
+ pe = malloc(sizeof(*pe));
+ if (!pe) {
+ fprintf(stderr, "out of memory\n");
+ return -1;
+ }
+
+ estrlcpy(pe->path, db->prefix, sizeof(pe->path));
+ estrlcat(pe->path, "/", sizeof(pe->path));
+ estrlcat(pe->path, buf, sizeof(pe->path));
+
+ pe->next = pkg->head;
+ pkg->head = pe;
+ }
+ if (ferror(fp)) {
+ fprintf(stderr, "input error %s: %s\n", pkg->name,
+ strerror(errno));
+ fclose(fp);
+ return -1;
+ }
+
+ free(buf);
+ fclose(fp);
+ return 0;
+}
+
+int
+dbpkginstall(struct db *db, const char *name)
+{
+ char cwd[PATH_MAX];
+ char pkgpath[PATH_MAX];
+ struct archive *ar;
+ struct archive_entry *entry;
+ int flags;
+ int r;
+
+ realpath(name, pkgpath);
+
+ ar = archive_read_new();
+
+ archive_read_support_filter_gzip(ar);
+ archive_read_support_format_tar(ar);
+
+ r = archive_read_open_filename(ar, pkgpath, 10240);
+ if (r < 0) {
+ fprintf(stderr, "%s\n", archive_error_string(ar));
+ return -1;
+ }
+
+ getcwd(cwd, sizeof(cwd));
+ r = chdir(db->prefix);
+ if (r < 0) {
+ fprintf(stderr, "chdir %s: %s\n", db->prefix,
+ strerror(errno));
+ return -1;
+ }
+
+ while (1) {
+ r = archive_read_next_header(ar, &entry);
+ if (r == ARCHIVE_EOF)
+ break;
+ if (r != ARCHIVE_OK) {
+ fprintf(stderr, "%s\n", archive_error_string(ar));
+ r = chdir(cwd);
+ if (r < 0)
+ fprintf(stderr, "chdir %s: %s\n", cwd, strerror(errno));
+ return -1;
+ }
+ flags = ARCHIVE_EXTRACT_OWNER | ARCHIVE_EXTRACT_PERM |
+ ARCHIVE_EXTRACT_TIME | ARCHIVE_EXTRACT_UNLINK |
+ ARCHIVE_EXTRACT_SECURE_NODOTDOT;
+ if (archive_read_extract(ar, entry, flags) != ARCHIVE_OK)
+ fprintf(stderr, "%s\n", archive_error_string(ar));
+ }
+
+ archive_read_free(ar);
+
+ r = chdir(cwd);
+ if (r < 0) {
+ fprintf(stderr, "chdir %s: %s\n", cwd, strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+rmemptydir(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;
+}
+
+int
+dbpkgremove(struct db *db, const char *name)
+{
+ struct dbentry *de;
+ struct pkg *pkg;
+ struct pkgentry *pe;
+ struct stat sb;
+ char tmppath[PATH_MAX], *p;
+ int r;
+
+ estrlcpy(tmppath, name, sizeof(tmppath));
+ p = basename(tmppath);
+
+ for (de = db->head; de; de = de->next) {
+ if (de->deleted == 1)
+ continue;
+ if (strcmp(de->pkg->name, p) == 0) {
+ pkg = de->pkg;
+ break;
+ }
+ }
+ if (!de) {
+ fprintf(stderr, "%s is not installed\n", name);
+ return -1;
+ }
+
+ for (pe = pkg->head; pe; pe = pe->next) {
+ r = lstat(pe->path, &sb);
+ if (r < 0) {
+ fprintf(stderr, "lstat %s: %s\n",
+ pe->path, strerror(errno));
+ continue;
+ }
+
+ if (S_ISDIR(sb.st_mode) == 1) {
+ if (fflag == 0)
+ printf("ignoring directory %s\n", pe->path);
+ 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);
+ r = remove(pe->path);
+ if (r < 0) {
+ fprintf(stderr, "remove %s: %s\n", pe->path,
+ strerror(errno));
+ continue;
+ }
+ }
+
+ if (fflag == 1) {
+ /* prune empty directories as well */
+ for (pe = pkg->head; pe; pe = pe->next) {
+ if (dblinks(db, pe->path) > 1)
+ continue;
+ nftw(pe->path, rmemptydir, 1, FTW_DEPTH);
+ }
+ }
+
+ de->deleted = 1;
+
+ return 0;
+}
+
+int
+dbrm(struct db *db, const char *name)
+{
+ struct dbentry *de;
+ char path[PATH_MAX], tmpname[PATH_MAX], *p;
+ int r;
+
+ estrlcpy(tmpname, name, sizeof(tmpname));
+ p = basename(tmpname);
+ for (de = db->head; de; de = de->next) {
+ if (de->deleted == 1 && strcmp(de->pkg->name, p) == 0) {
+ estrlcpy(path, db->path, sizeof(path));
+ estrlcat(path, "/", sizeof(path));
+ estrlcat(path, de->pkg->name, sizeof(path));
+ if (vflag == 1)
+ printf("removing %s\n", path);
+ /* nuke db entry for this package */
+ r = remove(path);
+ if (r < 0) {
+ fprintf(stderr, "remove %s: %s\n", path,
+ strerror(errno));
+ return -1;
+ }
+ break;
+ }
+ }
+ return 0;
+}
+
+struct pkg *
+pkgnew(char *name)
+{
+ struct pkg *pkg;
+
+ pkg = malloc(sizeof(*pkg));
+ if (!pkg) {
+ fprintf(stderr, "out of memory\n");
+ return NULL;
+ }
+ pkg->name = name;
+ pkg->head = NULL;
+ return pkg;
+}
+
+void
+pkgfree(struct pkg *pkg)
+{
+ struct pkgentry *pe, *tmp;
+
+ pe = pkg->head;
+ while (pe) {
+ tmp = pe->next;
+ free(pe);
+ pe = tmp;
+ }
+ free(pkg);
+}
diff --git a/db.h b/db.h
@@ -0,0 +1,28 @@
+/* See LICENSE file for copyright and license details. */
+struct pkgentry {
+ char path[PATH_MAX];
+ struct pkgentry *next;
+};
+
+struct pkg {
+ char *name;
+ struct pkgentry *head;
+};
+
+extern int fflag;
+extern int vflag;
+
+struct db *dbinit(const char *);
+int dbload(struct db *);
+int dbcollide(struct db *, const char *);
+int dbadd(struct db *, const char *);
+int dbwalk(struct db *, int (*)(struct db *, struct pkg *, void *), void *);
+int dblinks(struct db *, const char *);
+int dbfree(struct db *);
+void dbdump(struct db *);
+int dbpkgload(struct db *, struct pkg *);
+int dbpkginstall(struct db *, const char *);
+int dbpkgremove(struct db *, const char *);
+int dbrm(struct db *, const char *);
+struct pkg *pkgnew(char *);
+void pkgfree(struct pkg *);
diff --git a/infopkg.c b/infopkg.c
@@ -1,7 +1,5 @@
/* See LICENSE file for copyright and license details. */
-#include <dirent.h>
#include <errno.h>
-#include <libgen.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
@@ -9,9 +7,10 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
+#include "db.h"
#include "util.h"
-static void ownpkg(const char *, const char *);
+static int ownpkg(struct db *, struct pkg *, void *);
char *argv0;
@@ -27,10 +26,8 @@ usage(void)
int
main(int argc, char *argv[])
{
- DIR *dir;
- struct dirent *dp;
+ struct db *db;
char *prefix = "/";
- char path[PATH_MAX];
int Oflag = 0;
int i;
int r;
@@ -49,110 +46,56 @@ main(int argc, char *argv[])
if (Oflag == 0 || argc < 1)
usage();
- r = chdir(prefix);
- if (r < 0) {
- fprintf(stderr, "chdir %s: %s\n", prefix,
- strerror(errno));
- return EXIT_FAILURE;
- }
-
- lockdb();
-
- dir = opendir("var/pkg");
- if (!dir) {
- fprintf(stderr, "opendir %s: %s\n", "var/pkg",
- strerror(errno));
- return EXIT_FAILURE;
- }
+ db = dbinit(prefix);
+ if (!db)
+ exit(EXIT_FAILURE);
+ r = dbload(db);
+ if (r < 0)
+ exit(EXIT_FAILURE);
for (i = 0; i < argc; i++) {
- while ((dp = readdir(dir))) {
- if (strcmp(dp->d_name, ".") == 0 ||
- strcmp(dp->d_name, "..") == 0)
- continue;
- if (strlcpy(path, dp->d_name, sizeof(path)) >= sizeof(path)) {
- fprintf(stderr, "path too long\n");
- exit(EXIT_FAILURE);
- }
- ownpkg(basename(path), argv[i]);
- }
- rewinddir(dir);
+ r = dbwalk(db, ownpkg, argv[i]);
+ if (r < 0)
+ exit(EXIT_FAILURE);
}
- closedir(dir);
+ dbfree(db);
return EXIT_SUCCESS;
}
-static void
-ownpkg(const char *pkg, const char *f)
+static int
+ownpkg(struct db *db, struct pkg *pkg, void *file)
{
+ struct pkgentry *pe;
struct stat sb1, sb2;
- char buf[BUFSIZ], *p;
- char path[PATH_MAX], filename[PATH_MAX];
- FILE *fp;
+ char path[PATH_MAX];
int r;
- for (; *f == '/'; f++)
- ;
- if (strlcpy(filename, f, sizeof(filename)) >= sizeof(filename)) {
- fprintf(stderr, "path too long\n");
- exit(EXIT_FAILURE);
- }
+ realpath(file, path);
- r = lstat(filename, &sb1);
+ r = lstat(path, &sb1);
if (r < 0) {
- fprintf(stderr, "lstat %s: %s\n", f, strerror(errno));
- exit(EXIT_FAILURE);
- }
- if (S_ISREG(sb1.st_mode) == 0) {
- fprintf(stderr, "%s is not a regular file\n", filename);
+ fprintf(stderr, "lstat %s: %s\n", path, strerror(errno));
exit(EXIT_FAILURE);
}
- if (strlcpy(path, "var/pkg/", sizeof(path)) >= sizeof(path)) {
- fprintf(stderr, "path too long\n");
- exit(EXIT_FAILURE);
- }
- if (strlcat(path, pkg, sizeof(path)) >= sizeof(path)) {
- fprintf(stderr, "path too long\n");
+ if (dbpkgload(db, pkg) < 0)
exit(EXIT_FAILURE);
- }
-
- fp = fopen(path, "r");
- if (!fp) {
- fprintf(stderr, "fopen %s: %s\n", path,
- strerror(errno));
- exit(EXIT_FAILURE);
- }
- while (fgets(buf, sizeof(buf), fp)) {
- p = strrchr(buf, '\n');
- if (p)
- *p = '\0';
-
- if (buf[0] == '\0') {
- fprintf(stderr, "nil file entry in %s, skipping\n", path);
- continue;
- }
-
- r = lstat(buf, &sb2);
+ for (pe = pkg->head; pe; pe = pe->next) {
+ r = lstat(pe->path, &sb2);
if (r < 0) {
fprintf(stderr, "lstat %s: %s\n",
- buf, strerror(errno));
+ pe->path, strerror(errno));
continue;
}
-
if (sb1.st_dev == sb2.st_dev &&
sb1.st_ino == sb2.st_ino) {
- printf("/%s is owned by %s\n", filename, pkg);
+ printf("%s is owned by %s\n", path, pkg->name);
break;
}
}
- if (ferror(fp)) {
- fprintf(stderr, "I/O error while processing %s\n", path);
- exit(EXIT_FAILURE);
- }
- fclose(fp);
+ return 0;
}
diff --git a/installpkg.c b/installpkg.c
@@ -1,25 +1,13 @@
/* See LICENSE file for copyright and license details. */
-#include <archive.h>
-#include <archive_entry.h>
-#include <errno.h>
-#include <libgen.h>
#include <limits.h>
-#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
+#include "db.h"
#include "util.h"
-static void checkdb(const char *);
-static void updatedb(const char *, const char *);
-static int collisions(const char *, const char *);
-static int extract(const char *, const char *);
+static int collidepkg(struct db *, struct pkg *, void *);
char *argv0;
-static int vflag = 0;
static void
usage(void)
@@ -34,11 +22,11 @@ usage(void)
int
main(int argc, char *argv[])
{
+ struct db *db;
+ char path[PATH_MAX];
+ char *prefix = "/";
int r;
int i;
- char cwd[PATH_MAX];
- char *prefix = "/";
- int fflag = 0;
ARGBEGIN {
case 'v':
@@ -57,287 +45,37 @@ main(int argc, char *argv[])
if (argc < 1)
usage();
- getcwd(cwd, sizeof(cwd));
-
- r = chdir(prefix);
- if (r < 0) {
- fprintf(stderr, "chdir %s: %s\n", prefix,
- strerror(errno));
+ db = dbinit(prefix);
+ if (!db)
exit(EXIT_FAILURE);
- }
-
- lockdb();
-
- r = chdir(cwd);
- if (r < 0) {
- fprintf(stderr, "chdir %s: %s\n", prefix,
- strerror(errno));
+ r = dbload(db);
+ if (r < 0)
exit(EXIT_FAILURE);
- }
- checkdb(prefix);
for (i = 0; i < argc; i++) {
+ realpath(argv[i], path);
if (vflag == 1)
- printf("installing %s\n", argv[i]);
+ printf("installing %s\n", path);
if (fflag == 0) {
- if (collisions(prefix, argv[i]) != 0) {
- fprintf(stderr,
- "aborting %s, use -f to override\n",
- argv[i]);
+ r = dbwalk(db, collidepkg, path);
+ if (r < 0)
exit(EXIT_FAILURE);
- }
}
- updatedb(prefix, argv[i]);
- extract(prefix, argv[i]);
- printf("installed %s\n", argv[i]);
+ dbadd(db, path);
+ dbpkginstall(db, path);
+ printf("installed %s\n", path);
}
- r = chdir(prefix);
- if (r < 0) {
- fprintf(stderr, "chdir %s: %s\n", prefix,
- strerror(errno));
- exit(EXIT_FAILURE);
- }
+ dbfree(db);
return EXIT_SUCCESS;
}
-static void
-checkdb(const char *prefix)
-{
- char cwd[PATH_MAX];
- char *dbpath = "var/pkg";
- int r;
-
- getcwd(cwd, sizeof(cwd));
-
- r = chdir(prefix);
- if (r < 0) {
- fprintf(stderr, "chdir %s: %s\n", prefix,
- strerror(errno));
- exit(EXIT_FAILURE);
- }
-
- r = access(dbpath, R_OK | W_OK | X_OK);
- if (r < 0) {
- fprintf(stderr, "access %s: %s\n", dbpath, strerror(errno));
- exit(EXIT_FAILURE);
- }
-
- chdir(cwd);
-}
-
-static void
-updatedb(const char *prefix, const char *f)
-{
- char cwd[PATH_MAX];
- char path[PATH_MAX], filename[PATH_MAX];
- FILE *fp;
- struct archive *in;
- struct archive_entry *entry;
- int r;
-
- getcwd(cwd, sizeof(cwd));
-
- in = archive_read_new();
-
- archive_read_support_filter_gzip(in);
- archive_read_support_format_tar(in);
-
- r = archive_read_open_filename(in, f, BUFSIZ);
- if (r < 0) {
- fprintf(stderr, "%s\n", archive_error_string(in));
- exit(EXIT_FAILURE);
- }
-
- r = chdir(prefix);
- if (r < 0) {
- fprintf(stderr, "chdir %s: %s\n", prefix,
- strerror(errno));
- exit(EXIT_FAILURE);
- }
-
- if (strlcpy(path, "var/pkg/", sizeof(path)) >= sizeof(path)) {
- fprintf(stderr, "path too long\n");
- exit(EXIT_FAILURE);
- }
- if (strlcpy(filename, f, sizeof(filename)) >= sizeof(filename)) {
- fprintf(stderr, "path too long\n");
- exit(EXIT_FAILURE);
- }
- if (strlcat(path, basename(filename), sizeof(path)) >= sizeof(path)) {
- fprintf(stderr, "path too long\n");
- exit(EXIT_FAILURE);
- }
-
- fp = fopen(path, "w");
- if (!fp) {
- fprintf(stderr, "fopen %s: %s\n", path,
- strerror(errno));
- exit(EXIT_FAILURE);
- }
-
- while (1) {
- r = archive_read_next_header(in, &entry);
- if (r == ARCHIVE_EOF)
- break;
- if (r != ARCHIVE_OK) {
- fprintf(stderr, "%s\n", archive_error_string(in));
- exit(EXIT_FAILURE);
- }
- if (vflag == 1)
- printf("installed %s\n", archive_entry_pathname(entry));
- fputs(archive_entry_pathname(entry), fp);
- fputc('\n', fp);
- }
-
- if (vflag == 1)
- printf("updating %s\n", path);
- fflush(fp);
- r = fsync(fileno(fp));
- if (r < 0)
- fprintf(stderr, "fsync: %s\n", strerror(errno));
- fclose(fp);
-
- archive_read_close(in);
- archive_read_free(in);
-
- chdir(cwd);
-}
-
-static int
-collisions(const char *prefix, const char *f)
-{
- char cwd[PATH_MAX];
- struct archive *in;
- struct archive_entry *entry;
- struct stat sb;
- int ok = 0;
- int r;
-
- getcwd(cwd, sizeof(cwd));
-
- in = archive_read_new();
-
- archive_read_support_filter_gzip(in);
- archive_read_support_format_tar(in);
-
- r = archive_read_open_filename(in, f, BUFSIZ);
- if (r < 0) {
- fprintf(stderr, "%s\n", archive_error_string(in));
- exit(EXIT_FAILURE);
- }
-
- r = chdir(prefix);
- if (r < 0) {
- fprintf(stderr, "chdir %s: %s\n", prefix,
- strerror(errno));
- exit(EXIT_FAILURE);
- }
-
- while (1) {
- r = archive_read_next_header(in, &entry);
- if (r == ARCHIVE_EOF)
- break;
- if (r != ARCHIVE_OK) {
- fprintf(stderr, "%s\n", archive_error_string(in));
- exit(EXIT_FAILURE);
- }
- if (access(archive_entry_pathname(entry), F_OK) == 0) {
- r = stat(archive_entry_pathname(entry), &sb);
- if (r < 0) {
- fprintf(stderr, "lstat %s: %s\n",
- archive_entry_pathname(entry),
- strerror(errno));
- exit(EXIT_FAILURE);
- }
- if (S_ISDIR(sb.st_mode) == 0) {
- fprintf(stderr, "%s/%s exists\n", prefix,
- archive_entry_pathname(entry));
- ok = 1;
- }
- }
- }
-
- archive_read_close(in);
- archive_read_free(in);
-
- chdir(cwd);
- return ok;
-}
-
static int
-extract(const char *prefix, const char *f)
+collidepkg(struct db *db, struct pkg *pkg, void *file)
{
- char cwd[PATH_MAX];
- const void *buf;
- size_t size;
- int64_t offset;
- struct archive *in;
- struct archive *out;
- struct archive_entry *entry;
- int r;
-
- getcwd(cwd, sizeof(cwd));
-
- in = archive_read_new();
- out = archive_write_disk_new();
-
- archive_write_disk_set_options(out,
- ARCHIVE_EXTRACT_OWNER |
- ARCHIVE_EXTRACT_PERM |
- ARCHIVE_EXTRACT_TIME |
- ARCHIVE_EXTRACT_UNLINK |
- ARCHIVE_EXTRACT_SECURE_NODOTDOT);
-
- archive_read_support_filter_gzip(in);
- archive_read_support_format_tar(in);
-
- r = archive_read_open_filename(in, f, BUFSIZ);
- if (r < 0) {
- fprintf(stderr, "%s\n", archive_error_string(in));
- exit(EXIT_FAILURE);
- }
-
- r = chdir(prefix);
- if (r < 0) {
- fprintf(stderr, "chdir %s: %s\n", prefix,
- strerror(errno));
- exit(EXIT_FAILURE);
- }
-
- while (1) {
- r = archive_read_next_header(in, &entry);
- if (r == ARCHIVE_EOF)
- break;
- if (r != ARCHIVE_OK) {
- fprintf(stderr, "%s\n", archive_error_string(in));
- exit(EXIT_FAILURE);
- }
- r = archive_write_header(out, entry);
- if (r != ARCHIVE_OK) {
- fprintf(stderr, "%s\n", archive_error_string(out));
- } else {
- while (1) {
- r = archive_read_data_block(in, &buf,
- &size, &offset);
- if (r == ARCHIVE_EOF)
- break;
- if (r != ARCHIVE_OK)
- break;
- r = archive_write_data_block(out, buf, size,
- offset);
- if (r != ARCHIVE_OK)
- break;
- }
- }
- }
-
- archive_read_close(in);
- archive_read_free(in);
- archive_write_close(out);
- archive_write_free(out);
-
- chdir(cwd);
+ (void)pkg;
+ if (dbcollide(db, file) < 0)
+ return -1;
return 0;
}
diff --git a/lock.c b/lock.c
@@ -1,32 +0,0 @@
-/* See LICENSE file for copyright and license details. */
-#include <dirent.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-/* lock the package dabatase - assumes cwd is the root prefix */
-void
-lockdb(void)
-{
- DIR *dir;
-
- dir = opendir("var/pkg");
- if (!dir) {
- fprintf(stderr, "opendir %s: %s\n", "var/pkg",
- strerror(errno));
- exit(EXIT_FAILURE);
- }
-
- if (flock(dirfd(dir), LOCK_EX | LOCK_NB) < 0) {
- if (errno == EWOULDBLOCK)
- fprintf(stderr, "package db already locked\n");
- else
- fprintf(stderr, "flock %s: %s\n", "var/pkg",
- strerror(errno));
- exit(EXIT_FAILURE);
- }
-}
diff --git a/removepkg.c b/removepkg.c
@@ -1,25 +1,14 @@
/* See LICENSE file for copyright and license details. */
-#define _XOPEN_SOURCE 500
-#include <dirent.h>
-#include <errno.h>
-#include <ftw.h>
-#include <libgen.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
+#include "db.h"
#include "util.h"
-static int numrefs(const char *);
-static int rmemptydir(const char *, const struct stat *, int, struct FTW *);
-static int removepkg(const char *);
+static int removepkg(struct db *, struct pkg *, void *);
char *argv0;
-static int vflag;
-static int fflag;
static void
usage(void)
@@ -34,11 +23,9 @@ usage(void)
int
main(int argc, char *argv[])
{
- DIR *dir;
- struct dirent *dp;
- char filename[PATH_MAX];
+ struct db *db;
+ char path[PATH_MAX];
char *prefix = "/";
- int found = 0;
int r;
int i;
@@ -59,239 +46,36 @@ main(int argc, char *argv[])
if (argc < 1)
usage();
- r = chdir(prefix);
- if (r < 0) {
- fprintf(stderr, "chdir %s: %s\n", prefix,
- strerror(errno));
- return EXIT_FAILURE;
- }
-
- lockdb();
-
- dir = opendir("var/pkg");
- if (!dir) {
- fprintf(stderr, "opendir %s: %s\n", "var/pkg",
- strerror(errno));
- return EXIT_FAILURE;
- }
+ db = dbinit(prefix);
+ if (!db)
+ exit(EXIT_FAILURE);
+ r = dbload(db);
+ if (r < 0)
+ exit(EXIT_FAILURE);
for (i = 0; i < argc; i++) {
- if (strlcpy(filename, argv[i], sizeof(filename)) >= sizeof(filename)) {
- fprintf(stderr, "path too long\n");
+ realpath(argv[i], path);
+ r = dbwalk(db, removepkg, path);
+ if (r < 0)
exit(EXIT_FAILURE);
- }
- found = 0;
-
- while ((dp = readdir(dir))) {
- if (strcmp(dp->d_name, ".") == 0 ||
- strcmp(dp->d_name, "..") == 0)
- continue;
- if (strcmp(dp->d_name, basename(filename)) == 0) {
- if (vflag == 1)
- printf("removing %s\n", argv[i]);
- if (removepkg(argv[i]) != 0)
- return EXIT_FAILURE;
- printf("removed %s\n", argv[i]);
- found = 1;
- break;
- }
- }
- if (found == 0) {
- fprintf(stderr, "package %s not installed\n", argv[i]);
- return EXIT_FAILURE;
- }
-
- rewinddir(dir);
+ dbrm(db, path);
+ printf("removed %s\n", path);
}
- closedir(dir);
+ dbfree(db);
return EXIT_SUCCESS;
}
static int
-numrefs(const char *f)
-{
- DIR *dir;
- struct dirent *dp;
- FILE *fp;
- char path[PATH_MAX];
- char buf[BUFSIZ], *p;
- int refs = 0;
-
- dir = opendir("var/pkg");
- if (!dir) {
- fprintf(stderr, "opendir %s: %s\n", "var/pkg",
- strerror(errno));
- exit(EXIT_FAILURE);
- }
-
- while ((dp = readdir(dir))) {
- if (strcmp(dp->d_name, ".") == 0 ||
- strcmp(dp->d_name, "..") == 0)
- continue;
-
- if (strlcpy(path, "var/pkg/", sizeof(path)) >= sizeof(path)) {
- fprintf(stderr, "path too long\n");
- exit(EXIT_FAILURE);
- }
- if (strlcat(path, dp->d_name, sizeof(path)) >= sizeof(path)) {
- fprintf(stderr, "path too long\n");
- exit(EXIT_FAILURE);
- }
-
- fp = fopen(path, "r");
- if (!fp) {
- fprintf(stderr, "fopen %s: %s\n", path,
- strerror(errno));
- exit(EXIT_FAILURE);
- }
-
- while (fgets(buf, sizeof(buf), fp)) {
- p = strrchr(buf, '\n');
- if (p)
- *p = '\0';
- if (buf[0] == '\0')
- continue;
- if (strcmp(buf, f) == 0)
- refs++;
- }
- if (ferror(fp)) {
- fprintf(stderr, "I/O error while processing %s\n", path);
- fclose(fp);
- return 1;
- }
-
- fclose(fp);
- }
-
- closedir(dir);
-
- return refs;
-}
-
-static int
-rmemptydir(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;
-}
-
-static int
-removepkg(const char *f)
+removepkg(struct db *db, struct pkg *pkg, void *file)
{
- FILE *fp;
- struct stat sb;
- char buf[BUFSIZ], *p;
- char path[PATH_MAX], filename[PATH_MAX];
- int r;
-
- if (strlcpy(path, "var/pkg/", sizeof(path)) >= sizeof(path)) {
- fprintf(stderr, "path too long\n");
- exit(EXIT_FAILURE);
- }
- if (strlcpy(filename, f, sizeof(filename)) >= sizeof(filename)) {
- fprintf(stderr, "path too long\n");
- exit(EXIT_FAILURE);
- }
- if (strlcat(path, basename(filename), sizeof(path)) >= sizeof(path)) {
- fprintf(stderr, "path too long\n");
- exit(EXIT_FAILURE);
- }
-
- fp = fopen(path, "r");
- if (!fp) {
- fprintf(stderr, "fopen %s: %s\n", path,
- strerror(errno));
- return 1;
- }
-
- while (fgets(buf, sizeof(buf), fp)) {
- p = strrchr(buf, '\n');
- if (p)
- *p = '\0';
-
- if (buf[0] == '\0') {
- fprintf(stderr, "nil file entry in %s, skipping\n",
- path);
- continue;
- }
-
- r = lstat(buf, &sb);
- if (r < 0) {
- fprintf(stderr, "lstat %s: %s\n",
- buf, strerror(errno));
- continue;
- }
-
- if (S_ISDIR(sb.st_mode) == 1) {
- if (fflag == 0)
- printf("ignoring directory %s\n", buf);
- continue;
- }
-
- if (S_ISLNK(sb.st_mode) == 1) {
- if (fflag == 0) {
- printf("ignoring link %s\n", buf);
- continue;
- }
- }
-
- if (vflag == 1)
- printf("removing %s\n", buf);
- r = remove(buf);
- if (r < 0) {
- fprintf(stderr, "remove %s: %s\n", buf,
- strerror(errno));
- continue;
- }
- }
- if (ferror(fp)) {
- fprintf(stderr, "I/O error while processing %s\n", path);
- fclose(fp);
- return 1;
- }
-
- if (fflag == 1) {
- /* prune empty directories as well */
- rewind(fp);
- while (fgets(buf, sizeof(buf), fp)) {
- p = strrchr(buf, '\n');
- if (p)
- *p = '\0';
- if (buf[0] == '\0')
- continue;
- if (numrefs(buf) > 1)
- continue;
- nftw(buf, rmemptydir, 1, FTW_DEPTH);
- }
- if (ferror(fp)) {
- fprintf(stderr, "I/O error while processing %s\n", path);
- fclose(fp);
- return 1;
- }
- }
-
- fclose(fp);
-
- if (vflag == 1)
- printf("removing %s\n", path);
- /* nuke db entry for this package */
- r = remove(path);
- if (r < 0) {
- fprintf(stderr, "remove %s: %s\n", path,
- strerror(errno));
- return 1;
- }
+ char name[PATH_MAX], *p;
- sync();
+ estrlcpy(name, file, sizeof(name));
+ p = basename(name);
+ if (strcmp(pkg->name, p) == 0)
+ if (dbpkgremove(db, p) < 0)
+ return -1;
return 0;
}
diff --git a/strlcat.c b/strlcat.c
@@ -14,8 +14,10 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
+#include <sys/types.h>
#include "util.h"
/*
@@ -49,3 +51,16 @@ strlcat(char *dst, const char *src, size_t siz)
*d = '\0';
return(dlen + (s - src)); /* count does not include NUL */
}
+
+size_t
+estrlcat(char *dst, const char *src, size_t siz)
+{
+ size_t r;
+
+ r = strlcat(dst, src, siz);
+ if (r >= siz) {
+ fprintf(stderr, "destination buffer too small\n");
+ exit(EXIT_FAILURE);
+ }
+ return r;
+}
diff --git a/strlcpy.c b/strlcpy.c
@@ -14,8 +14,10 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
+#include <sys/types.h>
#include "util.h"
/*
@@ -45,3 +47,16 @@ strlcpy(char *dst, const char *src, size_t siz)
}
return(s - src - 1); /* count does not include NUL */
}
+
+size_t
+estrlcpy(char *dst, const char *src, size_t siz)
+{
+ size_t r;
+
+ r = strlcpy(dst, src, siz);
+ if (r >= siz) {
+ fprintf(stderr, "destination buffer too small\n");
+ exit(EXIT_FAILURE);
+ }
+ return r;
+}
diff --git a/util.h b/util.h
@@ -10,5 +10,7 @@ void lockdb(void);
#undef strlcat
size_t strlcat(char *, const char *, size_t);
+size_t estrlcat(char *, const char *, size_t);
#undef strlcpy
size_t strlcpy(char *, const char *, size_t);
+size_t estrlcpy(char *, const char *, size_t);