]> pd.if.org Git - zpackage/blob - zpm-runscript.c
fix pointer related bugs
[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
152                         /* perhaps also pass in the phase name?  or ENV? */
153                         /* TODO sanitize environment ? */
154                         args[0] = script;
155                         args[1] = pkgid;
156                         args[2] = 0;
157                         args[3] = 0;
158                         if (argn + 1 <= ac) {
159                                 args[2] = av[argn+1];
160                         }
161
162                         if (rootdir) {
163                                 if (chdir(rootdir) == -1) {
164                                         perror("can not chdir to rootdir");
165                                         exit(EXIT_FAILURE);
166                                 }
167                                 if (geteuid() == 0) {
168                                         /* chroot is deprecated, and not in
169                                          * posix.  need to use OS/kernel
170                                          * specific code.
171                                          */
172                                         fprintf(stderr, "support for chroot equivalent not supported on this OS\n");
173                                 } else {
174                                         fprintf(stderr, "unable to chroot as non root user\n");
175                                 }
176                         } else {
177                                 if (chdir("/") == -1) {
178                                         perror("can not chdir to /");
179                                         exit(EXIT_FAILURE);
180                                 }
181                         }
182
183                         if (!zpm_extract(&zpm, hash, script, 0700)) {
184                                 fprintf(stderr, "unable to extract script");
185                                 exit(EXIT_FAILURE);
186                         }
187
188                         rv = run(script, args, output, &status);
189                         if (rv) {
190                                 //                      cat(output);
191                                 fprintf(stderr, "package %s script failed with code %d\n",
192                                                 pkgid, rv);
193                         }
194                         /* TODO log output */
195                         if (script) {
196                                 unlink(script);
197                         }
198                         if (output) {
199                                 unlink(output);
200                         }
201                         if (rv) {
202                                 failures++;
203                         }
204                 } else {
205                         if (required) {
206                                 fprintf(stderr, "no script for %s %s\n", phase, pkgid);
207                                 failures++;
208                         }
209                 }
210                 free(pkgid);
211         } else {
212                 fprintf(stderr, "unable to find package for %s in %s\n",
213                                 pkgstr, db);
214                 failures++;
215         }
216
217         zpm_close(&zpm);
218
219         return failures ? EXIT_FAILURE : EXIT_SUCCESS;
220 }