message.c revision 207753
1/////////////////////////////////////////////////////////////////////////////// 2// 3/// \file message.c 4/// \brief Printing messages 5// 6// Author: Lasse Collin 7// 8// This file has been put into the public domain. 9// You can do whatever you want with this file. 10// 11/////////////////////////////////////////////////////////////////////////////// 12 13#include "private.h" 14 15#ifdef HAVE_SYS_TIME_H 16# include <sys/time.h> 17#endif 18 19#include <stdarg.h> 20 21 22/// Number of the current file 23static unsigned int files_pos = 0; 24 25/// Total number of input files; zero if unknown. 26static unsigned int files_total; 27 28/// Verbosity level 29static enum message_verbosity verbosity = V_WARNING; 30 31/// Filename which we will print with the verbose messages 32static const char *filename; 33 34/// True once the a filename has been printed to stderr as part of progress 35/// message. If automatic progress updating isn't enabled, this becomes true 36/// after the first progress message has been printed due to user sending 37/// SIGINFO, SIGUSR1, or SIGALRM. Once this variable is true, we will print 38/// an empty line before the next filename to make the output more readable. 39static bool first_filename_printed = false; 40 41/// This is set to true when we have printed the current filename to stderr 42/// as part of a progress message. This variable is useful only if not 43/// updating progress automatically: if user sends many SIGINFO, SIGUSR1, or 44/// SIGALRM signals, we won't print the name of the same file multiple times. 45static bool current_filename_printed = false; 46 47/// True if we should print progress indicator and update it automatically 48/// if also verbose >= V_VERBOSE. 49static bool progress_automatic; 50 51/// True if message_progress_start() has been called but 52/// message_progress_end() hasn't been called yet. 53static bool progress_started = false; 54 55/// This is true when a progress message was printed and the cursor is still 56/// on the same line with the progress message. In that case, a newline has 57/// to be printed before any error messages. 58static bool progress_active = false; 59 60/// Pointer to lzma_stream used to do the encoding or decoding. 61static lzma_stream *progress_strm; 62 63/// Expected size of the input stream is needed to show completion percentage 64/// and estimate remaining time. 65static uint64_t expected_in_size; 66 67/// Time when we started processing the file 68static uint64_t start_time; 69 70 71// Use alarm() and SIGALRM when they are supported. This has two minor 72// advantages over the alternative of polling gettimeofday(): 73// - It is possible for the user to send SIGINFO, SIGUSR1, or SIGALRM to 74// get intermediate progress information even when --verbose wasn't used 75// or stderr is not a terminal. 76// - alarm() + SIGALRM seems to have slightly less overhead than polling 77// gettimeofday(). 78#ifdef SIGALRM 79 80/// The signal handler for SIGALRM sets this to true. It is set back to false 81/// once the progress message has been updated. 82static volatile sig_atomic_t progress_needs_updating = false; 83 84/// Signal handler for SIGALRM 85static void 86progress_signal_handler(int sig lzma_attribute((unused))) 87{ 88 progress_needs_updating = true; 89 return; 90} 91 92#else 93 94/// This is true when progress message printing is wanted. Using the same 95/// variable name as above to avoid some ifdefs. 96static bool progress_needs_updating = false; 97 98/// Elapsed time when the next progress message update should be done. 99static uint64_t progress_next_update; 100 101#endif 102 103 104/// Get the current time as microseconds since epoch 105static uint64_t 106my_time(void) 107{ 108 struct timeval tv; 109 gettimeofday(&tv, NULL); 110 return (uint64_t)(tv.tv_sec) * UINT64_C(1000000) + tv.tv_usec; 111} 112 113 114extern void 115message_init(void) 116{ 117 // If --verbose is used, we use a progress indicator if and only 118 // if stderr is a terminal. If stderr is not a terminal, we print 119 // verbose information only after finishing the file. As a special 120 // exception, even if --verbose was not used, user can send SIGALRM 121 // to make us print progress information once without automatic 122 // updating. 123 progress_automatic = isatty(STDERR_FILENO); 124 125 // Commented out because COLUMNS is rarely exported to environment. 126 // Most users have at least 80 columns anyway, let's think something 127 // fancy here if enough people complain. 128/* 129 if (progress_automatic) { 130 // stderr is a terminal. Check the COLUMNS environment 131 // variable to see if the terminal is wide enough. If COLUMNS 132 // doesn't exist or it has some unparsable value, we assume 133 // that the terminal is wide enough. 134 const char *columns_str = getenv("COLUMNS"); 135 if (columns_str != NULL) { 136 char *endptr; 137 const long columns = strtol(columns_str, &endptr, 10); 138 if (*endptr != '\0' || columns < 80) 139 progress_automatic = false; 140 } 141 } 142*/ 143 144#ifdef SIGALRM 145 // At least DJGPP lacks SA_RESTART. It's not essential for us (the 146 // rest of the code can handle interrupted system calls), so just 147 // define it zero. 148# ifndef SA_RESTART 149# define SA_RESTART 0 150# endif 151 // Establish the signal handlers which set a flag to tell us that 152 // progress info should be updated. Since these signals don't 153 // require any quick action, we set SA_RESTART. 154 static const int sigs[] = { 155#ifdef SIGALRM 156 SIGALRM, 157#endif 158#ifdef SIGINFO 159 SIGINFO, 160#endif 161#ifdef SIGUSR1 162 SIGUSR1, 163#endif 164 }; 165 166 struct sigaction sa; 167 sigemptyset(&sa.sa_mask); 168 sa.sa_flags = SA_RESTART; 169 sa.sa_handler = &progress_signal_handler; 170 171 for (size_t i = 0; i < ARRAY_SIZE(sigs); ++i) 172 if (sigaction(sigs[i], &sa, NULL)) 173 message_signal_handler(); 174#endif 175 176 return; 177} 178 179 180extern void 181message_verbosity_increase(void) 182{ 183 if (verbosity < V_DEBUG) 184 ++verbosity; 185 186 return; 187} 188 189 190extern void 191message_verbosity_decrease(void) 192{ 193 if (verbosity > V_SILENT) 194 --verbosity; 195 196 return; 197} 198 199 200extern enum message_verbosity 201message_verbosity_get(void) 202{ 203 return verbosity; 204} 205 206 207extern void 208message_set_files(unsigned int files) 209{ 210 files_total = files; 211 return; 212} 213 214 215/// Prints the name of the current file if it hasn't been printed already, 216/// except if we are processing exactly one stream from stdin to stdout. 217/// I think it looks nicer to not print "(stdin)" when --verbose is used 218/// in a pipe and no other files are processed. 219static void 220print_filename(void) 221{ 222 if (files_total != 1 || filename != stdin_filename) { 223 signals_block(); 224 225 FILE *file = opt_mode == MODE_LIST ? stdout : stderr; 226 227 // If a file was already processed, put an empty line 228 // before the next filename to improve readability. 229 if (first_filename_printed) 230 fputc('\n', file); 231 232 first_filename_printed = true; 233 current_filename_printed = true; 234 235 // If we don't know how many files there will be due 236 // to usage of --files or --files0. 237 if (files_total == 0) 238 fprintf(file, "%s (%u)\n", filename, 239 files_pos); 240 else 241 fprintf(file, "%s (%u/%u)\n", filename, 242 files_pos, files_total); 243 244 signals_unblock(); 245 } 246 247 return; 248} 249 250 251extern void 252message_filename(const char *src_name) 253{ 254 // Start numbering the files starting from one. 255 ++files_pos; 256 filename = src_name; 257 258 if (verbosity >= V_VERBOSE 259 && (progress_automatic || opt_mode == MODE_LIST)) 260 print_filename(); 261 else 262 current_filename_printed = false; 263 264 return; 265} 266 267 268extern void 269message_progress_start(lzma_stream *strm, uint64_t in_size) 270{ 271 // Store the pointer to the lzma_stream used to do the coding. 272 // It is needed to find out the position in the stream. 273 progress_strm = strm; 274 275 // Store the processing start time of the file and its expected size. 276 // If we aren't printing any statistics, then these are unused. But 277 // since it is possible that the user sends us a signal to show 278 // statistics, we need to have these available anyway. 279 start_time = my_time(); 280 expected_in_size = in_size; 281 282 // Indicate that progress info may need to be printed before 283 // printing error messages. 284 progress_started = true; 285 286 // If progress indicator is wanted, print the filename and possibly 287 // the file count now. 288 if (verbosity >= V_VERBOSE && progress_automatic) { 289 // Start the timer to display the first progress message 290 // after one second. An alternative would be to show the 291 // first message almost immediately, but delaying by one 292 // second looks better to me, since extremely early 293 // progress info is pretty much useless. 294#ifdef SIGALRM 295 // First disable a possibly existing alarm. 296 alarm(0); 297 progress_needs_updating = false; 298 alarm(1); 299#else 300 progress_needs_updating = true; 301 progress_next_update = 1000000; 302#endif 303 } 304 305 return; 306} 307 308 309/// Make the string indicating completion percentage. 310static const char * 311progress_percentage(uint64_t in_pos) 312{ 313 // If the size of the input file is unknown or the size told us is 314 // clearly wrong since we have processed more data than the alleged 315 // size of the file, show a static string indicating that we have 316 // no idea of the completion percentage. 317 if (expected_in_size == 0 || in_pos > expected_in_size) 318 return "--- %"; 319 320 // Never show 100.0 % before we actually are finished. 321 double percentage = (double)(in_pos) / (double)(expected_in_size) 322 * 99.9; 323 324 static char buf[sizeof("99.9 %")]; 325 snprintf(buf, sizeof(buf), "%.1f %%", percentage); 326 327 return buf; 328} 329 330 331/// Make the string containing the amount of input processed, amount of 332/// output produced, and the compression ratio. 333static const char * 334progress_sizes(uint64_t compressed_pos, uint64_t uncompressed_pos, bool final) 335{ 336 // This is enough to hold sizes up to about 99 TiB if thousand 337 // separator is used, or about 1 PiB without thousand separator. 338 // After that the progress indicator will look a bit silly, since 339 // the compression ratio no longer fits with three decimal places. 340 static char buf[36]; 341 342 char *pos = buf; 343 size_t left = sizeof(buf); 344 345 // Print the sizes. If this the final message, use more reasonable 346 // units than MiB if the file was small. 347 const enum nicestr_unit unit_min = final ? NICESTR_B : NICESTR_MIB; 348 my_snprintf(&pos, &left, "%s / %s", 349 uint64_to_nicestr(compressed_pos, 350 unit_min, NICESTR_TIB, false, 0), 351 uint64_to_nicestr(uncompressed_pos, 352 unit_min, NICESTR_TIB, false, 1)); 353 354 // Avoid division by zero. If we cannot calculate the ratio, set 355 // it to some nice number greater than 10.0 so that it gets caught 356 // in the next if-clause. 357 const double ratio = uncompressed_pos > 0 358 ? (double)(compressed_pos) / (double)(uncompressed_pos) 359 : 16.0; 360 361 // If the ratio is very bad, just indicate that it is greater than 362 // 9.999. This way the length of the ratio field stays fixed. 363 if (ratio > 9.999) 364 snprintf(pos, left, " > %.3f", 9.999); 365 else 366 snprintf(pos, left, " = %.3f", ratio); 367 368 return buf; 369} 370 371 372/// Make the string containing the processing speed of uncompressed data. 373static const char * 374progress_speed(uint64_t uncompressed_pos, uint64_t elapsed) 375{ 376 // Don't print the speed immediately, since the early values look 377 // somewhat random. 378 if (elapsed < 3000000) 379 return ""; 380 381 static const char unit[][8] = { 382 "KiB/s", 383 "MiB/s", 384 "GiB/s", 385 }; 386 387 size_t unit_index = 0; 388 389 // Calculate the speed as KiB/s. 390 double speed = (double)(uncompressed_pos) 391 / ((double)(elapsed) * (1024.0 / 1e6)); 392 393 // Adjust the unit of the speed if needed. 394 while (speed > 999.0) { 395 speed /= 1024.0; 396 if (++unit_index == ARRAY_SIZE(unit)) 397 return ""; // Way too fast ;-) 398 } 399 400 // Use decimal point only if the number is small. Examples: 401 // - 0.1 KiB/s 402 // - 9.9 KiB/s 403 // - 99 KiB/s 404 // - 999 KiB/s 405 static char buf[sizeof("999 GiB/s")]; 406 snprintf(buf, sizeof(buf), "%.*f %s", 407 speed > 9.9 ? 0 : 1, speed, unit[unit_index]); 408 return buf; 409} 410 411 412/// Make a string indicating elapsed or remaining time. The format is either 413/// M:SS or H:MM:SS depending on if the time is an hour or more. 414static const char * 415progress_time(uint64_t useconds) 416{ 417 // 9999 hours = 416 days 418 static char buf[sizeof("9999:59:59")]; 419 420 uint32_t seconds = useconds / 1000000; 421 422 // Don't show anything if the time is zero or ridiculously big. 423 if (seconds == 0 || seconds > ((9999 * 60) + 59) * 60 + 59) 424 return ""; 425 426 uint32_t minutes = seconds / 60; 427 seconds %= 60; 428 429 if (minutes >= 60) { 430 const uint32_t hours = minutes / 60; 431 minutes %= 60; 432 snprintf(buf, sizeof(buf), 433 "%" PRIu32 ":%02" PRIu32 ":%02" PRIu32, 434 hours, minutes, seconds); 435 } else { 436 snprintf(buf, sizeof(buf), "%" PRIu32 ":%02" PRIu32, 437 minutes, seconds); 438 } 439 440 return buf; 441} 442 443 444/// Return a string containing estimated remaining time when 445/// reasonably possible. 446static const char * 447progress_remaining(uint64_t in_pos, uint64_t elapsed) 448{ 449 // Don't show the estimated remaining time when it wouldn't 450 // make sense: 451 // - Input size is unknown. 452 // - Input has grown bigger since we started (de)compressing. 453 // - We haven't processed much data yet, so estimate would be 454 // too inaccurate. 455 // - Only a few seconds has passed since we started (de)compressing, 456 // so estimate would be too inaccurate. 457 if (expected_in_size == 0 || in_pos > expected_in_size 458 || in_pos < (UINT64_C(1) << 19) || elapsed < 8000000) 459 return ""; 460 461 // Calculate the estimate. Don't give an estimate of zero seconds, 462 // since it is possible that all the input has been already passed 463 // to the library, but there is still quite a bit of output pending. 464 uint32_t remaining = (double)(expected_in_size - in_pos) 465 * ((double)(elapsed) / 1e6) / (double)(in_pos); 466 if (remaining < 1) 467 remaining = 1; 468 469 static char buf[sizeof("9 h 55 min")]; 470 471 // Select appropriate precision for the estimated remaining time. 472 if (remaining <= 10) { 473 // A maximum of 10 seconds remaining. 474 // Show the number of seconds as is. 475 snprintf(buf, sizeof(buf), "%" PRIu32 " s", remaining); 476 477 } else if (remaining <= 50) { 478 // A maximum of 50 seconds remaining. 479 // Round up to the next multiple of five seconds. 480 remaining = (remaining + 4) / 5 * 5; 481 snprintf(buf, sizeof(buf), "%" PRIu32 " s", remaining); 482 483 } else if (remaining <= 590) { 484 // A maximum of 9 minutes and 50 seconds remaining. 485 // Round up to the next multiple of ten seconds. 486 remaining = (remaining + 9) / 10 * 10; 487 snprintf(buf, sizeof(buf), "%" PRIu32 " min %" PRIu32 " s", 488 remaining / 60, remaining % 60); 489 490 } else if (remaining <= 59 * 60) { 491 // A maximum of 59 minutes remaining. 492 // Round up to the next multiple of a minute. 493 remaining = (remaining + 59) / 60; 494 snprintf(buf, sizeof(buf), "%" PRIu32 " min", remaining); 495 496 } else if (remaining <= 9 * 3600 + 50 * 60) { 497 // A maximum of 9 hours and 50 minutes left. 498 // Round up to the next multiple of ten minutes. 499 remaining = (remaining + 599) / 600 * 10; 500 snprintf(buf, sizeof(buf), "%" PRIu32 " h %" PRIu32 " min", 501 remaining / 60, remaining % 60); 502 503 } else if (remaining <= 23 * 3600) { 504 // A maximum of 23 hours remaining. 505 // Round up to the next multiple of an hour. 506 remaining = (remaining + 3599) / 3600; 507 snprintf(buf, sizeof(buf), "%" PRIu32 " h", remaining); 508 509 } else if (remaining <= 9 * 24 * 3600 + 23 * 3600) { 510 // A maximum of 9 days and 23 hours remaining. 511 // Round up to the next multiple of an hour. 512 remaining = (remaining + 3599) / 3600; 513 snprintf(buf, sizeof(buf), "%" PRIu32 " d %" PRIu32 " h", 514 remaining / 24, remaining % 24); 515 516 } else if (remaining <= 999 * 24 * 3600) { 517 // A maximum of 999 days remaining. ;-) 518 // Round up to the next multiple of a day. 519 remaining = (remaining + 24 * 3600 - 1) / (24 * 3600); 520 snprintf(buf, sizeof(buf), "%" PRIu32 " d", remaining); 521 522 } else { 523 // The estimated remaining time is too big. Don't show it. 524 return ""; 525 } 526 527 return buf; 528} 529 530 531/// Calculate the elapsed time as microseconds. 532static uint64_t 533progress_elapsed(void) 534{ 535 return my_time() - start_time; 536} 537 538 539/// Get information about position in the stream. This is currently simple, 540/// but it will become more complicated once we have multithreading support. 541static void 542progress_pos(uint64_t *in_pos, 543 uint64_t *compressed_pos, uint64_t *uncompressed_pos) 544{ 545 *in_pos = progress_strm->total_in; 546 547 if (opt_mode == MODE_COMPRESS) { 548 *compressed_pos = progress_strm->total_out; 549 *uncompressed_pos = progress_strm->total_in; 550 } else { 551 *compressed_pos = progress_strm->total_in; 552 *uncompressed_pos = progress_strm->total_out; 553 } 554 555 return; 556} 557 558 559extern void 560message_progress_update(void) 561{ 562 if (!progress_needs_updating) 563 return; 564 565 // Calculate how long we have been processing this file. 566 const uint64_t elapsed = progress_elapsed(); 567 568#ifndef SIGALRM 569 if (progress_next_update > elapsed) 570 return; 571 572 progress_next_update = elapsed + 1000000; 573#endif 574 575 // Get our current position in the stream. 576 uint64_t in_pos; 577 uint64_t compressed_pos; 578 uint64_t uncompressed_pos; 579 progress_pos(&in_pos, &compressed_pos, &uncompressed_pos); 580 581 // Block signals so that fprintf() doesn't get interrupted. 582 signals_block(); 583 584 // Print the filename if it hasn't been printed yet. 585 if (!current_filename_printed) 586 print_filename(); 587 588 // Print the actual progress message. The idea is that there is at 589 // least three spaces between the fields in typical situations, but 590 // even in rare situations there is at least one space. 591 fprintf(stderr, "\r %6s %35s %9s %10s %10s\r", 592 progress_percentage(in_pos), 593 progress_sizes(compressed_pos, uncompressed_pos, false), 594 progress_speed(uncompressed_pos, elapsed), 595 progress_time(elapsed), 596 progress_remaining(in_pos, elapsed)); 597 598#ifdef SIGALRM 599 // Updating the progress info was finished. Reset 600 // progress_needs_updating to wait for the next SIGALRM. 601 // 602 // NOTE: This has to be done before alarm(1) or with (very) bad 603 // luck we could be setting this to false after the alarm has already 604 // been triggered. 605 progress_needs_updating = false; 606 607 if (verbosity >= V_VERBOSE && progress_automatic) { 608 // Mark that the progress indicator is active, so if an error 609 // occurs, the error message gets printed cleanly. 610 progress_active = true; 611 612 // Restart the timer so that progress_needs_updating gets 613 // set to true after about one second. 614 alarm(1); 615 } else { 616 // The progress message was printed because user had sent us 617 // SIGALRM. In this case, each progress message is printed 618 // on its own line. 619 fputc('\n', stderr); 620 } 621#else 622 // When SIGALRM isn't supported and we get here, it's always due to 623 // automatic progress update. We set progress_active here too like 624 // described above. 625 assert(verbosity >= V_VERBOSE); 626 assert(progress_automatic); 627 progress_active = true; 628#endif 629 630 signals_unblock(); 631 632 return; 633} 634 635 636static void 637progress_flush(bool finished) 638{ 639 if (!progress_started || verbosity < V_VERBOSE) 640 return; 641 642 uint64_t in_pos; 643 uint64_t compressed_pos; 644 uint64_t uncompressed_pos; 645 progress_pos(&in_pos, &compressed_pos, &uncompressed_pos); 646 647 // Avoid printing intermediate progress info if some error occurs 648 // in the beginning of the stream. (If something goes wrong later in 649 // the stream, it is sometimes useful to tell the user where the 650 // error approximately occurred, especially if the error occurs 651 // after a time-consuming operation.) 652 if (!finished && !progress_active 653 && (compressed_pos == 0 || uncompressed_pos == 0)) 654 return; 655 656 progress_active = false; 657 658 const uint64_t elapsed = progress_elapsed(); 659 660 signals_block(); 661 662 // When using the auto-updating progress indicator, the final 663 // statistics are printed in the same format as the progress 664 // indicator itself. 665 if (progress_automatic) { 666 fprintf(stderr, "\r %6s %35s %9s %10s %10s\n", 667 finished ? "100 %" : progress_percentage(in_pos), 668 progress_sizes(compressed_pos, uncompressed_pos, true), 669 progress_speed(uncompressed_pos, elapsed), 670 progress_time(elapsed), 671 finished ? "" : progress_remaining(in_pos, elapsed)); 672 } else { 673 // The filename is always printed. 674 fprintf(stderr, "%s: ", filename); 675 676 // Percentage is printed only if we didn't finish yet. 677 if (!finished) { 678 // Don't print the percentage when it isn't known 679 // (starts with a dash). 680 const char *percentage = progress_percentage(in_pos); 681 if (percentage[0] != '-') 682 fprintf(stderr, "%s, ", percentage); 683 } 684 685 // Size information is always printed. 686 fprintf(stderr, "%s", progress_sizes( 687 compressed_pos, uncompressed_pos, true)); 688 689 // The speed and elapsed time aren't always shown. 690 const char *speed = progress_speed(uncompressed_pos, elapsed); 691 if (speed[0] != '\0') 692 fprintf(stderr, ", %s", speed); 693 694 const char *elapsed_str = progress_time(elapsed); 695 if (elapsed_str[0] != '\0') 696 fprintf(stderr, ", %s", elapsed_str); 697 698 fputc('\n', stderr); 699 } 700 701 signals_unblock(); 702 703 return; 704} 705 706 707extern void 708message_progress_end(bool success) 709{ 710 assert(progress_started); 711 progress_flush(success); 712 progress_started = false; 713 return; 714} 715 716 717static void 718vmessage(enum message_verbosity v, const char *fmt, va_list ap) 719{ 720 if (v <= verbosity) { 721 signals_block(); 722 723 progress_flush(false); 724 725 fprintf(stderr, "%s: ", progname); 726 vfprintf(stderr, fmt, ap); 727 fputc('\n', stderr); 728 729 signals_unblock(); 730 } 731 732 return; 733} 734 735 736extern void 737message(enum message_verbosity v, const char *fmt, ...) 738{ 739 va_list ap; 740 va_start(ap, fmt); 741 vmessage(v, fmt, ap); 742 va_end(ap); 743 return; 744} 745 746 747extern void 748message_warning(const char *fmt, ...) 749{ 750 va_list ap; 751 va_start(ap, fmt); 752 vmessage(V_WARNING, fmt, ap); 753 va_end(ap); 754 755 set_exit_status(E_WARNING); 756 return; 757} 758 759 760extern void 761message_error(const char *fmt, ...) 762{ 763 va_list ap; 764 va_start(ap, fmt); 765 vmessage(V_ERROR, fmt, ap); 766 va_end(ap); 767 768 set_exit_status(E_ERROR); 769 return; 770} 771 772 773extern void 774message_fatal(const char *fmt, ...) 775{ 776 va_list ap; 777 va_start(ap, fmt); 778 vmessage(V_ERROR, fmt, ap); 779 va_end(ap); 780 781 tuklib_exit(E_ERROR, E_ERROR, false); 782} 783 784 785extern void 786message_bug(void) 787{ 788 message_fatal(_("Internal error (bug)")); 789} 790 791 792extern void 793message_signal_handler(void) 794{ 795 message_fatal(_("Cannot establish signal handlers")); 796} 797 798 799extern const char * 800message_strm(lzma_ret code) 801{ 802 switch (code) { 803 case LZMA_NO_CHECK: 804 return _("No integrity check; not verifying file integrity"); 805 806 case LZMA_UNSUPPORTED_CHECK: 807 return _("Unsupported type of integrity check; " 808 "not verifying file integrity"); 809 810 case LZMA_MEM_ERROR: 811 return strerror(ENOMEM); 812 813 case LZMA_MEMLIMIT_ERROR: 814 return _("Memory usage limit reached"); 815 816 case LZMA_FORMAT_ERROR: 817 return _("File format not recognized"); 818 819 case LZMA_OPTIONS_ERROR: 820 return _("Unsupported options"); 821 822 case LZMA_DATA_ERROR: 823 return _("Compressed data is corrupt"); 824 825 case LZMA_BUF_ERROR: 826 return _("Unexpected end of input"); 827 828 case LZMA_OK: 829 case LZMA_STREAM_END: 830 case LZMA_GET_CHECK: 831 case LZMA_PROG_ERROR: 832 return _("Internal error (bug)"); 833 } 834 835 return NULL; 836} 837 838 839extern void 840message_mem_needed(enum message_verbosity v, uint64_t memusage) 841{ 842 if (v > verbosity) 843 return; 844 845 // Convert memusage to MiB, rounding up to the next full MiB. 846 // This way the user can always use the displayed usage as 847 // the new memory usage limit. (If we rounded to the nearest, 848 // the user might need to +1 MiB to get high enough limit.) 849 memusage = round_up_to_mib(memusage); 850 851 // 2^64 with thousand separators + " MiB" suffix + '\0' = 26 + 4 + 1 852 char memlimitstr[32]; 853 854 // Show the memory usage limit as MiB unless it is less than 1 MiB. 855 // This way it's easy to notice errors where one has typed 856 // --memory=123 instead of --memory=123MiB. 857 uint64_t memlimit = hardware_memlimit_get(); 858 if (memlimit < (UINT32_C(1) << 20)) { 859 snprintf(memlimitstr, sizeof(memlimitstr), "%s B", 860 uint64_to_str(memlimit, 1)); 861 } else { 862 // Round up just like with memusage. If this function is 863 // called for informational purposes (to just show the 864 // current usage and limit), we should never show that 865 // the usage is higher than the limit, which would give 866 // a false impression that the memory usage limit isn't 867 // properly enforced. 868 snprintf(memlimitstr, sizeof(memlimitstr), "%s MiB", 869 uint64_to_str(round_up_to_mib(memlimit), 1)); 870 } 871 872 message(v, _("%s MiB of memory is required. The limit is %s."), 873 uint64_to_str(memusage, 0), memlimitstr); 874 875 return; 876} 877 878 879extern void 880message_filters(enum message_verbosity v, const lzma_filter *filters) 881{ 882 if (v > verbosity) 883 return; 884 885 fprintf(stderr, _("%s: Filter chain:"), progname); 886 887 for (size_t i = 0; filters[i].id != LZMA_VLI_UNKNOWN; ++i) { 888 fprintf(stderr, " --"); 889 890 switch (filters[i].id) { 891 case LZMA_FILTER_LZMA1: 892 case LZMA_FILTER_LZMA2: { 893 const lzma_options_lzma *opt = filters[i].options; 894 const char *mode; 895 const char *mf; 896 897 switch (opt->mode) { 898 case LZMA_MODE_FAST: 899 mode = "fast"; 900 break; 901 902 case LZMA_MODE_NORMAL: 903 mode = "normal"; 904 break; 905 906 default: 907 mode = "UNKNOWN"; 908 break; 909 } 910 911 switch (opt->mf) { 912 case LZMA_MF_HC3: 913 mf = "hc3"; 914 break; 915 916 case LZMA_MF_HC4: 917 mf = "hc4"; 918 break; 919 920 case LZMA_MF_BT2: 921 mf = "bt2"; 922 break; 923 924 case LZMA_MF_BT3: 925 mf = "bt3"; 926 break; 927 928 case LZMA_MF_BT4: 929 mf = "bt4"; 930 break; 931 932 default: 933 mf = "UNKNOWN"; 934 break; 935 } 936 937 fprintf(stderr, "lzma%c=dict=%" PRIu32 938 ",lc=%" PRIu32 ",lp=%" PRIu32 939 ",pb=%" PRIu32 940 ",mode=%s,nice=%" PRIu32 ",mf=%s" 941 ",depth=%" PRIu32, 942 filters[i].id == LZMA_FILTER_LZMA2 943 ? '2' : '1', 944 opt->dict_size, 945 opt->lc, opt->lp, opt->pb, 946 mode, opt->nice_len, mf, opt->depth); 947 break; 948 } 949 950 case LZMA_FILTER_X86: 951 fprintf(stderr, "x86"); 952 break; 953 954 case LZMA_FILTER_POWERPC: 955 fprintf(stderr, "powerpc"); 956 break; 957 958 case LZMA_FILTER_IA64: 959 fprintf(stderr, "ia64"); 960 break; 961 962 case LZMA_FILTER_ARM: 963 fprintf(stderr, "arm"); 964 break; 965 966 case LZMA_FILTER_ARMTHUMB: 967 fprintf(stderr, "armthumb"); 968 break; 969 970 case LZMA_FILTER_SPARC: 971 fprintf(stderr, "sparc"); 972 break; 973 974 case LZMA_FILTER_DELTA: { 975 const lzma_options_delta *opt = filters[i].options; 976 fprintf(stderr, "delta=dist=%" PRIu32, opt->dist); 977 break; 978 } 979 980 default: 981 fprintf(stderr, "UNKNOWN"); 982 break; 983 } 984 } 985 986 fputc('\n', stderr); 987 return; 988} 989 990 991extern void 992message_try_help(void) 993{ 994 // Print this with V_WARNING instead of V_ERROR to prevent it from 995 // showing up when --quiet has been specified. 996 message(V_WARNING, _("Try `%s --help' for more information."), 997 progname); 998 return; 999} 1000 1001 1002extern void 1003message_memlimit(void) 1004{ 1005 if (opt_robot) 1006 printf("%" PRIu64 "\n", hardware_memlimit_get()); 1007 else 1008 printf(_("%s MiB (%s bytes)\n"), 1009 uint64_to_str( 1010 round_up_to_mib(hardware_memlimit_get()), 0), 1011 uint64_to_str(hardware_memlimit_get(), 1)); 1012 1013 tuklib_exit(E_SUCCESS, E_ERROR, verbosity != V_SILENT); 1014} 1015 1016 1017extern void 1018message_version(void) 1019{ 1020 // It is possible that liblzma version is different than the command 1021 // line tool version, so print both. 1022 if (opt_robot) { 1023 printf("XZ_VERSION=%d\nLIBLZMA_VERSION=%d\n", 1024 LZMA_VERSION, lzma_version_number()); 1025 } else { 1026 printf("xz (" PACKAGE_NAME ") " LZMA_VERSION_STRING "\n"); 1027 printf("liblzma %s\n", lzma_version_string()); 1028 } 1029 1030 tuklib_exit(E_SUCCESS, E_ERROR, verbosity != V_SILENT); 1031} 1032 1033 1034extern void 1035message_help(bool long_help) 1036{ 1037 printf(_("Usage: %s [OPTION]... [FILE]...\n" 1038 "Compress or decompress FILEs in the .xz format.\n\n"), 1039 progname); 1040 1041 puts(_("Mandatory arguments to long options are mandatory for " 1042 "short options too.\n")); 1043 1044 if (long_help) 1045 puts(_(" Operation mode:\n")); 1046 1047 puts(_( 1048" -z, --compress force compression\n" 1049" -d, --decompress force decompression\n" 1050" -t, --test test compressed file integrity\n" 1051" -l, --list list information about files")); 1052 1053 if (long_help) 1054 puts(_("\n Operation modifiers:\n")); 1055 1056 puts(_( 1057" -k, --keep keep (don't delete) input files\n" 1058" -f, --force force overwrite of output file and (de)compress links\n" 1059" -c, --stdout write to standard output and don't delete input files")); 1060 1061 if (long_help) 1062 puts(_( 1063" --no-sparse do not create sparse files when decompressing\n" 1064" -S, --suffix=.SUF use the suffix `.SUF' on compressed files\n" 1065" --files=[FILE] read filenames to process from FILE; if FILE is\n" 1066" omitted, filenames are read from the standard input;\n" 1067" filenames must be terminated with the newline character\n" 1068" --files0=[FILE] like --files but use the null character as terminator")); 1069 1070 if (long_help) { 1071 puts(_("\n Basic file format and compression options:\n")); 1072 puts(_( 1073" -F, --format=FMT file format to encode or decode; possible values are\n" 1074" `auto' (default), `xz', `lzma', and `raw'\n" 1075" -C, --check=CHECK integrity check type: `crc32', `crc64' (default),\n" 1076" `sha256', or `none' (use with caution)")); 1077 } 1078 1079 puts(_( 1080" -0 .. -9 compression preset; 0-2 fast compression, 3-5 good\n" 1081" compression, 6-9 excellent compression; default is 6")); 1082 1083 puts(_( 1084" -e, --extreme use more CPU time when encoding to increase compression\n" 1085" ratio without increasing memory usage of the decoder")); 1086 1087 if (long_help) 1088 puts(_( // xgettext:no-c-format 1089" -M, --memory=NUM use roughly NUM bytes of memory at maximum; 0 indicates\n" 1090" the default setting, which is 40 % of total RAM")); 1091 1092 if (long_help) { 1093 puts(_( 1094"\n Custom filter chain for compression (alternative for using presets):")); 1095 1096#if defined(HAVE_ENCODER_LZMA1) || defined(HAVE_DECODER_LZMA1) \ 1097 || defined(HAVE_ENCODER_LZMA2) || defined(HAVE_DECODER_LZMA2) 1098 puts(_( 1099"\n" 1100" --lzma1[=OPTS] LZMA1 or LZMA2; OPTS is a comma-separated list of zero or\n" 1101" --lzma2[=OPTS] more of the following options (valid values; default):\n" 1102" preset=NUM reset options to preset number NUM (0-9)\n" 1103" dict=NUM dictionary size (4KiB - 1536MiB; 8MiB)\n" 1104" lc=NUM number of literal context bits (0-4; 3)\n" 1105" lp=NUM number of literal position bits (0-4; 0)\n" 1106" pb=NUM number of position bits (0-4; 2)\n" 1107" mode=MODE compression mode (fast, normal; normal)\n" 1108" nice=NUM nice length of a match (2-273; 64)\n" 1109" mf=NAME match finder (hc3, hc4, bt2, bt3, bt4; bt4)\n" 1110" depth=NUM maximum search depth; 0=automatic (default)")); 1111#endif 1112 1113 puts(_( 1114"\n" 1115" --x86[=OPTS] x86 BCJ filter\n" 1116" --powerpc[=OPTS] PowerPC BCJ filter (big endian only)\n" 1117" --ia64[=OPTS] IA64 (Itanium) BCJ filter\n" 1118" --arm[=OPTS] ARM BCJ filter (little endian only)\n" 1119" --armthumb[=OPTS] ARM-Thumb BCJ filter (little endian only)\n" 1120" --sparc[=OPTS] SPARC BCJ filter\n" 1121" Valid OPTS for all BCJ filters:\n" 1122" start=NUM start offset for conversions (default=0)")); 1123 1124#if defined(HAVE_ENCODER_DELTA) || defined(HAVE_DECODER_DELTA) 1125 puts(_( 1126"\n" 1127" --delta[=OPTS] Delta filter; valid OPTS (valid values; default):\n" 1128" dist=NUM distance between bytes being subtracted\n" 1129" from each other (1-256; 1)")); 1130#endif 1131 1132#if defined(HAVE_ENCODER_SUBBLOCK) || defined(HAVE_DECODER_SUBBLOCK) 1133 puts(_( 1134"\n" 1135" --subblock[=OPTS] Subblock filter; valid OPTS (valid values; default):\n" 1136" size=NUM number of bytes of data per subblock\n" 1137" (1 - 256Mi; 4Ki)\n" 1138" rle=NUM run-length encoder chunk size (0-256; 0)")); 1139#endif 1140 } 1141 1142 if (long_help) 1143 puts(_("\n Other options:\n")); 1144 1145 puts(_( 1146" -q, --quiet suppress warnings; specify twice to suppress errors too\n" 1147" -v, --verbose be verbose; specify twice for even more verbose")); 1148 1149 if (long_help) { 1150 puts(_( 1151" -Q, --no-warn make warnings not affect the exit status")); 1152 puts(_( 1153" --robot use machine-parsable messages (useful for scripts)")); 1154 puts(""); 1155 puts(_( 1156" --info-memory display the memory usage limit and exit")); 1157 puts(_( 1158" -h, --help display the short help (lists only the basic options)\n" 1159" -H, --long-help display this long help and exit")); 1160 } else { 1161 puts(_( 1162" -h, --help display this short help and exit\n" 1163" -H, --long-help display the long help (lists also the advanced options)")); 1164 } 1165 1166 puts(_( 1167" -V, --version display the version number and exit")); 1168 1169 puts(_("\nWith no FILE, or when FILE is -, read standard input.\n")); 1170 1171 if (long_help) { 1172 printf(_( 1173"On this system and configuration, this program will use a maximum of roughly\n" 1174"%s MiB RAM and "), uint64_to_str(round_up_to_mib(hardware_memlimit_get()), 0)); 1175 printf(N_("one thread.\n\n", "%s threads.\n\n", 1176 hardware_threadlimit_get()), 1177 uint64_to_str(hardware_threadlimit_get(), 0)); 1178 } 1179 1180 // TRANSLATORS: This message indicates the bug reporting address 1181 // for this package. Please add _another line_ saying 1182 // "Report translation bugs to <...>\n" with the email or WWW 1183 // address for translation bugs. Thanks. 1184 printf(_("Report bugs to <%s> (in English or Finnish).\n"), 1185 PACKAGE_BUGREPORT); 1186 printf(_("%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL); 1187 1188 tuklib_exit(E_SUCCESS, E_ERROR, verbosity != V_SILENT); 1189} 1190