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