Coverage Report

Created: 2025-08-26 06:04

/src/rauc/include/utils.h
Line
Count
Source (jump to first uncovered line)
1
#pragma once
2
3
#include <gio/gio.h>
4
#include <glib.h>
5
6
146
#define R_UTILS_ERROR r_utils_error_quark()
7
8
GQuark r_utils_error_quark(void);
9
10
typedef enum {
11
  R_UTILS_ERROR_FAILED,
12
  R_UTILS_ERROR_INAPPROPRIATE_IOCTL,
13
  R_UTILS_ERROR_INVALID_ENV_KEY,
14
  R_UTILS_ERROR_SEMVER_PARSE,
15
  R_UTILS_ERROR_OPEN_FILE,
16
} RUtilsError;
17
18
#define BIT(nr) (1UL << (nr))
19
20
/* Evaluate EXPRESSION, and repeat as long as it returns -1 with `errno'
21
 * set to EINTR. Needed for builds against musl, taken from glibc's unistd.h.
22
 */
23
#ifndef TEMP_FAILURE_RETRY
24
#define TEMP_FAILURE_RETRY(expression) \
25
  (__extension__ \
26
     ({ long int __result; \
27
        do {__result = (long int) (expression);} \
28
        while (__result == -1L && errno == EINTR); \
29
        __result; }))
30
#endif
31
32
/* Use
33
 *
34
 *   g_auto(filedesc) fd = -1
35
 *
36
 * to declare a file descriptor that will be automatically closed when
37
 * fd goes out of scope. The destructor is guaranteed to preserve
38
 * errno.
39
 */
