summaryrefslogtreecommitdiff
path: root/progressmeter.c
diff options
context:
space:
mode:
authorschwarze@openbsd.org <schwarze@openbsd.org>2016-05-25 23:48:45 +0000
committerDarren Tucker <dtucker@zip.com.au>2016-06-06 11:27:38 +1000
commit0e059cdf5fd86297546c63fa8607c24059118832 (patch)
tree830942b6fd6f34250a42f265c1c90b9a398a6ab4 /progressmeter.c
parent8c02e3639acefe1e447e293dbe23a0917abd3734 (diff)
upstream commit
To prevent screwing up terminal settings when printing to the terminal, for ASCII and UTF-8, escape bytes not forming characters and bytes forming non-printable characters with vis(3) VIS_OCTAL. For other character sets, abort printing of the current string in these cases. In particular, * let scp(1) respect the local user's LC_CTYPE locale(1); * sanitize data received from the remote host; * sanitize filenames, usernames, and similar data even locally; * take character display widths into account for the progressmeter. This is believed to be sufficient to keep the local terminal safe on OpenBSD, but bad things can still happen on other systems with state-dependent locales because many places in the code print unencoded ASCII characters into the output stream. Using feedback from djm@ and martijn@, various aspects discussed with many others. deraadt@ says it should go in now, i probably already hesitated too long Upstream-ID: e66afbc94ee396ddcaffd433b9a3b80f387647e0
Diffstat (limited to 'progressmeter.c')
-rw-r--r--progressmeter.c51
1 files changed, 27 insertions, 24 deletions
diff --git a/progressmeter.c b/progressmeter.c
index 3a455408c..4fed2f4f0 100644
--- a/progressmeter.c
+++ b/progressmeter.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: progressmeter.c,v 1.42 2016/03/02 22:42:40 dtucker Exp $ */ 1/* $OpenBSD: progressmeter.c,v 1.43 2016/05/25 23:48:45 schwarze Exp $ */
2/* 2/*
3 * Copyright (c) 2003 Nils Nordman. All rights reserved. 3 * Copyright (c) 2003 Nils Nordman. All rights reserved.
4 * 4 *
@@ -31,6 +31,7 @@
31 31
32#include <errno.h> 32#include <errno.h>
33#include <signal.h> 33#include <signal.h>
34#include <stdarg.h>
34#include <stdio.h> 35#include <stdio.h>
35#include <string.h> 36#include <string.h>
36#include <time.h> 37#include <time.h>
@@ -39,6 +40,7 @@
39#include "progressmeter.h" 40#include "progressmeter.h"
40#include "atomicio.h" 41#include "atomicio.h"
41#include "misc.h" 42#include "misc.h"
43#include "utf8.h"
42 44
43#define DEFAULT_WINSIZE 80 45#define DEFAULT_WINSIZE 80
44#define MAX_WINSIZE 512 46#define MAX_WINSIZE 512
@@ -119,14 +121,14 @@ format_size(char *buf, int size, off_t bytes)
119void 121void
120refresh_progress_meter(void) 122refresh_progress_meter(void)
121{ 123{
122 char buf[MAX_WINSIZE + 1]; 124 char buf[MAX_WINSIZE * 4 + 1];
123 off_t transferred; 125 off_t transferred;
124 double elapsed, now; 126 double elapsed, now;
125 int percent; 127 int percent;
126 off_t bytes_left; 128 off_t bytes_left;
127 int cur_speed; 129 int cur_speed;
128 int hours, minutes, seconds; 130 int hours, minutes, seconds;
129 int i, len; 131 size_t i;
130 int file_len; 132 int file_len;
131 133
132 transferred = *counter - (cur_pos ? cur_pos : start_pos); 134 transferred = *counter - (cur_pos ? cur_pos : start_pos);
@@ -157,17 +159,16 @@ refresh_progress_meter(void)
157 bytes_per_second = cur_speed; 159 bytes_per_second = cur_speed;
158 160
159 /* filename */ 161 /* filename */
160 buf[0] = '\0'; 162 buf[0] = '\r';
163 buf[1] = '\0';
161 file_len = win_size - 35; 164 file_len = win_size - 35;
162 if (file_len > 0) { 165 if (file_len > 0) {
163 len = snprintf(buf, file_len + 1, "\r%s", file); 166 (void) snmprintf(buf + 1, sizeof(buf) - 1 - 35,
164 if (len < 0) 167 &file_len, "%s", file);
165 len = 0; 168 i = strlen(buf);
166 if (len >= file_len + 1) 169 while (++file_len < win_size - 35 && i + 1 < sizeof(buf))
167 len = file_len; 170 buf[i++] = ' ';
168 for (i = len; i < file_len; i++) 171 buf[i] = '\0';
169 buf[i] = ' ';
170 buf[file_len] = '\0';
171 } 172 }
172 173
173 /* percent of transfer done */ 174 /* percent of transfer done */
@@ -175,18 +176,18 @@ refresh_progress_meter(void)
175 percent = ((float)cur_pos / end_pos) * 100; 176 percent = ((float)cur_pos / end_pos) * 100;
176 else 177 else
177 percent = 100; 178 percent = 100;
178 snprintf(buf + strlen(buf), win_size - strlen(buf), 179 snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
179 " %3d%% ", percent); 180 " %3d%% ", percent);
180 181
181 /* amount transferred */ 182 /* amount transferred */
182 format_size(buf + strlen(buf), win_size - strlen(buf), 183 format_size(buf + strlen(buf), sizeof(buf) - strlen(buf),
183 cur_pos); 184 cur_pos);
184 strlcat(buf, " ", win_size); 185 strlcat(buf, " ", sizeof(buf));
185 186
186 /* bandwidth usage */ 187 /* bandwidth usage */
187 format_rate(buf + strlen(buf), win_size - strlen(buf), 188 format_rate(buf + strlen(buf), sizeof(buf) - strlen(buf),
188 (off_t)bytes_per_second); 189 (off_t)bytes_per_second);
189 strlcat(buf, "/s ", win_size); 190 strlcat(buf, "/s ", sizeof(buf));
190 191
191 /* ETA */ 192 /* ETA */
192 if (!transferred) 193 if (!transferred)
@@ -195,9 +196,9 @@ refresh_progress_meter(void)
195 stalled = 0; 196 stalled = 0;
196 197
197 if (stalled >= STALL_TIME) 198 if (stalled >= STALL_TIME)
198 strlcat(buf, "- stalled -", win_size); 199 strlcat(buf, "- stalled -", sizeof(buf));
199 else if (bytes_per_second == 0 && bytes_left) 200 else if (bytes_per_second == 0 && bytes_left)
200 strlcat(buf, " --:-- ETA", win_size); 201 strlcat(buf, " --:-- ETA", sizeof(buf));
201 else { 202 else {
202 if (bytes_left > 0) 203 if (bytes_left > 0)
203 seconds = bytes_left / bytes_per_second; 204 seconds = bytes_left / bytes_per_second;
@@ -210,19 +211,21 @@ refresh_progress_meter(void)
210 seconds -= minutes * 60; 211 seconds -= minutes * 60;
211 212
212 if (hours != 0) 213 if (hours != 0)
213 snprintf(buf + strlen(buf), win_size - strlen(buf), 214 snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
214 "%d:%02d:%02d", hours, minutes, seconds); 215 "%d:%02d:%02d", hours, minutes, seconds);
215 else 216 else
216 snprintf(buf + strlen(buf), win_size - strlen(buf), 217 snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
217 " %02d:%02d", minutes, seconds); 218 " %02d:%02d", minutes, seconds);
218 219
219 if (bytes_left > 0) 220 if (bytes_left > 0)
220 strlcat(buf, " ETA", win_size); 221 strlcat(buf, " ETA", sizeof(buf));
221 else 222 else
222 strlcat(buf, " ", win_size); 223 strlcat(buf, " ", sizeof(buf));
223 } 224 }
225 if (win_size < 35)
226 buf[win_size] = '\0';
224 227
225 atomicio(vwrite, STDOUT_FILENO, buf, win_size - 1); 228 atomicio(vwrite, STDOUT_FILENO, buf, strlen(buf));
226 last_update = now; 229 last_update = now;
227} 230}
228 231