]>
git.ipfire.org Git - pakfire.git/blob - src/libpakfire/util.c
1 /*#############################################################################
3 # Pakfire - The IPFire package management system #
4 # Copyright (C) 2013 Pakfire development team #
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. #
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. #
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/>. #
19 #############################################################################*/
31 #include <sys/resource.h>
33 #include <sys/types.h>
38 #include <archive_entry.h>
40 #include <solv/pool.h>
41 #include <uuid/uuid.h>
43 #include <pakfire/constants.h>
44 #include <pakfire/logging.h>
45 #include <pakfire/package.h>
46 #include <pakfire/util.h>
48 #define NSEC_PER_SEC 1000000000
50 static Id
pakfire_parse_namespace(Pool
* pool
, const char* s
) {
51 const char* p
= strchr(s
, '(');
55 // Store the namespace ID
56 Id
namespace = pool_strn2id(pool
, s
, p
- s
, 1);
58 // Find the end of the string
63 Id id
= pool_strn2id(pool
, p
+ 1, s
- p
- 1, 1);
65 // Bring it all together
66 return pool_rel2id(pool
, namespace, id
, REL_NAMESPACE
, 1);
69 Id
pakfire_parse_dep(struct pakfire
* pakfire
, const char* s
) {
77 // Ignore empty strings
81 Pool
* pool
= pakfire_get_solv_pool(pakfire
);
83 // Consume any leading space
89 // Find the first part (before =, >= or <=)
90 while (*p
&& !isspace(*p
) && *p
!= '<' && *p
!= '=' && *p
!= '>')
93 // The length of the first part
97 if (pakfire_string_startswith(s
, "pakfire("))
98 id
= pakfire_parse_namespace(pool
, s
);
100 id
= pool_strn2id(pool
, s
, l
, 1);
102 // Consume any more space
106 if (*p
== '<' || *p
== '=' || *p
== '>') {
122 // Consume any more space
127 Id evr
= pool_str2id(pool
, p
, 1);
129 // Combine everything
130 id
= pool_rel2id(pool
, id
, evr
, flags
, 1);
136 void pakfire_parse_deps(struct pakfire
* pakfire
, struct pakfire_package
* pkg
,
137 void (*func
)(struct pakfire_package
* pkg
, const char* dep
), const char* deps
) {
138 char* p
= strdupa(deps
);
141 char* e
= strchr(p
, '\n');
143 // Terminate the string
147 // Add the dependency
150 // End loop when we reached the end
154 // Or continue at the next line
159 int pakfire_string_startswith(const char* s
, const char* prefix
) {
166 return !strncmp(s
, prefix
, strlen(prefix
));
169 int pakfire_string_endswith(const char* s
, const char* suffix
) {
176 return !strcmp(s
+ strlen(s
) - strlen(suffix
), suffix
);
179 int pakfire_string_matches(const char* s
, const char* pattern
) {
181 if (!s
|| !pattern
) {
186 return !!strstr(s
, pattern
);
189 char* pakfire_unquote_in_place(char* s
) {
193 // Is the first character a quote?
197 // Find the end of value
198 size_t l
= strlen(s
);
202 // Is the last character a quote?
206 // The string seems to be in quotes; remove them
213 int pakfire_string_partition(const char* s
, const char* delim
, char** s1
, char** s2
) {
214 char* p
= strstr(s
, delim
);
216 // Delim was not found
223 // Length of string before delim
226 char* buffer
= malloc(l
+ 1);
231 *s1
= memcpy(buffer
, s
, l
);
235 *s2
= strdup(p
+ strlen(delim
));
240 char* pakfire_string_replace(const char* s
, const char* pattern
, const char* repl
) {
241 // Return NULL on no input or no pattern
242 if (!s
|| !pattern
) {
247 // Replace with nothing when repl is NULL
252 const char** cache
= NULL
;
253 unsigned int count
= 0;
255 const size_t pattern_length
= strlen(pattern
);
260 // Find all occurrences of pattern and store their location
262 const char* needle
= strstr(p
, pattern
);
266 // Make space in the cache
267 cache
= reallocarray(cache
, sizeof(*cache
), count
+ 1);
268 cache
[count
++] = needle
;
271 p
= needle
+ pattern_length
;
274 // Copy the string if no occurence was found
280 // Store the end pointer
281 cache
= reallocarray(cache
, sizeof(*cache
), count
+ 1);
282 cache
[count
] = s
+ strlen(s
);
284 const size_t repl_length
= strlen(repl
);
286 // Determine the length of the final string
287 const size_t length
= strlen(s
) + ((repl_length
- pattern_length
) * count
);
289 // Allocate enough memory for the result
290 result
= malloc(length
+ 1);
297 // Working pointer for the result
300 // Copy everything up to the first match
301 ssize_t l
= cache
[0] - s
;
306 for (unsigned int i
= 0; i
< count
; i
++) {
307 // Put replacement here
308 memcpy(r
, repl
, repl_length
);
312 // Determine the length between two matches
313 l
= cache
[i
+1] - (cache
[i
] + pattern_length
);
320 // Terminate the string
321 result
[length
] = '\0';
330 static unsigned int pakfire_chrcnt(const char* s
, char delim
) {
331 size_t length
= strlen(s
);
333 unsigned int count
= 0;
335 for (unsigned int i
= 0; i
< length
; i
++)
342 char** pakfire_split_string(const char* s
, char delim
) {
350 // Count how often we need to split
351 unsigned int count
= pakfire_chrcnt(s
, delim
) + 1;
354 array
= calloc(count
+ 1, sizeof(*array
));
358 // Copy string to stack
359 char* p
= strdupa(s
);
365 char* e
= strchr(p
, delim
);
367 // Terminate the string
371 // Add string to the array
372 array
[i
++] = strdup(p
);
374 // End loop when we reached the end
378 // Or continue at the next line
385 char* pakfire_string_join(char** list
, const char* delim
) {
390 unsigned int elements
= 0;
392 // Count the number of elements and the total length
393 for (char** item
= list
; *item
; item
++) {
394 length
+= strlen(*item
);
402 // Add the delimiters
403 length
+= strlen(delim
) * (elements
- 1);
405 // Allocate the result string
406 char* string
= malloc(length
+ 1);
410 // Pointer to where we are writing
413 size_t bytes_left
= length
;
414 size_t bytes_written
;
416 for (char** item
= list
; *item
; item
++) {
417 bytes_written
= snprintf(p
, bytes_left
, "%s", *item
);
419 bytes_left
-= bytes_written
;
422 // Write the delimiter
424 bytes_written
= snprintf(p
, bytes_left
, "%s", delim
);
426 bytes_left
-= bytes_written
;
434 int pakfire_format_size(char* dst
, size_t length
, double value
) {
435 const char* units
[] = {
443 const char** unit
= units
;
445 while (*(unit
+ 1) && value
>= 1024.0) {
450 #pragma GCC diagnostic push
451 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
452 return snprintf(dst
, length
, *unit
, value
);
453 #pragma GCC diagnostic pop
456 int pakfire_format_speed(char* dst
, size_t length
, double value
) {
457 const char* units
[] = {
465 const char** unit
= units
;
467 while (*(unit
+ 1) && value
>= 1024.0) {
472 #pragma GCC diagnostic push
473 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
474 return snprintf(dst
, length
, *unit
, value
);
475 #pragma GCC diagnostic pop
478 #pragma GCC diagnostic push
479 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
480 static char* pakfire_strftime(const char* format
, time_t t
) {
482 struct tm
* tm
= gmtime(&t
);
484 strftime(string
, sizeof(string
) - 1, format
, tm
);
486 return strdup(string
);
488 #pragma GCC diagnostic pop
490 char* pakfire_format_date(time_t t
) {
491 return pakfire_strftime("%Y-%m-%d", t
);
494 int __pakfire_strftime_now(char* dest
, size_t length
, const char* format
) {
497 // Fetch the current time
498 const time_t t
= time(NULL
);
502 // Convert to struct tm
503 struct tm
* now
= gmtime_r(&t
, &tm
);
507 #pragma GCC diagnostic push
508 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
509 strftime(dest
, length
, format
, now
);
510 #pragma GCC diagnostic pop
515 int __pakfire_path_join(char* dest
, size_t length
,
516 const char* first
, const char* second
) {
518 return snprintf(dest
, length
, "%s", second
);
521 return snprintf(dest
, length
, "%s", first
);
523 // Remove leading slashes from second argument
524 while (*second
== '/')
527 return snprintf(dest
, length
, "%s/%s", first
, second
);
530 const char* pakfire_path_relpath(const char* root
, const char* path
) {
531 if (pakfire_string_startswith(path
, root
))
532 return path
+ strlen(root
);
537 int pakfire_path_exists(const char* path
) {
538 return !access(path
, F_OK
);
541 time_t pakfire_path_age(const char* path
) {
544 int r
= stat(path
, &st
);
546 // Get current timestamp
547 time_t now
= time(NULL
);
549 // Return the difference since the file has been created and now
550 return now
- st
.st_ctime
;
556 char* pakfire_basename(const char* path
) {
557 char* name
= strdup(path
);
559 char* r
= basename(name
);
568 char* pakfire_dirname(const char* path
) {
569 char* parent
= strdup(path
);
571 char* r
= dirname(parent
);
580 char* pakfire_remove_trailing_newline(char* str
) {
581 ssize_t pos
= strlen(str
) - 1;
583 if (str
[pos
] == '\n')
589 int pakfire_read_file_into_buffer(FILE* f
, char** buffer
, size_t* len
) {
593 int r
= fseek(f
, 0, SEEK_END
);
597 // Save length of file
600 // Go back to the start
601 r
= fseek(f
, 0, SEEK_SET
);
606 *buffer
= malloc((sizeof(**buffer
) * *len
) + 1);
611 fread(*buffer
, *len
, sizeof(**buffer
), f
);
613 // Check we encountered any errors
620 // Terminate the buffer
621 (*buffer
)[*len
] = '\0';
626 char* pakfire_generate_uuid() {
629 // Generate a new random value
630 uuid_generate_random(uuid
);
632 char* ret
= malloc(UUID_STR_LEN
+ 1);
636 // Convert it to string
637 uuid_unparse_lower(uuid
, ret
);
640 ret
[UUID_STR_LEN
] = '\0';
645 int pakfire_tty_is_noninteractive(void) {
653 for (const int* fd
= fds
; *fd
>= 0; fd
++) {
661 char* __pakfire_hexlify(const unsigned char* digest
, const size_t length
) {
662 const char* hexdigits
= "0123456789abcdef";
664 char* s
= malloc((length
* 2) + 1);
668 for (unsigned int i
= 0, j
= 0; i
< length
; i
++) {
671 s
[j
++] = hexdigits
[(b
>> 4) & 0xf];
672 s
[j
++] = hexdigits
[(b
& 0x0f)];
676 s
[length
* 2] = '\0';
681 static int parse_nibble(char nibble
) {
683 if (nibble
>= '0' && nibble
<= '9')
686 // Handle lowercase letters
687 if (nibble
>= 'a' && nibble
<= 'f')
688 return 10 + nibble
- 'a';
690 // Handle uppercase letters
691 if (nibble
>= 'A' && nibble
<= 'F')
692 return 10 + nibble
- 'A';
698 int __pakfire_unhexlify(unsigned char* dst
, const size_t l
, const char* src
) {
704 // Determine input length
705 const size_t length
= strlen(src
);
707 for (unsigned int i
= 0, j
= 0; i
< length
&& j
< l
; i
+= 2, j
++) {
708 int h
= parse_nibble(src
[i
]);
709 int l
= parse_nibble(src
[i
+1]);
711 // Check for invalid input
712 if (h
< 0 || l
< 0) {
724 int pakfire_mkparentdir(const char* path
, mode_t mode
) {
727 char* dirname
= pakfire_dirname(path
);
731 // We have arrived at the top of the tree
732 if (*dirname
== '.' || strcmp(dirname
, "/") == 0)
735 // Ensure the parent directory exists
736 r
= pakfire_mkparentdir(dirname
, mode
);
740 // Create this directory
741 r
= mkdir(dirname
, mode
);
743 // Ignore when the directory already exists
744 if (r
&& errno
== EEXIST
)
753 int pakfire_mkdir(const char* path
, mode_t mode
) {
754 int r
= pakfire_mkparentdir(path
, mode
);
758 // Finally, create the directory we want
759 return mkdir(path
, mode
);
762 FILE* pakfire_mktemp(char* path
) {
763 int r
= pakfire_mkparentdir(path
, 0);
767 // Create a temporary result file
768 int fd
= mkostemp(path
, O_CLOEXEC
);
772 // Re-open as file handle
773 return fdopen(fd
, "w+");
776 char* pakfire_mkdtemp(char* path
) {
777 int r
= pakfire_mkparentdir(path
, 0);
781 return mkdtemp(path
);
784 static int _unlink(const char* path
, const struct stat
* stat
, int typeflag
, struct FTW
* ftwbuf
) {
788 int pakfire_rmtree(const char* path
, int flags
) {
789 int r
= nftw(path
, _unlink
, 64, flags
|FTW_DEPTH
|FTW_PHYS
);
791 // Ignore if path didn't exist
792 if (r
< 0 && errno
== ENOENT
)
800 size_t pakfire_digest_length(enum pakfire_digests digest
) {
802 case PAKFIRE_DIGEST_SHA512
:
805 case PAKFIRE_DIGEST_SHA256
:
808 case PAKFIRE_DIGEST_SHA1
:
811 case PAKFIRE_DIGEST_NONE
:
820 int pakfire_archive_copy_data(struct archive
* src
, struct archive
* dst
,
821 struct archive_entry
* entry
) {
828 // Read a block of data
829 r
= archive_read_data_block(src
, &buffer
, &size
, &offset
);
830 if (r
== ARCHIVE_EOF
)
835 // Write the read block of data
836 r
= archive_write_data(dst
, buffer
, size
);
842 int pakfire_archive_copy_data_to_buffer(struct pakfire
* pakfire
, struct archive
* a
,
843 struct archive_entry
* entry
, char** data
, size_t* data_size
) {
847 size_t required_size
= archive_entry_size(entry
);
851 // Allocate a block of the required size
852 *data
= calloc(1, required_size
+ 1);
856 ssize_t bytes_read
= archive_read_data(a
, *data
, required_size
);
857 if (bytes_read
< 0) {
858 ERROR(pakfire
, "Could not read from archive: %s\n", archive_error_string(a
));
863 *data_size
= bytes_read
;
870 static struct json_object
* pakfire_json_parse(struct pakfire
* pakfire
, FILE* f
) {
871 struct json_tokener
* tokener
= NULL
;
872 struct json_object
* json
= NULL
;
876 // Read everything into memory
877 int r
= pakfire_read_file_into_buffer(f
, &buffer
, &length
);
882 tokener
= json_tokener_new();
884 ERROR(pakfire
, "Could not allocate JSON tokener: %m\n");
888 // Parse JSON from path
889 json
= json_tokener_parse_ex(tokener
, buffer
, length
);
891 enum json_tokener_error error
= json_tokener_get_error(tokener
);
893 ERROR(pakfire
, "JSON parsing error: %s\n", json_tokener_error_desc(error
));
897 // Log what we have parsed
898 DEBUG(pakfire
, "Parsed JSON:\n%s\n",
899 json_object_to_json_string_ext(json
,
900 JSON_C_TO_STRING_SPACED
| JSON_C_TO_STRING_PRETTY
)
908 json_tokener_free(tokener
);
913 struct json_object
* pakfire_json_parse_from_file(struct pakfire
* pakfire
, const char* path
) {
914 FILE* f
= fopen(path
, "r");
918 struct json_object
* json
= pakfire_json_parse(pakfire
, f
);
926 static void timespec_normalize(struct timespec
* t
) {
927 while (t
->tv_nsec
>= NSEC_PER_SEC
) {
929 t
->tv_nsec
-= NSEC_PER_SEC
;
932 while (t
->tv_nsec
<= -NSEC_PER_SEC
) {
934 t
->tv_nsec
+= NSEC_PER_SEC
;
938 struct timespec
timespec_add(const struct timespec
* t1
, const struct timespec
* t2
) {
939 struct timespec r
= {
940 .tv_sec
= t1
->tv_sec
+ t2
->tv_sec
,
941 .tv_nsec
= t2
->tv_nsec
+ t2
->tv_nsec
,
944 // Correct any negative values
945 timespec_normalize(&r
);
950 struct timespec
timespec_from_ms(int milliseconds
) {
951 struct timespec t
= {
952 .tv_sec
= (milliseconds
/ 1000),
953 .tv_nsec
= (milliseconds
% 1000) * 1000000,
959 int timespec_lt(struct timespec
* t1
, struct timespec
* t2
) {
961 t1
->tv_sec
< t2
->tv_sec
||
962 (t1
->tv_sec
== t2
->tv_sec
&& t1
->tv_nsec
< t2
->tv_nsec
)
968 int pakfire_rlimit_set(struct pakfire
* pakfire
, int limit
) {
977 // Fetch current configuration
978 if (getrlimit(RLIMIT_NOFILE
, &rl
) < 0) {
979 ERROR(pakfire
, "Could not read RLIMIT_NOFILE: %m\n");
983 // Do not attempt to set higher than maximum
984 if ((long unsigned int)limit
> rl
.rlim_max
)
990 if (setrlimit(RLIMIT_NOFILE
, &rl
) < 0) {
991 ERROR(pakfire
, "Could not set RLIMIT_NOFILE to %lu: %m\n", rl
.rlim_cur
);
995 DEBUG(pakfire
, "RLIMIT_NOFILE set to %d\n", limit
);
1001 Resets RLIMIT_NOFILE to FD_SETSIZE (e.g. 1024)
1002 for compatibility with software that uses select()
1004 int pakfire_rlimit_reset_nofile(struct pakfire
* pakfire
) {
1005 return pakfire_rlimit_set(pakfire
, FD_SETSIZE
);