]> pd.if.org Git - zpackage/blobdiff - src/script.c
move C source files into src
[zpackage] / src / script.c
diff --git a/src/script.c b/src/script.c
new file mode 100644 (file)
index 0000000..7c03b24
--- /dev/null
@@ -0,0 +1,348 @@
+#define _POSIX_C_SOURCE 200809L
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include <sys/mman.h>
+
+#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: zpm script ...\n");
+}
+
+int setdir(char *rootdir) {
+       if (chdir(rootdir ? rootdir : "/") == -1) {
+               perror("can not chdir to rootdir");
+               return 0;
+       }
+#if 0
+       if (rootdir && strcmp(rootdir, "/")) {
+               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");
+               }
+       }
+#endif
+       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
+
+static int list_scripts(void *ud, const char *pkg, const char *stage,
+               const char *hash) {
+       printf("%s %s %.8s\n", pkg, stage, hash);
+       return 0;
+}
+
+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/local.db";
+       char *script = "/var/tmp/zpm-script";
+       char *output = "/var/tmp/zpm-script.out";
+       char *phase = 0;
+       char *envvar = 0;
+       int quiet = 0;
+       int scriptishash = 0;
+       int mode = RUN;
+
+       if (getenv("ZPMDB")) {
+               db = 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;
+       }
+
+       /* 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 <pkgid args...>
+        * set: zpm-script -s <pkgid [script]>
+        * set: zpm-script -s -h <pkgid [hash]>
+        * 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) {
+               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 'h': scriptishash = 1; break;
+                       case 'o': output = optarg; break;
+                       case 'S': script = optarg; break;
+                       case 'q': quiet = 1; break;
+
+                       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, NULL);
+
+       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 (!phase) {
+                       zpm_foreach_script(&zpm, pkgid, phase, 0, list_scripts);
+               } else if (!zpm_script_hash(&zpm, pkgid, phase, hash)) {
+                       fail = SOFT;
+               } else if (scriptishash) {
+                       if (!quiet) {
+                               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;
+                       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);
+
+                       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;
+}