1 /*
2 Copyright (C) 2004, 2005 Stephen Bach
3 This file is part of the Viewglob package.
4
5 Viewglob is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 Viewglob is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with Viewglob; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19
20 #include "common.h"
21 #include "hardened-io.h"
22
23 #include <sys/stat.h>
24 #include <fcntl.h>
25
26
27 /* Attempt to open the given file with the given flags and mode.
28 Emit warning if it doesn't work out. */
open_warning(gchar * file_name,gint flags,mode_t mode)29 gint open_warning(gchar* file_name, gint flags, mode_t mode) {
30
31 g_return_val_if_fail(file_name != NULL, -1);
32
33 gint fd;
34
35 if ((fd = open(file_name, flags, mode)) == -1)
36 g_warning("Could not open file \"%s\": %s", file_name,
37 g_strerror(errno));
38
39 return fd;
40 }
41
42
43 /* Attempt to close the given file. Emit warning on failure. */
close_warning(gint fd,gchar * file_name)44 void close_warning(gint fd, gchar* file_name) {
45 if (fd != -1 && close(fd) == -1)
46 g_warning("Could not close file \"%s\": %s", file_name,
47 g_strerror(errno));
48 }
49
50
51 /* Retry read on EINTR. */
hardened_read(gint fd,void * buf,gsize count,gssize * nread)52 enum io_result hardened_read(gint fd, void* buf, gsize count, gssize* nread) {
53
54 g_return_val_if_fail(fd >= 0, IOR_ERROR);
55 g_return_val_if_fail(buf != NULL, IOR_ERROR);
56
57 gboolean result = IOR_OK;
58
59 do {
60 *nread = read(fd, buf, count);
61 } while (*nread == -1 && errno == EINTR);
62
63 if (*nread == -1)
64 result = IOR_ERROR;
65 else if (*nread == 0)
66 result = IOR_EOF;
67
68 return result;
69 }
70
71
72 /* Read exactly the given number of bytes. */
read_all(gint fd,void * buf,gsize bytes)73 enum io_result read_all(gint fd, void* buf, gsize bytes) {
74
75 g_return_val_if_fail(fd >= 0, IOR_ERROR);
76 g_return_val_if_fail(buf != NULL, IOR_ERROR);
77
78 gboolean result = IOR_OK;
79 gssize nread = 0;
80
81 gchar* pos = buf;
82 while (bytes) {
83 errno = 0;
84 if ( (nread = read(fd, pos, bytes)) == -1) {
85 if (errno == EINTR)
86 nread = 0;
87 else {
88 result = IOR_ERROR;
89 break;
90 }
91 }
92 else if (nread == 0) {
93 result = IOR_EOF;
94 break;
95 }
96 bytes -= nread;
97 pos += nread;
98 }
99
100 return result;
101 }
102
103
104 /* Write all length bytes of buf to fd, even if it requires several tries.
105 Retry after signal interrupts. */
write_all(gint fd,void * buf,gsize bytes)106 enum io_result write_all(gint fd, void* buf, gsize bytes) {
107
108 g_return_val_if_fail(fd >= 0, IOR_ERROR);
109 g_return_val_if_fail(buf != NULL, IOR_ERROR);
110
111 enum io_result result = IOR_OK;
112 gssize nwritten;
113
114 gchar* pos = buf;
115 while (bytes) {
116 errno = 0;
117 if ( (nwritten = write(fd, pos, bytes)) == -1 ) {
118 if (errno == EINTR)
119 nwritten = 0;
120 else {
121 result = IOR_ERROR;
122 break;
123 }
124 }
125 bytes -= nwritten;
126 pos += nwritten;
127 }
128
129 return result;
130 }
131
132
133 /* Wrapper for writev() to ensure everything is written. */
writev_all(gint fd,struct iovec * vec,gint count)134 enum io_result writev_all(gint fd, struct iovec* vec, gint count) {
135
136 g_return_val_if_fail(fd >= 0, IOR_ERROR);
137 g_return_val_if_fail(vec != NULL, IOR_ERROR);
138 g_return_val_if_fail(count >= 0, IOR_ERROR);
139
140 gssize nwritten;
141 enum io_result result = IOR_OK;
142
143 do
144 nwritten = writev(fd, vec, count);
145 while (nwritten == -1 && errno == EINTR);
146
147 if (nwritten == -1)
148 result = IOR_ERROR;
149 else {
150 gchar* ptr;
151 while (count > 0) {
152 if (nwritten >= vec->iov_len) {
153 /* This buffer was completely written. */
154 nwritten -= vec->iov_len;
155 vec++;
156 count--;
157 }
158 else {
159 /* This buffer was partially written. */
160 ptr = vec->iov_base;
161 ptr += nwritten;
162 vec->iov_base = ptr;
163 vec->iov_len -= nwritten;
164 break;
165 }
166 }
167
168 if (count > 1)
169 result = writev_all(fd, vec, count);
170 else if (count == 1)
171 result = write_all(fd, vec->iov_base, vec->iov_len);
172 }
173
174 return result;
175 }
176
177
178 /* If select is interrupted by a signal, try again. */
179 //int hardened_select(gint n, fd_set* readfds, struct timeval* timeout) {
hardened_select(gint n,fd_set * readfds,long milliseconds)180 int hardened_select(gint n, fd_set* readfds, long milliseconds) {
181
182 g_return_val_if_fail(n > 0, -1);
183 g_return_val_if_fail(readfds != NULL, -1);
184
185 int result;
186 struct timeval* t = NULL;
187
188 /* Create a timestruct for the given number of milliseconds. */
189 if (milliseconds >= 0) {
190 t = g_new(struct timeval, 1);
191 t->tv_sec = milliseconds / 1000;
192 t->tv_usec = (milliseconds - (1000 * t->tv_sec)) * 1000;
193 }
194
195 do {
196 result = select(n, readfds, NULL, NULL, t);
197 } while (result == -1 && errno == EINTR);
198
199 g_free(t);
200 return result;
201 }
202
203