40
typedef int filedesc;
41
void close_preserve_errno(filedesc fd);
42
G_DEFINE_AUTO_CLEANUP_FREE_FUNC(filedesc, close_preserve_errno, -1)
43
44
0
#define R_LOG_DOMAIN_SUBPROCESS "rauc-subprocess"
45
46
static inline GSubprocess* r_subprocess_newv(GPtrArray *args, GSubprocessFlags flags, GError **error)
47
0
{
48
0
  g_return_val_if_fail(args, NULL);
49
0
  g_return_val_if_fail(args->len, NULL);
50
0
  g_return_val_if_fail(args->pdata[args->len-1] == NULL, NULL);
51
0
  g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
52
0
  g_autofree gchar *call = g_strjoinv(" ", (gchar**) args->pdata);
53
0
  g_log(R_LOG_DOMAIN_SUBPROCESS, G_LOG_LEVEL_DEBUG, "launching subprocess: %s", call);
54
55
0
  return g_subprocess_newv((const gchar * const *) args->pdata, flags, error);
56
0
}
Unexecuted instantiation: manifest.c:r_subprocess_newv
Unexecuted instantiation: utils.c:r_subprocess_newv
Unexecuted instantiation: checksum.c:r_subprocess_newv
Unexecuted instantiation: context.c:r_subprocess_newv
Unexecuted instantiation: event_log.c:r_subprocess_newv
Unexecuted instantiation: signature.c:r_subprocess_newv
Unexecuted instantiation: status_file.c:r_subprocess_newv
Unexecuted instantiation: bootchooser.c:r_subprocess_newv
Unexecuted instantiation: barebox.c:r_subprocess_newv
Unexecuted instantiation: custom.c:r_subprocess_newv
Unexecuted instantiation: efi.c:r_subprocess_newv
Unexecuted instantiation: grub.c:r_subprocess_newv
Unexecuted instantiation: uboot.c:r_subprocess_newv
Unexecuted instantiation: config_file.c:r_subprocess_newv
Unexecuted instantiation: install.c:r_subprocess_newv
Unexecuted instantiation: mark.c:r_subprocess_newv
Unexecuted instantiation: mount.c:r_subprocess_newv
Unexecuted instantiation: service.c:r_subprocess_newv
Unexecuted instantiation: shell.c:r_subprocess_newv
Unexecuted instantiation: slot.c:r_subprocess_newv
Unexecuted instantiation: update_handler.c:r_subprocess_newv
Unexecuted instantiation: update_utils.c:r_subprocess_newv
Unexecuted instantiation: artifacts.c:r_subprocess_newv
Unexecuted instantiation: bundle.c:r_subprocess_newv
Unexecuted instantiation: crypt.c:r_subprocess_newv
Unexecuted instantiation: emmc.c:r_subprocess_newv
Unexecuted instantiation: hash_index.c:r_subprocess_newv
Unexecuted instantiation: mbr.c:r_subprocess_newv
57
58
static inline GSubprocess * r_subprocess_launcher_spawnv(GSubprocessLauncher *launcher, GPtrArray *args, GError **error)
59
0
{
60
0
  g_return_val_if_fail(launcher, NULL);
61
0
  g_return_val_if_fail(args, NULL);
62
0
  g_return_val_if_fail(args->len, NULL);
63
0
  g_return_val_if_fail(args->pdata[args->len-1] == NULL, NULL);
64
0
  g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
65
0
  g_autofree gchar *call = g_strjoinv(" ", (gchar**) args->pdata);
66
0
  g_log(R_LOG_DOMAIN_SUBPROCESS, G_LOG_LEVEL_DEBUG, "launching subprocess: %s", call);
67
68
0
  return g_subprocess_launcher_spawnv(launcher,
69
0
      (const gchar * const *)args->pdata, error);
70
0
}
Unexecuted instantiation: manifest.c:r_subprocess_launcher_spawnv
Unexecuted instantiation: utils.c:r_subprocess_launcher_spawnv
Unexecuted instantiation: checksum.c:r_subprocess_launcher_spawnv
Unexecuted instantiation: context.c:r_subprocess_launcher_spawnv
Unexecuted instantiation: event_log.c:r_subprocess_launcher_spawnv
Unexecuted instantiation: signature.c:r_subprocess_launcher_spawnv
Unexecuted instantiation: status_file.c:r_subprocess_launcher_spawnv
Unexecuted instantiation: bootchooser.c:r_subprocess_launcher_spawnv
Unexecuted instantiation: barebox.c:r_subprocess_launcher_spawnv
Unexecuted instantiation: custom.c:r_subprocess_launcher_spawnv
Unexecuted instantiation: efi.c:r_subprocess_launcher_spawnv
Unexecuted instantiation: grub.c:r_subprocess_launcher_spawnv
Unexecuted instantiation: uboot.c:r_subprocess_launcher_spawnv
Unexecuted instantiation: config_file.c:r_subprocess_launcher_spawnv
Unexecuted instantiation: install.c:r_subprocess_launcher_spawnv
Unexecuted instantiation: mark.c:r_subprocess_launcher_spawnv
Unexecuted instantiation: mount.c:r_subprocess_launcher_spawnv
Unexecuted instantiation: service.c:r_subprocess_launcher_spawnv
Unexecuted instantiation: shell.c:r_subprocess_launcher_spawnv
Unexecuted instantiation: slot.c:r_subprocess_launcher_spawnv
Unexecuted instantiation: update_handler.c:r_subprocess_launcher_spawnv
Unexecuted instantiation: update_utils.c:r_subprocess_launcher_spawnv
Unexecuted instantiation: artifacts.c:r_subprocess_launcher_spawnv
Unexecuted instantiation: bundle.c:r_subprocess_launcher_spawnv
Unexecuted instantiation: crypt.c:r_subprocess_launcher_spawnv
Unexecuted instantiation: emmc.c:r_subprocess_launcher_spawnv
Unexecuted instantiation: hash_index.c:r_subprocess_launcher_spawnv
Unexecuted instantiation: mbr.c:r_subprocess_launcher_spawnv
71
72
GSubprocess *r_subprocess_new(GSubprocessFlags flags, GError **error, const gchar *argv0, ...)
73
G_GNUC_WARN_UNUSED_RESULT;
74
75
/**
76
 * Starts a subprocess and waits for it to finish.
77
 *
78
 * @param args subprocess arguments
79
 * @param flags subprocess flags
80
 * @param error return location for a GError, or NULL
81
 *
82
 * @return TRUE on success, FALSE if an error occurred
83
 */
