"Fossies" - the Fresh Open Source Software Archive 
Member "cryptsetup-2.4.3/src/utils_tools.c" (13 Jan 2022, 12783 Bytes) of package /linux/misc/cryptsetup-2.4.3.tar.xz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "utils_tools.c" see the
Fossies "Dox" file reference documentation and the last
Fossies "Diffs" side-by-side code changes report:
2.4.1_vs_2.4.2.
1 /*
2 * cryptsetup - setup cryptographic volumes for dm-crypt
3 *
4 * Copyright (C) 2004 Jana Saout <jana@saout.de>
5 * Copyright (C) 2004-2007 Clemens Fruhwirth <clemens@endorphin.org>
6 * Copyright (C) 2009-2021 Red Hat, Inc. All rights reserved.
7 * Copyright (C) 2009-2021 Milan Broz
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version 2
12 * of the License, or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 */
23
24 #include "cryptsetup.h"
25 #include <math.h>
26 #include <signal.h>
27
28 /* interrupt handling */
29 volatile int quit = 0;
30 static int signals_blocked = 0;
31
32 static void int_handler(int sig __attribute__((__unused__)))
33 {
34 quit++;
35 }
36
37 int tools_signals_blocked(void)
38 {
39 return signals_blocked;
40 }
41
42 void set_int_block(int block)
43 {
44 sigset_t signals_open;
45
46 log_dbg("%slocking interruption on signal.", block ? "B" : "Unb");
47
48 sigemptyset(&signals_open);
49 sigaddset(&signals_open, SIGINT);
50 sigaddset(&signals_open, SIGTERM);
51 sigprocmask(block ? SIG_SETMASK : SIG_UNBLOCK, &signals_open, NULL);
52 signals_blocked = block;
53 quit = 0;
54 }
55
56 void set_int_handler(int block)
57 {
58 struct sigaction sigaction_open;
59
60 log_dbg("Installing SIGINT/SIGTERM handler.");
61 memset(&sigaction_open, 0, sizeof(struct sigaction));
62 sigaction_open.sa_handler = int_handler;
63 sigaction(SIGINT, &sigaction_open, 0);
64 sigaction(SIGTERM, &sigaction_open, 0);
65 set_int_block(block);
66 }
67
68 void check_signal(int *r)
69 {
70 if (quit && !*r)
71 *r = -EINTR;
72 }
73
74 void tool_log(int level, const char *msg, void *usrptr)
75 {
76 struct tools_log_params *params = (struct tools_log_params *)usrptr;
77
78 switch (level) {
79
80 case CRYPT_LOG_NORMAL:
81 fprintf(stdout, "%s", msg);
82 break;
83 case CRYPT_LOG_VERBOSE:
84 if (params && params->verbose)
85 fprintf(stdout, "%s", msg);
86 break;
87 case CRYPT_LOG_ERROR:
88 fprintf(stderr, "%s", msg);
89 break;
90 case CRYPT_LOG_DEBUG_JSON:
91 case CRYPT_LOG_DEBUG:
92 if (params && params->debug)
93 fprintf(stdout, "# %s", msg);
94 break;
95 }
96 }
97
98 void quiet_log(int level, const char *msg, void *usrptr)
99 {
100 struct tools_log_params *params = (struct tools_log_params *)usrptr;
101
102 if ((!params || !params->verbose) && (level == CRYPT_LOG_ERROR || level == CRYPT_LOG_NORMAL))
103 return;
104 tool_log(level, msg, usrptr);
105 }
106
107 static int _dialog(const char *msg, void *usrptr, int default_answer)
108 {
109 const char *fail_msg = (const char *)usrptr;
110 char *answer = NULL;
111 size_t size = 0;
112 int r = default_answer, block;
113
114 block = tools_signals_blocked();
115 if (block)
116 set_int_block(0);
117
118 if (isatty(STDIN_FILENO)) {
119 log_std(_("\nWARNING!\n========\n"));
120 /* TRANSLATORS: User must type "YES" (in capital letters), do not translate this word. */
121 log_std(_("%s\n\nAre you sure? (Type 'yes' in capital letters): "), msg);
122 fflush(stdout);
123 if(getline(&answer, &size, stdin) == -1) {
124 r = 0;
125 /* Aborted by signal */
126 if (!quit)
127 log_err(_("Error reading response from terminal."));
128 else
129 log_dbg("Query interrupted on signal.");
130 } else {
131 r = !strcmp(answer, "YES\n");
132 if (!r && fail_msg)
133 log_err("%s", fail_msg);
134 }
135 }
136
137 if (block && !quit)
138 set_int_block(1);
139
140 free(answer);
141 return r;
142 }
143
144 int yesDialog(const char *msg, void *usrptr)
145 {
146 return _dialog(msg, usrptr, 1);
147 }
148
149 int noDialog(const char *msg, void *usrptr)
150 {
151 return _dialog(msg, usrptr, 0);
152 }
153
154 void show_status(int errcode)
155 {
156 char *crypt_error;
157
158 if (!errcode) {
159 log_verbose(_("Command successful."));
160 return;
161 }
162
163 if (errcode < 0)
164 errcode = translate_errno(errcode);
165
166 if (errcode == 1)
167 crypt_error = _("wrong or missing parameters");
168 else if (errcode == 2)
169 crypt_error = _("no permission or bad passphrase");
170 else if (errcode == 3)
171 crypt_error = _("out of memory");
172 else if (errcode == 4)
173 crypt_error = _("wrong device or file specified");
174 else if (errcode == 5)
175 crypt_error = _("device already exists or device is busy");
176 else
177 crypt_error = _("unknown error");
178
179 log_verbose(_("Command failed with code %i (%s)."), -errcode, crypt_error);
180 }
181
182 const char *uuid_or_device(const char *spec)
183 {
184 static char device[PATH_MAX];
185 char s, *ptr;
186 int i = 0, uuid_len = 5;
187
188 /* Check if it is correct UUID=<LUKS_UUID> format */
189 if (spec && !strncmp(spec, "UUID=", uuid_len)) {
190 strcpy(device, "/dev/disk/by-uuid/");
191 ptr = &device[strlen(device)];
192 i = uuid_len;
193 while ((s = spec[i++]) && i < (PATH_MAX - 13)) {
194 if (!isxdigit(s) && s != '-')
195 return spec; /* Bail it out */
196 if (isalpha(s))
197 s = tolower(s);
198 *ptr++ = s;
199 }
200 *ptr = '\0';
201 return device;
202 }
203
204 return spec;
205 }
206
207 __attribute__ ((noreturn)) void usage(poptContext popt_context,
208 int exitcode, const char *error,
209 const char *more)
210 {
211 poptPrintUsage(popt_context, stderr, 0);
212 if (error)
213 log_err("%s: %s", more, error);
214 tools_cleanup();
215 poptFreeContext(popt_context);
216 exit(exitcode);
217 }
218
219 void dbg_version_and_cmd(int argc, const char **argv)
220 {
221 int i;
222
223 log_std("# %s %s processing \"", PACKAGE_NAME, PACKAGE_VERSION);
224 for (i = 0; i < argc; i++) {
225 if (i)
226 log_std(" ");
227 log_std("%s", argv[i]);
228 }
229 log_std("\"\n");
230 }
231
232 /* Translate exit code to simple codes */
233 int translate_errno(int r)
234 {
235 switch (r) {
236 case 0: r = EXIT_SUCCESS; break;
237 case -EEXIST:
238 case -EBUSY: r = 5; break;
239 case -ENOTBLK:
240 case -ENODEV: r = 4; break;
241 case -ENOMEM: r = 3; break;
242 case -EPERM: r = 2; break;
243 case -EINVAL:
244 case -ENOENT:
245 case -ENOSYS:
246 default: r = EXIT_FAILURE;
247 }
248 return r;
249 }
250
251 void tools_keyslot_msg(int keyslot, crypt_object_op op)
252 {
253 if (keyslot < 0)
254 return;
255
256 if (op == CREATED)
257 log_verbose(_("Key slot %i created."), keyslot);
258 else if (op == UNLOCKED)
259 log_verbose(_("Key slot %i unlocked."), keyslot);
260 else if (op == REMOVED)
261 log_verbose(_("Key slot %i removed."), keyslot);
262 }
263
264 void tools_token_msg(int token, crypt_object_op op)
265 {
266 if (token < 0)
267 return;
268
269 if (op == CREATED)
270 log_verbose(_("Token %i created."), token);
271 else if (op == REMOVED)
272 log_verbose(_("Token %i removed."), token);
273 }
274
275 void tools_token_error_msg(int error, const char *type, int token, bool pin_provided)
276 {
277 if (error >= 0)
278 return;
279
280 if (error == -ENOANO) {
281 if (pin_provided)
282 log_verbose(_("No token could be unlocked with this PIN."));
283 else if (token != CRYPT_ANY_TOKEN)
284 log_verbose(_("Token %i requires PIN."), token);
285 else if (type)
286 log_verbose(_("Token (type %s) requires PIN."), type);
287 } else if (error == -EPERM) {
288 if (token != CRYPT_ANY_TOKEN)
289 log_verbose(_("Token %i cannot unlock assigned keyslot(s) (wrong keyslot passphrase)."), token);
290 else if (type)
291 log_verbose(_("Token (type %s) cannot unlock assigned keyslot(s) (wrong keyslot passphrase)."), type);
292 } if (error == -EAGAIN) {
293 if (token != CRYPT_ANY_TOKEN)
294 log_verbose(_("Token %i requires additional missing resource."), token);
295 else if (type)
296 log_verbose(_("Token (type %s) requires additional missing resource."), type);
297 } if (error == -ENOENT) {
298 if (type)
299 log_verbose(_("No usable token (type %s) is available."), type);
300 else
301 log_verbose(_("No usable token is available."));
302 }
303 }
304
305 /*
306 * Device size string parsing, suffixes:
307 * s|S - 512 bytes sectors
308 * k |K |m |M |g |G |t |T - 1024 base
309 * kiB|KiB|miB|MiB|giB|GiB|tiB|TiB - 1024 base
310 * kb |KB |mM |MB |gB |GB |tB |TB - 1000 base
311 */
312 int tools_string_to_size(const char *s, uint64_t *size)
313 {
314 char *endp = NULL;
315 size_t len;
316 uint64_t mult_base, mult, tmp;
317
318 *size = strtoull(s, &endp, 10);
319 if (!isdigit(s[0]) ||
320 (errno == ERANGE && *size == ULLONG_MAX) ||
321 (errno != 0 && *size == 0))
322 return -EINVAL;
323
324 if (!endp || !*endp)
325 return 0;
326
327 len = strlen(endp);
328 /* Allow "B" and "iB" suffixes */
329 if (len > 3 ||
330 (len == 3 && (endp[1] != 'i' || endp[2] != 'B')) ||
331 (len == 2 && endp[1] != 'B'))
332 return -EINVAL;
333
334 if (len == 1 || len == 3)
335 mult_base = 1024;
336 else
337 mult_base = 1000;
338
339 mult = 1;
340 switch (endp[0]) {
341 case 's':
342 case 'S': mult = 512;
343 break;
344 case 't':
345 case 'T': mult *= mult_base;
346 /* Fall through */
347 case 'g':
348 case 'G': mult *= mult_base;
349 /* Fall through */
350 case 'm':
351 case 'M': mult *= mult_base;
352 /* Fall through */
353 case 'k':
354 case 'K': mult *= mult_base;
355 break;
356 default:
357 return -EINVAL;
358 }
359
360 tmp = *size * mult;
361 if (*size && (tmp / *size) != mult) {
362 log_dbg("Device size overflow.");
363 return -EINVAL;
364 }
365
366 *size = tmp;
367 return 0;
368 }
369
370 /* Time progress helper */
371
372 /* The difference in seconds between two times in "timeval" format. */
373 static double time_diff(struct timeval *start, struct timeval *end)
374 {
375 return (end->tv_sec - start->tv_sec)
376 + (end->tv_usec - start->tv_usec) / 1E6;
377 }
378
379 static void tools_clear_line(void)
380 {
381 /* vt100 code clear line */
382 log_std("\33[2K\r");
383 }
384
385 static void tools_time_progress(uint64_t device_size, uint64_t bytes, struct tools_progress_params *parms)
386 {
387 struct timeval now_time;
388 unsigned long long mbytes, eta;
389 double tdiff, uib, frequency;
390 int final = (bytes == device_size);
391 const char *eol, *ustr = "";
392
393 gettimeofday(&now_time, NULL);
394 if (parms->start_time.tv_sec == 0 && parms->start_time.tv_usec == 0) {
395 parms->start_time = now_time;
396 parms->end_time = now_time;
397 parms->start_offset = bytes;
398 return;
399 }
400
401 if (parms->frequency) {
402 frequency = (double)parms->frequency;
403 eol = "\n";
404 } else {
405 frequency = 0.5;
406 eol = "";
407 }
408
409 if (!final && time_diff(&parms->end_time, &now_time) < frequency)
410 return;
411
412 parms->end_time = now_time;
413
414 tdiff = time_diff(&parms->start_time, &parms->end_time);
415 if (!tdiff)
416 return;
417
418 mbytes = bytes / 1024 / 1024;
419 uib = (double)(bytes - parms->start_offset) / tdiff;
420
421 eta = (unsigned long long)(device_size / uib - tdiff);
422
423 if (uib > 1073741824.0f) {
424 uib /= 1073741824.0f;
425 ustr = "Gi";
426 } else if (uib > 1048576.0f) {
427 uib /= 1048576.0f;
428 ustr = "Mi";
429 } else if (uib > 1024.0f) {
430 uib /= 1024.0f;
431 ustr = "Ki";
432 }
433
434 if (!parms->frequency)
435 tools_clear_line();
436 if (final)
437 log_std("Finished, time %02llu:%02llu.%03llu, "
438 "%4llu MiB written, speed %5.1f %sB/s\n",
439 (unsigned long long)tdiff / 60,
440 (unsigned long long)tdiff % 60,
441 (unsigned long long)((tdiff - floor(tdiff)) * 1000.0),
442 mbytes, uib, ustr);
443 else
444 log_std("Progress: %5.1f%%, ETA %02llu:%02llu, "
445 "%4llu MiB written, speed %5.1f %sB/s%s",
446 (double)bytes / device_size * 100,
447 eta / 60, eta % 60, mbytes, uib, ustr, eol);
448 fflush(stdout);
449 }
450
451 int tools_wipe_progress(uint64_t size, uint64_t offset, void *usrptr)
452 {
453 int r = 0;
454 struct tools_progress_params *parms = (struct tools_progress_params *)usrptr;
455
456 if (parms && !parms->batch_mode)
457 tools_time_progress(size, offset, parms);
458
459 check_signal(&r);
460 if (r) {
461 if (!parms || !parms->frequency)
462 tools_clear_line();
463 log_err(_("\nWipe interrupted."));
464 }
465
466 return r;
467 }
468
469 /*
470 * Keyfile - is standard input treated as a binary file (no EOL handling).
471 */
472 int tools_is_stdin(const char *key_file)
473 {
474 if (!key_file)
475 return 1;
476
477 return strcmp(key_file, "-") ? 0 : 1;
478 }
479
480 int tools_reencrypt_progress(uint64_t size, uint64_t offset, void *usrptr)
481 {
482 int r = 0;
483 struct tools_progress_params *parms = (struct tools_progress_params *)usrptr;
484
485 if (parms && !parms->batch_mode)
486 tools_time_progress(size, offset, parms);
487
488 check_signal(&r);
489 if (r) {
490 if (!parms || !parms->frequency)
491 tools_clear_line();
492 log_err(_("\nReencryption interrupted."));
493 }
494
495 return r;
496 }
497
498 int tools_read_mk(const char *file, char **key, int keysize)
499 {
500 int fd = -1, r = -EINVAL;
501
502 if (keysize <= 0 || !key)
503 return -EINVAL;
504
505 *key = crypt_safe_alloc(keysize);
506 if (!*key)
507 return -ENOMEM;
508
509 fd = open(file, O_RDONLY);
510 if (fd == -1) {
511 log_err(_("Cannot read keyfile %s."), file);
512 goto out;
513 }
514
515 if (read_buffer(fd, *key, keysize) != keysize) {
516 log_err(_("Cannot read %d bytes from keyfile %s."), keysize, file);
517 goto out;
518 }
519 r = 0;
520 out:
521 if (fd != -1)
522 close(fd);
523
524 if (r) {
525 crypt_safe_free(*key);
526 *key = NULL;
527 }
528
529 return r;
530 }
531
532 int tools_write_mk(const char *file, const char *key, int keysize)
533 {
534 int fd, r = -EINVAL;
535
536 if (keysize <= 0 || !key)
537 return -EINVAL;
538
539 fd = open(file, O_CREAT|O_EXCL|O_WRONLY, S_IRUSR);
540 if (fd < 0) {
541 log_err(_("Cannot open keyfile %s for write."), file);
542 return r;
543 }
544
545 if (write_buffer(fd, key, keysize) == keysize)
546 r = 0;
547 else
548 log_err(_("Cannot write to keyfile %s."), file);
549
550 close(fd);
551 return r;
552 }