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

stefanberger / swtpm / #2824

13 May 2025 12:34PM UTC coverage: 72.964% (-0.5%) from 73.462%
#2824

push

travis-ci

web-flow
Merge c2b02e9b2 into 1544c99ca

7033 of 9639 relevant lines covered (72.96%)

13748.12 hits per line

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

85.6
/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

25
#include "swtpm_utils.h"
26

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

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

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

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

53
    if (logfile == NULL)
719✔
54
        fprintf(stream, "%s", str);
616✔
55
    else
56
        append_to_file(logfile, str);
103✔
57

58
    free(str);
719✔
59
}
60

61
void logit(const char *logfile, const char *fmt, ...)
715✔
62
{
63
    va_list ap;
715✔
64

65
    va_start(ap, fmt);
715✔
66
    alog(stdout, logfile, fmt, ap);
715✔
67
    va_end(ap);
715✔
68
}
715✔
69

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

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

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

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

109
    for (i = 0; arr1 != NULL && arr1[i]; i++)
17,862✔
110
        n++;
15,507✔
111
    for (i = 0; arr2 != NULL && arr2[i]; i++)
7,900✔
112
        n++;
5,545✔
113

114
    res = g_malloc0(sizeof(char *) * (n + 1));
2,355✔
115
    for (i = 0, n = 0; arr1 != NULL && arr1[i]; i++)
20,217✔
116
        res[n++] = arr1[i];
15,507✔
117
    for (i = 0; arr2 != NULL && arr2[i]; i++)
7,900✔
118
        res[n++] = arr2[i];
5,545✔
119

120
    if (free_arr1 && arr1)
2,355✔
121
        g_free(arr1);
1,692✔
122

123
    return res;
2,355✔
124
}
125

126
/* Concatenate buffers into a given buffer of a given length 'buflen' */
127
ssize_t concat(unsigned char *buffer, size_t buflen, ...)
202✔
128
{
129
    va_list ap;
202✔
130
    ssize_t offset = 0;
202✔
131

132
    va_start(ap, buflen);
202✔
133

134
    while (1) {
750✔
135
        size_t len;
476✔
136
        unsigned char *i = va_arg(ap, unsigned char *);
476✔
137

138
        if (i == NULL)
476✔
139
            break;
140

141
        len = va_arg(ap, size_t);
274✔
142
        if (offset + len > buflen) {
274✔
143
            offset = -(offset + len);
×
144
            break;
×
145
        }
146

147
        memcpy(&buffer[offset], i, len);
274✔
148
        offset += len;
274✔
149
   }
150
   va_end(ap);
202✔
151

152
   return offset;
202✔
153
}
154

155
/* Concatenate buffers and allocate a new buffer and return its size */
156
ssize_t memconcat(unsigned char **buffer, ...)
814✔
157
{
158
    va_list ap;
814✔
159
    ssize_t offset = 0;
814✔
160
    size_t allocated = 128;
814✔
161
    unsigned char *p;
814✔
162

163
    *buffer = g_malloc(allocated);
814✔
164
    p = *buffer;
814✔
165

166
    va_start(ap, buffer);
814✔
167

168
    while (1) {
7,414✔
169
        size_t len;
4,114✔
170
        unsigned char *i = va_arg(ap, unsigned char *);
4,114✔
171

172
        if (i == NULL)
4,114✔
173
            break;
174

175
        len = va_arg(ap, size_t);
3,300✔
176
        if (offset + len > allocated) {
3,300✔
177
            allocated += offset + len;
84✔
178
            *buffer = g_realloc(*buffer, allocated);
84✔
179
            p = *buffer;
84✔
180
        }
181

182
        memcpy(&p[offset], i, len);
3,300✔
183
        offset += len;
3,300✔
184
   }
185
   va_end(ap);
814✔
186

187
   return offset;
814✔
188
}
189

190
/* Print an input buffer as hex number */
191
gchar *print_as_hex(unsigned char *input, size_t input_len)
122✔
192
{
193
    gchar *out = g_malloc(input_len * 2 + 1);
122✔
194
    size_t i;
122✔
195

196
    for (i = 0; i < input_len; i++)
17,076✔
197
        g_snprintf(&out[i * 2], 3, "%02x", input[i]);
16,832✔
198

199
    return out;
122✔
200
}
201

202
/* Split a command line and remove all trailing and leading spaces from all entries and remove
203
 * 0-length strings entirely.
204
 */