84
gboolean r_subprocess_runv(GPtrArray *args, GSubprocessFlags flags, GError **error)
85
G_GNUC_WARN_UNUSED_RESULT;
86
87
#define R_LOG_LEVEL_TRACE 1 << G_LOG_LEVEL_USER_SHIFT
88
#define r_trace(...)   g_log(G_LOG_DOMAIN,         \
89
    R_LOG_LEVEL_TRACE,    \
90
    __VA_ARGS__)
91
92
/**
93
 * Adds elements of a zero-terminated GStrv/gchar** to an existing GPtrArray
94
 *
95
 * @param ptrarray GPtrArray to add to
96
 * @param argvp arguments to add (may be NULL)
97
 * @param copy whether to just add the pointer (FALSE) or copy the underlying data (TRUE)
98
 */
99
static inline void r_ptr_array_addv(GPtrArray *ptrarray, gchar **argvp, gboolean copy)
100
0
{
101
0
  if (argvp == NULL)
102
0
    return;
103
104
0
  for (gchar **addarg = argvp; *addarg != NULL; addarg++) {
105
0
    g_ptr_array_add(ptrarray, copy ? g_strdup(*addarg) : *addarg);
106
0
  }
107
0
}
Unexecuted instantiation: manifest.c:r_ptr_array_addv
Unexecuted instantiation: utils.c:r_ptr_array_addv
Unexecuted instantiation: checksum.c:r_ptr_array_addv
Unexecuted instantiation: context.c:r_ptr_array_addv
Unexecuted instantiation: event_log.c:r_ptr_array_addv
Unexecuted instantiation: signature.c:r_ptr_array_addv
Unexecuted instantiation: status_file.c:r_ptr_array_addv
Unexecuted instantiation: bootchooser.c:r_ptr_array_addv
Unexecuted instantiation: barebox.c:r_ptr_array_addv
Unexecuted instantiation: custom.c:r_ptr_array_addv
Unexecuted instantiation: efi.c:r_ptr_array_addv
Unexecuted instantiation: grub.c:r_ptr_array_addv
Unexecuted instantiation: uboot.c:r_ptr_array_addv
Unexecuted instantiation: config_file.c:r_ptr_array_addv
Unexecuted instantiation: install.c:r_ptr_array_addv
Unexecuted instantiation: mark.c:r_ptr_array_addv
Unexecuted instantiation: mount.c:r_ptr_array_addv
Unexecuted instantiation: service.c:r_ptr_array_addv
Unexecuted instantiation: shell.c:r_ptr_array_addv
Unexecuted instantiation: slot.c:r_ptr_array_addv
Unexecuted instantiation: update_handler.c:r_ptr_array_addv
Unexecuted instantiation: update_utils.c:r_ptr_array_addv
Unexecuted instantiation: artifacts.c:r_ptr_array_addv
Unexecuted instantiation: bundle.c:r_ptr_array_addv
Unexecuted instantiation: crypt.c:r_ptr_array_addv
Unexecuted instantiation: emmc.c:r_ptr_array_addv
Unexecuted instantiation: hash_index.c:r_ptr_array_addv
Unexecuted instantiation: mbr.c:r_ptr_array_addv
108
109
/**
110
 * Adds a formatted string to the end of a GPtrArray
111
 *
112
 * This is a shorter alternative to:
113
 * g_ptr_array_add(arr, g_strdup_printf("%s: %s", ...));
114
 *
115
 * @param ptrarray GPtrArray to add to
116
 * @param format the printf-like format string
117
 * @param ... the parameters for the format string
118
 */
