]> pd.if.org Git - zpackage/blob - zpm-script.c
remove unused variable
[zpackage] / zpm-script.c
1 #define _POSIX_C_SOURCE 200809L
2
3 #include <stdlib.h>
4 #include <stdio.h>
5 #include <string.h>
6 #include <sys/types.h>
7 #include <sys/wait.h>
8 #include <sys/stat.h>
9 #include <fcntl.h>
10 #include <unistd.h>
11 #include <errno.h>
12 #include <unistd.h>
13
14 #include <sys/mman.h>
15
16 #include "zpm.h"
17
18 /*
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
24  *
25  * arg is package id
26  */
27
28 void usage(void) {
29         fprintf(stderr, "usage: zpm script ...\n");
30 }
31
32 int setdir(char *rootdir) {
33         if (rootdir && strcmp(rootdir, "/")) {
34                 if (chdir(rootdir) == -1) {
35                         perror("can not chdir to rootdir");
36                         return 0;
37                 }
38                 if (geteuid() == 0) {
39                         /* chroot is deprecated, and not in posix.  need to use
40                          * OS/kernel specific code.
41                          */
42                         fprintf(stderr, "support for chroot equivalent not supported on this OS\n");
43                 } else {
44                         fprintf(stderr, "unable to chroot as non root user\n");
45                 }
46         } else {
47                 if (chdir("/") == -1) {
48                         perror("can not chdir to /");
49                         return 0;
50                 }
51         }
52         return 1;
53 }
54
55
56 int run(char *program, char **args, char *output, int *status) {
57         /* if stdout is a terminal, leave stdout where it goes,
58          * if it's not a terminal, redirect stdout to output.
59          * in either case, send stderr to output, unless null
60          * if output is null or "-", just run the program
61          */
62         int interactive = 0;
63         pid_t pid;
64         int rv;
65
66         errno = 0;
67
68         interactive = isatty(1);
69
70         pid = fork();
71
72         if (pid == -1) {
73                 *status = 1;
74                 return -1;
75         }
76
77         if (pid == 0) {
78                 /* child */
79                 if (output && strcmp(output, "-") != 0) {
80                         close(2);
81                         rv = open(output, O_NOFOLLOW|O_TRUNC|O_CREAT|O_WRONLY,
82                                         0600);
83                         if (rv == -1) {
84                                 perror("cannot open output file");
85                         }
86                         if (!interactive) {
87                                 rv = dup2(2,1);
88                                 if (rv == -1) {
89                                         perror("unable to redirect stdout");
90                                         exit(EXIT_FAILURE);
91                                 }
92                         }
93                 }
94
95                 rv = execvp(program, args);
96                 if (rv == -1) {
97                         perror("cannot exec");
98                         exit(EXIT_FAILURE);
99                 }
100         }
101
102         pid = wait(status);
103         if (pid == -1) {
104                 perror("error waiting for child");
105                 return -2;
106         }
107
108         if (WIFEXITED(*status)) {
109                 return WEXITSTATUS(*status);
110         }
111
112         return -3;
113 }
114
115 #define RUN 1
116 #define SET 2
117 #define LIST 3
118
119 #define SOFT 1
120 #define HARD 2
121
122 static int list_scripts(void *ud, const char *pkg, const char *stage,
123                 const char *hash) {
124         printf("%s %s %.8s\n", pkg, stage, hash);
125         return 0;
126 }
127
128 int main(int ac, char **av){
129         struct zpm zpm;
130         int rv;
131         int status;
132         int required = 0;
133         int fail = 0;
134         char *pkgstr;
135         int opt;
136
137         char hash[ZPM_HASH_STRLEN+1];
138         char *args[4];
139         char *pkgid;
140
141         char *rootdir = 0;
142         char *db = "/var/lib/zpm/local.db";
143         char *script = "/var/tmp/zpm-script";
144         char *output = "/var/tmp/zpm-script.out";
145         char *phase = 0;
146         int quiet = 0;
147         int scriptishash = 0;
148         int mode = RUN;
149
150         if (getenv("ZPMDB")) {
151                 db = getenv("ZPMDB");
152         }
153         /* ZPM_PACKAGE_FILE ? */
154
155         rootdir = getenv("ZPM_ROOT_DIR");
156
157         /* run, set, show, hash */
158         /* set -S, if -H set the hash, output hash, unless quiet
159          * show: -o, or stdout, 
160          * All modes: [-f pkgfile] default to zpmdb
161          * All modes: [-p phase], default to configure
162          * All modes: [-R rootdir], chdir, attempt to chroot
163          * All modes: [-N], required, error if no such script
164          *
165          * run: zpm-script -r -p foo <pkgid args...>
166          * set: zpm-script -s <pkgid [script]>
167          * set: zpm-script -s -h <pkgid [hash]>
168          * show: zpm-script -l [-a] [-o outfile] <pkgid>
169          * show hash: zpm-script -lh <pkgid>
170          */
171         while ((opt = getopt(ac, av, "f:p:rslRFho:S:q")) != -1) {
172                 switch (opt) {
173                         case 'f': db = optarg; break;
174                         case 'p': phase = optarg; break;
175                         case 'r': mode = RUN; break;
176                         case 's': mode = SET; break;
177                         case 'l': mode = LIST; break;
178                         case 'R': rootdir = optarg; break;
179                         case 'F': required = 1; break;
180
181                         case 'h': scriptishash = 1; break;
182                         case 'o': output = optarg; break;
183                         case 'S': script = optarg; break;
184                         case 'q': quiet = 1; break;
185
186                         default:
187                                   usage();
188                                   exit(EXIT_FAILURE);
189                                   break;
190                 }
191         }
192         int argn = optind;
193
194         if (argn >= ac) {
195                 usage();
196                 exit(EXIT_FAILURE);
197         }
198
199         if (!zpm_open(&zpm, db)) {
200                 fprintf(stderr, "unable to open zpm database: %s\n", db);
201                 if (zpm.errmsg) {
202                         fprintf(stderr, "error detail: %s\n", zpm.errmsg);
203                 }
204                 exit(EXIT_FAILURE);
205         }
206
207         /* first non option arg is always a package id */
208         pkgstr = av[argn];
209         pkgid = zpm_findpkg(&zpm, pkgstr, NULL);
210
211         if (!pkgid) {
212                 fprintf(stderr, "no package for %s\n", pkgstr);
213                 zpm_close(&zpm);
214                 exit(EXIT_FAILURE);
215         }
216
217         argn++;
218
219         if (mode == SET) {
220                 char *sethash = 0;
221                 char *setscript = 0;
222                 int rv = 0;
223
224                 if (!phase) {
225                         phase = "configure";
226                 }
227
228                 if (argn < ac) {
229                         if (scriptishash) {
230                                 sethash = av[argn];
231                         } else {
232                                 setscript = av[argn];
233                         }
234                 }
235
236                 if (setscript) {
237                         rv = zpm_import(&zpm,setscript,0,hash);
238                         if (!rv) {
239                                 fprintf(stderr, "unable to import %s\n",
240                                                 setscript);
241                                 fail = HARD;
242                         } else {
243                                 sethash = hash;
244                         }
245                 } 
246
247                 if (!fail && !zpm_script_set(&zpm,pkgid,phase,sethash)) {
248                         fprintf(stderr, "unable to set %s script hash %s\n",
249                                         pkgid,
250                                         sethash ? sethash : "null");
251                         fprintf(stderr, "zpm error: %s\n", zpm.errmsg);
252                         fail = HARD;
253                 }
254         } else if (mode == LIST) {
255                 if (!phase) {
256                         zpm_foreach_script(&zpm, pkgid, phase, 0, list_scripts);
257                 } else if (!zpm_script_hash(&zpm, pkgid, phase, hash)) {
258                         fail = SOFT;
259                 } else if (scriptishash) {
260                         if (!quiet) {
261                                 printf("%s\n", hash);
262                         }
263                 } else {
264                         if (!output) {
265                                 output = "-";
266                         }
267                         if (!zpm_extract(&zpm, hash, output, 0700)) {
268                                 fail = HARD;
269                         }
270                 }
271         } else {
272                 /* run a script */
273                 if (!phase) {
274                         phase = "configure";
275                 }
276
277                 if (!output) {
278                         output = "/var/tmp/zpm-script.out";
279                 }
280
281                 if (!script) {
282                         script = "/var/tmp/zpm-script";
283                 }
284
285                 /* since the script file name doesn't really
286                  * mean anything, pass in the phase as arg 0
287                  */
288                 /* TODO sanitize environment ? */
289                 args[0] = phase;
290                 args[1] = pkgid;
291                 args[2] = 0;
292                 args[3] = 0;
293
294                 if (argn <= ac) {
295                         args[2] = av[argn];
296                 }
297
298                 if (!zpm_script_hash(&zpm, pkgid, phase, hash)) {
299                         fail = SOFT;
300                         goto cleanup;
301                 }
302
303                 if (!setdir(rootdir)) {
304                         fail = HARD;
305                         goto cleanup;
306                 }
307
308                 if (!zpm_extract(&zpm, hash, script, 0700)) {
309                         fprintf(stderr, "unable to extract script");
310                         fail = HARD;
311                         goto cleanup;
312                 }
313
314                 rv = run(script, args, output, &status);
315                 if (rv) {
316                         fprintf(stderr, "package %s script failed with code %d\n",
317                                         pkgid, rv);
318                         fail = HARD;
319                 }
320
321                 /* TODO log output */
322                 if (script) {
323                         unlink(script);
324                 }
325                 if (output) {
326                         unlink(output);
327                 }
328         }
329
330 cleanup:
331         free(pkgid);
332         zpm_close(&zpm);
333
334         return (fail == HARD || (required && fail)) ? EXIT_FAILURE : 0;
335
336 }