busybox/archival/bbunzip.c
<<
>>
Prefs
   1/* vi: set sw=4 ts=4: */
   2/*
   3 * Common code for gunzip-like applets
   4 *
   5 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
   6 */
   7//kbuild:lib-$(CONFIG_ZCAT) += bbunzip.o
   8//kbuild:lib-$(CONFIG_GUNZIP) += bbunzip.o
   9//kbuild:lib-$(CONFIG_BZCAT) += bbunzip.o
  10//kbuild:lib-$(CONFIG_BUNZIP2) += bbunzip.o
  11
  12/* lzop_main() uses bbunpack(), need this: */
  13//kbuild:lib-$(CONFIG_LZOP) += bbunzip.o
  14//kbuild:lib-$(CONFIG_LZOPCAT) += bbunzip.o
  15//kbuild:lib-$(CONFIG_UNLZOP) += bbunzip.o
  16/* bzip2_main() too: */
  17//kbuild:lib-$(CONFIG_BZIP2) += bbunzip.o
  18/* gzip_main() too: */
  19//kbuild:lib-$(CONFIG_GZIP) += bbunzip.o
  20
  21#include "libbb.h"
  22#include "bb_archive.h"
  23
  24static
  25int open_to_or_warn(int to_fd, const char *filename, int flags, int mode)
  26{
  27        int fd = open3_or_warn(filename, flags, mode);
  28        if (fd < 0) {
  29                return 1;
  30        }
  31        xmove_fd(fd, to_fd);
  32        return 0;
  33}
  34
  35char* FAST_FUNC append_ext(char *filename, const char *expected_ext)
  36{
  37        return xasprintf("%s.%s", filename, expected_ext);
  38}
  39
  40int FAST_FUNC bbunpack(char **argv,
  41        IF_DESKTOP(long long) int FAST_FUNC (*unpacker)(transformer_state_t *xstate),
  42        char* FAST_FUNC (*make_new_name)(char *filename, const char *expected_ext),
  43        const char *expected_ext
  44)
  45{
  46        struct stat stat_buf;
  47        IF_DESKTOP(long long) int status = 0;
  48        char *filename, *new_name;
  49        smallint exitcode = 0;
  50        transformer_state_t xstate;
  51
  52        do {
  53                /* NB: new_name is *maybe* malloc'ed! */
  54                new_name = NULL;
  55                filename = *argv; /* can be NULL - 'streaming' bunzip2 */
  56
  57                if (filename && LONE_DASH(filename))
  58                        filename = NULL;
  59
  60                /* Open src */
  61                if (filename) {
  62                        if (!(option_mask32 & BBUNPK_SEAMLESS_MAGIC)) {
  63                                if (stat(filename, &stat_buf) != 0) {
  64 err_name:
  65                                        bb_simple_perror_msg(filename);
  66 err:
  67                                        exitcode = 1;
  68                                        goto free_name;
  69                                }
  70                                if (open_to_or_warn(STDIN_FILENO, filename, O_RDONLY, 0))
  71                                        goto err;
  72                        } else {
  73                                /* "clever zcat" with FILE */
  74                                /* fail_if_not_compressed because zcat refuses uncompressed input */
  75                                int fd = open_zipped(filename, /*fail_if_not_compressed:*/ 1);
  76                                if (fd < 0)
  77                                        goto err_name;
  78                                xmove_fd(fd, STDIN_FILENO);
  79                        }
  80                } else
  81                if (option_mask32 & BBUNPK_SEAMLESS_MAGIC) {
  82                        /* "clever zcat" on stdin */
  83                        if (setup_unzip_on_fd(STDIN_FILENO, /*fail_if_not_compressed*/ 1))
  84                                goto err;
  85                }
  86
  87                /* Special cases: test, stdout */
  88                if (option_mask32 & (BBUNPK_OPT_STDOUT|BBUNPK_OPT_TEST)) {
  89                        if (option_mask32 & BBUNPK_OPT_TEST)
  90                                if (open_to_or_warn(STDOUT_FILENO, bb_dev_null, O_WRONLY, 0))
  91                                        xfunc_die();
  92                        filename = NULL;
  93                }
  94
  95                /* Open dst if we are going to unpack to file */
  96                if (filename) {
  97                        new_name = make_new_name(filename, expected_ext);
  98                        if (!new_name) {
  99                                bb_error_msg("%s: unknown suffix - ignored", filename);
 100                                goto err;
 101                        }
 102
 103                        /* -f: overwrite existing output files */
 104                        if (option_mask32 & BBUNPK_OPT_FORCE) {
 105                                unlink(new_name);
 106                        }
 107
 108                        /* O_EXCL: "real" bunzip2 doesn't overwrite files */
 109                        /* GNU gunzip does not bail out, but goes to next file */
 110                        if (open_to_or_warn(STDOUT_FILENO, new_name, O_WRONLY | O_CREAT | O_EXCL,
 111                                        stat_buf.st_mode))
 112                                goto err;
 113                }
 114
 115                /* Check that the input is sane */
 116                if (!(option_mask32 & BBUNPK_OPT_FORCE) && isatty(STDIN_FILENO)) {
 117                        bb_error_msg_and_die("compressed data not read from terminal, "
 118                                        "use -f to force it");
 119                }
 120
 121                if (!(option_mask32 & BBUNPK_SEAMLESS_MAGIC)) {
 122                        init_transformer_state(&xstate);
 123                        /*xstate.signature_skipped = 0; - already is */
 124                        /*xstate.src_fd = STDIN_FILENO; - already is */
 125                        xstate.dst_fd = STDOUT_FILENO;
 126                        status = unpacker(&xstate);
 127                        if (status < 0)
 128                                exitcode = 1;
 129                } else {
 130                        if (bb_copyfd_eof(STDIN_FILENO, STDOUT_FILENO) < 0)
 131                                /* Disk full, tty closed, etc. No point in continuing */
 132                                xfunc_die();
 133                }
 134
 135                if (!(option_mask32 & BBUNPK_OPT_STDOUT))
 136                        xclose(STDOUT_FILENO); /* with error check! */
 137
 138                if (filename) {
 139                        char *del = new_name;
 140
 141                        if (status >= 0) {
 142                                unsigned new_name_len;
 143
 144                                /* TODO: restore other things? */
 145                                if (xstate.mtime != 0) {
 146                                        struct timeval times[2];
 147
 148                                        times[1].tv_sec = times[0].tv_sec = xstate.mtime;
 149                                        times[1].tv_usec = times[0].tv_usec = 0;
 150                                        /* Note: we closed it first.
 151                                         * On some systems calling utimes
 152                                         * then closing resets the mtime
 153                                         * back to current time. */
 154                                        utimes(new_name, times); /* ignoring errors */
 155                                }
 156
 157                                if (ENABLE_DESKTOP)
 158                                        new_name_len = strlen(new_name);
 159                                /* Restore source filename (unless tgz -> tar case) */
 160                                if (new_name == filename) {
 161                                        new_name_len = strlen(filename);
 162                                        filename[new_name_len] = '.';
 163                                }
 164                                /* Extreme bloat for gunzip compat */
 165                                /* Some users do want this info... */
 166                                if (ENABLE_DESKTOP && (option_mask32 & BBUNPK_OPT_VERBOSE)) {
 167                                        unsigned percent = status
 168                                                ? ((uoff_t)stat_buf.st_size * 100u / (unsigned long long)status)
 169                                                : 0;
 170                                        fprintf(stderr, "%s: %u%% - replaced with %.*s\n",
 171                                                filename,
 172                                                100u - percent,
 173                                                new_name_len, new_name
 174                                        );
 175                                }
 176                                /* Delete _source_ file */
 177                                del = filename;
 178                                if (option_mask32 & BBUNPK_OPT_KEEP) /* ... unless -k */
 179                                        del = NULL;
 180                        }
 181                        if (del)
 182                                xunlink(del);
 183 free_name:
 184                        if (new_name != filename)
 185                                free(new_name);
 186                }
 187        } while (*argv && *++argv);
 188
 189        if (option_mask32 & BBUNPK_OPT_STDOUT)
 190                xclose(STDOUT_FILENO); /* with error check! */
 191
 192        return exitcode;
 193}
 194
 195#if ENABLE_UNCOMPRESS \
 196 || ENABLE_FEATURE_BZIP2_DECOMPRESS \
 197 || ENABLE_UNLZMA || ENABLE_LZCAT || ENABLE_LZMA \
 198 || ENABLE_UNXZ || ENABLE_XZCAT || ENABLE_XZ
 199static
 200char* FAST_FUNC make_new_name_generic(char *filename, const char *expected_ext)
 201{
 202        char *extension = strrchr(filename, '.');
 203        if (!extension || strcmp(extension + 1, expected_ext) != 0) {
 204                /* Mimic GNU gunzip - "real" bunzip2 tries to */
 205                /* unpack file anyway, to file.out */
 206                return NULL;
 207        }
 208        *extension = '\0';
 209        return filename;
 210}
 211#endif
 212
 213
 214/*
 215 * Uncompress applet for busybox (c) 2002 Glenn McGrath
 216 *
 217 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
 218 */
 219//usage:#define uncompress_trivial_usage
 220//usage:       "[-cf] [FILE]..."
 221//usage:#define uncompress_full_usage "\n\n"
 222//usage:       "Decompress .Z file[s]\n"
 223//usage:     "\n        -c      Write to stdout"
 224//usage:     "\n        -f      Overwrite"
 225
 226//config:config UNCOMPRESS
 227//config:       bool "uncompress (7.1 kb)"
 228//config:       default n  # ancient
 229//config:       help
 230//config:       uncompress is used to decompress archives created by compress.
 231//config:       Not much used anymore, replaced by gzip/gunzip.
 232
 233//applet:IF_UNCOMPRESS(APPLET(uncompress, BB_DIR_BIN, BB_SUID_DROP))
 234//kbuild:lib-$(CONFIG_UNCOMPRESS) += bbunzip.o
 235#if ENABLE_UNCOMPRESS
 236int uncompress_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
 237int uncompress_main(int argc UNUSED_PARAM, char **argv)
 238{
 239// (N)compress 4.2.4.4:
 240// -d If given, decompression is done instead
 241// -c Write output on stdout, don't remove original
 242// -b Parameter limits the max number of bits/code
 243// -f Forces output file to be generated
 244// -v Write compression statistics
 245// -V Output vesion and compile options
 246// -r Recursive. If a filename is a directory, descend into it and compress everything
 247        getopt32(argv, "cf");
 248
 249        argv += optind;
 250
 251        return bbunpack(argv, unpack_Z_stream, make_new_name_generic, "Z");
 252}
 253#endif
 254
 255
 256/*
 257 * Gzip implementation for busybox
 258 *
 259 * Based on GNU gzip v1.2.4 Copyright (C) 1992-1993 Jean-loup Gailly.
 260 *
 261 * Originally adjusted for busybox by Sven Rudolph <sr1@inf.tu-dresden.de>
 262 * based on gzip sources
 263 *
 264 * Adjusted further by Erik Andersen <andersen@codepoet.org> to support files as
 265 * well as stdin/stdout, and to generally behave itself wrt command line
 266 * handling.
 267 *
 268 * General cleanup to better adhere to the style guide and make use of standard
 269 * busybox functions by Glenn McGrath
 270 *
 271 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
 272 *
 273 * gzip (GNU zip) -- compress files with zip algorithm and 'compress' interface
 274 * Copyright (C) 1992-1993 Jean-loup Gailly
 275 * The unzip code was written and put in the public domain by Mark Adler.
 276 * Portions of the lzw code are derived from the public domain 'compress'
 277 * written by Spencer Thomas, Joe Orost, James Woods, Jim McKie, Steve Davies,
 278 * Ken Turkowski, Dave Mack and Peter Jannesen.
 279 */
 280//usage:#define gunzip_trivial_usage
 281//usage:       "[-cfkt] [FILE]..."
 282//usage:#define gunzip_full_usage "\n\n"
 283//usage:       "Decompress FILEs (or stdin)\n"
 284//usage:     "\n        -c      Write to stdout"
 285//usage:     "\n        -f      Force"
 286//usage:     "\n        -k      Keep input files"
 287//usage:     "\n        -t      Test file integrity"
 288//usage:
 289//usage:#define gunzip_example_usage
 290//usage:       "$ ls -la /tmp/BusyBox*\n"
 291//usage:       "-rw-rw-r--    1 andersen andersen   557009 Apr 11 10:55 /tmp/BusyBox-0.43.tar.gz\n"
 292//usage:       "$ gunzip /tmp/BusyBox-0.43.tar.gz\n"
 293//usage:       "$ ls -la /tmp/BusyBox*\n"
 294//usage:       "-rw-rw-r--    1 andersen andersen  1761280 Apr 14 17:47 /tmp/BusyBox-0.43.tar\n"
 295//usage:
 296//usage:#define zcat_trivial_usage
 297//usage:       "[FILE]..."
 298//usage:#define zcat_full_usage "\n\n"
 299//usage:       "Decompress to stdout"
 300
 301//config:config GUNZIP
 302//config:       bool "gunzip (11 kb)"
 303//config:       default y
 304//config:       select FEATURE_GZIP_DECOMPRESS
 305//config:       help
 306//config:       gunzip is used to decompress archives created by gzip.
 307//config:       You can use the '-t' option to test the integrity of
 308//config:       an archive, without decompressing it.
 309//config:
 310//config:config ZCAT
 311//config:       bool "zcat (24 kb)"
 312//config:       default y
 313//config:       select FEATURE_GZIP_DECOMPRESS
 314//config:       help
 315//config:       Alias to "gunzip -c".
 316//config:
 317//config:config FEATURE_GUNZIP_LONG_OPTIONS
 318//config:       bool "Enable long options"
 319//config:       default y
 320//config:       depends on (GUNZIP || ZCAT) && LONG_OPTS
 321
 322//applet:IF_GUNZIP(APPLET(gunzip, BB_DIR_BIN, BB_SUID_DROP))
 323//               APPLET_ODDNAME:name  main    location    suid_type     help
 324//applet:IF_ZCAT(APPLET_ODDNAME(zcat, gunzip, BB_DIR_BIN, BB_SUID_DROP, zcat))
 325#if ENABLE_FEATURE_GZIP_DECOMPRESS
 326static
 327char* FAST_FUNC make_new_name_gunzip(char *filename, const char *expected_ext UNUSED_PARAM)
 328{
 329        char *extension = strrchr(filename, '.');
 330
 331        if (!extension)
 332                return NULL;
 333
 334        extension++;
 335        if (strcmp(extension, "tgz" + 1) == 0
 336#if ENABLE_FEATURE_SEAMLESS_Z
 337         || (extension[0] == 'Z' && extension[1] == '\0')
 338#endif
 339        ) {
 340                extension[-1] = '\0';
 341        } else if (strcmp(extension, "tgz") == 0) {
 342                filename = xstrdup(filename);
 343                extension = strrchr(filename, '.');
 344                extension[2] = 'a';
 345                extension[3] = 'r';
 346        } else {
 347                return NULL;
 348        }
 349        return filename;
 350}
 351
 352#if ENABLE_FEATURE_GUNZIP_LONG_OPTIONS
 353static const char gunzip_longopts[] ALIGN1 =
 354        "stdout\0"              No_argument       "c"
 355        "to-stdout\0"           No_argument       "c"
 356        "force\0"               No_argument       "f"
 357        "test\0"                No_argument       "t"
 358        "no-name\0"             No_argument       "n"
 359        ;
 360#endif
 361
 362/*
 363 * Linux kernel build uses gzip -d -n. We accept and ignore it.
 364 * Man page says:
 365 * -n --no-name
 366 * gzip: do not save the original file name and time stamp.
 367 * (The original name is always saved if the name had to be truncated.)
 368 * gunzip: do not restore the original file name/time even if present
 369 * (remove only the gzip suffix from the compressed file name).
 370 * This option is the default when decompressing.
 371 * -N --name
 372 * gzip: always save the original file name and time stamp (this is the default)
 373 * gunzip: restore the original file name and time stamp if present.
 374 */
 375int gunzip_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
 376int gunzip_main(int argc UNUSED_PARAM, char **argv)
 377{
 378#if ENABLE_FEATURE_GUNZIP_LONG_OPTIONS
 379        getopt32long(argv, BBUNPK_OPTSTR "dtn", gunzip_longopts);
 380#else
 381        getopt32(argv, BBUNPK_OPTSTR "dtn");
 382#endif
 383        argv += optind;
 384
 385        /* If called as zcat...
 386         * Normally, "zcat" is just "gunzip -c".
 387         * But if seamless magic is enabled, then we are much more clever.
 388         */
 389        if (ENABLE_ZCAT && (!ENABLE_GUNZIP || applet_name[1] == 'c'))
 390                option_mask32 |= BBUNPK_OPT_STDOUT | BBUNPK_SEAMLESS_MAGIC;
 391
 392        return bbunpack(argv, unpack_gz_stream, make_new_name_gunzip, /*unused:*/ NULL);
 393}
 394#endif /* FEATURE_GZIP_DECOMPRESS */
 395
 396
 397/*
 398 * Modified for busybox by Glenn McGrath
 399 * Added support output to stdout by Thomas Lundquist <thomasez@zelow.no>
 400 *
 401 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
 402 */
 403//usage:#define bunzip2_trivial_usage
 404//usage:       "[-cfk] [FILE]..."
 405//usage:#define bunzip2_full_usage "\n\n"
 406//usage:       "Decompress FILEs (or stdin)\n"
 407//usage:     "\n        -c      Write to stdout"
 408//usage:     "\n        -f      Force"
 409//usage:     "\n        -k      Keep input files"
 410//usage:#define bzcat_trivial_usage
 411//usage:       "[FILE]..."
 412//usage:#define bzcat_full_usage "\n\n"
 413//usage:       "Decompress to stdout"
 414
 415//config:config BUNZIP2
 416//config:       bool "bunzip2 (8.7 kb)"
 417//config:       default y
 418//config:       select FEATURE_BZIP2_DECOMPRESS
 419//config:       help
 420//config:       bunzip2 is a compression utility using the Burrows-Wheeler block
 421//config:       sorting text compression algorithm, and Huffman coding. Compression
 422//config:       is generally considerably better than that achieved by more
 423//config:       conventional LZ77/LZ78-based compressors, and approaches the
 424//config:       performance of the PPM family of statistical compressors.
 425//config:
 426//config:       Unless you have a specific application which requires bunzip2, you
 427//config:       should probably say N here.
 428//config:
 429//config:config BZCAT
 430//config:       bool "bzcat (8.7 kb)"
 431//config:       default y
 432//config:       select FEATURE_BZIP2_DECOMPRESS
 433//config:       help
 434//config:       Alias to "bunzip2 -c".
 435
 436//applet:IF_BUNZIP2(APPLET(bunzip2, BB_DIR_USR_BIN, BB_SUID_DROP))
 437//                APPLET_ODDNAME:name   main     location        suid_type     help
 438//applet:IF_BZCAT(APPLET_ODDNAME(bzcat, bunzip2, BB_DIR_USR_BIN, BB_SUID_DROP, bzcat))
 439#if ENABLE_FEATURE_BZIP2_DECOMPRESS || ENABLE_BUNZIP2 || ENABLE_BZCAT
 440int bunzip2_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
 441int bunzip2_main(int argc UNUSED_PARAM, char **argv)
 442{
 443        getopt32(argv, BBUNPK_OPTSTR "dt");
 444        argv += optind;
 445        if (ENABLE_BZCAT && (!ENABLE_BUNZIP2 || applet_name[2] == 'c')) /* bzcat */
 446                option_mask32 |= BBUNPK_OPT_STDOUT;
 447
 448        return bbunpack(argv, unpack_bz2_stream, make_new_name_generic, "bz2");
 449}
 450#endif
 451
 452
 453/*
 454 * Small lzma deflate implementation.
 455 * Copyright (C) 2006  Aurelien Jacobs <aurel@gnuage.org>
 456 *
 457 * Based on bunzip.c from busybox
 458 *
 459 * Licensed under GPLv2, see file LICENSE in this source tree.
 460 */
 461//usage:#define unlzma_trivial_usage
 462//usage:       "[-cfk] [FILE]..."
 463//usage:#define unlzma_full_usage "\n\n"
 464//usage:       "Decompress FILE (or stdin)\n"
 465//usage:     "\n        -c      Write to stdout"
 466//usage:     "\n        -f      Force"
 467//usage:     "\n        -k      Keep input files"
 468//usage:
 469//usage:#define lzma_trivial_usage
 470//usage:       "-d [-cfk] [FILE]..."
 471//usage:#define lzma_full_usage "\n\n"
 472//usage:       "Decompress FILE (or stdin)\n"
 473//usage:     "\n        -d      Decompress"
 474//usage:     "\n        -c      Write to stdout"
 475//usage:     "\n        -f      Force"
 476//usage:     "\n        -k      Keep input files"
 477//usage:
 478//usage:#define lzcat_trivial_usage
 479//usage:       "[FILE]..."
 480//usage:#define lzcat_full_usage "\n\n"
 481//usage:       "Decompress to stdout"
 482
 483//config:config UNLZMA
 484//config:       bool "unlzma (7.5 kb)"
 485//config:       default y
 486//config:       help
 487//config:       unlzma is a compression utility using the Lempel-Ziv-Markov chain
 488//config:       compression algorithm, and range coding. Compression
 489//config:       is generally considerably better than that achieved by the bzip2
 490//config:       compressors.
 491//config:
 492//config:config LZCAT
 493//config:       bool "lzcat (7.5 kb)"
 494//config:       default y
 495//config:       help
 496//config:       Alias to "unlzma -c".
 497//config:
 498//config:config LZMA
 499//config:       bool "lzma -d"
 500//config:       default y
 501//config:       help
 502//config:       Enable this option if you want commands like "lzma -d" to work.
 503//config:       IOW: you'll get lzma applet, but it will always require -d option.
 504
 505//applet:IF_UNLZMA(APPLET(unlzma, BB_DIR_USR_BIN, BB_SUID_DROP))
 506//                APPLET_ODDNAME:name   main    location        suid_type     help
 507//applet:IF_LZCAT(APPLET_ODDNAME(lzcat, unlzma, BB_DIR_USR_BIN, BB_SUID_DROP, lzcat))
 508//applet:IF_LZMA( APPLET_ODDNAME(lzma,  unlzma, BB_DIR_USR_BIN, BB_SUID_DROP, lzma))
 509//kbuild:lib-$(CONFIG_UNLZMA) += bbunzip.o
 510//kbuild:lib-$(CONFIG_LZCAT) += bbunzip.o
 511//kbuild:lib-$(CONFIG_LZMA) += bbunzip.o
 512#if ENABLE_UNLZMA || ENABLE_LZCAT || ENABLE_LZMA
 513int unlzma_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
 514int unlzma_main(int argc UNUSED_PARAM, char **argv)
 515{
 516        IF_LZMA(int opts =) getopt32(argv, BBUNPK_OPTSTR "dt");
 517# if ENABLE_LZMA
 518        /* lzma without -d or -t? */
 519        if (applet_name[2] == 'm' && !(opts & (BBUNPK_OPT_DECOMPRESS|BBUNPK_OPT_TEST)))
 520                bb_show_usage();
 521# endif
 522        /* lzcat? */
 523        if (ENABLE_LZCAT && applet_name[2] == 'c')
 524                option_mask32 |= BBUNPK_OPT_STDOUT;
 525
 526        argv += optind;
 527        return bbunpack(argv, unpack_lzma_stream, make_new_name_generic, "lzma");
 528}
 529#endif
 530
 531
 532//usage:#define unxz_trivial_usage
 533//usage:       "[-cfk] [FILE]..."
 534//usage:#define unxz_full_usage "\n\n"
 535//usage:       "Decompress FILE (or stdin)\n"
 536//usage:     "\n        -c      Write to stdout"
 537//usage:     "\n        -f      Force"
 538//usage:     "\n        -k      Keep input files"
 539//usage:
 540//usage:#define xz_trivial_usage
 541//usage:       "-d [-cfk] [FILE]..."
 542//usage:#define xz_full_usage "\n\n"
 543//usage:       "Decompress FILE (or stdin)\n"
 544//usage:     "\n        -d      Decompress"
 545//usage:     "\n        -c      Write to stdout"
 546//usage:     "\n        -f      Force"
 547//usage:     "\n        -k      Keep input files"
 548//usage:
 549//usage:#define xzcat_trivial_usage
 550//usage:       "[FILE]..."
 551//usage:#define xzcat_full_usage "\n\n"
 552//usage:       "Decompress to stdout"
 553
 554//config:config UNXZ
 555//config:       bool "unxz (13 kb)"
 556//config:       default y
 557//config:       help
 558//config:       unxz is a unlzma successor.
 559//config:
 560//config:config XZCAT
 561//config:       bool "xzcat (13 kb)"
 562//config:       default y
 563//config:       help
 564//config:       Alias to "unxz -c".
 565//config:
 566//config:config XZ
 567//config:       bool "xz -d"
 568//config:       default y
 569//config:       help
 570//config:       Enable this option if you want commands like "xz -d" to work.
 571//config:       IOW: you'll get xz applet, but it will always require -d option.
 572
 573//applet:IF_UNXZ(APPLET(unxz, BB_DIR_USR_BIN, BB_SUID_DROP))
 574//                APPLET_ODDNAME:name   main  location        suid_type     help
 575//applet:IF_XZCAT(APPLET_ODDNAME(xzcat, unxz, BB_DIR_USR_BIN, BB_SUID_DROP, xzcat))
 576//applet:IF_XZ(   APPLET_ODDNAME(xz,    unxz, BB_DIR_USR_BIN, BB_SUID_DROP, xz))
 577//kbuild:lib-$(CONFIG_UNXZ) += bbunzip.o
 578//kbuild:lib-$(CONFIG_XZCAT) += bbunzip.o
 579//kbuild:lib-$(CONFIG_XZ) += bbunzip.o
 580#if ENABLE_UNXZ || ENABLE_XZCAT || ENABLE_XZ
 581int unxz_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
 582int unxz_main(int argc UNUSED_PARAM, char **argv)
 583{
 584        IF_XZ(int opts =) getopt32(argv, BBUNPK_OPTSTR "dt");
 585# if ENABLE_XZ
 586        /* xz without -d or -t? */
 587        if (applet_name[2] == '\0' && !(opts & (BBUNPK_OPT_DECOMPRESS|BBUNPK_OPT_TEST)))
 588                bb_show_usage();
 589# endif
 590        /* xzcat? */
 591        if (ENABLE_XZCAT && applet_name[2] == 'c')
 592                option_mask32 |= BBUNPK_OPT_STDOUT;
 593
 594        argv += optind;
 595        return bbunpack(argv, unpack_xz_stream, make_new_name_generic, "xz");
 596}
 597#endif
 598