]>
git.ipfire.org Git - pakfire.git/blob - src/libpakfire/util.c
a470221b58137c84b0f043ad723f4e6cf707fb88
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 const char* pakfire_dep2str(struct pakfire
* pakfire
, Id id
) {
51 Pool
* pool
= pakfire_get_solv_pool(pakfire
);
55 return pool_dep2str(pool
, id
);
58 static Id
pakfire_parse_namespace(Pool
* pool
, const char* s
) {
59 const char* p
= strchr(s
, '(');
63 // Store the namespace ID
64 Id
namespace = pool_strn2id(pool
, s
, p
- s
, 1);
66 // Find the end of the string
71 Id id
= pool_strn2id(pool
, p
+ 1, s
- p
- 1, 1);
73 // Bring it all together
74 return pool_rel2id(pool
, namespace, id
, REL_NAMESPACE
, 1);
77 Id
pakfire_parse_dep(struct pakfire
* pakfire
, const char* s
) {
85 // Ignore empty strings
89 Pool
* pool
= pakfire_get_solv_pool(pakfire
);
91 // Consume any leading space
97 // Find the first part (before =, >= or <=)
98 while (*p
&& !isspace(*p
) && *p
!= '<' && *p
!= '=' && *p
!= '>')
101 // The length of the first part
105 if (pakfire_string_startswith(s
, "pakfire("))
106 id
= pakfire_parse_namespace(pool
, s
);
108 id
= pool_strn2id(pool
, s
, l
, 1);
110 // Consume any more space
114 if (*p
== '<' || *p
== '=' || *p
== '>') {
130 // Consume any more space
135 Id evr
= pool_str2id(pool
, p
, 1);
137 // Combine everything
138 id
= pool_rel2id(pool
, id
, evr
, flags
, 1);
144 void pakfire_parse_deps(struct pakfire
* pakfire
, struct pakfire_package
* pkg
,
145 void (*func
)(struct pakfire_package
* pkg
, const char* dep
), const char* deps
) {
146 char* p
= strdupa(deps
);
149 char* e
= strchr(p
, '\n');
151 // Terminate the string
155 // Add the dependency
158 // End loop when we reached the end
162 // Or continue at the next line
167 int pakfire_string_startswith(const char* s
, const char* prefix
) {
174 return !strncmp(s
, prefix
, strlen(prefix
));
177 int pakfire_string_endswith(const char* s
, const char* suffix
) {
184 return !strcmp(s
+ strlen(s
) - strlen(suffix
), suffix
);
187 int pakfire_string_matches(const char* s
, const char* pattern
) {
189 if (!s
|| !pattern
) {
194 return !!strstr(s
, pattern
);
197 char* pakfire_unquote_in_place(char* s
) {
201 // Is the first character a quote?
205 // Find the end of value
206 size_t l
= strlen(s
);
210 // Is the last character a quote?
214 // The string seems to be in quotes; remove them
221 int pakfire_string_partition(const char* s
, const char* delim
, char** s1
, char** s2
) {
222 char* p
= strstr(s
, delim
);
224 // Delim was not found
231 // Length of string before delim
234 char* buffer
= malloc(l
+ 1);
239 *s1
= memcpy(buffer
, s
, l
);
243 *s2
= strdup(p
+ strlen(delim
));
248 char* pakfire_string_replace(const char* s
, const char* pattern
, const char* repl
) {
249 // Return NULL on no input or no pattern
250 if (!s
|| !pattern
) {
255 // Replace with nothing when repl is NULL
260 const char** cache
= NULL
;
261 unsigned int count
= 0;
263 const size_t pattern_length
= strlen(pattern
);
268 // Find all occurrences of pattern and store their location
270 const char* needle
= strstr(p
, pattern
);
274 // Make space in the cache
275 cache
= reallocarray(cache
, sizeof(*cache
), count
+ 1);
276 cache
[count
++] = needle
;
279 p
= needle
+ pattern_length
;
282 // Copy the string if no occurence was found
288 // Store the end pointer
289 cache
= reallocarray(cache
, sizeof(*cache
), count
+ 1);
290 cache
[count
] = s
+ strlen(s
);
292 const size_t repl_length
= strlen(repl
);
294 // Determine the length of the final string
295 const size_t length
= strlen(s
) + ((repl_length
- pattern_length
) * count
);
297 // Allocate enough memory for the result
298 result
= malloc(length
+ 1);
305 // Working pointer for the result
308 // Copy everything up to the first match
309 ssize_t l
= cache
[0] - s
;
314 for (unsigned int i
= 0; i
< count
; i
++) {
315 // Put replacement here
316 memcpy(r
, repl
, repl_length
);
320 // Determine the length between two matches
321 l
= cache
[i
+1] - (cache
[i
] + pattern_length
);
328 // Terminate the string
329 result
[length
] = '\0';
338 static unsigned int pakfire_chrcnt(const char* s
, char delim
) {
339 size_t length
= strlen(s
);
341 unsigned int count
= 0;
343 for (unsigned int i
= 0; i
< length
; i
++)
350 char** pakfire_split_string(const char* s
, char delim
) {
358 // Count how often we need to split
359 unsigned int count
= pakfire_chrcnt(s
, delim
) + 1;
362 array
= calloc(count
+ 1, sizeof(*array
));
366 // Copy string to stack
367 char* p
= strdupa(s
);
373 char* e
= strchr(p
, delim
);
375 // Terminate the string
379 // Add string to the array
380 array
[i
++] = strdup(p
);
382 // End loop when we reached the end
386 // Or continue at the next line
393 char* pakfire_string_join(char** list
, const char* delim
) {
398 unsigned int elements
= 0;
400 // Count the number of elements and the total length
401 for (char** item
= list
; *item
; item
++) {
402 length
+= strlen(*item
);
410 // Add the delimiters
411 length
+= strlen(delim
) * (elements
- 1);
413 // Allocate the result string
414 char* string
= malloc(length
+ 1);
418 // Pointer to where we are writing
421 size_t bytes_left
= length
;
422 size_t bytes_written
;
424 for (char** item
= list
; *item
; item
++) {
425 bytes_written
= snprintf(p
, bytes_left
, "%s", *item
);
427 bytes_left
-= bytes_written
;
430 // Write the delimiter
432 bytes_written
= snprintf(p
, bytes_left
, "%s", delim
);
434 bytes_left
-= bytes_written
;
442 int pakfire_format_size(char* dst
, size_t length
, double value
) {
443 const char* units
[] = {
451 const char** unit
= units
;
453 while (*(unit
+ 1) && value
>= 1024.0) {
458 #pragma GCC diagnostic push
459 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
460 return snprintf(dst
, length
, *unit
, value
);
461 #pragma GCC diagnostic pop
464 int pakfire_format_speed(char* dst
, size_t length
, double value
) {
465 const char* units
[] = {
473 const char** unit
= units
;
475 while (*(unit
+ 1) && value
>= 1024.0) {
480 #pragma GCC diagnostic push
481 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
482 return snprintf(dst
, length
, *unit
, value
);
483 #pragma GCC diagnostic pop
486 #pragma GCC diagnostic push
487 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
488 static char* pakfire_strftime(const char* format
, time_t t
) {
490 struct tm
* tm
= gmtime(&t
);
492 strftime(string
, sizeof(string
) - 1, format
, tm
);
494 return strdup(string
);
496 #pragma GCC diagnostic pop
498 char* pakfire_format_date(time_t t
) {
499 return pakfire_strftime("%Y-%m-%d", t
);
502 int __pakfire_strftime_now(char* dest
, size_t length
, const char* format
) {
505 // Fetch the current time
506 const time_t t
= time(NULL
);
510 // Convert to struct tm
511 struct tm
* now
= gmtime_r(&t
, &tm
);
515 #pragma GCC diagnostic push
516 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
517 strftime(dest
, length
, format
, now
);
518 #pragma GCC diagnostic pop
523 int __pakfire_path_join(char* dest
, size_t length
,
524 const char* first
, const char* second
) {
526 return snprintf(dest
, length
, "%s", second
);
529 return snprintf(dest
, length
, "%s", first
);
531 // Remove leading slashes from second argument
532 while (*second
== '/')
535 return snprintf(dest
, length
, "%s/%s", first
, second
);
538 const char* pakfire_path_relpath(const char* root
, const char* path
) {
539 if (pakfire_string_startswith(path
, root
))
540 return path
+ strlen(root
);
545 int pakfire_path_exists(const char* path
) {
546 return !access(path
, F_OK
);
549 time_t pakfire_path_age(const char* path
) {
552 int r
= stat(path
, &st
);
554 // Get current timestamp
555 time_t now
= time(NULL
);
557 // Return the difference since the file has been created and now
558 return now
- st
.st_ctime
;
564 char* pakfire_basename(const char* path
) {
565 char* name
= strdup(path
);
567 char* r
= basename(name
);
576 char* pakfire_dirname(const char* path
) {
577 char* parent
= strdup(path
);
579 char* r
= dirname(parent
);
588 char* pakfire_remove_trailing_newline(char* str
) {
589 ssize_t pos
= strlen(str
) - 1;
591 if (str
[pos
] == '\n')
597 int pakfire_read_file_into_buffer(FILE* f
, char** buffer
, size_t* len
) {
601 int r
= fseek(f
, 0, SEEK_END
);
605 // Save length of file
608 // Go back to the start
609 r
= fseek(f
, 0, SEEK_SET
);
614 *buffer
= malloc((sizeof(**buffer
) * *len
) + 1);
619 fread(*buffer
, *len
, sizeof(**buffer
), f
);
621 // Check we encountered any errors
628 // Terminate the buffer
629 (*buffer
)[*len
] = '\0';
634 char* pakfire_generate_uuid() {
637 // Generate a new random value
638 uuid_generate_random(uuid
);
640 char* ret
= malloc(UUID_STR_LEN
+ 1);
644 // Convert it to string
645 uuid_unparse_lower(uuid
, ret
);
648 ret
[UUID_STR_LEN
] = '\0';
653 int pakfire_tty_is_noninteractive(void) {
661 for (const int* fd
= fds
; *fd
>= 0; fd
++) {
669 char* __pakfire_hexlify(const unsigned char* digest
, const size_t length
) {
670 const char* hexdigits
= "0123456789abcdef";
672 char* s
= malloc((length
* 2) + 1);
676 for (unsigned int i
= 0, j
= 0; i
< length
; i
++) {
679 s
[j
++] = hexdigits
[(b
>> 4) & 0xf];
680 s
[j
++] = hexdigits
[(b
& 0x0f)];
684 s
[length
* 2] = '\0';
689 static int parse_nibble(char nibble
) {
691 if (nibble
>= '0' && nibble
<= '9')
694 // Handle lowercase letters
695 if (nibble
>= 'a' && nibble
<= 'f')
696 return 10 + nibble
- 'a';
698 // Handle uppercase letters
699 if (nibble
>= 'A' && nibble
<= 'F')
700 return 10 + nibble
- 'A';
706 int __pakfire_unhexlify(unsigned char* dst
, const size_t l
, const char* src
) {
712 // Determine input length
713 const size_t length
= strlen(src
);
715 for (unsigned int i
= 0, j
= 0; i
< length
&& j
< l
; i
+= 2, j
++) {
716 int h
= parse_nibble(src
[i
]);
717 int l
= parse_nibble(src
[i
+1]);
719 // Check for invalid input
720 if (h
< 0 || l
< 0) {
732 int pakfire_mkparentdir(const char* path
, mode_t mode
) {
735 char* dirname
= pakfire_dirname(path
);
739 // We have arrived at the top of the tree
740 if (*dirname
== '.' || strcmp(dirname
, "/") == 0)
743 // Ensure the parent directory exists
744 r
= pakfire_mkparentdir(dirname
, mode
);
748 // Create this directory
749 r
= mkdir(dirname
, mode
);
751 // Ignore when the directory already exists
752 if (r
&& errno
== EEXIST
)
761 int pakfire_mkdir(const char* path
, mode_t mode
) {
762 int r
= pakfire_mkparentdir(path
, mode
);
766 // Finally, create the directory we want
767 return mkdir(path
, mode
);
770 FILE* pakfire_mktemp(char* path
) {
771 int r
= pakfire_mkparentdir(path
, 0);
775 // Create a temporary result file
776 int fd
= mkostemp(path
, O_CLOEXEC
);
780 // Re-open as file handle
781 return fdopen(fd
, "w+");
784 char* pakfire_mkdtemp(char* path
) {
785 int r
= pakfire_mkparentdir(path
, 0);
789 return mkdtemp(path
);
792 static int _unlink(const char* path
, const struct stat
* stat
, int typeflag
, struct FTW
* ftwbuf
) {
796 int pakfire_rmtree(const char* path
, int flags
) {
797 int r
= nftw(path
, _unlink
, 64, flags
|FTW_DEPTH
|FTW_PHYS
);
799 // Ignore if path didn't exist
800 if (r
< 0 && errno
== ENOENT
)
808 size_t pakfire_digest_length(enum pakfire_digests digest
) {
810 case PAKFIRE_DIGEST_SHA512
:
813 case PAKFIRE_DIGEST_SHA256
:
816 case PAKFIRE_DIGEST_SHA1
:
819 case PAKFIRE_DIGEST_NONE
:
828 int pakfire_archive_copy_data(struct archive
* src
, struct archive
* dst
,
829 struct archive_entry
* entry
) {
836 // Read a block of data
837 r
= archive_read_data_block(src
, &buffer
, &size
, &offset
);
838 if (r
== ARCHIVE_EOF
)
843 // Write the read block of data
844 r
= archive_write_data(dst
, buffer
, size
);
850 int pakfire_archive_copy_data_to_buffer(struct pakfire
* pakfire
, struct archive
* a
,
851 struct archive_entry
* entry
, char** data
, size_t* data_size
) {
855 size_t required_size
= archive_entry_size(entry
);
859 // Allocate a block of the required size
860 *data
= calloc(1, required_size
+ 1);
864 ssize_t bytes_read
= archive_read_data(a
, *data
, required_size
);
865 if (bytes_read
< 0) {
866 ERROR(pakfire
, "Could not read from archive: %s\n", archive_error_string(a
));
871 *data_size
= bytes_read
;
878 static struct json_object
* pakfire_json_parse(struct pakfire
* pakfire
, FILE* f
) {
879 struct json_tokener
* tokener
= NULL
;
880 struct json_object
* json
= NULL
;
884 // Read everything into memory
885 int r
= pakfire_read_file_into_buffer(f
, &buffer
, &length
);
890 tokener
= json_tokener_new();
892 ERROR(pakfire
, "Could not allocate JSON tokener: %m\n");
896 // Parse JSON from path
897 json
= json_tokener_parse_ex(tokener
, buffer
, length
);
899 enum json_tokener_error error
= json_tokener_get_error(tokener
);
901 ERROR(pakfire
, "JSON parsing error: %s\n", json_tokener_error_desc(error
));
905 // Log what we have parsed
906 DEBUG(pakfire
, "Parsed JSON:\n%s\n",
907 json_object_to_json_string_ext(json
,
908 JSON_C_TO_STRING_SPACED
| JSON_C_TO_STRING_PRETTY
)
916 json_tokener_free(tokener
);
921 struct json_object
* pakfire_json_parse_from_file(struct pakfire
* pakfire
, const char* path
) {
922 FILE* f
= fopen(path
, "r");
926 struct json_object
* json
= pakfire_json_parse(pakfire
, f
);
934 static void timespec_normalize(struct timespec
* t
) {
935 while (t
->tv_nsec
>= NSEC_PER_SEC
) {
937 t
->tv_nsec
-= NSEC_PER_SEC
;
940 while (t
->tv_nsec
<= -NSEC_PER_SEC
) {
942 t
->tv_nsec
+= NSEC_PER_SEC
;
946 struct timespec
timespec_add(const struct timespec
* t1
, const struct timespec
* t2
) {
947 struct timespec r
= {
948 .tv_sec
= t1
->tv_sec
+ t2
->tv_sec
,
949 .tv_nsec
= t2
->tv_nsec
+ t2
->tv_nsec
,
952 // Correct any negative values
953 timespec_normalize(&r
);
958 struct timespec
timespec_from_ms(int milliseconds
) {
959 struct timespec t
= {
960 .tv_sec
= (milliseconds
/ 1000),
961 .tv_nsec
= (milliseconds
% 1000) * 1000000,
967 int timespec_lt(struct timespec
* t1
, struct timespec
* t2
) {
969 t1
->tv_sec
< t2
->tv_sec
||
970 (t1
->tv_sec
== t2
->tv_sec
&& t1
->tv_nsec
< t2
->tv_nsec
)
976 int pakfire_rlimit_set(struct pakfire
* pakfire
, int limit
) {
985 // Fetch current configuration
986 if (getrlimit(RLIMIT_NOFILE
, &rl
) < 0) {
987 ERROR(pakfire
, "Could not read RLIMIT_NOFILE: %m\n");
991 // Do not attempt to set higher than maximum
992 if ((long unsigned int)limit
> rl
.rlim_max
)
998 if (setrlimit(RLIMIT_NOFILE
, &rl
) < 0) {
999 ERROR(pakfire
, "Could not set RLIMIT_NOFILE to %lu: %m\n", rl
.rlim_cur
);
1003 DEBUG(pakfire
, "RLIMIT_NOFILE set to %d\n", limit
);
1009 Resets RLIMIT_NOFILE to FD_SETSIZE (e.g. 1024)
1010 for compatibility with software that uses select()
1012 int pakfire_rlimit_reset_nofile(struct pakfire
* pakfire
) {
1013 return pakfire_rlimit_set(pakfire
, FD_SETSIZE
);