119
void r_ptr_array_add_printf(GPtrArray *ptrarray, const gchar *format, ...)
120
__attribute__((__format__(__printf__, 2, 3)));
121
122
/**
123
 * Converts an array of 'key=value' strings to a shell quoted string.
124
 *
125
 * This is useful when generating shell-parsable output.
126
 *
127
 * @param ptrarray the GPtrArray to print
128
 */
129
gchar *r_ptr_array_env_to_shell(const GPtrArray *ptrarray);
130
131
/**
132
 * Calls g_environ_setenv for each 'key=value' string in the array.
133
 *
134
 * This is useful when setting up the environment for a subprocess.
135
 *
136
 * @param envp an environment list
137
 * @param ptrarray the GPtrArray to add to the environment
138
 * @param overwrite whether to change existing variables
139
 */
140
gchar **r_environ_setenv_ptr_array(gchar **envp, const GPtrArray *ptrarray, gboolean overwrite)
141
G_GNUC_WARN_UNUSED_RESULT;
142
143
/**
144
 * Calls g_subprocess_launcher_setenv for each 'key=value' string in the array.
145
 *
146
 * This is useful when setting up the environment via a subprocess launcher.
147
 *
148
 * @param launcher a GSubprocessLauncher
149
 * @param ptrarray the GPtrArray to add to the environment
150
 * @param overwrite whether to change existing variables
151
 */
152
void r_subprocess_launcher_setenv_ptr_array(GSubprocessLauncher *launcher, const GPtrArray *ptrarray, gboolean overwrite);
153
154
/**
155
 * Read file content into a GBytes.
156
 *
157
 * @param filename Filename to read from
158
 * @param error return location for a GError, or NULL
159
 *
160
 * @return A newly allocated GBytes on success, NULL if an error occurred
161
 */
162
GBytes *read_file(const gchar *filename, GError **error)
163
G_GNUC_WARN_UNUSED_RESULT;
164
165
/**
166
 * Read file content into a gchar.
167
 *
168
 * @param filename Filename to read from
169
 * @param error return location for a GError, or NULL
170
 *
171
 * @return A newly allocated gchar on success, NULL if an error occurred
172
 */
173
gchar *read_file_str(const gchar *filename, GError **error)
174
G_GNUC_WARN_UNUSED_RESULT;
175
176
/**
177
 * Write content of a GBytes to file.
178
 *
179
 * @param filename
180
 * @param bytes
181
 * @param error return location for a GError, or NULL
182
 *
183
 * @return TRUE on success, FALSE if an error occurred
184
 */
185
gboolean write_file(const gchar *filename, GBytes *bytes, GError **error)
186
G_GNUC_WARN_UNUSED_RESULT;
187
188
/**
189
 * Copy a file.
190
 *
191
 * @param srcprefix Prefix path to append to filename given in srcfile
192
 * @param srcfile filename or path of file to copy from
193
 * @param dtsprefix Prefix path to append to filename given in dstfile
194
 * @param dstfile filename or path of file to copy to
195
 * @param error return location for a GError, or NULL
196
 *
197
 * @return TRUE on success, FALSE if an error occurred
198
 */
199
gboolean copy_file(const gchar *srcprefix, const gchar *srcfile,
200
    const gchar *dstprefix, const gchar *dstfile, GError **error)
201
G_GNUC_WARN_UNUSED_RESULT;
202
203
/**
204
 * Recursively delete directory contents.
205
 *
206
 * @param path path of directory to delete
207
 * @param error return location for a GError, or NULL
208
 *
209
 * @return TRUE on success, FALSE if an error occurred
210
 */
211
gboolean rm_tree(const gchar *path, GError **error);
212
213
/**
214
 * Recursively check directory tree for open files.
215
 *
216
 * @param path path of directory to check
217
 * @param error return location for a GError, or NULL
218
 *
219
 * @return TRUE if no files are open, FALSE otherwise
220
 */
