xref: /freebsd/contrib/pkgconf/cli/core.c (revision 592efe252472a3385acf36b1f49ecf710a7f3d9c)
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