]> pd.if.org Git - zpackage/commitdiff
expand script functionality
authorNathan Wagner <nw@hydaspes.if.org>
Thu, 7 Mar 2019 20:03:25 +0000 (20:03 +0000)
committerNathan Wagner <nw@hydaspes.if.org>
Thu, 7 Mar 2019 20:03:25 +0000 (20:03 +0000)
doc/zpm-script.8
src/script.c

index bf5bbb77090696d5a4208dc8ab9e58ecc2b6bf97..97d1a9a61dae48a7b4beebb243998046a078e74c 100644 (file)
@@ -1,10 +1,10 @@
-.TH zpm-script 8 2019-02-15 "ZPM 0.3"
+.TH zpm-script 8 2019-03-06 "ZPM 0.7.0"
 .SH NAME
 zpm-script \- run, set, or list package scripts
 .SH SYNOPSIS
 .B zpm script
 [
 .SH NAME
 zpm-script \- run, set, or list package scripts
 .SH SYNOPSIS
 .B zpm script
 [
-.B -Fhq
+.B -Fhql
 ]
 [
 .BI -f " pkgfile"
 ]
 [
 .BI -f " pkgfile"
@@ -22,6 +22,9 @@ zpm-script \- run, set, or list package scripts
 .BI -S " script"
 ]
 .I package
 .BI -S " script"
 ]
 .I package
+[
+.I arg
+]
 .SH DESCRIPTION
 \fBzpm-script\fR
 runs, sets, or lists package scripts for a package.  The package is a package
 .SH DESCRIPTION
 \fBzpm-script\fR
 runs, sets, or lists package scripts for a package.  The package is a package
@@ -38,8 +41,11 @@ to /var/tmp/zpm-script.out, or as specified by the -o option.
 The script itself will be extracted to /var/tmp/zpm-script, set as executable,
 and then run.  The script is run with one or two arguments.  The
 first argument is the package id being installed, removed, or configured.
 The script itself will be extracted to /var/tmp/zpm-script, set as executable,
 and then run.  The script is run with one or two arguments.  The
 first argument is the package id being installed, removed, or configured.
-For a package version update (or downgrade) the second argument is
-the previous version of the package.
+If given \fIarg\fR is passed to the script as a second argument.
+For a package version update (or downgrade) this is the previous version of the
+package.
+.PP If the script fails (i.e. any non-zero exit status), the output will
+be imported into the database and a note will be added.
 .TP
 An example script
 .EX
 .TP
 An example script
 .EX
@@ -53,12 +59,40 @@ Set mode will set the script for a given package and phase to the
 path given as an additional argument.  If the -h is given, the script
 is interpreted as a hash to be set directly, and nothing is taken
 from the filesystem.
 path given as an additional argument.  If the -h is given, the script
 is interpreted as a hash to be set directly, and nothing is taken
 from the filesystem.
+.SS List Mode
+If a phase is given with \-p the script will be printed to stdout (or
+wherever \-o specifies).  If no phase is given, a list of scripts for
+the package will be printed to stdout.
 .SH OPTIONS
 .TP
 .SH OPTIONS
 .TP
+.B \-l
+Run in list mode.
+.TP
+.B \-r
+Run in run mode.  This is the default.
+.TP
+.B \-s
+Run in set mode.
+.TP
 .BI \-p phase
 Specify the script phase.  This defaults to all phases for list mode,
 and configure for running or setting scripts.
 .TP
 .BI \-p phase
 Specify the script phase.  This defaults to all phases for list mode,
 and configure for running or setting scripts.
 .TP
+.B \-n
+Do not create notes.  Overrides other note options.
+.TP
+.B \-N
+Create notes only if the database is writable, otherwise send
+output to stdout.
+.TP
+.B \-a
+Make a note for all output, regardless of the exit status.
+.TP
+.B \-e
+Allow empty notes to be created for the \-a option.
+Normally if the output is empty and the script succeeded, the \-a option
+will not cause a note to be created.
+.TP
 .B \-f
 specify the package file to find packages in
 .TP
 .B \-f
 specify the package file to find packages in
 .TP
@@ -68,6 +102,18 @@ than a path to a script.
 .TP
 .B \-q
 Run quietly.
 .TP
 .B \-q
 Run quietly.
