nkiss

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

commit d737825b1eb7fb43734f64ddaf067e0a3ef12d9c
parent 15c6d0445e25e7d0ceb25b798ae7989fb2b1c03d
Author: Nihal Jere <nihal@nihaljere.xyz>
Date:   Sun, 21 Feb 2021 16:00:52 -0600

add alt.*

Diffstat:
Aalt.c | 146+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aalt.h | 10++++++++++
2 files changed, 156 insertions(+), 0 deletions(-)

diff --git a/alt.c b/alt.c @@ -0,0 +1,146 @@ +#define _BSD_SOURCE + +#include <dirent.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "pkg.h" +#include "alt.h" +#include "util.h" + +void +alt_from_choice(struct alt_t *alt, char *fname) +{ + char *term; + + if (strlen(fname) >= PATH_LEN) + die("choice %s too long", fname); + + /* choice must contain '>' */ + if ((term = memccpy(alt->name, fname, '>', strlen(fname)))) + *(term-1) = '\0'; + else + die("malformatted fname %s", fname); + + strcpy(alt->path, strchr(fname, '>')); + strrepl(alt->path, '>', '/'); +} + +/* dest *must* be at least PKG_NAME_SIZE + ALT_PATH_SIZE */ +static void +to_choice(struct alt_t *alt, char *dest) +{ + char *end; + /* choice system uses '>' to represent slashes, so if the path already + * contains a '>', it cannot be used as an alternative */ + if (strchr(alt->path, '>')) + die("Path '%s' in package '%s' contains '>'", alt->path, alt->name); + + end = stpcpy(dest, alt->name); + strcpy(end, alt->path); + + strrepl(dest, '/', '>'); +} + +static int +alt_sort(const void *a, const void *b) +{ + struct alt_t *alta = (struct alt_t *)a; + struct alt_t *altb = (struct alt_t *)b; + int first; + + if ((first = strcmp(alta->name, altb->name)) != 0) + return first; + + return strcmp(alta->path, altb->path); +} + +void +alt_load(struct alt_t *alts) +{ + DIR *choices; + struct dirent *choice; + int count = 0; + + if ((choices = opendir(KISS_CHOICES)) == NULL) + die("couldn't open choices database:"); + + choice = readdir(choices); + for (; choice != NULL; choice = readdir(choices)) { + if (choice->d_name[0] == '.') + continue; + + alt_from_choice(&alts[count], choice->d_name); + count++; + } + closedir(choices); + + qsort(alts, count, sizeof(struct alt_t), &alt_sort); + + for (int i = 0; i < count; i++) + printf("%s %s\n", alts[i].name, alts[i].path); +} + +void +alt_owner(char owner[PKG_NAME_MAX], char *path) +{ + char mpath[PATH_LEN], line[PATH_LEN], *p; + FILE *mfile; + DIR *installed; + struct dirent *pkg; + int c; + + if ((installed = opendir(KISS_INSTALLED)) == NULL) + die("couldn't open choices database:"); + + pkg = readdir(installed); + + /* loop through packages in KISS_INSTALLED */ + for (; pkg != NULL; pkg = readdir(installed)) { + if (strncmp(pkg->d_name, ".", sizeof(".") - 1) == 0) + continue; + + c = snprintf(mpath, PATH_LEN, "%s/%s/manifest", KISS_INSTALLED, + pkg->d_name); + + if (c >= PATH_LEN) { + closedir(installed); + die("%s: manifest path for %s too long", __func__, pkg->d_name); + } + + if (strlen(pkg->d_name) >= PKG_NAME_MAX) { + closedir(installed); + die("%s: package name %s too long", __func__, pkg->d_name); + } + + if ((mfile = fopen(mpath, "r")) == NULL) { + closedir(installed); + die("%s: couldn't open manifest for %s", __func__, pkg->d_name); + } + + /* loop through lines in manifest file */ + while (fgets(line, 512, mfile)) { + if ((p = strrchr(line, '\n')) == NULL) { + fclose(mfile); + closedir(installed); + die("%s: manifest line too long for %s", __func__, + pkg->d_name); + } + + *p = '\0'; + + /* path is present in this manifest */ + if (strcmp(path, line) == 0) { + fclose(mfile); + strncpy(owner, pkg->d_name, PKG_NAME_MAX); + closedir(installed); + return; + } + } + + fclose(mfile); + } + + closedir(installed); +} diff --git a/alt.h b/alt.h @@ -0,0 +1,10 @@ +#define ALT_MAX 256 +#define KISS_CHOICES "/var/db/kiss/choices" + +struct alt_t { + char name[PKG_NAME_MAX]; + char path[PATH_LEN]; +}; + +void alt_load(); +void alt_owner(char owner[PKG_NAME_MAX], char *path);