1 /*
2 Bacula(R) - The Network Backup Solution
3
4 Copyright (C) 2000-2020 Kern Sibbald
5
6 The original author of Bacula is Kern Sibbald, with contributions
7 from many others, a complete list can be found in the file AUTHORS.
8
9 You may use this file and others of this release according to the
10 license defined in the LICENSE file, which includes the Affero General
11 Public License, v3.0 ("AGPLv3") and some additional permissions and
12 terms pursuant to its AGPLv3 Section 7.
13
14 This notice must be preserved when any source code is
15 conveyed and/or propagated.
16
17 Bacula(R) is a registered trademark of Kern Sibbald.
18 */
19
20 #ifdef HAVE_WIN32
21
22 # include <windows.h>
23 # include <conio.h>
24 # include <stdbool.h>
25
26 #else /* !HAVE_WIN32 */
27
28 # include <sys/stat.h>
29 # include <unistd.h>
30 # include <errno.h>
31 # include <stdlib.h>
32 # include <string.h>
33
34 #endif /* HAVE_WIN32 */
35
36 /* Common include */
37 #include <stdio.h>
38 #include <sys/types.h>
39 #include <fcntl.h>
40
41 #include "namedpipe.h"
42
43 #ifdef TEST_PROGRAM
44 # define Dmsg(level, ...) printf(__VA_ARGS__ )
45 #endif
46
47 #ifdef HAVE_WIN32
48
namedpipe_init(NamedPipe * self)49 void namedpipe_init(NamedPipe *self)
50 {
51 self->fd = INVALID_HANDLE_VALUE;
52 self->ifd = -1;
53 }
54
namedpipe_free(NamedPipe * self)55 void namedpipe_free(NamedPipe *self)
56 {
57 if (self->fd != INVALID_HANDLE_VALUE) {
58 CloseHandle(self->fd);
59 self->fd = INVALID_HANDLE_VALUE;
60 self->ifd = -1;
61 }
62 }
63 #define BUFSIZE 8192
namedpipe_create(NamedPipe * self,const char * path,mode_t mode)64 int namedpipe_create(NamedPipe *self, const char *path, mode_t mode)
65 {
66 /* On windows, */
67 self->fd = CreateNamedPipeA(
68 path, // pipe name
69 PIPE_ACCESS_DUPLEX, // read/write access
70 PIPE_TYPE_MESSAGE | // message type pipe
71 PIPE_READMODE_MESSAGE | // message-read mode
72 PIPE_WAIT, // blocking mode
73 PIPE_UNLIMITED_INSTANCES, // max. instances
74 BUFSIZE, // output buffer size
75 BUFSIZE, // input buffer size
76 0, // client time-out
77 NULL); // default security attribute
78
79 if (self->fd == INVALID_HANDLE_VALUE) {
80 Dmsg(10, "CreateNamedPipe failed, ERR=%d.\n", (int)GetLastError());
81 return -1;
82 }
83
84 return 0;
85 }
86
namedpipe_open(NamedPipe * self,const char * path,mode_t mode)87 int namedpipe_open(NamedPipe *self, const char *path, mode_t mode)
88 {
89 bool fConnected=false;
90 int retry = 30;
91
92 if (self->fd != INVALID_HANDLE_VALUE) { /* server mode */
93
94 fConnected = ConnectNamedPipe(self->fd, NULL) ?
95 TRUE : (GetLastError() == ERROR_PIPE_CONNECTED);
96
97 } else { /* client mode */
98
99 /* Need to wait for creation */
100 while (retry-- > 0)
101 {
102 self->fd = CreateFileA(
103 path, // pipe name
104 GENERIC_WRITE | GENERIC_READ,
105 0, // no sharing
106 NULL, // default security attributes
107 OPEN_EXISTING, // opens existing pipe
108 0, // default attributes
109 NULL); // no template file
110
111 // Break if the pipe handle is valid.
112 if (self->fd != INVALID_HANDLE_VALUE) {
113 break;
114 }
115
116 /* Wait a little bit for the other side to create the fifo */
117 if (GetLastError() == ERROR_FILE_NOT_FOUND) {
118 Dmsg(10, "File not found, ERR=%d.\n", (int)GetLastError());
119 Sleep(20000);
120 continue;
121 }
122
123 // Exit if an error other than ERROR_PIPE_BUSY occurs.
124 if (GetLastError() != ERROR_PIPE_BUSY) {
125 Dmsg(10, "CreateFile failed, ERR=%d.\n",
126 (int)GetLastError());
127 return -1;
128 }
129
130 // All pipe instances are busy, so wait for 20 seconds.
131 if (!WaitNamedPipeA(path, 20000)) {
132 Dmsg(10, "WaitNamedPipe failed, ERR=%d.\n",
133 (int)GetLastError());
134 return -1;
135 }
136 }
137 }
138
139 DWORD dwMode = PIPE_READMODE_MESSAGE;
140
141 fConnected = SetNamedPipeHandleState(
142 self->fd, // pipe handle
143 &dwMode, // new pipe mode
144 NULL, // don't set maximum bytes
145 NULL); // don't set maximum time
146
147 if (!fConnected) {
148 Dmsg(10, "SetNamedPipeHandleState failed, ERR=%d.\n",
149 (int)GetLastError());
150 }
151
152 if (fConnected) {
153 int m = 0;
154 if (mode & O_WRONLY || mode & O_APPEND) {
155 m |= O_APPEND;
156
157 } else if (mode & O_RDONLY) {
158 m |= O_RDONLY;
159 }
160 self->ifd = _open_osfhandle((intptr_t)self->fd, m);
161 }
162
163 return self->ifd;
164 }
165
166
167 #else /* !HAVE_WIN32 */
168
namedpipe_init(NamedPipe * self)169 void namedpipe_init(NamedPipe *self)
170 {
171 self->fd = -1;
172 self->ifd = -1;
173 self->name = NULL;
174 }
175
namedpipe_free(NamedPipe * self)176 void namedpipe_free(NamedPipe *self)
177 {
178 if (self->fd != -1) {
179 close(self->fd);
180 self->fd = -1;
181 self->ifd = -1;
182 }
183 if (self->name) {
184 unlink(self->name);
185 free(self->name);
186 self->name = NULL;
187 }
188 }
189
namedpipe_create(NamedPipe * self,const char * path,mode_t mode)190 int namedpipe_create(NamedPipe *self, const char *path, mode_t mode)
191 {
192 self->name = (char *)malloc(strlen(path) + 1);
193 strcpy(self->name, path);
194
195 if (mkfifo(path, mode) < 0 && errno != EEXIST) {
196 return -1;
197 }
198
199 return 0;
200 }
201
namedpipe_open(NamedPipe * self,const char * path,mode_t mode)202 int namedpipe_open(NamedPipe *self, const char *path, mode_t mode)
203 {
204 self->ifd = self->fd = open(path, mode);
205 return self->fd;
206 }
207
208 #endif /* HAVE_WIN32 */
209
210 #ifdef TEST_PROGRAM
211
212 #include <string.h>
213 #include <stdlib.h>
214
215 #define BUF "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \
216 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \
217 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \
218 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \
219 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \
220 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \
221 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \
222 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \
223 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
224
main(int argc,char ** argv)225 int main(int argc, char **argv)
226 {
227 FILE *fp;
228 NamedPipe p;
229 char buf[65*1024], file[128];
230 int fd;
231 int mode;
232 int n, m, o;
233 if (argc < 4) {
234 printf("Usage: %s client|server pipe file\n", argv[0]);
235 exit(3);
236 }
237
238 namedpipe_init(&p);
239
240 if (strcmp(argv[1], "server") == 0) {
241 mode = O_WRONLY;
242 if (namedpipe_create(&p, argv[2], 0600) < 0) {
243 exit(2);
244 }
245
246 } else {
247 mode = O_RDONLY;
248 }
249
250 printf("Trying to open %s mode=%d\n", argv[2], mode);
251 fd = namedpipe_open(&p, argv[2], mode);
252
253 if (fd < 0) {
254 printf("Unable to open pipe\n");
255 exit(1);
256 }
257
258 if (strcmp(argv[1], "server") == 0) {
259 if (write(fd, BUF, strlen(BUF)+1) != strlen(BUF)+1) {
260 printf("Unable to write data\n");
261 exit(4);
262 }
263
264 if (write(fd, BUF, strlen(BUF)+1) != strlen(BUF)+1) {
265 printf("Unable to write data\n");
266 exit(4);
267 }
268
269 fp = bfopen(argv[3], "rb");
270 if (!fp) {
271 printf("Unable to open %s for reading\n", argv[3]);
272 exit(4);
273 }
274
275 fseek(fp, 0, SEEK_END);
276 m = ftell(fp);
277 fseek(fp, 0, SEEK_SET);
278
279 snprintf(buf, sizeof(buf), "%.10d\n", m);
280 write(fd, buf, strlen(buf)+1);
281
282 while (m > 0 && !feof(fp)) {
283 n = fread(buf, 1, sizeof(buf), fp);
284 Dmsg(000, "read %d from file\n", n);
285 if (write(fd, buf, n) != n) {
286 printf("Unable to write data from file\n");
287 exit(5);
288 }
289 m -= n;
290 }
291 Dmsg(000, "EOF found\n");
292 fclose(fp);
293
294 } else {
295 if ((n = read(fd, buf, sizeof(buf))) != strlen(BUF)+1) {
296 Dmsg(000, "read failed (%d != %d), ERR=%d.\n", n,
297 (int)strlen(BUF)+1, errno);
298 exit(4);
299 }
300 if (read(fd, buf, sizeof(buf)) != strlen(BUF)+1) {
301 Dmsg(000, "read failed, ERR=%d.\n", errno);
302 exit(4);
303 }
304
305 printf("buf=[%s]\n", buf);
306
307 snprintf(file, sizeof(file), "%s.out", argv[3]);
308 fp = bfopen(file, "wb");
309 if (!fp) {
310 printf("Unable to open %s for writing\n", buf);
311 exit(4);
312 }
313
314 if ((n = read(fd, buf, sizeof(buf))) != 12) {
315 Dmsg(000, "read failed (%d != %d), ERR=%d.\n", n, 12, errno);
316 exit(4);
317 }
318
319 m = atoi(buf);
320 Dmsg(000, "will read %d from fifo\n", m);
321
322 while (m > 0) {
323 n = read(fd, buf, sizeof(buf));
324 Dmsg(000, "Got %d bytes\n", n);
325 if ((o = fwrite(buf, n, 1, fp)) != 1) {
326 Dmsg(000, "write to file failed (%d != %d) ERR=%d.\n", o, n, errno);
327 exit(4);
328 }
329 m -= n;
330 }
331 fclose(fp);
332 }
333
334 namedpipe_free(&p);
335
336 exit(0);
337 }
338 #endif
339