221
gboolean r_tree_check_open(const gchar *path, GError **error)
222
G_GNUC_WARN_UNUSED_RESULT;
223
224
/**
225
 * Resolve path based on directory of `basefile` argument or current working dir.
226
 *
227
 * This is useful for parsing paths from config files where the path locations
228
 * may depend on the config files location. In this case `path` would be the
229
 * pathname set in the config file, and `basefile` would be the path to the
230
 * config file itself.
231
 *
232
 * If given path itself is absolute, this will be returned.
233
 * If `basefile` is given and absolute, its location (with the pathname
234
 * stripped) will be used as the prefix path for `path`.
235
 * If `basefile` is not an absolute path, the current workding dir will be used
236
 * as the prefix path for `path` instead.
237
 *
238
 * @param basefile Reference path to resolve `path` to
239
 * @param path The path to resolve an absolute path for
240
 *
241
 * @return An absolute path name, determined as described above, NULL if undeterminable
242
 *         [transfer full]
243
 */
244
gchar *resolve_path(const gchar *basefile, const gchar *path)
245
G_GNUC_WARN_UNUSED_RESULT;
246
247
/**
248
 * Resolve path based on directory of `basefile` argument or current working dir
249
 * and free path.
250
 *
251
 * This is a wrapper around resolve_path(), for use when the path argument is
252
 * not needed after the call.
253
 *
254
 * @param basefile Reference path to resolve `path` to
255
 * @param path The path to resolve an absolute path for (freed)
256
 *
257
 * @return An absolute path name, determined as described above, NULL if undeterminable
258
 *         [transfer full]
259
 */
260
gchar *resolve_path_take(const gchar *basefile, gchar *path)
261
G_GNUC_WARN_UNUSED_RESULT;
262
263
gboolean check_remaining_groups(GKeyFile *key_file, GError **error)
264
G_GNUC_WARN_UNUSED_RESULT;
265
gboolean check_remaining_keys(GKeyFile *key_file, const gchar *groupname, GError **error)
266
G_GNUC_WARN_UNUSED_RESULT;
267
268
/**
269
 * Get string argument from key and remove key from key_file.
270
 *
271
 * @return A newly allocated string or NULL on error.
272
 */
273
gchar * key_file_consume_string(
274
    GKeyFile *key_file,
275
    const gchar *group_name,
276
    const gchar *key,
277
    GError **error)
278
G_GNUC_WARN_UNUSED_RESULT;
279
280
/**
281
 * Ensure that the input string contains neither whitespace nor tab.
282
 *
283
 * @param str string to check.
284
 *
285
 * @return TRUE if str contains neither whitespace nor tab, FALSE otherwise
286
 */
287
gboolean value_check_tab_whitespace(const gchar *str, GError **error)
288
G_GNUC_WARN_UNUSED_RESULT;
289
290
/**
291
 * Get integer argument from key and remove key from key_file.
292
 */
293
gint key_file_consume_integer(
294
    GKeyFile *key_file,
295
    const gchar *group_name,
296
    const gchar *key,
297
    GError **error)
298
G_GNUC_WARN_UNUSED_RESULT;
299
300
guint64 key_file_consume_binary_suffixed_string(GKeyFile *key_file,
301
    const gchar *group_name,
302
    const gchar *key,
303
    GError **error)
304
G_GNUC_WARN_UNUSED_RESULT;
305
306
gchar * r_realpath(const gchar *path)
307
G_GNUC_WARN_UNUSED_RESULT;
308
309
/**
310
 * Remove surrounding whitespace and signal changes.
311
 *
312
 * @param str string to modify
313
 *
314
 * @return TRUE if whitespace was removed, FALSE otherwise
315
 */
