]> pd.if.org Git - zpackage/blob - zpm-foreach-path.c
fix possible memory leak in uncompress
[zpackage] / zpm-foreach-path.c
1 #define _POSIX_C_SOURCE 2
2 #include <stdlib.h>
3 #include <stdio.h>
4 #include <ctype.h>
5 #include <limits.h>
6 #include <unistd.h>
7 #include <sys/types.h>
8 #include <sys/wait.h>
9
10 #include <string.h>
11
12 #include "sqlite3.h"
13 #include "zpm.h"
14
15 struct config {
16         char *dbfile;
17         char *cmd;
18         char *program;
19         char *pkgid;
20         char *nullstr;
21         int errcontinue;
22         int errors;
23         int (*callback)(void*,int,char**,char**);
24 };
25
26 static void usage() {
27         printf("usage: zpm foreach-path [-fncC] args ...\n");
28 }
29
30 static int run_program(void *f, int ncols, char **vals, char **cols) {
31         struct config *conf = f;
32         int i;
33         char *argv[ncols+1];
34         pid_t pid;
35         int status;
36         int rv;
37
38         argv[0] = conf->program;
39
40         for (i=0;i<ncols;i++) {
41                 argv[i+1] = vals[i] ? vals[i] : conf->nullstr;
42         }
43         argv[i+1] = 0;
44
45         pid = fork();
46
47         if (pid == -1) {
48                 perror("cannot fork");
49                 return 1;
50         }
51
52         if (pid == 0) {
53                 /* child */
54                 rv = execvp(conf->program, argv);
55                 if (rv == -1) {
56                         perror("cannot exec");
57                         exit(EXIT_FAILURE);
58                 }
59         }
60
61         rv = wait(&status);
62         if (rv == -1) {
63                 perror("error waiting for child");
64                 exit(EXIT_FAILURE);
65         }
66         if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
67                 return 0;
68         } else if (conf->errcontinue) {
69                 conf->errors++;
70                 return 0;
71         }
72         return 1;
73 }
74
75 static int run_shell(void *f, int ncols, char **vals, char **cols) {
76         struct config *conf = f;
77         int i;
78         char *argv[ncols+4];
79         pid_t pid;
80         int status;
81         int rv;
82
83         argv[0] = "sh";
84         argv[1] = "-c";
85         argv[2] = conf->cmd;
86         argv[3] = "sh";
87
88         for (i=0;i<ncols;i++) {
89                 argv[i+4] = vals[i] ? vals[i] : conf->nullstr;
90         }
91         argv[i+4] = 0;
92
93         pid = fork();
94
95         if (pid == -1) {
96                 perror("cannot fork");
97                 return 1;
98         }
99
100         if (pid == 0) {
101                 /* child */
102                 rv = execvp("sh", argv);
103                 if (rv == -1) {
104                         perror("cannot exec");
105                         exit(EXIT_FAILURE);
106                 }
107         }
108
109         rv = wait(&status);
110         if (rv == -1) {
111                 perror("error waiting for child");
112         }
113         if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
114                 return 0;
115         } else if (conf->errcontinue) {
116                 conf->errors++;
117                 return 0;
118         }
119         return 1;
120 }
121
122 static int printpaths(void *f, int ncols, char **vals, char **cols) {
123
124         /* suppress unused warnings */
125
126         if (ncols < 4) {
127                 fprintf(stderr, "can't find path names\n");
128                 return 1;
129         }
130 //      printf("path cols %d %p %p\n", ncols, vals, cols);
131         fprintf(stdout, "%s\n", vals[3]);
132 #if 0
133         cols = 0;
134         f = 0;
135         int i;
136         if (cols == 0) {
137                 fprintf(stderr, "sqlite can't get column names\n");
138         }
139         for (i=0;i<ncols;i++) {
140 //              if (i>3) fprintf(out, "\t");
141                 fprintf(stdout, "%s\n", vals[i]);
142         }
143 #endif
144         return 0;
145 }
146
147 void parse_package(char *pstr, char *name, char *ver, int *rel) {
148         if (name) *name = 0;
149         if (ver) *ver = 0;
150         if (rel) *rel = -1;
151
152         /* string - ver - rel */
153         /* rel is all digits */
154         /* possible forms:
155          * ^(.+)-([0-9][^-]*)-([\d+])$
156          * ^(.+)-([0-9][^-]*)$
157          * ^(.+)$
158          * The main problem in parsing is that the package name itself
159          * can contain a '-', so you can't just split on '-'
160          * Also, the version can be just digits.
161          */
162
163         /* everything up to the first '-' is in the name */
164         while (*pstr) {
165                 if (*pstr == '-' && isdigit(*(pstr+1))) {
166                         break;
167                 }
168                 if (name) {
169                         *name++ = *pstr;
170                 }
171                 pstr++;
172         }
173         if (name) *name = 0;
174         if (*pstr == '-') {
175                 pstr++;
176         }
177         while (*pstr && *pstr != '-') {
178                 if (ver) {
179                         *ver++ = *pstr;
180                 }
181                 pstr++;
182         }
183         if (ver) *ver = 0;
184         if (*pstr == '-') {
185                 pstr++;
186         }
187         if (rel && *pstr) {
188                 *rel = atoi(pstr);
189         }
190 }
191
192 #ifdef PATH_MAX
193 #define PATHLEN PATH_MAX
194 #else
195 #define PATHLEN 4096
196 #endif
197
198 int main(int ac, char **av){
199         struct zpm pkg;
200         char *s;
201         int opt;
202
203         struct config conf = { "/var/lib/zpm/local.db", 0, 0, 0, "", 0, 0, printpaths
204         };
205
206         if ((s = getenv("ZPMDB"))) {
207                 /* TODO does this need to be copied ? */
208                 conf.dbfile = s;
209         }
210
211         /*
212          * -c 'shell command'
213          * -f 'package database', otherwise regular default of env ZPMDB,
214          * or /var/lib/zpm/zpm.db, or die
215          *
216          *  arg 1: pkgid triple, but will do a pkg find
217          *  arg 2: program to run.  equivalent of 'printf "%s\n" "$path"
218          *  otherwise' 
219          */
220
221         while ((opt = getopt(ac, av, "f:c:n:C")) != -1) {
222                 switch (opt) {
223                         case 'f': conf.dbfile = optarg;
224                                   break;
225                         case 'c': conf.cmd = optarg;
226                                   conf.callback = run_shell;
227                                   break;
228                         case 'C':
229                                   conf.errcontinue = 1;
230                                   break;
231                         case 'n':
232                                   conf.nullstr = optarg;
233                                   break;
234                         default:
235                                   usage();
236                                   exit(EXIT_FAILURE);
237                                   break;
238                 }
239         }
240         int argn = optind;
241
242         if (!zpm_open(&pkg, conf.dbfile)) {
243                 fprintf(stderr, "can't open zpm db %s\n", conf.dbfile);
244                 exit(EXIT_FAILURE);
245         }
246         char *errmsg = 0;
247
248         if (argn < ac) {
249                 conf.pkgid = av[argn];
250         //      fprintf(stderr, "set pkgid to %s\n", conf.pkgid);
251                 argn++;
252         } else {
253                 fprintf(stderr, "must specify pkgid\n");
254                 usage();
255                 exit(EXIT_FAILURE);
256         }
257
258         /* TODO lookup pkgid via zpm-findpkg equivalent */
259
260         if (argn < ac) {
261                 conf.program = av[argn];
262                 conf.callback = run_program;
263                 argn++;
264                 /* TODO set conf.args to remaining arguments */
265         }
266
267         /* install a collation function */
268         // zpm_addvercmp(&pkg);
269
270         if (!zpm_foreach_path(&pkg, conf.pkgid, 0, conf.callback, &conf, &errmsg)) {
271                 if (errmsg) {
272                         fprintf(stderr, "database error: %s\n", errmsg);
273                         exit(EXIT_FAILURE);
274                 }
275                 if (pkg.error == 1) {
276                         fprintf(stderr, "unable to allocate memory\n");
277                 }
278                 exit(EXIT_FAILURE);
279         }
280
281         zpm_close(&pkg);
282         return conf.errors ? 1 : 0;
283 }