Coverage Report

Created: 2025-10-10 06:38

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/openssh/atomicio.c
Line
Count
Source
1
/* $OpenBSD: atomicio.c,v 1.30 2019/01/24 02:42:23 dtucker Exp $ */
2
/*
3
 * Copyright (c) 2006 Damien Miller. All rights reserved.
4
 * Copyright (c) 2005 Anil Madhavapeddy. All rights reserved.
5
 * Copyright (c) 1995,1999 Theo de Raadt.  All rights reserved.
6
 * All rights reserved.
7
 *
8
 * Redistribution and use in source and binary forms, with or without
9
 * modification, are permitted provided that the following conditions
10
 * are met:
11
 * 1. Redistributions of source code must retain the above copyright
12
 *    notice, this list of conditions and the following disclaimer.
13
 * 2. Redistributions in binary form must reproduce the above copyright
14
 *    notice, this list of conditions and the following disclaimer in the
15
 *    documentation and/or other materials provided with the distribution.
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
 */
28
29
#include "includes.h"
30
31
#include <sys/uio.h>
32
33
#include <errno.h>
34
#include <poll.h>
35
#include <string.h>
36
#include <unistd.h>
37
#include <limits.h>
38
39
#include "atomicio.h"
40
41
/*
42
 * ensure all of data on socket comes through. f==read || f==vwrite
43
 */
44
size_t
45
atomicio6(ssize_t (*f) (int, void *, size_t), int fd, void *_s, size_t n,
46
    int (*cb)(void *, size_t), void *cb_arg)
47
0
{
48
0
  char *s = _s;
49
0
  size_t pos = 0;
50
0
  ssize_t res;
51
0
  struct pollfd pfd;
52
53
0
  pfd.fd = fd;
54
0
#ifndef BROKEN_READ_COMPARISON
55
0
  pfd.events = f == read ? POLLIN : POLLOUT;
56
#else
57
  pfd.events = POLLIN|POLLOUT;
58
#endif
59
0
  while (n > pos) {
60
0
    res = (f) (fd, s + pos, n - pos);
61
0
    switch (res) {
62
0
    case -1:
63
0
      if (errno == EINTR) {
64
        /* possible SIGALARM, update callback */
65
0
        if (cb != NULL && cb(cb_arg, 0) == -1) {
66
0
          errno = EINTR;
67
0
          return pos;
68
0
        }
69
0
        continue;
70
0
      } else if (errno == EAGAIN || errno == EWOULDBLOCK) {
71
0
        (void)poll(&pfd, 1, -1);
72
0
        continue;
73
0
      }
74
0
      return 0;
75
0
    case 0:
76
0
      errno = EPIPE;
77
0
      return pos;
78
0
    default:
79
0
      pos += (size_t)res;
80
0
      if (cb != NULL && cb(cb_arg, (size_t)res) == -1) {
81
0
        errno = EINTR;
82
0
        return pos;
83
0
      }
84
0
    }
85
0
  }
86
0
  return pos;
87
0
}
88
89
size_t
90
atomicio(ssize_t (*f) (int, void *, size_t), int fd, void *_s, size_t n)
91
0
{
92
0
  return atomicio6(f, fd, _s, n, NULL, NULL);
93
0
}
94
95
/*
96
 * ensure all of data on socket comes through. f==readv || f==writev
97
 */
98
size_t
99
atomiciov6(ssize_t (*f) (int, const struct iovec *, int), int fd,
100
    const struct iovec *_iov, int iovcnt,
101
    int (*cb)(void *, size_t), void *cb_arg)
102
0
{
103
0
  size_t pos = 0, rem;
104
0
  ssize_t res;
105
0
  struct iovec iov_array[IOV_MAX], *iov = iov_array;
106
0
  struct pollfd pfd;
107
108
0
  if (iovcnt < 0 || iovcnt > IOV_MAX) {
109
0
    errno = EINVAL;
110
0
    return 0;
111
0
  }
112
  /* Make a copy of the iov array because we may modify it below */
113
0
  memcpy(iov, _iov, (size_t)iovcnt * sizeof(*_iov));
114
115
0
  pfd.fd = fd;
116
0
#ifndef BROKEN_READV_COMPARISON
117
0
  pfd.events = f == readv ? POLLIN : POLLOUT;
118
#else
119
  pfd.events = POLLIN|POLLOUT;
120
#endif
121
0
  for (; iovcnt > 0 && iov[0].iov_len > 0;) {
122
0
    res = (f) (fd, iov, iovcnt);
123
0
    switch (res) {
124
0
    case -1:
125
0
      if (errno == EINTR) {
126
        /* possible SIGALARM, update callback */
127
0
        if (cb != NULL && cb(cb_arg, 0) == -1) {
128
0
          errno = EINTR;
129
0
          return pos;
130
0
        }
131
0
        continue;
132
0
      } else if (errno == EAGAIN || errno == EWOULDBLOCK) {
133
0
        (void)poll(&pfd, 1, -1);
134
0
        continue;
135
0
      }
136
0
      return 0;
137
0
    case 0:
138
0
      errno = EPIPE;
139
0
      return pos;
140
0
    default:
141
0
      rem = (size_t)res;
142
0
      pos += rem;
143
      /* skip completed iov entries */
144
0
      while (iovcnt > 0 && rem >= iov[0].iov_len) {
145
0
        rem -= iov[0].iov_len;
146
0
        iov++;
147
0
        iovcnt--;
148
0
      }
149
      /* This shouldn't happen... */
150
0
      if (rem > 0 && (iovcnt <= 0 || rem > iov[0].iov_len)) {
151
0
        errno = EFAULT;
152
0
        return 0;
153
0
      }
154
0
      if (iovcnt == 0)
155
0
        break;
156
      /* update pointer in partially complete iov */
157
0
      iov[0].iov_base = ((char *)iov[0].iov_base) + rem;
158
0
      iov[0].iov_len -= rem;
159
0
    }
160
0
    if (cb != NULL && cb(cb_arg, (size_t)res) == -1) {
161
0
      errno = EINTR;
162
0
      return pos;
163
0
    }
164
0
  }
165
0
  return pos;
166
0
}
167
168
size_t
169
atomiciov(ssize_t (*f) (int, const struct iovec *, int), int fd,
170
    const struct iovec *_iov, int iovcnt)
171
0
{
172
0
  return atomiciov6(f, fd, _iov, iovcnt, NULL, NULL);
173
0
}