316
gboolean r_whitespace_removed(gchar *str)
317
G_GNUC_WARN_UNUSED_RESULT;
318
319
guint8 *r_hex_decode(const gchar *hex, size_t len)
320
G_GNUC_WARN_UNUSED_RESULT;
321
gchar *r_hex_encode(const guint8 *raw, size_t len)
322
G_GNUC_WARN_UNUSED_RESULT;
323
324
gboolean r_read_exact(const int fd, guint8 *data, size_t size, GError **error)
325
G_GNUC_WARN_UNUSED_RESULT;
326
gboolean r_write_exact(const int fd, const guint8 *data, size_t size, GError **error)
327
G_GNUC_WARN_UNUSED_RESULT;
328
329
gboolean r_pread_exact(const int fd, guint8 *data, size_t size, off_t offset, GError **error)
330
G_GNUC_WARN_UNUSED_RESULT;
331
332
gboolean r_pwrite_exact(const int fd, const guint8 *data, size_t size, off_t offset, GError **error)
333
G_GNUC_WARN_UNUSED_RESULT;
334
335
gboolean r_pwrite_lazy(const int fd, const guint8 *data, size_t size, off_t offset, GError **error)
336
G_GNUC_WARN_UNUSED_RESULT;
337
338
guint get_sectorsize(gint fd)
339
G_GNUC_WARN_UNUSED_RESULT;
340
341
goffset get_device_size(gint fd, GError **error)
342
G_GNUC_WARN_UNUSED_RESULT;
343
344
/**
345
 * Replaces a string pointer with a newly allocated copy of the source string.
346
 *
347
 * If the pointer was non-NULL previously, the old string is freed.
348
 *
349
 * @param dst the pointer to update
350
 * @param src the string to copy
351
 */
352
void r_replace_strdup(gchar **dst, const gchar *src);
353
354
/**
355
 * Converts a key for use in an environment variable name.
356
 *
357
 * Only alphanumeric characters and '_' are allowed. '-' is converted to '_'.
358
 *
359
 * @param key string to convert
360
 * @param error return location for a GError, or NULL
361
 *
362
 * @return the newly alloacted and converted string
363
 */
364
gchar *r_prepare_env_key(const gchar *key, GError **error)
365
G_GNUC_WARN_UNUSED_RESULT;
366
367
/**
368
 * Atomically updates a symlink (if needed).
369
 *
370
 * @param target new target for the symlink
371
 * @param name filename of the symlink to update
372
 * @param error return location for a GError, or NULL
373
 *
374
 * @return TRUE if the symlink now points to the given target, FALSE otherwise
375
 */
376
gboolean r_update_symlink(const gchar *target, const gchar *name, GError **error)
377
G_GNUC_WARN_UNUSED_RESULT;
378
379
/**
380
 * Calls syncfs on a given filesystem.
381
 *
382
 * @param path path on the filesystem to sync
383
 * @param error return location for a GError, or NULL
384
 *
385
 * @return TRUE if the filesystem was synced, FALSE otherwise
386
 */
387
gboolean r_syncfs(const gchar *path, GError **error)
388
G_GNUC_WARN_UNUSED_RESULT;
389
390
/**
391
 * Create a temporary directory for the fakeroot environment file.
392
 *
393
 * @param error return location for a GError, or NULL
394
 *
395
 * @return path to the env file, NULL on error
396
 */
397
gchar* r_fakeroot_init(GError **error)
398
G_GNUC_WARN_UNUSED_RESULT;
399
400
/**
401
 * Add fakeroot startup arguments to the array.
402
 *
403
 * The env file needs to be created with r_fakeroot_init first.
404
 * Does nothing if the path is NULL.
405
 *
406
 * @param args the GPtrArray to modify
407
 * @param envpath path to the env file
408
 */
409
void r_fakeroot_add_args(GPtrArray *args, const gchar *envpath);
410
411
/**
412
 * Removes the temporary directory containing the fakeroot environment file.
413
 *
414
 * Does nothing if the path is NULL.
415
 *
416
 * @param envpath path to the env file
417
 * @param error return location for a GError, or NULL
418
 *
419
 * @return TRUE if the cleanup was successful, FALSE otherwise
420
 */
