Annotation of src/usr.bin/rsync/receiver.c, Revision 1.4
1.4 ! deraadt 1: /* $Id: receiver.c,v 1.3 2019/02/10 23:43:31 benno Exp $ */
1.1 benno 2:
3: /*
4: * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
5: *
6: * Permission to use, copy, modify, and distribute this software for any
7: * purpose with or without fee is hereby granted, provided that the above
8: * copyright notice and this permission notice appear in all copies.
9: *
10: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17: */
18: #include <sys/mman.h>
19: #include <sys/stat.h>
20:
21: #include <assert.h>
22: #include <errno.h>
23: #include <fcntl.h>
24: #include <inttypes.h>
25: #include <math.h>
26: #include <poll.h>
27: #include <stdio.h>
28: #include <stdlib.h>
29: #include <string.h>
30: #include <time.h>
31: #include <unistd.h>
32:
33: #include "extern.h"
34:
35: enum pfdt {
36: PFD_SENDER_IN = 0, /* input from the sender */
37: PFD_UPLOADER_IN, /* uploader input from a local file */
38: PFD_DOWNLOADER_IN, /* downloader input from a local file */
39: PFD_SENDER_OUT, /* output to the sender */
40: PFD__MAX
41: };
42:
1.2 benno 43: /*
1.1 benno 44: * Pledges: unveil, rpath, cpath, wpath, stdio, fattr.
45: * Pledges (dry-run): -cpath, -wpath, -fattr.
46: */
47: int
48: rsync_receiver(struct sess *sess,
49: int fdin, int fdout, const char *root)
50: {
51: struct flist *fl = NULL, *dfl = NULL;
52: size_t i, flsz = 0, dflsz = 0, excl;
53: char *tofree;
54: int rc = 0, dfd = -1, phase = 0, c;
1.2 benno 55: int32_t ioerror;
1.1 benno 56: struct pollfd pfd[PFD__MAX];
57: struct download *dl = NULL;
1.2 benno 58: struct upload *ul = NULL;
1.1 benno 59: mode_t oumask;
60:
1.3 benno 61: if (-1 == pledge("stdio rpath wpath cpath fattr unveil", NULL)) {
1.1 benno 62: ERR(sess, "pledge");
63: goto out;
64: }
65:
66: /* Client sends zero-length exclusions. */
67:
1.4 ! deraadt 68: if (!sess->opts->server &&
! 69: !io_write_int(sess, fdout, 0)) {
1.1 benno 70: ERRX1(sess, "io_write_int");
71: goto out;
72: }
73:
74: if (sess->opts->server && sess->opts->del) {
1.4 ! deraadt 75: if (!io_read_size(sess, fdin, &excl)) {
1.1 benno 76: ERRX1(sess, "io_read_size");
77: goto out;
78: } else if (0 != excl) {
79: ERRX(sess, "exclusion list is non-empty");
80: goto out;
81: }
82: }
83:
84: /*
85: * Start by receiving the file list and our mystery number.
86: * These we're going to be touching on our local system.
87: */
88:
1.4 ! deraadt 89: if (!flist_recv(sess, fdin, &fl, &flsz)) {
1.1 benno 90: ERRX1(sess, "flist_recv");
91: goto out;
1.2 benno 92: }
93:
1.1 benno 94: /* The IO error is sent after the file list. */
95:
1.4 ! deraadt 96: if (!io_read_int(sess, fdin, &ioerror)) {
1.1 benno 97: ERRX1(sess, "io_read_int");
98: goto out;
99: } else if (0 != ioerror) {
100: ERRX1(sess, "io_error is non-zero");
101: goto out;
102: }
103:
1.4 ! deraadt 104: if (0 == flsz && !sess->opts->server) {
1.1 benno 105: WARNX(sess, "receiver has empty file list: exiting");
106: rc = 1;
107: goto out;
1.4 ! deraadt 108: } else if (!sess->opts->server)
1.1 benno 109: LOG1(sess, "Transfer starting: %zu files", flsz);
110:
111: LOG2(sess, "%s: receiver destination", root);
112:
113: /*
114: * Create the path for our destination directory, if we're not
115: * in dry-run mode (which would otherwise crash w/the pledge).
116: * This uses our current umask: we might set the permissions on
117: * this directory in post_dir().
118: */
119:
1.4 ! deraadt 120: if (!sess->opts->dry_run) {
1.1 benno 121: if (NULL == (tofree = strdup(root))) {
122: ERR(sess, "strdup");
123: goto out;
124: } else if (mkpath(sess, tofree) < 0) {
125: ERRX1(sess, "%s: mkpath", root);
126: free(tofree);
127: goto out;
128: }
129: free(tofree);
130: }
131:
132: /*
133: * Disable umask() so we can set permissions fully.
134: * Then open the directory iff we're not in dry_run.
135: */
136:
137: oumask = umask(0);
138:
1.4 ! deraadt 139: if (!sess->opts->dry_run) {
1.1 benno 140: dfd = open(root, O_RDONLY | O_DIRECTORY, 0);
141: if (-1 == dfd) {
142: ERR(sess, "%s: open", root);
143: goto out;
144: }
145: }
146:
147: /*
148: * Begin by conditionally getting all files we have currently
149: * available in our destination.
150: * XXX: THIS IS A BUG IN OPENBSD 6.4.
151: * For newer version of OpenBSD, this is safe to put after the
152: * unveil.
153: */
154:
1.2 benno 155: if (sess->opts->del &&
1.1 benno 156: sess->opts->recursive &&
1.4 ! deraadt 157: !flist_gen_dels(sess, root, &dfl, &dflsz, fl, flsz)) {
1.1 benno 158: ERRX1(sess, "flist_gen_local");
159: goto out;
160: }
161:
162: /*
163: * Make our entire view of the file-system be limited to what's
164: * in the root directory.
165: * This prevents us from accidentally (or "under the influence")
166: * writing into other parts of the file-system.
167: */
168:
169: if (-1 == unveil(root, "rwc")) {
170: ERR(sess, "%s: unveil", root);
171: goto out;
172: } else if (-1 == unveil(NULL, NULL)) {
173: ERR(sess, "%s: unveil", root);
174: goto out;
175: }
176:
177: /* If we have a local set, go for the deletion. */
178:
1.4 ! deraadt 179: if (!flist_del(sess, dfd, dfl, dflsz)) {
1.1 benno 180: ERRX1(sess, "flist_del");
181: goto out;
182: }
183:
184: /* Initialise poll events to listen from the sender. */
185:
186: pfd[PFD_SENDER_IN].fd = fdin;
187: pfd[PFD_UPLOADER_IN].fd = -1;
188: pfd[PFD_DOWNLOADER_IN].fd = -1;
189: pfd[PFD_SENDER_OUT].fd = fdout;
190:
191: pfd[PFD_SENDER_IN].events = POLLIN;
192: pfd[PFD_UPLOADER_IN].events = POLLIN;
193: pfd[PFD_DOWNLOADER_IN].events = POLLIN;
194: pfd[PFD_SENDER_OUT].events = POLLOUT;
195:
1.2 benno 196: ul = upload_alloc(sess, dfd, fdout,
1.1 benno 197: CSUM_LENGTH_PHASE1, fl, flsz, oumask);
198: if (NULL == ul) {
199: ERRX1(sess, "upload_alloc");
200: goto out;
201: }
202:
203: dl = download_alloc(sess, fdin, fl, flsz, dfd);
204: if (NULL == dl) {
205: ERRX1(sess, "download_alloc");
206: goto out;
207: }
208:
209: LOG2(sess, "%s: ready for phase 1 data", root);
210:
211: for (;;) {
212: if (-1 == (c = poll(pfd, PFD__MAX, INFTIM))) {
213: ERR(sess, "poll");
214: goto out;
1.2 benno 215: }
1.1 benno 216:
1.2 benno 217: for (i = 0; i < PFD__MAX; i++)
1.1 benno 218: if (pfd[i].revents & (POLLERR|POLLNVAL)) {
219: ERRX(sess, "poll: bad fd");
220: goto out;
221: } else if (pfd[i].revents & POLLHUP) {
222: ERRX(sess, "poll: hangup");
223: goto out;
224: }
225:
226: /*
227: * If we have a read event and we're multiplexing, we
228: * might just have error messages in the pipe.
229: * It's important to flush these out so that we don't
230: * clog the pipe.
231: * Unset our polling status if there's nothing that
232: * remains in the pipe.
233: */
234:
235: if (sess->mplex_reads &&
236: (POLLIN & pfd[PFD_SENDER_IN].revents)) {
1.4 ! deraadt 237: if (!io_read_flush(sess, fdin)) {
1.1 benno 238: ERRX1(sess, "io_read_flush");
239: goto out;
240: } else if (0 == sess->mplex_read_remain)
241: pfd[PFD_SENDER_IN].revents &= ~POLLIN;
242: }
243:
244:
245: /*
246: * We run the uploader if we have files left to examine
247: * (i < flsz) or if we have a file that we've opened and
248: * is read to mmap.
249: */
250:
251: if ((POLLIN & pfd[PFD_UPLOADER_IN].revents) ||
252: (POLLOUT & pfd[PFD_SENDER_OUT].revents)) {
1.2 benno 253: c = rsync_uploader(ul,
254: &pfd[PFD_UPLOADER_IN].fd,
1.1 benno 255: sess, &pfd[PFD_SENDER_OUT].fd);
256: if (c < 0) {
257: ERRX1(sess, "rsync_uploader");
258: goto out;
259: }
260: }
261:
1.2 benno 262: /*
1.1 benno 263: * We need to run the downloader when we either have
264: * read events from the sender or an asynchronous local
265: * open is ready.
266: * XXX: we don't disable PFD_SENDER_IN like with the
267: * uploader because we might stop getting error
268: * messages, which will otherwise clog up the pipes.
269: */
270:
1.2 benno 271: if ((POLLIN & pfd[PFD_SENDER_IN].revents) ||
1.1 benno 272: (POLLIN & pfd[PFD_DOWNLOADER_IN].revents)) {
1.2 benno 273: c = rsync_downloader(dl, sess,
1.1 benno 274: &pfd[PFD_DOWNLOADER_IN].fd);
275: if (c < 0) {
276: ERRX1(sess, "rsync_downloader");
277: goto out;
278: } else if (0 == c) {
279: assert(0 == phase);
280: phase++;
281: LOG2(sess, "%s: receiver ready "
282: "for phase 2 data", root);
283: break;
284: }
285:
286: /*
287: * FIXME: if we have any errors during the
288: * download, most notably files getting out of
289: * sync between the send and the receiver, then
290: * here we should bump our checksum length and
291: * go into the second phase.
292: */
1.2 benno 293: }
1.1 benno 294: }
295:
296: /* Properly close us out by progressing through the phases. */
297:
298: if (1 == phase) {
1.4 ! deraadt 299: if (!io_write_int(sess, fdout, -1)) {
1.1 benno 300: ERRX1(sess, "io_write_int");
301: goto out;
1.4 ! deraadt 302: } else if (!io_read_int(sess, fdin, &ioerror)) {
1.1 benno 303: ERRX1(sess, "io_read_int");
304: goto out;
305: } else if (-1 != ioerror) {
306: ERRX(sess, "expected phase ack");
307: goto out;
308: }
309: }
310:
311: /*
312: * Now all of our transfers are complete, so we can fix up our
313: * directory permissions.
314: */
315:
1.4 ! deraadt 316: if (!rsync_uploader_tail(ul, sess)) {
1.1 benno 317: ERRX1(sess, "rsync_uploader_tail");
318: goto out;
319: }
320:
321: /* Process server statistics and say good-bye. */
322:
1.4 ! deraadt 323: if (!sess_stats_recv(sess, fdin)) {
1.1 benno 324: ERRX1(sess, "sess_stats_recv");
325: goto out;
1.4 ! deraadt 326: } else if (!io_write_int(sess, fdout, -1)) {
1.1 benno 327: ERRX1(sess, "io_write_int");
328: goto out;
329: }
330:
331: LOG2(sess, "receiver finished updating");
332: rc = 1;
333: out:
334: if (-1 != dfd)
335: close(dfd);
336: upload_free(ul);
337: download_free(dl);
338: flist_free(fl, flsz);
339: flist_free(dfl, dflsz);
340: return rc;
341: }