• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

stefanberger / swtpm / #2905

16 Mar 2026 08:52PM UTC coverage: 73.216%. Remained the same
#2905

push

travis-ci

web-flow
Merge 8ab773bdc into 4a9949609

13 of 20 new or added lines in 4 files covered. (65.0%)

77 existing lines in 3 files now uncovered.

7728 of 10555 relevant lines covered (73.22%)

10184.45 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

85.51
/src/utils/swtpm_utils.c
1
/* SPDX-License-Identifier: BSD-3-Clause */
2
/*
3
 * swtpm_setup_utils.c: Utility functions for swtpm_setup et al.
4
 *
5
 * Author: Stefan Berger, stefanb@linux.ibm.com
6
 *
7
 * Copyright (c) IBM Corporation, 2021
8
 */
9

10
#include "config.h"
11

12
#define _GNU_SOURCE
13
#include <sys/types.h>
14
#include <sys/stat.h>
15
#include <errno.h>
16
#include <fcntl.h>
17
#include <stdarg.h>
18
#include <stdio.h>
19
#include <stdlib.h>
20
#include <string.h>
21
#include <unistd.h>
22

23
#include <glib.h>
24
#include <json-glib/json-glib.h>
25

26
#include "swtpm_utils.h"
27

28
void append_to_file(const char *pathname, const char *str)
575✔
29
{
30
    size_t n, len;
575✔
31
    int fd = open(pathname, O_WRONLY|O_APPEND|O_CREAT|O_NOFOLLOW, S_IRUSR|S_IWUSR|S_IRGRP);
575✔
32

33
    if (fd >= 0) {
575✔
34
        len = strlen(str);
575✔
35
        n = write(fd, str, len);
575✔
36
        if (n != len) {
575✔
37
            fprintf(stderr, "Error writing to %s: %s\n", pathname, strerror(errno));
×
38
        }
39
        close(fd);
575✔
40
    } else {
41
        fprintf(stderr, "Error opening file %s: %s\n", pathname, strerror(errno));
×
42
    }
43
}
575✔
44

45
static void alog(FILE *stream, const char *logfile, const char *fmt, va_list ap)
1,328✔
46
{
47
    char *str = NULL;
1,328✔
48
    int n;
1,328✔
49

50
    n = vasprintf(&str, fmt, ap);
1,328✔
51
    if (n < 0)
1,328✔
52
        return;
×
53

54
    if (logfile == NULL)
1,328✔
55
        fprintf(stream, "%s", str);
753✔
56
    else
57
        append_to_file(logfile, str);
575✔
58

59
    free(str);
1,328✔
60
}
61

62
void logit(const char *logfile, const char *fmt, ...)
1,287✔
63
{
64
    va_list ap;
1,287✔
65

66
    va_start(ap, fmt);
1,287✔
67
    alog(stdout, logfile, fmt, ap);
1,287✔
68
    va_end(ap);
1,287✔
69
}
1,287✔
70

71
void logerr(const char *logfile, const char *fmt, ...)
41✔
72
{
73
    va_list ap;
41✔
74

75
    va_start(ap, fmt);
41✔
76
    alog(stderr, logfile, fmt, ap);
41✔
77
    va_end(ap);
41✔
78
}
41✔
79

80
/* Join paths of up to 3 parts into a pre-allocated buffer. The last part is optional */
81
char *pathjoin(char *buffer, size_t bufferlen, const char *p1, const char *p2, const char *p3)
154✔
82
{
83
    char *res = NULL;
154✔
84
    int n = snprintf(buffer, bufferlen, "%s%s%s%s%s",
308✔
85
                     p1,
86
                     G_DIR_SEPARATOR_S,
87
                     p2,
88
                     p3 ? G_DIR_SEPARATOR_S : "",
89
                     p3 ? p3 : "");
90
    if (n < 0) {
154✔
91
        logerr(gl_LOGFILE, "Error: Could not print into buffer.\n");
×
92
    } else if ((size_t)n >= bufferlen) {
154✔
93
        logerr(gl_LOGFILE, "Error: Buffer for path is too small.\n");
×
94
    } else {
95
        res = buffer;
96
    }
97
    return res;
154✔
98
}
99

