rpm  5.4.15
rpmz.c
Go to the documentation of this file.
1 
5 /*
6  *
7  * Copyright (C) 2007 Lasse Collin
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17  * Lesser General Public License for more details.
18  *
19  */
20 
21 #include "system.h"
22 
23 #include <lzma.h>
24 
25 #define _RPMIOB_INTERNAL
26 #define _RPMZ_INTERNAL
27 #define _RPMZ_INTERNAL_XZ
28 #include "rpmz.h"
29 
30 #include "debug.h"
31 
32 /*@unchecked@*/
33 static int _debug = 0;
34 
35 #ifdef NOTYET
36 /*@unchecked@*/
37 static int opt_preserve_name;
38 #endif
39 
40 #ifdef NOTYET
41 /*@unchecked@*/
42 static lzma_stream strm = LZMA_STREAM_INIT;
43 #endif
44 
45 #ifdef NOTYET
46 /* True if we should auto-adjust the compression settings to use less memory
47  if memory usage limit is too low for the original settings. */
48 /*@unchecked@*/
49 static bool auto_adjust = true;
50 /* Indicate if no preset has been explicitly given. In that case, if we need
51  to auto-adjust for lower memory usage, we won't print a warning. */
52 /*@unchecked@*/
53 static bool preset_default = true;
54 #endif
55 
56 enum {
57  OPT_SUBBLOCK = INT_MIN,
58 
62 
63 };
64 
65 #define F_ISSET(_f, _FLAG) (((_f) & ((RPMZ_FLAGS_##_FLAG) & ~0x40000000)) != RPMZ_FLAGS_NONE)
66 #define RZ_ISSET(_FLAG) F_ISSET(z->flags, _FLAG)
67 
68 /*@unchecked@*/
69 struct rpmz_s __rpmz = {
70  .stdin_fn = "(stdin)",
71  .stdout_fn = "(stdout)",
72 
73  /* XXX logic is reversed, disablers should clear with toggle. */
75  .format = RPMZ_FORMAT_AUTO,
77  .level = 6, /* XXX compression level is type specific. */
78 
79  .nb = 16 * BUFSIZ,
80  .ifmode = "rb",
81  .ofmode = "wb",
82 
83  ._auto_adjust = 1,
84 #ifdef NOTYET
85  ._format_compress_auto = RPMZ_FORMAT_XZ,
86 #else
87  ._format_compress_auto = RPMZ_FORMAT_GZIP,
88 #endif
89  ._checksum = LZMA_CHECK_CRC64,
90 
91 };
92 
93 /*@unchecked@*/
95 
96 /*==============================================================*/
99 static int checkfd(const char * devnull, int fdno, int flags)
100  /*@*/
101 {
102  struct stat sb;
103  int ret = 0;
104 
105  if (fstat(fdno, &sb) == -1 && errno == EBADF)
106  ret = (open(devnull, flags) == fdno) ? 1 : 2;
107  return ret;
108 }
109 
112 static void io_init(void)
113  /*@*/
114 {
115  static int _oneshot = 0;
116 
117  /* Insure that stdin/stdout/stderr are open, lest stderr end up in rpmdb. */
118  if (!_oneshot) {
119  static const char _devnull[] = "/dev/null";
120 #if defined(STDIN_FILENO)
121  (void) checkfd(_devnull, STDIN_FILENO, O_RDONLY);
122 #endif
123 #if defined(STDOUT_FILENO)
124  (void) checkfd(_devnull, STDOUT_FILENO, O_WRONLY);
125 #endif
126 #if defined(STDERR_FILENO)
127  (void) checkfd(_devnull, STDERR_FILENO, O_WRONLY);
128 #endif
129  _oneshot++;
130  }
131 }
132 
133 /* \brief Unlinks a file
134 
135  This tries to verify that the file being unlinked really is the file that
136  we want to unlink by verifying device and inode numbers. There's still
137  a small unavoidable race, but this is much better than nothing (the file
138  could have been moved/replaced even hours earlier). */
139 static void
140 io_unlink(const char *fn, const struct stat *ost)
141  /*@*/
142 {
143  /* On Windows, st_ino is meaningless, so don't bother testing it. */
144 #ifndef _WIN32
145  struct stat nsb;
146 
147  if (Lstat(fn, &nsb) != 0
148  || nsb.st_dev != ost->st_dev || nsb.st_ino != ost->st_ino)
149  rpmlog(RPMLOG_ERR, _("%s: File seems to be moved, not removing\n"), fn);
150  else
151  /* There's a race condition between Lstat() and Unlink()
152  but at least we have tried to avoid removing wrong file. */
153  if (S_ISREG(nsb.st_mode) && Unlink(fn))
154  rpmlog(RPMLOG_ERR, _("%s: Cannot remove: %s\n"), fn, strerror(errno));
155 #else
156  if (Unlink(fn))
157  rpmlog(RPMLOG_ERR, _("%s: Cannot remove: %s\n"), fn, strerror(errno));
158 #endif
159  return;
160 }
161 
162 /* \brief Copies owner/group and permissions
163 
164  \todo ACL and EA support
165 */
166 static void
168  /*@*/
169 {
170  /* Skip chown and chmod on Windows. */
171 #ifndef _WIN32
172  /* This function is more tricky than you may think at first.
173  Blindly copying permissions may permit users to access the
174  destination file who didn't have permission to access the
175  source file. */
176 
177 #ifdef NOTYET /* XXX Fileno used by Fchmod/Fchown needs work. */
178  /* Try changing the owner of the file. If we aren't root or the owner
179  isn't already us, fchown() probably doesn't succeed. We warn
180  about failing fchown() only if we are root. */
181  if (Fchown(z->ofd, z->isb.st_uid, -1) && (geteuid() == 0))
182  rpmlog(RPMLOG_WARNING, _("%s: Cannot set the file owner: %s\n"),
183  zq->ofn, strerror(errno));
184 
185  { mode_t mode;
186 
187  if (Fchown(z->ofd, -1, z->isb.st_gid)) {
188  rpmlog(RPMLOG_WARNING, _("%s: Cannot set the file group: %s\n"),
189  zq->ofn, strerror(errno));
190  /* We can still safely copy some additional permissions:
191  `group' must be at least as strict as `other' and
192  also vice versa.
193 
194  NOTE: After this, the owner of the source file may
195  get additional permissions. This shouldn't be too bad,
196  because the owner would have had permission to chmod
197  the original file anyway. */
198  mode = ((z->isb.st_mode & 0070) >> 3)
199  & (z->isb.st_mode & 0007);
200  mode = (z->isb.st_mode & 0700) | (mode << 3) | mode;
201  } else {
202  /* Drop the setuid, setgid, and sticky bits. */
203  mode = z->isb.st_mode & 0777;
204  }
205 
206  if (Fchmod(z->ofd, mode))
207  rpmlog(RPMLOG_WARNING, _("%s: Cannot set the file permissions: %s\n"),
208  zq->ofn, strerror(errno));
209  }
210 #endif
211 #endif
212 
213  /* Copy the timestamps. We have several possible ways to do this, of
214  which some are better in both security and precision.
215 
216  First, get the nanosecond part of the timestamps. As of writing,
217  it's not standardized by POSIX, and there are several names for
218  the same thing in struct stat. */
219  { long atime_nsec;
220  long mtime_nsec;
221 
222 # if defined(HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC)
223  /* GNU and Solaris */
224  atime_nsec = z->isb.st_atim.tv_nsec;
225  mtime_nsec = z->isb.st_mtim.tv_nsec;
226 
227 # elif defined(HAVE_STRUCT_STAT_ST_ATIMESPEC_TV_NSEC)
228  /* BSD */
229  atime_nsec = z->isb.st_atimespec.tv_nsec;
230  mtime_nsec = z->isb.st_mtimespec.tv_nsec;
231 
232 # elif defined(HAVE_STRUCT_STAT_ST_ATIMENSEC)
233  /* GNU and BSD without extensions */
234  atime_nsec = z->isb.st_atimensec;
235  mtime_nsec = z->isb.st_mtimensec;
236 
237 # elif defined(HAVE_STRUCT_STAT_ST_UATIME)
238  /* Tru64 */
239  atime_nsec = z->isb.st_uatime * 1000;
240  mtime_nsec = z->isb.st_umtime * 1000;
241 
242 # elif defined(HAVE_STRUCT_STAT_ST_ATIM_ST__TIM_TV_NSEC)
243  /* UnixWare */
244  atime_nsec = z->isb.st_atim.st__tim.tv_nsec;
245  mtime_nsec = z->isb.st_mtim.st__tim.tv_nsec;
246 
247 # else
248  /* Safe fallback */
249  atime_nsec = 0;
250  mtime_nsec = 0;
251 # endif
252 
253  /* Construct a structure to hold the timestamps and call appropriate
254  function to set the timestamps. */
255 #if defined(HAVE_FUTIMENS)
256  /* Use nanosecond precision. */
257  { struct timespec tv[2];
258  tv[0].tv_sec = z->isb.st_atime;
259  tv[0].tv_nsec = atime_nsec;
260  tv[1].tv_sec = z->isb.st_mtime;
261  tv[1].tv_nsec = mtime_nsec;
262 
263  /* XXX Fileno onto libio FILE * is -1 so EBADF is returned. */
264  (void)futimens(Fileno(z->ofd), tv);
265  }
266 
267 #elif defined(HAVE_FUTIMES) || defined(HAVE_FUTIMESAT) || defined(HAVE_UTIMES)
268  /* Use microsecond precision. */
269  { struct timeval tv[2];
270  tv[0].tv_sec = z->isb.st_atime;
271  tv[0].tv_usec = atime_nsec / 1000;
272  tv[1].tv_sec = z->isb.st_mtime;
273  tv[1].tv_usec = mtime_nsec / 1000;
274 
275 # if defined(HAVE_FUTIMES)
276  /* XXX Fileno onto libio FILE * is -1 so EBADF is returned. */
277  (void)futimes(Fileno(z->ofd), tv);
278 # elif defined(HAVE_FUTIMESAT)
279  /* XXX Fileno onto libio FILE * is -1 so EBADF is returned. */
280  (void)futimesat(Fileno(z->ofd), NULL, tv);
281 # else
282  /* Argh, no function to use a file descriptor to set the timestamp. */
283  (void)Utimes(zq->ofn, tv);
284 # endif
285  }
286 
287 #elif defined(HAVE_UTIME)
288  /* Use one-second precision. utime() doesn't support using file
289  descriptor either. Some systems have broken utime() prototype
290  so don't make this const. */
291  { struct utimbuf buf = {
292  .actime = z->isb.st_atime,
293  .modtime = z->isb.st_mtime,
294  };
295 
296  /* Avoid warnings. */
297  (void)atime_nsec;
298  (void)mtime_nsec;
299 
300  (void)Utime(zq->ofn, &buf);
301  }
302 #endif
303  }
304 
305  return;
306 }
307 
308 /*==============================================================*/
309 
310 #if defined(HAVE_PHYSMEM_SYSCTL) /* HAVE_SYS_SYSCTL_H */
311 #include <sys/sysctl.h>
312 #endif
313 
314 static rpmuint64_t physmem(void)
315  /*@*/
316 {
317  rpmuint64_t ret = 0;
318 
319 #if defined(HAVE_PHYSMEM_SYSCONF)
320  { const long pagesize = sysconf(_SC_PAGESIZE);
321  const long pages = sysconf(_SC_PHYS_PAGES);
322  if (pagesize != -1 || pages != -1)
323  ret = (rpmuint64_t)(pagesize) * (rpmuint64_t)(pages);
324  }
325 #elif defined(HAVE_PHYSMEM_SYSCTL)
326  { int name[2] = { CTL_HW, HW_PHYSMEM };
327  unsigned long mem;
328  size_t mem_ptr_size = sizeof(mem);
329  if (!sysctl(name, 2, &mem, &mem_ptr_size, NULL, 0)) {
330  if (mem_ptr_size != sizeof(mem)) {
331  if (mem_ptr_size == sizeof(unsigned int))
332  ret = *(unsigned int *)(&mem);
333  } else {
334  ret = mem;
335  }
336  }
337  }
338 #endif
339  return ret;
340 }
341 
342 #if defined(HAVE_NCPU_SYSCTL) /* HAVE_SYS_SYSCTL_H */
343 #include <sys/sysctl.h>
344 #endif
345 
346 static void
348  /*@modifies z @*/
349 {
350  rpmzQueue zq = z->zq;
351 
352 #if defined(HAVE_NCPU_SYSCONF)
353  { const long cpus = sysconf(_SC_NPROCESSORS_ONLN);
354  if (cpus > 0)
355  zq->threads = (size_t)(cpus);
356  }
357 
358 #elif defined(HAVE_NCPU_SYSCTL)
359  { int name[2] = { CTL_HW, HW_NCPU };
360  int cpus;
361  size_t cpus_size = sizeof(cpus);
362  if (!sysctl(name, 2, &cpus, &cpus_size, NULL, 0)
363  && cpus_size == sizeof(cpus) && cpus > 0)
364  z->threads = (size_t)(cpus);
365  }
366 #endif
367 
368 #if defined(_SC_THREAD_THREADS_MAX)
369  { const long threads_max = sysconf(_SC_THREAD_THREADS_MAX);
370  if (threads_max > 0 && (unsigned)(threads_max) < zq->threads)
371  zq->threads = (unsigned)(threads_max);
372  }
373 #elif defined(PTHREAD_THREADS_MAX)
374  if (zq->threads > PTHREAD_THREADS_MAX)
375  zq->threads = PTHREAD_THREADS_MAX;
376 #endif
377 
378  return;
379 }
380 
381 static void
383  /*@globals memlimit_decoder, memlimit_encoder @*/
384  /*@modifies memlimit_decoder, memlimit_encoder @*/
385 {
386  z->mem = physmem();
387 
388  /* Assume 16MB as minimum memory. */
389  if (z->mem == 0)
390  z->mem = 16 * 1024 * 1024;
391 
392  /* Use 90% of RAM when encoding, 33% when decoding. */
393  z->memlimit_encoder = z->mem - z->mem / 10;
394  z->memlimit_decoder = z->mem / 3;
395  return;
396 }
397 
398 static void
400 {
401  hw_memlimit_init(z);
402  hw_cores(z);
403  return;
404 }
405 
406 /*==============================================================*/
407 
408 /* XXX todo: add zlib/zip and other common suffixes. */
409 /*@unchecked@*/ /*@observer@*/
410 static struct suffixPairs_s {
412 /*@null@*/
413  const char * csuffix;
414 /*@relnull@*/
415  const char * usuffix;
416 } suffixPairs[] = {
417  { RPMZ_FORMAT_XZ, ".xz", "" },
418  { RPMZ_FORMAT_XZ, ".txz", ".tar" },
419  { RPMZ_FORMAT_LZMA, ".lzma","" },
420  { RPMZ_FORMAT_LZMA, ".tlz", ".tar" },
421  { RPMZ_FORMAT_GZIP, ".gz", "" },
422  { RPMZ_FORMAT_GZIP, ".tgz", ".tar" },
423  { RPMZ_FORMAT_ZLIB, ".zz", "" },
424  { RPMZ_FORMAT_ZLIB, ".tzz", ".tar" },
425  { RPMZ_FORMAT_ZIP2, ".zip", "" }, /* XXX zip3 from pigz? */
426 #ifdef NOTYET
427  { RPMZ_FORMAT_ZIP2, ".tgz", ".tar" },
428 #endif
429  { RPMZ_FORMAT_BZIP2, ".bz2", "" },
430  { RPMZ_FORMAT_RAW, NULL, NULL }
431 };
432 
439 static int chkSuffix(const char * fn, const char * suffix)
440  /*@*/
441 {
442  size_t flen = strlen(fn);
443  size_t slen = strlen(suffix);
444  int rc = (flen > slen && !strcmp(fn + flen - slen, suffix));
445 if (_debug)
446 fprintf(stderr, "\tchk(%s,%s) ret %d\n", fn, suffix, rc);
447  return rc;
448 }
449 
457 static char * changeSuffix(const char * fn,
458  /*@null@*/ const char * old,
459  /*@null@*/ const char * new)
460  /*@*/
461 {
462  size_t nfn = strlen(fn);
463  size_t nos = (old ? strlen(old) : 0);
464  size_t nns = (new ? strlen(new) : 0);
465  char * t = xmalloc(nfn - nos + nns + 1);
466 
467  { char * te = t;
468 
469  strncpy(te, fn, (nfn - nos));
470  te += (nfn - nos);
471  if (new)
472  te = stpcpy(te, new);
473  *te = '\0';
474  }
475 
476  return t;
477 }
478 
484 static const char * uncompressedFN(rpmz z)
485  /*@*/
486 {
487  struct suffixPairs_s * sp;
488  const char * fn = z->ifn;
489  const char * t = NULL;
490 
491  for (sp = suffixPairs; sp->csuffix != NULL; sp++) {
492  if (z->format != sp->format)
493  continue;
494  if (!chkSuffix(fn, sp->csuffix))
495  continue;
496  t = changeSuffix(fn, sp->csuffix, sp->usuffix);
497  break;
498  }
499 
500  if (t == NULL)
501  t = xstrdup(fn);
502 
503 if (_debug)
504 fprintf(stderr, "==> uncompressedFN: %s\n", t);
505  return t;
506 }
507 
513 static const char * compressedFN(rpmz z)
514  /*@*/
515 {
516  struct suffixPairs_s * sp;
517  const char * fn = z->ifn;
518  const char * t = NULL;
519 
520  for (sp = suffixPairs; sp->csuffix != NULL; sp++) {
521  if (z->format != sp->format || *sp->usuffix == '\0')
522  continue;
523  if (!chkSuffix(fn, sp->usuffix))
524  continue;
525  t = changeSuffix(fn, sp->usuffix, sp->csuffix);
526  break;
527  }
528 
529  if (t == NULL)
530  t = rpmGetPath(fn, (z->suffix ? z->suffix : z->osuffix), NULL);
531 
532 if (_debug)
533 fprintf(stderr, "==> compressedFN: %s (suffix %s osuffix %s)\n", t, z->suffix, z->osuffix);
534  return t;
535 }
536 
537 /* forward ref */
538 static rpmRC rpmzProcess(rpmz z, /*@null@*/ const char * ifn)
539  /*@modifies z @*/;
540 
541 static rpmRC rpmzFini(rpmz z, rpmRC rc)
542 {
543  rpmzQueue zq = z->zq;
544  int xx;
545 
546  /* XXX mask signals */
547  if (z->ofd != NULL) {
548  xx = Fflush(z->ofd);
549 
550  /* Timestamp output file same as input. */
551  if (zq->ofn != NULL && strcmp(zq->ofn, z->stdout_fn))
552  io_copy_attrs(z); /* XXX add error return */
553  if ((xx = Fclose(z->ofd)) != 0) {
554  rpmlog(RPMLOG_ERR, _("%s: Closing output file failed: %s\n"),
555  zq->ofn, strerror(errno));
556  rc = RPMRC_FAIL;
557  }
558  z->ofd = NULL;
559  }
560  if (z->ifd != NULL) {
561  if ((xx = Fclose(z->ifd)) != 0) {
562  rpmlog(RPMLOG_ERR, _("%s: Closing input file failed: %s\n"),
563  z->ifn, strerror(errno));
564  rc = RPMRC_FAIL;
565  }
566  z->ifd = NULL;
567  }
568 
569  /* Clean up input/output files as needed. */
570  switch (rc) {
571  default:
572  break;
573  case RPMRC_FAIL:
574  if (zq->ofn != NULL && strcmp(zq->ofn, z->stdout_fn)) {
575  xx = Unlink(zq->ofn);
576 if (_debug)
577 fprintf(stderr, "==> Unlink(%s) FAIL\n", zq->ofn);
578  }
579  break;
580  case RPMRC_OK:
581  if (!F_ISSET(z->flags, KEEP) && z->ifn != z->stdin_fn) {
582  io_unlink(z->ifn, &z->isb);
583 if (_debug)
584 fprintf(stderr, "==> Unlink(%s)\n", z->ifn);
585  }
586  break;
587  }
588 
589  zq->ofn = _free(zq->ofn);
590 
591  return rc;
592 }
593 
594 static rpmRC rpmzInit(rpmz z, /*@null@*/ const char * ifn)
595  /*@*/
596 {
597  rpmzQueue zq = z->zq;
598  rpmRC rc = RPMRC_FAIL;
599 
600 if (_debug)
601 fprintf(stderr, "==> rpmzInit(%p) ifn %s ofmode %s\n", z, z->ifn, z->ofmode);
602 
603  z->ifn = ifn; /* XXX ifn[] for rpmzProcess() append w --recurse */
604 
605  if (ifn == NULL) {
606  z->ifn = z->stdin_fn;
607  switch (z->mode) {
608  default:
609  break;
610  case RPMZ_MODE_COMPRESS:
611  z->ifd = fdDup(STDIN_FILENO);
612  break;
614  z->ifd = z->idio->_fdopen(fdDup(STDIN_FILENO), z->ifmode);
615  break;
616  }
617  } else {
618  struct stat * st = &z->isb;
619 
620  /* set input file name (already set if recursed here) */
621  if (ifn != z->_ifn) {
622 /*@-mayaliasunique@*/
623  strncpy(z->_ifn, ifn, sizeof(z->_ifn));
624 /*@=mayaliasunique@*/
625 assert(z->_ifn[sizeof(z->_ifn) - 1] == '\0');
626  z->ifn = z->_ifn;
627  }
628  if (Lstat(z->ifn, &z->isb) < 0) {
629 #ifdef EOVERFLOW
630 assert(errno != EOVERFLOW);
631 assert(errno != EFBIG);
632 #endif
633  fprintf(stderr, "%s: input %s does not exist, skipping\n",
634  __progname, z->ifn);
635  goto exit;
636  }
637  if (!S_ISREG(st->st_mode) && !S_ISLNK(st->st_mode) && !S_ISDIR(st->st_mode))
638  {
639  fprintf(stderr, "%s: input %s is a special file or device -- skipping\n",
640  __progname, z->ifn);
641  goto exit;
642  }
643  if (S_ISLNK(st->st_mode) && !F_ISSET(z->flags, SYMLINKS)) {
644  fprintf(stderr, "%s: input %s is a symbolic link -- skipping\n",
645  __progname, z->ifn);
646  goto exit;
647  }
648 
649  /* Recurse into directory */
650  if (S_ISDIR(st->st_mode)) {
651  struct stat sb = *st; /* structure assignment. */
652  struct dirent * dp;
653  DIR * dir;
654  ARGV_t av = NULL;
655  size_t len;
656  char * te;
657  int xx;
658  int i;
659 
660  if (!F_ISSET(z->flags, RECURSE)) {
661  fprintf(stderr, "%s: input %s is a directory -- skipping\n",
662  __progname, z->_ifn);
663  goto exit;
664  }
665  len = strlen(z->_ifn);
666  te = z->_ifn + len;
667  if ((dir = Opendir(z->_ifn)) == NULL)
668  goto exit;
669  while ((dp = Readdir(dir)) != NULL) {
670  if (dp->d_name[0] == '\0' ||
671  (dp->d_name[0] == '.' && (dp->d_name[1] == '\0' ||
672  (dp->d_name[1] == '.' && dp->d_name[2] == '\0'))))
673  continue;
674  xx = argvAdd(&av, dp->d_name);
675  }
676  xx = Closedir(dir);
677  if (av != NULL)
678  for (i = 0; av[i] != NULL; i++) {
679  *te = '/';
680  strncpy(te+1, av[i], sizeof(z->_ifn) - len - 1);
681 assert(z->_ifn[sizeof(z->_ifn) - 1] == '\0');
682  (void) rpmzProcess(z, z->_ifn);
683  *te = '\0';
684  }
685  av = argvFree(av);
686  *st = sb; /* structure assignment. */
687  rc = RPMRC_OK;
688  goto exit;
689  }
690 
691  /* Open input file. */
692  switch (z->mode) {
693  default:
694  break;
695  case RPMZ_MODE_COMPRESS:
696  z->ifd = Fopen(z->ifn, z->ifmode);
697  break;
699  z->ifd = z->idio->_fopen(z->ifn, z->ifmode);
700  fdFree(z->ifd, NULL); /* XXX adjust refcounts. */
701  break;
702  }
703  }
704  if (z->ifd == NULL || Ferror(z->ifd)) {
705  fprintf(stderr, "%s: can't open %s\n", __progname, z->ifn);
706  goto exit;
707  }
708 
709  if (F_ISSET(z->flags, STDOUT)) {
710  zq->ofn = xstrdup(z->stdout_fn);
711  switch (z->mode) {
712  default:
713  break;
714  case RPMZ_MODE_COMPRESS:
715  z->ofd = z->odio->_fdopen(fdDup(STDOUT_FILENO), z->ofmode);
716  break;
718  z->ofd = fdDup(STDOUT_FILENO);
719  break;
720  }
721  } else {
722  if (z->ifn == z->stdin_fn) /* XXX error needed here. */
723  goto exit;
724 
725  /* Open output file. */
726  switch (z->mode) {
727  default:
728  break;
729  case RPMZ_MODE_COMPRESS:
730  zq->ofn = compressedFN(z);
731  if (!F_ISSET(z->flags, OVERWRITE) && Stat(zq->ofn, &z->osb) == 0) {
732  fprintf(stderr, "%s: output file %s already exists\n",
733  __progname, zq->ofn);
734  /* XXX TODO: ok to overwrite(y/N)? */
735  goto exit;
736  }
737  z->ofd = z->odio->_fopen(zq->ofn, z->ofmode);
738  fdFree(z->ofd, NULL); /* XXX adjust refcounts. */
739  break;
741  zq->ofn = uncompressedFN(z);
742  if (!F_ISSET(z->flags, OVERWRITE) && Stat(zq->ofn, &z->osb) == 0) {
743  fprintf(stderr, "%s: output file %s already exists\n",
744  __progname, zq->ofn);
745  /* XXX TODO: ok to overwrite(y/N)? */
746  goto exit;
747  }
748  z->ofd = Fopen(zq->ofn, z->ofmode);
749  break;
750  }
751  }
752  if (z->ofd == NULL || Ferror(z->ofd)) {
753  fprintf(stderr, "%s: can't open %s\n", __progname, zq->ofn);
754  goto exit;
755  }
756 
757  rc = RPMRC_OK;
758 
759 exit:
760  return rc;
761 }
762 
763 /*
764  * Copy input to output.
765  */
766 static rpmRC rpmzCopy(rpmz z, rpmiob iob)
767  /*@*/
768 {
769  for (;;) {
770  iob->blen = Fread(iob->b, 1, iob->allocated, z->ifd);
771 
772  if (Ferror(z->ifd))
773  return RPMRC_FAIL;
774 
775  if (iob->blen == 0) break;
776 
777  if (Fwrite(iob->b, 1, iob->blen, z->ofd) != iob->blen)
778  return RPMRC_FAIL;
779  }
780  return RPMRC_OK;
781 }
782 
783 /*
784  * Copy input to output.
785  */
786 static rpmRC rpmzProcess(rpmz z, /*@null@*/ const char * ifn)
787 {
788  rpmRC rc;
789 
790  rc = rpmzInit(z, ifn);
791  if (rc == RPMRC_OK && z->ifd != NULL && z->ofd != NULL)
792  rc = rpmzCopy(z, z->iob);
793  rc = rpmzFini(z, rc);
794  return rc;
795 }
796 
797 /*==============================================================*/
798 /*@unchecked@*/
800 
801 static void signals_init(void)
802  /*@*/
803 {
804  int xx;
805 
806  if (signals_init_count++ == 0) {
807  xx = rpmsqEnable(SIGHUP, NULL);
808  xx = rpmsqEnable(SIGINT, NULL);
809  xx = rpmsqEnable(SIGTERM, NULL);
810  xx = rpmsqEnable(SIGQUIT, NULL);
811  xx = rpmsqEnable(SIGPIPE, NULL);
812  xx = rpmsqEnable(SIGXCPU, NULL);
813  xx = rpmsqEnable(SIGXFSZ, NULL);
814  }
815 }
816 
817 static void signals_fini(void)
818  /*@*/
819 {
820  int xx;
821 
822  if (--signals_init_count == 0) {
823  xx = rpmsqEnable(-SIGHUP, NULL);
824  xx = rpmsqEnable(-SIGINT, NULL);
825  xx = rpmsqEnable(-SIGTERM, NULL);
826  xx = rpmsqEnable(-SIGQUIT, NULL);
827  xx = rpmsqEnable(-SIGPIPE, NULL);
828  xx = rpmsqEnable(-SIGXCPU, NULL);
829  xx = rpmsqEnable(-SIGXFSZ, NULL);
830  }
831 }
832 
833 static int signals_terminating(int terminate)
834  /*@*/
835 {
836  static int terminating = 0;
837 
838  if (terminating) return 1;
839 
840  if (sigismember(&rpmsqCaught, SIGHUP)
841  || sigismember(&rpmsqCaught, SIGINT)
842  || sigismember(&rpmsqCaught, SIGTERM)
843  || sigismember(&rpmsqCaught, SIGQUIT)
844  || sigismember(&rpmsqCaught, SIGPIPE)
845  || sigismember(&rpmsqCaught, SIGXCPU)
846  || sigismember(&rpmsqCaught, SIGXFSZ)
847  || terminate)
848  terminating = 1;
849  return terminating;
850 }
851 
852 #ifdef NOTYET
853 /*@unchecked@*/
854 static int signals_block_count;
855 
856 static void
857 signals_block(void)
858  /*@globals errno, signals_block_count @*/
859  /*@modifies errno, signals_block_count @*/
860 {
861  if (signals_block_count++ == 0) {
862  const int saved_errno = errno;
863  mythread_sigmask(SIG_BLOCK, &hooked_signals, NULL);
864  errno = saved_errno;
865  }
866  return;
867 }
868 
869 static void
870 signals_unblock(void)
871  /*@globals errno, signals_block_count @*/
872  /*@modifies errno, signals_block_count @*/
873 {
874  assert(signals_block_count > 0);
875 
876  if (--signals_block_count == 0) {
877  const int saved_errno = errno;
878  mythread_sigmask(SIG_UNBLOCK, &hooked_signals, NULL);
879  errno = saved_errno;
880  }
881  return;
882 }
883 #endif
884 
885 static void signals_exit(void)
886  /*@*/
887 {
888 #ifdef NOTYET
889  const int sig = exit_signal;
890 
891  if (sig != 0) {
892  struct sigaction sa;
893  sa.sa_handler = SIG_DFL;
894  sigfillset(&sa.sa_mask);
895  sa.sa_flags = 0;
896  sigaction(sig, &sa, NULL);
897  raise(exit_signal);
898  }
899 
900  return;
901 #else
902  signals_fini();
903 #endif
904 }
905 
906 /*==============================================================*/
907 
908 typedef struct {
909  const char *name;
911 } name_id_map;
912 
913 typedef struct {
914  const char *name;
915  const name_id_map *map;
918 } option_map;
919 
920 /* Parses option=value pairs that are separated with colons, semicolons,
921  or commas: opt=val:opt=val;opt=val,opt=val
922 
923  Each option is a string, that is converted to an integer using the
924  index where the option string is in the array.
925 
926  Value can be either a number with minimum and maximum value limit, or
927  a string-id map mapping a list of possible string values to integers.
928 
929  When parsing both option and value succeed, a filter-specific function
930  is called, which should update the given value to filter-specific
931  options structure.
932 
933  \param str String containing the options from the command line
934  \param opts Filter-specific option map
935  \param set Filter-specific function to update filter_options
936  \param filter_options Pointer to filter-specific options structure
937 
938  \return Returns only if no errors occur.
939 */
940 static void
941 parse_options(const char *str, const option_map *opts,
942  void (*set)(void *filter_options,
943  rpmuint32_t key, rpmuint64_t value),
944  void *filter_options)
945  /*@*/
946 {
947  char * s;
948  char *name;
949 
950  if (str == NULL || str[0] == '\0')
951  return;
952 
953  s = xstrdup(str);
954  name = s;
955 
956  while (1) {
957  char *split = strchr(name, ',');
958  char *value;
959  int found;
960  size_t i;
961 
962  if (split != NULL)
963  *split = '\0';
964 
965  value = strchr(name, '=');
966  if (value != NULL)
967  *value++ = '\0';
968 
969  if (value == NULL || value[0] == '\0') {
970  fprintf(stderr, _("%s: %s: Options must be `name=value' pairs separated with commas\n"),
971  __progname, str);
972  /*@-exitarg@*/ exit(2); /*@=exitarg@*/
973  }
974 
975  /* Look for the option name from the option map. */
976  found = 0;
977  for (i = 0; opts[i].name != NULL; ++i) {
978  if (strcmp(name, opts[i].name) != 0)
979  continue;
980 
981  if (opts[i].map == NULL) {
982  /* value is an integer. */
983  rpmuint64_t v;
984 #ifdef NOTYET
985  v = str_to_uint64(name, value, opts[i].min, opts[i].max);
986 #else
987  v = strtoull(value, NULL, 0);
988 #endif
989  set(filter_options, i, v);
990  } else {
991  /* value is a string which we should map
992  to an integer. */
993  size_t j;
994  for (j = 0; opts[i].map[j].name != NULL; ++j) {
995  if (strcmp(opts[i].map[j].name, value) == 0)
996  break;
997  }
998 
999  if (opts[i].map[j].name == NULL) {
1000  fprintf(stderr, _("%s: %s: Invalid option value\n"),
1001  __progname, value);
1002  /*@-exitarg@*/ exit(2); /*@=exitarg@*/
1003  }
1004 
1005  set(filter_options, i, opts[i].map[j].id);
1006  }
1007 
1008  found = 1;
1009  break;
1010  }
1011 
1012  if (!found) {
1013  fprintf(stderr, _("%s: %s: Invalid option name\n"), __progname, name);
1014  /*@-exitarg@*/ exit(2); /*@=exitarg@*/
1015  }
1016 
1017  if (split == NULL)
1018  break;
1019 
1020  name = split + 1;
1021  }
1022 
1023  s = _free(s);
1024  return;
1025 }
1026 
1027 /* ===== Subblock ===== */
1028 enum {
1032 };
1033 
1034 static void
1036  /*@*/
1037 {
1038  lzma_options_subblock *opt = options;
1039 
1040  switch (key) {
1041  case OPT_SIZE: opt->subblock_data_size = value; break;
1042  case OPT_RLE: opt->rle = value; break;
1043  case OPT_ALIGN: opt->alignment = value; break;
1044  }
1045 }
1046 
1047 static lzma_options_subblock *
1048 options_subblock(const char *str)
1049  /*@*/
1050 {
1051  static const option_map opts[] = {
1052  { "size", NULL, LZMA_SUBBLOCK_DATA_SIZE_MIN,
1053  LZMA_SUBBLOCK_DATA_SIZE_MAX },
1054  { "rle", NULL, LZMA_SUBBLOCK_RLE_OFF,
1055  LZMA_SUBBLOCK_RLE_MAX },
1056  { "align",NULL, LZMA_SUBBLOCK_ALIGNMENT_MIN,
1057  LZMA_SUBBLOCK_ALIGNMENT_MAX },
1058  { NULL, NULL, 0, 0 }
1059  };
1060 
1061  lzma_options_subblock *options = xmalloc(sizeof(lzma_options_subblock));
1062  options->allow_subfilters = 0;
1063  options->alignment = LZMA_SUBBLOCK_ALIGNMENT_DEFAULT;
1064  options->subblock_data_size = LZMA_SUBBLOCK_DATA_SIZE_DEFAULT;
1065  options->rle = LZMA_SUBBLOCK_RLE_OFF;
1066 
1067  parse_options(str, opts, &set_subblock, options);
1068 
1069  return options;
1070 }
1071 
1072 /* ===== Delta ===== */
1073 
1074 enum {
1076 };
1077 
1078 static void
1080  /*@*/
1081 {
1082  lzma_options_delta *opt = options;
1083  switch (key) {
1084  case OPT_DIST: opt->dist = value; break;
1085  }
1086 }
1087 
1088 static lzma_options_delta *
1089 options_delta(const char *str)
1090 {
1091  static const option_map opts[] = {
1092  { "dist", NULL, LZMA_DELTA_DIST_MIN,
1093  LZMA_DELTA_DIST_MAX },
1094  { NULL, NULL, 0, 0 }
1095  };
1096 
1097  lzma_options_delta *options = xmalloc(sizeof(lzma_options_delta));
1098  /* It's hard to give a useful default for this. */
1099  options->type = LZMA_DELTA_TYPE_BYTE;
1100  options->dist = LZMA_DELTA_DIST_MIN;
1101 
1102  parse_options(str, opts, &set_delta, options);
1103 
1104  return options;
1105 }
1106 
1107 /* ===== LZMA ===== */
1108 enum {
1118 };
1119 
1120 static void
1122  /*@*/
1123 {
1124  lzma_options_lzma *opt = options;
1125 
1126  switch (key) {
1127  case OPT_PRESET:
1128  if (lzma_lzma_preset(options, (uint32_t)(value))) {
1129  fprintf(stderr, _("LZMA1/LZMA2 preset %u is not supported\n"),
1130  (unsigned int)(value));
1131  /*@-exitarg@*/ exit(2); /*@=exitarg@*/
1132  }
1133  break;
1134  case OPT_DICT: opt->dict_size = value; break;
1135  case OPT_LC: opt->lc = value; break;
1136  case OPT_LP: opt->lp = value; break;
1137  case OPT_PB: opt->pb = value; break;
1138  case OPT_MODE: opt->mode = value; break;
1139  case OPT_NICE: opt->nice_len = value; break;
1140  case OPT_MF: opt->mf = value; break;
1141  case OPT_DEPTH: opt->depth = value; break;
1142  }
1143 }
1144 
1145 static lzma_options_lzma *
1146 options_lzma(const char *str)
1147 {
1148  /*@unchecked@*/ /*@observer@*/
1149  static const name_id_map modes[] = {
1150  { "fast", LZMA_MODE_FAST },
1151  { "normal", LZMA_MODE_NORMAL },
1152  { NULL, 0 }
1153  };
1154 
1155  /*@unchecked@*/ /*@observer@*/
1156  static const name_id_map mfs[] = {
1157  { "hc3", LZMA_MF_HC3 },
1158  { "hc4", LZMA_MF_HC4 },
1159  { "bt2", LZMA_MF_BT2 },
1160  { "bt3", LZMA_MF_BT3 },
1161  { "bt4", LZMA_MF_BT4 },
1162  { NULL, 0 }
1163  };
1164 
1165  /*@unchecked@*/ /*@observer@*/
1166  static const option_map opts[] = {
1167  { "preset", NULL, 1, 9 },
1168  { "dict", NULL, LZMA_DICT_SIZE_MIN,
1169  (UINT32_C(1) << 30) + (UINT32_C(1) << 29) },
1170  { "lc", NULL, LZMA_LCLP_MIN, LZMA_LCLP_MAX },
1171  { "lp", NULL, LZMA_LCLP_MIN, LZMA_LCLP_MAX },
1172  { "pb", NULL, LZMA_PB_MIN, LZMA_PB_MAX },
1173  { "mode", modes, 0, 0 },
1174  { "nice", NULL, 2, 273 },
1175  { "mf", mfs, 0, 0 },
1176  { "depth", NULL, 0, UINT32_MAX },
1177  { NULL, NULL, 0, 0 }
1178  };
1179 
1180  lzma_options_lzma *options = xmalloc(sizeof(lzma_options_lzma));
1181 
1182  options->dict_size = LZMA_DICT_SIZE_DEFAULT;
1183  options->preset_dict = NULL;
1184  options->preset_dict_size = 0,
1185  options->lc = LZMA_LC_DEFAULT;
1186  options->lp = LZMA_LP_DEFAULT;
1187  options->pb = LZMA_PB_DEFAULT;
1188  options->persistent = 0;
1189  options->mode = LZMA_MODE_NORMAL;
1190  options->nice_len = 64;
1191  options->mf = LZMA_MF_BT4;
1192  options->depth = 0;
1193 
1194  parse_options(str, opts, &set_lzma, options);
1195 
1196  return options;
1197 }
1198 
1199 static void
1200 coder_add_filter(rpmz z, lzma_vli id, void *options)
1201  /*@modifies z @*/
1202 {
1203  if (z->_filters_count == LZMA_FILTERS_MAX) {
1204  fprintf(stderr, _("%s: Maximum number of filters is %d\n"),
1205  __progname, LZMA_FILTERS_MAX);
1206  /*@-exitarg@*/ exit(2); /*@=exitarg@*/
1207  }
1208 
1209  z->_filters[z->_filters_count].id = id;
1210  z->_filters[z->_filters_count].options = options;
1211  z->_filters_count++;
1212 
1213  return;
1214 }
1215 
1216 static rpmuint64_t
1218  /*@*/
1219 {
1220  return z->memlimit_custom != 0 ? z->memlimit_custom : z->memlimit_encoder;
1221 }
1222 
1223 static rpmuint64_t
1225  /*@*/
1226 {
1227  return z->memlimit_custom != 0 ? z->memlimit_custom : z->memlimit_decoder;
1228 }
1229 
1230 static void
1231 message_filters(int code, const lzma_filter *filters)
1232 {
1233  char t[BUFSIZ];
1234  char * te = t;
1235  unsigned pri = RPMLOG_PRI(code);
1236  unsigned mask = RPMLOG_MASK(pri);
1237  size_t i;
1238 
1239  if ((mask & rpmlogSetMask(0)) == 0)
1240  return;
1241 
1242  *te = '\0';
1243  te = stpcpy( stpcpy(te, __progname), ": Filter chain:");
1244 
1245  for (i = 0; filters[i].id != LZMA_VLI_UNKNOWN; ++i) {
1246  te = stpcpy(te, " --");
1247 
1248  switch (filters[i].id) {
1249  case LZMA_FILTER_LZMA1:
1250  case LZMA_FILTER_LZMA2: {
1251  const lzma_options_lzma *opt = filters[i].options;
1252  const char *lzmaver;
1253  const char *mode;
1254  const char *mf;
1255 
1256  switch (opt->mode) {
1257  case LZMA_MODE_FAST: mode = "fast"; break;
1258  case LZMA_MODE_NORMAL: mode = "normal"; break;
1259  default: mode = "UNKNOWN"; break;
1260  }
1261 
1262  switch (opt->mf) {
1263  case LZMA_MF_HC3: mf = "hc3"; break;
1264  case LZMA_MF_HC4: mf = "hc4"; break;
1265  case LZMA_MF_BT2: mf = "bt2"; break;
1266  case LZMA_MF_BT3: mf = "bt3"; break;
1267  case LZMA_MF_BT4: mf = "bt4"; break;
1268  default: mf = "UNKNOWN"; break;
1269  }
1270 
1271  lzmaver = (filters[i].id == LZMA_FILTER_LZMA2 ? "2" : "1");
1272  te = stpcpy( stpcpy(te, "lzma"), lzmaver);
1273  te = stpcpy(te, "=dict=");
1274  sprintf(te, "%u", (unsigned)opt->dict_size);
1275  te += strlen(te);
1276  te = stpcpy(te, ",lc=");
1277  sprintf(te, "%u", (unsigned)opt->lc);
1278  te += strlen(te);
1279  te = stpcpy(te, ",lp=");
1280  sprintf(te, "%u", (unsigned)opt->lp);
1281  te += strlen(te);
1282  te = stpcpy(te, ",pb=");
1283  sprintf(te, "%u", (unsigned)opt->pb);
1284  te += strlen(te);
1285  te = stpcpy( stpcpy(te, ",mode="), mode);
1286  te = stpcpy(te, ",nice=");
1287  sprintf(te, "%u", (unsigned)opt->nice_len);
1288  te += strlen(te);
1289  te = stpcpy( stpcpy(te, ",mf="), mf);
1290  te = stpcpy(te, ",depth=");
1291  sprintf(te, "%u", (unsigned)opt->depth);
1292  te += strlen(te);
1293  break;
1294  }
1295 
1296  case LZMA_FILTER_X86: te = stpcpy(te, "x86"); break;
1297  case LZMA_FILTER_POWERPC: te = stpcpy(te, "powerpc"); break;
1298  case LZMA_FILTER_IA64: te = stpcpy(te, "ia64"); break;
1299  case LZMA_FILTER_ARM: te = stpcpy(te, "arm"); break;
1300  case LZMA_FILTER_ARMTHUMB: te = stpcpy(te, "armthumb"); break;
1301  case LZMA_FILTER_SPARC: te = stpcpy(te, "sparc"); break;
1302  case LZMA_FILTER_DELTA: {
1303  const lzma_options_delta *opt = filters[i].options;
1304  te = stpcpy(te, "delta=dist=");
1305  sprintf(te, "%u", (unsigned)opt->dist);
1306  te += strlen(te);
1307  break;
1308  }
1309 
1310  default: te = stpcpy(te, "UNKNOWN"); break;
1311  }
1312  }
1313  *te = '\0';
1314  rpmlog(code, "%s\n", t);
1315  return;
1316 }
1317 
1318 static void
1319 memlimit_too_small(rpmuint64_t memory_usage, rpmuint64_t memory_limit)
1320  /*@*/
1321 {
1322  rpmlog(RPMLOG_CRIT, _("Memory usage limit (%llu MiB) is too small for the given filter setup (%llu MiB)\n"),
1323  (unsigned long long)(memory_limit >> 20),
1324  (unsigned long long)(memory_usage >> 20));
1325 /*@notreached@*/
1326  exit(EXIT_FAILURE);
1327 }
1328 
1329 static void
1331  /*@globals preset_default, preset_number @*/
1332  /*@modifies z, preset_default, preset_number @*/
1333 {
1334  rpmzQueue zq = z->zq;
1335 
1336  /* Options for LZMA1 or LZMA2 in case we are using a preset. */
1337  rpmuint64_t memory_usage;
1338  rpmuint64_t memory_limit;
1339  size_t thread_limit;
1340 
1341  /* Add the per-architecture filters. */
1342  if (F_ISSET(z->flags, X86))
1343  coder_add_filter(z, LZMA_FILTER_X86, NULL);
1344  if (F_ISSET(z->flags, POWERPC))
1345  coder_add_filter(z, LZMA_FILTER_POWERPC, NULL);
1346  if (F_ISSET(z->flags, IA64))
1347  coder_add_filter(z, LZMA_FILTER_IA64, NULL);
1348  if (F_ISSET(z->flags, ARM))
1349  coder_add_filter(z, LZMA_FILTER_ARM, NULL);
1350  if (F_ISSET(z->flags, ARMTHUMB))
1351  coder_add_filter(z, LZMA_FILTER_ARMTHUMB, NULL);
1352  if (F_ISSET(z->flags, SPARC))
1353  coder_add_filter(z, LZMA_FILTER_SPARC, NULL);
1354 
1355  if (z->_filters_count == 0) {
1356  /* We are using a preset. This is not a good idea in raw mode
1357  except when playing around with things. Different versions
1358  of this software may use different options in presets, and
1359  thus make uncompressing the raw data difficult. */
1360  if (z->format == RPMZ_FORMAT_RAW) {
1361  /* The message is shown only if warnings are allowed
1362  but the exit status isn't changed. */
1363  rpmlog(RPMLOG_WARNING, _("Using a preset in raw mode is discouraged.\n"));
1364  rpmlog(RPMLOG_WARNING, _("The exact options of the presets may vary between software versions.\n"));
1365  }
1366 
1367  { size_t preset_number = z->level;
1368 
1369  /* Get the preset for LZMA1 or LZMA2. */
1370  if (F_ISSET(z->flags, EXTREME))
1371  preset_number |= LZMA_PRESET_EXTREME;
1372 
1373  if (lzma_lzma_preset(&z->_options, preset_number))
1374 assert(0);
1375  }
1376 
1377  /* Use LZMA2 except with --format=lzma we use LZMA1. */
1378  z->_filters[0].id = z->format == RPMZ_FORMAT_LZMA
1379  ? LZMA_FILTER_LZMA1 : LZMA_FILTER_LZMA2;
1380  z->_filters[0].options = &z->_options;
1381  z->_filters_count = 1;
1382  }
1383 #ifdef NOTYET
1384  else
1385  preset_default = false;
1386 #endif /* NOTYET */
1387 
1388  /* Terminate the filter options array. */
1389  z->_filters[z->_filters_count].id = LZMA_VLI_UNKNOWN;
1390 
1391  /* If we are using the LZMA_Alone format, allow exactly one filter
1392  which has to be LZMA. */
1393  if (z->format == RPMZ_FORMAT_LZMA && (z->_filters_count != 1
1394  || z->_filters[0].id != LZMA_FILTER_LZMA1))
1395  rpmlog(RPMLOG_CRIT, _("With --format=lzma only the LZMA1 filter is supported\n"));
1396 
1397  /* Print the selected filter chain. */
1398  message_filters(RPMLOG_DEBUG, z->_filters);
1399 
1400  /* If using --format=raw, we can be decoding. The memusage function
1401  also validates the filter chain and the options used for the
1402  filters. */
1403  if (z->mode == RPMZ_MODE_COMPRESS) {
1404  memory_usage = lzma_raw_encoder_memusage(z->_filters);
1405  memory_limit = hw_memlimit_encoder(z);
1406  } else {
1407  memory_usage = lzma_raw_decoder_memusage(z->_filters);
1408  memory_limit = hw_memlimit_decoder(z);
1409  }
1410 
1411  if (memory_usage == UINT64_MAX)
1412  rpmlog(RPMLOG_CRIT, "Unsupported filter chain or filter options\n");
1413 
1414  /* Print memory usage info. */
1415  rpmlog(RPMLOG_DEBUG, _("%'llu MiB (%'llu B) of memory is required per thread, limit is %'llu MiB (%'llu B)\n"),
1416  (unsigned long long)(memory_usage >> 20),
1417  (unsigned long long)memory_usage,
1418  (unsigned long long)(memory_limit >> 20),
1419  (unsigned long long)memory_limit);
1420 
1421  if (memory_usage > memory_limit) {
1422  size_t i = 0;
1423  lzma_options_lzma *opt;
1424  rpmuint32_t orig_dict_size;
1425 
1426  /* If --no-auto-adjust was used or we didn't find LZMA1 or
1427  LZMA2 as the last filter, give an error immediatelly.
1428  --format=raw implies --no-auto-adjust. */
1429  if (!z->_auto_adjust || z->format == RPMZ_FORMAT_RAW)
1430  memlimit_too_small(memory_usage, memory_limit);
1431 
1432 #ifdef NOTYET
1433  assert(z->mode == RPMZ_MODE_COMPRESS);
1434 #endif /* NOTYET */
1435 
1436  /* Look for the last filter if it is LZMA2 or LZMA1, so
1437  we can make it use less RAM. With other filters we don't
1438  know what to do. */
1439  while (z->_filters[i].id != LZMA_FILTER_LZMA2
1440  && z->_filters[i].id != LZMA_FILTER_LZMA1) {
1441  if (z->_filters[i].id == LZMA_VLI_UNKNOWN)
1442  memlimit_too_small(memory_usage, memory_limit);
1443 
1444  ++i;
1445  }
1446 
1447  /* Decrease the dictionary size until we meet the memory
1448  usage limit. First round down to full mebibytes. */
1449  opt = z->_filters[i].options;
1450  orig_dict_size = opt->dict_size;
1451  opt->dict_size &= ~((UINT32_C(1) << 20) - 1);
1452  while (1) {
1453  /* If it is below 1 MiB, auto-adjusting failed. We
1454  could be more sophisticated and scale it down even
1455  more, but let's see if many complain about this
1456  version.
1457 
1458  FIXME: Displays the scaled memory usage instead
1459  of the original. */
1460  if (opt->dict_size < (UINT32_C(1) << 20))
1461  memlimit_too_small(memory_usage, memory_limit);
1462 
1463  memory_usage = lzma_raw_encoder_memusage(z->_filters);
1464 assert(memory_usage != UINT64_MAX);
1465 
1466  /* Accept it if it is low enough. */
1467  if (memory_usage <= memory_limit)
1468  break;
1469 
1470  /* Otherwise 1 MiB down and try again. I hope this
1471  isn't too slow method for cases where the original
1472  dict_size is very big. */
1473  opt->dict_size -= UINT32_C(1) << 20;
1474  }
1475 
1476  /* Tell the user that we decreased the dictionary size.
1477  However, omit the message if no preset or custom chain
1478  was given. FIXME: Always warn? */
1479 #ifdef NOTYET
1480  if (!preset_default)
1481 #endif /* NOTYET */
1482  rpmlog(RPMLOG_WARNING, "Adjusted LZMA%c dictionary size from %'u MiB to %'u MiB to not exceed the memory usage limit of %'llu MiB\n",
1483  z->_filters[i].id == LZMA_FILTER_LZMA2
1484  ? '2' : '1',
1485  (unsigned)(orig_dict_size >> 20),
1486  (unsigned)(opt->dict_size >> 20),
1487  (unsigned long long)(memory_limit >> 20));
1488  }
1489 
1490  /* Limit the number of worker threads so that memory usage
1491  limit isn't exceeded. */
1492  assert(memory_usage > 0);
1493  thread_limit = memory_limit / memory_usage;
1494  if (thread_limit == 0)
1495  thread_limit = 1;
1496 
1497  if (zq->threads > thread_limit)
1498  zq->threads = thread_limit;
1499 
1500  return;
1501 }
1502 
1503 #ifdef DYING
1504 /*==============================================================*/
1505 
1508 static int rpmzLoadManifests(rpmz z)
1509  /*@modifies z @*/
1510 {
1511  ARGV_t manifests;
1512  const char * fn;
1513  int rc = 0; /* assume success */
1514 
1515  if ((manifests = z->manifests) != NULL) /* note rc=0 return with no files to load. */
1516  while ((fn = *manifests++) != NULL) {
1517  unsigned lineno;
1518  char * be = NULL;
1519  rpmiob iob = NULL;
1520  int xx = rpmiobSlurp(fn, &iob);
1521  char * f;
1522  char * fe;
1523 
1524  if (!(xx == 0 && iob != NULL)) {
1525  fprintf(stderr, _("%s: Failed to open %s\n"), __progname, fn);
1526  rc = -1;
1527  goto bottom;
1528  }
1529 
1530  be = (char *)(iob->b + iob->blen);
1531  while (be > (char *)iob->b && (be[-1] == '\n' || be[-1] == '\r')) {
1532  be--;
1533  *be = '\0';
1534  }
1535 
1536  /* Parse and save manifest items. */
1537  lineno = 0;
1538  for (f = (char *)iob->b; *f; f = fe) {
1539  const char * path;
1540  char * g, * ge;
1541  lineno++;
1542 
1543  fe = f;
1544  while (*fe && !(*fe == '\n' || *fe == '\r'))
1545  fe++;
1546  g = f;
1547  ge = fe;
1548  while (*fe && (*fe == '\n' || *fe == '\r'))
1549  *fe++ = '\0';
1550 
1551  while (*g && xisspace((int)*g))
1552  *g++ = '\0';
1553  /* Skip comment lines. */
1554  if (*g == '#')
1555  continue;
1556 
1557  while (ge > g && xisspace(ge[-1]))
1558  *--ge = '\0';
1559  /* Skip empty lines. */
1560  if (ge == g)
1561  continue;
1562 
1563  /* Prepend z->base_prefix if specified. */
1564  if (z->base_prefix)
1565  path = rpmExpand(z->base_prefix, g, NULL);
1566  else
1567  path = rpmExpand(g, NULL);
1568  (void) argvAdd(&z->argv, path);
1569  path = _free(path);
1570  }
1571 
1572 bottom:
1573  iob = rpmiobFree(iob);
1574  if (rc != 0)
1575  goto exit;
1576  }
1577 
1578 exit:
1579  return rc;
1580 }
1581 #endif
1582 
1583 /*==============================================================*/
1584 
1587 void rpmzArgCallback(poptContext con,
1588  /*@unused@*/ enum poptCallbackReason reason,
1589  const struct poptOption * opt, const char * arg,
1590  /*@unused@*/ void * data)
1591  /*@*/
1592 {
1593  rpmz z = _rpmz;
1594 
1595  /* XXX avoid accidental collisions with POPT_BIT_SET for flags */
1596  if (opt->arg == NULL)
1597  switch (opt->val) {
1598  case 'M':
1599  { char * end = NULL;
1600  z->memlimit_custom = (rpmuint64_t) strtoll(arg, &end, 0);
1601  if (end == NULL || *end == '\0')
1602  break;
1603  if (!strcmp(end, "k") || !strcmp(end, "kB"))
1604  z->memlimit_custom *= 1000;
1605  else if (!strcmp(end, "M") || !strcmp(end, "MB"))
1606  z->memlimit_custom *= 1000 * 1000;
1607  else if (!strcmp(end, "G") || !strcmp(end, "GB"))
1608  z->memlimit_custom *= 1000 * 1000 * 1000;
1609  else if (!strcmp(end, "Ki") || !strcmp(end, "KiB"))
1610  z->memlimit_custom *= 1024;
1611  else if (!strcmp(end, "Mi") || !strcmp(end, "MiB"))
1612  z->memlimit_custom *= 1024 * 1024;
1613  else if (!strcmp(end, "Gi") || !strcmp(end, "GiB"))
1614  z->memlimit_custom *= 1024 * 1024 * 1024;
1615  else {
1616  fprintf(stderr, _("%s: Invalid memory scaling suffix \"%s\"\n"),
1617  __progname, arg);
1618  /*@-exitarg@*/ exit(2); /*@=exitarg@*/
1619  /*@notreached@*/
1620  }
1621  } break;
1622  case 'C':
1623  if (!strcmp(arg, "none"))
1624  z->_checksum = LZMA_CHECK_NONE;
1625  else if (!strcmp(arg, "crc32"))
1626  z->_checksum = LZMA_CHECK_CRC32;
1627  else if (!strcmp(arg, "crc64"))
1628  z->_checksum = LZMA_CHECK_CRC64;
1629  else if (!strcmp(arg, "sha256"))
1630  z->_checksum = LZMA_CHECK_SHA256;
1631  else {
1632  fprintf(stderr, _("%s: Unknown integrity check method \"%s\"\n"),
1633  __progname, arg);
1634  /*@-exitarg@*/ exit(2); /*@=exitarg@*/
1635  /*@notreached@*/
1636  }
1637  break;
1638  case 'F':
1639  if (!strcmp(arg, "auto"))
1640  z->format = RPMZ_FORMAT_AUTO;
1641  else if (!strcmp(arg, "xz"))
1642  z->format = RPMZ_FORMAT_XZ;
1643  else if (!strcmp(arg, "lzma") || !strcmp(arg, "alone"))
1644  z->format = RPMZ_FORMAT_LZMA;
1645  else if (!strcmp(arg, "raw"))
1646  z->format = RPMZ_FORMAT_RAW;
1647  else if (!strcmp(arg, "gzip") || !strcmp(arg, "gz"))
1648  z->format = RPMZ_FORMAT_GZIP;
1649  else if (!strcmp(arg, "zlib"))
1650  z->format = RPMZ_FORMAT_ZLIB;
1651  else if (!strcmp(arg, "zip"))
1652  z->format = RPMZ_FORMAT_ZIP2; /* XXX zip3 from pigz? */
1653  else if (!strcmp(arg, "bzip2") || !strcmp(arg, "bz2"))
1654  z->format = RPMZ_FORMAT_BZIP2;
1655  else {
1656  fprintf(stderr, _("%s: Unknown file format type \"%s\"\n"),
1657  __progname, arg);
1658  /*@-exitarg@*/ exit(2); /*@=exitarg@*/
1659  /*@notreached@*/
1660  }
1661  break;
1662 
1663  case OPT_SUBBLOCK:
1664  coder_add_filter(z, LZMA_FILTER_SUBBLOCK, options_subblock(optarg));
1665  break;
1666  case OPT_DELTA:
1667  coder_add_filter(z, LZMA_FILTER_DELTA, options_delta(optarg));
1668  break;
1669  case OPT_LZMA1:
1670  coder_add_filter(z, LZMA_FILTER_LZMA1, options_lzma(optarg));
1671  break;
1672  case OPT_LZMA2:
1673  coder_add_filter(z, LZMA_FILTER_LZMA2, options_lzma(optarg));
1674  break;
1675 
1676  case 'L':
1677  fprintf(stderr, "%s\n", VERSION);
1678  /* XXX add license display. */
1679  exit(EXIT_SUCCESS);
1680  /*@notreached@*/ break;
1681  case 'V': fprintf(stderr, "%s\n", VERSION); exit(EXIT_SUCCESS);
1682 
1683  default:
1684  fprintf(stderr, _("%s: Unknown option -%c\n"), __progname, opt->val);
1685  poptPrintUsage(con, stderr, 0);
1686  /*@-exitarg@*/ exit(2); /*@=exitarg@*/
1687  /*@notreached@*/ break;
1688  }
1689 }
1690 
1691 /*==============================================================*/
1692 /*@unchecked@*/ /*@observer@*/
1693 static struct poptOption rpmzFiltersPoptTable[] = {
1694 /*@-type@*/ /* FIX: cast? */
1695  { NULL, '\0', POPT_ARG_CALLBACK | POPT_CBFLAG_INC_DATA | POPT_CBFLAG_CONTINUE,
1696  rpmzArgCallback, 0, NULL, NULL },
1697 /*@=type@*/
1698 
1699  /* ===== Custom filters */
1700 #ifdef REFERENCE
1701 " --lzma=[OPTS] LZMA filter; OPTS is a comma-separated list of zero or\n"
1702 " more of the following options (valid values; default):\n"
1703 " dict=NUM dictionary size in bytes (1 - 1Gi; 8Mi)\n"
1704 " lc=NUM number of literal context bits (0-8; 3)\n"
1705 " lp=NUM number of literal position bits (0-4; 0)\n"
1706 " pb=NUM number of position bits (0-4; 2)\n"
1707 " mode=MODE compression mode (`fast' or `best'; `best')\n"
1708 " nice_len=NUM number of fast bytes (5-273; 128)\n"
1709 " mf=NAME match finder (hc3, hc4, bt2, bt3, bt4; bt4)\n"
1710 " depth=NUM match finder cycles; 0=automatic (default)\n"
1711 #endif
1712  { "lzma1", '\0', POPT_ARG_STRING|POPT_ARGFLAG_OPTIONAL, NULL, OPT_LZMA1,
1713  N_("LZMA1 filter"), N_("OPTS") },
1714  { "lzma2", '\0', POPT_ARG_STRING|POPT_ARGFLAG_OPTIONAL, NULL, OPT_LZMA2,
1715  N_("LZMA2 filter"), N_("OPTS") },
1716 
1717  { "x86", '\0', POPT_BIT_SET, &__rpmz.flags, RPMZ_FLAGS_X86,
1718  N_("ix86 filter (sometimes called BCJ filter)"), NULL },
1719  { "bcj", '\0', POPT_BIT_SET|POPT_ARGFLAG_DOC_HIDDEN, &__rpmz.flags, RPMZ_FLAGS_X86,
1720  N_("x86 filter (also called BCJ filter)"), NULL },
1721  { "powerpc", '\0', POPT_BIT_SET, &__rpmz.flags, RPMZ_FLAGS_POWERPC,
1722  N_("PowerPC (big endian) filter"), NULL },
1723  { "ppc", '\0', POPT_BIT_SET|POPT_ARGFLAG_DOC_HIDDEN, &__rpmz.flags, RPMZ_FLAGS_POWERPC,
1724  N_("PowerPC (big endian) filter"), NULL },
1725  { "ia64", '\0', POPT_BIT_SET, &__rpmz.flags, RPMZ_FLAGS_IA64,
1726  N_("IA64 (Itanium) filter"), NULL },
1727  { "itanium", '\0', POPT_BIT_SET|POPT_ARGFLAG_DOC_HIDDEN, &__rpmz.flags, RPMZ_FLAGS_IA64,
1728  N_("IA64 (Itanium) filter"), NULL },
1729  { "arm", '\0', POPT_BIT_SET, &__rpmz.flags, RPMZ_FLAGS_ARM,
1730  N_("ARM filter"), NULL },
1731  { "armthumb", '\0', POPT_BIT_SET, &__rpmz.flags, RPMZ_FLAGS_ARMTHUMB,
1732  N_("ARM-Thumb filter"), NULL },
1733  { "sparc", '\0', POPT_BIT_SET, &__rpmz.flags, RPMZ_FLAGS_SPARC,
1734  N_("SPARC filter"), NULL },
1735 
1736 #ifdef REFERENCE
1737 " --delta=[OPTS] Delta filter; valid OPTS (valid values; default):\n"
1738 " dist=NUM Distance between bytes being\n"
1739 " subtracted from each other (1-256; 1)\n"
1740 #endif
1741  { "delta", '\0', POPT_ARG_STRING|POPT_ARGFLAG_OPTIONAL, NULL, OPT_DELTA,
1742  N_("Delta filter"), N_("OPTS") },
1743 
1744 #ifdef REFERENCE
1745 " --subblock=[OPTS] Subblock filter; valid OPTS (valid values; default):\n"
1746 " size=NUM number of bytes of data per subblock\n"
1747 " (1 - 256Mi; 4Ki)\n"
1748 " rle=NUM run-length encoder chunk size (0-256; 0)\n"
1749 #endif
1750  { "subblock", '\0', POPT_ARG_STRING|POPT_ARGFLAG_OPTIONAL, NULL, OPT_SUBBLOCK,
1751  N_("Subblock filter"), N_("OPTS") },
1752 
1753  POPT_TABLEEND
1754 };
1755 
1756 /* XXX grrr, popt needs better way to insert text strings in --help. */
1757 /* XXX fixme: popt does post order recursion into sub-tables. */
1758 /*@unchecked@*/ /*@observer@*/
1759 static struct poptOption rpmzPrivatePoptTable[] = {
1760 /*@-type@*/ /* FIX: cast? */
1761  { NULL, '\0', POPT_ARG_CALLBACK | POPT_CBFLAG_INC_DATA | POPT_CBFLAG_CONTINUE,
1762  rpmzArgCallback, 0, NULL, NULL },
1763 /*@=type@*/
1764 
1765  { "debug", 'D', POPT_ARG_VAL|POPT_ARGFLAG_DOC_HIDDEN, &_debug, -1,
1766  N_("debug spewage"), NULL },
1767 
1768  { "format", 'F', POPT_ARG_STRING, NULL, 'F',
1769  N_("file FORMAT {auto|xz|lzma|alone|raw|gz|bz2}"), N_("FORMAT") },
1770  { "check", 'C', POPT_ARG_STRING, NULL, 'C',
1771  N_("integrity check METHOD {none|crc32|crc64|sha256}"), N_("METHOD") },
1772  { "memory", 'M', POPT_ARG_STRING, NULL, 'M',
1773  N_("use roughly NUM Mbytes of memory at maximum"), N_("NUM") },
1774 
1775  /* XXX POPT_ARG_ARGV portability. */
1776  { "files", '\0', POPT_ARG_ARGV, &__rpmz.manifests, 0,
1777  N_("Read file names from MANIFEST"), N_("MANIFEST") },
1778 #ifdef NOTYET
1779  { "quiet", 'q', POPT_ARG_VAL, NULL, 'q',
1780  N_("suppress warnings; specify twice to suppress errors too"), NULL },
1781  { "verbose", 'v', POPT_ARG_VAL, NULL, 'v',
1782  N_("be verbose; specify twice for even more verbose"), NULL },
1783  { "help", 'h', POPT_ARG_VAL, NULL, 'h',
1784  N_("display this help and exit"), NULL },
1785  { "long-help", 'h', POPT_ARG_VAL, NULL, 'H',
1786  N_("display this help and exit"), NULL },
1787 #endif
1788  { "version", 'V', POPT_ARG_VAL|POPT_ARGFLAG_DOC_HIDDEN, NULL, 'V',
1789  N_("Display software version"), NULL },
1790  { "license", 'L', POPT_ARG_VAL|POPT_ARGFLAG_DOC_HIDDEN, NULL, 'L',
1791  N_("Display softwre license"), NULL },
1792 
1793  POPT_TABLEEND
1794 };
1795 /*@unchecked@*/ /*@observer@*/
1796 static struct poptOption optionsTable[] = {
1797 /*@-type@*/ /* FIX: cast? */
1798  { NULL, '\0', POPT_ARG_CALLBACK | POPT_CBFLAG_INC_DATA | POPT_CBFLAG_CONTINUE,
1799  rpmzArgCallback, 0, NULL, NULL },
1800 /*@=type@*/
1801 
1802  { NULL, '\0', POPT_ARG_INCLUDE_TABLE, rpmzPrivatePoptTable, 0,
1803  N_("\
1804  Compress or decompress FILEs.\n\
1805 \n\
1806 Options:\
1807 "), NULL },
1808 
1809  /* ===== Basic compression settings */
1810  { NULL, '\0', POPT_ARG_INCLUDE_TABLE, rpmzOptionsPoptTable, 0,
1811  N_("Compression options: "), NULL },
1812 
1813  /* ===== Compression options */
1814 #ifdef DYING
1815  /* XXX compressor specific flags need to be set some other way. */
1816  { "extreme", 'e', POPT_BIT_SET|POPT_ARGFLAG_TOGGLE, &__rpmz.flags, RPMZ_FLAGS_EXTREME,
1817  N_("extreme compression"), NULL },
1818 #endif
1819 
1820  /* ===== Custom filters */
1821  { NULL, '\0', POPT_ARG_INCLUDE_TABLE, rpmzFiltersPoptTable, 0,
1822  N_("Filters:"), NULL },
1823 
1824  /* ===== Metadata options */
1825 #ifdef NOTYET
1826  { "sign", 'S', POPT_ARG_STRING, NULL, 0,
1827  N_("sign the data with GnuPG when compressing, or verify the signature when decompressing"), N_("PUBKEY") },
1828 #endif
1829 
1830  /* ===== Other options */
1831 
1832  { NULL, '\0', POPT_ARG_INCLUDE_TABLE, rpmioAllPoptTable, 0,
1833  N_("Common options for all rpmio executables:"),
1834  NULL },
1835 
1836  POPT_AUTOALIAS
1837  POPT_AUTOHELP
1838 
1839  { NULL, (char)-1, POPT_ARG_INCLUDE_TABLE, NULL, 0,
1840  N_("\
1841 Usage: rpmz [OPTION]... [FILE]...\n\
1842  Compress or decompress FILEs.\
1843 "), NULL },
1844 
1845  POPT_TABLEEND
1846 
1847 };
1848 
1849 int
1850 main(int argc, char *argv[])
1851  /*@globals __assert_program_name,
1852  rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
1853  /*@modifies __assert_program_name, _rpmrepo,
1854  rpmGlobalMacroContext, fileSystem, internalState @*/
1855 {
1856  rpmz z = _rpmz;
1857  rpmzQueue zq = &z->_zq;
1858 
1859  poptContext optCon;
1860  int ac;
1861  int rc = 1; /* assume failure. */
1862  int xx;
1863  int i;
1864 
1865 /*@-observertrans -readonlytrans @*/
1866  __progname = "rpmz";
1867 /*@=observertrans =readonlytrans @*/
1868 
1869  z->zq = zq; /* XXX initialize rpmzq */
1870  zq->blocksize = 128;
1871  zq->threads = 8;
1872 
1873  /* Set modes and format based on argv[0]. */
1874  xx = rpmzParseArgv0(z, argv[0]);
1875  if (xx)
1876  goto exit;
1877 
1878  z->iob = rpmiobNew(z->nb);
1879 
1880  /* Make sure that stdin/stdout/stderr are open. */
1881  /* XXX done by rpmioInit as well. */
1882  io_init();
1883 
1884  /* Set hardware specific parameters. */
1885  hw_init(z);
1886 
1887  /* Parse environment options. */
1888  /* XXX NULL uses "RPMZ" envvar. */
1889  xx = rpmzParseEnv(z, NULL, optionsTable);
1890  if (xx)
1891  goto exit;
1892 
1893  /* Parse CLI options. */
1894  /* XXX todo: needs to be earlier. */
1895  optCon = rpmioInit(argc, argv, optionsTable);
1896 
1897  /* Never remove the source file when the destination is not on disk.
1898  In test mode the data is written nowhere, but setting opt_stdout
1899  will make the rest of the code behave well. */
1900  if (F_ISSET(z->flags, STDOUT) || z->mode == RPMZ_MODE_TEST) {
1901  z->flags |= RPMZ_FLAGS_KEEP;
1902  z->flags |= RPMZ_FLAGS_STDOUT;
1903  }
1904 
1905  /* If no --format flag was used, or it was --format=auto, we need to
1906  decide what is the target file format we are going to use. This
1907  depends on how we were called (checked earlier in this function). */
1908  if (z->mode == RPMZ_MODE_COMPRESS && z->format == RPMZ_FORMAT_AUTO)
1909  z->format = z->_format_compress_auto;
1910 
1911  /* XXX Set additional parameters from z->format. */
1912  switch (z->format) {
1913  default:
1914  case RPMZ_FORMAT_XZ:
1915  z->idio = z->odio = xzdio;
1916  z->osuffix = ".xz";
1917  if (z->mode == RPMZ_MODE_COMPRESS)
1919  break;
1920  case RPMZ_FORMAT_LZMA:
1921  z->idio = z->odio = lzdio;
1922  z->osuffix = ".lzma";
1923  if (z->mode == RPMZ_MODE_COMPRESS)
1925  break;
1926  case RPMZ_FORMAT_RAW:
1927  z->idio = z->odio = xzdio;
1928  z->osuffix = ".xz"; /* XXX W2DO? */
1930  break;
1931  case RPMZ_FORMAT_AUTO:
1932 fprintf(stderr, "==> warning: assuming auto format is gzip\n");
1933  z->format = RPMZ_FORMAT_GZIP;
1934  /*@fallthrough@*/
1935  case RPMZ_FORMAT_GZIP:
1936  z->idio = z->odio = gzdio;
1937  z->osuffix = ".gz";
1938  break;
1939  case RPMZ_FORMAT_ZLIB:
1940  z->idio = z->odio = gzdio;
1941  z->osuffix = ".zz";
1942  break;
1943  case RPMZ_FORMAT_ZIP2:
1944  z->idio = z->odio = gzdio;
1945  z->osuffix = ".zip";
1946  break;
1947  case RPMZ_FORMAT_BZIP2:
1948  z->idio = z->odio = bzdio;
1949  z->osuffix = ".bz2";
1950  break;
1951  }
1952 
1953  if (z->mode == RPMZ_MODE_COMPRESS) {
1954  int xx;
1955  xx = snprintf(z->ofmode, sizeof(z->ofmode)-1, "wb%u",
1956  (unsigned)(__rpmz.level % 10));
1957  }
1958 
1959  /* Add files from CLI. */
1960  { ARGV_t av = poptGetArgs(optCon);
1961  if (av != NULL)
1962  xx = argvAppend(&z->argv, av);
1963  }
1964 
1965  /* Add files from --files manifest(s). */
1966  if (z->manifests != NULL)
1967  xx = rpmzLoadManifests(z);
1968 
1969 if (_debug)
1970 argvPrint("input args", z->argv, NULL);
1971 
1972  ac = argvCount(z->argv);
1973  /* With no arguments, act as a stdin/stdout filter. */
1974  if (z->argv == NULL || z->argv[0] == NULL)
1975  ac++;
1976 
1977  signals_init();
1978 
1979  /* Process arguments. */
1980  for (i = 0; i < ac; i++) {
1981  const char * ifn;
1982  rpmRC frc = RPMRC_OK;
1983 
1984  /* Use NULL for stdin. */
1985  ifn = (z->argv && strcmp(z->argv[i], "-") ? z->argv[i] : NULL);
1986 
1987  switch (z->mode) {
1988  case RPMZ_MODE_COMPRESS:
1989  case RPMZ_MODE_DECOMPRESS:
1990  frc = rpmzProcess(z, ifn);
1991  break;
1992  case RPMZ_MODE_TEST:
1993  break;
1994  }
1995 
1996  if (frc != RPMRC_OK || signals_terminating(0))
1997  goto exit;
1998  }
1999 
2000  rc = 0;
2001 
2002 exit:
2003  z->manifests = argvFree(z->manifests);
2004  z->argv = argvFree(z->argv);
2005  z->iob = rpmiobFree(z->iob);
2006 
2007  optCon = rpmioFini(optCon);
2008 
2009  signals_exit();
2010 
2011  return rc;
2012 }
#define RPMLOG_PRI(p)
Definition: rpmlog.h:37
static const char * suffix[]
Definition: rpmgrep.c:188
static void signals_exit(void)
Definition: rpmz.c:885
poptContext rpmioInit(int argc, char *const argv[], struct poptOption *optionsTable)
Initialize most everything needed by an rpmio executable context.
Definition: poptIO.c:767
static struct suffixPairs_s suffixPairs[]
static void parse_options(const char *str, const option_map *opts, void(*set)(void *filter_options, rpmuint32_t key, rpmuint64_t value), void *filter_options)
Definition: rpmz.c:941
const name_id_map * map
Definition: rpmz.c:915
const char const char size_t len
Definition: bson.h:823
#define EXIT_FAILURE
size_t Fwrite(const void *buf, size_t size, size_t nmemb, FD_t fd)
fwrite(3) clone.
Definition: rpmio.c:2434
Definition: rpmz.c:1111
static char * changeSuffix(const char *fn, const char *old, const char *new)
Return (malloc'd) string with new suffix substituted for old.
Definition: rpmz.c:457
char * xstrdup(const char *str)
Definition: rpmmalloc.c:321
FD_t Fopen(const char *path, const char *_fmode)
fopen(3) clone.
Definition: rpmio.c:2833
void rpmzArgCallback(poptContext con, enum poptCallbackReason reason, const struct poptOption *opt, const char *arg, void *data)
Definition: rpmz.c:1587
static void set_delta(void *options, rpmuint32_t key, rpmuint64_t value)
Definition: rpmz.c:1079
char * rpmGetPath(const char *path,...)
Return (malloc'ed) expanded, canonicalized, file path.
Definition: macro.c:3431
#define __progname
Definition: system.h:363
int Utimes(const char *path, const struct timeval *times)
utimes(2) clone.
static rpmuint64_t physmem(void)
Definition: rpmz.c:314
static void signals_fini(void)
Definition: rpmz.c:817
#define RPMLOG_MASK(pri)
Definition: rpmlog.h:136
struct rpmzQueue_s * rpmzQueue
Definition: rpmzq.h:23
int argvAppend(ARGV_t *argvp, ARGV_t av)
Append one argv array to another.
Definition: argv.c:216
#define VERSION
Definition: config.h:1306
int Stat(const char *path, struct stat *st)
stat(2) clone.
Definition: rpmrpc.c:1361
Definition: rpmz.c:1116
#define S_ISLNK(mode)
Definition: system.h:651
int Fflush(FD_t fd)
fflush(3) clone.
Definition: rpmio.c:2916
int errno
Definition: rpmz.c:61
static struct poptOption rpmzFiltersPoptTable[]
Definition: rpmz.c:1693
rpmiob rpmiobFree(rpmiob iob)
Destroy a I/O buffer instance.
FDIO_t xzdio
static void rpmlog(int code, const char *fmt,...)
Definition: rpmlog.h:299
FD_t fdDup(int fdno)
Definition: rpmio.c:266
static void io_unlink(const char *fn, const struct stat *ost)
Definition: rpmz.c:140
int Utime(const char *path, const struct utimbuf *buf)
Definition: rpmrpc.c:2021
int rpmiobSlurp(const char *fn, rpmiob *iobp)
Definition: rpmiob.c:129
RPM parallel compressor internals.
const char * str
Definition: bson.h:593
static int checkfd(const char *devnull, int fdno, int flags)
Definition: rpmz.c:99
static void coder_set_compression_settings(rpmz z)
Definition: rpmz.c:1330
unsigned int rpmuint32_t
Definition: rpmiotypes.h:28
int Fchown(FD_t fd, uid_t owner, gid_t group)
fchown(2) clone.
Definition: rpmrpc.c:1704
rpmz _rpmz
Definition: rpmz.c:94
const char const bson_bool_t v
Definition: bson.h:919
static lzma_options_delta * options_delta(const char *str)
Definition: rpmz.c:1089
static rpmuint64_t hw_memlimit_encoder(rpmz z)
Definition: rpmz.c:1217
static lzma_options_subblock * options_subblock(const char *str)
Definition: rpmz.c:1048
const char * mode
Definition: mongo.h:440
static void coder_add_filter(rpmz z, lzma_vli id, void *options)
Definition: rpmz.c:1200
#define N_(Text)
Definition: system.h:531
FD_t fdFree(FD_t fd, const char *msg)
static rpmRC rpmzCopy(rpmz z, rpmiob iob)
Definition: rpmz.c:766
FDIO_t lzdio
int argvCount(const ARGV_t argv)
Return no.
Definition: argv.c:71
struct rpmz_s * rpmz
Definition: rpmz.h:28
FDIO_t gzdio
struct rpmz_s __rpmz
Definition: rpmz.c:69
const char const bson * data
Definition: mongo.h:463
int Lstat(const char *path, struct stat *st)
lstat(2) clone.
Definition: rpmrpc.c:1401
#define POPT_ARGFLAG_TOGGLE
Definition: poptIO.c:69
static int xisspace(int c)
Definition: rpmiotypes.h:555
unsigned long long rpmuint64_t
Definition: rpmiotypes.h:29
ARGV_t argvFree(ARGV_t argv)
Destroy an argv array.
Definition: argv.c:44
static int signals_init_count
Definition: rpmz.c:799
rpmzFormat_e
Definition: rpmzq.h:59
rpmuint64_t id
Definition: rpmz.c:910
static void memlimit_too_small(rpmuint64_t memory_usage, rpmuint64_t memory_limit)
Definition: rpmz.c:1319
static void signals_init(void)
Definition: rpmz.c:801
Definition: rpmz.c:59
const char * name
Definition: rpmz.c:914
static lzma_options_lzma * options_lzma(const char *str)
Definition: rpmz.c:1146
static void set_subblock(void *options, rpmuint32_t key, rpmuint64_t value)
Definition: rpmz.c:1035
int argvAdd(ARGV_t *argvp, ARGstr_t val)
Add a string to an argv array.
Definition: argv.c:199
static rpmuint64_t hw_memlimit_decoder(rpmz z)
Definition: rpmz.c:1224
char * rpmExpand(const char *arg,...)
Return (malloc'ed) concatenated macro expansion(s).
Definition: macro.c:3238
static rpmRC rpmzInit(rpmz z, const char *ifn)
Definition: rpmz.c:594
static void hw_memlimit_init(rpmz z)
Definition: rpmz.c:382
size_t Fread(void *buf, size_t size, size_t nmemb, FD_t fd)
fread(3) clone.
Definition: rpmio.c:2412
#define dirent
Definition: system.h:245
const char const char int arg
Definition: mongo.h:777
int Fchmod(FD_t fd, mode_t mode)
fchmod(2) clone.
Definition: rpmrpc.c:1830
rpmuint64_t min
Definition: rpmz.c:916
FDIO_t bzdio
int Fclose(FD_t fd)
fclose(3) clone.
Definition: rpmio.c:2534
rpmiob rpmiobNew(size_t len)
Create an I/O buffer.
Definition: rpmiob.c:44
static void io_init(void)
Definition: rpmz.c:112
const char const bson int mongo_write_concern int flags
Definition: mongo.h:485
void argvPrint(const char *msg, ARGV_t argv, FILE *fp)
Print argv array elements.
Definition: argv.c:19
sigset_t rpmsqCaught
Definition: rpmsq.c:352
static void hw_init(rpmz z)
Definition: rpmz.c:399
enum rpmRC_e rpmRC
RPM return codes.
int Ferror(FD_t fd)
ferror(3) clone.
Definition: rpmio.c:2944
static int _debug
Definition: rpmz.c:33
const char const char const char * opts
Definition: bson.h:971
const char const int i
Definition: bson.h:778
static int snprintf(char *buf, int nb, const char *fmt,...)
Definition: rpmps.c:220
const char const bson * key
Definition: mongo.h:717
static void set(char *t, NODE *ip)
Definition: rpmmtree.c:1408
const char const char int int max
Definition: mongo.h:749
struct dirent * Readdir(DIR *dir)
readdir(3) clone.
Definition: rpmdir.c:432
Definition: rpmz.c:1113
static struct poptOption rpmzPrivatePoptTable[]
Definition: rpmz.c:1759
char * stpcpy(char *dest, const char *src)
static const char * uncompressedFN(rpmz z)
Return (malloc'd) uncompressed file name.
Definition: rpmz.c:484
const char * csuffix
Definition: rpmz.c:413
static void * _free(const void *p)
Wrapper to free(3), hides const compilation noise, permit NULL, return NULL.
Definition: rpmiotypes.h:756
struct rpmiob_s * rpmiob
Definition: rpmiotypes.h:60
static rpmRC rpmzFini(rpmz z, rpmRC rc)
Definition: rpmz.c:541
rpmuint64_t max
Definition: rpmz.c:917
#define F_ISSET(_f, _FLAG)
Definition: rpmz.c:65
Definition: rpmz.c:1112
int main(int argc, char *argv[])
Definition: rpmz.c:1850
int Fileno(FD_t fd)
fileno(3) clone.
Definition: rpmio.c:2991
int Closedir(DIR *dir)
closedir(3) clone.
Definition: rpmdir.c:385
const char const char * code
Definition: bson.h:882
static const char * name
#define _(Text)
Definition: system.h:29
#define xmalloc
Definition: system.h:32
DIR * Opendir(const char *path)
opendir(3) clone.
Definition: rpmdir.c:396
const char * name
Definition: rpmz.c:909
static int chkSuffix(const char *fn, const char *suffix)
Check string for a suffix.
Definition: rpmz.c:439
ARGstr_t * ARGV_t
Definition: argv.h:12
int rpmlogSetMask(int mask)
Set the log mask level.
Definition: rpmlog.c:98
struct poptOption rpmioAllPoptTable[]
Popt option table for options shared by all modes and executables.
Definition: poptIO.c:564
static void hw_cores(rpmz z)
Definition: rpmz.c:347
poptContext rpmioFini(poptContext optCon)
Destroy most everything needed by an rpm CLI executable context.
Definition: poptIO.c:734
Definition: rpmz.c:60
const char const bson const bson int int int options
Definition: mongo.h:569
static void message_filters(int code, const lzma_filter *filters)
Definition: rpmz.c:1231
static rpmRC rpmzProcess(rpmz z, const char *ifn)
Definition: rpmz.c:786
const char * usuffix
Definition: rpmz.c:415
static const char * compressedFN(rpmz z)
Return (malloc'd) compressed file name.
Definition: rpmz.c:513
int rpmsqEnable(int signum, rpmsqAction_t handler)
Enable or disable a signal handler.
Definition: rpmsq.c:439
modes
Definition: rpmqv.c:136
static int signals_terminating(int terminate)
Definition: rpmz.c:833
enum rpmzFormat_e format
Definition: rpmz.c:411
static void io_copy_attrs(rpmz z)
Definition: rpmz.c:167
Definition: rpmz.c:1030
static struct poptOption optionsTable[]
Definition: rpmz.c:1796
int j
Definition: mongo.h:438
static void set_lzma(void *options, rpmuint32_t key, rpmuint64_t value)
Definition: rpmz.c:1121
int Unlink(const char *path)
unlink(2) clone.
Definition: rpmrpc.c:397