1 #define _POSIX_C_SOURCE 200809L
19 * -f package file, otherwise localdb
20 * -p phase, defaults to 'configure'
21 * -s script name, defaults to /var/tmp/zpm-script
22 * -r chroot to directory
23 * -o script output, /var/tmp/zpm-script.out, '-' for stdout
29 fprintf(stderr, "usage: zpm script ...\n");
32 int setdir(char *rootdir) {
33 if (chdir(rootdir ? rootdir : "/") == -1) {
34 perror("can not chdir to rootdir");
38 if (rootdir && strcmp(rootdir, "/")) {
40 /* chroot is deprecated, and not in posix. need to use
41 * OS/kernel specific code.
43 fprintf(stderr, "support for chroot equivalent not supported on this OS\n");
45 fprintf(stderr, "unable to chroot as non root user\n");
53 int run(char *program, char **args, char *output, int *status) {
54 /* if stdout is a terminal, leave stdout where it goes,
55 * if it's not a terminal, redirect stdout to output.
56 * in either case, send stderr to output, unless null
57 * if output is null or "-", just run the program
65 interactive = isatty(1);
76 if (output && strcmp(output, "-") != 0) {
78 rv = open(output, O_NOFOLLOW|O_TRUNC|O_CREAT|O_WRONLY,
81 perror("cannot open output file");
86 perror("unable to redirect stdout");
92 rv = execvp(program, args);
94 perror("cannot exec");
101 perror("error waiting for child");
105 if (WIFEXITED(*status)) {
106 return WEXITSTATUS(*status);
119 static int list_scripts(void *ud, const char *pkg, const char *stage,
121 printf("%s %s %.8s\n", pkg, stage, hash);
125 int main(int ac, char **av){
134 char hash[ZPM_HASH_STRLEN+1];
139 char *db = "/var/lib/zpm/local.db";
143 int quiet = 0, verbose = 0;
144 int allowempty = 0, notealways = 0, makenote = 0, showoutput = 0;
145 int scriptishash = 0, notenever = 0, noteifwritable = 0;
149 if (getenv("ZPMDB")) {
150 db = getenv("ZPMDB");
152 /* ZPM_PACKAGE_FILE ? */
154 rootdir = getenv("ZPM_ROOT_DIR");
155 script = getenv("ZPM_SCRIPT_FILE");
156 output = getenv("ZPM_SCRIPT_OUTPUT");
158 /* run, set, show, hash */
159 /* set -S, if -H set the hash, output hash, unless quiet
160 * show: -o, or stdout,
161 * All modes: [-f pkgfile] default to zpmdb
162 * All modes: [-p phase], default to configure
163 * All modes: [-R rootdir], chdir, attempt to chroot
164 * All modes: [-N], required, error if no such script
166 * run: zpm-script -r -p foo <pkgid args...>
167 * set: zpm-script -s <pkgid [script]>
168 * set: zpm-script -s -h <pkgid [hash]>
169 * show: zpm-script -l [-a] [-o outfile] <pkgid>
170 * show hash: zpm-script -lh <pkgid>
172 while ((opt = getopt(ac, av, "f:p:rslRFho:S:qv")) != -1) {
174 case 'f': db = optarg; break;
175 case 'p': phase = optarg; break;
176 case 'r': mode = RUN; break;
177 case 's': mode = SET; break;
178 case 'l': mode = LIST; break;
179 case 'R': rootdir = optarg; break;
180 case 'F': required = 1; break;
181 case 'a': notealways = 1; break;
182 case 'n': notenever = 1; break;
183 case 'N': noteifwritable = 1; break;
184 case 'e': allowempty = 1; break;
185 case 'h': scriptishash = 1; break;
186 case 'o': output = optarg; break;
187 case 'S': script = optarg; break;
188 case 'q': quiet = 1; break;
189 case 'v': verbose = 1; break;
204 if (!zpm_open(&zpm, db)) {
205 fprintf(stderr, "unable to open zpm database: %s\n", db);
207 fprintf(stderr, "error detail: %s\n", zpm.errmsg);
212 /* first non option arg is always a package id */
214 pkgid = zpm_findpkg(&zpm, pkgstr, NULL);
217 fprintf(stderr, "no package for %s\n", pkgstr);
237 setscript = av[argn];
242 rv = zpm_import(&zpm,setscript,0,hash);
244 fprintf(stderr, "unable to import %s\n",
252 if (!fail && !zpm_script_set(&zpm,pkgid,phase,sethash)) {
253 fprintf(stderr, "unable to set %s script hash %s\n",
255 sethash ? sethash : "null");
256 fprintf(stderr, "zpm error: %s\n", zpm.errmsg);
259 } else if (mode == LIST) {
261 zpm_foreach_script(&zpm, pkgid, phase, 0, list_scripts);
262 } else if (!zpm_script_hash(&zpm, pkgid, phase, hash)) {
264 } else if (scriptishash) {
266 printf("%s\n", hash);
272 if (!zpm_extract(&zpm, hash, output, 0700)) {
283 output = "/var/tmp/zpm-script.out";
287 script = "/var/tmp/zpm-script";
290 /* since the script file name doesn't really
291 * mean anything, pass in the phase as arg 0
293 /* TODO sanitize environment ? */
303 if (!zpm_script_hash(&zpm, pkgid, phase, hash)) {
305 status = EXIT_FAILURE;
309 if (!setdir(rootdir)) {
311 status = EXIT_FAILURE;
315 if (!zpm_extract(&zpm, hash, script, 0700)) {
316 fprintf(stderr, "unable to extract script");
318 status = EXIT_FAILURE;
319 zpm_note_add(&zpm, pkgid, NULL, hash, "unable to extract %s script", phase);
323 rv = run(script, args, output, &status);
325 status = WEXITSTATUS(status);
330 if (zpm_readonly(&zpm) && noteifwritable) {
334 if (output && !notenever) {
336 stat(output, &outstat);
337 outsize = outstat.st_size;
338 if (notealways || (outsize && status && (outsize || allowempty))) {
346 zpm_import(&zpm, output, 0, hash);
349 sprintf(note, "%.64s script failed with code %d",
354 sprintf(note, "%.64s script succeeded", phase);
356 zpm_note_add(&zpm, pkgid, NULL, hash, note);
359 if (output && showoutput) {
361 int out = open(output, O_RDONLY);
364 perror("can't open output file");
366 while ((bytes = read(out, buf, sizeof buf)) > 0) {
367 write(1, buf, bytes);
370 perror("output file read error");
390 return (fail == HARD || (required && fail)) ? status : 0;