commit 55385f8857d702bc5c1af7b0a39fc974f16dd3ad Author: kento2 Date: Fri Sep 4 19:59:24 2026 +0200 . diff --git a/README b/README new file mode 100644 index 0000000..7359a6d --- /dev/null +++ b/README @@ -0,0 +1,18 @@ +depends: https://github.com/arp242/toml-c + +expected usage: +(1) pkg_add /path/to/source/code/with/template/file +(2) pkg_add name of source template in source repo + +We need a template format that specifies compiletime +dependencies in addition to the standart rpm spec fields +such as name, description, build script, etc.. +In the case of (2), it must also specify an URL to get the +source code from. + +in the end it should produce an rpm package and install it +(with dnf). referenced packages(like in dependencies) should +use the name from fedoras package list. +If a source template depends on another package that only +exists as a source template, pkg_add must make sure to +compile that first. diff --git a/builder/README b/builder/README new file mode 100644 index 0000000..0d60c9c --- /dev/null +++ b/builder/README @@ -0,0 +1,9 @@ +build steps: + - create rootfs(empty fs) + - fetch all files(including dependencies) + cache + - extract/install files/deps + - chroot into rootfs + +impl details: + - use queues for fetch and extract with parallel workers + - rootfs diff --git a/builder/run b/builder/run new file mode 100755 index 0000000..521052d --- /dev/null +++ b/builder/run @@ -0,0 +1,10 @@ +#!/bin/sh +mkdir -p rootfs +podman run \ + -v ./rootfs:/data \ + docker.io/fedora \ + dnf5 \ + --installroot /data \ + --repofrompath "bootstrap,https://ftp.uni-stuttgart.de/fedora/releases/44/Everything/x86_64/os/" \ + --assumeyes \ + install basesystem ed diff --git a/conf.strff b/conf.strff new file mode 100644 index 0000000..2ca3868 --- /dev/null +++ b/conf.strff @@ -0,0 +1,12 @@ +name=pkg_add +version=0.1 +makedeps=muon samurai + +[build] +muon setup build +samu -C build + +[install] +install -d /usr/local/bin +install -m755 pkg_add /usr/local/bin + diff --git a/example.source-template b/example.source-template new file mode 100644 index 0000000..28e4cd2 --- /dev/null +++ b/example.source-template @@ -0,0 +1,11 @@ +name=lr +ver=2.0.1 +descr=List files, recursively + +build() { + make +} + +install() { + make install +} diff --git a/fetcher/.cache/clangd/index/fetcher.h.C36D6C766E6C351D.idx b/fetcher/.cache/clangd/index/fetcher.h.C36D6C766E6C351D.idx new file mode 100644 index 0000000..b6b664d Binary files /dev/null and b/fetcher/.cache/clangd/index/fetcher.h.C36D6C766E6C351D.idx differ diff --git a/fetcher/.cache/clangd/index/main.c.4133924D837FB6CB.idx b/fetcher/.cache/clangd/index/main.c.4133924D837FB6CB.idx new file mode 100644 index 0000000..7a223ed Binary files /dev/null and b/fetcher/.cache/clangd/index/main.c.4133924D837FB6CB.idx differ diff --git a/fetcher/.cache/clangd/index/spawnchild.c.CA3605D2CF26EC96.idx b/fetcher/.cache/clangd/index/spawnchild.c.CA3605D2CF26EC96.idx new file mode 100644 index 0000000..972a34b Binary files /dev/null and b/fetcher/.cache/clangd/index/spawnchild.c.CA3605D2CF26EC96.idx differ diff --git a/fetcher/README b/fetcher/README new file mode 100644 index 0000000..9e2d1ec --- /dev/null +++ b/fetcher/README @@ -0,0 +1,10 @@ +idea: + given a list of URL-to-path pairs, it downloads them in + parallel to the specified path. + +implementation: + These pairs are added to a queue(FIFO) along with an + attempt counter. Multiple worker processes are spawned + that each handle an entry in a queue. + + workers write to an error pipe and to a out pipe. diff --git a/fetcher/a.txt b/fetcher/a.txt new file mode 100644 index 0000000..f8fbf60 --- /dev/null +++ b/fetcher/a.txt @@ -0,0 +1,11 @@ + + + +lab 0x13 + + +

welcome to the lab!

+

git

+

intellij colorscheme +inspired by this blog post

