-.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"
.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
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
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
.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
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
int main(int ac, char **av){
struct zpm zpm;
int rv;
- int status;
+ int status = 0;
int required = 0;
int fail = 0;
char *pkgstr;
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")) {
/* 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
* 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;
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();
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);
}
free(pkgid);
zpm_close(&zpm);
- return (fail == HARD || (required && fail)) ? EXIT_FAILURE : 0;
+ return (fail == HARD || (required && fail)) ? status : 0;
}