205
gchar **split_cmdline(const gchar *cmdline) {
82✔
206
    gchar **result = g_strsplit(cmdline, " ", -1);
82✔
207
    size_t i, j;
82✔
208

209
    for (i = 0, j = 0; result[i] != NULL; i++) {
405✔
210
        gchar *chomped = g_strchomp(result[i]);
241✔
211

212
        if (strlen(chomped) == 0) {
241✔
213
            g_free(chomped);
77✔
214
            result[i] = NULL;
77✔
215
        } else {
216
            result[i] = NULL;
164✔
217
            result[j++] = chomped;
164✔
218
        }
219
    }
220
    return result;
82✔
221
}
222

223
/* resolve environment variables in a string */
224
gchar *resolve_string(const gchar *inp) {
232✔
225
    char *pe;
232✔
226
    gchar *result = NULL;
232✔
227
    gchar *new_res, *tmp;
232✔
228
    size_t sidx = 0;
232✔
229
    const gchar *envval;
244✔
230

231
    while (1) {
256✔
232
        gchar *ps = g_strstr_len(&inp[sidx], -1, "${");
244✔
233
        if (ps == NULL) {
244✔
234
            if (sidx == 0) {
232✔
235
                g_free(result); /* coverity */
220✔
236
                return g_strdup(inp);
220✔
237
            }
238
            new_res = g_strconcat(result ? result : "", &inp[sidx], NULL);
12✔
239
            g_free(result);
12✔
240
            return new_res;
12✔
241
        }
242

243
        tmp = g_strndup(&inp[sidx], ps - &inp[sidx]);
12✔
244
        new_res = g_strconcat(result ? result : "", tmp, NULL);
24✔
245
        g_free(tmp);
12✔
246
        g_free(result);
12✔
247
        result = new_res;
12✔
248

249
        pe = g_strstr_len(&ps[2], -1, "}");
12✔
250
        if (pe == NULL) {
12✔
251
            new_res = g_strconcat(result ? result : "", ps, NULL);
×
252
            g_free(result);
×
253
            return new_res;
×
254
        }
255

256
        /* name of environment variable */
257
        tmp = g_strndup(&ps[2], pe - &ps[2]);
12✔
258

259
        envval = g_getenv(tmp);
12✔
260
        new_res = g_strconcat(result ? result : "",
12✔
261
                              envval ? envval : "",
262
                              NULL);
263
        g_free(tmp);
12✔
264
        g_free(result);
12✔
265
        result = new_res;
12✔
266
        sidx = &pe[1] - inp;
12✔
267
    }
268
}
269

270
/* Read an entire file */
271
int read_file(const gchar *filename, gchar **buffer, gsize *buffer_len)
327✔
272
{
273
    GError *error = NULL;
327✔
274

275
    if (!g_file_get_contents(filename, buffer, buffer_len, &error)) {
327✔
276
        logerr(gl_LOGFILE, "%s\n", error->message);
×
277
        g_error_free(error);
×
278
        return 1;
×
279
    }
280
    return 0;
281
}
282

283
/* Read a file and convert its lines into a NULL-termianted array */
284
int read_file_lines(const char *filename, gchar ***config_file_lines)
190✔
285
{
286
    g_autofree gchar *buffer = NULL;
380✔
287
    gsize buffer_len;
190✔
288
    size_t start = 0;
190✔
289
    gchar **array;
190✔
290
    gsize array_len = 1; /* null-terminated array */
190✔
291

292
    if (read_file(filename, &buffer, &buffer_len) != 0)
190✔
293
        return 1;
294

295
    array = g_malloc0(sizeof(char *) * array_len);
190✔
296

297
    while (start < buffer_len) {
857✔
298
        size_t off = start;
299

300
        /* search for end-of-string or next newline */
301
        while (off < buffer_len && buffer[off] != '\n')
27,630✔
302
            off++;
26,963✔
303

304
        if (off > start) {
667✔
305
            /* non-empty line */
306
            array = g_realloc(array, sizeof(char *) * (array_len + 1));
667✔
307
            array[array_len - 1] = g_strndup(&buffer[start], off - start);
667✔
308
            array_len++;
667✔
309
        }
310
        start = off + 1;
667✔
311
    }
312
    array[array_len - 1] = NULL;
190✔
313
    *config_file_lines = array;
190✔
314

315
    return 0;
190✔
316
}
317

