From 0187a28d81a65b5b92c6c2dbaacce07d6277ba33 Mon Sep 17 00:00:00 2001 From: Nathan Wagner Date: Mon, 17 Sep 2018 11:34:29 +0000 Subject: [PATCH] use stage instead of phase in script_hash add zpm-runscript to makefile improve error handling in script_hash. --- Makefile | 6 +- lib/dbquery.c | 1 - lib/findpkg.c | 9 ++- lib/script_hash.c | 8 +- zpm-runscript.c | 185 ++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 205 insertions(+), 4 deletions(-) create mode 100644 zpm-runscript.c diff --git a/Makefile b/Makefile index 32a48ee..c876ce1 100644 --- a/Makefile +++ b/Makefile @@ -24,7 +24,8 @@ LIBZPMOBJ=$(addprefix lib/, $(LIBZPMSRC:%.c=%.o)) curdir=$(shell pwd) ZPKGBIN=zpm-addfile zpm-extract zpm-init zpm-vercmp zpm-stat zpm-hash \ - zpm-findpkg zpm-shell zpm-soneed zpm-foreach-path zpm-parse + zpm-findpkg zpm-shell zpm-soneed zpm-foreach-path zpm-parse \ + zpm-runscript SCRIPTS=zpm zpm-install zpm-merge zpm-list zpm-preserve zpm-test zpm-log \ zpm-contents @@ -116,6 +117,9 @@ zpm-init: zpm-init.o libzpm.a zpm-extract: zpm-extract.o libzpm.a $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< -lzpm -lelf + +zpm-runscript: zpm-runscript.o libzpm.a + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< -lzpm -lelf zpm-foreach-path.o: CFLAGS+=-Wno-unused diff --git a/lib/dbquery.c b/lib/dbquery.c index 479070c..d6ef8b5 100644 --- a/lib/dbquery.c +++ b/lib/dbquery.c @@ -28,7 +28,6 @@ sqlite3_stmt *zpm_dbquery(struct zpm *zpm, char *query, ...) { return 0; } - fprintf(stderr, "preparing query: %s\n", sql); rv = sqlite3_prepare_v2(db, sql, strlen(sql), &st, NULL); if (rv != SQLITE_OK) { SQLERROR(sqlite3_errmsg(db)); diff --git a/lib/findpkg.c b/lib/findpkg.c index 6f69876..900b6cb 100644 --- a/lib/findpkg.c +++ b/lib/findpkg.c @@ -9,6 +9,8 @@ #include "sqlite3.h" +#define DMARK fprintf(stderr, "mark %s %s:%d\n", __FILE__, __func__, __LINE__) + int zpm_parse_package(char *pstr, char *name, char *ver, int *rel) { if (name) *name = 0; if (ver) *ver = 0; @@ -106,11 +108,16 @@ char *zpm_findpkg(struct zpm *zpm, char *pkgstr) { // char *order = "order by package, version collate vercmp, cast(release as integer)"; sqlite3_str *sql; sqlite3_stmt *stmt; - char *query, *pkgid; + char *query, *pkgid = 0; char package[32]; char version[32]; int release; + if (pkgstr == NULL) { + fprintf(stderr, "trying to parse null string\n"); + return NULL; + } + /* null pkgstr find "best" package * best is shortest complete package if any are complete * shortest incomplete if any are incomplete diff --git a/lib/script_hash.c b/lib/script_hash.c index c559e87..60c87ed 100644 --- a/lib/script_hash.c +++ b/lib/script_hash.c @@ -1,3 +1,5 @@ +#define _POSIX_C_SOURCE 200809L + #include #include #include @@ -7,15 +9,18 @@ int zpm_script_hash(struct zpm *zpm, char *pkgstr, char *phase, char *hash) { char *pkgid = 0; - char *template = "select hash from scripts_pkgid where pkgid = %Q and phase = %Q"; + char *template = "select hash from scripts_pkgid where pkgid = %Q and stage = %Q"; sqlite3_stmt *st; pkgid = zpm_findpkg(zpm, pkgstr); st = zpm_dbquery(zpm, template, pkgid, phase); + free(pkgid); if (!st) { + zpm->error = 1; + zpm->errmsg = strdup(sqlite3_errmsg(zpm->db)); return 0; } @@ -26,6 +31,7 @@ int zpm_script_hash(struct zpm *zpm, char *pkgstr, char *phase, char *hash) { hash[ZPM_HASH_STRLEN] = 0; break; default: zpm->error = 1; /* fall through */ + zpm->errmsg = strdup(sqlite3_errmsg(zpm->db)); case SQLITE_DONE: sqlite3_finalize(st); return 0; break; /* not found */ diff --git a/zpm-runscript.c b/zpm-runscript.c new file mode 100644 index 0000000..e6b1af5 --- /dev/null +++ b/zpm-runscript.c @@ -0,0 +1,185 @@ +#define _POSIX_C_SOURCE 200809L + +#include +#include +#include +#include +#include +#include +#include +#include + + +#include + +#include "zpm.h" + +/* + * -f package file, otherwise localdb + * -p phase, defaults to 'configure' + * -s script name, defaults to /var/tmp/zpm-script + * -r chroot to directory + * -o script output, /var/tmp/zpm-script.out, '-' for stdout + * + * arg is package id + */ + +void usage(void) { + fprintf(stderr, "usage: db hash file\n"); +} + +int run(char *program, char **args, char *output, int *status) { + /* if stdout is a terminal, leave stdout where it goes, + * if it's not a terminal, redirect stdout to output. + * in either case, send stderr to output, unless null + * if output is null, just run the program + */ + int interactive = 0; + pid_t pid; + int rv; + + errno = 0; + + interactive = isatty(1); + + pid = fork(); + + if (pid == -1) { + *status = 1; + return -1; + } + + if (pid == 0) { + /* child */ + if (output) { + close(2); + rv = open(output, O_NOFOLLOW|O_TRUNC|O_CREAT|O_WRONLY, + 0600); + if (rv == -1) { + perror("cannot open output file"); + } + if (!interactive) { + rv = dup2(2,1); + if (rv == -1) { + perror("unable to redirect stdout"); + exit(EXIT_FAILURE); + } + } + } + + rv = execvp(program, args); + if (rv == -1) { + perror("cannot exec"); + exit(EXIT_FAILURE); + } + } + + pid = wait(status); + if (pid == -1) { + perror("error waiting for child"); + return -2; + } + + if (WIFEXITED(*status)) { + return WEXITSTATUS(*status); + } + + return -3; +} + +int main(int ac, char **av){ + struct zpm zpm; + int rv; + int status; + int failures = 0; + char *pkgstr; + int opt; + + char hash[ZPM_HASH_STRLEN+1]; + char *args[3]; + char *pkgid; + + char *chroot = 0; + char *db = "/var/lib/zpm/zpm.db"; + char *script = "/var/tmp/zpm-script"; + char *output = "/var/tmp/zpm-script.out"; + char *phase = "configure"; + + if (getenv("ZPMDB")) { + db = getenv("ZPMDB"); + } + /* ZPM_PACKAGE_FILE ? */ + + while ((opt = getopt(ac, av, "f:p:s:r:")) != -1) { + switch (opt) { + case 'f': db = optarg; + break; + case 'p': phase = optarg; + break; + case 's': script = optarg; + break; + case 'r': chroot = optarg; + break; + default: + usage(); + exit(EXIT_FAILURE); + break; + } + } + int argn = optind; + + if (argn >= ac) { + usage(); + exit(EXIT_FAILURE); + } + + pkgstr = av[argn]; + + if (!zpm_open(&zpm, db)) { + fprintf(stderr, "unable to open zpm database: %s\n", db); + if (zpm.errmsg) { + fprintf(stderr, "error detail: %s\n", zpm.errmsg); + } + exit(EXIT_FAILURE); + } + + pkgid = zpm_findpkg(&zpm, pkgstr); + if (pkgid) { + if (zpm_script_hash(&zpm, pkgid, phase, hash)) { + rv = zpm_extract(&zpm, hash, script, 0700); + + /* perhaps also pass in the phase name? or ENV? */ + /* TODO sanitize environment ? */ + args[0] = script; + args[1] = pkgid; + args[2] = 0; + if (chroot) { + fprintf(stderr, "failing to chroot %s\n", chroot); + } + rv = run(script, args, output, &status); + if (rv) { + // cat(output); + fprintf(stderr, "package %s script failed with code %d\n", + pkgid, rv); + } + /* TODO log output */ + unlink(script); + unlink(output); + if (rv) { + failures++; + } + } else { + fprintf(stderr, "no script for %s %s\n", phase, pkgid); + failures++; + } + free(pkgid); + } else { + fprintf(stderr, "unable to find package for %s in %s\n", + pkgstr, db); + failures++; + } + + zpm_close(&zpm); + + return failures ? EXIT_FAILURE : EXIT_SUCCESS; +} -- 2.40.0