100
/* Concatenate two NULL-terminated arrays creating one new one;
101
 * This function does not duplicate the memory for the elements.
102
 * Either one of the arrays may be NULL. The first array can be freed.
103
 */
104
const gchar **concat_arrays(const gchar **arr1, const gchar **arr2, gboolean free_arr1)
4,053✔
105
{
106
    size_t n = 0;
4,053✔
107
    const gchar **res;
4,053✔
108
    size_t i;
4,053✔
109

110
    for (i = 0; arr1 != NULL && arr1[i]; i++)
29,382✔
111
        n++;
25,329✔
112
    for (i = 0; arr2 != NULL && arr2[i]; i++)
13,446✔
113
        n++;
9,393✔
114

115
    res = g_malloc0(sizeof(char *) * (n + 1));
4,053✔
116
    for (i = 0, n = 0; arr1 != NULL && arr1[i]; i++)
33,435✔
117
        res[n++] = arr1[i];
25,329✔
118
    for (i = 0; arr2 != NULL && arr2[i]; i++)
13,446✔
119
        res[n++] = arr2[i];
9,393✔
120

121
    if (free_arr1 && arr1)
4,053✔
122
        g_free(arr1);
2,812✔
123

124
    return res;
4,053✔
125
}
126

127
gchar **concat_varrays(gchar **arr1, gchar **arr2, gboolean free_arr1)
1,152✔
128
{
129
    return (gchar **)concat_arrays((const char **)arr1,
1,152✔
130
                                   (const char **)arr2,
131
                                   free_arr1);
132
}
133

134
/* Concatenate buffers into a given buffer of a given length 'buflen' */
135
ssize_t concat(unsigned char *buffer, size_t buflen, ...)
438✔
136
{
137
    va_list ap;
438✔
138
    ssize_t offset = 0;
438✔
139

140
    va_start(ap, buflen);
438✔
141

142
    while (1) {
1,458✔
143
        size_t len;
948✔
144
        unsigned char *i = va_arg(ap, unsigned char *);
948✔
145

146
        if (i == NULL)
948✔
147
            break;
148

149
        len = va_arg(ap, size_t);
510✔
150
        if (offset + len > buflen) {
510✔
151
            offset = -(offset + len);
×
152
            break;
×
153
        }
154

155
        memcpy(&buffer[offset], i, len);
510✔
156
        offset += len;
510✔
157
   }
158
   va_end(ap);
438✔
159

160
   return offset;
438✔
161
}
162

163
/* Concatenate buffers and allocate a new buffer and return its size */
164
ssize_t memconcat(unsigned char **buffer, ...)
1,079✔
165
{
166
    va_list ap;
1,079✔
167
    ssize_t offset = 0;
1,079✔
168
    size_t allocated = 128;
1,079✔
169
    unsigned char *p;
1,079✔
170

171
    *buffer = g_malloc(allocated);
1,079✔
172
    p = *buffer;
1,079✔
173

174
    va_start(ap, buffer);
1,079✔
175

176
    while (1) {
9,781✔
177
        size_t len;
5,430✔
178
        unsigned char *i = va_arg(ap, unsigned char *);
5,430✔
179

180
        if (i == NULL)
5,430✔
181
            break;
182

183
        len = va_arg(ap, size_t);
4,351✔
184
        if (offset + len > allocated) {
4,351✔
185
            allocated += offset + len;
95✔
186
            *buffer = g_realloc(*buffer, allocated);
95✔
187
            p = *buffer;
95✔
188
        }
189

190
        memcpy(&p[offset], i, len);
4,351✔
191
        offset += len;
4,351✔
192
   }
193
   va_end(ap);
1,079✔
194

195
   return offset;
1,079✔
196
}
197