318
static ssize_t write_to_fd(int fd, const unsigned char *data, size_t data_len)
58✔
319
{
320
    ssize_t n;
58✔
321

322
    n = write(fd, data, data_len);
58✔
323
    if (n < 0) {
58✔
324
        logerr(gl_LOGFILE, "Could not write to file: %s\n", strerror(errno));
×
325
    } else if ((size_t)n != data_len) {
58✔
326
        logerr(gl_LOGFILE, "Could not write all bytes to the file.\n");
×
327
        n = -1;
×
328
    }
329
    return n;
58✔
330
}
331

332
/* Write to a file with the given name */
333
int write_file(const gchar *filename, const unsigned char *data, size_t data_len)
30✔
334
{
335
    ssize_t n;
30✔
336
    int fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC,
30✔
337
                  S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH );
338
    if (fd < 0) {
30✔
339
        logerr(gl_LOGFILE, "Could not open file %s for writing: %s\n",
×
340
               filename, strerror(errno));
×
341
        return 1;
×
342
    }
343

344
    n = write_to_fd(fd, data, data_len);
30✔
345
    close(fd);
30✔
346
    if (n < 0)
30✔
347
        return 1;
×
348

349
    return 0;
350
}
351

352
int write_to_tempfile(gchar **filename, const unsigned char *data, size_t data_len)
28✔
353
{
354
    GError *error = NULL;
28✔
355
    int fd = g_file_open_tmp("XXXXXX", filename, &error);
28✔
356
    ssize_t n;
28✔
357

358
    if (error) {
28✔
359
        logerr(gl_LOGFILE, "Could not create temporary file: %s\n", error->message);
×
360
        g_error_free(error);
×
361
        return 1;
×
362
    }
363

364
    n = write_to_fd(fd, data, data_len);
28✔
365
    if (n < 0)
28✔
366
        goto error;
×
367

368
    n = lseek(fd, 0, SEEK_SET);
28✔
369
    if (n < 0) {
28✔
370
        logerr(gl_LOGFILE, "Could not seek(0) on file '%s': %s\n", filename, strerror(errno));
×
371
        goto error;
×
372
    }
373
    return fd;
374

375
error:
×
376
    close(fd);
×
377
    return -1;
×
378
}
379

380
/* replace occurences of 'torep' with 'rep' in a string 'in' */
381
gchar *str_replace(const char *in, const char *torep, const char *rep)
4✔
382
{
383
    char *res;
4✔
384
    const char *s, *b;
4✔
385
    size_t torep_len;
4✔
386
    size_t rep_len;
4✔
387
    size_t ctr = 0;
4✔
388
    size_t off = 0;
4✔
389

390
    if (in == NULL || torep == NULL || rep == NULL)
4✔
391
        return NULL;
392

393
    torep_len = strlen(torep);
4✔
394
    if (torep_len == 0)
4✔
395
        return NULL;
396

397
    rep_len = strlen(rep);
4✔
398

399
    s = in;
4✔
400
    while ((s = strstr(s, torep)) != NULL) {
28✔
401
        s += torep_len;
24✔
402
        ctr++;
24✔
403
    }
404

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

407
    b = s = in;
4✔
408
    while ((s = strstr(s, torep)) != NULL) {
28✔
409
        strncpy(&res[off], b, s - b);
24✔
410
        off += (s - b);
24✔
411
        s += torep_len;
24✔
412
        b = s;
24✔
413
        strcpy(&res[off], rep);
24✔
414
        off += rep_len;
24✔
415
    }
416
    strcpy(&res[off], b);
4✔
417

418
    return res;
4✔
419
}
420

421
int check_directory_access(const gchar *directory, int mode, const struct passwd *curr_user)
78✔
422
{
423
    struct stat statbuf;
78✔
424

425
    if (stat(directory, &statbuf) != 0 || (statbuf.st_mode & S_IFMT) != S_IFDIR) {
78✔
426
        logerr(gl_LOGFILE,
×
427
               "User %s cannot access directory %s. Make sure it exists and is a directory.\n",
428
               curr_user ? curr_user->pw_name : "<unknown>", directory);
429
        return 1;
×
430
    }
431
    if ((mode & R_OK) && access(directory, R_OK) != 0) {
78✔
432
        logerr(gl_LOGFILE, "Need read rights on directory %s for user %s.\n",
×
433
               directory, curr_user ? curr_user->pw_name : "<unknown>");
434
        return 1;
×
435
    }
436
    if ((mode & W_OK) && access(directory, W_OK) != 0) {
78✔
437
        logerr(gl_LOGFILE, "Need write rights on directory %s for user %s.\n",
×
438
               directory, curr_user ? curr_user->pw_name : "<unknown>");
439
        return 1;
×
440
    }
441
    return 0;
442
}
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