]> git.ipfire.org Git - pakfire.git/blame - src/libpakfire/util.c
repo: Set repo pointer for internal repositories, too
[pakfire.git] / src / libpakfire / util.c
CommitLineData
221cc3ce
MT
1/*#############################################################################
2# #
3# Pakfire - The IPFire package management system #
4# Copyright (C) 2013 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
5837952f 21#include <ctype.h>
3854acbd 22#include <errno.h>
62b60e37 23#include <fcntl.h>
e75d1e3c 24#include <ftw.h>
221cc3ce
MT
25#include <libgen.h>
26#include <math.h>
27#include <stddef.h>
28#include <stdio.h>
29#include <stdlib.h>
30#include <string.h>
6582a143 31#include <sys/resource.h>
3854acbd
MT
32#include <sys/stat.h>
33#include <sys/types.h>
526e4cec 34#include <time.h>
3854acbd 35#include <unistd.h>
221cc3ce 36
88124868 37#include <archive.h>
53f5745e 38#include <archive_entry.h>
0351af83 39#include <json.h>
9bddb328 40#include <solv/pool.h>
df552c32
MT
41#include <uuid/uuid.h>
42
221cc3ce 43#include <pakfire/constants.h>
3854acbd 44#include <pakfire/logging.h>
31480bee 45#include <pakfire/package.h>
9bddb328 46#include <pakfire/util.h>
221cc3ce 47
563e9600
MT
48#define NSEC_PER_SEC 1000000000
49
9bddb328
MT
50static Id pakfire_parse_namespace(Pool* pool, const char* s) {
51 const char* p = strchr(s, '(');
52 if (!p)
53 return 0;
54
55 // Store the namespace ID
56 Id namespace = pool_strn2id(pool, s, p - s, 1);
57
58 // Find the end of the string
59 s = strrchr(p, ')');
60 if (!s)
61 return 0;
62
63 Id id = pool_strn2id(pool, p + 1, s - p - 1, 1);
64
65 // Bring it all together
66 return pool_rel2id(pool, namespace, id, REL_NAMESPACE, 1);
67}
68
ac4c607b 69Id pakfire_parse_dep(struct pakfire* pakfire, const char* s) {
9bddb328
MT
70 Id id;
71
72 if (!s) {
73 errno = EINVAL;
74 return 0;
75 }
76
075bebef
MT
77 // Ignore empty strings
78 if (!*s)
79 return 0;
80
9bddb328
MT
81 Pool* pool = pakfire_get_solv_pool(pakfire);
82
83 // Consume any leading space
84 if (isspace(*s))
85 s++;
86
87 const char* p = s;
88
89 // Find the first part (before =, >= or <=)
90 while (*p && !isspace(*p) && *p != '<' && *p != '=' && *p != '>')
91 p++;
92
93 // The length of the first part
94 size_t l = p - s;
95
96 // Add name to pool
97 if (pakfire_string_startswith(s, "pakfire("))
98 id = pakfire_parse_namespace(pool, s);
99 else
100 id = pool_strn2id(pool, s, l, 1);
101
102 // Consume any more space
103 if (isspace(*p))
104 p++;
105
106 if (*p == '<' || *p == '=' || *p == '>') {
107 int flags = 0;
108
109 while (1) {
110 if (*p == '<')
111 flags |= REL_LT;
112 else if (*p == '=')
113 flags |= REL_EQ;
114 else if (*p == '>')
115 flags |= REL_GT;
116 else
117 break;
118
119 p++;
120 }
121
122 // Consume any more space
123 if (isspace(*p))
124 p++;
125
126 // Add EVR to pool
127 Id evr = pool_str2id(pool, p, 1);
128
129 // Combine everything
130 id = pool_rel2id(pool, id, evr, flags, 1);
131 }
132
133 return id;
134}
135
ac4c607b 136void pakfire_parse_deps(struct pakfire* pakfire, struct pakfire_package* pkg,
31480bee 137 void (*func)(struct pakfire_package* pkg, const char* dep), const char* deps) {
b81a64ec
MT
138 char* p = strdupa(deps);
139
140 while (*p) {
141 char* e = strchr(p, '\n');
142
143 // Terminate the string
144 if (e)
145 *e = '\0';
146
147 // Add the dependency
148 func(pkg, p);
149
150 // End loop when we reached the end
151 if (!e)
152 break;
153
154 // Or continue at the next line
155 p = e + 1;
156 }
157}
158
714c91a2 159int pakfire_string_startswith(const char* s, const char* prefix) {
5e3ca618 160 return !strncmp(s, prefix, strlen(prefix));
5c409596
MT
161}
162
be11aa6e
MT
163int pakfire_string_endswith(const char* s, const char* suffix) {
164 return !strcmp(s + strlen(s) - strlen(suffix), suffix);
165}
166
f4d93071
MT
167int pakfire_string_matches(const char* s, const char* pattern) {
168 return !!strstr(s, pattern);
169}
170
5c76be2c
MT
171char* pakfire_unquote_in_place(char* s) {
172 if (!s || !*s)
173 return s;
174
175 // Is the first character a quote?
176 if (*s != '"')
177 return s;
178
179 // Find the end of value
180 size_t l = strlen(s);
181 if (!l)
182 return s;
183
184 // Is the last character a quote?
185 if (s[l - 1] != '"')
186 return s;
187
188 // The string seems to be in quotes; remove them
189 s[l - 1] = '\0';
190 s++;
191
192 return s;
193}
194
89dbb9ac 195int pakfire_string_partition(const char* s, const char* delim, char** s1, char** s2) {
5837952f
MT
196 char* p = strstr(s, delim);
197
198 // Delim was not found
199 if (!p) {
200 *s1 = NULL;
201 *s2 = NULL;
202 return 1;
203 }
204
205 // Length of string before delim
206 size_t l = p - s;
207
208 char* buffer = malloc(l + 1);
209 if (!buffer)
210 return -ENOMEM;
211
212 // Copy first part
213 *s1 = memcpy(buffer, s, l);
214 buffer[l] = '\0';
215
216 // Copy second part
217 *s2 = strdup(p + strlen(delim));
218
219 return 0;
220}
221
8de06755 222char* pakfire_string_replace(const char* s, const char* pattern, const char* repl) {
b961e8d5
MT
223 // Return NULL on no input or no pattern
224 if (!s || !pattern) {
225 errno = EINVAL;
226 return NULL;
227 }
228
229 // Replace with nothing when repl is NULL
230 if (!repl)
231 repl = "";
232
b8377a9f
MT
233 char* result = NULL;
234 const char** cache = NULL;
235 unsigned int count = 0;
236
237 const size_t pattern_length = strlen(pattern);
238
239 // Working pointer
240 const char* p = s;
241
242 // Find all occurrences of pattern and store their location
243 while (1) {
244 const char* needle = strstr(p, pattern);
245 if (!needle)
246 break;
247
248 // Make space in the cache
249 cache = reallocarray(cache, sizeof(*cache), count + 1);
250 cache[count++] = needle;
251
252 // Move p forward
253 p = needle + pattern_length;
254 }
255
256 // Copy the string if no occurence was found
257 if (count == 0) {
258 result = strdup(s);
259 goto ERROR;
260 }
261
262 // Store the end pointer
263 cache = reallocarray(cache, sizeof(*cache), count + 1);
264 cache[count] = s + strlen(s);
265
266 const size_t repl_length = strlen(repl);
267
268 // Determine the length of the final string
269 const size_t length = strlen(s) + ((repl_length - pattern_length) * count);
270
271 // Allocate enough memory for the result
272 result = malloc(length + 1);
273 if (!result)
274 goto ERROR;
275
276 // Reset p
277 p = s;
278
279 // Working pointer for the result
280 char* r = result;
281
282 // Copy everything up to the first match
283 ssize_t l = cache[0] - s;
284 memcpy(r, p, l);
285 r += l;
286 p += l;
287
288 for (unsigned int i = 0; i < count; i++) {
289 // Put replacement here
290 memcpy(r, repl, repl_length);
291 r += repl_length;
292 p += pattern_length;
293
294 // Determine the length between two matches
295 l = cache[i+1] - (cache[i] + pattern_length);
296
297 memcpy(r, p, l);
298 r += l;
299 p += l;
300 }
301
302 // Terminate the string
303 result[length] = '\0';
304
305ERROR:
306 if (cache)
307 free(cache);
308
309 return result;
310}
311
c81287d2
MT
312static unsigned int pakfire_chrcnt(const char* s, char delim) {
313 size_t length = strlen(s);
603ca1e0 314
c81287d2 315 unsigned int count = 0;
603ca1e0 316
c81287d2
MT
317 for (unsigned int i = 0; i < length; i++)
318 if (s[i] == delim)
603ca1e0 319 count++;
c81287d2
MT
320
321 return count;
322}
323
324char** pakfire_split_string(const char* s, char delim) {
325 char** array = NULL;
326
327 if (!s) {
328 errno = EINVAL;
329 return NULL;
603ca1e0
MT
330 }
331
c81287d2
MT
332 // Count how often we need to split
333 unsigned int count = pakfire_chrcnt(s, delim) + 1;
334
335 // Allocate array
336 array = calloc(count + 1, sizeof(*array));
337 if (!array)
338 return NULL;
339
340 // Copy string to stack
341 char* p = strdupa(s);
342 if (!p)
343 return NULL;
603ca1e0 344
603ca1e0 345 unsigned int i = 0;
603ca1e0 346 while (*p) {
c81287d2 347 char* e = strchr(p, delim);
603ca1e0 348
c81287d2
MT
349 // Terminate the string
350 if (e)
351 *e = '\0';
352
353 // Add string to the array
354 array[i++] = strdup(p);
603ca1e0 355
c81287d2
MT
356 // End loop when we reached the end
357 if (!e)
358 break;
359
360 // Or continue at the next line
361 p = e + 1;
362 }
603ca1e0 363
c81287d2 364 return array;
603ca1e0
MT
365}
366
b03e1127
MT
367char* pakfire_string_join(char** list, const char* delim) {
368 if (!list)
369 return NULL;
370
371 size_t length = 0;
372 unsigned int elements = 0;
373
374 // Count the number of elements and the total length
375 for (char** item = list; *item; item++) {
376 length += strlen(*item);
377 elements++;
378 }
379
380 // Empty list?
381 if (!elements)
382 return NULL;
383
384 // Add the delimiters
385 length += strlen(delim) * (elements - 1);
386
387 // Allocate the result string
388 char* string = malloc(length + 1);
389 if (!string)
390 return NULL;
391
392 // Pointer to where we are writing
393 char* p = string;
394
395 size_t bytes_left = length;
396 size_t bytes_written;
397
398 for (char** item = list; *item; item++) {
399 bytes_written = snprintf(p, bytes_left, "%s", *item);
400
401 bytes_left -= bytes_written;
402 p += bytes_written;
403
404 // Write the delimiter
405 if (bytes_left) {
406 bytes_written = snprintf(p, bytes_left, "%s", delim);
407
408 bytes_left -= bytes_written;
409 p += bytes_written;
410 }
411 }
412
413 return string;
414}
415
cc90545a 416int pakfire_format_size(char* dst, size_t length, double value) {
df56e4ef 417 const char* units[] = {
3f1f5408
MT
418 "%.0f ",
419 "%.0fk",
420 "%.1fM",
421 "%.1fG",
422 "%.1fT",
df56e4ef
MT
423 NULL
424 };
221cc3ce
MT
425 const char** unit = units;
426
cc90545a
MT
427 while (*(unit + 1) && value >= 1024.0) {
428 value /= 1024.0;
221cc3ce
MT
429 unit++;
430 }
431
df56e4ef
MT
432#pragma GCC diagnostic push
433#pragma GCC diagnostic ignored "-Wformat-nonliteral"
68d26a6a
MT
434 return snprintf(dst, length, *unit, value);
435#pragma GCC diagnostic pop
436}
437
438int pakfire_format_speed(char* dst, size_t length, double value) {
439 const char* units[] = {
440 "%4.0fB/s",
441 "%4.0fkB/s",
442 "%4.1fMB/s",
443 "%4.1fGB/s",
444 "%4.1fTB/s",
445 NULL
446 };
447 const char** unit = units;
448
449 while (*(unit + 1) && value >= 1024.0) {
450 value /= 1024.0;
451 unit++;
452 }
453
454#pragma GCC diagnostic push
455#pragma GCC diagnostic ignored "-Wformat-nonliteral"
456 return snprintf(dst, length, *unit, value);
df56e4ef 457#pragma GCC diagnostic pop
221cc3ce
MT
458}
459
526e4cec
MT
460#pragma GCC diagnostic push
461#pragma GCC diagnostic ignored "-Wformat-nonliteral"
462static char* pakfire_strftime(const char* format, time_t t) {
7500066c 463 char string[128];
526e4cec
MT
464 struct tm* tm = gmtime(&t);
465
7500066c 466 strftime(string, sizeof(string) - 1, format, tm);
526e4cec 467
5d901566 468 return strdup(string);
526e4cec
MT
469}
470#pragma GCC diagnostic pop
471
472char* pakfire_format_date(time_t t) {
473 return pakfire_strftime("%Y-%m-%d", t);
474}
475
99865093 476int __pakfire_path_join(char* dest, size_t length,
384d009a 477 const char* first, const char* second) {
14143513
MT
478 if (!first)
479 return snprintf(dest, length, "%s", second);
480
221cc3ce 481 if (!second)
384d009a 482 return snprintf(dest, length, "%s", first);
221cc3ce 483
14143513
MT
484 // Remove leading slashes from second argument
485 while (*second == '/')
486 second++;
221cc3ce 487
384d009a 488 return snprintf(dest, length, "%s/%s", first, second);
221cc3ce
MT
489}
490
36790d86 491const char* pakfire_path_relpath(const char* root, const char* path) {
5e3ca618 492 if (pakfire_string_startswith(path, root))
55b57cf6 493 return path + strlen(root);
55b57cf6
MT
494
495 return NULL;
496}
497
8c22118b
MT
498int pakfire_path_exists(const char* path) {
499 return !access(path, F_OK);
500}
501
a5e9cd4b
MT
502time_t pakfire_path_age(const char* path) {
503 struct stat st;
504
505 int r = stat(path, &st);
506 if (r == 0) {
507 // Get current timestamp
508 time_t now = time(NULL);
509
510 // Return the difference since the file has been created and now
511 return now - st.st_ctime;
512 }
513
514 return -1;
515}
516
05e8d3c9 517char* pakfire_basename(const char* path) {
5d901566 518 char* name = strdup(path);
221cc3ce 519
2e9ddb9c 520 char* r = basename(name);
b196ec9d 521 if (r)
5d901566 522 r = strdup(r);
b196ec9d 523
f0d6233d 524 free(name);
d11561f7
MT
525
526 return r;
221cc3ce
MT
527}
528
41a7a52f 529char* pakfire_dirname(const char* path) {
5d901566 530 char* parent = strdup(path);
221cc3ce 531
2e9ddb9c 532 char* r = dirname(parent);
b196ec9d 533 if (r)
5d901566 534 r = strdup(r);
b196ec9d 535
f0d6233d 536 free(parent);
d11561f7
MT
537
538 return r;
221cc3ce
MT
539}
540
221cc3ce
MT
541char* pakfire_remove_trailing_newline(char* str) {
542 ssize_t pos = strlen(str) - 1;
543
544 if (str[pos] == '\n')
545 str[pos] = '\0';
546
547 return str;
548}
658c740d 549
a566ff7f 550int pakfire_read_file_into_buffer(FILE* f, char** buffer, size_t* len) {
3bf7e142
MT
551 if (!f)
552 return -EBADF;
553
554 int r = fseek(f, 0, SEEK_END);
555 if (r)
556 return r;
557
558 // Save length of file
559 *len = ftell(f);
560
561 // Go back to the start
562 r = fseek(f, 0, SEEK_SET);
563 if (r)
564 return r;
565
566 // Allocate buffer
547759ae 567 *buffer = malloc((sizeof(**buffer) * *len) + 1);
3bf7e142
MT
568 if (!*buffer)
569 return -ENOMEM;
570
571 // Read content
572 fread(*buffer, *len, sizeof(**buffer), f);
573
574 // Check we encountered any errors
575 r = ferror(f);
576 if (r) {
f0d6233d 577 free(*buffer);
3bf7e142
MT
578 return r;
579 }
580
581 // Terminate the buffer
582 (*buffer)[*len] = '\0';
583
584 return 0;
585}
312fd26f 586
ab96da22 587char* pakfire_generate_uuid() {
df552c32
MT
588 uuid_t uuid;
589
590 // Generate a new random value
591 uuid_generate_random(uuid);
592
593 char* ret = malloc(UUID_STR_LEN + 1);
594 if (!ret)
595 return NULL;
596
597 // Convert it to string
598 uuid_unparse_lower(uuid, ret);
599
600 // Terminate string
601 ret[UUID_STR_LEN] = '\0';
602
603 return ret;
604}
7ab0465c 605
457feacb
MT
606int pakfire_tty_is_noninteractive(void) {
607 const int fds[] = {
608 STDIN_FILENO,
609 STDOUT_FILENO,
610 STDERR_FILENO,
611 -1,
612 };
613
614 for (const int* fd = fds; *fd >= 0; fd++) {
615 if (!isatty(*fd))
616 return 1;
617 }
618
619 return 0;
620}
621
fa106e1b 622char* __pakfire_hexlify(const unsigned char* digest, const size_t length) {
7ab0465c
MT
623 const char* hexdigits = "0123456789abcdef";
624
625 char* s = malloc((length * 2) + 1);
626 if (!s)
627 return NULL;
628
629 for (unsigned int i = 0, j = 0; i < length; i++) {
630 char b = digest[i];
631
632 s[j++] = hexdigits[(b >> 4) & 0xf];
633 s[j++] = hexdigits[(b & 0x0f)];
634 }
635
636 // Terminate result
637 s[length * 2] = '\0';
638
639 return s;
640}
62b60e37 641
d0e6b214
MT
642static int parse_nibble(char nibble) {
643 // Handle digits
644 if (nibble >= '0' && nibble <= '9')
645 return nibble - '0';
646
647 // Handle lowercase letters
648 if (nibble >= 'a' && nibble <= 'f')
649 return 10 + nibble - 'a';
650
651 // Handle uppercase letters
652 if (nibble >= 'A' && nibble <= 'F')
653 return 10 + nibble - 'A';
654
655 // Error
656 return -1;
657}
658
01f8f6b0 659int __pakfire_unhexlify(unsigned char* dst, const size_t l, const char* src) {
d0e6b214
MT
660 if (!src) {
661 errno = EINVAL;
662 return 1;
663 }
8bfcf741 664
d0e6b214
MT
665 // Determine input length
666 const size_t length = strlen(src);
667
668 for (unsigned int i = 0, j = 0; i < length && j < l; i += 2, j++) {
669 int h = parse_nibble(src[i]);
670 int l = parse_nibble(src[i+1]);
671
672 // Check for invalid input
673 if (h < 0 || l < 0) {
674 errno = EINVAL;
8bfcf741 675 return 1;
d0e6b214 676 }
8bfcf741 677
d0e6b214
MT
678 // Store result
679 dst[j] = h << 4 | l;
8bfcf741
MT
680 }
681
682 return 0;
683}
684
a29c7190 685int pakfire_mkparentdir(const char* path, mode_t mode) {
62b60e37
MT
686 int r;
687
688 char* dirname = pakfire_dirname(path);
689 if (!dirname)
690 return 1;
691
692 // We have arrived at the top of the tree
aba60128 693 if (*dirname == '.' || strcmp(dirname, "/") == 0)
62b60e37
MT
694 return 0;
695
696 // Ensure the parent directory exists
4d47c163 697 r = pakfire_mkparentdir(dirname, mode);
aba60128 698 if (r)
62b60e37 699 goto END;
62b60e37
MT
700
701 // Create this directory
4d47c163 702 r = mkdir(dirname, mode);
62b60e37 703
aba60128
MT
704 // Ignore when the directory already exists
705 if (r && errno == EEXIST)
706 r = 0;
707
62b60e37
MT
708END:
709 free(dirname);
710
711 return r;
712}
713
4d47c163
MT
714int pakfire_mkdir(const char* path, mode_t mode) {
715 int r = pakfire_mkparentdir(path, mode);
716 if (r)
717 return r;
718
719 // Finally, create the directory we want
720 return mkdir(path, mode);
721}
722
62b60e37 723FILE* pakfire_mktemp(char* path) {
4d47c163 724 int r = pakfire_mkparentdir(path, 0);
aba60128
MT
725 if (r)
726 return NULL;
62b60e37
MT
727
728 // Create a temporary result file
729 int fd = mkostemp(path, O_CLOEXEC);
730 if (fd < 0)
731 return NULL;
732
733 // Re-open as file handle
734 return fdopen(fd, "w+");
735}
0351af83 736
e75d1e3c 737char* pakfire_mkdtemp(char* path) {
4d47c163 738 int r = pakfire_mkparentdir(path, 0);
e75d1e3c
MT
739 if (r)
740 return NULL;
741
742 return mkdtemp(path);
743}
744
745static int _unlink(const char* path, const struct stat* stat, int typeflag, struct FTW* ftwbuf) {
746 return remove(path);
747}
748
749int pakfire_rmtree(const char* path, int flags) {
750 int r = nftw(path, _unlink, 64, flags|FTW_DEPTH|FTW_PHYS);
751
752 // Ignore if path didn't exist
753 if (r < 0 && errno == ENOENT)
754 r = 0;
755
756 return r;
757}
758
88124868
MT
759// Archive Stuff
760
761int pakfire_archive_copy_data(struct archive* src, struct archive* dst,
762 struct archive_entry* entry) {
763 const void* buffer;
764 size_t size;
765 off_t offset;
766 int r;
767
768 for (;;) {
769 // Read a block of data
770 r = archive_read_data_block(src, &buffer, &size, &offset);
771 if (r == ARCHIVE_EOF)
772 return ARCHIVE_OK;
773 else if (r)
774 return r;
775
776 // Write the read block of data
777 r = archive_write_data(dst, buffer, size);
778 if (r < 0)
779 return r;
780 }
781}
782
ac4c607b 783int pakfire_archive_copy_data_to_buffer(struct pakfire* pakfire, struct archive* a,
53f5745e
MT
784 struct archive_entry* entry, char** data, size_t* data_size) {
785 *data = NULL;
786 *data_size = 0;
787
788 size_t required_size = archive_entry_size(entry);
789 if (!required_size)
790 return 0;
791
792 // Allocate a block of the required size
b38802ab 793 *data = calloc(1, required_size + 1);
53f5745e
MT
794 if (!*data)
795 return ENOMEM;
796
797 ssize_t bytes_read = archive_read_data(a, *data, required_size);
798 if (bytes_read < 0) {
799 ERROR(pakfire, "Could not read from archive: %s\n", archive_error_string(a));
800 free(*data);
801 return 1;
802 }
803
804 *data_size = bytes_read;
805
806 return 0;
807}
808
0351af83
MT
809// JSON Stuff
810
ac4c607b 811static struct json_object* pakfire_json_parse(struct pakfire* pakfire, FILE* f) {
0351af83
MT
812 struct json_tokener* tokener = NULL;
813 struct json_object* json = NULL;
814 char* buffer = NULL;
815 size_t length;
816
817 // Read everything into memory
818 int r = pakfire_read_file_into_buffer(f, &buffer, &length);
819 if (r)
820 goto ERROR;
821
822 // Create tokener
823 tokener = json_tokener_new();
824 if (!tokener) {
b1772bfb 825 ERROR(pakfire, "Could not allocate JSON tokener: %m\n");
0351af83
MT
826 goto ERROR;
827 }
828
829 // Parse JSON from path
830 json = json_tokener_parse_ex(tokener, buffer, length);
831 if (!json) {
832 enum json_tokener_error error = json_tokener_get_error(tokener);
833
834 ERROR(pakfire, "JSON parsing error: %s\n", json_tokener_error_desc(error));
835 goto ERROR;
836 }
837
838 // Log what we have parsed
839 DEBUG(pakfire, "Parsed JSON:\n%s\n",
840 json_object_to_json_string_ext(json,
841 JSON_C_TO_STRING_SPACED | JSON_C_TO_STRING_PRETTY)
842 );
843
844ERROR:
845 if (buffer)
846 free(buffer);
847
848 if (tokener)
849 json_tokener_free(tokener);
850
851 return json;
852}
853
ac4c607b 854struct json_object* pakfire_json_parse_from_file(struct pakfire* pakfire, const char* path) {
0351af83
MT
855 FILE* f = fopen(path, "r");
856 if (!f)
857 return NULL;
858
859 struct json_object* json = pakfire_json_parse(pakfire, f);
860 fclose(f);
861
862 return json;
863}
563e9600
MT
864
865// Time Stuff
866
867static void timespec_normalize(struct timespec* t) {
868 while (t->tv_nsec >= NSEC_PER_SEC) {
869 t->tv_sec++;
870 t->tv_nsec -= NSEC_PER_SEC;
871 }
872
873 while (t->tv_nsec <= -NSEC_PER_SEC) {
874 t->tv_sec--;
875 t->tv_nsec += NSEC_PER_SEC;
876 }
877}
878
879struct timespec timespec_add(const struct timespec* t1, const struct timespec* t2) {
880 struct timespec r = {
881 .tv_sec = t1->tv_sec + t2->tv_sec,
882 .tv_nsec = t2->tv_nsec + t2->tv_nsec,
883 };
884
885 // Correct any negative values
886 timespec_normalize(&r);
887
888 return r;
889}
890
891struct timespec timespec_from_ms(int milliseconds) {
892 struct timespec t = {
893 .tv_sec = (milliseconds / 1000),
894 .tv_nsec = (milliseconds % 1000) * 1000000,
895 };
896
897 return t;
898}
899
900int timespec_lt(struct timespec* t1, struct timespec* t2) {
901 return (
902 t1->tv_sec < t2->tv_sec ||
903 (t1->tv_sec == t2->tv_sec && t1->tv_nsec < t2->tv_nsec)
904 );
905}
6582a143
MT
906
907// Resource Limits
908
ac4c607b 909int pakfire_rlimit_set(struct pakfire* pakfire, int limit) {
6582a143
MT
910 struct rlimit rl;
911
912 // Sanity check
913 if (limit < 3) {
914 errno = EINVAL;
915 return 1;
916 }
917
918 // Fetch current configuration
919 if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
b1772bfb 920 ERROR(pakfire, "Could not read RLIMIT_NOFILE: %m\n");
6582a143
MT
921 return 1;
922 }
923
924 // Do not attempt to set higher than maximum
925 if ((long unsigned int)limit > rl.rlim_max)
926 limit = rl.rlim_max;
927
928 rl.rlim_cur = limit;
929
930 // Set the new limit
931 if (setrlimit(RLIMIT_NOFILE, &rl) < 0) {
b1772bfb 932 ERROR(pakfire, "Could not set RLIMIT_NOFILE to %lu: %m\n", rl.rlim_cur);
6582a143
MT
933 return 1;
934 }
935
936 DEBUG(pakfire, "RLIMIT_NOFILE set to %d\n", limit);
937
938 return 0;
939}
940
941/*
942 Resets RLIMIT_NOFILE to FD_SETSIZE (e.g. 1024)
943 for compatibility with software that uses select()
944*/
ac4c607b 945int pakfire_rlimit_reset_nofile(struct pakfire* pakfire) {
6582a143
MT
946 return pakfire_rlimit_set(pakfire, FD_SETSIZE);
947}