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