Coverage Report

Created: 2026-10-17 06:39

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
  pfd.events = f == read ? POLLIN : POLLOUT;
55
0
  while (n > pos) {
56
0
    res = (f) (fd, s + pos, n - pos);
57
0
    switch (res) {
58
0
    case -1:
59
0
      if (errno == EINTR) {
60
        /* possible SIGALARM, update callback */
61
0
        if (cb != NULL && cb(cb_arg, 0) == -1) {
62
0
          errno = EINTR;
63
0
          return pos;
64
0
        }
65
0
        continue;
66
0
      } else if (errno == EAGAIN || errno == EWOULDBLOCK) {
67
0
        (void)poll(&pfd, 1, -1);
68
0
        continue;
69
0
      }
70
0
      return 0;
71
0
    case 0:
72
0
      errno = EPIPE;
73
0
      return pos;
74
0
    default:
75
0
      pos += (size_t)res;
76
0
      if (cb != NULL && cb(cb_arg, (size_t)res) == -1) {
77
0
        errno = EINTR;
78
0
        return pos;
79
0
      }
80
0
    }
81
0
  }
82
0
  return pos;
83
0
}
84
85
size_t
86
atomicio(ssize_t (*f) (int, void *, size_t), int fd, void *_s, size_t n)
87
0
{
88
0
  return atomicio6(f, fd, _s, n, NULL, NULL);
89
0
}
90
91
/*
92
 * ensure all of data on socket comes through. f==readv || f==writev
93
 */
94
size_t
95
atomiciov6(ssize_t (*f) (int, const struct iovec *, int), int fd,
96
    const struct iovec *_iov, int iovcnt,
97
    int (*cb)(void *, size_t), void *cb_arg)
98
0
{
99
0
  size_t pos = 0, rem;
100
0
  ssize_t res;
101
0
  struct iovec iov_array[IOV_MAX], *iov = iov_array;
102
0
  struct pollfd pfd;
103
104
0
  if (iovcnt < 0 || iovcnt > IOV_MAX) {
105
0
    errno = EINVAL;
106
0
    return 0;
107
0
  }
108
  /* Make a copy of the iov array because we may modify it below */
109
0
  memcpy(iov, _iov, (size_t)iovcnt * sizeof(*_iov));
110
111
0
  pfd.fd = fd;
112
0
#ifndef BROKEN_READV_COMPARISON
113
0
  pfd.events = f == readv ? POLLIN : POLLOUT;
114
#else
115
  pfd.events = POLLIN|POLLOUT;
116
#endif
117
0
  for (; iovcnt > 0 && iov[0].iov_len > 0;) {
118
0
    res = (f) (fd, iov, iovcnt);
119
0
    switch (res) {
120
0
    case -1:
121
0
      if (errno == EINTR) {
122
        /* possible SIGALARM, update callback */
123
0
        if (cb != NULL && cb(cb_arg, 0) == -1) {
124
0
          errno = EINTR;
125
0
          return pos;
126
0
        }
127
0
        continue;
128
0
      } else if (errno == EAGAIN || errno == EWOULDBLOCK) {
129
0
        (void)poll(&pfd, 1, -1);
130
0
        continue;
131
0
      }
132
0
      return 0;
133
0
    case 0:
134
0
      errno = EPIPE;
135
0
      return pos;
136
0
    default:
137
0
      rem = (size_t)res;
138
0
      pos += rem;
139
      /* skip completed iov entries */
140
0
      while (iovcnt > 0 && rem >= iov[0].iov_len) {
141
0
        rem -= iov[0].iov_len;
142
0
        iov++;
143
0
        iovcnt--;
144
0
      }
145
      /* This shouldn't happen... */
146
0
      if (rem > 0 && (iovcnt <= 0 || rem > iov[0].iov_len)) {
147
0
        errno = EFAULT;
148
0
        return 0;
149
0
      }
150
0
      if (iovcnt == 0)
151
0
        break;
152
      /* update pointer in partially complete iov */
153
0
      iov[0].iov_base = ((char *)iov[0].iov_base) + rem;
154
0
      iov[0].iov_len -= rem;
155
0
    }
156
0
    if (cb != NULL && cb(cb_arg, (size_t)res) == -1) {
157
0
      errno = EINTR;
158
0
      return pos;
159
0
    }
160
0
  }
161
0
  return pos;
162
0
}
163
164
size_t
165
atomiciov(ssize_t (*f) (int, const struct iovec *, int), int fd,
166
    const struct iovec *_iov, int iovcnt)
167
0
{
168
0
  return atomiciov6(f, fd, _iov, iovcnt, NULL, NULL);
169
0
}