xref: /openbsd-src/usr.bin/rsync/session.c (revision 173dc8749401a03b492e3d8eaa9358ba3cce4e24)
1 /*	$OpenBSD: session.c,v 1.9 2021/09/02 21:06:06 deraadt Exp $ */
2 /*
3  * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 #include <assert.h>
19 #include <stdint.h>
20 #include <stdlib.h>
21 #include <unistd.h>
22 
23 #include "extern.h"
24 
25 /*
26  * Accept how much we've read, written, and file-size, and print them in
27  * a human-readable fashion (with GB, MB, etc. prefixes).
28  * This only prints as the client.
29  */
30 static void
stats_log(struct sess * sess,uint64_t tread,uint64_t twrite,uint64_t tsize)31 stats_log(struct sess *sess,
32 	uint64_t tread, uint64_t twrite, uint64_t tsize)
33 {
34 	double		 tr, tw, ts;
35 	const char	*tru = "B", *twu = "B", *tsu = "B";
36 	int		 trsz = 0, twsz = 0, tssz = 0;
37 
38 	assert(verbose);
39 	if (sess->opts->server)
40 		return;
41 
42 	if (tread >= 1024 * 1024 * 1024) {
43 		tr = tread / (1024.0 * 1024.0 * 1024.0);
44 		tru = "GB";
45 		trsz = 3;
46 	} else if (tread >= 1024 * 1024) {
47 		tr = tread / (1024.0 * 1024.0);
48 		tru = "MB";
49 		trsz = 2;
50 	} else if (tread >= 1024) {
51 		tr = tread / 1024.0;
52 		tru = "KB";
53 		trsz = 1;
54 	} else
55 		tr = tread;
56 
57 	if (twrite >= 1024 * 1024 * 1024) {
58 		tw = twrite / (1024.0 * 1024.0 * 1024.0);
59 		twu = "GB";
60 		twsz = 3;
61 	} else if (twrite >= 1024 * 1024) {
62 		tw = twrite / (1024.0 * 1024.0);
63 		twu = "MB";
64 		twsz = 2;
65 	} else if (twrite >= 1024) {
66 		tw = twrite / 1024.0;
67 		twu = "KB";
68 		twsz = 1;
69 	} else
70 		tw = twrite;
71 
72 	if (tsize >= 1024 * 1024 * 1024) {
73 		ts = tsize / (1024.0 * 1024.0 * 1024.0);
74 		tsu = "GB";
75 		tssz = 3;
76 	} else if (tsize >= 1024 * 1024) {
77 		ts = tsize / (1024.0 * 1024.0);
78 		tsu = "MB";
79 		tssz = 2;
80 	} else if (tsize >= 1024) {
81 		ts = tsize / 1024.0;
82 		tsu = "KB";
83 		tssz = 1;
84 	} else
85 		ts = tsize;
86 
87 	LOG1("Transfer complete: "
88 	    "%.*lf %s sent, %.*lf %s read, %.*lf %s file size",
89 	    trsz, tr, tru,
90 	    twsz, tw, twu,
91 	    tssz, ts, tsu);
92 }
93 
94 /*
95  * At the end of transmission, we write our statistics if we're the
96  * server, then log only if we're not the server.
97  * Either way, only do this if we're in verbose mode.
98  * Returns zero on failure, non-zero on success.
99  */
100 int
sess_stats_send(struct sess * sess,int fd)101 sess_stats_send(struct sess *sess, int fd)
102 {
103 	uint64_t tw, tr, ts;
104 
105 	if (verbose == 0)
106 		return 1;
107 
108 	tw = sess->total_write;
109 	tr = sess->total_read;
110 	ts = sess->total_size;
111 
112 	if (sess->opts->server) {
113 		if (!io_write_ulong(sess, fd, tr)) {
114 			ERRX1("io_write_ulong");
115 			return 0;
116 		} else if (!io_write_ulong(sess, fd, tw)) {
117 			ERRX1("io_write_ulong");
118 			return 0;
119 		} else if (!io_write_ulong(sess, fd, ts)) {
120 			ERRX1("io_write_ulong");
121 			return 0;
122 		}
123 	}
124 
125 	stats_log(sess, tr, tw, ts);
126 	return 1;
127 }
128 
129 /*
130  * At the end of the transmission, we have some statistics to read.
131  * Only do this (1) if we're in verbose mode and (2) if we're the
132  * server.
133  * Then log the findings.
134  * Return zero on failure, non-zero on success.
135  */
136 int
sess_stats_recv(struct sess * sess,int fd)137 sess_stats_recv(struct sess *sess, int fd)
138 {
139 	uint64_t tr, tw, ts;
140 
141 	if (sess->opts->server || verbose == 0)
142 		return 1;
143 
144 	if (!io_read_ulong(sess, fd, &tw)) {
145 		ERRX1("io_read_ulong");
146 		return 0;
147 	} else if (!io_read_ulong(sess, fd, &tr)) {
148 		ERRX1("io_read_ulong");
149 		return 0;
150 	} else if (!io_read_ulong(sess, fd, &ts)) {
151 		ERRX1("io_read_ulong");
152 		return 0;
153 	}
154 
155 	stats_log(sess, tr, tw, ts);
156 	return 1;
157 }
158