Glob ftswalk/arglist args always.
[platform/upstream/rpm.git] / lib / rpmgi.c
1 /*@-modfilesys@*/
2 /** \ingroup rpmio
3  * \file rpmio/rpmio.c
4  */
5 #include "system.h"
6
7 #define _RPMGI_INTERNAL
8 #include <rpmgi.h>
9
10 #include <rpmdb.h>
11 #include "manifest.h"
12
13 #include "debug.h"
14
15 /*@unchecked@*/
16 int _rpmgi_debug = 0;
17
18 static const char * hdlistpath = "/usr/share/comps/i386/hdlist";
19
20 rpmgi XrpmgiUnlink(rpmgi gi, const char * msg, const char * fn, unsigned ln)
21 {
22     if (gi == NULL) return NULL;
23
24 if (_rpmgi_debug && msg != NULL)
25 fprintf(stderr, "--> gi %p -- %d %s at %s:%u\n", gi, gi->nrefs, msg, fn, ln);
26
27     gi->nrefs--;
28     return NULL;
29 }
30
31 rpmgi XrpmgiLink(rpmgi gi, const char * msg, const char * fn, unsigned ln)
32 {
33     if (gi == NULL) return NULL;
34     gi->nrefs++;
35
36 if (_rpmgi_debug && msg != NULL)
37 fprintf(stderr, "--> gi %p ++ %d %s at %s:%u\n", gi, gi->nrefs, msg, fn, ln);
38
39     /*@-refcounttrans@*/ return gi; /*@=refcounttrans@*/
40 }
41
42 rpmgi rpmgiFree(rpmgi gi)
43 {
44     if (gi == NULL)
45         return NULL;
46
47     if (gi->nrefs > 1)
48         return rpmgiUnlink(gi, NULL);
49
50 if (_rpmgi_debug < 0)
51 fprintf(stderr, "*** gi %p\t%p[%d]\n", gi, gi->argv, gi->argc);
52
53     (void) rpmgiUnlink(gi, NULL);
54
55     switch (gi->tag) {
56     default:
57     case RPMGI_RPMDB:
58         break;
59     case RPMGI_HDLIST:
60         break;
61     case RPMGI_ARGLIST:
62         break;
63     case RPMGI_FTSWALK:
64         break;
65     }
66
67     gi->queryFormat = _free(gi->queryFormat);
68     gi->argv = argvFree(gi->argv);
69     if (gi->ftsp != NULL) {
70         int xx;
71         xx = Fts_close(gi->ftsp);
72         gi->ftsp = NULL;
73         gi->fts = NULL;
74     }
75     if (gi->fd != NULL) {
76         (void) Fclose(gi->fd);
77         gi->fd = NULL;
78     }
79     gi->mi = rpmdbFreeIterator(gi->mi);
80     gi->ts = rpmtsFree(gi->ts);
81
82     memset(gi, 0, sizeof(*gi));         /* XXX trash and burn */
83     gi = _free(gi);
84     return NULL;
85 }
86
87 rpmgi rpmgiNew(rpmts ts, int tag, void *const keyp, size_t keylen)
88 {
89     rpmgi gi = xcalloc(1, sizeof(*gi));
90
91     if (gi == NULL)
92         return NULL;
93
94     gi->ts = rpmtsLink(ts, NULL);
95     gi->tag = tag;
96     gi->i = -1;
97
98     switch (gi->tag) {
99     default:
100     case RPMGI_RPMDB:
101         gi->mi = rpmtsInitIterator(ts, RPMDBI_PACKAGES, NULL, 0);
102
103 if (_rpmgi_debug < 0)
104 fprintf(stderr, "*** gi %p\t%p\n", gi, gi->mi);
105
106         break;
107     case RPMGI_HDLIST:
108         gi->fd = Fopen(hdlistpath, "r.ufdio");
109         break;
110     case RPMGI_ARGLIST:
111     case RPMGI_FTSWALK:
112     {   ARGV_t pav = keyp;
113         const char * arg;
114         unsigned flags = keylen;
115         int xx;
116
117         gi->argv = xcalloc(1, sizeof(*gi->argv));
118         gi->argc = 0;
119         if (pav != NULL)
120         while ((arg = *pav++) != NULL) {
121             ARGV_t av = NULL;
122             int ac;
123
124             xx = rpmGlob(arg, &ac, &av);
125             xx = argvAppend(&gi->argv, av);
126             gi->argc += ac;
127             av = argvFree(av);
128         }
129         gi->ftsOpts = flags;
130
131 if (_rpmgi_debug < 0)
132 fprintf(stderr, "*** gi %p\t%p[%d]\n", gi, gi->argv, gi->argc);
133
134     }   break;
135     }
136
137     gi = rpmgiLink(gi, NULL);
138
139     return gi;
140 }
141
142 static int indent = 2;
143
144 static const char * ftsInfoStrings[] = {
145     "UNKNOWN",
146     "D",
147     "DC",
148     "DEFAULT",
149     "DNR",
150     "DOT",
151     "DP",
152     "ERR",
153     "F",
154     "INIT",
155     "NS",
156     "NSOK",
157     "SL",
158     "SLNONE",
159     "W",
160 };
161
162 static const char * ftsInfoStr(int fts_info) {
163     if (!(fts_info >= 1 && fts_info <= 14))
164         fts_info = 0;
165     return ftsInfoStrings[ fts_info ];
166 }
167
168 /*@only@*/
169 static const char * rpmgiPathOrQF(rpmgi gi, const char * fn,
170                 /*@null@*/ Header * hdrp)
171         /*@modifies gi, *hdrp @*/
172 {
173     const char * fmt = ((gi->queryFormat != NULL)
174         ? gi->queryFormat : "%{name}-%{version}-%{release}");
175     const char * val = NULL;
176     Header h = NULL;
177
178     if (hdrp != NULL && *hdrp != NULL)
179         h = headerLink(*hdrp);
180
181     if (h != NULL)
182         val = headerSprintf(h, fmt, rpmTagTable, rpmHeaderFormats, NULL);
183     else
184         val = xstrdup(fn);
185
186     h = headerFree(h);
187
188     return val;
189 }
190
191 /*@null@*/
192 static rpmRC rpmgiReadManifest(rpmgi gi, const char * fileURL)
193         /*@*/
194 {
195     rpmRC rpmrc;
196     FD_t fd;
197
198     fd = Fopen(fileURL, "r.ufdio");
199     if (fd == NULL || Ferror(fd)) {
200         rpmError(RPMERR_OPEN, _("open of %s failed: %s\n"), fileURL,
201                         Fstrerror(fd));
202         if (fd != NULL) (void) Fclose(fd);
203         return RPMRC_FAIL;
204     }
205
206     rpmrc = rpmReadPackageManifest(fd, &gi->argc, &gi->argv);
207
208     (void) Fclose(fd);
209
210     return rpmrc;
211 }
212
213 /*@null@*/
214 static Header rpmgiReadHeader(rpmgi gi, const char * fileURL)
215         /*@*/
216 {
217     Header h = NULL;
218     rpmRC rpmrc;
219     FD_t fd;
220
221     fd = Fopen(fileURL, "r.ufdio");
222     if (fd == NULL || Ferror(fd)) {
223         rpmError(RPMERR_OPEN, _("open of %s failed: %s\n"), fileURL,
224                         Fstrerror(fd));
225         if (fd != NULL) (void) Fclose(fd);
226         return h;
227     }
228
229     rpmrc = rpmReadPackageFile(gi->ts, fd, fileURL, &h);
230
231     (void) Fclose(fd);
232
233     switch (rpmrc) {
234     case RPMRC_NOTFOUND:
235         /* XXX Try to read a package manifest. Restart ftswalk on success. */
236     case RPMRC_FAIL:
237     default:
238         h = headerFree(h);
239         break;
240     case RPMRC_NOTTRUSTED:
241     case RPMRC_NOKEY:
242     case RPMRC_OK:
243         break;
244     }
245
246     return h;
247 }
248
249 const char * rpmgiNext(/*@null@*/ rpmgi gi)
250         /*@modifies gi @*/
251 {
252     const char * val = NULL;
253     const char * fn = NULL;
254     Header h = NULL;
255     rpmRC rpmrc;
256
257     if (gi != NULL && ++gi->i >= 0)
258     switch (gi->tag) {
259     default:
260     case RPMGI_RPMDB:
261         h = rpmdbNextIterator(gi->mi);
262         if (h != NULL) {
263             val = rpmgiPathOrQF(gi, "rpmdb", &h);
264         } else {
265             gi->mi = rpmdbFreeIterator(gi->mi);
266             gi->i = -1;
267         }
268         break;
269     case RPMGI_HDLIST:
270         h = headerRead(gi->fd, HEADER_MAGIC_YES);
271         if (h != NULL) {
272             val = rpmgiPathOrQF(gi, "hdlist", &h);
273         } else {
274             (void) Fclose(gi->fd);
275             gi->fd = NULL;
276             gi->i = -1;
277         }
278         break;
279     case RPMGI_ARGLIST:
280         if (gi->argv != NULL && gi->argv[gi->i] != NULL) {
281 if (_rpmgi_debug  < 0)
282 fprintf(stderr, "*** gi %p\t%p[%d]: %s\n", gi, gi->argv, gi->i, gi->argv[gi->i]);
283             /* Read next header, lazily expanding manifests as found. */
284             do {
285                 fn = gi->argv[gi->i];
286                 h = rpmgiReadHeader(gi, fn);
287                 if (h != NULL)
288                     break;
289                 /* Not a header, so try for a manifest. */
290                 gi->argv[gi->i] = NULL;
291                 rpmrc = rpmgiReadManifest(gi, fn);
292                 if (rpmrc != RPMRC_OK) {
293                     gi->argv[gi->i] = fn;
294                     break;
295                 }
296                 fn = _free(fn);
297             } while (1);
298             /* XXX check rpmrc */
299             val = rpmgiPathOrQF(gi, fn, &h);
300             h = headerFree(h);
301         } else
302             gi->i = -1;
303         break;
304     case RPMGI_FTSWALK:
305         if (gi->argv == NULL)
306             break;
307         if (gi->ftsp == NULL && gi->i == 0) {
308             gi->ftsp = Fts_open((char *const *)gi->argv, gi->ftsOpts, NULL);
309             /* XXX NULL with open(2)/malloc(3) errno set */
310         }
311
312         if (gi->ftsp != NULL)
313         while (val == NULL && (gi->fts = Fts_read(gi->ftsp)) != NULL) {
314             FTSENT * fts = gi->fts;
315
316 if (_rpmgi_debug < 0)
317 fprintf(stderr, "FTS_%s\t%*s %s\n", ftsInfoStr(fts->fts_info),
318                 indent * (fts->fts_level < 0 ? 0 : fts->fts_level), "",
319                 fts->fts_name);
320
321             switch (fts->fts_info) {
322             case FTS_F:
323             case FTS_SL:
324 if (_rpmgi_debug  < 0)
325 fprintf(stderr, "*** gi %p\t%p[%d]: %s\n", gi, gi->ftsp, gi->i, fts->fts_path);
326                 fn = fts->fts_path;
327                 h = rpmgiReadHeader(gi, fn);
328                 val = rpmgiPathOrQF(gi, fn, &h);
329                 h = headerFree(h);
330                 break;
331             default:
332                 break;
333             }
334         }
335         if (gi->fts == NULL && gi->ftsp != NULL) {
336             int xx;
337             xx = Fts_close(gi->ftsp);
338             gi->ftsp = NULL;
339             gi->i = -1;
340         }
341         break;
342     }
343
344     return val;
345 }
346
347 int rpmgiSetQueryFormat(rpmgi gi, const char * queryFormat)
348 {
349     int rc = 0;
350                                                                                 
351     if (gi != NULL) {
352         gi->queryFormat = _free(gi->queryFormat);
353         gi->queryFormat = (queryFormat != NULL ? xstrdup(queryFormat) : NULL);
354     }
355     return rc;
356
357 }
358
359 /*@=modfilesys@*/