]> pd.if.org Git - zpackage/blob - zpm-search.c
add zpm-search to look for packages and libraries
[zpackage] / zpm-search.c
1 #define _POSIX_C_SOURCE 200809L
2 #include <stdlib.h>
3 #include <string.h>
4 #include <unistd.h>
5
6 #include <glob.h>
7
8 #include "zpm.h"
9 #include "lib/jsw/jsw_hlib.h"
10 #include "lib/jsw/jsw_atree.h"
11
12 /*
13  * find packages, and lib deps
14  */
15
16 struct pkgloc {
17         char *id;
18         char *file;
19         int info;
20 };
21
22 char *checkfile(char *pkgstr, char *path) {
23         struct zpm pkgfile;
24         char *pkgid = 0;
25
26         if (!zpm_open(&pkgfile, path)) {
27                 return NULL;
28         }
29         
30         pkgid = zpm_findpkg(&pkgfile, pkgstr, "hash is not null");
31         zpm_close(&pkgfile);
32
33         return pkgid;
34 }
35
36 char *checkfileforlib(char *soname, char *path) {
37         struct zpm pkgfile;
38         char *pkgid = 0;
39
40         if (!zpm_open(&pkgfile, path)) {
41                 return NULL;
42         }
43         
44         pkgid = zpm_findlib(&pkgfile, soname, "hash is not null");
45         if (pkgfile.error) {
46                 fprintf(stderr, "sql error: %s\n", pkgfile.errmsg);
47         }
48         zpm_close(&pkgfile);
49
50         return pkgid;
51 }
52
53 int find_lib(char *soname, struct pkgloc *pkg) {
54         char *latest = 0;
55         char *installed = 0, *found = 0;
56         char *pkgfile = 0;
57         int rv;
58         struct zpm localdb;
59
60         if (zpm_open(&localdb, NULL)) {
61                 installed = zpm_findlib(&localdb, soname, "status = 'installed'");
62                 zpm_close(&localdb);
63
64                 if (installed) {
65                         /* we're done, the lib is installed */
66                         return 2;
67                 }
68         } else {
69                 fprintf(stderr, "can't open localdb\n");
70         }
71
72         glob_t repos;
73         repos.gl_offs = 0;
74         rv = glob("/var/lib/zpm/repos/*.repo", 0, NULL, &repos);
75         switch (rv) {
76                 case GLOB_NOSPACE:
77                         fprintf(stderr, "glob no mem\n");
78                         exit(EXIT_FAILURE); break;
79                 case GLOB_ABORTED:
80                         fprintf(stderr, "glob abort\n");
81                         exit(EXIT_FAILURE); break;
82                 case GLOB_NOMATCH:
83                         break;
84                 case 0:
85                                    break;
86                 default:
87                                    break;
88         }
89
90         unsigned i;
91         for (i = 0; i < repos.gl_pathc; i++) {
92                 found = checkfileforlib(soname, repos.gl_pathv[i]);
93                 if (found) {
94                         rv = zpm_vercmp(found, latest);
95                         if (rv == 1) {
96                                 latest = found;
97                                 free(pkgfile);
98                                 pkgfile = strdup(repos.gl_pathv[i]);
99                         }
100                 }
101         }
102
103         globfree(&repos);
104         repos.gl_offs = 0;
105
106         char *pkgdir = "/home/zoranix/zrepo/packages";
107         char *pkgglob = 0;
108
109         size_t globlen = strlen(pkgdir)+7;
110         pkgglob = malloc(globlen+1);
111         snprintf(pkgglob, globlen, "%s/*.zpm", pkgdir);
112         rv = glob(pkgglob, 0, NULL, &repos);
113         free(pkgglob);
114
115         switch (rv) {
116                 case GLOB_NOSPACE:
117                         exit(EXIT_FAILURE); break;
118                 case GLOB_ABORTED:
119                         exit(EXIT_FAILURE); break;
120                 case GLOB_NOMATCH: break;
121                 case 0:
122                                    break;
123                 default:
124                                    break;
125         }
126
127         for (i = 0; i < repos.gl_pathc; i++) {
128                 found = checkfileforlib(soname, repos.gl_pathv[i]);
129                 if (found) {
130                         rv = zpm_vercmp(found, latest);
131                         if (rv == 1) {
132                                 latest = found;
133                                 free(pkgfile);
134                                 pkgfile = strdup(repos.gl_pathv[i]);
135                         }
136                 }
137         }
138
139         if (latest && pkgfile) {
140                 pkg->id = strdup(latest);
141                 pkg->file = pkgfile;
142                 return 1;
143         }
144
145         return 0;
146 }
147
148 struct pkgloc *find_package(char *pkgstr) {
149         char *latest = 0;
150         char *installed = 0, *found = 0;
151         char *pkgfile;
152         struct pkgloc *pkg = 0;
153         int rv;
154         struct zpm localdb;
155
156         if (zpm_open(&localdb, NULL)) {
157                 installed = zpm_findpkg(&localdb, pkgstr, "status = 'installed'");
158                 if (installed) {
159                         latest = installed;
160                 }
161                 found = zpm_findpkg(&localdb, pkgstr, NULL);
162                 if (found) {
163                         rv = zpm_vercmp(found, latest);
164                         if (rv == 1) {
165                                 latest = found;
166                                 pkgfile = localdb.path;
167                         }
168                 }
169                 zpm_close(&localdb);
170         } else {
171                 fprintf(stderr, "can't open localdb\n");
172         }
173
174         glob_t repos;
175         repos.gl_offs = 0;
176         rv = glob("/var/lib/zpm/repos/*.repo", 0, NULL, &repos);
177         switch (rv) {
178                 case GLOB_NOSPACE:
179                         fprintf(stderr, "glob no mem\n");
180                         exit(EXIT_FAILURE); break;
181                 case GLOB_ABORTED:
182                         fprintf(stderr, "glob abort\n");
183                         exit(EXIT_FAILURE); break;
184                 case GLOB_NOMATCH:
185                         break;
186                 case 0:
187                                    break;
188                 default:
189                                    break;
190         }
191
192         unsigned i;
193         for (i = 0; i < repos.gl_pathc; i++) {
194                 found = checkfile(pkgstr, repos.gl_pathv[i]);
195                 if (found) {
196                         rv = zpm_vercmp(found, latest);
197                         if (rv == 1) {
198                                 latest = found;
199                                 pkgfile = repos.gl_pathv[i];
200                         }
201                 }
202         }
203
204         globfree(&repos);
205         repos.gl_offs = 0;
206
207         char *pkgdir = "/home/zoranix/zrepo/packages";
208         char *pkgglob = 0;
209
210         size_t globlen = strlen(pkgdir)+strlen(pkgstr)+7;
211         pkgglob = malloc(globlen+1);
212         snprintf(pkgglob, globlen, "%s/%s*.zpm", pkgdir, pkgstr);
213
214         rv = glob(pkgglob, 0, NULL, &repos);
215         switch (rv) {
216                 case GLOB_NOSPACE:
217                         exit(EXIT_FAILURE); break;
218                 case GLOB_ABORTED:
219                         exit(EXIT_FAILURE); break;
220                 case GLOB_NOMATCH: break;
221                 case 0:
222                                    break;
223                 default:
224                                    break;
225         }
226
227         for (i = 0; i < repos.gl_pathc; i++) {
228                 found = checkfile(pkgstr, repos.gl_pathv[i]);
229                 if (found) {
230                         rv = zpm_vercmp(found, latest);
231                         if (rv == 1) {
232                                 latest = found;
233                                 pkgfile = strdup(repos.gl_pathv[i]);
234                         }
235                 }
236         }
237
238         if (latest && pkgfile) {
239                 pkg = malloc(sizeof *pkg);
240                 pkg->id = strdup(latest);
241                 pkg->file = pkgfile;
242         }
243
244         return pkg;
245 }
246
247 char *pkglibsneeded = "\
248 with pkglibs as (\
249                 select distinct EN.needed as soname, PF.pkgid\
250                 from elfneeded EN\
251                 join packagefiles_pkgid PF on PF.hash = EN.file\
252                 ),\
253      pkgprovides as (\
254                      select distinct EL.soname, PF.pkgid\
255                      from elflibraries EL\
256                      join packagefiles_pkgid PF on PF.hash = EL.file\
257                     )\
258      select distinct PL.soname, PP.soname is not null as selfsatisfied\
259      from pkglibs PL\
260      left join pkgprovides PP on PL.pkgid = PP.pkgid and PL.soname = PP.soname\
261      where PL.pkgid = %Q\
262      ";
263
264 void checklibs(jsw_hash_t *check, jsw_hash_t *forlibs, jsw_hash_t *nfound) {
265         char *pkgid = 0, *pkgfile = 0;
266         struct zpm src;
267
268         /* checked_libs is a list of checked sonames
269          * checked is a list of checked packages
270          * needed is list of libs for package
271          */
272         jsw_atree_t *needed = 0, *checked, *checked_libs;
273
274         int libs;
275         jsw_atrav_t *i;
276         char *soname;
277         
278         checked = jsw_anew((cmp_f)strcmp, (dup_f)strdup, (rel_f)free);
279         checked_libs = jsw_anew((cmp_f)strcmp, (dup_f)strdup, (rel_f)free);
280
281         while (jsw_hsize(check) > 0) {
282                 free(pkgid);
283                 free(pkgfile);
284
285                 jsw_hreset(check);
286
287                 pkgid = strdup(jsw_hkey(check));
288                 pkgfile = strdup(jsw_hitem(check));
289
290                 if (!pkgid || !pkgfile) {
291                         break;
292                 }
293
294                 jsw_herase(check, pkgid);
295
296                 if (jsw_afind(checked, pkgid)) {
297                         /* already checked this one */
298                         continue;
299                 }
300
301                 /* we do this now so we catch self deps */
302                 jsw_ainsert(checked, pkgid);
303
304                 /* get the libraries needed by this package */
305                 if (!zpm_open(&src, pkgfile)) {
306                         fprintf(stderr, "can't zpm open %s\n", pkgfile);
307                         break;
308                 }
309
310                 if (needed) jsw_adelete(needed);
311                 needed = jsw_anew((cmp_f)strcmp, (dup_f)strdup, (rel_f)free);
312                 libs = zpm_libraries_needed(&src, pkgid, needed);
313                 zpm_close(&src);
314
315                 if (libs == 0) {
316                         continue;
317                 }
318
319                 i = jsw_atnew();
320
321                 for (soname = jsw_atfirst(i, needed); soname; soname = jsw_atnext(i)) {
322                         int found;
323                         struct pkgloc pkginfo;
324
325                         /* if it's in checked_libs, we've already looked at this one */
326                         if (jsw_afind(checked_libs, soname)) {
327                                 continue;
328                         }
329
330                         /* haven't found this soname */
331                         jsw_ainsert(checked_libs, soname);
332
333                         found = find_lib(soname, &pkginfo);
334                         if (!found) {
335                                 if (!jsw_hinsert(nfound, soname, pkgid)) {
336                                         fprintf(stderr,"insert error\n");
337                                 }
338                                 continue;
339                         }
340
341                         if (found == 1) {
342                                 /* if not alreacy checked, add to check */
343                                 if (!jsw_afind(checked, pkginfo.file)) {
344                                         jsw_hinsert(check,pkginfo.id,pkginfo.file);
345                                 }
346                                 /* shouldn't be in there already */
347                                 jsw_hinsert(forlibs, pkginfo.id, pkginfo.file);
348                         } 
349                         /* otherwise found == 2, so just continue */
350                         if (found) {
351                                 free(pkginfo.file);
352                                 free(pkginfo.id);
353                         }
354                 }
355         }
356         free(pkgid);
357         free(pkgfile);
358 }
359
360 char *pathcat(char *dir, char *path) {
361         size_t dirlen = 0, pathlen = 0;
362         char *cat;
363
364         /* chop off trailing / on dir */
365         if (dir) {
366                 dirlen = strlen(dir);
367                 while (dirlen && dir[dirlen-1] == '/') {
368                         dirlen--;
369                 }
370         }
371
372         if (path) {
373                 pathlen = strlen(path);
374                 while (*path && *path == '/') {
375                         path++;
376                         pathlen--;
377                 }
378         }
379
380         cat = malloc(dirlen + pathlen + 2);
381         if (cat) {
382                 strncpy(cat, dir, dirlen);
383                 cat[dirlen] = '/';
384                 strcpy(cat+dirlen+1, path);
385         }
386         return cat;
387 }
388
389 void print_pkghash(jsw_hash_t *hash, int json) {
390         const char *pkgid, *file;
391         char *fmt;
392         char *sep;
393         int count = 0;
394
395         fmt = json ? "\"%s\": \"%s\"" : "%s:%s";
396         sep = json ? ", " : "\n";
397
398         if (json) {
399                 printf("{ ");
400         }
401
402         if (jsw_hsize(hash) > 0) {
403                 for (jsw_hreset(hash); jsw_hitem(hash); jsw_hnext(hash)) {
404                         pkgid = jsw_hkey(hash);
405                         file = jsw_hitem(hash);
406                         if (count++) {
407                                 printf("%s", sep);
408                         }
409                         printf(fmt, pkgid, file);
410                 }
411         }
412         if (json) printf(" }");
413         printf("\n");
414 }
415
416 int main(int ac, char *av[]) {
417         int opt, argn;
418         int findlibs = 0, json = 0;
419         struct pkgloc *found;
420         jsw_hash_t *packages, *check, *forlibs, *nolib;
421         jsw_atree_t *nfound;
422
423         /* -l also find packages needed for libs
424          * -j output json
425          *  -q quiet - suppress output
426          *  -v verbose - 
427          *  -d debug - trace each step
428          *
429          *  environment:
430          *  ZPMDB - path to localdb, /var/lib/zpm/local.db
431          *  ZPM_REPO_DIR - path to *.repo files, '/var/lib/zpm/repos'
432          *  ZPM_PACKAGE_DIRS - : separated paths to *.zpm files,
433          *  '/var/lib/zpm/packages'
434          *  ZPM_ROOT_DIR :- prepends to above paths
435          *
436          *  -M (missing) invert the output and only output missing
437          *  outputs
438          *  packages found (suppress with -P)
439          *  package strings not found (suppress with -S)
440          *  library dependency packages needed and found (suppress with -N)
441          *  library dependency packages already installed (suppress with -H)
442          *  library dependency packages in install set (suppress with -I)
443          *  library dependency sonames not found (suppress with -L)
444          *
445          *  exit value is 0 if no missing libs and no bad package strings
446          *  exit value is non zero otherwise
447          */
448
449         int output = 1;
450         while ((opt = getopt(ac, av, "lj")) != -1) {
451                 switch (opt) {
452                         case 'l': findlibs = 1; break;
453                         case 'j': json = 1; break;
454                         case 'q': output = 0;
455                         default:
456                                   exit(EXIT_FAILURE);
457                                   break;
458                 }
459         }
460         argn = optind;
461
462         packages = jsw_hnew(ac,NULL,(cmp_f)strcmp,(keydup_f)strdup,
463                         (itemdup_f)strdup,free,free);
464         check = jsw_hnew(ac,NULL,(cmp_f)strcmp,(keydup_f)strdup,
465                         (itemdup_f)strdup,free,free);
466         forlibs = jsw_hnew(ac,NULL,(cmp_f)strcmp,(keydup_f)strdup,
467                         (itemdup_f)strdup,free,free);
468         nolib = jsw_hnew(ac,NULL,(cmp_f)strcmp,(keydup_f)strdup,
469                         (itemdup_f)strdup,free,free);
470         nfound = jsw_anew((cmp_f)strcmp, (dup_f)strdup, (rel_f)free);
471
472         int arg;
473         for (arg = argn; arg < ac; arg++) {
474                 found = find_package(av[arg]);
475                 if (found) {
476                         jsw_hinsert(packages, found->id, found->file);
477                         jsw_hinsert(check, found->id, found->file);
478                         free(found->id);
479                         free(found->file);
480                         free(found);
481                 } else {
482                         jsw_ainsert(nfound, av[arg]);
483                 }
484
485         }
486
487         if (findlibs) {
488                 checklibs(check, forlibs, nolib);
489         }
490
491         if (output) {
492                 print_pkghash(packages, json);
493                 print_pkghash(forlibs, json);
494         }
495
496         if (jsw_hsize(nolib) > 0) {
497                 for (jsw_hreset(nolib); jsw_hitem(nolib); jsw_hnext(nolib)) {
498                         const char *pkgid, *file;
499                         pkgid = jsw_hkey(nolib);
500                         file = jsw_hitem(nolib);
501                         fprintf(stderr, "no lib found %s:%s\n", pkgid, file);
502                 }
503         }
504
505         if (jsw_asize(nfound) > 0) {
506                 jsw_atrav_t *i;
507                 i = jsw_atnew();
508                 char *pkgstr;
509
510                 for (pkgstr = jsw_atfirst(i, nfound); pkgstr; pkgstr = jsw_atnext(i)) {
511                         fprintf(stderr, "%s:\n", pkgstr);
512                 }
513         }
514
515         return jsw_asize(nfound) > 0 || jsw_hsize(nolib) > 0 ? 1 : 0;
516 }