+ diff --git a/fetcher/fetcher-worker.c b/fetcher/fetcher-worker.c new file mode 100644 index 0000000..2c9a0c4 --- /dev/null +++ b/fetcher/fetcher-worker.c @@ -0,0 +1,5 @@ +/* + * stdin serves as a queue in the form of + * URL outputDir + * where outputDir is the directory to save the downloaded + * file in. diff --git a/fetcher/fetcher.c b/fetcher/fetcher.c new file mode 100644 index 0000000..161415c --- /dev/null +++ b/fetcher/fetcher.c @@ -0,0 +1,60 @@ +#include +#include +#include +#include +#include "fetcher.h" + +#define dieusage() die(100, "usage: ", argv0, " [-v] [-j jobs] URL...\n\ + (-v means verbose)") + +int verbose = 0; +int jobs = 5; + +int queuepipe[2]; +/* merged stdout of workers */ +int errpipe[2]; +/* merged stderr of workers */ +int outpipe[2]; + +int main(int argc, char **argv) +{ + errmsg_iam(*argv); + int i; + for (i = 1; i < argc; i++) { + if (argv[i][0] != '-') break; + if (argv[i][1] == '-' && !argv[i][2]) break; + switch (argv[i][1]) { + case 'j': + i++; + jobs = atoi(argv[i]); + if (jobs < 1) + die(100, "value for -n must be >= 1"); + break; + case 'v': + verbose = 1; + break; + default: dieusage(); + } + } + argc -= i; + argv += i; + if (argc < 1) dieusage(); + + if (pipe(errpipe)<0 + || pipe(outpipe)<0 + ) diesys(111, "pipe"); + + if (verbose) { + buffer_puts(buffer_2, "Using "); + buffer_putlong(buffer_2, jobs); + buffer_puts(buffer_2, " parallel jobs\n"); + buffer_flush(buffer_2); + } + + char **fetchcmd = (char *[]){"curl", "-o", "a.txt", "https://lab0x13.site/index.html", NULL}; + pid_t pid = spawnchild(fetchcmd, outpipe[1], errpipe[1]); + if (pid<0) + exit(111); + waitpid(pid, NULL, 0); + exit(0); +} diff --git a/fetcher/fetcher.h b/fetcher/fetcher.h new file mode 100644 index 0000000..0bd196c --- /dev/null +++ b/fetcher/fetcher.h @@ -0,0 +1,13 @@ +#ifndef FETCHER_H +#define FETCHER_H + +#include + +/* + * execs args[0] with args. output is connected to outfd + * and errfd. + * return: pid of child process or -1 on error. + */ +pid_t spawnchild(char **args, int outfd, int errfd); + +#endif diff --git a/fetcher/meson.build b/fetcher/meson.build new file mode 100644 index 0000000..15e55b7 --- /dev/null +++ b/fetcher/meson.build @@ -0,0 +1,26 @@ +project( + 'fetcher', 'c', + default_options: [ + 'c_std=c99', + 'warning_level=2', + ], +) + +cc = meson.get_compiler('c') +deps = [ + cc.find_library('libowfat'), + dependency('libtoml'), +] + +tmpdir = get_option('tmpdir') +add_project_arguments('-DTMPDIR="'+tmpdir+'"', language: 'c') + +executable('fetcher', files( + 'fetcher.c', + 'spawnchild.c', +), dependencies:deps) + +executable('fetcher-worker', files( + 'fetcher-worker.c', + 'spawnchild.c', +), dependencies:deps) diff --git a/fetcher/meson.options b/fetcher/meson.options new file mode 100644 index 0000000..78c7680 --- /dev/null +++ b/fetcher/meson.options @@ -0,0 +1 @@ +option('tmpdir', type : 'string', value : '/tmp', description : 'writable directory for temporary files') diff --git a/fetcher/spawnchild.c b/fetcher/spawnchild.c new file mode 100644 index 0000000..cbb6b18 --- /dev/null +++ b/fetcher/spawnchild.c @@ -0,0 +1,41 @@ +#include +#include +#include +#include +#include + +static void carpsysargs(char *args[]) +{ + buffer_puts(buffer_2, "failed to exec"); + while (*args) { + buffer_puts(buffer_2, " \'"); + buffer_puts(buffer_2, *args); + buffer_puts(buffer_2, "'"); + args++; + } + buffer_puts(buffer_2, ": "); + buffer_puts(buffer_2, strerror(errno)); + buffer_puts(buffer_2, "\n"); + buffer_flush(buffer_2); +} + +pid_t spawnchild(char *args[], int infd, int outfd, int errfd) +{ + pid_t pid = fork(); + switch (pid) { + case -1: carpsys("fork: "); return -1; + case 0: + // TODO pipe + if (dup2(1, outfd)<0 + || dup2(2, errfd)<0 + ) { + carpsys("dup2"); + return -1; + } + execvp(args[0], args); + carpsysargs(args); + return -1; + default: + return pid; + } +} diff --git a/meson.build b/meson.build new file mode 100644 index 0000000..80541dd --- /dev/null +++ b/meson.build @@ -0,0 +1,23 @@ +project( + 'pkg_add', 'c', + default_options: [ + 'c_std=c99', + 'warning_level=2', + ], +) + +cc = meson.get_compiler('c') +deps = [ + cc.find_library('libowfat'), + dependency('libtoml'), +] + +executable('pkg_add', files( + 'pkg_add.c', + 'strff/strff_open.c', + 'strff/strff_close.c', + 'strff/strff_seek.c', + 'strff/strff_read.c', + 'strff/strff_read_sa.c', + 'strff/strff_get.c', +), dependencies:deps) diff --git a/pkin/.cache/clangd/index/command.h.727709215E1D2925.idx b/pkin/.cache/clangd/index/command.h.727709215E1D2925.idx new file mode 100644 index 0000000..c436398 Binary files /dev/null and b/pkin/.cache/clangd/index/command.h.727709215E1D2925.idx differ diff --git a/pkin/.cache/clangd/index/command.h.E33C7F315E9CF039.idx b/pkin/.cache/clangd/index/command.h.E33C7F315E9CF039.idx new file mode 100644 index 0000000..9ee4e04 Binary files /dev/null and b/pkin/.cache/clangd/index/command.h.E33C7F315E9CF039.idx differ diff --git a/pkin/.cache/clangd/index/pkin-fetch.c.B7C410291EA526B1.idx b/pkin/.cache/clangd/index/pkin-fetch.c.B7C410291EA526B1.idx new file mode 100644 index 0000000..92284f2 Binary files /dev/null and b/pkin/.cache/clangd/index/pkin-fetch.c.B7C410291EA526B1.idx differ diff --git a/pkin/.cache/clangd/index/pkin-search.c.8730E14F4B8BB0EA.idx b/pkin/.cache/clangd/index/pkin-search.c.8730E14F4B8BB0EA.idx new file mode 100644 index 0000000..ddba38d Binary files /dev/null and b/pkin/.cache/clangd/index/pkin-search.c.8730E14F4B8BB0EA.idx differ diff --git a/pkin/.cache/clangd/index/pkin-search.c.D3DBB6646E975011.idx b/pkin/.cache/clangd/index/pkin-search.c.D3DBB6646E975011.idx new file mode 100644 index 0000000..a561e61 Binary files /dev/null and b/pkin/.cache/clangd/index/pkin-search.c.D3DBB6646E975011.idx differ diff --git a/pkin/.cache/clangd/index/pkin.c.C675078E4F1A4042.idx b/pkin/.cache/clangd/index/pkin.c.C675078E4F1A4042.idx new file mode 100644 index 0000000..72995a2 Binary files /dev/null and b/pkin/.cache/clangd/index/pkin.c.C675078E4F1A4042.idx differ diff --git a/pkin/.cache/clangd/index/pkin.c.D857533628058145.idx b/pkin/.cache/clangd/index/pkin.c.D857533628058145.idx new file mode 100644 index 0000000..a70469a Binary files /dev/null and b/pkin/.cache/clangd/index/pkin.c.D857533628058145.idx differ diff --git a/pkin/.cache/clangd/index/pkin.h.5D4259BBCB8EB07C.idx b/pkin/.cache/clangd/index/pkin.h.5D4259BBCB8EB07C.idx new file mode 100644 index 0000000..bbe8320 Binary files /dev/null and b/pkin/.cache/clangd/index/pkin.h.5D4259BBCB8EB07C.idx differ diff --git a/pkin/.cache/clangd/index/pkin__spawn.c.044553C952326624.idx b/pkin/.cache/clangd/index/pkin__spawn.c.044553C952326624.idx new file mode 100644 index 0000000..c24ae20 Binary files /dev/null and b/pkin/.cache/clangd/index/pkin__spawn.c.044553C952326624.idx differ diff --git a/pkin/.cache/clangd/index/pkin_internal.h.C7C817E1AC1D4889.idx b/pkin/.cache/clangd/index/pkin_internal.h.C7C817E1AC1D4889.idx new file mode 100644 index 0000000..aea4561 Binary files /dev/null and b/pkin/.cache/clangd/index/pkin_internal.h.C7C817E1AC1D4889.idx differ diff --git a/pkin/.cache/clangd/index/pkin_pkg_fetch_add.c.567D59DC572DF25C.idx b/pkin/.cache/clangd/index/pkin_pkg_fetch_add.c.567D59DC572DF25C.idx new file mode 100644 index 0000000..d5b4f6e Binary files /dev/null and b/pkin/.cache/clangd/index/pkin_pkg_fetch_add.c.567D59DC572DF25C.idx differ diff --git a/pkin/.cache/clangd/index/pkin_pkg_fetch_prepare.c.3C43AEA4633DFE94.idx b/pkin/.cache/clangd/index/pkin_pkg_fetch_prepare.c.3C43AEA4633DFE94.idx new file mode 100644 index 0000000..4f3878c Binary files /dev/null and b/pkin/.cache/clangd/index/pkin_pkg_fetch_prepare.c.3C43AEA4633DFE94.idx differ diff --git a/pkin/.cache/clangd/index/pkin_pkg_fetch_start.c.00A52DA4899B5257.idx b/pkin/.cache/clangd/index/pkin_pkg_fetch_start.c.00A52DA4899B5257.idx new file mode 100644 index 0000000..10010b9 Binary files /dev/null and b/pkin/.cache/clangd/index/pkin_pkg_fetch_start.c.00A52DA4899B5257.idx differ diff --git a/pkin/.cache/clangd/index/pkin_repo.h.084305234E7EB486.idx b/pkin/.cache/clangd/index/pkin_repo.h.084305234E7EB486.idx new file mode 100644 index 0000000..fc342b1 Binary files /dev/null and b/pkin/.cache/clangd/index/pkin_repo.h.084305234E7EB486.idx differ diff --git a/pkin/.cache/clangd/index/pkin_repo_findpkg.c.ABF447006ED33B46.idx b/pkin/.cache/clangd/index/pkin_repo_findpkg.c.ABF447006ED33B46.idx new file mode 100644 index 0000000..5a2a086 Binary files /dev/null and b/pkin/.cache/clangd/index/pkin_repo_findpkg.c.ABF447006ED33B46.idx differ diff --git a/pkin/.cache/clangd/index/pkin_repo_iter_init.c.7D258EE86721E7C5.idx b/pkin/.cache/clangd/index/pkin_repo_iter_init.c.7D258EE86721E7C5.idx new file mode 100644 index 0000000..3cac3a2 Binary files /dev/null and b/pkin/.cache/clangd/index/pkin_repo_iter_init.c.7D258EE86721E7C5.idx differ diff --git a/pkin/.cache/clangd/index/pkin_repo_iter_init.c.9C0D1EC759DF3F44.idx b/pkin/.cache/clangd/index/pkin_repo_iter_init.c.9C0D1EC759DF3F44.idx new file mode 100644 index 0000000..d26bb3c Binary files /dev/null and b/pkin/.cache/clangd/index/pkin_repo_iter_init.c.9C0D1EC759DF3F44.idx differ diff --git a/pkin/.cache/clangd/index/pkin_repo_iter_init.c.B9E838E2E779EB3F.idx b/pkin/.cache/clangd/index/pkin_repo_iter_init.c.B9E838E2E779EB3F.idx new file mode 100644 index 0000000..9e82ccf Binary files /dev/null and b/pkin/.cache/clangd/index/pkin_repo_iter_init.c.B9E838E2E779EB3F.idx differ diff --git a/pkin/.cache/clangd/index/pkin_repo_iter_next.c.1FA39567996AB993.idx b/pkin/.cache/clangd/index/pkin_repo_iter_next.c.1FA39567996AB993.idx new file mode 100644 index 0000000..642a44c Binary files /dev/null and b/pkin/.cache/clangd/index/pkin_repo_iter_next.c.1FA39567996AB993.idx differ diff --git a/pkin/.cache/clangd/index/pkin_repo_iter_read.c.3F15063555755D99.idx b/pkin/.cache/clangd/index/pkin_repo_iter_read.c.3F15063555755D99.idx new file mode 100644 index 0000000..1263dae Binary files /dev/null and b/pkin/.cache/clangd/index/pkin_repo_iter_read.c.3F15063555755D99.idx differ diff --git a/pkin/.cache/clangd/index/pkin_repo_iter_read.c.491CCB70672EBC34.idx b/pkin/.cache/clangd/index/pkin_repo_iter_read.c.491CCB70672EBC34.idx new file mode 100644 index 0000000..beedf57 Binary files /dev/null and b/pkin/.cache/clangd/index/pkin_repo_iter_read.c.491CCB70672EBC34.idx differ diff --git a/pkin/.cache/clangd/index/pkin_repo_iter_read.c.9FDBB2252A5F37B7.idx b/pkin/.cache/clangd/index/pkin_repo_iter_read.c.9FDBB2252A5F37B7.idx new file mode 100644 index 0000000..35fc604 Binary files /dev/null and b/pkin/.cache/clangd/index/pkin_repo_iter_read.c.9FDBB2252A5F37B7.idx differ diff --git a/pkin/.cache/clangd/index/pkin_repo_query_end.c.B4AE0E46BC59281A.idx b/pkin/.cache/clangd/index/pkin_repo_query_end.c.B4AE0E46BC59281A.idx new file mode 100644 index 0000000..ac5b8bc Binary files /dev/null and b/pkin/.cache/clangd/index/pkin_repo_query_end.c.B4AE0E46BC59281A.idx differ diff --git a/pkin/.cache/clangd/index/pkin_repo_query_next.c.9AE71B0E26964D21.idx b/pkin/.cache/clangd/index/pkin_repo_query_next.c.9AE71B0E26964D21.idx new file mode 100644 index 0000000..513a4cb Binary files /dev/null and b/pkin/.cache/clangd/index/pkin_repo_query_next.c.9AE71B0E26964D21.idx differ diff --git a/pkin/.cache/clangd/index/pkin_repo_query_start.c.FD7A5877F7EA8868.idx b/pkin/.cache/clangd/index/pkin_repo_query_start.c.FD7A5877F7EA8868.idx new file mode 100644 index 0000000..28f360f Binary files /dev/null and b/pkin/.cache/clangd/index/pkin_repo_query_start.c.FD7A5877F7EA8868.idx differ diff --git a/pkin/.cache/clangd/index/pkin_repo_simple.c.EAE9A2D3F20C471B.idx b/pkin/.cache/clangd/index/pkin_repo_simple.c.EAE9A2D3F20C471B.idx new file mode 100644 index 0000000..5dfcbe3 Binary files /dev/null and b/pkin/.cache/clangd/index/pkin_repo_simple.c.EAE9A2D3F20C471B.idx differ diff --git a/pkin/README b/pkin/README new file mode 100644 index 0000000..15f559f --- /dev/null +++ b/pkin/README @@ -0,0 +1,17 @@ +pkin is the binary package management frontend. +think of this as something like debian's apt or alpine's apk. + +source package templates specify compile-time dependencies, +i.e. packages that are required to be present in the build +environment, e.g. gcc and glibc to compile a c project. + +repositories +------------ + +goal: + - lazy pkg building + - lazy metadata + - + +deps: aria2 +makedeps: meson(or muon), ninja(or samu), a c compiler diff --git a/pkin/asset/example.a b/pkin/asset/example.a new file mode 100644 index 0000000..f74ba44 --- /dev/null +++ b/pkin/asset/example.a @@ -0,0 +1,2 @@ +lr 1.0 foo https://lab0x13.site/index.html +asd 1.0 asd http://kentoj/index.html diff --git a/pkin/asset/example.b b/pkin/asset/example.b new file mode 100644 index 0000000..95953bf --- /dev/null +++ b/pkin/asset/example.b @@ -0,0 +1,2 @@ +lsasdr 1.0 folo +lasd 1.0 asdl diff --git a/pkin/command.h b/pkin/command.h new file mode 100644 index 0000000..55d6623 --- /dev/null +++ b/pkin/command.h @@ -0,0 +1,8 @@ +#ifndef PKIN_SUBCOMMAND_H +#define PKIN_SUBCOMMAND_H + +void command_search(int argc, char **argv); + +void command_fetch(int argc, char **argv); + +#endif diff --git a/pkin/doc/pkin-repo.7.scd b/pkin/doc/pkin-repo.7.scd new file mode 100644 index 0000000..29d5c9d --- /dev/null +++ b/pkin/doc/pkin-repo.7.scd @@ -0,0 +1,22 @@ +pkin-repo(8) + +# DESCRIPTION + +Every repository really just consists of an indexfile. +The indexfile is used for querying/filtering available packages for e.g +pkin-search(8). + +The indexfile plain text file where each line presents a package's most +crucial metadata: name, version and description. +These fields are tab-separated. + +``` +foo 1.0 foo's description +foo 1.0 foo's description +``` + +# LIMITATIONS + +- it's hard to add fields to the indexfile with this format +- the format is not versioned. changing the format requires + changing the filename diff --git a/pkin/meson.build b/pkin/meson.build new file mode 100644 index 0000000..2b4245e --- /dev/null +++ b/pkin/meson.build @@ -0,0 +1,24 @@ +project( + 'pkin', 'c', + default_options: [ + 'c_std=c99', + 'warning_level=2', + ], +) + +cc = meson.get_compiler('c') +deps = [ + cc.find_library('libowfat'), +] + +executable('pkin', files( + './pkin.c', + './pkin-search.c', + './pkin-fetch.c', + './pkin/pkin_repo_iter_init.c', + './pkin/pkin_repo_iter_read.c', + './pkin/pkin_pkg_fetch_prepare.c', + './pkin/pkin_pkg_fetch_add.c', + './pkin/pkin_pkg_fetch_start.c', + './pkin_internal/pkin__spawn.c', +), dependencies:deps) diff --git a/pkin/pkin-fetch.c b/pkin/pkin-fetch.c new file mode 100644 index 0000000..da9cb94 --- /dev/null +++ b/pkin/pkin-fetch.c @@ -0,0 +1,54 @@ +#include +#include +#include + +#include "../pkin.h" +#include "command.h" + +#define dieusage() die(100, "usage: ", argv0, " PACKGE") + +static int find_package(char *name, pkin_pkgmeta *pkgmeta) +{ + pkin_repo_iter iter; + pkin_repo_iter_init(&iter); + + while (pkin_repo_iter_read(&iter, pkgmeta)) + if (str_equal(pkgmeta->name, name)) + return 1; + return 0; +} + +static void run(int argc, char **argv) +{ + int i; + pkin_pkgmeta pkgmeta; + pkin_fetch_queue queue; + if (!pkin_fetch_prepare(&queue)) + die(111, "failed to create package fetch queue"); + + for (i = 0; i < argc; i++) { + if (!find_package(argv[i], &pkgmeta)) + die(100, "package '", argv[i], "' not found "); + pkin_fetch_add(&queue, pkgmeta.url, pkgmeta.name); + } + + if (!pkin_fetch_start(&queue)) + die(111, "failed fetching packages"); +} + +void command_fetch(int argc, char **argv) +{ + int i; + errmsg_iam("pkin-fetch"); + for (i = 1; i < argc; i++) { + if (argv[i][0] != '-') break; + if (argv[i][1] == '-' && !argv[i][2]) break; + switch (argv[i][1]) { + default: dieusage(); + } + } + argc -= i; + argv += i; + + run(argc, argv); +} diff --git a/pkin/pkin-search.c b/pkin/pkin-search.c new file mode 100644 index 0000000..9cb1281 --- /dev/null +++ b/pkin/pkin-search.c @@ -0,0 +1,54 @@ +#include +#include +#include + +#include "../pkin.h" +#include "command.h" + +#define dieusage() die(100, "usage: ",argv0, " PATTERN...") + +static void print_meta(pkin_pkgmeta *pkgmeta) +{ + buffer_puts(buffer_1, pkgmeta->name); + buffer_puts(buffer_1, "-"); + buffer_puts(buffer_1, pkgmeta->version); + buffer_puts(buffer_1, ": "); + buffer_puts(buffer_1, pkgmeta->descr); + buffer_puts(buffer_1, "\n"); +} + +static void run(int argc, char **argv) +{ + pkin_repo_iter iter; + pkin_pkgmeta pkgmeta; + int i; + pkin_repo_iter_init(&iter); + while (pkin_repo_iter_read(&iter, &pkgmeta)) { + int matches = 1; + for (i = 0; i < argc; i++) { + if (!strstr(pkgmeta.name, argv[i]) && !strstr(pkgmeta.descr, argv[i])) + matches = 0; + } + if (matches) + print_meta(&pkgmeta); + } + if (buffer_flush(buffer_1) < 0) + carpsys("write to stdout"); +} + +void command_search(int argc, char **argv) +{ + int i; + errmsg_iam("pkin-search"); + for (i = 1; i < argc; i++) { + if (argv[i][0] != '-') break; + if (argv[i][1] == '-' && !argv[i][2]) break; + switch (argv[i][1]) { + default: dieusage(); + } + } + argc -= i; + argv += i; + + run(argc, argv); +} diff --git a/pkin/pkin.c b/pkin/pkin.c new file mode 100644 index 0000000..7fb92d9 --- /dev/null +++ b/pkin/pkin.c @@ -0,0 +1,90 @@ +#include +#include +#include +#include +#include + +#include "../pkin.h" +#include "command.h" + +#define dienoarg(OPT) \ + do { \ + carp("missing argument for -"OPT); \ + dieusage(); \ + } while(0) + +int pkin_verbose = 0; +array pkin_repos; + +static void add_repo(char *path, size_t pathlen) +{ + char **repo; + repo = array_allocate(&pkin_repos, sizeof(char *), array_length(&pkin_repos, sizeof(char *))); + if (!repo) diesys(111, "failed allocating repository entry"); + *repo = malloc(pathlen + 1); + if (!*repo) diesys(111, "failed allocating repository"); + byte_copy(*repo, pathlen, path); + (*repo)[pathlen] = 0; + + if (pkin_verbose) { + buffer_puts(buffer_2, "added repository "); + buffer_put(buffer_2, path, pathlen); + buffer_putsflush(buffer_2, "\n"); + } +} + +/* imports repositories defined by the PKIN_REPOS env var */ +static void env_import_repos(void) { + char *repos; + size_t l; + repos = getenv("PKIN_REPOS"); + if (!repos) { + carp("PKIN_REPOS not defined"); + return; + } + + for (;;) { + l = str_chr(repos, ':'); + add_repo(repos, l); + if (l == str_len(repos)) break; + repos += l + 1; + } +} + +static void dieusage() +{ + die(100, "usage: ",argv0, " [-r repository]... [-v] COMMAND\n" + " -v for verbose\n" + "Commands: search, fetch"); +} + +int main(int argc, char **argv) +{ + int i; + errmsg_iam(*argv); + for (i = 1; i < argc; i++) { + if (argv[i][0] != '-') break; + if (argv[i][1] == '-' && !argv[i][2]) break; + switch (argv[i][1]) { + case 'r': + if (!argv[++i]) dienoarg("r"); + add_repo(argv[i], str_len(argv[i])); + break; + case 'v': + pkin_verbose = 1; + break; + default: dieusage(); + } + } + argc -= i; + argv += i; + + if (argc == 0) dieusage(); + env_import_repos(); + + if (str_equal(*argv, "search")) + command_search(argc, argv); + else if (str_equal(*argv, "fetch")) + command_fetch(argc, argv); + else dieusage(); +} diff --git a/pkin/pkin.h b/pkin/pkin.h new file mode 100644 index 0000000..c29776b --- /dev/null +++ b/pkin/pkin.h @@ -0,0 +1,65 @@ +#ifndef PKIN_REPO_H +#define PKIN_REPO_H + +/* + * each repo is a directory with a repo-index json file. + */ + +#include +#include +#include +#include +#include + +#define PKIN_PKGMETA_NAME_MAX 128 +#define PKIN_PKGMETA_DESCR_MAX 256 +#define PKIN_PKGMETA_VERSION_MAX 256 +#define PKIN_PKGMETA_URL_MAX 2048 + +extern int pkin_verbose; +extern array pkin_repos; /* of char * */ + +typedef struct { + char name[PKIN_PKGMETA_NAME_MAX]; + char descr[PKIN_PKGMETA_DESCR_MAX]; + char version[PKIN_PKGMETA_VERSION_MAX]; + char url[PKIN_PKGMETA_URL_MAX]; /* url to download binary package from */ +} pkin_pkgmeta; + +typedef struct { + buffer b; + int fd; + char buf[4096]; + stralloc line; + size_t repos_i; + size_t repos_len; +} pkin_repo_iter; + +/* parlallel querying would be nice */ + +/* + * initialize a pkin_repo_query. + */ +void pkin_repo_iter_init(pkin_repo_iter *); + +/* + * gets the next pkgmeta. + * return: 1 if found, 0 if no next + */ +int pkin_repo_iter_read(pkin_repo_iter *, pkin_pkgmeta *res); + +typedef struct { + buffer writeb; + char writebuf[1024]; + int pipefd[2]; +} pkin_fetch_queue; + +int pkin_fetch_prepare(pkin_fetch_queue *queue); +void pkin_fetch_add(pkin_fetch_queue *queue, char *url, char *output); +/* + * downloads the binary package from url to the given + * directory and writes the resulting path to rest + */ +int pkin_fetch_start(pkin_fetch_queue *queue); + +#endif diff --git a/pkin/pkin/pkin_pkg_fetch.c b/pkin/pkin/pkin_pkg_fetch.c new file mode 100644 index 0000000..f5c3071 --- /dev/null +++ b/pkin/pkin/pkin_pkg_fetch.c @@ -0,0 +1,2 @@ + +int pkin_pkg_fetch(char *url, char *dir, stralloc *result); diff --git a/pkin/pkin/pkin_pkg_fetch_add.c b/pkin/pkin/pkin_pkg_fetch_add.c new file mode 100644 index 0000000..b92f3a3 --- /dev/null +++ b/pkin/pkin/pkin_pkg_fetch_add.c @@ -0,0 +1,8 @@ +#include "../pkin.h" + +void pkin_fetch_add(pkin_fetch_queue *queue, char *url, char *output) +{ + buffer_puts(&queue->writeb, url); + buffer_puts(&queue->writeb, "\n -o "); + buffer_puts(&queue->writeb, output); +} diff --git a/pkin/pkin/pkin_pkg_fetch_prepare.c b/pkin/pkin/pkin_pkg_fetch_prepare.c new file mode 100644 index 0000000..f28d836 --- /dev/null +++ b/pkin/pkin/pkin_pkg_fetch_prepare.c @@ -0,0 +1,15 @@ +#include +#include + +#include "../pkin.h" + +int pkin_fetch_prepare(pkin_fetch_queue *queue) +{ + if (pipe(queue->pipefd) < 0) { + carpsys("pipe"); + return 0; + } + buffer_init_write(&queue->writeb, queue->pipefd[1], + queue->writebuf, sizeof(queue->writebuf)); + return 1; +} diff --git a/pkin/pkin/pkin_pkg_fetch_start.c b/pkin/pkin/pkin_pkg_fetch_start.c new file mode 100644 index 0000000..8272b3d --- /dev/null +++ b/pkin/pkin/pkin_pkg_fetch_start.c @@ -0,0 +1,27 @@ +#include +#include +#include "../pkin.h" +#include "../pkin_internal.h" + +int pkin_fetch_start(pkin_fetch_queue *queue) +{ + char **fetchcmd; + pid_t pid; + if (buffer_flush(&queue->writeb) < 0) { + carpsys("write to pipe"); + return 0; + } + + fetchcmd = (char *[]){"aria2c", "-i", "-", NULL}; + pid = pkin__spawn(fetchcmd, queue->pipefd[0], 1, 2); + if (pid < 0) { + carp("failed spawning aria2c to fetch files"); + return 0; + } + + if (waitpid(pid, NULL, 0) < 0) { + carp("waitpid"); + return 0; + } + return 1; +} diff --git a/pkin/pkin/pkin_repo_iter_init.c b/pkin/pkin/pkin_repo_iter_init.c new file mode 100644 index 0000000..6b0a99c --- /dev/null +++ b/pkin/pkin/pkin_repo_iter_init.c @@ -0,0 +1,9 @@ +#include "../pkin.h" + +void pkin_repo_iter_init(pkin_repo_iter *iter) +{ + iter->fd = -1; + iter->repos_i = 0; + iter->repos_len = array_length(&pkin_repos, sizeof(char *)); + stralloc_init(&iter->line); +} diff --git a/pkin/pkin/pkin_repo_iter_read.c b/pkin/pkin/pkin_repo_iter_read.c new file mode 100644 index 0000000..322c153 --- /dev/null +++ b/pkin/pkin/pkin_repo_iter_read.c @@ -0,0 +1,106 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../pkin.h" + +static int parse_field(char *line, char *field, size_t fieldmax) +{ + size_t l; + l = str_chr(line, '\t'); + if (l == 0) return 0; + if (l >= fieldmax) { + carp("field ", field, " is too long "); + return 0; + } + byte_copy(field, l, line); + field[l] = 0; + return l; +} + +static int parse_pkgmeta(char *line, pkin_pkgmeta *res) +{ + size_t l; + + l = parse_field(line, res->name, PKIN_PKGMETA_NAME_MAX); + if (l == 0) goto skip; + line += l+1; + + l = parse_field(line, res->version, PKIN_PKGMETA_VERSION_MAX); + if (l == 0) goto skip; + line += l+1; + + l = parse_field(line, res->descr, PKIN_PKGMETA_DESCR_MAX); + if (l == 0) goto skip; + line += l+1; + + l = parse_field(line, res->url, PKIN_PKGMETA_URL_MAX); + if (l == 0) goto skip; + + return 1; +skip: + carp("skipping malformed pkgmeta: '", line, "'"); + return 0; +} + +static int repo_iter_read(char *repo, pkin_repo_iter *iter, pkin_pkgmeta *res) +{ + pkin_pkgmeta pkgmeta; + int r; + + if (iter->fd < 0) { + iter->fd = open_read(repo); + if (iter->fd < 0) { + carpsys("open_read repo indexfile ", repo); + return 0; + } + buffer_init_read(&iter->b, iter->fd, iter->buf, sizeof(iter->buf)); + } + + r = buffer_getnewline_sa(&iter->b, &iter->line); + if (r == 0) return 0; + if (r < 0) { + carpsys("failed to read ", repo); + goto notfound; + } + stralloc_chomp(&iter->line); + stralloc_0(&iter->line); + if (!parse_pkgmeta(iter->line.s, &pkgmeta)) { + carp("bad pkgmeta in ", repo, ": '", iter->line.s, "'"); + goto notfound; + } + *res = pkgmeta; + return 1; + +notfound: + buffer_close(&iter->b); + close(iter->fd); + iter->fd = -1; + return 0; +} + +int pkin_repo_iter_read(pkin_repo_iter *iter, pkin_pkgmeta *res) +{ + char **repo; + int found; + + for (; iter->repos_i < iter->repos_len; iter->repos_i++) { + repo = array_get(&pkin_repos, sizeof(char *), iter->repos_i); + found = repo_iter_read(*repo, iter, res); + if (found) + return 1; + } + + stralloc_free(&iter->line); + if (iter->fd >= 0) { + close(iter->fd); + buffer_close(&iter->b); + iter->fd = -1; + } + return 0; +} diff --git a/pkin/pkin_internal.h b/pkin/pkin_internal.h new file mode 100644 index 0000000..f5b6eb1 --- /dev/null +++ b/pkin/pkin_internal.h @@ -0,0 +1,8 @@ +#ifndef PKIN_INTERNAL +#define PKIN_INTERNAL + +#include + +pid_t pkin__spawn(char *args[], int infd, int outfd, int errfd); + +#endif diff --git a/pkin/pkin_internal/pkin__spawn.c b/pkin/pkin_internal/pkin__spawn.c new file mode 100644 index 0000000..1c44256 --- /dev/null +++ b/pkin/pkin_internal/pkin__spawn.c @@ -0,0 +1,43 @@ +#include +#include +#include +#include +#include + +static void carpsysargs(char *args[]) +{ + buffer_puts(buffer_2, "failed to exec"); + while (*args) { + buffer_puts(buffer_2, " \'"); + buffer_puts(buffer_2, *args); + buffer_puts(buffer_2, "'"); + args++; + } + buffer_puts(buffer_2, ": "); + buffer_puts(buffer_2, strerror(errno)); + buffer_puts(buffer_2, "\n"); + buffer_flush(buffer_2); +} + +pid_t pkin__spawn(char *args[], int infd, int outfd, int errfd) +{ + pid_t pid = fork(); + switch (pid) { + case -1: carpsys("fork: "); return -1; + case 0: + // TODO pipe + if (dup2(0, infd)<0 + || dup2(1, outfd)<0 + || dup2(2, errfd)<0 + ) { + carpsys("dup2"); + return -1; + } + execvp(args[0], args); + carpsysargs(args); + return -1; + default: + return pid; + } +} + diff --git a/strff.h b/strff.h new file mode 100644 index 0000000..d866878 --- /dev/null +++ b/strff.h @@ -0,0 +1,51 @@ +/* string file format */ +#ifndef STRFF_H +#define STRFF_H + +#include +#include + +enum strff_type { + STRFF_TYPE_NONE = 0, + STRFF_TYPE_BRACKET, + STRFF_TYPE_EQUAL +}; + +struct strff { + buffer b; + char buf[1024]; + int fd; + enum strff_type fieldtype; +}; + +void strff_open(struct strff *, int fd); +void strff_close(struct strff *); + +/* + * seeks for a field with the specified key in the file. + * sets cursor position ofc. + * strff_read can be used to get the value. + * key may not contain '['. + * if key not found, sets errno to ENOKEY + * return: 1 if found, 0 on error. + */ +int strff_seek(struct strff *, char *key); + +/* + * reads n bytes into buf. + * return: bytes read, 0 on end-of-field, -1 on error. + */ +int strff_read(struct strff *, size_t buflen, char buf[buflen]); + +/* + * same as strff_read but reads the whole value into sa + * return: 1 on success, 0 on error. + */ +int strff_read_sa(struct strff *, stralloc *sa); + +/* + * wrapper around strff_seek and strff_read_sa. + */ +int strff_get(struct strff *, char *key, stralloc *sa); + +#endif diff --git a/strff/strff_close.c b/strff/strff_close.c new file mode 100644 index 0000000..2150a05 --- /dev/null +++ b/strff/strff_close.c @@ -0,0 +1,6 @@ +#include "../strff.h" + +void strff_close(struct strff *strff) +{ + buffer_close(&strff->b); +} diff --git a/strff/strff_get.c b/strff/strff_get.c new file mode 100644 index 0000000..8eb17d5 --- /dev/null +++ b/strff/strff_get.c @@ -0,0 +1,8 @@ +#include "../strff.h" + +int strff_get(struct strff *strff, char *key, stralloc *sa) +{ + if (!strff_seek(strff, key)) + return 0; + return strff_read_sa(strff, sa); +} diff --git a/strff/strff_open.c b/strff/strff_open.c new file mode 100644 index 0000000..d5732a5 --- /dev/null +++ b/strff/strff_open.c @@ -0,0 +1,8 @@ +#include "../strff.h" +#include + +void strff_open(struct strff *strff, int fd) +{ + byte_zero(strff, sizeof *strff); + strff->fd = fd; +} diff --git a/strff/strff_read.c b/strff/strff_read.c new file mode 100644 index 0000000..354e717 --- /dev/null +++ b/strff/strff_read.c @@ -0,0 +1,44 @@ +#include "../strff.h" + +#include + +int strff_read(struct strff *strff, size_t buflen, char buf[buflen]) +{ + size_t nread; + int r; + char c; + int isnewline; + if (strff->fieldtype == STRFF_TYPE_NONE) { + errno = EINVAL; /* cannot read NONE field */ + return -1; + } + + isnewline = 1; + nread = 0; + while (nread < buflen) { + r = buffer_peekc(&strff->b, &c); + if (r < 0) return -1; + if (r == 0) { + if (isnewline && nread > 0) + nread--; /* remove last \n */ + break; + } + + if (strff->fieldtype == STRFF_TYPE_EQUAL && c == '\n') + break; + else if (strff->fieldtype == STRFF_TYPE_BRACKET) { + if (isnewline && c == '[') { + if (nread > 0) + nread--; /* remove last \n */ + break; + } + isnewline = 0; + if (c == '\n') + isnewline = 1; + } + + buf[nread++] = c; + strff->b.p++; + } + return nread; +} diff --git a/strff/strff_read_sa.c b/strff/strff_read_sa.c new file mode 100644 index 0000000..88f9f63 --- /dev/null +++ b/strff/strff_read_sa.c @@ -0,0 +1,15 @@ +#include "../strff.h" +#include + +int strff_read_sa(struct strff *strff, stralloc *sa) +{ + int n; + char buf[1024]; + for (;;) { + n = strff_read(strff, sizeof buf, buf); + if (n == 0) break; + if (n < 0) return 0; + if (!stralloc_catb(sa, buf, n)) return 0; + } + return 1; +} diff --git a/strff/strff_seek.c b/strff/strff_seek.c new file mode 100644 index 0000000..b3b8395 --- /dev/null +++ b/strff/strff_seek.c @@ -0,0 +1,124 @@ +#include "../strff.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +/* + keys can be defined either with key= or with [key]. + The first is the equalform, the second the bracketform. + There can be no keyforms after the bracketform. + */ + +static int skip_to_next_line(buffer *b) +{ + int r; + char c; + for (;;) { + r = buffer_getc(b, &c); + if (r == 0 || c == '\n') break; + if (r < 0) return 0; + } + return 1; +} + +/* + * advances the cursor until it is positioned at the value of a + * field. It will look for both the equalform and bracketform of + * the field, and returns STRFF_TYPE_BRACKET or STRFF_TYPE_EQUAL + * accordingly. If no such field is found, it returns STRFF_TYPE_NONE. + * On error, -1 is returned. + */ +static int seek_field(buffer *b, char *equalform, char *bracketform) +{ + size_t linemax, linelen; + char *line; + int r; + /* bracketform is longer */ + linemax = str_len(bracketform) + 1; + line = alloca(linemax); + linelen = 0; + + for (;;) { + r = buffer_getc(b, line + linelen); + if (r < 0) return -1; + if (r == 0) break; + linelen++; + + if (byte_starts(line, linelen, bracketform)) { + return STRFF_TYPE_BRACKET; + } + if (line[0] == '[') { + /* equalform cannot come after a bracketform */ + equalform = NULL; + } + if (equalform && byte_starts(line, linelen, equalform)){ + return STRFF_TYPE_EQUAL; + } + + if (line[linelen-1] == '\n') { + /* reset line */ + linelen = 0; + continue; + } + if (linelen == linemax) { + if (!skip_to_next_line(b)) + return -1; + linelen = 0; + } + } + + /* not found */ + return STRFF_TYPE_NONE; +} + +static int to_equalform(char *key, char *result) +{ + size_t l; + l = str_copy(result, key); + result[l++] = '='; + result[l++] = 0; + return 1; +} + +static int to_bracketform(char *key, char *result) +{ + size_t l; + l = 0; + result[l++] = '['; + l += str_copy(result + l, key); + result[l++] = ']'; + result[l++] = '\n'; + result[l++] = 0; + return 1; +} + +int strff_seek(struct strff *strff, char *key) { + char *equalform, *bracketform; + int fieldtype; + if (str_chr(key, '[') != str_len(key)) { + errno = EINVAL; /* key cannot contain '[' */ + return 0; + } + + equalform = alloca(str_len(key) + 2); + to_equalform(key, equalform); + bracketform = alloca(str_len(key) + 4); + to_bracketform(key, bracketform); + + buffer_init(&strff->b, read, strff->fd, strff->buf, sizeof strff->buf); + lseek(strff->fd, 0, SEEK_SET); + fieldtype = seek_field(&strff->b, equalform, bracketform); + if (fieldtype < 0) return 0; + strff->fieldtype = fieldtype; + if (fieldtype == STRFF_TYPE_NONE) { + errno = ENOKEY; + return 0; + } + return 1; +} diff --git a/strff_test.c b/strff_test.c new file mode 100644 index 0000000..d5160f2 --- /dev/null +++ b/strff_test.c @@ -0,0 +1,63 @@ +#include +#include +#include +#include "strff.h" + +typedef struct { + stralloc name; + stralloc version; + stralloc makedeps; + stralloc buildcmd; + stralloc installcmd; +} pkg; + +static struct strff cfgff; + +static void pkg_load(pkg *pkg, char *path) +{ + int fd; + fd = open_read(path); + if (fd < 0) + diesys(111, "open_read ", path); + + stralloc_init(&pkg->name); + stralloc_init(&pkg->version); + stralloc_init(&pkg->makedeps); + stralloc_init(&pkg->buildcmd); + stralloc_init(&pkg->installcmd); + strff_open(&cfgff, fd); + + if (!strff_get(&cfgff, "name", &pkg->name)) + diesys(111, "cannot get value for name"); + if (!strff_get(&cfgff, "version", &pkg->version)) + diesys(111, "cannot get value for version"); + if (!strff_get(&cfgff, "makedeps", &pkg->makedeps)) + diesys(111, "cannot get value for makedeps"); + if (!strff_get(&cfgff, "build", &pkg->buildcmd)) + diesys(111, "cannot get value for buildcmd"); + if (!strff_get(&cfgff, "install", &pkg->installcmd)) + diesys(111, "cannot get value for installcmd"); +} + +int main() +{ + pkg pkg; + pkg_load(&pkg, "./conf.strff"); + + buffer_puts(buffer_1, "name is '"); + buffer_put(buffer_1, pkg.name.s, pkg.name.len); + buffer_puts(buffer_1, "', "); + buffer_puts(buffer_1, "version is '"); + buffer_put(buffer_1, pkg.version.s, pkg.version.len); + buffer_puts(buffer_1, "', "); + buffer_puts(buffer_1, "makedeps is '"); + buffer_put(buffer_1, pkg.makedeps.s, pkg.makedeps.len); + buffer_puts(buffer_1, "', "); + buffer_puts(buffer_1, "buildcmd is '"); + buffer_put(buffer_1, pkg.buildcmd.s, pkg.buildcmd.len); + buffer_puts(buffer_1, "', "); + buffer_puts(buffer_1, "installcmd is '"); + buffer_put(buffer_1, pkg.installcmd.s, pkg.installcmd.len); + buffer_putsflush(buffer_1, "'\n"); + return 0; +}