]> git.ipfire.org Git - people/stevee/pakfire.git/blame - src/libpakfire/parser.c
file: Fix digest comment
[people/stevee/pakfire.git] / src / libpakfire / parser.c
CommitLineData
89045ec6
MT
1/*#############################################################################
2# #
3# Pakfire - The IPFire package management system #
4# Copyright (C) 2019 Pakfire development team #
5# #
6# This program is free software: you can redistribute it and/or modify #
7# it under the terms of the GNU General Public License as published by #
8# the Free Software Foundation, either version 3 of the License, or #
9# (at your option) any later version. #
10# #
11# This program is distributed in the hope that it will be useful, #
12# but WITHOUT ANY WARRANTY; without even the implied warranty of #
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
14# GNU General Public License for more details. #
15# #
16# You should have received a copy of the GNU General Public License #
17# along with this program. If not, see <http://www.gnu.org/licenses/>. #
18# #
19#############################################################################*/
20
5d901566 21#include <errno.h>
fa3cff8d 22#include <fnmatch.h>
20440ba7 23#include <linux/limits.h>
fb077c4c 24#include <regex.h>
f0d6233d 25#include <stdlib.h>
fb077c4c 26#include <string.h>
d73ca64f
MT
27#include <time.h>
28#include <unistd.h>
fb077c4c 29
c178c275
MT
30#define PCRE2_CODE_UNIT_WIDTH 8
31#include <pcre2.h>
32
2a623cf8 33#include <pakfire/dependencies.h>
0de6bb30 34#include <pakfire/jail.h>
fb077c4c 35#include <pakfire/logging.h>
f59d680a 36#include <pakfire/package.h>
89045ec6 37#include <pakfire/parser.h>
fb077c4c 38#include <pakfire/pakfire.h>
d973a13d 39#include <pakfire/string.h>
89045ec6
MT
40#include <pakfire/util.h>
41
657a5c72 42struct pakfire_parser {
ac4c607b 43 struct pakfire* pakfire;
fb077c4c
MT
44 int nrefs;
45
657a5c72 46 struct pakfire_parser* parent;
2dd267d4 47 int flags;
1141075e
MT
48 char* namespace;
49
8868318d 50 struct pakfire_parser_declaration** declarations;
6d206cc9 51 size_t num_declarations;
c178c275
MT
52
53 // Regular expressions
d25dd74f 54 pcre2_code* regex_command;
c178c275 55 pcre2_code* regex_variable;
d25dd74f 56
0315f885
MT
57 // XXX THESE ARE NEVER FREED
58};
c178c275 59
657a5c72 60static int pakfire_parser_compile_regexes(struct pakfire_parser* parser) {
bf7acff3 61 int r;
c178c275 62
bf7acff3 63 // Commands
e614c5a6 64 if (!parser->regex_command && (parser->flags & PAKFIRE_PARSER_FLAGS_EXPAND_COMMANDS)) {
0315f885
MT
65 r = pakfire_compile_regex(parser->pakfire, &parser->regex_command,
66 "%(\\(((?>[^()]|(?1))*)\\))");
bf7acff3
MT
67 if (r)
68 return r;
69 }
a41868f9 70
bf7acff3
MT
71 // Variables
72 if (!parser->regex_variable) {
0315f885
MT
73 r = pakfire_compile_regex(parser->pakfire, &parser->regex_variable,
74 "%\\{([A-Za-z0-9_\\-]+)\\}");
bf7acff3
MT
75 if (r)
76 return r;
c178c275
MT
77 }
78
79 return 0;
80}
81
ac4c607b 82struct pakfire_parser* pakfire_parser_create(struct pakfire* pakfire,
657a5c72
MT
83 struct pakfire_parser* parent, const char* namespace, int flags) {
84 struct pakfire_parser* parser = calloc(1, sizeof(*parser));
fb077c4c
MT
85 if (parser) {
86 parser->pakfire = pakfire_ref(pakfire);
c0f1c1f2 87 parser->nrefs = 1;
fb077c4c 88
d310f14c
MT
89 // Store a reference to the parent parser if we have one
90 if (parent)
91 parser->parent = pakfire_parser_ref(parent);
92
2dd267d4
MT
93 // Store flags
94 parser->flags = flags;
95
1141075e 96 // Make namespace
713da225 97 pakfire_parser_set_namespace(parser, namespace);
fb077c4c
MT
98 }
99
100 return parser;
101}
102
638abead 103struct pakfire_parser* pakfire_parser_create_child(struct pakfire_parser* parser, const char* namespace) {
2dd267d4 104 return pakfire_parser_create(parser->pakfire, parser, namespace, parser->flags);
fb08a3af
MT
105}
106
638abead 107struct pakfire_parser* pakfire_parser_ref(struct pakfire_parser* parser) {
d310f14c
MT
108 ++parser->nrefs;
109
110 return parser;
111}
112
ac4c607b 113struct pakfire* pakfire_parser_get_pakfire(struct pakfire_parser* parser) {
fb077c4c
MT
114 return pakfire_ref(parser->pakfire);
115}
116
657a5c72 117static void pakfire_parser_free_declarations(struct pakfire_parser* parser) {
8868318d
MT
118 if (!parser->declarations)
119 return;
120
6d206cc9
MT
121 for (unsigned int i = 0; i < parser->num_declarations; i++) {
122 struct pakfire_parser_declaration* d = parser->declarations[i];
f2aa4592 123
f2aa4592 124 // Free everything
f2aa4592 125 if (d->value)
f0d6233d
MT
126 free(d->value);
127 free(d);
fb077c4c 128 }
8868318d
MT
129
130 free(parser->declarations);
fb077c4c
MT
131}
132
657a5c72 133static void pakfire_parser_free(struct pakfire_parser* parser) {
c178c275
MT
134 // Release regular expressions
135 if (parser->regex_variable)
136 pcre2_code_free(parser->regex_variable);
137
6d206cc9 138 pakfire_parser_free_declarations(parser);
7fb3defa 139
6d206cc9 140 if (parser->namespace)
f0d6233d 141 free(parser->namespace);
fb077c4c 142
7fb3defa
MT
143 if (parser->parent)
144 pakfire_parser_unref(parser->parent);
145
fb077c4c 146 pakfire_unref(parser->pakfire);
f0d6233d 147 free(parser);
fb077c4c
MT
148}
149
638abead 150struct pakfire_parser* pakfire_parser_unref(struct pakfire_parser* parser) {
fb077c4c
MT
151 if (--parser->nrefs > 0)
152 return parser;
153
154 pakfire_parser_free(parser);
155 return NULL;
156}
157
638abead 158struct pakfire_parser* pakfire_parser_get_parent(struct pakfire_parser* parser) {
b1b15235
MT
159 if (parser->parent)
160 return pakfire_parser_ref(parser->parent);
161
162 return NULL;
163}
164
fb077c4c 165static struct pakfire_parser_declaration* pakfire_parser_get_declaration(
657a5c72 166 struct pakfire_parser* parser, const char* namespace, const char* name) {
20440ba7
MT
167 if (!name) {
168 errno = EINVAL;
169 return NULL;
170 }
171
172 if (!namespace)
173 namespace = "";
fb077c4c 174
3f6e35a7
MT
175 if (*namespace)
176 DEBUG(parser->pakfire, "%p: Looking up %s.%s\n", parser, namespace, name);
f4d93071 177 else
3f6e35a7 178 DEBUG(parser->pakfire, "%p: Looking up %s\n", parser, name);
f4d93071 179
20440ba7 180 struct pakfire_parser_declaration* d;
fb077c4c
MT
181 for (unsigned i = 0; i < parser->num_declarations; i++) {
182 d = parser->declarations[i];
183 if (!d)
184 break;
185
20440ba7 186 // Return if namespace and name match
3f6e35a7
MT
187 if ((strcmp(d->namespace, namespace) == 0) && (strcmp(d->name, name) == 0)) {
188 DEBUG(parser->pakfire, "%p: Found result = %s\n", parser, d->value);
189
190 return d;
191 }
192 }
193
194 DEBUG(parser->pakfire, "%p: Nothing found\n", parser);
195
196 return NULL;
197}
198
199static struct pakfire_parser_declaration* pakfire_parser_get_declaration_recursive(
657a5c72 200 struct pakfire_parser* parser, const char* namespace, const char* name) {
3f6e35a7
MT
201 struct pakfire_parser_declaration* d = pakfire_parser_get_declaration(
202 parser, namespace, name);
203 if (d)
204 return d;
205
206 // Continue searching in parent parser
207 if (parser->parent)
208 return pakfire_parser_get_declaration_recursive(parser->parent, namespace, name);
209
210 return NULL;
211}
212
213static void pakfire_parser_strip_namespace(char** s) {
214 char* pos = strrchr(*s, '.');
215
216 if (pos)
217 (*s)[pos - *s] = '\0';
218 else
219 (*s)[0] = '\0';
220}
221
02ac7cbd
MT
222static char* pakfire_parser_join(const char* fmt, const char* val1, const char* val2) {
223 char* result = NULL;
224 int r;
225
226 // Merge both values if both are set
227 if (val1 && *val1 && val2 && *val2) {
228 r = asprintf(&result, fmt, val1, val2);
229 if (r < 0)
230 return NULL;
231
232 return result;
233 }
234
235 // If only one value is set, return that one
236 if (val1 && *val1)
237 return strdup(val1);
238 else if (val2 && *val2)
239 return strdup(val2);
240
241 // Return an empty string if no value is set
242 return strdup("");
243}
244
3f6e35a7 245static struct pakfire_parser_declaration* pakfire_parser_find_declaration(
657a5c72 246 struct pakfire_parser* parser, const char* namespace, const char* name) {
3f6e35a7
MT
247 struct pakfire_parser_declaration* d;
248 char* n = NULL;
249
250 // Create a working copy of namespace
251 if (namespace)
252 n = strdupa(namespace);
253
254 while (1) {
255 d = pakfire_parser_get_declaration_recursive(parser, n, name);
256 if (d && d->value)
fb077c4c 257 return d;
3f6e35a7
MT
258
259 // End if we have exhausted the namespace
260 if (!n || !*n)
261 break;
262
263 // Strip namespace
264 pakfire_parser_strip_namespace(&n);
fb077c4c
MT
265 }
266
3f6e35a7 267 // Nothing found
fb077c4c
MT
268 return NULL;
269}
270
638abead 271int pakfire_parser_set(struct pakfire_parser* parser,
fea2e884 272 const char* namespace, const char* name, const char* value, int flags) {
02ac7cbd
MT
273 char* buffer = NULL;
274
5d901566
MT
275 if (!name)
276 return -EINVAL;
277
20440ba7
MT
278 if (!namespace)
279 namespace = "";
280
5e5f2d2b 281 // Handle when name already exists
aa75cc88 282 struct pakfire_parser_declaration* d = pakfire_parser_get_declaration(parser, namespace, name);
5e5f2d2b 283 if (d) {
02ac7cbd
MT
284 if (flags & PAKFIRE_PARSER_DECLARATION_APPEND) {
285 buffer = pakfire_parser_join("%s %s", d->value, value);
286 if (!buffer)
287 return 1;
288
289 // Reset the append flag
290 flags &= ~PAKFIRE_PARSER_DECLARATION_APPEND;
291 } else {
292 buffer = strdup(value);
293 }
294
5e5f2d2b
MT
295 // Replace value
296 if (d->value)
f0d6233d 297 free(d->value);
5d901566 298
02ac7cbd 299 d->value = buffer;
5e5f2d2b 300
fea2e884
MT
301 // Update flags
302 if (flags)
303 d->flags = flags;
304
aa75cc88
MT
305 DEBUG(parser->pakfire, "%p: Updated declaration: %s.%s = %s\n",
306 parser, d->namespace, d->name, d->value);
5e5f2d2b
MT
307
308 // All done
309 return 0;
310 }
311
fb077c4c 312 // Allocate a new declaration
90312f5c 313 d = calloc(1, sizeof(*d));
fb077c4c
MT
314 if (!d)
315 return -1;
316
20440ba7
MT
317 // Store namespace
318 pakfire_string_set(d->namespace, namespace);
aa75cc88 319
fb077c4c 320 // Import name & value
20440ba7 321 pakfire_string_set(d->name, name);
5d901566
MT
322 if (value)
323 d->value = strdup(value);
fb077c4c 324
fea2e884
MT
325 // Import flags
326 d->flags = flags;
327
02ac7cbd
MT
328 DEBUG(parser->pakfire, "%p: New declaration (%d): %s.%s %s= %s\n",
329 parser,
330 d->flags,
331 d->namespace,
332 d->name,
333 (d->flags & PAKFIRE_PARSER_DECLARATION_APPEND) ? "+" : "",
334 d->value);
fb077c4c
MT
335
336 // Assign new declaration to array
8868318d
MT
337 parser->declarations = reallocarray(parser->declarations,
338 sizeof(*parser->declarations), parser->num_declarations + 1);
339 parser->declarations[parser->num_declarations++] = d;
fb077c4c
MT
340
341 return 0;
342}
343
657a5c72 344int pakfire_parser_apply_declaration(struct pakfire_parser* parser,
79fd37b5 345 struct pakfire_parser_declaration* declaration) {
02ac7cbd 346 DEBUG(parser->pakfire, "GOT HERE %d\n", declaration->flags);
ec0f0419 347
fea2e884
MT
348 return pakfire_parser_set(parser, declaration->namespace,
349 declaration->name, declaration->value, declaration->flags);
79fd37b5
MT
350}
351
45d1bfad
MT
352static int pakfire_parser_find_template(struct pakfire_parser* parser,
353 char* template, const size_t length, const char* namespace) {
17689fc7
MT
354 DEBUG(parser->pakfire, "Looking up template in namespace '%s'\n", namespace);
355
356 struct pakfire_parser_declaration* d = pakfire_parser_get_declaration(
357 parser, namespace, "template");
358
359 const char* value = (d && *d->value) ? d->value : "MAIN";
360
45d1bfad
MT
361 // Format full variable name
362 return __pakfire_string_format(template, length, "packages.template:%s", value);
17689fc7
MT
363}
364
657a5c72 365static const char* pakfire_parser_get_raw(struct pakfire_parser* parser, const char* namespace, const char* name) {
17689fc7 366 struct pakfire_parser_declaration* d = NULL;
45d1bfad
MT
367 char template[NAME_MAX];
368 int r;
17689fc7
MT
369
370 // First, perform a simple lookup
3f6e35a7 371 d = pakfire_parser_get_declaration_recursive(parser, namespace, name);
fb077c4c 372
67738482 373 // Return a match when it actually contains a string
f4d93071 374 if (d && d->value)
17689fc7 375 return d->value;
67738482 376
17689fc7
MT
377 // If we couldn't find anything, we check if there is a template, and if that
378 // has our value...
3f6e35a7 379 if (namespace && pakfire_string_startswith(namespace, "packages.package:")) {
45d1bfad
MT
380 r = pakfire_parser_find_template(parser, template, sizeof(template), namespace);
381 if (r)
382 return NULL;
17689fc7 383
45d1bfad
MT
384 d = pakfire_parser_find_declaration(parser, template, name);
385 if (d && d->value)
386 return d->value;
17689fc7
MT
387 }
388
3f6e35a7
MT
389 // Otherwise we walk up the namespace to find a match
390 d = pakfire_parser_find_declaration(parser, namespace, name);
391 if (d && d->value)
392 return d->value;
f16c81ca
MT
393
394 return NULL;
395}
396
638abead 397int pakfire_parser_append(struct pakfire_parser* parser,
aa75cc88 398 const char* namespace, const char* name, const char* value) {
fb077c4c
MT
399 char* buffer = NULL;
400
f16c81ca 401 // Fetch the value of the current declaration
aa75cc88 402 const char* old_value = pakfire_parser_get_raw(parser, namespace, name);
f16c81ca 403
3f6e35a7
MT
404 DEBUG(parser->pakfire, "%p: Old value for %s.%s = %s\n",
405 parser, namespace, name, old_value);
406
f16c81ca
MT
407 // Set the new value when there is no old one
408 if (!old_value)
fea2e884 409 return pakfire_parser_set(parser, namespace, name, value, 0);
f16c81ca 410
fb077c4c 411 // Concat value
f16c81ca 412 int r = asprintf(&buffer, "%s %s", old_value, value);
fb077c4c
MT
413 if (r < 0)
414 return r;
415
f16c81ca 416 // Set the new value
fea2e884 417 r = pakfire_parser_set(parser, namespace, name, buffer, 0);
f0d6233d 418 free(buffer);
fb077c4c 419
f16c81ca 420 return r;
fb077c4c
MT
421}
422
657a5c72 423static int pakfire_parser_expand_commands(struct pakfire_parser* parser, char** buffer) {
d25dd74f
MT
424 int r = 0;
425 PCRE2_UCHAR* command = NULL;
426 PCRE2_SIZE command_length;
427 PCRE2_UCHAR* pattern = NULL;
428 PCRE2_SIZE pattern_length;
429
430 DEBUG(parser->pakfire, "Searching for commands in:\n%s\n", *buffer);
431
432 // Allocate memory for results
433 pcre2_match_data* match = pcre2_match_data_create_from_pattern(
434 parser->regex_command, NULL);
435
436 // Arguments passed to pakfire_execute
437 const char* argv[4] = {
438 "/bin/sh", "-c", NULL /* will be replaced by command later */, NULL,
439 };
440
441 while (1) {
442 // Perform matching
23b93958 443 r = pcre2_jit_match(parser->regex_command,
d25dd74f
MT
444 (PCRE2_UCHAR*)*buffer, strlen(*buffer), 0, 0, match, NULL);
445
446 // End loop when we have expanded all variables
e614c5a6
MT
447 if (r == PCRE2_ERROR_NOMATCH) {
448 DEBUG(parser->pakfire, "No (more) matches found\n");
cbfd19fa 449 r = 0;
d25dd74f 450 break;
e614c5a6 451 }
d25dd74f
MT
452
453 // Extract the command
e614c5a6 454 r = pcre2_substring_get_bynumber(match, 2, &command, &command_length);
d25dd74f
MT
455 if (r)
456 goto ERROR;
457
458 DEBUG(parser->pakfire, "Expanding command: %s\n", command);
459
460 // Update argv
461 argv[2] = (const char*)command;
462
463 // The output of the command
83d93f33 464 char* output = NULL;
d25dd74f
MT
465
466 // Execute the command inside the Pakfire environment
83d93f33 467 r = pakfire_jail_run(parser->pakfire, argv, 0, &output);
d25dd74f
MT
468 if (r) {
469 // Just log this and continue
470 DEBUG(parser->pakfire, "Command '%s' failed with return code %d\n", command, r);
471 }
472
0a1b68b3
MT
473 // Strip newline from output
474 if (output)
475 pakfire_remove_trailing_newline(output);
476
d25dd74f
MT
477 // Find the entire matched pattern
478 r = pcre2_substring_get_bynumber(match, 0, &pattern, &pattern_length);
0a1b68b3
MT
479 if (r) {
480 if (output)
481 free(output);
482
d25dd74f 483 goto ERROR;
0a1b68b3 484 }
d25dd74f
MT
485
486 // Replace all occurrences
487 char* tmp = pakfire_string_replace(*buffer, (const char*)pattern, output);
0a1b68b3
MT
488 if (!tmp) {
489 if (output)
490 free(output);
491
d25dd74f 492 goto ERROR;
0a1b68b3 493 }
d25dd74f
MT
494
495 // Replace buffer
496 free(*buffer);
497 *buffer = tmp;
498
499 // Free resources
500 pcre2_substring_free(command);
501 command = NULL;
502
503 pcre2_substring_free(pattern);
504 pattern = NULL;
0a1b68b3
MT
505
506 if (output)
507 free(output);
d25dd74f
MT
508 }
509
510ERROR:
511 pcre2_match_data_free(match);
512
513 if (command)
514 pcre2_substring_free(command);
515 if (pattern)
516 pcre2_substring_free(pattern);
517
518 return r;
519}
520
657a5c72 521static int pakfire_parser_expand_variables(struct pakfire_parser* parser,
6accaf43 522 const char* namespace, char** buffer) {
d25dd74f 523 int r = 0;
c178c275
MT
524 PCRE2_UCHAR* variable = NULL;
525 PCRE2_SIZE variable_length;
526 PCRE2_UCHAR* pattern = NULL;
527 PCRE2_SIZE pattern_length;
528
c178c275 529 // Allocate memory for results
d25dd74f
MT
530 pcre2_match_data* match = pcre2_match_data_create_from_pattern(
531 parser->regex_variable, NULL);
fb077c4c
MT
532
533 // Search for any variables
534 while (1) {
535 // Perform matching
23b93958 536 r = pcre2_jit_match(parser->regex_variable,
a41868f9 537 (PCRE2_UCHAR*)*buffer, strlen(*buffer), 0, 0, match, NULL);
fb077c4c
MT
538
539 // End loop when we have expanded all variables
c178c275 540 if (r == PCRE2_ERROR_NOMATCH) {
6accaf43 541 DEBUG(parser->pakfire, "No (more) matches found in: %s\n", *buffer);
cbfd19fa 542 r = 0;
fb077c4c
MT
543 break;
544 }
545
f4d93071
MT
546 // Find the entire matched pattern
547 r = pcre2_substring_get_bynumber(match, 0, &pattern, &pattern_length);
548 if (r)
549 goto ERROR;
550
38fa3305 551 // Find the variable name
c178c275
MT
552 r = pcre2_substring_get_bynumber(match, 1, &variable, &variable_length);
553 if (r)
38fa3305 554 goto ERROR;
fb077c4c
MT
555
556 DEBUG(parser->pakfire, "Expanding variable: %s\n", variable);
557
558 // Search for a declaration of this variable
17689fc7 559 const char* repl = pakfire_parser_get_raw(parser, namespace, (const char*)variable);
fb077c4c 560
f4d93071
MT
561 // Is this a recursive pattern?
562 if (repl && pakfire_string_matches(repl, (const char*)pattern)) {
563 DEBUG(parser->pakfire, "Recursion detected in %s\n", pattern);
564
565 // Move up one step and lookup there
566 if (namespace && *namespace) {
567 char* parent_namespace = strdupa(namespace);
568 pakfire_parser_strip_namespace(&parent_namespace);
569
570 repl = pakfire_parser_get_raw(parser, parent_namespace, (const char*)variable);
571
572 // If we have already reached the top namespace, we replace with an empty string
573 } else {
574 repl = NULL;
575 }
576 }
577
38fa3305 578 // What is its value?
17689fc7
MT
579 if (repl) {
580 DEBUG(parser->pakfire, "Replacing %%{%s} with '%s'\n", variable, repl);
d310f14c 581 } else {
38fa3305 582 DEBUG(parser->pakfire, "Replacing %%{%s} with an empty string\n", variable);
38fa3305 583 }
fb077c4c 584
38fa3305 585 // Replace all occurrences
17689fc7 586 char* tmp = pakfire_string_replace(*buffer, (const char*)pattern, (repl) ? repl : "");
38fa3305
MT
587 if (!tmp)
588 goto ERROR;
fb077c4c 589
38fa3305 590 // Replace buffer
6accaf43
MT
591 free(*buffer);
592 *buffer = tmp;
fb077c4c 593
38fa3305 594 // Free resources
c178c275 595 pcre2_substring_free(variable);
6accaf43 596 variable = NULL;
fb077c4c 597
6accaf43
MT
598 pcre2_substring_free(pattern);
599 pattern = NULL;
38fa3305 600 }
fb077c4c 601
38fa3305 602ERROR:
c178c275 603 pcre2_match_data_free(match);
fb077c4c 604
38fa3305 605 if (variable)
c178c275 606 pcre2_substring_free(variable);
38fa3305 607 if (pattern)
c178c275 608 pcre2_substring_free(pattern);
38fa3305 609
6accaf43
MT
610 return r;
611}
612
638abead 613char* pakfire_parser_expand(struct pakfire_parser* parser,
6accaf43
MT
614 const char* namespace, const char* value) {
615 // Return NULL when the value is NULL
616 if (!value)
617 return NULL;
618
619 // Create a working copy of the string we are expanding
620 char* buffer = strdup(value);
621
622 // Fast path to check if there are any variables in here whatsoever
623 char* pos = strchr(value, '%');
624 if (!pos)
625 return buffer;
626
d25dd74f 627 // Compile all regular expressions
bf7acff3 628 int r = pakfire_parser_compile_regexes(parser);
6107586a
MT
629 if (r) {
630 DEBUG(parser->pakfire, "Could not compile regular expressions: %m\n");
aed0b342 631 goto ERROR;
6107586a 632 }
d25dd74f 633
6accaf43 634 // Expand all variables
d25dd74f 635 r = pakfire_parser_expand_variables(parser, namespace, &buffer);
6107586a
MT
636 if (r) {
637 DEBUG(parser->pakfire, "Failed to expand variables in '%s': %m\n", value);
aed0b342 638 goto ERROR;
6107586a 639 }
6accaf43 640
d25dd74f
MT
641 // Expand all commands
642 if (parser->flags & PAKFIRE_PARSER_FLAGS_EXPAND_COMMANDS) {
643 r = pakfire_parser_expand_commands(parser, &buffer);
6107586a
MT
644 if (r) {
645 DEBUG(parser->pakfire, "Failed to expand commands in '%s': %m\n", value);
aed0b342 646 goto ERROR;
6107586a 647 }
d25dd74f
MT
648 }
649
fb077c4c 650 return buffer;
aed0b342
MT
651
652ERROR:
653 if (buffer)
654 free(buffer);
655
656 return NULL;
fb077c4c
MT
657}
658
638abead 659char* pakfire_parser_get(struct pakfire_parser* parser, const char* namespace, const char* name) {
aa75cc88 660 const char* value = pakfire_parser_get_raw(parser, namespace, name);
1a7200b5 661
fb077c4c 662 // Return NULL when nothing was found
1a7200b5 663 if (!value)
fb077c4c
MT
664 return NULL;
665
666 // Otherwise return the expanded value
aa75cc88 667 return pakfire_parser_expand(parser, namespace, value);
fb077c4c
MT
668}
669
638abead 670char** pakfire_parser_get_split(struct pakfire_parser* parser,
e10e1ad1
MT
671 const char* namespace, const char* name, char delim) {
672 char* value = pakfire_parser_get(parser, namespace, name);
673 if (!value)
674 return NULL;
675
676 // Split the string
d973a13d 677 char** list = pakfire_string_split(value, delim);
e10e1ad1
MT
678 free(value);
679
680 return list;
681}
682
638abead 683char** pakfire_parser_list_namespaces(struct pakfire_parser* parser,
fa3cff8d
MT
684 const char* filter) {
685 char** namespaces = NULL;
686 unsigned int counter = 0;
687
688 for (unsigned int i = 0; i < parser->num_declarations; i++) {
689 struct pakfire_parser_declaration* d = parser->declarations[i];
c8474e4f 690
fa3cff8d
MT
691 if (filter) {
692 int r = fnmatch(filter, d->namespace, 0);
693
694 // Skip declaration if it does not match
695 if (r == FNM_NOMATCH)
696 continue;
697
698 // Check for any errors
699 else if (r > 0) {
b1772bfb 700 ERROR(parser->pakfire, "fnmatch failed: %m\n");
fa3cff8d
MT
701 if (namespaces)
702 free(namespaces);
703
704 return NULL;
705 }
706 }
707
708 // Does this already exist on the list?
709 if (namespaces) {
710 int found = 0;
711
17689fc7 712 for (char** namespace = namespaces; *namespace; namespace++) {
fa3cff8d
MT
713 if (strcmp(d->namespace, *namespace) == 0) {
714 found = 1;
715 break;
716 }
717 }
718
719 // Skip adding if it already exists
720 if (found)
721 continue;
722 }
723
724 namespaces = reallocarray(namespaces, counter + 2, sizeof(*namespaces));
725 if (!namespaces)
726 return NULL;
727
c8474e4f 728 // Add namespace and terminate the array
fa3cff8d 729 namespaces[counter++] = d->namespace;
fa3cff8d 730 namespaces[counter] = NULL;
c8474e4f 731 }
fa3cff8d
MT
732
733 return namespaces;
734}
735
638abead 736int pakfire_parser_merge(struct pakfire_parser* parser1, struct pakfire_parser* parser2) {
02ac7cbd
MT
737 struct pakfire_parser_declaration* d = NULL;
738 char* namespace = NULL;
739 char* value = NULL;
740 int r;
741
d310f14c
MT
742 DEBUG(parser1->pakfire, "Merging parsers %p and %p\n", parser1, parser2);
743
c7577606
MT
744 if (!parser2) {
745 errno = EINVAL;
746 return 1;
747 }
748
1a7200b5
MT
749 // Do not try to merge a parser with itself
750 if (parser1 == parser2)
122e45f5 751 return EINVAL;
1a7200b5 752
fcbbe16e 753 for (unsigned int i = 0; i < parser2->num_declarations; i++) {
02ac7cbd 754 d = parser2->declarations[i];
fcbbe16e
MT
755 if (!d)
756 break;
d310f14c 757
02ac7cbd
MT
758 // Make the new namespace
759 namespace = pakfire_parser_join("%s.%s", parser2->namespace, d->namespace);
760 if (!namespace) {
761 r = 1;
762 goto OUT;
763 }
764
765 const char* old_value = NULL;
766
767 // Fetch the old value if we are supposed to be appending
768 if (d->flags & PAKFIRE_PARSER_DECLARATION_APPEND) {
769 old_value = pakfire_parser_get_raw(parser1, namespace, d->name);
770
771 // XXX This is not ideal, to only reset once we have found an old
772 // value because we might carry this over too far.
773 // However, this is the only way to fix #12997
774 if (old_value)
775 d->flags &= ~PAKFIRE_PARSER_DECLARATION_APPEND;
776 }
777
778 // Make the new value
779 value = pakfire_parser_join("%s %s", old_value, d->value);
780 if (!value) {
781 r = 1;
782 goto OUT;
783 }
713da225 784
02ac7cbd
MT
785 // Set everything in parser 1
786 r = pakfire_parser_set(parser1, namespace, d->name, value, d->flags);
122e45f5 787 if (r)
02ac7cbd
MT
788 goto OUT;
789
790OUT:
791 if (namespace)
792 free(namespace);
793 if (value)
794 free(value);
795
796 if (r)
797 break;
d310f14c
MT
798 }
799
02ac7cbd 800 return r;
d310f14c
MT
801}
802
638abead 803int pakfire_parser_read(struct pakfire_parser* parser, FILE* f,
4b7699d9 804 struct pakfire_parser_error** error) {
fb077c4c
MT
805 char* data;
806 size_t len;
807
808 int r = pakfire_read_file_into_buffer(f, &data, &len);
809 if (r)
810 return r;
811
4b7699d9 812 r = pakfire_parser_parse_data(parser, data, len, error);
89045ec6
MT
813
814 if (data)
f0d6233d 815 free(data);
89045ec6 816
fb077c4c 817 return r;
89045ec6 818}
dac3330d 819
638abead 820int pakfire_parser_read_file(struct pakfire_parser* parser, const char* path,
4b7699d9 821 struct pakfire_parser_error** error) {
68516038
MT
822 DEBUG(parser->pakfire, "Parsing %s...\n", path);
823
774aeac4
MT
824 FILE* f = fopen(path, "r");
825 if (!f)
826 return 1;
827
4b7699d9 828 int r = pakfire_parser_read(parser, f, error);
774aeac4
MT
829 fclose(f);
830
831 return r;
832}
833
638abead 834int pakfire_parser_parse(struct pakfire_parser* parser,
4b7699d9
MT
835 const char* data, size_t size, struct pakfire_parser_error** error) {
836 return pakfire_parser_parse_data(parser, data, size, error);
40f17018
MT
837}
838
638abead 839char* pakfire_parser_dump(struct pakfire_parser* parser) {
20440ba7 840 char buffer[NAME_MAX*2 + 1];
dac3330d
MT
841 char* s = NULL;
842
843 for (unsigned int i = 0; i < parser->num_declarations; i++) {
844 struct pakfire_parser_declaration* d = parser->declarations[i];
845
846 if (d) {
20440ba7
MT
847 if (*d->namespace)
848 pakfire_string_format(buffer, "%s.%s", d->namespace, d->name);
dac3330d 849 else
20440ba7 850 pakfire_string_set(buffer, d->name);
aa75cc88
MT
851
852 asprintf(&s, "%s%-24s = %s\n", (s) ? s : "", buffer, d->value);
dac3330d
MT
853 }
854 }
855
856 return s;
857}
40f17018 858
638abead 859const char* pakfire_parser_get_namespace(struct pakfire_parser* parser) {
40f17018
MT
860 return parser->namespace;
861}
713da225 862
638abead 863int pakfire_parser_set_namespace(struct pakfire_parser* parser, const char* namespace) {
713da225
MT
864 if (parser->namespace)
865 free(parser->namespace);
866
867 if (namespace)
868 parser->namespace = strdup(namespace);
869 else
870 parser->namespace = NULL;
871
872 DEBUG(parser->pakfire, "%p: Set namespace to: %s\n", parser, parser->namespace);
873
874 return 0;
875}
4b7699d9 876
657a5c72 877char** pakfire_parser_make_environ(struct pakfire_parser* parser) {
2ffd21f9
MT
878 char** envp = NULL;
879 unsigned int num = 0;
880
881 for (unsigned int i = 0; i < parser->num_declarations; i++) {
882 struct pakfire_parser_declaration* d = parser->declarations[i];
883 if (!d)
884 continue;
885
886 // Is the export flag set?
887 if (d->flags & PAKFIRE_PARSER_DECLARATION_EXPORT) {
888 char* buffer = NULL;
889
890 char* value = pakfire_parser_expand(parser, d->namespace, d->value);
891 if (!value)
892 goto ERROR;
893
894 // Build line
895 int r = asprintf(&buffer, "%s=%s", d->name, value);
896 free(value);
897 if (r < 0)
898 goto ERROR;
899
900 // Extend the array
901 envp = reallocarray(envp, num + 2, sizeof(*envp));
902 if (!envp)
903 goto ERROR;
904
905 envp[num++] = buffer;
906 envp[num] = NULL;
907 }
908 }
909
910 return envp;
911
912ERROR:
913 if (envp) {
914 for (char** e = envp; *e; e++)
915 free(*e);
916 free(envp);
917 }
918
919 return NULL;
920}
921
638abead 922int pakfire_parser_create_package(struct pakfire_parser* parser,
4651122b 923 struct pakfire_package** pkg, struct pakfire_repo* repo, const char* namespace, const char* default_arch) {
f59d680a
MT
924 int r = 1;
925
926 char* name = NULL;
f59d680a 927 char* evr = NULL;
57044dfe 928 char* arch = NULL;
6f3fad3b 929 char* deps = NULL;
f59d680a 930
17689fc7
MT
931 DEBUG(parser->pakfire, "Building package from namespace '%s'\n", namespace);
932
f59d680a
MT
933 // Fetch name
934 name = pakfire_parser_get(parser, namespace, "name");
f3b3ed8e 935 if (!name || !*name) {
f59d680a
MT
936 ERROR(parser->pakfire, "Name is empty\n");
937 goto CLEANUP;
938 }
939
57044dfe
MT
940 // Fetch EVR
941 evr = pakfire_parser_get(parser, namespace, "evr");
942 if (!evr || !*evr) {
943 ERROR(parser->pakfire, "EVR is empty\n");
f59d680a
MT
944 goto CLEANUP;
945 }
946
947 // Fetch arch
948 arch = pakfire_parser_get(parser, namespace, "arch");
f3b3ed8e 949 if (!arch || !*arch) {
08bcb46a
MT
950 if (default_arch) {
951 arch = strdup(default_arch);
952 if (!arch)
953 goto CLEANUP;
954 } else {
955 ERROR(parser->pakfire, "Arch is empty\n");
956 goto CLEANUP;
957 }
f59d680a
MT
958 }
959
f59d680a 960 // Create a new package object
33ad2a01
MT
961 r = pakfire_package_create(pkg, parser->pakfire, repo, name, evr, arch);
962 if (r) {
f3c94463 963 ERROR(parser->pakfire, "Could not create package: %m\n");
f59d680a
MT
964 goto CLEANUP;
965 }
966
5848e7cb
MT
967 // Is this a source package?
968 int is_source = pakfire_package_is_source(*pkg);
969
df552c32
MT
970 // Assign a new UUID to this package
971 char* uuid = pakfire_generate_uuid();
972 if (!uuid) {
b1772bfb 973 ERROR(parser->pakfire, "Generating a UUID failed: %m\n");
df552c32
MT
974 goto CLEANUP;
975 }
976
74468e4f 977 pakfire_package_set_string(*pkg, PAKFIRE_PKG_UUID, uuid);
df552c32
MT
978 free(uuid);
979
d73ca64f
MT
980 // Set build time
981 time_t now = time(NULL);
982
3f327c3c 983 pakfire_package_set_num(*pkg, PAKFIRE_PKG_BUILD_TIME, now);
d73ca64f 984
f00837c0
MT
985 // Assign more attributes
986 const struct attribute {
987 const char* name;
74468e4f 988 const enum pakfire_package_key key;
f00837c0 989 } attributes[] = {
74468e4f
MT
990 { "summary", PAKFIRE_PKG_SUMMARY },
991 { "description", PAKFIRE_PKG_DESCRIPTION, },
992 { "license", PAKFIRE_PKG_LICENSE, },
993 { "url", PAKFIRE_PKG_URL, },
994 { "groups", PAKFIRE_PKG_GROUPS, },
995 { "vendor", PAKFIRE_PKG_VENDOR, },
145d0efe 996 { "packager", PAKFIRE_PKG_PACKAGER, },
f00837c0
MT
997 { NULL },
998 };
999
1000 for (const struct attribute* a = attributes; a->name; a++) {
1001 char* value = pakfire_parser_get(parser, namespace, a->name);
1002 if (!value)
1003 continue;
1004
74468e4f 1005 r = pakfire_package_set_string(*pkg, a->key, value);
f00837c0 1006 free(value);
74468e4f
MT
1007
1008 if (r) {
1009 ERROR(parser->pakfire, "Could not set %s: %m\n", a->name);
1010 goto CLEANUP;
1011 }
f00837c0
MT
1012 }
1013
b81a64ec 1014 // Fetch build dependencies
5848e7cb 1015 if (is_source) {
6f3fad3b
MT
1016 deps = pakfire_parser_get(parser, "build", "requires");
1017 if (deps) {
1018 r = pakfire_str2deps(parser->pakfire, *pkg, PAKFIRE_PKG_REQUIRES, deps);
1019 if (r)
1020 goto CLEANUP;
8e3a7b94
MT
1021 }
1022 } else {
6f3fad3b
MT
1023 for (const struct pakfire_dep* dep = pakfire_deps; dep->key; dep++) {
1024 deps = pakfire_parser_get(parser, namespace, dep->name);
1025 if (deps) {
1026 r = pakfire_str2deps(parser->pakfire, *pkg, dep->key, deps);
1027 if (r)
1028 goto CLEANUP;
8e3a7b94
MT
1029 }
1030 }
5848e7cb
MT
1031 }
1032
f59d680a
MT
1033 // All okay
1034 r = 0;
1035
1036CLEANUP:
f3c94463
MT
1037 if (r)
1038 ERROR(parser->pakfire, "Could not create package: %m\n");
1039
f59d680a
MT
1040 if (name)
1041 free(name);
57044dfe
MT
1042 if (evr)
1043 free(evr);
f59d680a
MT
1044 if (arch)
1045 free(arch);
6f3fad3b
MT
1046 if (deps)
1047 free(deps);
f59d680a
MT
1048
1049 return r;
1050}
1051
4b7699d9
MT
1052// Error
1053
1054struct pakfire_parser_error {
657a5c72 1055 struct pakfire_parser* parser;
4b7699d9
MT
1056 int nrefs;
1057
1058 char* filename;
1059 int line;
1060 char* message;
1061};
1062
638abead 1063int pakfire_parser_error_create(struct pakfire_parser_error** error,
657a5c72 1064 struct pakfire_parser* parser, const char* filename, int line, const char* message) {
4b7699d9
MT
1065 struct pakfire_parser_error* e = calloc(1, sizeof(*e));
1066 if (!e)
1067 return ENOMEM;
1068
1069 // Initialize reference counter
1070 e->nrefs = 1;
1071
1072 e->parser = pakfire_parser_ref(parser);
1073
1074 // Copy all input values
1075 if (filename)
1076 e->filename = strdup(filename);
1077
1078 e->line = line;
1079
1080 if (message)
1081 e->message = strdup(message);
1082
1083 *error = e;
1084
1085 return 0;
1086}
1087
638abead 1088struct pakfire_parser_error* pakfire_parser_error_ref(
4b7699d9
MT
1089 struct pakfire_parser_error* error) {
1090 ++error->nrefs;
1091
1092 return error;
1093}
1094
1095static void pakfire_parser_error_free(struct pakfire_parser_error* error) {
1096 pakfire_parser_unref(error->parser);
1097
1098 if (error->filename)
1099 free(error->filename);
1100
1101 if (error->message)
1102 free(error->message);
1103
1104 free(error);
1105}
1106
638abead 1107struct pakfire_parser_error* pakfire_parser_error_unref(
4b7699d9
MT
1108 struct pakfire_parser_error* error) {
1109 if (--error->nrefs > 0)
1110 return error;
1111
1112 pakfire_parser_error_free(error);
1113
1114 return NULL;
1115}
1116
638abead 1117const char* pakfire_parser_error_get_filename(
4b7699d9
MT
1118 struct pakfire_parser_error* error) {
1119 return error->filename;
1120}
1121
638abead 1122int pakfire_parser_error_get_line(struct pakfire_parser_error* error) {
4b7699d9
MT
1123 return error->line;
1124}
1125
638abead 1126const char* pakfire_parser_error_get_message(
4b7699d9
MT
1127 struct pakfire_parser_error* error) {
1128 return error->message;
1129}