Coverage Report

Created: 2020-12-02 17:02

/libfido2/src/hid_unix.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (c) 2020 Yubico AB. All rights reserved.
3
 * Use of this source code is governed by a BSD-style
4
 * license that can be found in the LICENSE file.
5
 */
6
7
#include <sys/types.h>
8
#include <sys/stat.h>
9
10
#include <errno.h>
11
#include <fcntl.h>
12
#include <limits.h>
13
#include <poll.h>
14
#include <stdint.h>
15
#include <stdio.h>
16
#include <stdlib.h>
17
#include <string.h>
18
#include <time.h>
19
#include <unistd.h>
20
21
#include "fido.h"
22
23
static void
24
xstrerror(int errnum, char *buf, size_t len)
25
0
{
26
0
        if (len < 1)
27
0
                return;
28
0
29
0
        memset(buf, 0, len);
30
0
31
0
        if (strerror_r(errnum, buf, len - 1) != 0)
32
0
                snprintf(buf, len - 1, "error %d", errnum);
33
0
}
34
35
static int
36
timespec_to_ms(const struct timespec *ts, int upper_bound)
37
0
{
38
0
        int64_t x;
39
0
        int64_t y;
40
0
41
0
        if (ts->tv_sec < 0 || (uint64_t)ts->tv_sec > INT64_MAX / 1000LL ||
42
0
            ts->tv_nsec < 0 || (uint64_t)ts->tv_nsec / 1000000LL > INT64_MAX)
43
0
                return (upper_bound);
44
0
45
0
        x = ts->tv_sec * 1000LL;
46
0
        y = ts->tv_nsec / 1000000LL;
47
0
48
0
        if (INT64_MAX - x < y || x + y > upper_bound)
49
0
                return (upper_bound);
50
0
51
0
        return (int)(x + y);
52
0
}
53
54
int
55
fido_hid_unix_open(const char *path)
56
0
{
57
0
        char ebuf[128];
58
0
        int fd;
59
0
        struct stat st;
60
0
61
0
        if ((fd = open(path, O_RDWR)) == -1) {
62
0
                if (errno != ENOENT && errno != ENXIO) {
63
0
                        xstrerror(errno, ebuf, sizeof(ebuf));
64
0
                        fido_log_debug("%s: open %s: %s", __func__, path, ebuf);
65
0
                }
66
0
                return (-1);
67
0
        }
68
0
69
0
        if (fstat(fd, &st) == -1) {
70
0
                xstrerror(errno, ebuf, sizeof(ebuf));
71
0
                fido_log_debug("%s: fstat %s: %s", __func__, path, ebuf);
72
0
                close(fd);
73
0
                return (-1);
74
0
        }
75
0
76
0
        if (S_ISCHR(st.st_mode) == 0) {
77
0
                fido_log_debug("%s: S_ISCHR %s", __func__, path);
78
0
                close(fd);
79
0
                return (-1);
80
0
        }
81
0
82
0
        return (fd);
83
0
}
84
85
int
86
fido_hid_unix_wait(int fd, int ms)
87
0
{
88
0
        char            ebuf[128];
89
0
        struct timespec ts_start;
90
0
        struct timespec ts_now;
91
0
        struct timespec ts_delta;
92
0
        struct pollfd   pfd;
93
0
        int             ms_remain;
94
0
        int             r;
95
0
96
0
        if (ms < 0)
97
0
                return (0);
98
0
99
0
        memset(&pfd, 0, sizeof(pfd));
100
0
        pfd.events = POLLIN;
101
0
        pfd.fd = fd;
102
0
103
0
        if (clock_gettime(CLOCK_MONOTONIC, &ts_start) != 0) {
104
0
                xstrerror(errno, ebuf, sizeof(ebuf));
105
0
                fido_log_debug("%s: clock_gettime: %s", __func__, ebuf);
106
0
                return (-1);
107
0
        }
108
0
109
0
        for (ms_remain = ms; ms_remain > 0;) {
110
0
                if ((r = poll(&pfd, 1, ms_remain)) > 0)
111
0
                        return (0);
112
0
                else if (r == 0)
113
0
                        break;
114
0
                else if (errno != EINTR) {
115
0
                        xstrerror(errno, ebuf, sizeof(ebuf));
116
0
                        fido_log_debug("%s: poll: %s", __func__, ebuf);
117
0
                        return (-1);
118
0
                }
119
0
                /* poll interrupted - subtract time already waited */
120
0
                if (clock_gettime(CLOCK_MONOTONIC, &ts_now) != 0) {
121
0
                        xstrerror(errno, ebuf, sizeof(ebuf));
122
0
                        fido_log_debug("%s: clock_gettime: %s", __func__, ebuf);
123
0
                        return (-1);
124
0
                }
125
0
                timespecsub(&ts_now, &ts_start, &ts_delta);
126
0
                ms_remain = ms - timespec_to_ms(&ts_delta, ms);
127
0
        }
128
0
129
0
        return (-1);
130
0
}