+.TP
+.B \-v
+Send any output to stdout.
+.TP
+.BI \-R " rootdir"
+The current directory will be changed to \fIrootdir\fR before
+running the script.  Defaults to '/'.  No chroot is done
+before running the script, so scripts should be aware of this
+and generally use relative paths.  If neccessary and possible
+the script itself can chroot.  Calling chroot(2) requires superuser
+privileges, so it would be impossible to run the scripts as a non
+root user if chroot was attempted.
 .SH EXAMPLES
 .TP
 zpm script -f foo-1.0-1.zpm foo
 .SH EXAMPLES
 .TP
 zpm script -f foo-1.0-1.zpm foo
@@ -77,6 +123,9 @@ file.
 zpm script foo
 Run the configure script for the (most recent) foo package found
 in the local database.
 zpm script foo
 Run the configure script for the (most recent) foo package found
 in the local database.
+.TP
+zpm script -l foo
+List all scripts for the foo package.
 .SH EXIT STATUS
 0 on success non zero on failure
 .SH FILES
 .SH EXIT STATUS
 0 on success non zero on failure
 .SH FILES
index 7c03b241792ae1f91ea504215b1400526580c71b..f0b173fc2a5d72b1c0626a7563d30162e184ff24 100644 (file)
@@ -125,7 +125,7 @@ static int list_scripts(void *ud, const char *pkg, const char *stage,
 int main(int ac, char **av){
        struct zpm zpm;
        int rv;
 int main(int ac, char **av){
        struct zpm zpm;
        int rv;
-       int status;
+       int status = 0;
        int required = 0;
        int fail = 0;
        char *pkgstr;
        int required = 0;
        int fail = 0;
        char *pkgstr;
@@ -137,12 +137,13 @@ int main(int ac, char **av){
 
        char *rootdir = 0;
        char *db = "/var/lib/zpm/local.db";
 
        char *rootdir = 0;
        char *db = "/var/lib/zpm/local.db";
-       char *script = "/var/tmp/zpm-script";
-       char *output = "/var/tmp/zpm-script.out";
+       char *script = 0;
+       char *output = 0;
        char *phase = 0;
        char *phase = 0;
-       char *envvar = 0;
-       int quiet = 0;
-       int scriptishash = 0;
+       int quiet = 0, verbose = 0;
+       int allowempty = 0, notealways = 0, makenote = 0, showoutput = 0;
+       int scriptishash = 0, notenever = 0, noteifwritable = 0;
+       size_t outsize;
        int mode = RUN;
 
        if (getenv("ZPMDB")) {
        int mode = RUN;
 
        if (getenv("ZPMDB")) {
@@ -151,16 +152,8 @@ int main(int ac, char **av){
        /* ZPM_PACKAGE_FILE ? */
 
        rootdir = getenv("ZPM_ROOT_DIR");
        /* ZPM_PACKAGE_FILE ? */
 
        rootdir = getenv("ZPM_ROOT_DIR");
-
-       envvar = getenv("ZPM_SCRIPT_FILE");
-       if (envvar) {
-               script = envvar;
-       }
-
-       envvar = getenv("ZPM_SCRIPT_OUTPUT");
-       if (envvar) {
-               output = envvar;
-       }
+       script = getenv("ZPM_SCRIPT_FILE");
+       output = getenv("ZPM_SCRIPT_OUTPUT");
 
        /* run, set, show, hash */
        /* set -S, if -H set the hash, output hash, unless quiet
 
        /* run, set, show, hash */
        /* set -S, if -H set the hash, output hash, unless quiet
@@ -176,7 +169,7 @@ int main(int ac, char **av){
         * show: zpm-script -l [-a] [-o outfile] <pkgid>
         * show hash: zpm-script -lh <pkgid>
         */
         * show: zpm-script -l [-a] [-o outfile] <pkgid>
         * show hash: zpm-script -lh <pkgid>
         */
-       while ((opt = getopt(ac, av, "f:p:rslRFho:S:q")) != -1) {
+       while ((opt = getopt(ac, av, "f:p:rslRFho:S:qv")) != -1) {
                switch (opt) {
                        case 'f': db = optarg; break;
                        case 'p': phase = optarg; break;
                switch (opt) {
                        case 'f': db = optarg; break;
                        case 'p': phase = optarg; break;
@@ -185,11 +178,15 @@ int main(int ac, char **av){
                        case 'l': mode = LIST; break;
                        case 'R': rootdir = optarg; break;
                        case 'F': required = 1; break;
                        case 'l': mode = LIST; break;
                        case 'R': rootdir = optarg; break;
                        case 'F': required = 1; break;
-
+                       case 'a': notealways = 1; break;
+                       case 'n': notenever = 1; break;
+                       case 'N': noteifwritable = 1; break;
+                       case 'e': allowempty = 1; break;
                        case 'h': scriptishash = 1; break;
                        case 'o': output = optarg; break;
                        case 'S': script = optarg; break;
                        case 'q': quiet = 1; break;
                        case 'h': scriptishash = 1; break;
                        case 'o': output = optarg; break;
                        case 'S': script = optarg; break;
                        case 'q': quiet = 1; break;
+                       case 'v': verbose = 1; break;
 
                        default:
                                  usage();
 
                        default:
                                  usage();
@@ -305,33 +302,79 @@ int main(int ac, char **av){
 
                if (!zpm_script_hash(&zpm, pkgid, phase, hash)) {
                        fail = SOFT;
 
                if (!zpm_script_hash(&zpm, pkgid, phase, hash)) {
                        fail = SOFT;
+                       status = EXIT_FAILURE;
                        goto cleanup;
                }
 
                if (!setdir(rootdir)) {
                        fail = HARD;
                        goto cleanup;
                }
 
                if (!setdir(rootdir)) {
                        fail = HARD;
+                       status = EXIT_FAILURE;
                        goto cleanup;
                }
 
                if (!zpm_extract(&zpm, hash, script, 0700)) {
                        fprintf(stderr, "unable to extract script");
                        fail = HARD;
                        goto cleanup;
                }
 
                if (!zpm_extract(&zpm, hash, script, 0700)) {
                        fprintf(stderr, "unable to extract script");
                        fail = HARD;
+                       status = EXIT_FAILURE;
                        zpm_note_add(&zpm, pkgid, NULL, hash, "unable to extract %s script", phase);
                        goto cleanup;
                }
 
                rv = run(script, args, output, &status);
                        zpm_note_add(&zpm, pkgid, NULL, hash, "unable to extract %s script", phase);
                        goto cleanup;
                }
 
                rv = run(script, args, output, &status);
-               if (rv) {
-                       fprintf(stderr, "package %s script failed with code %d\n",
-                                       pkgid, rv);
-                       
-                       zpm_import(&zpm, output, 0, hash);
-                       zpm_note_add(&zpm, pkgid, NULL, hash, "package %s script failed with code %d", phase, rv);
 
 
+               status = WEXITSTATUS(status);
+               if (status != 0) {
                        fail = HARD;
                }
 
                        fail = HARD;
                }
 
-               /* TODO log output */
+               if (zpm_readonly(&zpm) && noteifwritable) {
+                       notenever = 1;
+               }
+
+               if (output && !notenever) {
+                       struct stat outstat;
+                       stat(output, &outstat);
+                       outsize = outstat.st_size;
+                       if (notealways || (outsize && status && (outsize || allowempty))) {
+                               makenote = 1;
+                       }
+               }
+               
+               if (makenote) {
+                       char note[1024];
+
+                       zpm_import(&zpm, output, 0, hash);
+
+                       if (status) {
+                               sprintf(note, "%.64s script failed with code %d",
+                                               phase, status);
+
+                               fail = HARD;
+                       } else {
+                               sprintf(note, "%.64s script succeeded", phase);
+                       }
+                       zpm_note_add(&zpm, pkgid, NULL, hash, note);
+               }
+
+               if (output && showoutput) {
+                       char buf[4096];
+                       int out = open(output, O_RDONLY);
+                       ssize_t bytes;
+                       if (out == -1) {
+                               perror("can't open output file");
+                       } else {
+                               while ((bytes = read(out, buf, sizeof buf)) > 0) {
+                                       write(1, buf, bytes);
+                               }
+                               if (bytes == -1) {
+                                       perror("output file read error");
+                               }
+                       }
+                       if (out != -1) {
+                               close(out);
+                       }
+               }
+
                if (script) {
                        unlink(script);
                }
                if (script) {
                        unlink(script);
                }
@@ -344,5 +387,5 @@ cleanup:
        free(pkgid);
        zpm_close(&zpm);
 
        free(pkgid);
        zpm_close(&zpm);
 
-       return (fail == HARD || (required && fail)) ? EXIT_FAILURE : 0;
+       return (fail == HARD || (required && fail)) ? status : 0;
 }
 }