1 /*
2 * core.c
3 * core, printer functions
4 *
5 * SPDX-License-Identifier: pkgconf
6 *
7 * Copyright (c) 2011-2025 pkgconf authors (see AUTHORS).
8 *
9 * Permission to use, copy, modify, and/or distribute this software for any
10 * purpose with or without fee is hereby granted, provided that the above
11 * copyright notice and this permission notice appear in all copies.
12 *
13 * This software is provided 'as is' and without any warranty, express or
14 * implied. In no event shall the authors be liable for any damages arising
15 * from the use of this software.
16 */
17
18 #include "libpkgconf/config.h"
19 #include <libpkgconf/stdinc.h>
20 #include <libpkgconf/libpkgconf.h>
21 #include "core.h"
22 #include "getopt_long.h"
23 #ifndef PKGCONF_LITE
24 #include "renderer-msvc.h"
25 #endif
26
27 static bool
print_list_entry(const pkgconf_pkg_t * entry,void * data)28 print_list_entry(const pkgconf_pkg_t *entry, void *data)
29 {
30 const pkgconf_node_t *n;
31 pkgconf_client_t *client = data;
32
33 if (entry->flags & PKGCONF_PKG_PROPF_UNINSTALLED)
34 return false;
35
36 pkgconf_output_fmt(client->output, PKGCONF_OUTPUT_STDOUT,
37 "%-30s %s - %s\n", entry->id, entry->realname, entry->description);
38
39 PKGCONF_FOREACH_LIST_ENTRY(entry->provides.head, n)
40 {
41 const pkgconf_dependency_t *dep = n->data;
42
43 if (!strcmp(dep->package, entry->id))
44 continue;
45
46 pkgconf_output_fmt(client->output, PKGCONF_OUTPUT_STDOUT,
47 "%-30s %s - %s (provided by %s)\n", dep->package, entry->realname, entry->description, entry->id);
48 }
49
50 return false;
51 }
52
53 static bool
print_package_entry(const pkgconf_pkg_t * entry,void * data)54 print_package_entry(const pkgconf_pkg_t *entry, void *data)
55 {
56 const pkgconf_node_t *n;
57 pkgconf_client_t *client = data;
58
59 if (entry->flags & PKGCONF_PKG_PROPF_UNINSTALLED)
60 return false;
61
62 pkgconf_output_puts(client->output, PKGCONF_OUTPUT_STDOUT, entry->id);
63
64 PKGCONF_FOREACH_LIST_ENTRY(entry->provides.head, n)
65 {
66 const pkgconf_dependency_t *dep = n->data;
67
68 if (!strcmp(dep->package, entry->id))
69 continue;
70
71 pkgconf_output_puts(client->output, PKGCONF_OUTPUT_STDOUT, dep->package);
72 }
73
74 return false;
75 }
76
77 static bool
filter_cflags(const pkgconf_client_t * client,const pkgconf_fragment_t * frag,void * data)78 filter_cflags(const pkgconf_client_t *client, const pkgconf_fragment_t *frag, void *data)
79 {
80 int got_flags = 0;
81 pkgconf_cli_state_t *state = client->client_data;
82 (void) data;
83
84 if (!(state->want_flags & PKG_KEEP_SYSTEM_CFLAGS) && pkgconf_fragment_has_system_dir(client, frag))
85 return false;
86
87 if (state->want_fragment_filter != NULL && (strchr(state->want_fragment_filter, frag->type) == NULL || !frag->type))
88 return false;
89
90 if (frag->type == 'I')
91 got_flags = PKG_CFLAGS_ONLY_I;
92 else
93 got_flags = PKG_CFLAGS_ONLY_OTHER;
94
95 return (state->want_flags & got_flags) != 0;
96 }
97
98 static bool
filter_libs(const pkgconf_client_t * client,const pkgconf_fragment_t * frag,void * data)99 filter_libs(const pkgconf_client_t *client, const pkgconf_fragment_t *frag, void *data)
100 {
101 int got_flags = 0;
102 pkgconf_cli_state_t *state = client->client_data;
103 (void) data;
104
105 if (!(state->want_flags & PKG_KEEP_SYSTEM_LIBS) && pkgconf_fragment_has_system_dir(client, frag))
106 return false;
107
108 if (state->want_fragment_filter != NULL && (strchr(state->want_fragment_filter, frag->type) == NULL || !frag->type))
109 return false;
110
111 switch (frag->type)
112 {
113 case 'L': got_flags = PKG_LIBS_ONLY_LDPATH; break;
114 case 'l': got_flags = PKG_LIBS_ONLY_LIBNAME; break;
115 default: got_flags = PKG_LIBS_ONLY_OTHER; break;
116 }
117
118 return (state->want_flags & got_flags) != 0;
119 }
120
121 static void
print_variables(pkgconf_output_t * output,pkgconf_pkg_t * pkg)122 print_variables(pkgconf_output_t *output, pkgconf_pkg_t *pkg)
123 {
124 pkgconf_node_t *node;
125
126 PKGCONF_FOREACH_LIST_ENTRY(pkg->vars.head, node)
127 {
128 pkgconf_tuple_t *tuple = node->data;
129
130 pkgconf_output_puts(output, PKGCONF_OUTPUT_STDOUT, tuple->key);
131 }
132 }
133
134 static void
print_dependency_list(pkgconf_output_t * output,pkgconf_list_t * list)135 print_dependency_list(pkgconf_output_t *output, pkgconf_list_t *list)
136 {
137 pkgconf_node_t *node;
138
139 PKGCONF_FOREACH_LIST_ENTRY(list->head, node)
140 {
141 pkgconf_dependency_t *dep = node->data;
142
143 pkgconf_output_fmt(output, PKGCONF_OUTPUT_STDOUT, "%s", dep->package);
144
145 if (dep->version != NULL)
146 pkgconf_output_fmt(output, PKGCONF_OUTPUT_STDOUT, " %s %s",
147 pkgconf_pkg_get_comparator(dep), dep->version);
148
149 pkgconf_output_fmt(output, PKGCONF_OUTPUT_STDOUT, "\n");
150 }
151 }
152
153 static bool
apply_provides(pkgconf_client_t * client,pkgconf_pkg_t * world,void * unused,int maxdepth)154 apply_provides(pkgconf_client_t *client, pkgconf_pkg_t *world, void *unused, int maxdepth)
155 {
156 pkgconf_node_t *iter;
157 (void) unused;
158 (void) maxdepth;
159
160 PKGCONF_FOREACH_LIST_ENTRY(world->required.head, iter)
161 {
162 pkgconf_dependency_t *dep = iter->data;
163 pkgconf_pkg_t *pkg = dep->match;
164
165 print_dependency_list(client->output, &pkg->provides);
166 }
167
168 return true;
169 }
170
171 #ifndef PKGCONF_LITE
172 static void
print_digraph_node(pkgconf_client_t * client,pkgconf_pkg_t * pkg,void * data)173 print_digraph_node(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *data)
174 {
175 pkgconf_node_t *node;
176 pkgconf_pkg_t **last_seen = data;
177
178 if (pkg->flags & PKGCONF_PKG_PROPF_VIRTUAL)
179 return;
180
181 pkgconf_output_fmt(client->output, PKGCONF_OUTPUT_STDOUT, "\"%s\" [fontname=Sans fontsize=8", pkg->id);
182
183 if (pkg->flags & PKGCONF_PKG_PROPF_VISITED_PRIVATE)
184 pkgconf_output_fmt(client->output, PKGCONF_OUTPUT_STDOUT, " fontcolor=gray color=gray");
185
186 pkgconf_output_fmt(client->output, PKGCONF_OUTPUT_STDOUT, " label=\"%s@%s\"]\n", pkg->id, pkg->version);
187
188 if (last_seen != NULL)
189 {
190 if (*last_seen != NULL)
191 pkgconf_output_fmt(client->output, PKGCONF_OUTPUT_STDOUT,
192 "\"%s\" -> \"%s\" [fontname=Sans fontsize=8 color=red]\n", (*last_seen)->id, pkg->id);
193
194 *last_seen = pkg;
195 }
196
197 PKGCONF_FOREACH_LIST_ENTRY(pkg->required.head, node)
198 {
199 pkgconf_dependency_t *dep = node->data;
200 const char *dep_id = (dep->match != NULL) ? dep->match->id : dep->package;
201
202 pkgconf_output_fmt(client->output, PKGCONF_OUTPUT_STDOUT, "\"%s\" -> \"%s\" [fontname=Sans fontsize=8",
203 pkg->id, dep_id);
204
205 if (dep->flags & PKGCONF_PKG_DEPF_PRIVATE)
206 pkgconf_output_fmt(client->output, PKGCONF_OUTPUT_STDOUT, " color=gray");
207
208 pkgconf_output_puts(client->output, PKGCONF_OUTPUT_STDOUT, "]");
209 }
210
211 PKGCONF_FOREACH_LIST_ENTRY(pkg->requires_private.head, node)
212 {
213 pkgconf_dependency_t *dep = node->data;
214 const char *dep_id = (dep->match != NULL) ? dep->match->id : dep->package;
215
216 pkgconf_output_fmt(client->output, PKGCONF_OUTPUT_STDOUT,
217 "\"%s\" -> \"%s\" [fontname=Sans fontsize=8 color=gray]\n", pkg->id, dep_id);
218 }
219
220 if (!(client->flags & PKGCONF_PKG_PKGF_MERGE_PRIVATE_FRAGMENTS))
221 {
222 PKGCONF_FOREACH_LIST_ENTRY(pkg->requires_shared.head, node)
223 {
224 pkgconf_dependency_t *dep = node->data;
225 const char *dep_id = (dep->match != NULL) ? dep->match->id : dep->package;
226 pkgconf_output_fmt(client->output, PKGCONF_OUTPUT_STDOUT,
227 "\"%s\" -> \"%s\" [fontname=Sans fontsize=8 color=orange]\n", pkg->id, dep_id);
228 }
229 }
230 }
231
232 static bool
apply_digraph(pkgconf_client_t * client,pkgconf_pkg_t * world,void * data,int maxdepth)233 apply_digraph(pkgconf_client_t *client, pkgconf_pkg_t *world, void *data, int maxdepth)
234 {
235 int eflag;
236 pkgconf_cli_state_t *state = client->client_data;
237 pkgconf_list_t *list = data;
238 pkgconf_pkg_t *last_seen = NULL;
239 pkgconf_node_t *iter;
240
241 pkgconf_output_puts(client->output, PKGCONF_OUTPUT_STDOUT,
242 "digraph deptree {\n"
243 "edge [color=blue len=7.5 fontname=Sans fontsize=8]\n"
244 "node [fontname=Sans fontsize=8]\n");
245
246 if (state->want_flags & PKG_PRINT_DIGRAPH_QUERY_NODES)
247 {
248 pkgconf_output_puts(client->output, PKGCONF_OUTPUT_STDOUT,
249 "\"user:request\" [fontname=Sans fontsize=8]\n");
250
251 PKGCONF_FOREACH_LIST_ENTRY(list->head, iter)
252 {
253 pkgconf_queue_t *pkgq = iter->data;
254 pkgconf_pkg_t *pkg = pkgconf_pkg_find(client, pkgq->package);
255
256 pkgconf_output_fmt(client->output, PKGCONF_OUTPUT_STDOUT,
257 "\"user:request\" -> \"%s\" [fontname=Sans fontsize=8]\n",
258 pkg == NULL ? pkgq->package : pkg->id);
259
260 if (pkg != NULL)
261 pkgconf_pkg_unref(client, pkg);
262 }
263 }
264
265 eflag = pkgconf_pkg_traverse(client, world, print_digraph_node, &last_seen, maxdepth, 0);
266
267 if (eflag != PKGCONF_PKG_ERRF_OK)
268 return false;
269
270 pkgconf_output_puts(client->output, PKGCONF_OUTPUT_STDOUT, "}");
271 return true;
272 }
273
274 static void
print_solution_node(pkgconf_client_t * client,pkgconf_pkg_t * pkg,void * unused)275 print_solution_node(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *unused)
276 {
277 (void) unused;
278
279 pkgconf_output_fmt(client->output, PKGCONF_OUTPUT_STDOUT, "%s (%llu)%s\n",
280 pkg->id, (unsigned long long) pkg->identifier,
281 (pkg->flags & PKGCONF_PKG_PROPF_VISITED_PRIVATE) == PKGCONF_PKG_PROPF_VISITED_PRIVATE ? " [private]" : "");
282 }
283
284 static bool
apply_print_solution(pkgconf_client_t * client,pkgconf_pkg_t * world,void * unused,int maxdepth)285 apply_print_solution(pkgconf_client_t *client, pkgconf_pkg_t *world, void *unused, int maxdepth)
286 {
287 int eflag;
288
289 eflag = pkgconf_pkg_traverse(client, world, print_solution_node, unused, maxdepth, 0);
290
291 return eflag == PKGCONF_PKG_ERRF_OK;
292 }
293 #endif
294
295 static bool
apply_modversion(pkgconf_client_t * client,pkgconf_pkg_t * world,void * data,int maxdepth)296 apply_modversion(pkgconf_client_t *client, pkgconf_pkg_t *world, void *data, int maxdepth)
297 {
298 pkgconf_cli_state_t *state = client->client_data;
299 pkgconf_node_t *queue_iter;
300 pkgconf_list_t *pkgq = data;
301 (void) maxdepth;
302
303 PKGCONF_FOREACH_LIST_ENTRY(pkgq->head, queue_iter)
304 {
305 pkgconf_node_t *world_iter;
306 pkgconf_queue_t *queue_node = queue_iter->data;
307
308 PKGCONF_FOREACH_LIST_ENTRY(world->required.head, world_iter)
309 {
310 pkgconf_dependency_t *dep = world_iter->data;
311 pkgconf_pkg_t *pkg = dep->match;
312
313 const size_t name_len = strlen(pkg->why);
314 if (name_len > strlen(queue_node->package) ||
315 strncmp(pkg->why, queue_node->package, name_len) ||
316 (queue_node->package[name_len] != 0 &&
317 !isspace((unsigned char)queue_node->package[name_len]) &&
318 !PKGCONF_IS_OPERATOR_CHAR(queue_node->package[name_len])))
319 {
320 continue;
321 }
322
323 if (pkg->version != NULL) {
324 if (state->verbosity)
325 pkgconf_output_fmt(client->output, PKGCONF_OUTPUT_STDOUT, "%s: ", pkg->id);
326
327 pkgconf_output_puts(client->output, PKGCONF_OUTPUT_STDOUT, pkg->version);
328 }
329
330 break;
331 }
332 }
333
334 return true;
335 }
336
337 static bool
apply_variables(pkgconf_client_t * client,pkgconf_pkg_t * world,void * unused,int maxdepth)338 apply_variables(pkgconf_client_t *client, pkgconf_pkg_t *world, void *unused, int maxdepth)
339 {
340 pkgconf_node_t *iter;
341 (void) unused;
342 (void) maxdepth;
343
344 PKGCONF_FOREACH_LIST_ENTRY(world->required.head, iter)
345 {
346 pkgconf_dependency_t *dep = iter->data;
347 pkgconf_pkg_t *pkg = dep->match;
348
349 print_variables(client->output, pkg);
350 }
351
352 return true;
353 }
354
355 static bool
apply_path(pkgconf_client_t * client,pkgconf_pkg_t * world,void * unused,int maxdepth)356 apply_path(pkgconf_client_t *client, pkgconf_pkg_t *world, void *unused, int maxdepth)
357 {
358 pkgconf_node_t *iter;
359 (void) unused;
360 (void) maxdepth;
361
362 PKGCONF_FOREACH_LIST_ENTRY(world->required.head, iter)
363 {
364 pkgconf_dependency_t *dep = iter->data;
365 pkgconf_pkg_t *pkg = dep->match;
366
367 /* a module entry with no filename is either virtual, static (builtin) or synthesized. */
368 if (pkg->filename != NULL)
369 pkgconf_output_puts(client->output, PKGCONF_OUTPUT_STDOUT, pkg->filename);
370 }
371
372 return true;
373 }
374
375 static char *
variable_eval(pkgconf_client_t * client,const pkgconf_list_t * vars,const char * varname)376 variable_eval(pkgconf_client_t *client, const pkgconf_list_t *vars, const char *varname)
377 {
378 pkgconf_buffer_t varbuf = PKGCONF_BUFFER_INITIALIZER;
379 const pkgconf_buffer_t *sysroot_dir = PKGCONF_BUFFER_FROM_STR(client->sysroot_dir);
380 bool saw_sysroot = false;
381 pkgconf_variable_t *v;
382
383 pkgconf_bytecode_eval_ctx_t ctx = {
384 .client = client,
385 .vars = vars,
386 };
387
388 v = pkgconf_bytecode_eval_lookup_var(&ctx, varname, strlen(varname));
389 (void) pkgconf_variable_eval(client, vars, v, &varbuf, &saw_sysroot);
390
391 if (!saw_sysroot && pkgconf_path_is_plausible(&varbuf))
392 {
393 /* if sysroot is set, and value does not already begin with sysroot */
394 if (!pkgconf_buffer_has_prefix(&varbuf, sysroot_dir))
395 pkgconf_buffer_prepend(&varbuf, pkgconf_buffer_str_or_empty(sysroot_dir));
396 }
397
398 return pkgconf_buffer_freeze(&varbuf);
399 }
400
401 static bool
apply_variable(pkgconf_client_t * client,pkgconf_pkg_t * world,const void * variable,int maxdepth)402 apply_variable(pkgconf_client_t *client, pkgconf_pkg_t *world, const void *variable, int maxdepth)
403 {
404 pkgconf_node_t *iter;
405 (void) maxdepth;
406
407 PKGCONF_FOREACH_LIST_ENTRY(world->required.head, iter)
408 {
409 pkgconf_dependency_t *dep = iter->data;
410 pkgconf_pkg_t *pkg = dep->match;
411 char *result;
412
413 if (pkg == NULL)
414 continue;
415
416 result = variable_eval(client, &pkg->vars, variable);
417
418 if (result != NULL)
419 {
420 pkgconf_output_fmt(client->output, PKGCONF_OUTPUT_STDOUT,
421 "%s%s", iter->prev != NULL ? " " : "", result);
422 free(result);
423 }
424 }
425
426 pkgconf_output_puts(client->output, PKGCONF_OUTPUT_STDOUT, "");
427
428 return true;
429 }
430
431 static bool
apply_env_var(const char * prefix,pkgconf_client_t * client,pkgconf_pkg_t * world,int maxdepth,unsigned int (* collect_fn)(pkgconf_client_t * client,pkgconf_pkg_t * world,pkgconf_list_t * list,int maxdepth),bool (* filter_fn)(const pkgconf_client_t * client,const pkgconf_fragment_t * frag,void * data),void (* postprocess_fn)(pkgconf_client_t * client,pkgconf_pkg_t * world,pkgconf_list_t * fragment_list))432 apply_env_var(const char *prefix, pkgconf_client_t *client, pkgconf_pkg_t *world, int maxdepth,
433 unsigned int (*collect_fn)(pkgconf_client_t *client, pkgconf_pkg_t *world, pkgconf_list_t *list, int maxdepth),
434 bool (*filter_fn)(const pkgconf_client_t *client, const pkgconf_fragment_t *frag, void *data),
435 void (*postprocess_fn)(pkgconf_client_t *client, pkgconf_pkg_t *world, pkgconf_list_t *fragment_list))
436 {
437 pkgconf_cli_state_t *state = client->client_data;
438 pkgconf_list_t unfiltered_list = PKGCONF_LIST_INITIALIZER;
439 pkgconf_list_t filtered_list = PKGCONF_LIST_INITIALIZER;
440 pkgconf_buffer_t render_buf = PKGCONF_BUFFER_INITIALIZER;
441 unsigned int eflag;
442
443 eflag = collect_fn(client, world, &unfiltered_list, maxdepth);
444 if (eflag != PKGCONF_PKG_ERRF_OK)
445 return false;
446
447 pkgconf_fragment_filter(client, &filtered_list, &unfiltered_list, filter_fn, NULL);
448
449 if (postprocess_fn != NULL)
450 postprocess_fn(client, world, &filtered_list);
451
452 if (filtered_list.head == NULL)
453 goto out;
454
455 pkgconf_fragment_render_buf(&filtered_list, &render_buf, true, state->want_render_ops, (state->want_flags & PKG_NEWLINES) ? '\n' : ' ');
456 pkgconf_output_fmt(client->output, PKGCONF_OUTPUT_STDOUT, "%s='%s'\n",
457 prefix, pkgconf_buffer_str_or_empty(&render_buf));
458 pkgconf_buffer_finalize(&render_buf);
459
460 out:
461 pkgconf_fragment_free(&unfiltered_list);
462 pkgconf_fragment_free(&filtered_list);
463
464 return true;
465 }
466
467 static void
maybe_add_module_definitions(pkgconf_client_t * client,pkgconf_pkg_t * world,pkgconf_list_t * fragment_list)468 maybe_add_module_definitions(pkgconf_client_t *client, pkgconf_pkg_t *world, pkgconf_list_t *fragment_list)
469 {
470 pkgconf_node_t *world_iter;
471 pkgconf_cli_state_t *state = client->client_data;
472
473 if ((state->want_flags & PKG_EXISTS_CFLAGS) != PKG_EXISTS_CFLAGS)
474 return;
475
476 PKGCONF_FOREACH_LIST_ENTRY(world->required.head, world_iter)
477 {
478 pkgconf_dependency_t *dep = world_iter->data;
479 char havebuf[PKGCONF_ITEM_SIZE];
480 char *p;
481
482 if ((dep->flags & PKGCONF_PKG_DEPF_QUERY) != PKGCONF_PKG_DEPF_QUERY)
483 continue;
484
485 if (dep->match == NULL)
486 continue;
487
488 snprintf(havebuf, sizeof havebuf, "HAVE_%s", dep->match->id);
489
490 for (p = havebuf; *p; p++)
491 {
492 switch (*p)
493 {
494 case ' ':
495 case '-':
496 *p = '_';
497 break;
498
499 default:
500 *p = (char) toupper((unsigned char) *p);
501 }
502 }
503
504 pkgconf_fragment_insert(client, fragment_list, 'D', havebuf, false);
505 }
506 }
507
508 static void
apply_env_variables(pkgconf_client_t * client,pkgconf_pkg_t * world,const char * env_prefix)509 apply_env_variables(pkgconf_client_t *client, pkgconf_pkg_t *world, const char *env_prefix)
510 {
511 pkgconf_node_t *world_iter;
512 pkgconf_cli_state_t *state = client->client_data;
513
514 PKGCONF_FOREACH_LIST_ENTRY(world->required.head, world_iter)
515 {
516 pkgconf_dependency_t *dep = world_iter->data;
517 pkgconf_pkg_t *pkg = dep->match;
518 pkgconf_node_t *tuple_iter;
519
520 if ((dep->flags & PKGCONF_PKG_DEPF_QUERY) != PKGCONF_PKG_DEPF_QUERY)
521 continue;
522
523 if (dep->match == NULL)
524 continue;
525
526 PKGCONF_FOREACH_LIST_ENTRY(pkg->vars.head, tuple_iter)
527 {
528 pkgconf_tuple_t *tuple = tuple_iter->data;
529 char havebuf[PKGCONF_ITEM_SIZE];
530 char *p;
531
532 if (state->want_variable != NULL && strcmp(state->want_variable, tuple->key))
533 continue;
534
535 snprintf(havebuf, sizeof havebuf, "%s_%s", env_prefix, tuple->key);
536
537 for (p = havebuf; *p; p++)
538 {
539 switch (*p)
540 {
541 case ' ':
542 case '-':
543 *p = '_';
544 break;
545
546 default:
547 *p = (char) toupper((unsigned char) *p);
548 }
549 }
550
551 char *val = pkgconf_variable_eval_str(client, &pkg->vars, tuple, NULL);
552 pkgconf_output_fmt(client->output, PKGCONF_OUTPUT_STDOUT,
553 "%s='%s'\n", havebuf, val);
554 free(val);
555 }
556 }
557 }
558
559 static bool
apply_env(pkgconf_client_t * client,pkgconf_pkg_t * world,const void * env_prefix_p,int maxdepth)560 apply_env(pkgconf_client_t *client, pkgconf_pkg_t *world, const void *env_prefix_p, int maxdepth)
561 {
562 pkgconf_cli_state_t *state = client->client_data;
563 const char *want_env_prefix = env_prefix_p, *it;
564 char workbuf[PKGCONF_ITEM_SIZE];
565
566 for (it = want_env_prefix; *it != '\0'; it++)
567 if (!isalpha((unsigned char)*it) &&
568 !isdigit((unsigned char)*it))
569 {
570 return false;
571 }
572
573 snprintf(workbuf, sizeof workbuf, "%s_CFLAGS", want_env_prefix);
574 if (!apply_env_var(workbuf, client, world, maxdepth, pkgconf_pkg_cflags, filter_cflags, maybe_add_module_definitions))
575 return false;
576
577 snprintf(workbuf, sizeof workbuf, "%s_LIBS", want_env_prefix);
578 if (!apply_env_var(workbuf, client, world, maxdepth, pkgconf_pkg_libs, filter_libs, NULL))
579 return false;
580
581 if ((state->want_flags & PKG_VARIABLES) == PKG_VARIABLES || state->want_variable != NULL)
582 apply_env_variables(client, world, want_env_prefix);
583
584 return true;
585 }
586
587 static bool
apply_cflags(pkgconf_client_t * client,pkgconf_pkg_t * world,pkgconf_list_t * target_list,int maxdepth)588 apply_cflags(pkgconf_client_t *client, pkgconf_pkg_t *world, pkgconf_list_t *target_list, int maxdepth)
589 {
590 pkgconf_list_t unfiltered_list = PKGCONF_LIST_INITIALIZER;
591 pkgconf_list_t filtered_list = PKGCONF_LIST_INITIALIZER;
592 int eflag;
593
594 eflag = pkgconf_pkg_cflags(client, world, &unfiltered_list, maxdepth);
595 if (eflag != PKGCONF_PKG_ERRF_OK)
596 return false;
597
598 pkgconf_fragment_filter(client, &filtered_list, &unfiltered_list, filter_cflags, NULL);
599 maybe_add_module_definitions(client, world, &filtered_list);
600
601 if (filtered_list.head == NULL)
602 goto out;
603
604 pkgconf_fragment_copy_list(client, target_list, &filtered_list);
605
606 out:
607 pkgconf_fragment_free(&unfiltered_list);
608 pkgconf_fragment_free(&filtered_list);
609
610 return true;
611 }
612
613 static bool
apply_libs(pkgconf_client_t * client,pkgconf_pkg_t * world,pkgconf_list_t * target_list,int maxdepth)614 apply_libs(pkgconf_client_t *client, pkgconf_pkg_t *world, pkgconf_list_t *target_list, int maxdepth)
615 {
616 pkgconf_list_t unfiltered_list = PKGCONF_LIST_INITIALIZER;
617 pkgconf_list_t filtered_list = PKGCONF_LIST_INITIALIZER;
618 int eflag;
619
620 eflag = pkgconf_pkg_libs(client, world, &unfiltered_list, maxdepth);
621 if (eflag != PKGCONF_PKG_ERRF_OK)
622 return false;
623
624 pkgconf_fragment_filter(client, &filtered_list, &unfiltered_list, filter_libs, NULL);
625
626 if (filtered_list.head == NULL)
627 goto out;
628
629 pkgconf_fragment_copy_list(client, target_list, &filtered_list);
630
631 out:
632 pkgconf_fragment_free(&unfiltered_list);
633 pkgconf_fragment_free(&filtered_list);
634
635 return true;
636 }
637
638 static bool
apply_requires(pkgconf_client_t * client,pkgconf_pkg_t * world,void * unused,int maxdepth)639 apply_requires(pkgconf_client_t *client, pkgconf_pkg_t *world, void *unused, int maxdepth)
640 {
641 pkgconf_node_t *iter;
642 (void) unused;
643 (void) maxdepth;
644
645 PKGCONF_FOREACH_LIST_ENTRY(world->required.head, iter)
646 {
647 pkgconf_dependency_t *dep = iter->data;
648 pkgconf_pkg_t *pkg = dep->match;
649
650 print_dependency_list(client->output, &pkg->required);
651 }
652
653 return true;
654 }
655
656 static bool
apply_requires_private(pkgconf_client_t * client,pkgconf_pkg_t * world,void * unused,int maxdepth)657 apply_requires_private(pkgconf_client_t *client, pkgconf_pkg_t *world, void *unused, int maxdepth)
658 {
659 pkgconf_node_t *iter;
660 (void) unused;
661 (void) maxdepth;
662
663 PKGCONF_FOREACH_LIST_ENTRY(world->required.head, iter)
664 {
665 pkgconf_dependency_t *dep = iter->data;
666 pkgconf_pkg_t *pkg = dep->match;
667
668 print_dependency_list(client->output, &pkg->requires_private);
669 }
670 return true;
671 }
672
673 static void
check_uninstalled(pkgconf_client_t * client,pkgconf_pkg_t * pkg,void * data)674 check_uninstalled(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *data)
675 {
676 int *retval = data;
677 (void) client;
678
679 if (pkg->flags & PKGCONF_PKG_PROPF_UNINSTALLED)
680 *retval = EXIT_SUCCESS;
681 }
682
683 static bool
apply_uninstalled(pkgconf_client_t * client,pkgconf_pkg_t * world,void * data,int maxdepth)684 apply_uninstalled(pkgconf_client_t *client, pkgconf_pkg_t *world, void *data, int maxdepth)
685 {
686 int eflag;
687
688 eflag = pkgconf_pkg_traverse(client, world, check_uninstalled, data, maxdepth, 0);
689
690 if (eflag != PKGCONF_PKG_ERRF_OK)
691 return false;
692
693 return true;
694 }
695
696 #ifndef PKGCONF_LITE
697 static void
print_graph_node(pkgconf_client_t * client,pkgconf_pkg_t * pkg,void * data)698 print_graph_node(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *data)
699 {
700 pkgconf_node_t *n;
701
702 (void) data;
703
704 pkgconf_output_fmt(client->output, PKGCONF_OUTPUT_STDOUT, "node '%s' {\n", pkg->id);
705
706 if (pkg->version != NULL)
707 pkgconf_output_fmt(client->output, PKGCONF_OUTPUT_STDOUT, " version = '%s';\n", pkg->version);
708
709 PKGCONF_FOREACH_LIST_ENTRY(pkg->required.head, n)
710 {
711 pkgconf_dependency_t *dep = n->data;
712
713 pkgconf_output_fmt(client->output, PKGCONF_OUTPUT_STDOUT, " dependency '%s'", dep->package);
714
715 if (dep->compare != PKGCONF_CMP_ANY)
716 {
717 pkgconf_output_fmt(client->output, PKGCONF_OUTPUT_STDOUT,
718 " {\n"
719 " comparator = '%s';\n"
720 " version = '%s';\n"
721 " };\n",
722 pkgconf_pkg_get_comparator(dep), dep->version);
723 }
724 else
725 pkgconf_output_puts(client->output, PKGCONF_OUTPUT_STDOUT, ";");
726 }
727
728 pkgconf_output_puts(client->output, PKGCONF_OUTPUT_STDOUT, "};");
729 }
730
731 static bool
apply_simulate(pkgconf_client_t * client,pkgconf_pkg_t * world,void * data,int maxdepth)732 apply_simulate(pkgconf_client_t *client, pkgconf_pkg_t *world, void *data, int maxdepth)
733 {
734 int eflag;
735
736 eflag = pkgconf_pkg_traverse(client, world, print_graph_node, data, maxdepth, 0);
737
738 if (eflag != PKGCONF_PKG_ERRF_OK)
739 return false;
740
741 return true;
742 }
743 #endif
744
745 static void
print_fragment_tree_branch(pkgconf_output_t * output,pkgconf_list_t * fragment_list,int indent)746 print_fragment_tree_branch(pkgconf_output_t *output, pkgconf_list_t *fragment_list, int indent)
747 {
748 pkgconf_node_t *iter;
749
750 PKGCONF_FOREACH_LIST_ENTRY(fragment_list->head, iter)
751 {
752 pkgconf_fragment_t *frag = iter->data;
753
754 if (frag->type)
755 pkgconf_output_fmt(output, PKGCONF_OUTPUT_STDOUT,
756 "%*s'-%c%s' [type %c, " SIZE_FMT_SPECIFIER " children]\n", indent, "", frag->type, frag->data, frag->type, frag->children.length);
757 else
758 pkgconf_output_fmt(output, PKGCONF_OUTPUT_STDOUT,
759 "%*s'%s' [untyped, " SIZE_FMT_SPECIFIER " children]\n", indent, "", frag->data, frag->children.length);
760
761 print_fragment_tree_branch(output, &frag->children, indent + 2);
762 }
763
764 if (fragment_list->head != NULL)
765 pkgconf_output_puts(output, PKGCONF_OUTPUT_STDOUT, "");
766 }
767
768 static bool
apply_fragment_tree(pkgconf_client_t * client,pkgconf_pkg_t * world,void * data,int maxdepth)769 apply_fragment_tree(pkgconf_client_t *client, pkgconf_pkg_t *world, void *data, int maxdepth)
770 {
771 pkgconf_list_t unfiltered_list = PKGCONF_LIST_INITIALIZER;
772 int eflag;
773
774 (void) data;
775
776 eflag = pkgconf_pkg_cflags(client, world, &unfiltered_list, maxdepth);
777 if (eflag != PKGCONF_PKG_ERRF_OK)
778 return false;
779
780 eflag = pkgconf_pkg_libs(client, world, &unfiltered_list, maxdepth);
781 if (eflag != PKGCONF_PKG_ERRF_OK)
782 return false;
783
784 print_fragment_tree_branch(client->output, &unfiltered_list, 0);
785 pkgconf_fragment_free(&unfiltered_list);
786
787 return true;
788 }
789
790 static void
print_license(pkgconf_client_t * client,pkgconf_pkg_t * pkg,void * data)791 print_license(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *data)
792 {
793 pkgconf_buffer_t render_buf = PKGCONF_BUFFER_INITIALIZER;
794 (void) data;
795
796 if (pkg->flags & PKGCONF_PKG_PROPF_VIRTUAL)
797 return;
798
799 if (pkg->license.head == NULL)
800 {
801 pkgconf_output_fmt(client->output, PKGCONF_OUTPUT_STDOUT,
802 "%s: NOASSERTION\n", pkg->id);
803 }
804 else
805 {
806 /* NOASSERTION is the default when the license is unknown, per SPDX spec § 3.15 */
807 pkgconf_license_render(client, &pkg->license, &render_buf);
808 pkgconf_output_fmt(client->output, PKGCONF_OUTPUT_STDOUT, "%s: ", pkg->id);
809 pkgconf_output_putbuf(client->output, PKGCONF_OUTPUT_STDOUT, &render_buf, true);
810 pkgconf_buffer_finalize(&render_buf);
811 }
812 }
813
814 static bool
apply_license(pkgconf_client_t * client,pkgconf_pkg_t * world,void * data,int maxdepth)815 apply_license(pkgconf_client_t *client, pkgconf_pkg_t *world, void *data, int maxdepth)
816 {
817 int eflag;
818
819 eflag = pkgconf_pkg_traverse(client, world, print_license, data, maxdepth, 0);
820
821 if (eflag != PKGCONF_PKG_ERRF_OK)
822 return false;
823
824 return true;
825 }
826
827 static bool
apply_link_abi(pkgconf_client_t * client,pkgconf_pkg_t * world,void * data,int maxdepth)828 apply_link_abi(pkgconf_client_t *client, pkgconf_pkg_t *world, void *data, int maxdepth)
829 {
830 pkgconf_list_t abis = PKGCONF_LIST_INITIALIZER;
831 pkgconf_buffer_t render_buf = PKGCONF_BUFFER_INITIALIZER;
832 pkgconf_node_t *node;
833 int *retval = data;
834
835 if (pkgconf_pkg_link_abi(client, world, &abis, maxdepth) != PKGCONF_PKG_ERRF_OK)
836 {
837 pkgconf_bufferset_free(&abis);
838 *retval = EXIT_FAILURE;
839 return false;
840 }
841
842 PKGCONF_FOREACH_LIST_ENTRY(abis.head, node)
843 {
844 pkgconf_bufferset_t *tag = node->data;
845
846 if (pkgconf_buffer_len(&render_buf))
847 pkgconf_buffer_push_byte(&render_buf, ' ');
848
849 pkgconf_buffer_append(&render_buf, pkgconf_buffer_str(&tag->buffer));
850 }
851
852 pkgconf_output_putbuf(client->output, PKGCONF_OUTPUT_STDOUT, &render_buf, true);
853
854 pkgconf_buffer_finalize(&render_buf);
855 pkgconf_bufferset_free(&abis);
856
857 return true;
858 }
859
860 static void
print_license_file(pkgconf_client_t * client,pkgconf_pkg_t * pkg,void * data)861 print_license_file(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *data)
862 {
863 (void) data;
864
865 if (pkg->flags & PKGCONF_PKG_PROPF_VIRTUAL)
866 return;
867
868 /* If license file location is not available then just print empty */
869 pkgconf_output_fmt(client->output, PKGCONF_OUTPUT_STDOUT, "%s: %s\n",
870 pkg->id, pkg->license_file != NULL ? pkg->license_file : "");
871 }
872
873 static bool
apply_license_file(pkgconf_client_t * client,pkgconf_pkg_t * world,void * data,int maxdepth)874 apply_license_file(pkgconf_client_t *client, pkgconf_pkg_t *world, void *data, int maxdepth)
875 {
876 int eflag;
877
878 eflag = pkgconf_pkg_traverse(client, world, print_license_file, data, maxdepth, 0);
879
880 if (eflag != PKGCONF_PKG_ERRF_OK)
881 return false;
882
883 return true;
884 }
885
886 static void
print_source(pkgconf_client_t * client,pkgconf_pkg_t * pkg,void * data)887 print_source(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *data)
888 {
889 (void) data;
890
891 if (pkg->flags & PKGCONF_PKG_PROPF_VIRTUAL)
892 return;
893
894 /* If source is empty then empty string is printed otherwise URL */
895 pkgconf_output_fmt(client->output, PKGCONF_OUTPUT_STDOUT, "%s: %s\n",
896 pkg->id, pkg->source != NULL ? pkg->source : "");
897 }
898
899 static bool
apply_source(pkgconf_client_t * client,pkgconf_pkg_t * world,void * data,int maxdepth)900 apply_source(pkgconf_client_t *client, pkgconf_pkg_t *world, void *data, int maxdepth)
901 {
902 int eflag;
903
904 eflag = pkgconf_pkg_traverse(client, world, print_source, data, maxdepth, 0);
905
906 if (eflag != PKGCONF_PKG_ERRF_OK)
907 return false;
908
909 return true;
910 }
911
912 void
path_list_to_buffer(const pkgconf_list_t * list,pkgconf_buffer_t * buffer,char delim)913 path_list_to_buffer(const pkgconf_list_t *list, pkgconf_buffer_t *buffer, char delim)
914 {
915 pkgconf_node_t *n;
916
917 PKGCONF_FOREACH_LIST_ENTRY(list->head, n)
918 {
919 pkgconf_path_t *pn = n->data;
920
921 if (n != list->head)
922 pkgconf_buffer_push_byte(buffer, delim);
923
924 pkgconf_buffer_append(buffer, pn->path);
925 }
926 }
927
928 static void
unveil_search_paths(pkgconf_client_t * client,const pkgconf_cross_personality_t * personality)929 unveil_search_paths(pkgconf_client_t *client, const pkgconf_cross_personality_t *personality)
930 {
931 pkgconf_node_t *n;
932
933 client->unveil_handler(client, "/dev/null", "rwc");
934
935 PKGCONF_FOREACH_LIST_ENTRY(client->dir_list.head, n)
936 {
937 pkgconf_path_t *pn = n->data;
938
939 client->unveil_handler(client, pn->path, "r");
940 }
941
942 PKGCONF_FOREACH_LIST_ENTRY(personality->dir_list.head, n)
943 {
944 pkgconf_path_t *pn = n->data;
945
946 client->unveil_handler(client, pn->path, "r");
947 }
948 }
949
950 /* SAFETY: pkgconf_client_t takes ownership of these package objects */
951 static void
register_builtins(pkgconf_client_t * client,const pkgconf_cross_personality_t * personality)952 register_builtins(pkgconf_client_t *client, const pkgconf_cross_personality_t *personality)
953 {
954 pkgconf_buffer_t pc_path_buf = PKGCONF_BUFFER_INITIALIZER;
955 path_list_to_buffer(&personality->dir_list, &pc_path_buf, ':');
956
957 pkgconf_buffer_t pc_system_libdirs_buf = PKGCONF_BUFFER_INITIALIZER;
958 path_list_to_buffer(&personality->filter_libdirs, &pc_system_libdirs_buf, ':');
959
960 pkgconf_buffer_t pc_system_includedirs_buf = PKGCONF_BUFFER_INITIALIZER;
961 path_list_to_buffer(&personality->filter_includedirs, &pc_system_includedirs_buf, ':');
962
963 pkgconf_pkg_t *pkg_config_virtual = calloc(1, sizeof(pkgconf_pkg_t));
964 if (pkg_config_virtual == NULL)
965 {
966 goto error;
967 }
968
969 pkg_config_virtual->owner = client;
970 pkg_config_virtual->id = strdup("pkg-config");
971 pkg_config_virtual->realname = strdup("pkg-config");
972 pkg_config_virtual->description = strdup("virtual package defining pkgconf API version supported");
973 pkg_config_virtual->url = strdup(PACKAGE_BUGREPORT);
974 pkg_config_virtual->version = strdup(PACKAGE_VERSION);
975
976 pkgconf_tuple_add(client, &pkg_config_virtual->vars, "pc_system_libdirs", pkgconf_buffer_str_or_empty(&pc_system_libdirs_buf), false, 0);
977 pkgconf_tuple_add(client, &pkg_config_virtual->vars, "pc_system_includedirs", pkgconf_buffer_str_or_empty(&pc_system_includedirs_buf), false, 0);
978 pkgconf_tuple_add(client, &pkg_config_virtual->vars, "pc_path", pkgconf_buffer_str_or_empty(&pc_path_buf), false, 0);
979
980 if (!pkgconf_client_preload_one(client, pkg_config_virtual))
981 {
982 goto error;
983 }
984
985 pkgconf_pkg_t *pkgconf_virtual = calloc(1, sizeof(pkgconf_pkg_t));
986 if (pkgconf_virtual == NULL)
987 {
988 goto error;
989 }
990
991 pkgconf_virtual->owner = client;
992 pkgconf_virtual->id = strdup("pkgconf");
993 pkgconf_virtual->realname = strdup("pkgconf");
994 pkgconf_virtual->description = strdup("virtual package defining pkgconf API version supported");
995 pkgconf_virtual->url = strdup(PACKAGE_BUGREPORT);
996 pkgconf_virtual->version = strdup(PACKAGE_VERSION);
997
998 pkgconf_tuple_add(client, &pkgconf_virtual->vars, "pc_system_libdirs", pkgconf_buffer_str_or_empty(&pc_system_libdirs_buf), false, 0);
999 pkgconf_tuple_add(client, &pkgconf_virtual->vars, "pc_system_includedirs", pkgconf_buffer_str_or_empty(&pc_system_includedirs_buf), false, 0);
1000 pkgconf_tuple_add(client, &pkgconf_virtual->vars, "pc_path", pkgconf_buffer_str_or_empty(&pc_path_buf), false, 0);
1001
1002 if (!pkgconf_client_preload_one(client, pkgconf_virtual))
1003 {
1004 goto error;
1005 }
1006
1007 error:
1008 pkgconf_buffer_finalize(&pc_path_buf);
1009 pkgconf_buffer_finalize(&pc_system_libdirs_buf);
1010 pkgconf_buffer_finalize(&pc_system_includedirs_buf);
1011 }
1012
1013 #ifndef PKGCONF_LITE
1014 static void
dump_personality(pkgconf_output_t * output,const pkgconf_cross_personality_t * p)1015 dump_personality(pkgconf_output_t *output, const pkgconf_cross_personality_t *p)
1016 {
1017 pkgconf_buffer_t pc_path_buf = PKGCONF_BUFFER_INITIALIZER;
1018 path_list_to_buffer(&p->dir_list, &pc_path_buf, ':');
1019
1020 pkgconf_buffer_t pc_system_libdirs_buf = PKGCONF_BUFFER_INITIALIZER;
1021 path_list_to_buffer(&p->filter_libdirs, &pc_system_libdirs_buf, ':');
1022
1023 pkgconf_buffer_t pc_system_includedirs_buf = PKGCONF_BUFFER_INITIALIZER;
1024 path_list_to_buffer(&p->filter_includedirs, &pc_system_includedirs_buf, ':');
1025
1026 pkgconf_output_fmt(output, PKGCONF_OUTPUT_STDOUT, "Triplet: %s\n", p->name);
1027
1028 if (p->sysroot_dir)
1029 pkgconf_output_fmt(output, PKGCONF_OUTPUT_STDOUT, "SysrootDir: %s\n", p->sysroot_dir);
1030
1031 pkgconf_output_fmt(output, PKGCONF_OUTPUT_STDOUT, "DefaultSearchPaths: %s\n", pc_path_buf.base);
1032 pkgconf_output_fmt(output, PKGCONF_OUTPUT_STDOUT, "SystemIncludePaths: %s\n", pc_system_includedirs_buf.base);
1033 pkgconf_output_fmt(output, PKGCONF_OUTPUT_STDOUT, "SystemLibraryPaths: %s\n", pc_system_libdirs_buf.base);
1034
1035 if (p->want_default_pure)
1036 pkgconf_output_fmt(output, PKGCONF_OUTPUT_STDOUT, "WantDefaultPure: true\n");
1037
1038 if (p->want_default_static)
1039 pkgconf_output_fmt(output, PKGCONF_OUTPUT_STDOUT, "WantDefaultStatic: true\n");
1040
1041 pkgconf_buffer_finalize(&pc_path_buf);
1042 pkgconf_buffer_finalize(&pc_system_libdirs_buf);
1043 pkgconf_buffer_finalize(&pc_system_includedirs_buf);
1044 }
1045 #endif
1046
1047 int
pkgconf_cli_run(pkgconf_cli_state_t * state,int argc,char * argv[],int last_argc)1048 pkgconf_cli_run(pkgconf_cli_state_t *state, int argc, char *argv[], int last_argc)
1049 {
1050 (void) argc;
1051
1052 int ret = EXIT_SUCCESS;
1053 unsigned int want_client_flags = PKGCONF_PKG_PKGF_NONE;
1054 const char *builddir;
1055 const char *sysroot_dir;
1056 pkgconf_list_t pkgq = PKGCONF_LIST_INITIALIZER;
1057 pkgconf_list_t deplist = PKGCONF_LIST_INITIALIZER;
1058 pkgconf_node_t *node;
1059 pkgconf_buffer_t queryparams = PKGCONF_BUFFER_INITIALIZER;
1060 pkgconf_pkg_t world = {
1061 .id = "virtual:world",
1062 .realname = "virtual world package",
1063 .flags = PKGCONF_PKG_PROPF_STATIC | PKGCONF_PKG_PROPF_VIRTUAL,
1064 };
1065
1066 #ifndef PKGCONF_LITE
1067 if ((state->want_flags & PKG_DUMP_PERSONALITY) == PKG_DUMP_PERSONALITY)
1068 {
1069 dump_personality(state->pkg_client.output, state->pkg_client.personality);
1070
1071 ret = EXIT_SUCCESS;
1072 goto out;
1073 }
1074 #endif
1075
1076 #ifndef PKGCONF_LITE
1077 if ((state->want_flags & PKG_MSVC_SYNTAX) == PKG_MSVC_SYNTAX)
1078 state->want_render_ops = msvc_renderer_get();
1079 #endif
1080
1081 if (pkgconf_client_getenv(&state->pkg_client, "PKG_CONFIG_FDO_SYSROOT_RULES"))
1082 want_client_flags |= PKGCONF_PKG_PKGF_FDO_SYSROOT_RULES;
1083
1084 if (pkgconf_client_getenv(&state->pkg_client, "PKG_CONFIG_PKGCONF1_SYSROOT_RULES"))
1085 want_client_flags |= PKGCONF_PKG_PKGF_PKGCONF1_SYSROOT_RULES;
1086
1087 if ((state->want_flags & PKG_SHORT_ERRORS) == PKG_SHORT_ERRORS)
1088 want_client_flags |= PKGCONF_PKG_PKGF_SIMPLIFY_ERRORS;
1089
1090 if ((state->want_flags & PKG_DONT_RELOCATE_PATHS) == PKG_DONT_RELOCATE_PATHS)
1091 want_client_flags |= PKGCONF_PKG_PKGF_DONT_RELOCATE_PATHS;
1092
1093 state->error_msgout = stderr;
1094 if ((state->want_flags & PKG_ERRORS_ON_STDOUT) == PKG_ERRORS_ON_STDOUT)
1095 state->error_msgout = stdout;
1096 if ((state->want_flags & PKG_SILENCE_ERRORS) == PKG_SILENCE_ERRORS) {
1097 state->error_msgout = fopen(PATH_DEV_NULL, "w");
1098 state->opened_error_msgout = true;
1099 }
1100
1101 if ((state->want_flags & PKG_IGNORE_CONFLICTS) == PKG_IGNORE_CONFLICTS || pkgconf_client_getenv(&state->pkg_client, "PKG_CONFIG_IGNORE_CONFLICTS") != NULL)
1102 want_client_flags |= PKGCONF_PKG_PKGF_SKIP_CONFLICTS;
1103
1104 if ((state->want_flags & PKG_STATIC) == PKG_STATIC || state->pkg_client.personality->want_default_static)
1105 want_client_flags |= (PKGCONF_PKG_PKGF_SEARCH_PRIVATE | PKGCONF_PKG_PKGF_MERGE_PRIVATE_FRAGMENTS);
1106
1107 if ((state->want_flags & PKG_SHARED) == PKG_SHARED)
1108 want_client_flags &= ~(PKGCONF_PKG_PKGF_SEARCH_PRIVATE | PKGCONF_PKG_PKGF_MERGE_PRIVATE_FRAGMENTS);
1109
1110 /* if --static and --pure are both specified, then disable merge-back.
1111 * this allows for a --static which searches private modules, but has the same fragment behaviour as if
1112 * --static were disabled. see <https://github.com/pkgconf/pkgconf/issues/83> for rationale.
1113 */
1114 if ((state->want_flags & PKG_PURE) == PKG_PURE || pkgconf_client_getenv(&state->pkg_client, "PKG_CONFIG_PURE_DEPGRAPH") != NULL || state->pkg_client.personality->want_default_pure)
1115 want_client_flags &= ~PKGCONF_PKG_PKGF_MERGE_PRIVATE_FRAGMENTS;
1116
1117 if ((state->want_flags & PKG_ENV_ONLY) == PKG_ENV_ONLY)
1118 want_client_flags |= PKGCONF_PKG_PKGF_ENV_ONLY;
1119
1120 if ((state->want_flags & PKG_NO_CACHE) == PKG_NO_CACHE)
1121 want_client_flags |= PKGCONF_PKG_PKGF_NO_CACHE;
1122
1123 /* On Windows we want to always redefine the prefix by default
1124 * but allow that behavior to be manually disabled */
1125 #if !defined(_WIN32) && !defined(_WIN64)
1126 if ((state->want_flags & PKG_DEFINE_PREFIX) == PKG_DEFINE_PREFIX || pkgconf_client_getenv(&state->pkg_client, "PKG_CONFIG_RELOCATE_PATHS") != NULL)
1127 #endif
1128 want_client_flags |= PKGCONF_PKG_PKGF_REDEFINE_PREFIX;
1129
1130 if ((state->want_flags & PKG_NO_UNINSTALLED) == PKG_NO_UNINSTALLED || pkgconf_client_getenv(&state->pkg_client, "PKG_CONFIG_DISABLE_UNINSTALLED") != NULL)
1131 want_client_flags |= PKGCONF_PKG_PKGF_NO_UNINSTALLED;
1132
1133 if ((state->want_flags & PKG_NO_PROVIDES) == PKG_NO_PROVIDES)
1134 want_client_flags |= PKGCONF_PKG_PKGF_SKIP_PROVIDES;
1135
1136 if ((state->want_flags & PKG_DONT_DEFINE_PREFIX) == PKG_DONT_DEFINE_PREFIX || pkgconf_client_getenv(&state->pkg_client, "PKG_CONFIG_DONT_DEFINE_PREFIX") != NULL)
1137 want_client_flags &= ~PKGCONF_PKG_PKGF_REDEFINE_PREFIX;
1138
1139 if ((state->want_flags & PKG_INTERNAL_CFLAGS) == PKG_INTERNAL_CFLAGS)
1140 want_client_flags |= PKGCONF_PKG_PKGF_DONT_FILTER_INTERNAL_CFLAGS;
1141
1142 /* --static --libs, --exists require the full dependency graph to be solved */
1143 if ((state->want_flags & (PKG_STATIC|PKG_LIBS)) == (PKG_STATIC|PKG_LIBS) || (state->want_flags & PKG_EXISTS) == PKG_EXISTS)
1144 want_client_flags |= PKGCONF_PKG_PKGF_REQUIRE_INTERNAL;
1145
1146 /* if these selectors are used, it means that we are querying metadata.
1147 * so signal to libpkgconf that we only want to walk the flattened dependency set.
1148 */
1149 if ((state->want_flags & PKG_MODVERSION) == PKG_MODVERSION ||
1150 (state->want_flags & PKG_REQUIRES) == PKG_REQUIRES ||
1151 (state->want_flags & PKG_REQUIRES_PRIVATE) == PKG_REQUIRES_PRIVATE ||
1152 (state->want_flags & PKG_PROVIDES) == PKG_PROVIDES ||
1153 (state->want_flags & PKG_VARIABLES) == PKG_VARIABLES ||
1154 (state->want_flags & PKG_PATH) == PKG_PATH ||
1155 state->want_variable != NULL)
1156 state->maximum_traverse_depth = 1;
1157
1158 /* if we are asking for a variable, path or list of variables, this only makes sense
1159 * for a single package.
1160 */
1161 if ((state->want_flags & PKG_VARIABLES) == PKG_VARIABLES ||
1162 (state->want_flags & PKG_PATH) == PKG_PATH ||
1163 state->want_variable != NULL)
1164 {
1165 state->maximum_package_count = 1;
1166 }
1167
1168 if ((state->want_flags & PKG_REQUIRES_PRIVATE) == PKG_REQUIRES_PRIVATE ||
1169 (state->want_flags & PKG_CFLAGS))
1170 {
1171 want_client_flags |= PKGCONF_PKG_PKGF_SEARCH_PRIVATE;
1172 }
1173
1174 if ((builddir = pkgconf_client_getenv(&state->pkg_client, "PKG_CONFIG_TOP_BUILD_DIR")) != NULL)
1175 pkgconf_client_set_buildroot_dir(&state->pkg_client, builddir);
1176
1177 if ((sysroot_dir = pkgconf_client_getenv(&state->pkg_client, "PKG_CONFIG_SYSROOT_DIR")) != NULL)
1178 {
1179 const char *destdir;
1180
1181 pkgconf_client_set_sysroot_dir(&state->pkg_client, sysroot_dir);
1182
1183 if ((destdir = pkgconf_client_getenv(&state->pkg_client, "DESTDIR")) != NULL)
1184 {
1185 if (!strcmp(destdir, sysroot_dir))
1186 want_client_flags |= PKGCONF_PKG_PKGF_FDO_SYSROOT_RULES;
1187 }
1188 }
1189
1190 /* we have determined what features we want most likely. in some cases, we override later. */
1191 pkgconf_client_set_flags(&state->pkg_client, want_client_flags);
1192
1193 /* at this point, want_client_flags should be set, so build the dir list */
1194 pkgconf_client_dir_list_build(&state->pkg_client, state->pkg_client.personality);
1195
1196 /* unveil the entire search path now that we have loaded the personality data and built the dir list. */
1197 unveil_search_paths(&state->pkg_client, state->pkg_client.personality);
1198
1199 /* register built-in packages */
1200 register_builtins(&state->pkg_client, state->pkg_client.personality);
1201
1202 /* preload any files in PKG_CONFIG_PRELOADED_FILES */
1203 pkgconf_client_preload_from_environ(&state->pkg_client, "PKG_CONFIG_PRELOADED_FILES");
1204
1205 if (state->required_pkgconfig_version != NULL)
1206 {
1207 if (pkgconf_compare_version(PACKAGE_VERSION, state->required_pkgconfig_version) >= 0)
1208 ret = EXIT_SUCCESS;
1209 else
1210 ret = EXIT_FAILURE;
1211
1212 goto out;
1213 }
1214
1215 if ((state->want_flags & PKG_LIST) == PKG_LIST)
1216 {
1217 pkgconf_scan_all(&state->pkg_client, &state->pkg_client, print_list_entry);
1218 ret = EXIT_SUCCESS;
1219 goto out;
1220 }
1221
1222 if ((state->want_flags & PKG_LIST_PACKAGE_NAMES) == PKG_LIST_PACKAGE_NAMES)
1223 {
1224 pkgconf_scan_all(&state->pkg_client, &state->pkg_client, print_package_entry);
1225 ret = EXIT_SUCCESS;
1226 goto out;
1227 }
1228
1229 while (last_argc < argc && argv[last_argc])
1230 {
1231 if (pkgconf_buffer_len(&queryparams) > 0)
1232 pkgconf_buffer_push_byte(&queryparams, ' ');
1233
1234 pkgconf_buffer_append(&queryparams, argv[last_argc]);
1235 last_argc++;
1236 }
1237
1238 pkgconf_dependency_parse_str(&state->pkg_client, &deplist, pkgconf_buffer_str_or_empty(&queryparams), 0);
1239 pkgconf_buffer_finalize(&queryparams);
1240
1241 if (state->required_module_version != NULL || state->required_exact_module_version != NULL || state->required_max_module_version != NULL)
1242 {
1243 const char *target_version = NULL;
1244 pkgconf_pkg_comparator_t compare = PKGCONF_CMP_ANY;
1245
1246 if (state->required_module_version != NULL)
1247 {
1248 target_version = state->required_module_version;
1249 compare = PKGCONF_CMP_GREATER_THAN_EQUAL;
1250 }
1251 else if (state->required_exact_module_version != NULL)
1252 {
1253 target_version = state->required_exact_module_version;
1254 compare = PKGCONF_CMP_EQUAL;
1255 }
1256 else if (state->required_max_module_version != NULL)
1257 {
1258 target_version = state->required_max_module_version;
1259 compare = PKGCONF_CMP_LESS_THAN_EQUAL;
1260 }
1261
1262 PKGCONF_FOREACH_LIST_ENTRY(deplist.head, node)
1263 {
1264 pkgconf_dependency_t *dep = node->data;
1265
1266 /* already constrained at query level */
1267 if (dep->compare != PKGCONF_CMP_ANY)
1268 continue;
1269
1270 dep->compare = compare;
1271 dep->version = strdup(target_version);
1272 }
1273 }
1274
1275 PKGCONF_FOREACH_LIST_ENTRY(deplist.head, node)
1276 {
1277 pkgconf_dependency_t *dep = node->data;
1278 pkgconf_queue_push_dependency(&pkgq, dep);
1279 }
1280
1281 pkgconf_dependency_free(&deplist);
1282
1283 if (pkgq.head == NULL)
1284 {
1285 pkgconf_output_puts(state->pkg_client.output, PKGCONF_OUTPUT_STDERR,
1286 "Please specify at least one package name on the command line.");
1287 ret = EXIT_FAILURE;
1288 goto out;
1289 }
1290
1291 ret = EXIT_SUCCESS;
1292
1293 if (!pkgconf_queue_solve(&state->pkg_client, &pkgq, &world, state->maximum_traverse_depth))
1294 {
1295 ret = EXIT_FAILURE;
1296 goto out;
1297 }
1298
1299 /* we shouldn't need to unveil any more filesystem accesses from this point, so lock it down */
1300 state->pkg_client.unveil_handler(&state->pkg_client, NULL, NULL);
1301
1302 #ifndef PKGCONF_LITE
1303 if ((state->want_flags & PKG_SIMULATE) == PKG_SIMULATE)
1304 {
1305 state->want_flags &= ~(PKG_CFLAGS|PKG_LIBS);
1306
1307 pkgconf_client_set_flags(&state->pkg_client, want_client_flags | PKGCONF_PKG_PKGF_SKIP_ERRORS);
1308 apply_simulate(&state->pkg_client, &world, NULL, -1);
1309 }
1310 #endif
1311
1312 if ((state->want_flags & PKG_VALIDATE) == PKG_VALIDATE)
1313 goto out;
1314
1315 if ((state->want_flags & PKG_DUMP_LICENSE) == PKG_DUMP_LICENSE)
1316 {
1317 apply_license(&state->pkg_client, &world, &ret, 2);
1318 goto out;
1319 }
1320
1321 if ((state->want_flags & PKG_LINK_ABI) == PKG_LINK_ABI)
1322 {
1323 /* private dependencies only contribute their ABI when statically linked */
1324 if (!(state->want_flags & PKG_STATIC))
1325 pkgconf_client_set_flags(&state->pkg_client, state->pkg_client.flags & ~PKGCONF_PKG_PKGF_SEARCH_PRIVATE);
1326
1327 apply_link_abi(&state->pkg_client, &world, &ret, 2);
1328 goto out;
1329 }
1330
1331 if ((state->want_flags & PKG_DUMP_LICENSE_FILE) == PKG_DUMP_LICENSE_FILE)
1332 {
1333 apply_license_file(&state->pkg_client, &world, &ret, 2);
1334 goto out;
1335 }
1336
1337 if ((state->want_flags & PKG_DUMP_SOURCE) == PKG_DUMP_SOURCE)
1338 {
1339 apply_source(&state->pkg_client, &world, &ret, 2);
1340 goto out;
1341 }
1342
1343
1344 if ((state->want_flags & PKG_UNINSTALLED) == PKG_UNINSTALLED)
1345 {
1346 ret = EXIT_FAILURE;
1347 apply_uninstalled(&state->pkg_client, &world, &ret, 2);
1348 goto out;
1349 }
1350
1351 if (state->want_env_prefix != NULL)
1352 {
1353 apply_env(&state->pkg_client, &world, state->want_env_prefix, 2);
1354 goto out;
1355 }
1356
1357 if ((state->want_flags & PKG_PROVIDES) == PKG_PROVIDES)
1358 {
1359 state->want_flags &= ~(PKG_CFLAGS|PKG_LIBS);
1360 apply_provides(&state->pkg_client, &world, NULL, 2);
1361 }
1362
1363 #ifndef PKGCONF_LITE
1364 if ((state->want_flags & PKG_DIGRAPH) == PKG_DIGRAPH)
1365 {
1366 state->want_flags &= ~(PKG_CFLAGS|PKG_LIBS);
1367 apply_digraph(&state->pkg_client, &world, &pkgq, 2);
1368 }
1369
1370 if ((state->want_flags & PKG_SOLUTION) == PKG_SOLUTION)
1371 {
1372 state->want_flags &= ~(PKG_CFLAGS|PKG_LIBS);
1373 apply_print_solution(&state->pkg_client, &world, NULL, 2);
1374 }
1375 #endif
1376
1377 if ((state->want_flags & PKG_MODVERSION) == PKG_MODVERSION)
1378 {
1379 state->want_flags &= ~(PKG_CFLAGS|PKG_LIBS);
1380 apply_modversion(&state->pkg_client, &world, &pkgq, 2);
1381 }
1382
1383 if ((state->want_flags & PKG_PATH) == PKG_PATH)
1384 {
1385 state->want_flags &= ~(PKG_CFLAGS|PKG_LIBS);
1386
1387 pkgconf_client_set_flags(&state->pkg_client, want_client_flags | PKGCONF_PKG_PKGF_SKIP_ROOT_VIRTUAL);
1388 apply_path(&state->pkg_client, &world, NULL, 2);
1389 }
1390
1391 if ((state->want_flags & PKG_VARIABLES) == PKG_VARIABLES)
1392 {
1393 state->want_flags &= ~(PKG_CFLAGS|PKG_LIBS);
1394 apply_variables(&state->pkg_client, &world, NULL, 2);
1395 }
1396
1397 if (state->want_variable != NULL)
1398 {
1399 state->want_flags &= ~(PKG_CFLAGS|PKG_LIBS);
1400
1401 pkgconf_client_set_flags(&state->pkg_client, want_client_flags | PKGCONF_PKG_PKGF_SKIP_ROOT_VIRTUAL);
1402 apply_variable(&state->pkg_client, &world, state->want_variable, 2);
1403 }
1404
1405 if ((state->want_flags & PKG_REQUIRES) == PKG_REQUIRES)
1406 {
1407 state->want_flags &= ~(PKG_CFLAGS|PKG_LIBS);
1408 apply_requires(&state->pkg_client, &world, NULL, 2);
1409 }
1410
1411 if ((state->want_flags & PKG_REQUIRES_PRIVATE) == PKG_REQUIRES_PRIVATE)
1412 {
1413 state->want_flags &= ~(PKG_CFLAGS|PKG_LIBS);
1414
1415 apply_requires_private(&state->pkg_client, &world, NULL, 2);
1416 }
1417
1418 if ((state->want_flags & PKG_FRAGMENT_TREE))
1419 {
1420 state->want_flags &= ~(PKG_CFLAGS|PKG_LIBS);
1421
1422 apply_fragment_tree(&state->pkg_client, &world, NULL, 2);
1423 }
1424
1425 if ((state->want_flags & (PKG_CFLAGS|PKG_LIBS)))
1426 {
1427 pkgconf_list_t target_list = PKGCONF_LIST_INITIALIZER;
1428 pkgconf_buffer_t render_buf = PKGCONF_BUFFER_INITIALIZER;
1429
1430 if ((state->want_flags & PKG_CFLAGS))
1431 apply_cflags(&state->pkg_client, &world, &target_list, 2);
1432
1433 if ((state->want_flags & PKG_LIBS) && !(state->want_flags & PKG_STATIC))
1434 pkgconf_client_set_flags(&state->pkg_client, state->pkg_client.flags & ~PKGCONF_PKG_PKGF_SEARCH_PRIVATE);
1435
1436 if ((state->want_flags & PKG_LIBS))
1437 apply_libs(&state->pkg_client, &world, &target_list, 2);
1438
1439 pkgconf_fragment_render_buf(&target_list, &render_buf, true, state->want_render_ops, (state->want_flags & PKG_NEWLINES) ? '\n' : ' ');
1440 pkgconf_output_putbuf(state->pkg_client.output, PKGCONF_OUTPUT_STDOUT, &render_buf, true);
1441 pkgconf_buffer_finalize(&render_buf);
1442
1443 pkgconf_fragment_free(&target_list);
1444 }
1445
1446 out:
1447 pkgconf_solution_free(&state->pkg_client, &world);
1448 pkgconf_queue_free(&pkgq);
1449 pkgconf_cli_state_reset(state);
1450
1451 return ret;
1452 }
1453
1454 void
pkgconf_cli_state_reset(pkgconf_cli_state_t * state)1455 pkgconf_cli_state_reset(pkgconf_cli_state_t *state)
1456 {
1457 pkgconf_cross_personality_deinit((void *) state->pkg_client.personality);
1458 pkgconf_client_deinit(&state->pkg_client);
1459
1460 if (state->logfile_out != NULL)
1461 fclose(state->logfile_out);
1462 if (state->opened_error_msgout)
1463 fclose(state->error_msgout);
1464 }
1465