From: Nathan Wagner Date: Fri, 26 Oct 2018 15:11:37 +0000 (+0000) Subject: combined runscript and setscript X-Git-Tag: v0.2.16~53 X-Git-Url: https://pd.if.org/git/?p=zpackage;a=commitdiff_plain;h=33ef8ea6e32e935fa8bf62b62710b216a1ce9b40 combined runscript and setscript --- diff --git a/Makefile b/Makefile index 0190c53..a294b38 100644 --- a/Makefile +++ b/Makefile @@ -28,12 +28,12 @@ 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-runscript zpm-soname zpm-syncfs zpm-packagehash zpm-verify \ + zpm-script zpm-soname zpm-syncfs zpm-packagehash zpm-verify \ zpm-elftype zpm-quote zpm-note SCRIPTS=zpm zpm-install zpm-merge zpm-list zpm-preserve zpm-test zpm-log \ zpm-contents zpm-uninstall zpm-pathmod zpm-rmpackage zpm-newpackage \ - zpm-pkg zpm-add zpm-setscript zpm-pkgfile zpm-gc + zpm-pkg zpm-add zpm-pkgfile zpm-gc COMPILED=$(ZPKGBIN) PROGRAMS=$(SCRIPTS) $(COMPILED) @@ -128,7 +128,7 @@ 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 +zpm-script: zpm-script.o libzpm.a $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< -lzpm -lelf zpm-packagehash: zpm-packagehash.o libzpm.a diff --git a/lib/script_hash.c b/lib/script_hash.c index 60c87ed..2185f77 100644 --- a/lib/script_hash.c +++ b/lib/script_hash.c @@ -7,6 +7,29 @@ #include "sqlite3.h" #include "zpm.h" +int zpm_script_set(struct zpm *zpm, char *pkgstr, char *phase, char *hash) { + char package[64]; + char version[32]; + int release; + char *insert = "insert into scripts (package,version,release,stage,hash) values (%Q,%Q,%d,%Q,%Q) on conflict (package,version,release,stage) do update set hash = excluded.hash "; + char *delete = "delete from scripts where package = ? and version = ? and release = ? and stage = ?"; + + if (!zpm || !zpm->db || !phase) { + return 0; + } + + if (zpm_parse_package(pkgstr, package, version, &release)) { + if (hash) { + zpm_db_run(zpm, insert, package, version, release, phase, hash); + } else { + zpm_db_run(zpm, delete, package, version, release, phase); + + } + } + + return !zpm->error; +} + 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 stage = %Q"; diff --git a/t/scripts.t b/t/scripts.t index 8328426..0f54445 100755 --- a/t/scripts.t +++ b/t/scripts.t @@ -4,7 +4,7 @@ . tap.sh -plan 16 +plan 13 PF=test.db pkgid=scriptrunner-1.0-1 @@ -16,22 +16,21 @@ cd tmp 2>/dev/null || bailout "can't cd to tmp" require zpm init $PF require zpm newpackage -f $PF $pkgid -tryrun zpm setscript -f $PF scriptrunner-1.0-1 configure /bin/true -tryrun zpm runscript -f $PF -p configure scriptrunner-1.0-1 -tryrun zpm setscript -f $PF scriptrunner-1.0-1 configure /bin/false -zpm runscript -f $PF -p configure scriptrunner-1.0-1 2>/dev/null +tryrun -v zpm script -f $PF -s -p configure scriptrunner-1.0-1 /bin/false +zpm script -f $PF -p configure -r scriptrunner-1.0-1 2>/dev/null failsok failure script fails -zpm runscript -f $PF -p nosuchphase -R scriptrunner-1.0-1 2>/dev/null +zpm script -f $PF -p nosuchphase -r -F scriptrunner-1.0-1 2>/dev/null failsok required non-existing script fails -tryrun zpm runscript -f $PF -p nosuchphase scriptrunner-1.0-1 2>/dev/null cat >script <<-'EOC' #!/bin/sh echo $1 EOC -tryrun zpm setscript -f $PF scriptrunner-1.0-1 configure script -first=$(zpm runscript -f $PF -p configure -o - scriptrunner-1.0-1) + +tryrun zpm script -f $PF -s -p configure scriptrunner-1.0-1 script + +first=$(zpm script -f $PF -p configure -r -o - scriptrunner-1.0-1) okexit first arg script okstreq "$first" "scriptrunner-1.0-1" "first arg value" @@ -39,14 +38,11 @@ cat >script <<-'EOC' #!/bin/sh echo $2 EOC -tryrun zpm setscript -f $PF scriptrunner-1.0-1 configure script -second=$(zpm runscript -f $PF -p configure -o - scriptrunner-1.0-1 secondarg) + +tryrun zpm script -s -f $PF scriptrunner-1.0-1 script +second=$(zpm script -f $PF -p configure -o - scriptrunner-1.0-1 secondarg) okexit second arg script okstreq "$second" "secondarg" "second arg value" cd .. rm -rf tmp - -finish - -rm -f $PF diff --git a/zpm-install b/zpm-install index 3589169..64b064b 100755 --- a/zpm-install +++ b/zpm-install @@ -164,7 +164,7 @@ for pkgstr in "$@"; do if [ $runscripts -gt 0 ]; then # TODO run pre-upgrade script if needed # zpm runscript -p pre-upgrade $current $pkgid - zpm runscript -f $pkgfile -p pre-install $pkgid $current + zpm script -f $pkgfile -p pre-install $pkgid $current if [ $? -ne 0 ]; then die "pre-install script for $pkgid failed" fi @@ -209,7 +209,7 @@ for pkgstr in "$@"; do fi if [ $runscripts -gt 0 ]; then - zpm runscript -f $pkgfile -p post-install $pkgid $current + zpm script -f $pkgfile -p post-install $pkgid $current fi if [ -n "$current" ]; then @@ -233,6 +233,8 @@ for pkgstr in "$@"; do # TODO skip configure if not on a terminal, regardless of settings # TODO will need force option if [ $runconfigure -gt 0 ]; then - zpm runscript -f $pkgfile -p configure $pkgid $current + zpm script -f $pkgfile -p configure $pkgid $current + else + true fi done diff --git a/zpm-runscript.c b/zpm-runscript.c deleted file mode 100644 index a3f4c2f..0000000 --- a/zpm-runscript.c +++ /dev/null @@ -1,222 +0,0 @@ -#define _POSIX_C_SOURCE 200809L - -#include -#include -#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 or "-", 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 && strcmp(output, "-") != 0) { - 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; - int required = 0; - - char hash[ZPM_HASH_STRLEN+1]; - char *args[4]; - char *pkgid; - - char *rootdir = 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 ? */ - - rootdir = getenv("ZPM_ROOT_DIR"); - - while ((opt = getopt(ac, av, "f:p:o:s:r:R")) != -1) { - switch (opt) { - case 'f': db = optarg; break; - case 'p': phase = optarg; break; - case 's': script = optarg; break; - case 'o': output = optarg; break; - case 'r': rootdir = optarg; break; - case 'R': required = 1; 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)) { - /* since the script file name doesn't really - * mean anything, pass in the phase as arg 0 - */ - - /* TODO sanitize environment ? */ - args[0] = phase; - args[1] = pkgid; - args[2] = 0; - args[3] = 0; - if (argn + 1 <= ac) { - args[2] = av[argn+1]; - } - - if (rootdir) { - if (chdir(rootdir) == -1) { - perror("can not chdir to rootdir"); - exit(EXIT_FAILURE); - } - if (geteuid() == 0) { - /* chroot is deprecated, and not in - * posix. need to use OS/kernel - * specific code. - */ - fprintf(stderr, "support for chroot equivalent not supported on this OS\n"); - } else { - fprintf(stderr, "unable to chroot as non root user\n"); - } - } else { - if (chdir("/") == -1) { - perror("can not chdir to /"); - exit(EXIT_FAILURE); - } - } - - if (!zpm_extract(&zpm, hash, script, 0700)) { - fprintf(stderr, "unable to extract script"); - exit(EXIT_FAILURE); - } - - 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 */ - if (script) { - unlink(script); - } - if (output) { - unlink(output); - } - if (rv) { - failures++; - } - } else { - if (required) { - 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; -} diff --git a/zpm-script.c b/zpm-script.c new file mode 100644 index 0000000..438cf50 --- /dev/null +++ b/zpm-script.c @@ -0,0 +1,328 @@ +#define _POSIX_C_SOURCE 200809L + +#include +#include +#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 setdir(char *rootdir) { + if (rootdir && strcmp(rootdir, "/")) { + if (chdir(rootdir) == -1) { + perror("can not chdir to rootdir"); + return 0; + } + if (geteuid() == 0) { + /* chroot is deprecated, and not in posix. need to use + * OS/kernel specific code. + */ + fprintf(stderr, "support for chroot equivalent not supported on this OS\n"); + } else { + fprintf(stderr, "unable to chroot as non root user\n"); + } + } else { + if (chdir("/") == -1) { + perror("can not chdir to /"); + return 0; + } + } + return 1; +} + + +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 or "-", 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 && strcmp(output, "-") != 0) { + 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; +} + +#define RUN 1 +#define SET 2 +#define LIST 3 + +#define SOFT 1 +#define HARD 2 + +int main(int ac, char **av){ + struct zpm zpm; + int rv; + int status; + int required = 0; + int fail = 0; + char *pkgstr; + int opt; + + char hash[ZPM_HASH_STRLEN+1]; + char *args[4]; + char *pkgid; + + char *rootdir = 0; + char *db = "/var/lib/zpm/zpm.db"; + char *script = "/var/tmp/zpm-script"; + char *output = "/var/tmp/zpm-script.out"; + char *phase = 0; + int quiet = 0; + int scriptishash = 0; + int mode = RUN; + int all = 0; + + if (getenv("ZPMDB")) { + db = getenv("ZPMDB"); + } + /* ZPM_PACKAGE_FILE ? */ + + rootdir = getenv("ZPM_ROOT_DIR"); + + /* run, set, show, hash */ + /* set -S, if -H set the hash, output hash, unless quiet + * show: -o, or stdout, + * All modes: [-f pkgfile] default to zpmdb + * All modes: [-p phase], default to configure + * All modes: [-R rootdir], chdir, attempt to chroot + * All modes: [-N], required, error if no such script + * + * run: zpm-script -r -p foo + * set: zpm-script -s + * set: zpm-script -s -h + * show: zpm-script -l [-a] [-o outfile] + * show hash: zpm-script -lh + */ + while ((opt = getopt(ac, av, "f:p:rslRFho:S:q")) != -1) { + switch (opt) { + case 'f': db = optarg; break; + case 'p': phase = optarg; break; + case 'r': mode = RUN; break; + case 's': mode = SET; break; + case 'l': mode = LIST; break; + case 'R': rootdir = optarg; break; + case 'F': required = 1; break; + case 'a': all = 1; break; + + case 'h': scriptishash = 1; break; + case 'o': output = optarg; break; + case 'S': script = optarg; break; + case 'q': quiet = 1; + + default: + usage(); + exit(EXIT_FAILURE); + break; + } + } + int argn = optind; + + if (argn >= ac) { + usage(); + exit(EXIT_FAILURE); + } + + 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); + } + + /* first non option arg is always a package id */ + pkgstr = av[argn]; + pkgid = zpm_findpkg(&zpm, pkgstr); + + if (!pkgid) { + fprintf(stderr, "no package for %s\n", pkgstr); + zpm_close(&zpm); + exit(EXIT_FAILURE); + } + + argn++; + + if (mode == SET) { + char *sethash = 0; + char *setscript = 0; + int rv = 0; + + if (!phase) { + phase = "configure"; + } + + if (argn < ac) { + if (scriptishash) { + sethash = av[argn]; + } else { + setscript = av[argn]; + } + } + + if (setscript) { + rv = zpm_import(&zpm,setscript,0,hash); + if (!rv) { + fprintf(stderr, "unable to import %s\n", + setscript); + fail = HARD; + } else { + sethash = hash; + } + } + + if (!fail && !zpm_script_set(&zpm,pkgid,phase,sethash)) { + fprintf(stderr, "unable to set %s script hash %s\n", + pkgid, + sethash ? sethash : "null"); + fprintf(stderr, "zpm error: %s\n", zpm.errmsg); + fail = HARD; + } + } else if (mode == LIST) { + if (!zpm_script_hash(&zpm, pkgid, phase, hash)) { + fail = SOFT; + } else if (scriptishash) { + printf("%s\n", hash); + } else { + if (!output) { + output = "-"; + } + if (!zpm_extract(&zpm, hash, output, 0700)) { + fail = HARD; + } + } + } else { + /* run a script */ + if (!phase) { + phase = "configure"; + } + + if (!output) { + output = "/var/tmp/zpm-script.out"; + } + + if (!script) { + script = "/var/tmp/zpm-script"; + } + + /* since the script file name doesn't really + * mean anything, pass in the phase as arg 0 + */ + /* TODO sanitize environment ? */ + args[0] = phase; + args[1] = pkgid; + args[2] = 0; + args[3] = 0; + + if (argn <= ac) { + args[2] = av[argn]; + } + + if (!zpm_script_hash(&zpm, pkgid, phase, hash)) { + fail = SOFT; + goto cleanup; + } + + if (!setdir(rootdir)) { + fail = HARD; + goto cleanup; + } + + if (!zpm_extract(&zpm, hash, script, 0700)) { + fprintf(stderr, "unable to extract script"); + fail = HARD; + goto cleanup; + } + + rv = run(script, args, output, &status); + if (rv) { + fprintf(stderr, "package %s script failed with code %d\n", + pkgid, rv); + fail = HARD; + } + + /* TODO log output */ + if (script) { + unlink(script); + } + if (output) { + unlink(output); + } + } + +cleanup: + free(pkgid); + zpm_close(&zpm); + + return (fail == HARD || (required && fail)) ? EXIT_FAILURE : 0; + +} diff --git a/zpm-setscript b/zpm-setscript deleted file mode 100755 index 0036e66..0000000 --- a/zpm-setscript +++ /dev/null @@ -1,158 +0,0 @@ -#!/bin/sh - -# zpm add -f pkgfile pkgid [ files ] - -# no package file? take from ZPM_PACKAGE_FILE -# no pkgid ? take from ZPM_PACKAGE_ID -# no id impossible - -die() { - echo $* 1>&2 - exit 1 -} - -while getopts :f: opt; do - case $opt in - f) pkgfile="$OPTARG" ;; - *) echo 'zpm-setscript unknown option' $opt; exit 1 ;; - esac -done -shift $((OPTIND - 1)) - -pkgid=$1 -shift - -if [ -z "$pkgid" ]; then - die "must specify pkgid" -fi - -eval "$(zpm parse -E $pkgid)" - -if [ -z "$pkgfile" ]; then - pkgfile=$ZPM_PACKAGE_FILE -fi - -# cases R = full package id, F = specified package file - -# immediate error -# --- 000 error, must specify something -if [ -z "$release" ] && [ -z "$pkgfile" ]; then - die must specify package file or complete package id -fi - -# try to get from package file -if [ -z "$release" ]; then - pkgid=$(zpm findpkg -f $pkgfile $pkgid) - if [ -z "$pkgid" ]; then - die cannot find package id - fi - eval "$(zpm parse -E $pkgid)" -fi - -# --F 001 error, wouldn't know which pkgid to create, could derive from file? -if [ -z "$release" ]; then - die must specify complete package id -fi - -#echo "have '$pkgid' '$pkgfile'" - -# set file from pkgid -# -R- 010 set file from pkgid, create in file, error if no file -if [ -z "$pkgfile" ]; then - pkgfile="$pkgid.zpm" -fi - -# will now be one of these -# -RF 011 create package in file, error if file doesn't exist -if [ ! -f "$pkgfile" ]; then - die $pkgfile does not exist -fi - -set -e - -if [ "$idempotent" = 1 ]; then - idempotent='or ignore' -fi - -package=$(zpm quote "$name") -pkgver=$(zpm quote "$version") -pkgrel=$(zpm quote "$release") - -# args are stage and script - -addscript() ( - stage=$1 - path=$2 - - #echo adding $path - if [ ! -f "$script" ]; then - die "$script is not a regular file" - fi - hash=$(zpm addfile $pkgfile "$path") - if [ $? -ne 0 ]; then - die "zpm addfile failed ($?): $pkgfile $path" - fi - #echo adding script $hash $path - hash=$(zpm quote "$hash") - - stage=$(zpm quote "$stage") - - #cat < $target"} -#printf "%s\n" $path -) - -removescript() ( - stage=$1 - stage=$(zpm quote "$stage") - - #cat < $target"} -#printf "%s\n" $path -) - -showscript() ( - stage=$1 - stage=$(zpm quote "$stage") - hash=$(zpm shell $pkgfile "select hash from scripts_pkgid - where pkgid = '$pkgid' and stage = '$stage'") - if [ -z "$hash" ]; then - die "no script for $stage $pkgid" - fi - zpm extract $pkgfile "$hash" - -) - -# TODO better syntax for showing the script -# TODO a way to set the script hash directly -while [ $# -gt 1 ]; do - stage=$1 - script=$2 - shift 2 - - if [ "$script" = '--' ]; then - removescript "$stage" - elif [ "$script" = '-' ]; then - showscript "$stage" - else - addscript "$stage" "$script" - fi - -done diff --git a/zpm.h b/zpm.h index 05b8fe9..f9e7b33 100644 --- a/zpm.h +++ b/zpm.h @@ -175,8 +175,9 @@ int zpm_foreach_path(struct zpm *zpm, char *pkgid, char *where, int (*callback)(void *f, int ncols, char **vals, char **cols), void *data, char **errmsg); - int zpm_script_hash(struct zpm *zpm, char *pkgstr, char *phase, char *hash); +int zpm_script_set(struct zpm *zpm, char *pkgstr, char *phase, char *hash); + int zpm_package_hash(struct zpm *zpm, char *pkgid, char *hash); int zpm_package_sethash(struct zpm *zpm, char *pkgid, char *hash);