]> 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
 [
-.B -Fhq
+.B -Fhql
 ]
 [
 .BI -f " pkgfile"
@@ -22,6 +22,9 @@ zpm-script \- run, set, or list package scripts
 .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
@@ -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.
-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
@@ -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.
+.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
+.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
+.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
@@ -68,6 +102,18 @@ than a path to a script.
 .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
@@ -77,6 +123,9 @@ file.
 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
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 status;
+       int status = 0;
        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 *script = "/var/tmp/zpm-script";
-       char *output = "/var/tmp/zpm-script.out";
+       char *script = 0;
+       char *output = 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")) {
@@ -151,16 +152,8 @@ int main(int ac, char **av){
        /* 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
@@ -176,7 +169,7 @@ int main(int ac, char **av){
         * 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;
@@ -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 '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 'v': verbose = 1; break;
 
                        default:
                                  usage();
@@ -305,33 +302,79 @@ int main(int ac, char **av){
 
                if (!zpm_script_hash(&zpm, pkgid, phase, hash)) {
                        fail = SOFT;
+                       status = EXIT_FAILURE;
                        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;
+                       status = EXIT_FAILURE;
                        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;
                }
 
-               /* 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);
                }
@@ -344,5 +387,5 @@ cleanup:
        free(pkgid);
        zpm_close(&zpm);
 
-       return (fail == HARD || (required && fail)) ? EXIT_FAILURE : 0;
+       return (fail == HARD || (required && fail)) ? status : 0;
 }