198
/* Print an input buffer as hex number */
199
gchar *print_as_hex(const unsigned char *input, size_t input_len)
146✔
200
{
201
    gchar *out = g_malloc(input_len * 2 + 1);
146✔
202
    size_t i;
146✔
203

204
    for (i = 0; i < input_len; i++)
21,860✔
205
        g_snprintf(&out[i * 2], 3, "%02x", input[i]);
21,568✔
206

207
    return out;
146✔
208
}
209

210
/* Split a command line and remove all trailing and leading spaces from all entries and remove
211
 * 0-length strings entirely.
212
 */
213
gchar **split_cmdline(const gchar *cmdline) {
169✔
214
    gchar **result = g_strsplit(cmdline, " ", -1);
169✔
215
    size_t i, j;
169✔
216

217
    for (i = 0, j = 0; result[i] != NULL; i++) {
841✔
218
        gchar *chomped = g_strchomp(result[i]);
503✔
219

220
        if (strlen(chomped) == 0) {
503✔
221
            g_free(chomped);
165✔
222
            result[i] = NULL;
165✔
223
        } else {
224
            result[i] = NULL;
338✔
225
            result[j++] = chomped;
338✔
226
        }
227
    }
228
    return result;
169✔
229
}
230

231
/* resolve environment variables in a string */
232
gchar *resolve_string(const gchar *inp) {
327✔
233
    char *pe;
327✔
234
    gchar *result = NULL;
327✔
235
    gchar *new_res, *tmp;
327✔
236
    size_t sidx = 0;
327✔
237
    const gchar *envval;
343✔
238

239
    while (1) {
359✔
240
        gchar *ps = g_strstr_len(&inp[sidx], -1, "${");
343✔
241
        if (ps == NULL) {
343✔
242
            if (sidx == 0) {
327✔
243
                g_free(result); /* coverity */
311✔
244
                return g_strdup(inp);
311✔
245
            }
246
            new_res = g_strconcat(result ? result : "", &inp[sidx], NULL);
16✔
247
            g_free(result);
16✔
248
            return new_res;
16✔
249
        }
250

251
        tmp = g_strndup(&inp[sidx], ps - &inp[sidx]);
16✔
252
        new_res = g_strconcat(result ? result : "", tmp, NULL);
32✔
253
        g_free(tmp);
16✔
254
        g_free(result);
16✔
255
        result = new_res;
16✔
256

257
        pe = g_strstr_len(&ps[2], -1, "}");
16✔
258
        if (pe == NULL) {
16✔
259
            new_res = g_strconcat(result ? result : "", ps, NULL);
×
260
            g_free(result);
×
261
            return new_res;
×
262
        }
263

264
        /* name of environment variable */
265
        tmp = g_strndup(&ps[2], pe - &ps[2]);
16✔
266

267
        envval = g_getenv(tmp);
16✔
268
        new_res = g_strconcat(result ? result : "",
16✔
269
                              envval ? envval : "",
270
                              NULL);
271
        g_free(tmp);
16✔
272
        g_free(result);
16✔
273
        result = new_res;
16✔
274
        sidx = &pe[1] - inp;
16✔
275
    }
276
}
277

278
/* Read an entire file */
279
int read_file(const gchar *filename, gchar **buffer, gsize *buffer_len)
469✔
280
{
281
    GError *error = NULL;
469✔
282

283
    if (!g_file_get_contents(filename, buffer, buffer_len, &error)) {
469✔
284
        logerr(gl_LOGFILE, "%s\n", error->message);
×
285
        g_error_free(error);
×
286
        return 1;
×
287
    }
288
    return 0;
289
}
290