421
gboolean r_fakeroot_cleanup(const gchar *envpath, GError **error)
422
G_GNUC_WARN_UNUSED_RESULT;
423
424
/**
425
 * Removes a temporary file and frees the filename string.
426
 *
427
 * Does nothing if the path is NULL. If the filename does not refer to a
428
 * regular file, it only frees the string.
429
 *
430
 * @param filename path to the temporary file
431
 */
432
void r_tempfile_cleanup(gchar *filename);
433
434
/* Use
435
 *
436
 *   g_auto(RTempFile) filename = g_build_filename(...);
437
 *
438
 * to declare a file that will be automatically removed when
439
 * filename goes out of scope.
440
 *
441
 * If the file should become permanent on success, simply use
442
 *
443
 *   g_clear_pointer(&filename, g_free);
444
 *
445
 * to avoid the automatic cleanup.
446
 */
447
typedef gchar* RTempFile;
448
G_DEFINE_AUTO_CLEANUP_FREE_FUNC(RTempFile, r_tempfile_cleanup, NULL)
449
450
/**
451
 * Returns the contents of the GBytes as a '\0'-terminated string.
452
 *
453
 * The provided GBytes pointer is freed and nulled.
454
 * Internally, it uses g_strndup.
455
 *
456
 * @param bytes GBytes to take the contents from
457
 *
458
 * @return null-terminated string, to be freed by the caller
459
 */
460
gchar *r_bytes_unref_to_string(GBytes **bytes)
461
G_GNUC_WARN_UNUSED_RESULT;
462
463
/**
464
 * Parse a "semantic version" string into its constituents.
465
 *
466
 *
467
 * @param version_string input string
468
 * @param[out] version_core return location for version-core as {major,minor,patch}
469
 * @param[out] pre_release return location for pre_release version part, can be NULL
470
 * @param[out] build return location for build version part, can be NULL
471
 * @param[out] error return location for a GError, or NULL
472
 *
473
 * @return TRUE if the parsing was successful, FALSE otherwise
474
 */
475
gboolean r_semver_parse(const gchar *version_string, guint64 version_core[3], gchar **pre_release, gchar **build, GError **error);
476
477
/**
478
 * Compare two "semantic version" strings over their version-core and pre_release identifier.
479
 *
480
 * @param version_string_a version A
481
 * @param version_string_b version B
482
 * @param error return location for a GError, or NULL
483
 *
484
 * @return TRUE if A<=B, FALSE otherwise
485
 */
486
gboolean r_semver_less_equal(const gchar *version_string_a, const gchar *version_string_b, GError **error);
487
488
/**
489
 * Converts a duration given in seconds into a short human-readable string.
490
 * The format is compact and space-separated, for example: "2h 15m 30s".
491
 *
492
 * Units are:
493
 * - Days: "d"
494
 * - Hours: "h"
495
 * - Minutes: "m"
496
 * - Seconds: "s"
497
 *
498
 * Units with zero values are omitted (except when the entire duration is zero,
499
 * in which case "0s" is returned).
500
 *
501
 * @param total_seconds duration in seconds
502
 *
503
 * @return newly-allocated string representing the formatted duration
504
 */
505
gchar *r_format_duration(gint64 total_seconds);
506
507
/**
508
 * Compiles, matches and fetches the match in one call.
509
 *
510
 * This should only be used to simplify code in non-performance-critical places.
511
 *
512
 * @param pattern the regular expression
513
 * @param string the string to search
514
 *
515
 * @return newly-allocated string with the matched substring or NULL
516
 */
517
gchar *r_regex_match_simple(const gchar *pattern, const gchar *string)
518
G_GNUC_WARN_UNUSED_RESULT;