/src/qubes-os/qubes-core-qrexec/libqrexec/write-stdin.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * The Qubes OS Project, http://www.qubes-os.org |
3 | | * |
4 | | * Copyright (C) 2010 Rafal Wojtczuk <rafal@invisiblethingslab.com> |
5 | | * |
6 | | * This program is free software; you can redistribute it and/or |
7 | | * modify it under the terms of the GNU General Public License |
8 | | * as published by the Free Software Foundation; either version 2 |
9 | | * of the License, or (at your option) any later version. |
10 | | * |
11 | | * This program is distributed in the hope that it will be useful, |
12 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | | * GNU General Public License for more details. |
15 | | * |
16 | | * You should have received a copy of the GNU General Public License |
17 | | * along with this program; if not, write to the Free Software |
18 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
19 | | * |
20 | | */ |
21 | | |
22 | | #include <stdio.h> |
23 | | #include <unistd.h> |
24 | | #include <errno.h> |
25 | | #include <fcntl.h> |
26 | | #include <stdlib.h> |
27 | | #include <libvchan.h> |
28 | | #include "qrexec.h" |
29 | | #include "libqrexec-utils.h" |
30 | | |
31 | | /* |
32 | | There is buffered data in "buffer" for client and poll() |
33 | | reports that "fd" is writable. Write as much as possible to fd. |
34 | | */ |
35 | | int flush_client_data(int fd, struct buffer *buffer) |
36 | 421 | { |
37 | 421 | if (fd == -1) |
38 | 0 | return 0; |
39 | 421 | int ret; |
40 | 421 | int len; |
41 | 421 | for (;;) { |
42 | 421 | len = buffer_len(buffer); |
43 | 421 | if (!len) { |
44 | 421 | return WRITE_STDIN_OK; |
45 | 421 | } |
46 | 0 | ret = write(fd, buffer_data(buffer), len); |
47 | 0 | if (ret == -1) { |
48 | 0 | if (errno != EAGAIN) |
49 | 0 | return WRITE_STDIN_ERROR; |
50 | 0 | else |
51 | 0 | return WRITE_STDIN_BUFFERED; |
52 | 0 | } |
53 | | // we previously called buffer_remove(buffer, len) |
54 | | // it will be wrong if we change MAX_DATA_CHUNK to something large |
55 | | // as pipes writes are atomic only to PIPE_MAX limit |
56 | 0 | buffer_remove(buffer, ret); |
57 | 0 | } |
58 | | |
59 | 421 | } |
60 | | |
61 | | /* |
62 | | * Write "len" bytes from "data" to "fd". If not all written, buffer the rest |
63 | | * to "buffer". |
64 | | */ |
65 | | int write_stdin(int fd, const char *data, int len, struct buffer *buffer) |
66 | 1.50k | { |
67 | 1.50k | int ret; |
68 | 1.50k | int written = 0; |
69 | | |
70 | 1.50k | if (buffer_len(buffer)) { |
71 | 0 | buffer_append(buffer, data, len); |
72 | 0 | return WRITE_STDIN_BUFFERED; |
73 | 0 | } |
74 | 3.01k | while (written < len) { |
75 | 1.50k | ret = write(fd, data + written, len - written); |
76 | 1.50k | if (ret == 0) { |
77 | 0 | PERROR("write_stdin: write returns 0 ???"); |
78 | 0 | exit(1); |
79 | 0 | } |
80 | 1.50k | if (ret == -1) { |
81 | 0 | if (errno != EAGAIN) |
82 | 0 | return WRITE_STDIN_ERROR; |
83 | | |
84 | 0 | buffer_append(buffer, data + written, |
85 | 0 | len - written); |
86 | |
|
87 | 0 | return WRITE_STDIN_BUFFERED; |
88 | 0 | } |
89 | 1.50k | written += ret; |
90 | 1.50k | } |
91 | 1.50k | return WRITE_STDIN_OK; |
92 | 1.50k | } |
93 | | |
94 | | /* |
95 | | * Data feed process has exited, so we need to clear all control structures for |
96 | | * the client. However, if we have buffered data for the client (which is rare btw), |
97 | | * fire&forget a separate process to flush them. |
98 | | */ |
99 | | int fork_and_flush_stdin(int fd, struct buffer *buffer) |
100 | 0 | { |
101 | 0 | int i; |
102 | 0 | if (!buffer_len(buffer)) |
103 | 0 | return 0; |
104 | 0 | switch (fork()) { |
105 | 0 | case -1: |
106 | 0 | PERROR("fork"); |
107 | 0 | exit(1); |
108 | 0 | case 0: |
109 | 0 | break; |
110 | 0 | default: |
111 | 0 | return 1; |
112 | 0 | } |
113 | 0 | for (i = 0; i < MAX_FDS; i++) |
114 | 0 | if (i != fd && i != 2) |
115 | 0 | close(i); |
116 | 0 | set_block(fd); |
117 | 0 | write_all(fd, buffer_data(buffer), buffer_len(buffer)); |
118 | 0 | _exit(0); |
119 | 0 | } |