291
/* Read a file and convert its lines into a NULL-termianted array */
292
int read_file_lines(const char *filename, gchar ***config_file_lines)
305✔
293
{
294
    g_autofree gchar *buffer = NULL;
610✔
295
    gsize buffer_len;
305✔
296
    size_t start = 0;
305✔
297
    gchar **array;
305✔
298
    gsize array_len = 1; /* null-terminated array */
305✔
299

300
    if (read_file(filename, &buffer, &buffer_len) != 0)
305✔
301
        return 1;
302

303
    array = g_malloc0(sizeof(char *) * array_len);
305✔
304

305
    while (start < buffer_len) {
1,471✔
306
        size_t off = start;
307

308
        /* search for end-of-string or next newline */
309
        while (off < buffer_len && buffer[off] != '\n')
50,358✔
310
            off++;
49,192✔
311

312
        if (off > start) {
1,166✔
313
            /* non-empty line */
314
            array = g_realloc(array, sizeof(char *) * (array_len + 1));
1,166✔
315
            array[array_len - 1] = g_strndup(&buffer[start], off - start);
1,166✔
316
            array_len++;
1,166✔
317
        }
318
        start = off + 1;
1,166✔
319
    }
320
    array[array_len - 1] = NULL;
305✔
321
    *config_file_lines = array;
305✔
322

323
    return 0;
305✔
324
}
325

326
static ssize_t write_to_fd(int fd, const unsigned char *data, size_t data_len)
69✔
327
{
328
    ssize_t n;
69✔
329

330
    n = write(fd, data, data_len);
69✔
331
    if (n < 0) {
69✔
332
        logerr(gl_LOGFILE, "Could not write to file: %s\n", strerror(errno));
×
333
    } else if ((size_t)n != data_len) {
69✔
334
        logerr(gl_LOGFILE, "Could not write all bytes to the file.\n");
×
335
        n = -1;
×
336
    }
337
    return n;
69✔
338
}
339

340
/* Write to a file with the given name */
341
int write_file(const gchar *filename, const unsigned char *data, size_t data_len)
37✔
342
{
343
    ssize_t n;
37✔
344
    int fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC,
37✔
345
                  S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH );
346
    if (fd < 0) {
37✔
347
        logerr(gl_LOGFILE, "Could not open file %s for writing: %s\n",
×
348
               filename, strerror(errno));
×
349
        return 1;
×
350
    }
351

352
    n = write_to_fd(fd, data, data_len);
37✔
353
    close(fd);
37✔
354
    if (n < 0)
37✔
355
        return 1;
×
356

357
    return 0;
358
}
359

360
int write_to_tempfile(gchar **filename, const unsigned char *data, size_t data_len)
32✔
361
{
362
    GError *error = NULL;
32✔
363
    int fd = g_file_open_tmp("XXXXXX", filename, &error);
32✔
364
    ssize_t n;
32✔
365

366
    if (error) {
32✔
367
        logerr(gl_LOGFILE, "Could not create temporary file: %s\n", error->message);
×
368
        g_error_free(error);
×
369
        return 1;
×
370
    }
371

372
    n = write_to_fd(fd, data, data_len);
32✔
373
    if (n < 0)
32✔
374
        goto error;
×
375

376
    n = lseek(fd, 0, SEEK_SET);
32✔
377
    if (n < 0) {
32✔
378
        logerr(gl_LOGFILE, "Could not seek(0) on file '%s': %s\n", filename, strerror(errno));
×
379
        goto error;
×
380
    }
381
    return fd;
382

383
error:
×
384
    close(fd);
×
385
    return -1;
×
386
}
387

