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

stefanberger / swtpm / #2966

05 May 2026 08:29PM UTC coverage: 72.813% (-0.9%) from 73.663%
#2966

push

travis-ci

web-flow
Merge 50c2561a4 into ec2fdc0e1

7909 of 10862 relevant lines covered (72.81%)

9877.44 hits per line

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

72.0
/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)
506✔
29
{
30
    size_t n, len;
506✔
31
    int fd = open(pathname, O_WRONLY|O_APPEND|O_CREAT|O_NOFOLLOW, S_IRUSR|S_IWUSR|S_IRGRP);
506✔
32

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

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

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

54
    if (logfile == NULL)
1,432✔
55
        fprintf(stream, "%s", str);
926✔
56
    else
57
        append_to_file(logfile, str);
506✔
58

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

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

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

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

75
    va_start(ap, fmt);
43✔
76
    alog(stderr, logfile, fmt, ap);
43✔
77
    va_end(ap);
43✔
78
}
43✔
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)
158✔
82
{
83
    char *res = NULL;
158✔
84
    int n = snprintf(buffer, bufferlen, "%s%s%s%s%s",
158✔
85
                     p1,
86
                     G_DIR_SEPARATOR_S,
87
                     p2,
88
                     p3 ? G_DIR_SEPARATOR_S : "",
89
                     p3 ? p3 : "");
90
    if (n < 0) {
158✔
91
        logerr(gl_LOGFILE, "Error: Could not print into buffer.\n");
×
92
    } else if ((size_t)n >= bufferlen) {
158✔
93
        logerr(gl_LOGFILE, "Error: Buffer for path is too small.\n");
×
94
    } else {
95
        res = buffer;
96
    }
97
    return res;
158✔
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)
3,431✔
105
{
106
    size_t n = 0;
3,431✔
107
    const gchar **res;
3,431✔
108
    size_t i;
3,431✔
109

110
    for (i = 0; arr1 != NULL && arr1[i]; i++)
23,347✔
111
        n++;
19,916✔
112
    for (i = 0; arr2 != NULL && arr2[i]; i++)
11,826✔
113
        n++;
8,395✔
114

115
    res = g_malloc0(sizeof(char *) * (n + 1));
3,431✔
116
    for (i = 0, n = 0; arr1 != NULL && arr1[i]; i++)
26,778✔
117
        res[n++] = arr1[i];
19,916✔
118
    for (i = 0; arr2 != NULL && arr2[i]; i++)
11,826✔
119
        res[n++] = arr2[i];
8,395✔
120

121
    if (free_arr1 && arr1)
3,431✔
122
        g_free(arr1);
2,255✔
123

124
    return res;
3,431✔
125
}
126

127
gchar **concat_varrays(gchar **arr1, gchar **arr2, gboolean free_arr1)
974✔
128
{
129
    return (gchar **)concat_arrays((const char **)arr1,
974✔
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, ...)
454✔
136
{
137
    va_list ap;
454✔
138
    ssize_t offset = 0;
454✔
139

140
    va_start(ap, buflen);
454✔
141

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

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

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

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

160
   return offset;
454✔
161
}
162

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

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

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

176
    while (1) {
11,571✔
177
        size_t len;
6,411✔
178
        unsigned char *i = va_arg(ap, unsigned char *);
6,411✔
179

180
        if (i == NULL)
6,411✔
181
            break;
182

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

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

195
   return offset;
1,251✔
196
}
197

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

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

207
    return out;
192✔
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) {
170✔
214
    gchar **result = g_strsplit(cmdline, " ", -1);
170✔
215
    size_t i, j;
170✔
216

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

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

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

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

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

257
        pe = g_strstr_len(&ps[2], -1, "}");
12✔
258
        if (pe == NULL) {
12✔
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]);
12✔
266

267
        envval = g_getenv(tmp);
12✔
268
        new_res = g_strconcat(result ? result : "",
12✔
269
                              envval ? envval : "",
270
                              NULL);
271
        g_free(tmp);
12✔
272
        g_free(result);
12✔
273
        result = new_res;
12✔
274
        sidx = &pe[1] - inp;
12✔
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)
291✔
293
{
294
    g_autofree gchar *buffer = NULL;
582✔
295
    gsize buffer_len;
291✔
296
    size_t start = 0;
291✔
297
    gchar **array;
291✔
298
    gsize array_len = 1; /* null-terminated array */
291✔
299

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

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

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

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

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

323
    return 0;
291✔
324
}
325

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

330
    n = write(fd, data, data_len);
12✔
331
    if (n < 0) {
12✔
332
        logerr(gl_LOGFILE, "Could not write to file: %s\n", strerror(errno));
×
333
    } else if ((size_t)n != data_len) {
12✔
334
        logerr(gl_LOGFILE, "Could not write all bytes to the file.\n");
×
335
        n = -1;
×
336
    }
337
    return n;
12✔
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)
12✔
342
{
343
    ssize_t n;
12✔
344
    int fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC,
12✔
345
                  S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH );
346
    if (fd < 0) {
12✔
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);
12✔
353
    close(fd);
12✔
354
    if (n < 0)
12✔
355
        return 1;
356

357
    return 0;
358
}
359

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

366
    if (error) {
×
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);
×
373
    if (n < 0)
×
374
        goto error;
×
375

376
    n = lseek(fd, 0, SEEK_SET);
×
377
    if (n < 0) {
×
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)
×
390
{
391
    char *res;
×
392
    const char *s, *b;
×
393
    size_t torep_len;
×
394
    size_t rep_len;
×
395
    size_t ctr = 0;
×
396
    size_t off = 0;
×
397
    size_t res_len;
×
398

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

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

406
    rep_len = strlen(rep);
×
407

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

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

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

429
    return res;
×
430
}
431

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

436
    if (stat(directory, &statbuf) != 0 || (statbuf.st_mode & S_IFMT) != S_IFDIR) {
162✔
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) {
162✔
443
        logerr(gl_LOGFILE, "Need read rights on directory %s for user %s.\n",
×
444
               directory, curr_user ? curr_user->pw_name : "<unknown>");
445
        return 1;
×
446
    }
447
    if ((mode & W_OK) && access(directory, W_OK) != 0) {
162✔
448
        logerr(gl_LOGFILE, "Need write rights on directory %s for user %s.\n",
×
449
               directory, curr_user ? curr_user->pw_name : "<unknown>");
450
        return 1;
×
451
    }
452
    return 0;
453
}
454

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

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

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

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

482
    ret = 0;
95✔
483

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

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

490
    return ret;
95✔
491
}
492

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

497
    for (i = 0; str_array[i]; i++) {
208✔
498
        if (strcmp(str_array[i], s) == 0)
207✔
499
            return (int)i;
71✔
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