commit d737825b1eb7fb43734f64ddaf067e0a3ef12d9c
parent 15c6d0445e25e7d0ceb25b798ae7989fb2b1c03d
Author: Nihal Jere <nihal@nihaljere.xyz>
Date: Sun, 21 Feb 2021 16:00:52 -0600
add alt.*
Diffstat:
A | alt.c | | | 146 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | alt.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);