388
/* replace occurrences of 'torep' with 'rep' in a string 'in' */
389
gchar *str_replace(const char *in, const char *torep, const char *rep)
4✔
390
{
391
    char *res;
4✔
392
    const char *s, *b;
4✔
393
    size_t torep_len;
4✔
394
    size_t rep_len;
4✔
395
    size_t ctr = 0;
4✔
396
    size_t off = 0;
4✔
397
    size_t res_len;
4✔
398

399
    if (in == NULL || torep == NULL || rep == NULL)
4✔
400
        return NULL;
401

402
    torep_len = strlen(torep);
4✔
403
    if (torep_len == 0)
4✔
404
        return NULL;
405

406
    rep_len = strlen(rep);
4✔
407

408
    s = in;
4✔
409
    while ((s = strstr(s, torep)) != NULL) {
28✔
410
        s += torep_len;
24✔
411
        ctr++;
24✔
412
    }
413

414
    res_len = strlen(in) - ctr * torep_len + ctr * rep_len;
4✔
415
    res = g_malloc(res_len + 1);
4✔
416

417
    b = s = in;
4✔
418
    while ((s = strstr(s, torep)) != NULL) {
28✔
419
        strncpy(&res[off], b, s - b);
24✔
420
        off += (s - b);
24✔
421
        s += torep_len;
24✔
422
        b = s;
24✔
423
        strncpy(&res[off], rep, res_len - off);
24✔
424
        off += rep_len;
24✔
425
    }
426
    strncpy(&res[off], b, res_len - off);
4✔
427
    res[res_len] = 0;
4✔
428

429
    return res;
4✔
430
}
431

432
int check_directory_access(const gchar *directory, int mode, const struct passwd *curr_user)
160✔
433
{
434
    struct stat statbuf;
160✔
435

436
    if (stat(directory, &statbuf) != 0 || (statbuf.st_mode & S_IFMT) != S_IFDIR) {
160✔
UNCOV
437
        logerr(gl_LOGFILE,
×
438
               "User %s cannot access directory %s. Make sure it exists and is a directory.\n",
439
               curr_user ? curr_user->pw_name : "<unknown>", directory);
440
        return 1;
×
441
    }
442
    if ((mode & R_OK) && access(directory, R_OK) != 0) {
160✔
443
        logerr(gl_LOGFILE, "Need read rights on directory %s for user %s.\n",
×
444
               directory, curr_user ? curr_user->pw_name : "<unknown>");
UNCOV
445
        return 1;
×
446
    }
447
    if ((mode & W_OK) && access(directory, W_OK) != 0) {
160✔
448
        logerr(gl_LOGFILE, "Need write rights on directory %s for user %s.\n",
×
449
               directory, curr_user ? curr_user->pw_name : "<unknown>");
UNCOV
450
        return 1;
×
451
    }
452
    return 0;
453
}
454

455
int json_get_map_value(const char *json_input, const char *field_name,
85✔
456
                       gchar **value)
457
{
458
    g_autoptr(GError) error = NULL;
170✔
459
    JsonParser *jp = NULL;
85✔
460
    JsonReader *jr = NULL;
85✔
461
    JsonNode *root;
85✔
462
    int ret = -1;
85✔
463

464
    jp = json_parser_new();
85✔
465
    if (!json_parser_load_from_data(jp, json_input, -1, &error)) {
85✔
UNCOV
466
        logerr(gl_LOGFILE,
×
UNCOV
467
               "Could not parse JSON '%s': %s\n", json_input, error->message);
×
UNCOV
468
        goto error_unref_jp;
×
469
    }
470

471
    root = json_parser_get_root(jp);
85✔
472
    jr = json_reader_new(root);
85✔
473

474
    if (!json_reader_read_member(jr, field_name)) {
85✔
UNCOV
475
        logerr(gl_LOGFILE, "Missing '%s' field in '%s'\n",
×
476
               field_name, json_input);
UNCOV
477
        goto error_unref_jr;
×
478
    }
479
    *value = g_strdup(json_reader_get_string_value(jr));
85✔
480
    /* caller should handle *value == NULL */
481

482
    ret = 0;
85✔
483

484
error_unref_jr:
85✔
485
    g_object_unref(jr);
85✔
486

487
error_unref_jp:
85✔
488
    g_object_unref(jp);
85✔
489

490
    return ret;
85✔
491
}
492

493
int strv_strcmp(gchar *const*str_array, const gchar *s)
62✔
494
{
495
    size_t i;
62✔
496

497
    for (i = 0; str_array[i]; i++) {
179✔
498
        if (strcmp(str_array[i], s) == 0)
178✔
499
            return (int)i;
61✔
500
    }
501
    return -1;
502
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc