]>
git.ipfire.org Git - pakfire.git/blob - src/libpakfire/util.c
553c83af65ec79a0a9c061961e9af723c6ab7210
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
) {
180 return !!strstr(s
, pattern
);
183 char* pakfire_unquote_in_place(char* s
) {
187 // Is the first character a quote?
191 // Find the end of value
192 size_t l
= strlen(s
);
196 // Is the last character a quote?
200 // The string seems to be in quotes; remove them
207 int pakfire_string_partition(const char* s
, const char* delim
, char** s1
, char** s2
) {
208 char* p
= strstr(s
, delim
);
210 // Delim was not found
217 // Length of string before delim
220 char* buffer
= malloc(l
+ 1);
225 *s1
= memcpy(buffer
, s
, l
);
229 *s2
= strdup(p
+ strlen(delim
));
234 char* pakfire_string_replace(const char* s
, const char* pattern
, const char* repl
) {
235 // Return NULL on no input or no pattern
236 if (!s
|| !pattern
) {
241 // Replace with nothing when repl is NULL
246 const char** cache
= NULL
;
247 unsigned int count
= 0;
249 const size_t pattern_length
= strlen(pattern
);
254 // Find all occurrences of pattern and store their location
256 const char* needle
= strstr(p
, pattern
);
260 // Make space in the cache
261 cache
= reallocarray(cache
, sizeof(*cache
), count
+ 1);
262 cache
[count
++] = needle
;
265 p
= needle
+ pattern_length
;
268 // Copy the string if no occurence was found
274 // Store the end pointer
275 cache
= reallocarray(cache
, sizeof(*cache
), count
+ 1);
276 cache
[count
] = s
+ strlen(s
);
278 const size_t repl_length
= strlen(repl
);
280 // Determine the length of the final string
281 const size_t length
= strlen(s
) + ((repl_length
- pattern_length
) * count
);
283 // Allocate enough memory for the result
284 result
= malloc(length
+ 1);
291 // Working pointer for the result
294 // Copy everything up to the first match
295 ssize_t l
= cache
[0] - s
;
300 for (unsigned int i
= 0; i
< count
; i
++) {
301 // Put replacement here
302 memcpy(r
, repl
, repl_length
);
306 // Determine the length between two matches
307 l
= cache
[i
+1] - (cache
[i
] + pattern_length
);
314 // Terminate the string
315 result
[length
] = '\0';
324 static unsigned int pakfire_chrcnt(const char* s
, char delim
) {
325 size_t length
= strlen(s
);
327 unsigned int count
= 0;
329 for (unsigned int i
= 0; i
< length
; i
++)
336 char** pakfire_split_string(const char* s
, char delim
) {
344 // Count how often we need to split
345 unsigned int count
= pakfire_chrcnt(s
, delim
) + 1;
348 array
= calloc(count
+ 1, sizeof(*array
));
352 // Copy string to stack
353 char* p
= strdupa(s
);
359 char* e
= strchr(p
, delim
);
361 // Terminate the string
365 // Add string to the array
366 array
[i
++] = strdup(p
);
368 // End loop when we reached the end
372 // Or continue at the next line
379 char* pakfire_string_join(char** list
, const char* delim
) {
384 unsigned int elements
= 0;
386 // Count the number of elements and the total length
387 for (char** item
= list
; *item
; item
++) {
388 length
+= strlen(*item
);
396 // Add the delimiters
397 length
+= strlen(delim
) * (elements
- 1);
399 // Allocate the result string
400 char* string
= malloc(length
+ 1);
404 // Pointer to where we are writing
407 size_t bytes_left
= length
;
408 size_t bytes_written
;
410 for (char** item
= list
; *item
; item
++) {
411 bytes_written
= snprintf(p
, bytes_left
, "%s", *item
);
413 bytes_left
-= bytes_written
;
416 // Write the delimiter
418 bytes_written
= snprintf(p
, bytes_left
, "%s", delim
);
420 bytes_left
-= bytes_written
;
428 int pakfire_format_size(char* dst
, size_t length
, double value
) {
429 const char* units
[] = {
437 const char** unit
= units
;
439 while (*(unit
+ 1) && value
>= 1024.0) {
444 #pragma GCC diagnostic push
445 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
446 return snprintf(dst
, length
, *unit
, value
);
447 #pragma GCC diagnostic pop
450 int pakfire_format_speed(char* dst
, size_t length
, double value
) {
451 const char* units
[] = {
459 const char** unit
= units
;
461 while (*(unit
+ 1) && value
>= 1024.0) {
466 #pragma GCC diagnostic push
467 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
468 return snprintf(dst
, length
, *unit
, value
);
469 #pragma GCC diagnostic pop
472 #pragma GCC diagnostic push
473 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
474 static char* pakfire_strftime(const char* format
, time_t t
) {
476 struct tm
* tm
= gmtime(&t
);
478 strftime(string
, sizeof(string
) - 1, format
, tm
);
480 return strdup(string
);
482 #pragma GCC diagnostic pop
484 char* pakfire_format_date(time_t t
) {
485 return pakfire_strftime("%Y-%m-%d", t
);
488 int __pakfire_strftime_now(char* dest
, size_t length
, const char* format
) {
491 // Fetch the current time
492 const time_t t
= time(NULL
);
496 // Convert to struct tm
497 struct tm
* now
= gmtime_r(&t
, &tm
);
501 #pragma GCC diagnostic push
502 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
503 strftime(dest
, length
, format
, now
);
504 #pragma GCC diagnostic pop
509 int __pakfire_path_join(char* dest
, size_t length
,
510 const char* first
, const char* second
) {
512 return snprintf(dest
, length
, "%s", second
);
515 return snprintf(dest
, length
, "%s", first
);
517 // Remove leading slashes from second argument
518 while (*second
== '/')
521 return snprintf(dest
, length
, "%s/%s", first
, second
);
524 const char* pakfire_path_relpath(const char* root
, const char* path
) {
525 if (pakfire_string_startswith(path
, root
))
526 return path
+ strlen(root
);
531 int pakfire_path_exists(const char* path
) {
532 return !access(path
, F_OK
);
535 time_t pakfire_path_age(const char* path
) {
538 int r
= stat(path
, &st
);
540 // Get current timestamp
541 time_t now
= time(NULL
);
543 // Return the difference since the file has been created and now
544 return now
- st
.st_ctime
;
550 char* pakfire_basename(const char* path
) {
551 char* name
= strdup(path
);
553 char* r
= basename(name
);
562 char* pakfire_dirname(const char* path
) {
563 char* parent
= strdup(path
);
565 char* r
= dirname(parent
);
574 char* pakfire_remove_trailing_newline(char* str
) {
575 ssize_t pos
= strlen(str
) - 1;
577 if (str
[pos
] == '\n')
583 int pakfire_read_file_into_buffer(FILE* f
, char** buffer
, size_t* len
) {
587 int r
= fseek(f
, 0, SEEK_END
);
591 // Save length of file
594 // Go back to the start
595 r
= fseek(f
, 0, SEEK_SET
);
600 *buffer
= malloc((sizeof(**buffer
) * *len
) + 1);
605 fread(*buffer
, *len
, sizeof(**buffer
), f
);
607 // Check we encountered any errors
614 // Terminate the buffer
615 (*buffer
)[*len
] = '\0';
620 char* pakfire_generate_uuid() {
623 // Generate a new random value
624 uuid_generate_random(uuid
);
626 char* ret
= malloc(UUID_STR_LEN
+ 1);
630 // Convert it to string
631 uuid_unparse_lower(uuid
, ret
);
634 ret
[UUID_STR_LEN
] = '\0';
639 int pakfire_tty_is_noninteractive(void) {
647 for (const int* fd
= fds
; *fd
>= 0; fd
++) {
655 char* __pakfire_hexlify(const unsigned char* digest
, const size_t length
) {
656 const char* hexdigits
= "0123456789abcdef";
658 char* s
= malloc((length
* 2) + 1);
662 for (unsigned int i
= 0, j
= 0; i
< length
; i
++) {
665 s
[j
++] = hexdigits
[(b
>> 4) & 0xf];
666 s
[j
++] = hexdigits
[(b
& 0x0f)];
670 s
[length
* 2] = '\0';
675 static int parse_nibble(char nibble
) {
677 if (nibble
>= '0' && nibble
<= '9')
680 // Handle lowercase letters
681 if (nibble
>= 'a' && nibble
<= 'f')
682 return 10 + nibble
- 'a';
684 // Handle uppercase letters
685 if (nibble
>= 'A' && nibble
<= 'F')
686 return 10 + nibble
- 'A';
692 int __pakfire_unhexlify(unsigned char* dst
, const size_t l
, const char* src
) {
698 // Determine input length
699 const size_t length
= strlen(src
);
701 for (unsigned int i
= 0, j
= 0; i
< length
&& j
< l
; i
+= 2, j
++) {
702 int h
= parse_nibble(src
[i
]);
703 int l
= parse_nibble(src
[i
+1]);
705 // Check for invalid input
706 if (h
< 0 || l
< 0) {
718 int pakfire_mkparentdir(const char* path
, mode_t mode
) {
721 char* dirname
= pakfire_dirname(path
);
725 // We have arrived at the top of the tree
726 if (*dirname
== '.' || strcmp(dirname
, "/") == 0)
729 // Ensure the parent directory exists
730 r
= pakfire_mkparentdir(dirname
, mode
);
734 // Create this directory
735 r
= mkdir(dirname
, mode
);
737 // Ignore when the directory already exists
738 if (r
&& errno
== EEXIST
)
747 int pakfire_mkdir(const char* path
, mode_t mode
) {
748 int r
= pakfire_mkparentdir(path
, mode
);
752 // Finally, create the directory we want
753 return mkdir(path
, mode
);
756 FILE* pakfire_mktemp(char* path
) {
757 int r
= pakfire_mkparentdir(path
, 0);
761 // Create a temporary result file
762 int fd
= mkostemp(path
, O_CLOEXEC
);
766 // Re-open as file handle
767 return fdopen(fd
, "w+");
770 char* pakfire_mkdtemp(char* path
) {
771 int r
= pakfire_mkparentdir(path
, 0);
775 return mkdtemp(path
);
778 static int _unlink(const char* path
, const struct stat
* stat
, int typeflag
, struct FTW
* ftwbuf
) {
782 int pakfire_rmtree(const char* path
, int flags
) {
783 int r
= nftw(path
, _unlink
, 64, flags
|FTW_DEPTH
|FTW_PHYS
);
785 // Ignore if path didn't exist
786 if (r
< 0 && errno
== ENOENT
)
794 size_t pakfire_digest_length(enum pakfire_digests digest
) {
796 case PAKFIRE_DIGEST_SHA512
:
799 case PAKFIRE_DIGEST_SHA256
:
802 case PAKFIRE_DIGEST_SHA1
:
805 case PAKFIRE_DIGEST_NONE
:
814 int pakfire_archive_copy_data(struct archive
* src
, struct archive
* dst
,
815 struct archive_entry
* entry
) {
822 // Read a block of data
823 r
= archive_read_data_block(src
, &buffer
, &size
, &offset
);
824 if (r
== ARCHIVE_EOF
)
829 // Write the read block of data
830 r
= archive_write_data(dst
, buffer
, size
);
836 int pakfire_archive_copy_data_to_buffer(struct pakfire
* pakfire
, struct archive
* a
,
837 struct archive_entry
* entry
, char** data
, size_t* data_size
) {
841 size_t required_size
= archive_entry_size(entry
);
845 // Allocate a block of the required size
846 *data
= calloc(1, required_size
+ 1);
850 ssize_t bytes_read
= archive_read_data(a
, *data
, required_size
);
851 if (bytes_read
< 0) {
852 ERROR(pakfire
, "Could not read from archive: %s\n", archive_error_string(a
));
857 *data_size
= bytes_read
;
864 static struct json_object
* pakfire_json_parse(struct pakfire
* pakfire
, FILE* f
) {
865 struct json_tokener
* tokener
= NULL
;
866 struct json_object
* json
= NULL
;
870 // Read everything into memory
871 int r
= pakfire_read_file_into_buffer(f
, &buffer
, &length
);
876 tokener
= json_tokener_new();
878 ERROR(pakfire
, "Could not allocate JSON tokener: %m\n");
882 // Parse JSON from path
883 json
= json_tokener_parse_ex(tokener
, buffer
, length
);
885 enum json_tokener_error error
= json_tokener_get_error(tokener
);
887 ERROR(pakfire
, "JSON parsing error: %s\n", json_tokener_error_desc(error
));
891 // Log what we have parsed
892 DEBUG(pakfire
, "Parsed JSON:\n%s\n",
893 json_object_to_json_string_ext(json
,
894 JSON_C_TO_STRING_SPACED
| JSON_C_TO_STRING_PRETTY
)
902 json_tokener_free(tokener
);
907 struct json_object
* pakfire_json_parse_from_file(struct pakfire
* pakfire
, const char* path
) {
908 FILE* f
= fopen(path
, "r");
912 struct json_object
* json
= pakfire_json_parse(pakfire
, f
);
920 static void timespec_normalize(struct timespec
* t
) {
921 while (t
->tv_nsec
>= NSEC_PER_SEC
) {
923 t
->tv_nsec
-= NSEC_PER_SEC
;
926 while (t
->tv_nsec
<= -NSEC_PER_SEC
) {
928 t
->tv_nsec
+= NSEC_PER_SEC
;
932 struct timespec
timespec_add(const struct timespec
* t1
, const struct timespec
* t2
) {
933 struct timespec r
= {
934 .tv_sec
= t1
->tv_sec
+ t2
->tv_sec
,
935 .tv_nsec
= t2
->tv_nsec
+ t2
->tv_nsec
,
938 // Correct any negative values
939 timespec_normalize(&r
);
944 struct timespec
timespec_from_ms(int milliseconds
) {
945 struct timespec t
= {
946 .tv_sec
= (milliseconds
/ 1000),
947 .tv_nsec
= (milliseconds
% 1000) * 1000000,
953 int timespec_lt(struct timespec
* t1
, struct timespec
* t2
) {
955 t1
->tv_sec
< t2
->tv_sec
||
956 (t1
->tv_sec
== t2
->tv_sec
&& t1
->tv_nsec
< t2
->tv_nsec
)
962 int pakfire_rlimit_set(struct pakfire
* pakfire
, int limit
) {
971 // Fetch current configuration
972 if (getrlimit(RLIMIT_NOFILE
, &rl
) < 0) {
973 ERROR(pakfire
, "Could not read RLIMIT_NOFILE: %m\n");
977 // Do not attempt to set higher than maximum
978 if ((long unsigned int)limit
> rl
.rlim_max
)
984 if (setrlimit(RLIMIT_NOFILE
, &rl
) < 0) {
985 ERROR(pakfire
, "Could not set RLIMIT_NOFILE to %lu: %m\n", rl
.rlim_cur
);
989 DEBUG(pakfire
, "RLIMIT_NOFILE set to %d\n", limit
);
995 Resets RLIMIT_NOFILE to FD_SETSIZE (e.g. 1024)
996 for compatibility with software that uses select()
998 int pakfire_rlimit_reset_nofile(struct pakfire
* pakfire
) {
999 return pakfire_rlimit_set(pakfire
, FD_SETSIZE
);