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

stefanberger / swtpm / #2826

13 May 2025 12:42PM UTC coverage: 73.293% (+0.09%) from 73.203%
#2826

push

travis-ci

web-flow
Merge 79ab56b79 into f55e820e5

8060 of 10997 relevant lines covered (73.29%)

13568.95 hits per line

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

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

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

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

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

54
    if (logfile == NULL)
1,216✔
55
        fprintf(stream, "%s", str);
669✔
56
    else
57
        append_to_file(logfile, str);
547✔
58

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

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

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

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

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

110
    for (i = 0; arr1 != NULL && arr1[i]; i++)
25,865✔
111
        n++;
22,245✔
112
    for (i = 0; arr2 != NULL && arr2[i]; i++)
12,067✔
113
        n++;
8,447✔
114

115
    res = g_malloc0(sizeof(char *) * (n + 1));
3,620✔
116
    for (i = 0, n = 0; arr1 != NULL && arr1[i]; i++)
29,485✔
117
        res[n++] = arr1[i];
22,245✔
118
    for (i = 0; arr2 != NULL && arr2[i]; i++)
12,067✔
119
        res[n++] = arr2[i];
8,447✔
120

121
    if (free_arr1 && arr1)
3,620✔
122
        g_free(arr1);
2,488✔
123

124
    return res;
3,620✔
125
}
126

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

140
    va_start(ap, buflen);
402✔
141

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

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

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

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

160
   return offset;
402✔
161
}
162

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

171
    *buffer = g_malloc(allocated);
960✔
172
    p = *buffer;
960✔
173

174
    va_start(ap, buffer);
960✔
175

176
    while (1) {
8,622✔
177
        size_t len;
4,791✔
178
        unsigned char *i = va_arg(ap, unsigned char *);
4,791✔
179

180
        if (i == NULL)
4,791✔
181
            break;
182

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

190
        memcpy(&p[offset], i, len);
3,831✔
191
        offset += len;
3,831✔
192
   }
193
   va_end(ap);
960✔
194

195
   return offset;
960✔
196
}
197

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

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

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

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

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

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

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

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

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

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

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

283
    if (!g_file_get_contents(filename, buffer, buffer_len, &error)) {
421✔
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)
278✔
293
{
294
    g_autofree gchar *buffer = NULL;
556✔
295
    gsize buffer_len;
278✔
296
    size_t start = 0;
278✔
297
    gchar **array;
278✔
298
    gsize array_len = 1; /* null-terminated array */
278✔
299

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

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

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

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

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

323
    return 0;
278✔
324
}
325

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

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

357
    return 0;
358
}
359

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

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

376
    n = lseek(fd, 0, SEEK_SET);
30✔
377
    if (n < 0) {
30✔
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

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

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

405
    rep_len = strlen(rep);
4✔
406

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

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

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

426
    return res;
4✔
427
}
428

429
int check_directory_access(const gchar *directory, int mode, const struct passwd *curr_user)
150✔
430
{
431
    struct stat statbuf;
150✔
432

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

452
int json_get_map_value(const char *json_input, const char *field_name,
76✔
453
                       gchar **value)
454
{
455
    g_autoptr(GError) error = NULL;
152✔
456
    JsonParser *jp = NULL;
76✔
457
    JsonReader *jr = NULL;
76✔
458
    JsonNode *root;
76✔
459
    int ret = -1;
76✔
460

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

468
    root = json_parser_get_root(jp);
76✔
469
    jr = json_reader_new(root);
76✔
470

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

479
    ret = 0;
76✔
480

481
error_unref_jr:
76✔
482
    g_object_unref(jr);
76✔
483

484
error_unref_jp:
76✔
485
    g_object_unref(jp);
76✔
486

487
    return ret;
76✔
488
}
489

490
int strv_strcmp(gchar *const*str_array, const gchar *s)
53✔
491
{
492
    size_t i;
53✔
493

494
    for (i = 0; str_array[i]; i++) {
174✔
495
        if (strcmp(str_array[i], s) == 0)
173✔
496
            return (int)i;
52✔
497
    }
498
    return -1;
499
}
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