]> pd.if.org Git - zpackage/blob - zpm-runscript.c
a3f4c2f6d07efe0e21c071483264b2deca97a301
[zpackage] / zpm-runscript.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: db hash file\n");
30 }
31
32 int run(char *program, char **args, char *output, int *status) {
33         /* if stdout is a terminal, leave stdout where it goes,
34          * if it's not a terminal, redirect stdout to output.
35          * in either case, send stderr to output, unless null
36          * if output is null or "-", just run the program
37          */
38         int interactive = 0;
39         pid_t pid;
40         int rv;
41
42         errno = 0;
43
44         interactive = isatty(1);
45
46         pid = fork();
47
48         if (pid == -1) {
49                 *status = 1;
50                 return -1;
51         }
52
53         if (pid == 0) {
54                 /* child */
55                 if (output && strcmp(output, "-") != 0) {
56                         close(2);
57                         rv = open(output, O_NOFOLLOW|O_TRUNC|O_CREAT|O_WRONLY,
58                                         0600);
59                         if (rv == -1) {
60                                 perror("cannot open output file");
61                         }
62                         if (!interactive) {
63                                 rv = dup2(2,1);
64                                 if (rv == -1) {
65                                         perror("unable to redirect stdout");
66                                         exit(EXIT_FAILURE);
67                                 }
68                         }
69                 }
70
71                 rv = execvp(program, args);
72                 if (rv == -1) {
73                         perror("cannot exec");
74                         exit(EXIT_FAILURE);
75                 }
76         }
77
78         pid = wait(status);
79         if (pid == -1) {
80                 perror("error waiting for child");
81                 return -2;
82         }
83
84         if (WIFEXITED(*status)) {
85                 return WEXITSTATUS(*status);
86         }
87
88         return -3;
89 }
90
91 int main(int ac, char **av){
92         struct zpm zpm;
93         int rv;
94         int status;
95         int failures = 0;
96         char *pkgstr;
97         int opt;
98         int required = 0;
99
100         char hash[ZPM_HASH_STRLEN+1];
101         char *args[4];
102         char *pkgid;
103
104         char *rootdir = 0;
105         char *db = "/var/lib/zpm/zpm.db";
106         char *script = "/var/tmp/zpm-script";
107         char *output = "/var/tmp/zpm-script.out";
108         char *phase = "configure";
109
110         if (getenv("ZPMDB")) {
111                 db = getenv("ZPMDB");
112         }
113         /* ZPM_PACKAGE_FILE ? */
114
115         rootdir = getenv("ZPM_ROOT_DIR");
116
117         while ((opt = getopt(ac, av, "f:p:o:s:r:R")) != -1) {
118                 switch (opt) {
119                         case 'f': db = optarg; break;
120                         case 'p': phase = optarg; break;
121                         case 's': script = optarg; break;
122                         case 'o': output = optarg; break;
123                         case 'r': rootdir = optarg; break;
124                         case 'R': required = 1; break;
125                         default:
126                                   usage();
127                                   exit(EXIT_FAILURE);
128                                   break;
129                 }
130         }
131         int argn = optind;
132
133         if (argn >= ac) {
134                 usage();
135                 exit(EXIT_FAILURE);
136         }
137
138         pkgstr = av[argn];
139
140         if (!zpm_open(&zpm, db)) {
141                 fprintf(stderr, "unable to open zpm database: %s\n", db);
142                 if (zpm.errmsg) {
143                         fprintf(stderr, "error detail: %s\n", zpm.errmsg);
144                 }
145                 exit(EXIT_FAILURE);
146         }
147
148         pkgid = zpm_findpkg(&zpm, pkgstr);
149         if (pkgid) {
150                 if (zpm_script_hash(&zpm, pkgid, phase, hash)) {
151                         /* since the script file name doesn't really
152                          * mean anything, pass in the phase as arg 0
153                          */
154
155                         /* TODO sanitize environment ? */
156                         args[0] = phase;
157                         args[1] = pkgid;
158                         args[2] = 0;
159                         args[3] = 0;
160                         if (argn + 1 <= ac) {
161                                 args[2] = av[argn+1];
162                         }
163
164                         if (rootdir) {
165                                 if (chdir(rootdir) == -1) {
166                                         perror("can not chdir to rootdir");
167                                         exit(EXIT_FAILURE);
168                                 }
169                                 if (geteuid() == 0) {
170                                         /* chroot is deprecated, and not in
171                                          * posix.  need to use OS/kernel
172                                          * specific code.
173                                          */
174                                         fprintf(stderr, "support for chroot equivalent not supported on this OS\n");
175                                 } else {
176                                         fprintf(stderr, "unable to chroot as non root user\n");
177                                 }
178                         } else {
179                                 if (chdir("/") == -1) {
180                                         perror("can not chdir to /");
181                                         exit(EXIT_FAILURE);
182                                 }
183                         }
184
185                         if (!zpm_extract(&zpm, hash, script, 0700)) {
186                                 fprintf(stderr, "unable to extract script");
187                                 exit(EXIT_FAILURE);
188                         }
189
190                         rv = run(script, args, output, &status);
191                         if (rv) {
192                                 //                      cat(output);
193                                 fprintf(stderr, "package %s script failed with code %d\n",
194                                                 pkgid, rv);
195                         }
196                         /* TODO log output */
197                         if (script) {
198                                 unlink(script);
199                         }
200                         if (output) {
201                                 unlink(output);
202                         }
203                         if (rv) {
204                                 failures++;
205                         }
206                 } else {
207                         if (required) {
208                                 fprintf(stderr, "no script for %s %s\n", phase, pkgid);
209                                 failures++;
210                         }
211                 }
212                 free(pkgid);
213         } else {
214                 fprintf(stderr, "unable to find package for %s in %s\n",
215                                 pkgstr, db);
216                 failures++;
217         }
218
219         zpm_close(&zpm);
220
221         return failures ? EXIT_FAILURE : EXIT_SUCCESS;
222 }