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